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: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