Skip to content
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

Use setData operation when diffing geojson sources #5332

Merged
merged 9 commits into from
Sep 26, 2017

Conversation

zjernst
Copy link

@zjernst zjernst commented Sep 20, 2017

#4914

When diffing the styles, if a geojson source is found with different data, perform a setData operation. Previously, the diff would cause a removeSource/addSource pair when a change was found, causing the source to flicker.

I'm migrating my project from performing all diffs myself to keeping a style state tree and utilizing the smarter setStyle that performs the necessary diffs, however the flickering was a noticeable downgrade to the experience.

First contribution, so feel free to tear it apart/offer a better implementation!

Copy link
Contributor

@anandthakker anandthakker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @zjernst thanks very much for this contribution!

A few comments inline, but it looks great overall.

if (this._source && this._source.setData) {
this._source.setData(data);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding this geojson-source-specific method to SourceCache, we can use sourceCache.getSource().setData(...) in the Style method handling this diff operation.

style.on('style.load', () => {
const sourceCache = style.sourceCaches['source-id'];
t.spy(sourceCache, 'setData');
style.setData('source-id', geoJSONSourceData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of testing style.setData(), could you please rework this test to use style.setState()? The latter is part of the interface of Style from the perspective of the rest of the codebase, whereas the former is essentially private. (Admittedly, this isn't very clearly documented or enforced at the moment.)


if (this.sourceCaches[id] === undefined) {
throw new Error('There is no source with this ID');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an internal invariant, please replace this check with just assert(this.sourceCaches[id] === undefined, 'There is no source with this ID')

@@ -44,6 +44,11 @@ const operations = {
removeSource: 'removeSource',

/*
* { command: 'setData', args: ['sourceId', data] }
*/
setData: 'setData',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call this setGeoJSONSourceData

@zjernst
Copy link
Author

zjernst commented Sep 22, 2017

@anandthakker Thanks for the review! Made changes to reflect your comments. Let me know how it looks

@@ -57,6 +57,7 @@ export interface Source {

+onAdd?: (map: Map) => void;
+onRemove?: (map: Map) => void;
+setData?: (data: GeoJSON | string) => Source;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover -- this can be removed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but I believe I still need to add this to the Source interface so setData can be called in Style#setGeoJSONSourceData. I'm getting a flow error of property setData of unknown type when I remove this line.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. setData is defined on GeoJSONSource. So, instead of adding it to the general Source interface, you can do the following in setGeoJSONSourceData:

const geojsonSource: GeoJSONSource = (this.sourceCaches[id].getSource(): any);
geojsonSource.setData()

Note that the use of : any essentially disables Flow's checking, so it should be used with caution. As a general practice, I try to include some sort of runtime check to accompany any use of : any -- e.g., assert(geojsonSource.type === 'geojson').

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Gotcha -- that makes sense

@anandthakker
Copy link
Contributor

@zjernst changes look good, thanks! One leftover: #5332 (review)

@jfirebaugh @mourner FYI, 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 I think we should go ahead with it and leave that for #3692

@zjernst
Copy link
Author

zjernst commented Sep 22, 2017

@anandthakker Thanks for your help! Think it should be good now

@anandthakker anandthakker merged commit e08f4fa into mapbox:master Sep 26, 2017
@anandthakker
Copy link
Contributor

Thanks again @zjernst 🎉 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants