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.
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 using GPUGridLayer
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:
const [filterCondition, setFilter] = useState('');
useEffect(() => {
// dispatch some action to set the filter
setFilter('cities');
}, []);
new ScatterplotLayer({
...otherProps,
getFilterValue: object => object.properties.target === filterCondition ? 1 : 0,
filterRange: [1, 1],
extensions: [new DataFilterExtension({ filterSize: 1 })],
updateTriggers: {
// It's important to tell deck.gl when to update
getFilterValue: filterCondition
}
});
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:
const [yourData, setData] = useState([]);
useEffect(() => {
// dispatch some action to set data
setData([newData]);
}, []);
const layers = [
new HexagonLayer({
...otherProps,
data: yourData
});
];
return (
<DeckGL
...otherProps,
layers={layers}
/>
);
P.D: deck.setProps()
is recommended to use in a non-reactive environment