Manhattan demo
by felixp
HTML
<!DOCTYPE html>
<html>
<head>
<title>Manhattan demo</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- Only required for H3 Layer -->
<script src="https://unpkg.com/h3-js@^3.0.0"></script>
<script src="https://unpkg.com/[email protected]/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/[email protected]/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/[email protected]/dist.min.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css' rel='stylesheet' />
<script src="https://unpkg.com/range-slider-input@2"></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="map"></div>
<div id="range-slider"></div>
</body>
</html>
CSS
/* Always set the map height explicitly to define the size of the div element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#legend {
position: absolute;
top: 10px;
right: 10px;
opacity: 0;
transition: opacity 0.5s ease-in;
}
#range-slider {
width: calc(100vw - 50px);
margin: 30px 25px;
position: absolute;
bottom: 0px;
}
#range-slider .range-slider__thumb {
transition: transform .3s;
}
#range-slider .range-slider__thumb[data-active] {
transform: translate(-50%, -50%) scale(1.25);
}
JavaScript
const cartoMapId = '7fe0992f-ee41-4d6d-9dd2-8038d53368b4';
let deckgl = null;
let builderLayers = null;
let range = [1950, 1980];
let selectedPolygon = null;
async function fetchLayers() {
const {initialViewState, layers, mapStyle} = await deck.carto.fetchMap({cartoMapId});
builderLayers = layers;
deckgl = new deck.DeckGL({
container: 'map',
controller: true,
initialViewState,
mapStyle: `https://basemaps.cartocdn.com/gl/${mapStyle.styleType}-gl-style/style.json`
});
render();
}
fetchLayers();
function render() {
const [zipCodes, buildings, centroids] = builderLayers;
const layers = [
zipCodes.clone({
highlightColor: [255, 255, 255, 100],
onClick: e => {
selectedPolygon = e.object.geometry.coordinates;
render();
}
}),
selectedPolygon && new deck.SolidPolygonLayer({
id: 'mask',
operation: 'draw+mask',
data: [{polygon: selectedPolygon}]
}),
selectedPolygon && buildings.clone({
extensions: [
new deck.DataFilterExtension({filterSize: 1}),
new deck.MaskExtension(),
],
extruded: true,
elevationScale: 10,
getElevation: d => d.properties.numbldgs,
getFilterValue: f => f.properties.yearbuilt,
pickable: false,
filterRange: range,
maskId: 'mask',
}),
centroids.clone({
extensions: [
new deck.DataFilterExtension({filterSize: 1}),
new deck.CollisionFilterExtension(),
new deck.MaskExtension()
],
collisionTestProps: {radiusScale: 2},
getFilterValue: f => f.properties.yearbuilt,
filterRange: range,
pickable: false,
maskId: 'mask',
maskInverted: true
})
]
deckgl.setProps({layers});
}
rangeSlider(document.querySelector('#range-slider'), {
min: 1900, max: 2023, step: 01, value: range, onInput: newRange => {
range = newRange;
render();
}
});