{"id":"84d43e980075cc64","slug":"all-buildings-in-the-netherlands","trashed":false,"description":"","likes":18,"publish_level":"public","forks":0,"fork_of":null,"has_importers":true,"update_time":"2020-09-23T06:04:07.392Z","first_public_version":null,"paused_version":null,"publish_time":"2018-08-29T15:15:24.213Z","publish_version":456,"latest_version":456,"thumbnail":"3eacb44229b56e6b5c0dc70bc54f2b329a33a5ccf9701465cb5d579c83810f78","default_thumbnail":"3eacb44229b56e6b5c0dc70bc54f2b329a33a5ccf9701465cb5d579c83810f78","roles":[],"sharing":null,"owner":{"id":"569e0b420e4a1957","avatar_url":"https://avatars.observableusercontent.com/avatar/30e87702a8b688510b4d1c30f411d16532c7d46a100044235468810a711ae98d","login":"bertspaan","name":"Bert Spaan","bio":"","home_url":"https://bertspaan.nl","type":"team","tier":"starter_2024"},"creator":{"id":"bf3b6e1e3dc67c1f","avatar_url":"https://avatars.observableusercontent.com/avatar/30e87702a8b688510b4d1c30f411d16532c7d46a100044235468810a711ae98d","login":"bertspaan","name":"Bert Spaan","bio":"","home_url":"https://bertspaan.nl","tier":"public"},"authors":[{"id":"bf3b6e1e3dc67c1f","avatar_url":"https://avatars.observableusercontent.com/avatar/30e87702a8b688510b4d1c30f411d16532c7d46a100044235468810a711ae98d","name":"Bert Spaan","login":"bertspaan","bio":"","home_url":"https://bertspaan.nl","tier":"public","approved":true,"description":""}],"collections":[],"files":[],"comments":[],"commenting_lock":null,"suggestion_from":null,"suggestions_to":[],"version":456,"title":"All Buildings in the Netherlands","license":null,"copyright":"","nodes":[{"id":0,"value":"md`# All Buildings in the Netherlands\n\nA few years ago, [I made a map](http://code.waag.org/buildings/) which showed all 9,866,539 buildings in the Netherlands, colored by their year of construction. People [really](https://www.citylab.com/equity/2013/10/delightfully-trippy-map-every-single-building-netherlands/7127/) [liked](https://www.theverge.com/2013/9/2/4683912/interactive-map-plots-out-nearly-10-million-netherlands-buildings-by) this map! In the meantime, many more new buildings were constructed, the data has become available via [a WFS server](https://www.pdok.nl/geo-services?articleid=1948911), and [Observable was released](https://beta.observablehq.com/@mbostock/why-observable).\n\nMove the [map below](#area), select which part of Holland you want to see, and save the visualization as PNG or SVG.\n\n_Note: the more you zoom out, the more buildings the visualization will likely contain. This can mean downloading tens of thousands of polygons from the server, and will slow down your computer. Be careful when zooming out! Please be kind to the WFS server!_\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":27,"value":"buildings = svg`<svg viewBox=\"0 0 ${width} ${height}\" class=\"buildings\">\n  <rect width=\"${width}px\" height=\"${height}px\" style=\"fill: black; stroke: none\" />\n\n  ${geojson.features.map(path).map((path, index) => svg`\n    <path d=\"${path}\" style=\"stroke: none; fill: ${color(geojson.features[index].properties.bouwjaar)}\"/>\n  `)}\n</svg>`","pinned":false,"mode":"js","data":null,"name":null},{"id":279,"value":"html`Download the map as a ${DOM.download(await rasterize(buildings), 'buildings', 'PNG file')} or as an ${DOM.download(serialize(buildings), 'buildings', 'SVG file')}.`","pinned":false,"mode":"js","data":null,"name":null},{"id":380,"value":"md`Move the map below to select an area (building data will only load if you are zoomed in):`","pinned":false,"mode":"js","data":null,"name":null},{"id":74,"value":"area = display(viewof bounds)","pinned":false,"mode":"js","data":null,"name":null},{"id":378,"value":"md`## Legend`","pinned":false,"mode":"js","data":null,"name":null},{"id":213,"value":"html`\n<div style=\"columns: 2;\">\n  ${bands.map((band, i) => html`\n  <div style=\"display: flex; align-items: center;\">\n    <span style=\"background-color: ${band[1]}; margin-right: 0.5em; width: 1.5em; height: 1em; display: inline-block; border: black 1px solid;\">\n    </span>\n    <span>\n      ${printBand(i)}\n    </span>\n  </div>\n  `)}\n</div>`","pinned":false,"mode":"js","data":null,"name":null},{"id":364,"value":"md`## Configuration`","pinned":false,"mode":"js","data":null,"name":null},{"id":123,"value":"bands = [\n  [1800, '#A50026'],\n  [1850, '#D73027'],\n  [1900, '#F46D43'],\n  [1930, '#FDAE61'],\n  [1945, '#FEE090'],\n  [1960, '#FFFFBF'],\n  [1975, '#E0F3F8'],\n  [1985, '#ABD9E9'],\n  [1995, '#74ADD1'],\n  [2005, '#4575B4'],\n  [Infinity, '#313695']\n]","pinned":false,"mode":"js","data":null,"name":null},{"id":40,"value":"height = 600","pinned":false,"mode":"js","data":null,"name":null},{"id":451,"value":"maxBuildings = 25000","pinned":false,"mode":"js","data":null,"name":null},{"id":373,"value":"md`## Data`","pinned":false,"mode":"js","data":null,"name":null},{"id":142,"value":"geojson = {\n  let first = true\n  let done = false\n\n  let stillResults = true\n  let requestsDone = 0\n  \n  const count = 1000\n  \n  let results = {\n    type: 'FeatureCollection',\n    features: []\n  }\n\n  const createUrl = (startIndex) => `https://geodata.nationaalgeoregister.nl/bag/wfs/v1_1?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:pand&outputFormat=json&srsName=urn:ogc:def:crs:EPSG:4326&count=${count}&startIndex=${startIndex}&bbox=${bounds.toBBoxString()},urn:ogc:def:crs:OGC:1.3:CRS84`\n\n  while (stillResults && results.features.length < maxBuildings) {\n    const geojson = await fetchGeojson(createUrl(requestsDone * count))\n    \n    if (geojson && geojson.features.length) {\n      results = {\n        type: 'FeatureCollection',\n        features: [...results.features, ...geojson.features]\n      }       \n    } else {\n      stillResults = false\n    }   \n    \n    yield results\n    requestsDone += 1\n  }\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":386,"value":"boundsGeoJSON = L.polygon([\n  bounds.getSouthWest(),\n  bounds.getSouthEast(),\n  bounds.getNorthEast(),\n  bounds.getNorthWest()\n]).toGeoJSON()","pinned":false,"mode":"js","data":null,"name":null},{"id":366,"value":"md`## Functions`","pinned":false,"mode":"js","data":null,"name":null},{"id":65,"value":"color = (year) => {\n  let i = 0\n  while (true) {\n    if (between(getBandYears(i), year)) {\n      return bands[i][1]\n    }\n    \n    i += 1\n  }\n}\n","pinned":false,"mode":"js","data":null,"name":null},{"id":320,"value":"printBand = (i) => {\n  if (i === 0) {\n    return `≤\t${bands[0][0]}`\n  } else if (i === bands.length - 1) {\n    return `≥\t${bands[bands.length - 2][0]}`\n  } else {\n    return `${bands[i - 1][0]}–${bands[i][0]}`\n  }\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":300,"value":"getBandYears = (i) => [i - 1 >= 0 ? bands[i - 1][0] : -Infinity, bands[i][0]]","pinned":false,"mode":"js","data":null,"name":null},{"id":150,"value":"fetchGeojson = (url) => fetch(url, {\n  mode: 'cors'\n}).then((response) => response.json())","pinned":false,"mode":"js","data":null,"name":null},{"id":202,"value":"viewof bounds = new View(\n  L.latLngBounds(L.latLng(52.1525194, 5.3794324), L.latLng(52.1604181, 5.4001176))\n)","pinned":false,"mode":"js","data":null,"name":null},{"id":198,"value":"function* display (bounds) {  \n  let container = DOM.element('div', {\n    style: `width:${width}px; height:${height}px` \n  })\n   \n  yield container\n  \n  let map = L.map(container, {\n    minZoom: 9,\n    maxZoom: 18\n  }).setView(bounds.value.getCenter(), 17)\n  let osmLayer = L.tileLayer('https://a.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n      attribution: '&copy; <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors'\n  }).addTo(map)\n  \n  map.on('moveend', () => {\n    if (map.getZoom() >= 14) {\n      bounds.value = map.getBounds()\n    }\n  })\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":132,"value":"between = (range, n) => n >= range[0] && n < range[1]","pinned":false,"mode":"js","data":null,"name":null},{"id":22,"value":"path = d3.geoPath()\n  .projection(projection)","pinned":false,"mode":"js","data":null,"name":null},{"id":35,"value":"projection = d3.geoMercator()\n  .center([bounds.getCenter().lat, bounds.getCenter().lng])\n  .fitSize([width, height], boundsGeoJSON)","pinned":false,"mode":"js","data":null,"name":null},{"id":375,"value":"md`## Imports`","pinned":false,"mode":"js","data":null,"name":null},{"id":72,"value":"L = require('leaflet@1.2.0')","pinned":false,"mode":"js","data":null,"name":null},{"id":70,"value":"html`<link href='${resolve('leaflet@1.2.0/dist/leaflet.css')}' rel='stylesheet' />`","pinned":false,"mode":"js","data":null,"name":null},{"id":184,"value":"import {rasterize, serialize} from \"@mbostock/saving-svg\"","pinned":false,"mode":"js","data":null,"name":null},{"id":200,"value":"import { View } from '@mbostock/synchronized-views'","pinned":false,"mode":"js","data":null,"name":null},{"id":23,"value":"d3 = require(\"d3@5\")","pinned":false,"mode":"js","data":null,"name":null}],"resolutions":[],"schedule":null,"last_view_time":null}