change layer property based on slider input with deck.gl
Asked Answered
R

1

8

I am following an example provided on the deck.gl github repository that displays polygons from a geojson.

I've since changed the initial focus of the map and provided my own geojson to visualise, the data I've replaced the examples with has a temporal component that I'd like to visualise via the manipulation of a range input.


Example GeoJSON Structure

{
"type": "FeatureCollection",
"name": "RandomData",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature",
    "properties": { "id": 1,"hr00": 10000, "hr01": 12000, "hr02": 12000, "hr03": 30000, "hr04": 40000, "hr05": 10500, "hr06": 50000}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 103.73992, 1.15903 ], [ 103.74048, 1.15935 ], [ 103.74104, 1.15903 ], [ 103.74104, 1.15837 ], [ 103.74048, 1.15805 ], [ 103.73992, 1.15837 ], [ 103.73992, 1.15903 ] ] ] } } ] }

Instead of repeating each geometry for every timepoint I've shifted the temporal aspect of the data to the properties. This makes the file size manageable on the complete dataset (~50mb versus ~500mb).


For visualising a single time point I know that I can provide the property to getElevation and getFillColor.

_renderLayers() {
    const {data = DATA_URL} = this.props;

    return [
      new GeoJsonLayer({
        id: 'geojson',
        data,
        opacity: 0.8,
        stroked: false,
        filled: true,
        extruded: true,
        wireframe: true,
        fp64: true,
        getElevation: f => f.properties.hr00,
        getFillColor: f => COLOR_SCALE(f.properties.hr00),
        getLineColor: [255, 255, 255],
        lightSettings: LIGHT_SETTINGS,
        pickable: true,
        onHover: this._onHover,
        transitions: {
          duration: 300
        }
      })
    ];
  }

So I went ahead and used range.slider, adding code to my app.js, this following snippet was added. I believe I also may be placing this in the wrong location, should this exist in render()?

import ionRangeSlider from 'ion-rangeslider';

// Code for slider input
$("#slider").ionRangeSlider({
      min: 0,
      max: 24,
      from: 12,
      step: 1,
      grid: true,
      grid_num: 1,
      grid_snap: true
  });
$(".js-range-slider").ionRangeSlider();

added to my index.html

<input type="text" id="slider" class="js-range-slider" name="my_range" value=""/>

So how can I have the slider change which property of my geojson is being supplied to getElevation and getFillColor?

My JavaScript/JQuery is lacking and I have been unable to find any clear examples of how to change the data property based on the input, any help is greatly appreciated.

Here is a codesandbox link - doesn't seem to like it there however. Locally with npm install and npm start should have it behave as intended.

Rouse answered 7/2, 2019 at 12:48 Comment(2)
can you please provide an example on codesandbox.io/s? and what exactly you expect to be changed by slider? hr00 ... hr06?Scalade
The slider will be a range from 0-24 which would determine the property of the geojson to use within the GeoJsonLayer. I'll look at the website and try upload an example when I wake up.Rouse
S
4

At first you'll need to tell your dependent accessors about the value that is going to be changed by the slider. This can be done by using updateTriggers:

_renderLayers() {
  const { data = DATA_URL } = this.props;

  return [
    new GeoJsonLayer({
      // ...
      getElevation: f => f.properties[this.state.geoJsonValue],
      getFillColor: f => COLOR_SCALE(f.properties[this.state.geoJsonValue]),

      updateTriggers: {
        getElevation: [this.state.geoJsonValue],
        getFillColor: [this.state.geoJsonValue]
      }
      // ...
    })
  ];
}

And to actually change this value using range-slider you need to add onChange callback during the initialization:

constructor(props) {
    super(props);
    this.state = { hoveredObject: null, geoJsonValue: "hr01" };
    this.sliderRef = React.createRef();
    this._handleChange = this._handleChange.bind(this);
    // ...
}

componentDidMount() {
  // Code for slider input
  $(this.sliderRef.current).ionRangeSlider({
    // ...
    onChange: this._handleChange
  });
}

_handleChange(data) {
  this.setState({
    geoJsonValue: `hr0${data.from}`
  });
}

render() {
  ...
  <DeckGL ...>
    ...
  </DeckGL>

  <div id="sliderstyle">
    <input
      ref={this.sliderRef}
      id="slider"
      className="js-range-slider"
      name="my_range"
    />
  </div>

  ...
}

And this is basically it. And here is the full code

Scalade answered 9/2, 2019 at 18:14 Comment(4)
This is great, I was wondering if you could do something like hr0${data.from} but didn't see an example until now. However However _handleChange() = data => {...}` is giving me an "Unexpected token (87:18)" error when I run npm start with changes you've provided.Rouse
Updated. Just .bind it in a constructor instead of using an arrow funcScalade
@streletss would this be similar if i want to programmatically change the visible property? Thanks!Plantation
@FlorinVîrdol check out deck.gl/docs/api-reference/core/layer#visibleScalade

© 2022 - 2024 — McMap. All rights reserved.