I’m using DeckGL with React to display some data on an OpenStreetMap. I’m planning on implementing some filters to be able to display different views on the data I have. My main problem is, that I can’t figure out how to refresh the data representing layer after filtering the data array.
I saw a bunch of people creating a DeckGL-Object in JavaScript, and then using this, to call deck.setProps()
but I couldn’t figure out how to render this DeckGL-Object by using react.
This is my app.js
:
export default function App({showBorder = false, onTilesLoad = null}) {
layers = [
/**
* TileLayer ist ein Layer aus Open-Streetmap-Tiles (Anzeigen der Karte)
*/
new TileLayer({
data: [/*OSM TileServer*/],
maxRequests: 20,
pickable: true,
onViewportLoad: onTilesLoad,
autoHighlight: showBorder,
highlightColor: [60, 60, 60, 40],
minZoom: 0,
maxZoom: 19,
tileSize: 512 / devicePixelRatio,
renderSubLayers: (props) => {
const {
bbox: {west, south, east, north}
} = props.tile;
return [
new BitmapLayer(props, {
data: null,
image: props.data,
bounds: [west, south, east, north]
}),
showBorder &&
new PathLayer({
id: `${props.id}-border`,
visible: props.visible,
data: [
[
[west, north],
[west, south],
[east, south],
[east, north],
[west, north]
]
],
getPath: (d) => d,
getColor: [255, 0, 0],
widthMinPixels: 4
})
];
}
}),
new HexagonLayer({
id: 'hexagon-layer',
data: /*JsonDataArray*/,
pickable: true,
extruded: true,
radius: 2000,
elevationRange: [25, 500],
elevationScale: 200,
autoHighlight: true,
opacity: 0.2,
colorRange: [
[255, 255, 204],
[199, 233, 180],
[127, 205, 187],
[65, 182, 196],
[44, 127, 184],
[37, 52, 148]
],
getElevationHeight: () => 500,
getPosition: (d) => d.coordinates,
})
];
return (
<DeckGL
layers={layers}
views={new MapView({repeat: true})}
initialViewState={INITIAL_VIEW_STATE}
controller={true}
/>
);
}
Obviously is there a little bit more to my app.js
but I don’t think the missing parts are important since I just wanna know how I can refresh a layer.
I also have a index.html
but I don’t think it’s content is really relevant either since it’s only use is to call the App
function to render the layers.
I just can’t find out what to do, to cause a reload of the HexagonLayer.
Thanks for your help in advance.
Advertisement
Answer
A good approach is using DataFilterExtension. GPU-based data filtering, go this way if you care about performance. For the moment there is a limitation of the extension for
HexagonLayer
, but maybe usingGPUGridLayer
can help you in your visualization also.I.e: let’s say you want to filter your qualitative data.
filterRange
needs numeric bounds (which defines whether an object should be rendered), so you can set your bounds as[1, 1]
and check if some object matches with you current filter condition, if matches,getFilterValue
gets 1, so that object will be rendered, otherwise, not rendered:JavaScript118181const [filterCondition, setFilter] = useState('');
2
3useEffect(() => {
4// dispatch some action to set the filter
5setFilter('cities');
6}, []);
7
8new ScatterplotLayer({
9otherProps,
10getFilterValue: object => object.properties.target === filterCondition ? 1 : 0,
11filterRange: [1, 1],
12extensions: [new DataFilterExtension({ filterSize: 1 })],
13updateTriggers: {
14// It's important to tell deck.gl when to update
15getFilterValue: filterCondition
16}
17});
18
Otherwise updating you
data
array should be enough. That means a CPU-based data filtering, if your data is not huge, it’s okey. Thanks to reactivity should be enough with something like this:JavaScript121211const [yourData, setData] = useState([]);
2
3useEffect(() => {
4// dispatch some action to set data
5setData([newData]);
6}, []);
7
8const layers = [
9new HexagonLayer({
10otherProps,
11data: yourData
12});
13];
14
15return (
16<DeckGL
17otherProps,
18layers={layers}
19/>
20);
21
P.D: deck.setProps()
is recommended to use in a non-reactive environment