Skip to content

Commit 94d2bf4

Browse files
Slight mods to PR 6800 (#6809)
* mods * code review changes * revert parameter * fix comment * comment, revert formatting * link and spacing * more * flatten updateable * rename variable --------- Co-authored-by: wayofthefuture <[email protected]>
1 parent e430c63 commit 94d2bf4

File tree

3 files changed

+63
-35
lines changed

3 files changed

+63
-35
lines changed

src/source/geojson_source.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ describe('GeoJSONSource.shoudReloadTile', () => {
977977

978978
expect(result).toBeTruthy();
979979
});
980-
980+
981981
test('returns false when tile contains a feature that is being removed but was never added', async () => {
982982
const diff: GeoJSONSourceDiff = {remove: [0]};
983983
let shouldReloadTileOptions: GeoJSONSourceShouldReloadTileOptions = undefined;
@@ -1030,7 +1030,7 @@ describe('GeoJSONSource.shoudReloadTile', () => {
10301030

10311031
expect(result).toBe(false);
10321032
});
1033-
1033+
10341034
test('handles string feature ids and returns no bounds since feature does not exist', async () => {
10351035
const diff: GeoJSONSourceDiff = {remove: ['abc']};
10361036

@@ -1060,4 +1060,4 @@ describe('GeoJSONSource.shoudReloadTile', () => {
10601060
expect(shouldReloadTileOptions).toBeUndefined();
10611061
});
10621062

1063-
});
1063+
});

src/source/geojson_source.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,8 @@ export class GeoJSONSource extends Evented implements Source {
417417
this.fire(new Event('dataabort', {dataType: 'source'}));
418418
return;
419419
}
420-
const affectedBounds = this._applyDiffIfNeeded(diff);
420+
const affectedGeometries = this._applyDiffToSource(diff);
421+
const shouldReloadTileOptions = this._getShouldReloadTileOptions(affectedGeometries);
421422

422423
let resourceTiming: PerformanceResourceTiming[] = null;
423424
if (result.resourceTiming && result.resourceTiming[this.id]) {
@@ -432,7 +433,7 @@ export class GeoJSONSource extends Evented implements Source {
432433
// although GeoJSON sources contain no metadata, we fire this event to let the TileManager
433434
// know its ok to start requesting tiles.
434435
this.fire(new Event('data', {...eventData, sourceDataType: 'metadata'}));
435-
this.fire(new Event('data', {...eventData, sourceDataType: 'content', shouldReloadTileOptions: affectedBounds !== undefined ? {affectedBounds} : undefined}));
436+
this.fire(new Event('data', {...eventData, sourceDataType: 'content', shouldReloadTileOptions}));
436437
} catch (err) {
437438
this._isUpdatingWorker = false;
438439
if (this._removed) {
@@ -449,14 +450,15 @@ export class GeoJSONSource extends Evented implements Source {
449450
}
450451

451452
/**
452-
* Apply a diff to the source data and return the bounds of the affected geometries.
453-
* @param diff - The diff to apply.
454-
* @returns The bounds of the affected geometries, undefined if the diff is not applicable or all geometries are affected.
453+
* Apply a diff to this source's data and return the affected feature geometries.
454+
* @param diff - The {@link GeoJSONSourceDiff} to apply.
455+
* @returns The affected geometries, or undefined if the diff is not applicable or all geometries are affected.
455456
*/
456-
private _applyDiffIfNeeded(diff: GeoJSONSourceDiff): LngLatBounds[] | undefined {
457+
private _applyDiffToSource(diff: GeoJSONSourceDiff): GeoJSON.Geometry[] | undefined {
457458
if (!diff) {
458459
return undefined;
459460
}
461+
460462
const promoteId = typeof this.promoteId === 'string' ? this.promoteId : undefined;
461463

462464
// Lazily convert `this._data` to updateable if it's not already
@@ -472,13 +474,26 @@ export class GeoJSONSource extends Evented implements Source {
472474
}
473475
const affectedGeometries = applySourceDiff(this._data.updateable, diff, promoteId);
474476

475-
if (this._options.cluster || diff.removeAll) {
477+
if (diff.removeAll || this._options.cluster) {
476478
return undefined;
477479
}
478-
479-
return affectedGeometries
480+
481+
return affectedGeometries;
482+
}
483+
484+
/**
485+
* Get options for use in determining whether to reload a tile based on the modified features.
486+
* @param affectedGeometries - The feature geometries affected by the update.
487+
* @returns A {@link GeoJSONSourceShouldReloadTileOptions} object which contains an array of affected bounds caused by the update.
488+
*/
489+
private _getShouldReloadTileOptions(affectedGeometries: GeoJSON.Geometry[]): GeoJSONSourceShouldReloadTileOptions | undefined {
490+
if (!affectedGeometries) return undefined;
491+
492+
const affectedBounds = affectedGeometries
480493
.filter(Boolean)
481494
.map(g => getGeoJSONBounds(g));
495+
496+
return {affectedBounds};
482497
}
483498

484499
/**
@@ -492,7 +507,8 @@ export class GeoJSONSource extends Evented implements Source {
492507
if (tile.state === 'unloaded') {
493508
return false;
494509
}
495-
// Update the tile if it WILL NOW contain an updated feature.
510+
511+
// Update the tile if contained or will contain an updated feature.
496512
const {buffer, extent} = this.workerOptions.geojsonVtOptions;
497513
const tileBounds = tileIdToLngLatBounds(
498514
tile.tileID.canonical,
@@ -503,6 +519,7 @@ export class GeoJSONSource extends Evented implements Source {
503519
return true;
504520
}
505521
}
522+
506523
return false;
507524
}
508525

src/source/geojson_source_diff.ts

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -106,55 +106,66 @@ export function isUpdateableGeoJSON(data: GeoJSON.GeoJSON | undefined, promoteId
106106
}
107107

108108
export function toUpdateable(data: UpdateableGeoJSON, promoteId?: string) {
109-
const result = new Map<GeoJSONFeatureId, GeoJSON.Feature>();
109+
const updateable = new Map<GeoJSONFeatureId, GeoJSON.Feature>();
110+
111+
// empty updateable
110112
if (data == null || data.type == null) {
111-
// empty result
112-
} else if (data.type === 'Feature') {
113-
result.set(getFeatureId(data, promoteId)!, data);
114-
} else {
115-
for (const feature of data.features) {
116-
result.set(getFeatureId(feature, promoteId)!, feature);
117-
}
113+
return updateable;
114+
}
115+
116+
if (data.type === 'Feature') {
117+
updateable.set(getFeatureId(data, promoteId)!, data);
118+
return updateable;
119+
}
120+
121+
for (const feature of data.features) {
122+
updateable.set(getFeatureId(feature, promoteId)!, feature);
118123
}
119124

120-
return result;
125+
return updateable;
121126
}
122127

123128
/**
124-
* Mutates updateable and applies a GeoJSONSourceDiff. Operations are processed in a specific order to ensure predictable behavior:
129+
* Mutates updateable and applies a {@link GeoJSONSourceDiff}. Operations are processed in a specific order to ensure predictable behavior:
125130
* 1. Remove operations (removeAll, remove)
126131
* 2. Add operations (add)
127132
* 3. Update operations (update)
128-
* @returns an array of geometries that were affected by the diff
133+
* @returns an array of geometries that were affected by the diff - with the exception of removeAll which does not track any affected geometries.
129134
*/
130135
export function applySourceDiff(updateable: Map<GeoJSONFeatureId, GeoJSON.Feature>, diff: GeoJSONSourceDiff, promoteId?: string): GeoJSON.Geometry[] {
131136
const affectedGeometries: GeoJSON.Geometry[] = [];
137+
132138
if (diff.removeAll) {
133139
updateable.clear();
134140
}
135141
else if (diff.remove) {
136142
for (const id of diff.remove) {
137-
if (updateable.has(id)) {
138-
affectedGeometries.push(updateable.get(id).geometry);
139-
updateable.delete(id);
140-
}
143+
const existing = updateable.get(id);
144+
if (!existing) continue;
145+
146+
affectedGeometries.push(existing.geometry);
147+
updateable.delete(id);
141148
}
142149
}
143150

144151
if (diff.add) {
145152
for (const feature of diff.add) {
146153
const id = getFeatureId(feature, promoteId);
147-
if (id != null) {
148-
affectedGeometries.push(feature.geometry);
149-
updateable.set(id, feature);
150-
}
154+
if (id == null) continue;
155+
156+
// we are allowed to replace duplicate features with the same id, so need to check for existing
157+
const existing = updateable.get(id);
158+
if (existing) affectedGeometries.push(existing.geometry);
159+
160+
affectedGeometries.push(feature.geometry);
161+
updateable.set(id, feature);
151162
}
152163
}
153164

154165
if (diff.update) {
155166
for (const update of diff.update) {
156-
let feature = updateable.get(update.id);
157-
if (!feature) continue;
167+
const existing = updateable.get(update.id);
168+
if (!existing) continue;
158169

159170
const changeGeometry = !!update.newGeometry;
160171

@@ -167,7 +178,7 @@ export function applySourceDiff(updateable: Map<GeoJSONFeatureId, GeoJSON.Featur
167178
if (!changeGeometry && !changeProps) continue;
168179

169180
// clone once since we'll mutate
170-
feature = {...feature};
181+
const feature = {...existing};
171182
updateable.set(update.id, feature);
172183
affectedGeometries.push(feature.geometry);
173184

0 commit comments

Comments
 (0)