-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatically batch the work done by GeoJSON#setData() #3692
Comments
cc @kronick |
This sounds great and addresses the issue I ran into pretty quickly once I started trying out some relatively complicated animations. Just thinking about the API for this, ideally I would be able to do:
Would it be possible to integrate the
Which is awkward 1) because for correctness you should call |
This would be possible syntactically if Conceptually, this nesting would not result in the optimal animation loop. In the worst case, the time between calls to
We should debug this race condition.
Agreed 👍 |
All you should need to do with this API is the following: function animate() {
source.setData(myData);
map.requestDataUpdateFrame("sourcename", animate);
} (note that we call |
In conjunction with this method it may be wise to add a warning when the map's event queue becomes backlogged, suggesting the use of |
Agreed on the _.debounce(requestSetDataFrame(), delayTime, function reportError(e) { console.log(e) } ) Is it possibly to abstract this function to work well with While performance is best with |
Good question. This would make sense to me as a callback to each of those functions. Otherwise we'll have |
I'm not sure I understand.
The proposed implementation of Can you think of a name for this method that makes it more apparent it can be used with all
I'm not aware of any strong arguments against completion callbacks. Completion callbacks are a different feature and deserve a separate discussion in a separate issue. They do not address the same need as
|
I think this can be done without adding something to the external api: From a user's perspective:
implementation: GeoJSONSource.prototype._queuedData = null;
GeoJSONSource.prototype._currentlySettingData = false;
GeoJSONSource.prototype.setData = function(data) {
if (!this._currentlySettingData) {
this._currentlySettingData = true;
this.actualSetData(data, done.bind(this));
} else {
this._queuedData = data;
}
function done() {
this._currentlySettingData = false;
var data = this._queuedData;
if (data) {
delete this._queuedData;
this.setData(data);
}
}
}; This has the advantage of working automatically without any extra effort from the user. They just call The downside is that the work the user does before calling
|
@ansis I really like this option-- especially how it automatically uses data from the most recent call. This behavior is what I would almost always want, and I think you're right that asking the user to throttle their own calls is not a major burden (which |
Good points @ansis. I'm in favor of automatic throttling as you propose.
Can you think of any cases where the data update wouldn't be cheap and access to this primitive would be necessary? |
I can't think of anything right now. And if we add a callback to |
This change makes setStyle() smarter by using GeoJSONSource#setData() when possible, rather than always removing/re-adding the source. It _doesn't_ currently defer the setData() work to the once-per-frame batch update (Style#update()), but that should happen as part of #3692 * setData for geojson source on setStyle diff * add style tests for setData * diff test for setData * remove from SourceCache and test uses setState * remove from SourceCache and test uses setState * remove leftover * add setData back to Source interface * add flow check and validation to Style#setGeoJSONSourceData
@lucaswoj @kronick I stumbled into this problem without realizing this issue already existed, and implemented a PR that does After reading through this issue, I think it'll address the main concerns here without requiring any API changes, but please correct me if I'm missing something. |
#5902 has merged and removes the potential for developing a There are definitely cases where you'd want to do further throttling/debouncing, but it depends on the application. For doing interactive animation with a small set of GeoJSON, you probably don't want any throttling because you want the "frame rate" of the animation to be as high as possible, and the cost of continually reloading the GeoJSON is not that bad. On the other hand, I can image an application that needs to frequently update a large set of GeoJSON but isn't trying to make a smooth animation -- in that case, it might work best for the application itself to implement something like a 1s update frequency. Please re-open if you think there's still an important case for something like the |
@ChrisLoer Does this mean we can call Our current workaround was to only request an animation frame, when the source which has been updated (via setData) fired a |
@Scarysize This removes one cause of stuttering, but if you're calling The difference is that (1) no backlog will develop, and (2) if other (non GeoJSON) tile requests come in to the worker that's handling GeoJSON, they'll get a chance to be processed before the next |
Okay, that sounds like a step in the right direction concerning animations 👍 If you need feedback on further experiments feel free to reach out, we got some projects depending on animations with mapbox-gl :) |
Re-fixed with #5988. |
I'm currently using this to avoid setData congestion (should work for multiple sources too) function animate () {
if (!map.isSourceLoaded('source'))
return requestAnimationFrame(animate) //wait until the next frame
map.getSource('source').setData(data)
requestAnimationFrame(animate)
})
animate() |
Now we using 0.47.0. |
If is relatively common for users to animate geometries on the map using
GeoJSONSource#setData
It can be hard to do so performantly and without causing the queue of data update operations to become seriously clogged.
We could make this use of GL JS easier via a new
Map#requestSetDataFrame(sourceId: string, callback: Function)
method (analogous torequestAnimationFrame
).The text was updated successfully, but these errors were encountered: