Public
Edited
Aug 15, 2023
Insert cell
Insert cell
Insert cell
mapContainer = html`<div style="height:600px"></div>`
Insert cell
Insert cell
buildingsUrl = "https://humusklimanetz-couch.thuenen.de/datasets/Utah.geojson.zip"
Insert cell
zipBuffer = {
console.time("downloading");
const ab = await fetch(buildingsUrl).then((res) => res.arrayBuffer());
console.timeEnd("downloading");
return ab;
}
Insert cell
Insert cell
geojson = {
// Unzip using fflate and convert to string
console.time("parsing");
const uint8 = fflate.unzipSync(new Uint8Array(zipBuffer))["Utah.geojson"];
const geojsonString = fflate.strFromU8(uint8);
const geojson = JSON.parse(geojsonString);
console.timeEnd("parsing");
return geojson;
}
Insert cell
Insert cell
areaMutatedGeojson = {
console.time("area");
for (let i = 0; i < geojson.features.length; ++i) {
const feature = geojson.features[i];
feature.properties.area = turf.area(feature);
}
console.timeEnd("area");
return geojson;
}
Insert cell
Insert cell
data = {
console.time("geojsonToBinary");
const bin = gis.geojsonToBinary(areaMutatedGeojson.features);
console.timeEnd("geojsonToBinary");
return bin;
}
Insert cell
Insert cell
colorScale = {
// Convert from value to RGB values
const lowerBound = 10;
const upperBound = 5000;
const linearScale = d3
.scaleLinear()
.domain([parseFloat(lowerBound), parseFloat(upperBound)])
.range([0, 1]);

// This is a fast vectorized approach: we store all colors in a single Float32Array instead of many small JS buffers
// Indices maps from geometry to vertex index
return (values, indices) => {
const vertexArrayLength = indices[indices.length - 1];
const outputArray = new Float32Array(vertexArrayLength * 3);
let lastIndex = 0;
for (let i = 0; i < indices.length - 1; ++i) {
let nextIndex = indices[i + 1];
const value = values[indices[i]];
const color = d3.color(d3.interpolateViridis(linearScale(value)));
const r = color.r / 255;
const g = color.g / 255;
const b = color.b / 255;
for (let j = lastIndex; j < nextIndex; ++j) {
outputArray[j * 3] = r;
outputArray[j * 3 + 1] = g;
outputArray[j * 3 + 2] = b;
}
lastIndex = nextIndex;
}

return outputArray;
};
}
Insert cell
Insert cell
colorAttribute = {
// On my computer, generating the color scale from the area array takes ~130ms.
// Check your browser console for your timing.
console.time("colorScale");
const result = colorScale(
data.polygons.numericProps.area.value,
data.polygons.polygonIndices.value
);
console.timeEnd("colorScale");
return result;
}
Insert cell
deckglLayer = {
const d = {
// Number of geometries
length: data.polygons.properties.length,
// Indices into coordinateArray where each polygon starts
startIndices: data.polygons.polygonIndices.value,
// Flat coordinates array
attributes: {
getPolygon: { value: data.polygons.positions.value, size: 2 },
getFillColor: { value: colorAttribute, size: 3 }
}
};
const layer = new deck.SolidPolygonLayer({
// This is an Observable hack - changing the id will force the layer to refresh when the cell reevaluates
id: `layer-${Date.now()}`,
data: d,
// Skip normalization for binary data
_normalize: false,
// Counter-clockwise winding order
_windingOrder: "CCW"
});

deckglMap.setProps({ layers: [layer] });

return layer;
}
Insert cell
deckglMap = {
// This is an Observable hack: clear previously generated content
mapContainer.innerHTML = "";

return new deck.DeckGL({
// The HTML container to render into
container: mapContainer,
map: mapboxgl,
mapStyle:
"https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json",

// Viewport settings
initialViewState: {
longitude: -111.89479567035976,
latitude: 40.69352652341092,
zoom: 12.739031655851761,
pitch: 0,
bearing: 0
},
controller: true,
onAfterRender: () => {
const now = new Date();

console.log(
"Total time since page load: " +
(now - window.performance.timing.navigationStart) +
" ms"
);
}
});
}
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
mapboxgl = require("mapbox-gl@1.6.0/dist/mapbox-gl.js")
Insert cell
deck = require.alias({
h3: {}
})("deck.gl@8.8.6/dist.min.js")
Insert cell
fflate = require("fflate")
Insert cell
turf = require("@turf/turf")
Insert cell
gis = import("https://cdn.skypack.dev/@loaders.gl/gis@3.4.9?min")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more