Deck.gl: Updating getColor with updateTriggers not working

Created on 25 Jul 2018  路  8Comments  路  Source: visgl/deck.gl

Hi all, I've been visualizing some flight data in a unique way using the line layer class. I am using data that was collected every 10 seconds and therefore have a lot of line segments which are parts of a total flight. I want to slice what data is visible based on time and for that I have created a slider overlay whose value defines the minimum time visible. I am _trying_ to control the opacity of every line segment based on the changing time range. I am using the scripting version of deck and I cannot figure out for the life of me why the updateTriggers is not working. The documentation isn't giving me much help as I did exactly as it said.

Here's the deck layer code :

      new deck.LineLayer({
        id: 'flight-paths',
        data: 'exampleUrl', 
        fp64: false,
        getSourcePosition: d => {
            return [d.position[0], d.position[1], d.altitude]
        },
        getTargetPosition: d => {
            return [d.nextPos[0], d.nextPos[1], d.nextAlt]
        },
        getColor: d => {
            var color = (d.altitude < 0 ? [0,0,0] :
                (d.altitude < 2500 ? colors[0] : 
                    (d.altitude < 5000 ? colors[2] : 
                        (d.altitude < 7500 ? colors[2] : colors[3])
                    )
                )
            );
            var opacity = 0;
            if(d.time > tmin && d.time < tmax)
            {
                opacity = 60;
            }
            else{
                opacity = 0; 
            }
            return [color[0], color[1], color[2], opacity];
        },
        getStrokeWidth: function(){
            return

And here's the slider code in the same file above the declaration of the deck object. The sliders change the values of tmin, tmax, and stroke. Neither the stroke nor color update when the values are changed on the html sliders.

    var stroke = 30
    var tmin = 1525244400.0
    var tmax  = tmin + 7200.0 //in seconds
    var timeSlider = document.getElementById("timeSlider");
    var strokeSlider = document.getElementById("strokeSlider");
    timeSlider.oninput = function() {
        tmin = this.value;
        tmax = parseFloat(tmin) + 3600;
        console.log(tmax, tmin)
    }
    strokeSlider.oninput = function(){
        stroke = this.value;
        console.log(stroke)
    }
FAQ

Most helpful comment

for these examples that include the control panel and are not just the barebones demo.

Noted. That is a good point. We have kept the controls panels separated in the demos for a couple of reasons, but maybe we should rethink this to improve the usefulness of the examples.

If I wanted to, say, change the opacity of a layer, Is my only option to create a new layer with the same Id and different properties?

Yes. deck.gl is a "reactive" application architecture and is optimized to be used like this. The layer and its props are essentially only a "descriptor", deck.gl matches and "diffs" the layers under the hood and only does the necessary changes based on actual differences compared to last layer.

This is a "functional" take on programming that is in fashion now, and it parallels key ideas in the widely used React library. I do agree that if you are coming from a more "imperative" programming experience, it can initially seem a little counter-intuitive (especially from a performance perspective).

The reactive architecture has big benefits when writing bigger applications, but these are not as evident when writing smaller scripts. Regardless, in spite of how the API looks, performance should be very good, you are welcome to ping us again if this is not the case.

Maybe we should add some text like this to get-started docs...

All 8 comments

I believe updateTriggers just tells deck.gl to update the keys provided when redrawn (otherwise it would leave them). You still need to trigger the update of the layer by calling the function that defines the lineLayer again in your code, it's not a "watch" in that sense.

The updateTriggers object informs deck.gl not to skip recalculating those values, which it otherwise would do for performance reasons.

So in your case, in your oninput functions, at the bottom, you'll want to call the function that redraws the layer. This is not a hack and how deck.gl is intended to work.

I encountered this issue too, and agree it might be more helpful if the docs were more explicit that updateTriggers is not a watch.

I see! I was able to find an example under the geojson example where they updated layer properties when needed. This worked, however I don't know if it is the most efficient way to do things.
I basically used the function in the code that they called redraw:

// Update deck.gl layers
function redraw() {

const layers = [
  new GeoJsonLayer({
    id: 'geojson',
    data: 'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/highway/roads.json',
    opacity: 1,
    stroked: false,
    filled: false,
    lineWidthMinPixels: 1,
    parameters: {
      depthTest: false
    },

    getLineColor: getLineColor,
    getLineWidth: getLineWidth,

    pickable: true,
    onHover: updateTooltip,

    updateTriggers: {
      getLineColor: {year},
      getLineWidth: {year}
    },

    transitions: {
      getLineColor: 1000,
      getLineWidth: 1000
    }
  })
];

deckgl.setProps({layers});

}

Maybe I'm just blind, but I can't seem to find solid documentation on a lot of the features deck _seems_ to have.

Maybe I'm just blind, but I can't seem to find solid documentation on a lot of the features deck seems to have.

Have you looked at http://deck.gl/#/documentation/developer-guide/optimizing-updates?section=update-triggers? If so, can you give any hints on why it did not give the right information?

Or, if you haven't read it, that basically shows the need for a better doc search function. We are overdue to introduce a search mechanism for the deck.gl docs, we have that feature in some of our other repos. We should bite the bullet and refactor deck.gl docs so that we can introduce it..

Writing docs is a big task, we try our best, but the framework is developing at a high pace so things do get out of date etc. Hints from users on what is hard to find/understand are valuable, feel free to give us your list...

can you give any hints on why it did not give the right information?

I'm not a very experienced documentation reader nor am I very experienced with deck or javascript or react. I'm assuming that's most of the problem. However, another problem I've been having is that I cannot find nearly any examples with interactivity that have source code. The deck examples page has a control panel for most demos which boasts interactivity but I can't for the life of me figure out where I can find the code for these examples that include the control panel and are not just the barebones demo.

Like @oller said above, I was under the impression that having updateTriggers would somehow rerender the changed layer. Like he stated,

...it might be more helpful if the docs were more explicit that updateTriggers is not a watch.

I'm still very confused as to how layer updates and renderings are handled when working with changing layer properties and not just data. If I wanted to, say, change the opacity of a layer, Is my only option to create a new layer with the same Id and different properties? I'm probably missing something huge in the documentation about layer rendering but I couldn't find a simple answer to that question.

Just wanted to say that I appreciate the support this issue recieved- I didn't realize how active deck's development is! 馃憤

for these examples that include the control panel and are not just the barebones demo.

Noted. That is a good point. We have kept the controls panels separated in the demos for a couple of reasons, but maybe we should rethink this to improve the usefulness of the examples.

If I wanted to, say, change the opacity of a layer, Is my only option to create a new layer with the same Id and different properties?

Yes. deck.gl is a "reactive" application architecture and is optimized to be used like this. The layer and its props are essentially only a "descriptor", deck.gl matches and "diffs" the layers under the hood and only does the necessary changes based on actual differences compared to last layer.

This is a "functional" take on programming that is in fashion now, and it parallels key ideas in the widely used React library. I do agree that if you are coming from a more "imperative" programming experience, it can initially seem a little counter-intuitive (especially from a performance perspective).

The reactive architecture has big benefits when writing bigger applications, but these are not as evident when writing smaller scripts. Regardless, in spite of how the API looks, performance should be very good, you are welcome to ping us again if this is not the case.

Maybe we should add some text like this to get-started docs...

Thank you for your response and feedback! I'll look more into react integration but I think I now have a better understanding on how to implement deck correctly.

Reopening and marking as candidate for a new FAQ page in the docs

I'm trying to reconcile this comment from @oller earlier in the thread

  1. > You still need to trigger the update of the layer by calling the function that defines the lineLayer again in your code, it's not a "watch" in that sense

And other docs on updateTriggers, for example this comment from @Pessimistress

  1. > The "trigger" value may be a string, object or function - as long as it can be shallow-compared with the previous value.

If we were using

    updateTriggers: {
        getColor: {c1: maleColor, c2: femaleColor}
    }

Do the objects/functions/values maleColor or femaleColor need to call the function which draws the layer (as suggested in comment 1), or does the updateTrigger simply 'observe' the changes to maleColor and femaleColor ?

Was this page helpful?
0 / 5 - 0 ratings