-
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
Use setData operation when diffing geojson sources #5332
Changes from 3 commits
8799ae3
39bae05
5cf2dff
90c6b81
237d751
65bd757
ebae7f3
6e1a1ba
c0f9a92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,6 +102,12 @@ class SourceCache extends Evented { | |
} | ||
} | ||
|
||
setData(data: GeoJSON | string) { | ||
if (this._source && this._source.setData) { | ||
this._source.setData(data); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding this geojson-source-specific method to |
||
|
||
/** | ||
* Return true if no tile data is pending, tiles will not change unless | ||
* an additional API call is received. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,11 @@ const operations = { | |
*/ | ||
removeSource: 'removeSource', | ||
|
||
/* | ||
* { command: 'setData', args: ['sourceId', data] } | ||
*/ | ||
setData: 'setData', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's call this |
||
|
||
/* | ||
* { command: 'setLayerZoomRange', args: ['layerId', 0, 22] } | ||
*/ | ||
|
@@ -117,10 +122,15 @@ function diffSources(before, after, commands, sourcesRemoved) { | |
if (!before.hasOwnProperty(sourceId)) { | ||
commands.push({ command: operations.addSource, args: [sourceId, after[sourceId]] }); | ||
} else if (!isEqual(before[sourceId], after[sourceId])) { | ||
// no update command, must remove then add | ||
commands.push({ command: operations.removeSource, args: [sourceId] }); | ||
commands.push({ command: operations.addSource, args: [sourceId, after[sourceId]] }); | ||
sourcesRemoved[sourceId] = true; | ||
if (before[sourceId].type === 'geojson' && after[sourceId].type === 'geojson') { | ||
// geojson sources use setData command to update | ||
commands.push({ command: operations.setData, args: [sourceId, after[sourceId].data] }); | ||
} else { | ||
// no update command, must remove then add | ||
commands.push({ command: operations.removeSource, args: [sourceId] }); | ||
commands.push({ command: operations.addSource, args: [sourceId, after[sourceId]] }); | ||
sourcesRemoved[sourceId] = true; | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,8 @@ const supportedDiffOperations = util.pick(diff.operations, [ | |
'removeSource', | ||
'setLayerZoomRange', | ||
'setLight', | ||
'setTransition' | ||
'setTransition', | ||
'setData' | ||
// 'setGlyphs', | ||
// 'setSprite', | ||
]); | ||
|
@@ -500,6 +501,27 @@ class Style extends Evented { | |
this._changed = true; | ||
} | ||
|
||
/** | ||
* Set the data of a source, given its id. Only available for GeoJSON sources. | ||
* @param {string} id id of the source | ||
* @param {GeoJSON|string} data GeoJSON source | ||
* @throws {Error} if no source is found with the given ID | ||
*/ | ||
|
||
setData(id: string, data: GeoJSON | string) { | ||
this._checkLoaded(); | ||
|
||
if (this.sourceCaches[id] === undefined) { | ||
throw new Error('There is no source with this ID'); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is an internal invariant, please replace this check with just |
||
|
||
|
||
const sourceCache = this.sourceCaches[id]; | ||
|
||
sourceCache.setData(data); | ||
this._changed = true; | ||
} | ||
|
||
/** | ||
* Get a source by id. | ||
* @param {string} id id of the desired source | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -405,6 +405,7 @@ test('Style#setState', (t) => { | |
'setFilter', | ||
'addSource', | ||
'removeSource', | ||
'setData', | ||
'setLayerZoomRange', | ||
'setLight' | ||
].forEach((method) => t.stub(style, method).callsFake(() => t.fail(`${method} called`))); | ||
|
@@ -644,6 +645,64 @@ test('Style#removeSource', (t) => { | |
t.end(); | ||
}); | ||
|
||
test('Style#setData', (t) => { | ||
t.test('throw before loaded', (t) => { | ||
const style = new Style(createStyleJSON({ | ||
"sources": { "source-id": createGeoJSONSource() } | ||
}), new StubMap()); | ||
const geoJSONSourceData = { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { "type": "Point", "coordinates": [125.6, 10.1] } | ||
} | ||
] | ||
}; | ||
t.throws(() => { | ||
style.setData('source-id', geoJSONSourceData); | ||
}, Error, /load/i); | ||
style.on('style.load', () => { | ||
t.end(); | ||
}); | ||
}); | ||
|
||
t.test('throws on non-existence', (t) => { | ||
const style = new Style(createStyleJSON(), new StubMap()), | ||
geoJSONSourceData = { type: "FeatureCollection", "features": [] }; | ||
style.on('style.load', () => { | ||
t.throws(() => { | ||
style.setData('source-id', geoJSONSourceData); | ||
}, /There is no source with this ID/); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
t.test('sets data of source', (t) => { | ||
const style = new Style(createStyleJSON({ | ||
sources: {'source-id': createGeoJSONSource()} | ||
}), new StubMap()); | ||
const geoJSONSourceData = { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { "type": "Point", "coordinates": [125.6, 10.1] } | ||
} | ||
] | ||
}; | ||
style.on('style.load', () => { | ||
const sourceCache = style.sourceCaches['source-id']; | ||
t.spy(sourceCache, 'setData'); | ||
style.setData('source-id', geoJSONSourceData); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of testing |
||
t.ok(sourceCache.setData.calledWith(geoJSONSourceData)); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
t.end(); | ||
}); | ||
|
||
test('Style#addLayer', (t) => { | ||
t.test('throw before loaded', (t) => { | ||
const style = new Style(createStyleJSON(), new StubMap()), | ||
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 sosetData
can be called inStyle#setGeoJSONSourceData
. I'm getting a flow error ofproperty setData of unknown type
when I remove this line.There was a problem hiding this comment.
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 generalSource
interface, you can do the following insetGeoJSONSourceData
: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')
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Gotcha -- that makes sense