Skip to content

Commit

Permalink
chore(examples) Use MapboxOverlay in mapbox (formerly safegraph) webs…
Browse files Browse the repository at this point in the history
…ite example (#8558)

* chore(examples) Use MapboxOverlay in mapbox website example

* rename safegraph folder to mapbox

* chore(examples) use react in mapbox website example

---------

Signed-off-by: Chris Gervang <chris@gervang.com>
  • Loading branch information
chrisgervang committed Mar 6, 2024
1 parent 5af293f commit 2e0fd4a
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 142 deletions.
File renamed without changes.
150 changes: 150 additions & 0 deletions examples/website/mapbox/app.jsx
@@ -0,0 +1,150 @@
import React, {useCallback, useState, useRef, useMemo} from 'react';
import {createRoot} from 'react-dom/client';
import {MapboxOverlay} from '@deck.gl/mapbox';
import {ArcLayer} from '@deck.gl/layers';
import {H3HexagonLayer} from '@deck.gl/geo-layers';
import {scaleLog} from 'd3-scale';
import {cellToLatLng} from 'h3-js';
import {load} from '@loaders.gl/core';
import {CSVLoader} from '@loaders.gl/csv';
import {Map, NavigationControl, useControl, Layer} from 'react-map-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

const DATA_URL =
'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/safegraph/sf-pois.csv';

// Set your mapbox token here
const MAPBOX_TOKEN = process.env.MapboxAccessToken; // eslint-disable-line

const colorScale = scaleLog()
.domain([10, 100, 1000, 10000])
.range([
[255, 255, 178],
[254, 204, 92],
[253, 141, 60],
[227, 26, 28]
]);

const buildings3DLayer = {
id: '3d-buildings',
source: 'composite',
'source-layer': 'building',
filter: ['==', 'extrude', 'true'],
type: 'fill-extrusion',
minzoom: 14,
paint: {
'fill-extrusion-color': '#ccc',
'fill-extrusion-height': ['get', 'height']
}
};

function DeckGLOverlay(props) {
const overlay = useControl(() => new MapboxOverlay(props));
overlay.setProps(props);
return null;
}

export default function App({data}) {
const [selectedPOI, setSelectedPOI] = useState('8a283082aa17fff');
const [firstLabelLayerId, setFirstLabelLayerId] = useState();
const mapRef = useRef();

const onMapLoad = useCallback(() => {
setFirstLabelLayerId(getFirstLabelLayerId(mapRef.current.getStyle()));
}, []);

const selectedPOICentroid = useMemo(() => {
const [lat, lng] = cellToLatLng(selectedPOI);
return [lng, lat];
}, [selectedPOI]);

const arcs = useMemo(() => filterArcs(data, selectedPOI), [data, selectedPOI]);

const hexes = useMemo(() => aggregateHexes(data), [data]);

const arcLayer = new ArcLayer({
id: 'deckgl-connections',
data: arcs,
getSourcePosition: d => selectedPOICentroid,
getTargetPosition: d => [d.home_lng, d.home_lat],
getSourceColor: [255, 0, 128],
getTargetColor: [0, 200, 255],
getWidth: d => Math.max(2, d.count / 15)
});

const poiLayer = new H3HexagonLayer({
id: 'deckgl-pois',
data: hexes,
opacity: 0.4,
pickable: true,
autoHighlight: true,
onClick: ({object}) => object && setSelectedPOI(object.hex),
getHexagon: d => d.hex,
getFillColor: d => colorScale(d.count),
extruded: false,
stroked: false,
beforeId: firstLabelLayerId
});

return (
<Map
ref={mapRef}
mapboxAccessToken={MAPBOX_TOKEN}
mapStyle="mapbox://styles/mapbox/light-v9"
antialias={true}
initialViewState={{
longitude: -122.4034,
latitude: 37.7845,
zoom: 15.5,
bearing: 20,
pitch: 60
}}
onLoad={onMapLoad}
>
<DeckGLOverlay interleaved={true} layers={[poiLayer, arcLayer]} />
<NavigationControl />
<Layer {...buildings3DLayer} />
</Map>
);
}

function filterArcs(data, selectedPOI) {
if (!data) {
return null;
}
return data.filter(d => d.hex === selectedPOI);
}

function aggregateHexes(data) {
if (!data) {
return null;
}
const result = {};
for (const object of data) {
if (!result[object.hex]) {
result[object.hex] = {hex: object.hex, count: 0};
}
result[object.hex].count += object.count;
}
return Object.values(result);
}

function getFirstLabelLayerId(style) {
const layers = style.layers;
// Find the index of the first symbol (i.e. label) layer in the map style
for (let i = 0; i < layers.length; i++) {
if (layers[i].type === 'symbol') {
return layers[i].id;
}
}
return undefined;
}

export function renderToDOM(container) {
const root = createRoot(container);
root.render(<App />);

load(DATA_URL, CSVLoader).then(data => {
root.render(<App data={data.data} />);
});
}
Expand Up @@ -3,7 +3,6 @@
<head>
<meta charset='UTF-8' />
<title>mapbox-custom-layer-example</title>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.13.0/mapbox-gl.css" rel="stylesheet" />
<style>
body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
Expand All @@ -23,7 +22,7 @@
<div id="app"></div>
</body>
<script type="module">
import {loadAndRender} from './app.js';
loadAndRender(document.getElementById('app'));
import {renderToDOM} from './app.jsx';
renderToDOM(document.getElementById('app'));
</script>
</html>
Expand Up @@ -11,8 +11,11 @@
"dependencies": {
"@loaders.gl/csv": "^4.1.0",
"d3-scale": "^2.0.0",
"deck.gl": "^9.0.0-alpha",
"mapbox-gl": "^2.0.0"
"deck.gl": "^9.0.0-beta",
"mapbox-gl": "^3.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-map-gl": "^7.0.0"
},
"devDependencies": {
"typescript": "^4.6.0",
Expand Down
File renamed without changes.
135 changes: 0 additions & 135 deletions examples/website/safegraph/app.js

This file was deleted.

4 changes: 2 additions & 2 deletions website/src/examples/mapbox.js
@@ -1,13 +1,13 @@
import React, {Component, createRef} from 'react';
import {DATA_URI, GITHUB_TREE} from '../constants/defaults';
import {renderToDOM} from 'website-examples/safegraph/app';
import {renderToDOM} from 'website-examples/mapbox/app';

import {makeExample} from '../components';

class MapboxDemo extends Component {
static title = 'Who Is Visiting San Francisco?';

static code = `${GITHUB_TREE}/examples/website/safegraph`;
static code = `${GITHUB_TREE}/examples/website/mapbox`;

static data = {
url: `${DATA_URI}/safegraph.txt`,
Expand Down

0 comments on commit 2e0fd4a

Please sign in to comment.