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.

zacdav
  • 4,603
  • 2
  • 16
  • 37
  • can you please provide an example on https://codesandbox.io/s/? and what exactly you expect to be changed by slider? `hr00 ... hr06`? – n1stre Feb 09 '19 at 13:32
  • 1
    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. – zacdav Feb 09 '19 at 13:35

1 Answers1

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

n1stre
  • 5,856
  • 4
  • 20
  • 41
  • 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. – zacdav Feb 09 '19 at 22:28
  • Updated. Just `.bind` it in a `constructor` instead of using an arrow func – n1stre Feb 09 '19 at 22:35
  • @streletss would this be similar if i want to programmatically change the visible property? Thanks! – Florin Vîrdol Apr 28 '21 at 14:18
  • 1
    @FlorinVîrdol check out https://deck.gl/docs/api-reference/core/layer#visible – n1stre Apr 29 '21 at 08:17