question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Update styles from arrays

See original GitHub issue

Previously, we’ve animated line and point features by getting access to the WebGL Float32Arrays used for specific styles, such as opacity or color, modified those arrays, and then rerendered. This is very fast, but requires knowledge of internal data structures. For unclustered points, for instance, each point has a a record that has some number of vertices per point (which could be 1, 3, or 4 depending on how we constructed the point feature). The user has to know to use this value.

As an alternative, if we added a function to set styles from arrays, the generic mode would just update that style by converting the array to a function:

this.styleFromArray = function (key, styleArray, refresh) {
  this.style(key, function (d, i) {
    return styleArray[i];
  });
  if (refresh && this.visible()) {
    this.draw();
  }
  return(this);
}

The styleArray contents in this example would be not be functions. This means for lines and polygons, there would be one value for each line or polygon regardless of how many line segments or vertices they had.

Perhaps this could also take a dictionary of style keys and their associated arrays as a convenience to avoid having to call the function multiple times for multiple concurrent style changes.

For features where we chose to optimize things, the subclass could provide an extra method to accelerate updates. For instance, in the gl_pointFeature, this function could be:

s_styleFromArray = <parent>.styleFromArray;
this.styleFromArray = function (key, styleArray, refresh) {
  if (this.visible() {
    var vpf, mapper, buffer, numPts, value, i, j, v;
    switch (key) {
      case 'fillOpacity': case 'strokeOpacity':
        numPts = this.data().length;
        mapper = this.actors()[0].mapper();
        buffer = mapper.getSourceBuffer(key);
        vpf = this.verticesPerFeature();
        if (!buffer || !numPts || numPts * vpf !== buffer.length) {
          break;
        }
        for (i = 0, v = 0; i < numPts; i += 1) {
          value = styleArray[i];
          for (j = 0; j < vpf; j += 1, v += 1) {
            buffer[v] = value;
          }
        }
        mapper.updateSourceBuffer(key);
        // I'll have to check if this causes a refresh or not, but we don't need to refresh from the superclass call
        refresh = false;
        break;
    }
  }
  // we always need to update the style to keep the overall state consistent.
  return s_styleFromArray(key, styleArray, refresh);
}

There are a few dangers to this optimization: (a) the values extracted from styleArray are not checked for validity, so passing bad values will do odd things, (b) for efficiency some styles will be necessarily more restrictive than they are in general. For instance, colors would need to be in {r: <value>, g: <value>, b: <value>} rather than our permissive css possibly with opacity processing we currently do, © it may not work with certain features, such as point clustering, (d) this doesn’t give access to per-vertex values of lines and polygons. All of this could be worked around, but for animations, speed is paramount, so any checks and validation need to be very quick – for instance, we could skip the fast path if points are clustered.

Thoughts?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:17 (17 by maintainers)

github_iconTop GitHub Comments

2reactions
mantheycommented, Mar 31, 2017

I’ve got a fist pass of this working on my local machine, with just the pointFeature optimized for radius, fill, fillOpacity, stroke, strokeOpacity, and strokeWidth. Initially, while animating 4 styles (radius, fillOpacity, strokeOpacity, and strokeWidth) with 10% of the points having any opacity in any given frame, I get 60 fps for 500,000 points, 30 fps for 1,000,000 and 15 fps for 2,000,000.

1reaction
mantheycommented, Mar 30, 2017

updateStyleFromArray sounds fine to me.

Read more comments on GitHub >

github_iconTop Results From Across the Web

javascript - How do I change the style of a character in an array?
I have a div#effect in my HTML which of the text inside is written from the JavaScript I've put here, I want to...
Read more >
Updating Arrays in State - React Docs
If you want to change some or all items of the array, you can use map() to create a new array. The function...
Read more >
Component styles - Angular
The styles property takes an array of strings that contain CSS code. ... for customizing styles, using template bindings to update CSS classes...
Read more >
eslint-plugin-react-native/no-single-element-style-arrays.md at ...
No Single Element Style Arrays are allowed. These cause unnecessary re-renders as each time the array's identity changes.
Read more >
Array.prototype.fill() - JavaScript - MDN Web Docs - Mozilla
The fill() method is a mutating method. It does not alter the length of this , but it will change the content of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found