Update styles from arrays
See original GitHub issuePreviously, 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:
- Created 6 years ago
- Reactions:1
- Comments:17 (17 by maintainers)

Top Related StackOverflow Question
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.
updateStyleFromArraysounds fine to me.