@mapwhit/tilerenderer 0.52.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +7 -0
  2. package/build/min/package.json +1 -1
  3. package/build/min/src/shaders/_prelude.fragment.glsl.js +2 -2
  4. package/build/min/src/shaders/_prelude.vertex.glsl.js +2 -2
  5. package/build/min/src/shaders/background.fragment.glsl.js +2 -2
  6. package/build/min/src/shaders/background.vertex.glsl.js +1 -1
  7. package/build/min/src/shaders/background_pattern.fragment.glsl.js +2 -2
  8. package/build/min/src/shaders/background_pattern.vertex.glsl.js +1 -1
  9. package/build/min/src/shaders/circle.fragment.glsl.js +2 -2
  10. package/build/min/src/shaders/circle.vertex.glsl.js +2 -2
  11. package/build/min/src/shaders/clipping_mask.fragment.glsl.js +1 -1
  12. package/build/min/src/shaders/clipping_mask.vertex.glsl.js +1 -1
  13. package/build/min/src/shaders/collision_box.fragment.glsl.js +1 -1
  14. package/build/min/src/shaders/collision_box.vertex.glsl.js +1 -1
  15. package/build/min/src/shaders/collision_circle.fragment.glsl.js +1 -1
  16. package/build/min/src/shaders/collision_circle.vertex.glsl.js +1 -1
  17. package/build/min/src/shaders/debug.fragment.glsl.js +1 -1
  18. package/build/min/src/shaders/debug.vertex.glsl.js +1 -1
  19. package/build/min/src/shaders/fill.fragment.glsl.js +2 -2
  20. package/build/min/src/shaders/fill.vertex.glsl.js +2 -2
  21. package/build/min/src/shaders/fill_extrusion.fragment.glsl.js +2 -2
  22. package/build/min/src/shaders/fill_extrusion.vertex.glsl.js +2 -2
  23. package/build/min/src/shaders/fill_extrusion_pattern.fragment.glsl.js +2 -2
  24. package/build/min/src/shaders/fill_extrusion_pattern.vertex.glsl.js +2 -2
  25. package/build/min/src/shaders/fill_outline.fragment.glsl.js +2 -2
  26. package/build/min/src/shaders/fill_outline.vertex.glsl.js +2 -2
  27. package/build/min/src/shaders/fill_outline_pattern.fragment.glsl.js +2 -2
  28. package/build/min/src/shaders/fill_outline_pattern.vertex.glsl.js +2 -2
  29. package/build/min/src/shaders/fill_pattern.fragment.glsl.js +2 -2
  30. package/build/min/src/shaders/fill_pattern.vertex.glsl.js +2 -2
  31. package/build/min/src/shaders/heatmap.fragment.glsl.js +2 -2
  32. package/build/min/src/shaders/heatmap.vertex.glsl.js +2 -2
  33. package/build/min/src/shaders/heatmap_texture.fragment.glsl.js +2 -2
  34. package/build/min/src/shaders/heatmap_texture.vertex.glsl.js +1 -1
  35. package/build/min/src/shaders/hillshade.fragment.glsl.js +2 -2
  36. package/build/min/src/shaders/hillshade.vertex.glsl.js +1 -1
  37. package/build/min/src/shaders/hillshade_prepare.fragment.glsl.js +2 -2
  38. package/build/min/src/shaders/hillshade_prepare.vertex.glsl.js +1 -1
  39. package/build/min/src/shaders/line.fragment.glsl.js +2 -2
  40. package/build/min/src/shaders/line.vertex.glsl.js +2 -2
  41. package/build/min/src/shaders/line_gradient.fragment.glsl.js +2 -2
  42. package/build/min/src/shaders/line_gradient.vertex.glsl.js +2 -2
  43. package/build/min/src/shaders/line_pattern.fragment.glsl.js +2 -2
  44. package/build/min/src/shaders/line_pattern.vertex.glsl.js +2 -2
  45. package/build/min/src/shaders/line_sdf.fragment.glsl.js +2 -2
  46. package/build/min/src/shaders/line_sdf.vertex.glsl.js +2 -2
  47. package/build/min/src/shaders/raster.fragment.glsl.js +2 -2
  48. package/build/min/src/shaders/raster.vertex.glsl.js +1 -1
  49. package/build/min/src/shaders/symbol_icon.fragment.glsl.js +2 -2
  50. package/build/min/src/shaders/symbol_icon.vertex.glsl.js +2 -2
  51. package/build/min/src/shaders/symbol_sdf.fragment.glsl.js +2 -2
  52. package/build/min/src/shaders/symbol_sdf.vertex.glsl.js +2 -2
  53. package/package.json +3 -3
  54. package/src/data/array_types.js +1 -36
  55. package/src/data/bucket/circle_bucket.js +0 -3
  56. package/src/data/bucket/fill_bucket.js +0 -3
  57. package/src/data/bucket/fill_extrusion_bucket.js +0 -3
  58. package/src/data/bucket/heatmap_bucket.js +0 -4
  59. package/src/data/bucket/line_bucket.js +1 -4
  60. package/src/data/bucket/pattern_bucket_features.js +2 -2
  61. package/src/data/bucket/symbol_bucket.js +87 -126
  62. package/src/data/bucket.js +26 -21
  63. package/src/data/dem_data.js +0 -3
  64. package/src/data/feature_index.js +3 -8
  65. package/src/data/program_configuration.js +3 -12
  66. package/src/data/segment.js +0 -4
  67. package/src/render/draw_background.js +3 -3
  68. package/src/render/draw_circle.js +4 -4
  69. package/src/render/draw_fill.js +8 -8
  70. package/src/render/draw_fill_extrusion.js +8 -8
  71. package/src/render/draw_heatmap.js +4 -4
  72. package/src/render/draw_line.js +6 -6
  73. package/src/render/draw_raster.js +6 -6
  74. package/src/render/draw_symbol.js +16 -16
  75. package/src/render/glyph_atlas.js +0 -3
  76. package/src/render/glyph_manager.js +1 -2
  77. package/src/render/image_atlas.js +0 -4
  78. package/src/render/image_manager.js +33 -19
  79. package/src/render/painter.js +13 -14
  80. package/src/render/program/circle_program.js +4 -4
  81. package/src/render/program/fill_extrusion_program.js +1 -1
  82. package/src/render/program/heatmap_program.js +1 -1
  83. package/src/render/program/hillshade_program.js +6 -6
  84. package/src/render/program/line_program.js +3 -3
  85. package/src/render/program/raster_program.js +6 -6
  86. package/src/source/geojson_source.js +15 -24
  87. package/src/source/geojson_worker_source.js +40 -68
  88. package/src/source/geojson_wrapper.js +9 -1
  89. package/src/source/image_source.js +6 -16
  90. package/src/source/query_features.js +4 -5
  91. package/src/source/raster_dem_tile_source.js +45 -64
  92. package/src/source/raster_tile_source.js +1 -6
  93. package/src/source/resources/glyphs.js +2 -2
  94. package/src/source/resources/index.js +3 -9
  95. package/src/source/rtl_text_plugin.js +58 -31
  96. package/src/source/source.js +11 -13
  97. package/src/source/source_cache.js +135 -151
  98. package/src/source/source_state.js +101 -12
  99. package/src/source/tile.js +32 -46
  100. package/src/source/tile_bounds.js +26 -26
  101. package/src/source/tile_id.js +2 -5
  102. package/src/source/vector_tile_source.js +14 -14
  103. package/src/source/vector_tile_worker_source.js +19 -23
  104. package/src/source/worker_tile.js +120 -117
  105. package/src/style/create_style_layer.js +1 -1
  106. package/src/style/pauseable_placement.js +4 -5
  107. package/src/style/properties.js +1 -8
  108. package/src/style/query_utils.js +3 -3
  109. package/src/style/style.js +263 -195
  110. package/src/style/style_layer/circle_style_layer.js +13 -11
  111. package/src/style/style_layer/fill_extrusion_style_layer.js +42 -27
  112. package/src/style/style_layer/fill_style_layer.js +5 -5
  113. package/src/style/style_layer/heatmap_style_layer.js +1 -1
  114. package/src/style/style_layer/hillshade_style_layer.js +1 -1
  115. package/src/style/style_layer/line_style_layer.js +23 -19
  116. package/src/style/style_layer/symbol_style_layer.js +13 -13
  117. package/src/style/style_layer.js +48 -30
  118. package/src/style/style_layer_index.js +16 -41
  119. package/src/symbol/anchor.js +0 -4
  120. package/src/symbol/cross_tile_symbol_index.js +2 -5
  121. package/src/symbol/opacity_state.js +0 -4
  122. package/src/symbol/placement.js +3 -3
  123. package/src/symbol/quads.js +4 -4
  124. package/src/symbol/symbol_layout.js +7 -7
  125. package/src/symbol/transform_text.js +1 -1
  126. package/src/ui/map.js +49 -11
  127. package/src/util/group_layers.js +41 -0
  128. package/src/util/image.js +0 -5
  129. package/src/util/key.js +21 -0
  130. package/src/util/object.js +8 -53
  131. package/src/worker.js +1 -4
  132. package/src/source/resources/images.js +0 -68
  133. package/src/source/worker.js +0 -110
  134. package/src/source/worker_source.js +0 -14
  135. package/src/style-spec/deref.js +0 -51
  136. package/src/style-spec/group_by_layout.js +0 -46
  137. package/src/util/actor.js +0 -108
  138. package/src/util/dispatcher.js +0 -65
  139. package/src/util/global_worker_pool.js +0 -15
  140. package/src/util/transfer_registry.js +0 -168
  141. package/src/util/web_worker_transfer.js +0 -43
  142. package/src/util/worker_pool.js +0 -41
@@ -23,10 +23,11 @@ const padding = 1;
23
23
  */
24
24
  class ImageManager {
25
25
  #loadedState = Promise.withResolvers();
26
+ #imageQueue = new Map();
26
27
  constructor() {
27
- this.images = {};
28
+ this.images = new Map();
28
29
 
29
- this.patterns = {};
30
+ this.patterns = new Map();
30
31
  this.atlasImage = new RGBAImage({ width: 1, height: 1 });
31
32
  this.dirty = true;
32
33
  }
@@ -44,22 +45,31 @@ class ImageManager {
44
45
  }
45
46
 
46
47
  getImage(id) {
47
- return this.images[id];
48
+ return this.images.get(id);
48
49
  }
49
50
 
50
51
  addImage(id, image) {
51
- assert(!this.images[id]);
52
- this.images[id] = image;
52
+ assert(!(this.images.has(id) || this.#imageQueue.has(id)));
53
+ if (image.promise) {
54
+ this.#imageQueue.set(id, image.promise);
55
+ image.promise.then(image => {
56
+ this.#imageQueue.delete(id);
57
+ this.images.set(id, image);
58
+ });
59
+ return;
60
+ }
61
+ this.images.set(id, image);
53
62
  }
54
63
 
55
64
  removeImage(id) {
56
- assert(this.images[id]);
57
- delete this.images[id];
58
- delete this.patterns[id];
65
+ assert(this.images.has(id) || this.#imageQueue.has(id));
66
+ this.images.delete(id);
67
+ this.#imageQueue.delete(id);
68
+ this.patterns.delete(id);
59
69
  }
60
70
 
61
71
  listImages() {
62
- return Object.keys(this.images);
72
+ return Array.from(this.images.keys());
63
73
  }
64
74
 
65
75
  async getImages(ids) {
@@ -67,11 +77,16 @@ class ImageManager {
67
77
 
68
78
  const response = {};
69
79
  for (const id of ids) {
70
- const image = this.images[id];
80
+ let image = this.images.get(id);
81
+ if (!image) {
82
+ if (!this.#imageQueue.has(id)) {
83
+ continue;
84
+ }
85
+ image = await this.#imageQueue.get(id);
86
+ }
71
87
  if (image) {
72
- // Clone the image so that our own copy of its ArrayBuffer doesn't get transferred.
73
88
  response[id] = {
74
- data: image.data.clone(),
89
+ data: image.data,
75
90
  pixelRatio: image.pixelRatio,
76
91
  sdf: image.sdf
77
92
  };
@@ -88,7 +103,7 @@ class ImageManager {
88
103
  }
89
104
 
90
105
  getPattern(id) {
91
- const pattern = this.patterns[id];
106
+ const pattern = this.patterns.get(id);
92
107
  if (pattern) {
93
108
  return pattern.position;
94
109
  }
@@ -102,7 +117,7 @@ class ImageManager {
102
117
  const h = image.data.height + padding * 2;
103
118
  const bin = { w, h, x: 0, y: 0 };
104
119
  const position = new ImagePosition(bin, image);
105
- this.patterns[id] = { bin, position };
120
+ this.patterns.set(id, { bin, position });
106
121
  this._updatePatternAtlas();
107
122
 
108
123
  return position;
@@ -122,8 +137,8 @@ class ImageManager {
122
137
 
123
138
  _updatePatternAtlas() {
124
139
  const bins = [];
125
- for (const id in this.patterns) {
126
- bins.push(this.patterns[id].bin);
140
+ for (const { bin } of this.patterns.values()) {
141
+ bins.push(bin);
127
142
  }
128
143
 
129
144
  const { w, h } = potpack(bins);
@@ -131,11 +146,10 @@ class ImageManager {
131
146
  const dst = this.atlasImage;
132
147
  dst.resize({ width: w ?? 1, height: h ?? 1 });
133
148
 
134
- for (const id in this.patterns) {
135
- const { bin } = this.patterns[id];
149
+ for (const [id, { bin }] of this.patterns) {
136
150
  const x = bin.x + padding;
137
151
  const y = bin.y + padding;
138
- const src = this.images[id].data;
152
+ const src = this.images.get(id).data;
139
153
  const w = src.width;
140
154
  const h = src.height;
141
155
 
@@ -83,8 +83,8 @@ class Painter {
83
83
  this.context.viewport.set([0, 0, this.width, this.height]);
84
84
 
85
85
  if (this.style) {
86
- for (const layerId of this.style._order) {
87
- this.style._layers[layerId].resize();
86
+ for (const layer of this.style._layers.values()) {
87
+ layer.resize();
88
88
  }
89
89
  }
90
90
 
@@ -284,8 +284,7 @@ class Painter {
284
284
 
285
285
  this.symbolFadeChange = style.placement.symbolFadeChange(browser.now());
286
286
 
287
- const layerIds = this.style._order;
288
- const sourceCaches = this.style.sourceCaches;
287
+ const sourceCaches = style._sources;
289
288
 
290
289
  for (const id in sourceCaches) {
291
290
  const sourceCache = sourceCaches[id];
@@ -314,10 +313,11 @@ class Painter {
314
313
  updateTileMasks(visibleTiles, this.context);
315
314
  }
316
315
 
316
+ const layers = Array.from(style._layers.values());
317
+
317
318
  this.opaquePassCutoff = Number.POSITIVE_INFINITY;
318
- for (let i = 0; i < layerIds.length; i++) {
319
- const layerId = layerIds[i];
320
- if (this.style._layers[layerId].is3D()) {
319
+ for (let i = 0; i < layers.length; i++) {
320
+ if (layers[i].is3D()) {
321
321
  this.opaquePassCutoff = i;
322
322
  break;
323
323
  }
@@ -330,8 +330,7 @@ class Painter {
330
330
  this.renderPass = 'offscreen';
331
331
  this.depthRboNeedsClear = true;
332
332
 
333
- for (const layerId of layerIds) {
334
- const layer = this.style._layers[layerId];
333
+ for (const layer of layers) {
335
334
  if (!layer.hasOffscreenPass() || layer.isHidden(this.transform.zoom)) continue;
336
335
 
337
336
  const coords = coordsDescending[layer.source];
@@ -349,14 +348,14 @@ class Painter {
349
348
  this.clearStencil();
350
349
 
351
350
  this._showOverdrawInspector = options.showOverdrawInspector;
352
- this.depthRangeFor3D = [0, 1 - (style._order.length + 2) * this.numSublayers * this.depthEpsilon];
351
+ this.depthRangeFor3D = [0, 1 - (style._layers.size + 2) * this.numSublayers * this.depthEpsilon];
353
352
 
354
353
  // Opaque pass ===============================================
355
354
  // Draw opaque layers top-to-bottom first.
356
355
  this.renderPass = 'opaque';
357
356
 
358
- for (this.currentLayer = layerIds.length - 1; this.currentLayer >= 0; this.currentLayer--) {
359
- const layer = this.style._layers[layerIds[this.currentLayer]];
357
+ for (this.currentLayer = layers.length - 1; this.currentLayer >= 0; this.currentLayer--) {
358
+ const layer = layers[this.currentLayer];
360
359
  const sourceCache = sourceCaches[layer.source];
361
360
  const coords = coordsAscending[layer.source];
362
361
 
@@ -368,8 +367,8 @@ class Painter {
368
367
  // Draw all other layers bottom-to-top.
369
368
  this.renderPass = 'translucent';
370
369
 
371
- for (this.currentLayer = 0; this.currentLayer < layerIds.length; this.currentLayer++) {
372
- const layer = this.style._layers[layerIds[this.currentLayer]];
370
+ for (this.currentLayer = 0; this.currentLayer < layers.length; this.currentLayer++) {
371
+ const layer = layers[this.currentLayer];
373
372
  const sourceCache = sourceCaches[layer.source];
374
373
 
375
374
  // For symbol layers in the translucent pass, we add extra tiles to the renderable set
@@ -14,7 +14,7 @@ const circleUniformValues = (painter, coord, tile, layer) => {
14
14
 
15
15
  let pitchWithMap;
16
16
  let extrudeScale;
17
- if (layer.paint.get('circle-pitch-alignment') === 'map') {
17
+ if (layer._paint.get('circle-pitch-alignment') === 'map') {
18
18
  const pixelRatio = pixelsToTileUnits(tile, 1, transform.zoom);
19
19
  pitchWithMap = true;
20
20
  extrudeScale = [pixelRatio, pixelRatio];
@@ -25,12 +25,12 @@ const circleUniformValues = (painter, coord, tile, layer) => {
25
25
 
26
26
  return {
27
27
  u_camera_to_center_distance: transform.cameraToCenterDistance,
28
- u_scale_with_map: +(layer.paint.get('circle-pitch-scale') === 'map'),
28
+ u_scale_with_map: +(layer._paint.get('circle-pitch-scale') === 'map'),
29
29
  u_matrix: painter.translatePosMatrix(
30
30
  coord.posMatrix,
31
31
  tile,
32
- layer.paint.get('circle-translate'),
33
- layer.paint.get('circle-translate-anchor')
32
+ layer._paint.get('circle-translate'),
33
+ layer._paint.get('circle-translate-anchor')
34
34
  ),
35
35
  u_pitch_with_map: +pitchWithMap,
36
36
  u_extrude_scale: extrudeScale
@@ -29,7 +29,7 @@ const fillExtrusionPatternUniforms = (context, locations) => ({
29
29
  });
30
30
 
31
31
  const fillExtrusionUniformValues = (matrix, painter, shouldUseVerticalGradient, opacity) => {
32
- const light = painter.style.light;
32
+ const light = painter.style._light;
33
33
  const _lp = light.properties.get('position');
34
34
  const lightPos = [_lp.x, _lp.y, _lp.z];
35
35
  const lightMat = mat3.create();
@@ -34,7 +34,7 @@ const heatmapTextureUniformValues = (painter, layer, textureUnit, colorRampUnit)
34
34
  u_world: [gl.drawingBufferWidth, gl.drawingBufferHeight],
35
35
  u_image: textureUnit,
36
36
  u_color_ramp: colorRampUnit,
37
- u_opacity: layer.paint.get('heatmap-opacity')
37
+ u_opacity: layer._paint.get('heatmap-opacity')
38
38
  };
39
39
  };
40
40
 
@@ -24,13 +24,13 @@ const hillshadePrepareUniforms = (context, locations) => ({
24
24
  });
25
25
 
26
26
  const hillshadeUniformValues = (painter, tile, layer) => {
27
- const shadow = layer.paint.get('hillshade-shadow-color');
28
- const highlight = layer.paint.get('hillshade-highlight-color');
29
- const accent = layer.paint.get('hillshade-accent-color');
27
+ const shadow = layer._paint.get('hillshade-shadow-color');
28
+ const highlight = layer._paint.get('hillshade-highlight-color');
29
+ const accent = layer._paint.get('hillshade-accent-color');
30
30
 
31
- let azimuthal = layer.paint.get('hillshade-illumination-direction') * (Math.PI / 180);
31
+ let azimuthal = layer._paint.get('hillshade-illumination-direction') * (Math.PI / 180);
32
32
  // modify azimuthal angle by map rotation if light is anchored at the viewport
33
- if (layer.paint.get('hillshade-illumination-anchor') === 'viewport') {
33
+ if (layer._paint.get('hillshade-illumination-anchor') === 'viewport') {
34
34
  azimuthal -= painter.transform.angle;
35
35
  }
36
36
  const align = !painter.options.moving;
@@ -38,7 +38,7 @@ const hillshadeUniformValues = (painter, tile, layer) => {
38
38
  u_matrix: painter.transform.calculatePosMatrix(tile.tileID.toUnwrapped(), align),
39
39
  u_image: 0,
40
40
  u_latrange: getTileLatRange(painter, tile.tileID),
41
- u_light: [layer.paint.get('hillshade-exaggeration'), azimuthal],
41
+ u_light: [layer._paint.get('hillshade-exaggeration'), azimuthal],
42
42
  u_shadow: shadow,
43
43
  u_highlight: highlight,
44
44
  u_accent: accent
@@ -75,7 +75,7 @@ const lineSDFUniformValues = (painter, tile, layer, dasharray, crossfade) => {
75
75
  const lineAtlas = painter.lineAtlas;
76
76
  const tileRatio = calculateTileRatio(tile, transform);
77
77
 
78
- const round = layer.layout.get('line-cap') === 'round';
78
+ const round = layer._layout.get('line-cap') === 'round';
79
79
 
80
80
  const posA = lineAtlas.getDash(dasharray.from, round);
81
81
  const posB = lineAtlas.getDash(dasharray.to, round);
@@ -102,8 +102,8 @@ function calculateMatrix(painter, tile, layer) {
102
102
  return painter.translatePosMatrix(
103
103
  tile.tileID.posMatrix,
104
104
  tile,
105
- layer.paint.get('line-translate'),
106
- layer.paint.get('line-translate-anchor')
105
+ layer._paint.get('line-translate'),
106
+ layer._paint.get('line-translate-anchor')
107
107
  );
108
108
  }
109
109
 
@@ -22,14 +22,14 @@ const rasterUniformValues = (matrix, parentTL, parentScaleBy, fade, layer) => ({
22
22
  u_scale_parent: parentScaleBy,
23
23
  u_buffer_scale: 1,
24
24
  u_fade_t: fade.mix,
25
- u_opacity: fade.opacity * layer.paint.get('raster-opacity'),
25
+ u_opacity: fade.opacity * layer._paint.get('raster-opacity'),
26
26
  u_image0: 0,
27
27
  u_image1: 1,
28
- u_brightness_low: layer.paint.get('raster-brightness-min'),
29
- u_brightness_high: layer.paint.get('raster-brightness-max'),
30
- u_saturation_factor: saturationFactor(layer.paint.get('raster-saturation')),
31
- u_contrast_factor: contrastFactor(layer.paint.get('raster-contrast')),
32
- u_spin_weights: spinWeights(layer.paint.get('raster-hue-rotate'))
28
+ u_brightness_low: layer._paint.get('raster-brightness-min'),
29
+ u_brightness_high: layer._paint.get('raster-brightness-max'),
30
+ u_saturation_factor: saturationFactor(layer._paint.get('raster-saturation')),
31
+ u_contrast_factor: contrastFactor(layer._paint.get('raster-contrast')),
32
+ u_spin_weights: spinWeights(layer._paint.get('raster-hue-rotate'))
33
33
  });
34
34
 
35
35
  function spinWeights(angle) {
@@ -2,6 +2,7 @@ const { Event, ErrorEvent, Evented } = require('@mapwhit/events');
2
2
 
3
3
  const EXTENT = require('../data/extent');
4
4
  const browser = require('../util/browser');
5
+ const GeoJSONWorkerSource = require('./geojson_worker_source');
5
6
 
6
7
  /**
7
8
  * A source containing GeoJSON.
@@ -52,8 +53,9 @@ class GeoJSONSource extends Evented {
52
53
  #pendingDataEvents = new Set();
53
54
  #newData = false;
54
55
  #updateInProgress = false;
56
+ #worker;
55
57
 
56
- constructor(id, options, dispatcher, eventedParent) {
58
+ constructor(id, options, eventedParent, { resources, layerIndex }) {
57
59
  super();
58
60
 
59
61
  this.id = id;
@@ -69,10 +71,9 @@ class GeoJSONSource extends Evented {
69
71
  this.reparseOverscaled = true;
70
72
  this._removed = false;
71
73
 
72
- this.dispatcher = dispatcher;
73
74
  this.setEventedParent(eventedParent);
74
75
 
75
- this._data = options.data;
76
+ this.data = options.data;
76
77
  this._options = Object.assign({}, options);
77
78
 
78
79
  if (options.maxzoom !== undefined) this.maxzoom = options.maxzoom;
@@ -107,6 +108,7 @@ class GeoJSONSource extends Evented {
107
108
  },
108
109
  options.workerOptions
109
110
  );
111
+ this.#worker = new GeoJSONWorkerSource(resources, layerIndex);
110
112
  }
111
113
 
112
114
  load() {
@@ -125,7 +127,7 @@ class GeoJSONSource extends Evented {
125
127
  * @returns {GeoJSONSource} this
126
128
  */
127
129
  setData(data) {
128
- this._data = data;
130
+ this.data = data;
129
131
  this.#updateData();
130
132
  return this;
131
133
  }
@@ -142,7 +144,7 @@ class GeoJSONSource extends Evented {
142
144
  this.fire(new Event('dataloading', { dataType: 'source' }));
143
145
  while (this.#newData) {
144
146
  this.#newData = false;
145
- await this._updateWorkerData(this._data);
147
+ await this._updateWorkerData(this.data);
146
148
  }
147
149
  this.#pendingDataEvents.forEach(sourceDataType =>
148
150
  this.fire(new Event('data', { dataType: 'source', sourceDataType }))
@@ -165,13 +167,9 @@ class GeoJSONSource extends Evented {
165
167
  if (!json) {
166
168
  throw new Error('no GeoJSON data');
167
169
  }
168
- const options = { ...this.workerOptions, data: JSON.stringify(json) };
169
- this.workerID ??= this.dispatcher.nextWorkerId();
170
+ const options = { ...this.workerOptions, data: json };
170
171
 
171
- // target {this.type}.loadData rather than literally geojson.loadData,
172
- // so that other geojson-like source types can easily reuse this
173
- // implementation
174
- await this.dispatcher.send(`${this.type}.loadData`, options, this.workerID);
172
+ return await this.#worker.loadData(options);
175
173
  }
176
174
 
177
175
  async loadTile(tile) {
@@ -185,14 +183,15 @@ class GeoJSONSource extends Evented {
185
183
  source: this.id,
186
184
  pixelRatio: browser.devicePixelRatio,
187
185
  showCollisionBoxes: this.map.showCollisionBoxes,
188
- globalState: this.map.getGlobalState()
186
+ globalState: this.map.getGlobalState(),
187
+ justReloaded: tile.workerID != null,
188
+ painter: this.map.painter
189
189
  };
190
190
 
191
- const justReloaded = tile.workerID != null;
192
- tile.workerID ??= this.dispatcher.nextWorkerId(this.workerID);
193
- const data = await this.dispatcher.send('loadTile', params, tile.workerID).finally(() => tile.unloadVectorData());
191
+ tile.workerID ??= true;
192
+ const data = await this.#worker.loadTile(params).finally(() => tile.unloadVectorData());
194
193
  if (!tile.aborted) {
195
- tile.loadVectorData(data, this.map.painter, justReloaded);
194
+ tile.loadVectorData(data, this.map.painter);
196
195
  }
197
196
  }
198
197
 
@@ -206,14 +205,6 @@ class GeoJSONSource extends Evented {
206
205
 
207
206
  onRemove() {
208
207
  this._removed = true;
209
- return this.dispatcher.send('removeSource', { type: this.type, source: this.id }, this.workerID);
210
- }
211
-
212
- serialize() {
213
- return Object.assign({}, this._options, {
214
- type: this.type,
215
- data: this._data
216
- });
217
208
  }
218
209
 
219
210
  hasTransition() {
@@ -1,68 +1,14 @@
1
1
  const rewind = require('@mapwhit/geojson-rewind');
2
2
  const GeoJSONWrapper = require('./geojson_wrapper');
3
- const { fromVectorTileJs } = require('@mapwhit/vt-pbf');
4
3
  const { default: Supercluster } = require('supercluster');
5
4
  const { default: geojsonvt } = require('geojson-vt');
6
5
  const VectorTileWorkerSource = require('./vector_tile_worker_source');
7
6
 
8
- function loadGeoJSONTile(params) {
9
- if (!this._geoJSONIndex) {
10
- if (!this._createGeoJSONIndex) {
11
- return; // we couldn't load the file
12
- }
13
-
14
- try {
15
- this._geoJSONIndex = this._createGeoJSONIndex();
16
- } finally {
17
- this._createGeoJSONIndex = null;
18
- }
19
- }
20
-
21
- const { z, x, y } = params.tileID.canonical;
22
- const geoJSONTile = this._geoJSONIndex.getTile(z, x, y);
23
- if (!geoJSONTile) {
24
- return; // nothing in the given tile
25
- }
26
-
27
- const geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features);
28
-
29
- // Encode the geojson-vt tile into binary vector tile form. This
30
- // is a convenience that allows `FeatureIndex` to operate the same way
31
- // across `VectorTileSource` and `GeoJSONSource` data.
32
- let pbf = fromVectorTileJs(geojsonWrapper);
33
- if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) {
34
- // Compatibility with node Buffer (https://github.com/mapbox/pbf/issues/35)
35
- pbf = new Uint8Array(pbf);
36
- }
37
-
38
- return {
39
- vectorTile: geojsonWrapper,
40
- rawData: pbf.buffer
41
- };
42
- }
43
-
44
7
  /**
45
8
  * The {@link WorkerSource} implementation that supports {@link GeoJSONSource}.
46
- * This class is designed to be easily reused to support custom source types
47
- * for data formats that can be parsed/converted into an in-memory GeoJSON
48
- * representation. To do so, create it with
49
- * `new GeoJSONWorkerSource(resources, layerIndex, customLoadGeoJSONFunction)`.
50
- * For a full example, see [mapbox-gl-topojson](https://github.com/developmentseed/mapbox-gl-topojson).
51
9
  *
52
10
  */
53
11
  class GeoJSONWorkerSource extends VectorTileWorkerSource {
54
- /**
55
- * @param [loadGeoJSON] Optional method for custom loading/parsing of
56
- * GeoJSON based on parameters passed from the main-thread Source.
57
- * See {@link GeoJSONWorkerSource#loadGeoJSON}.
58
- */
59
- constructor(resources, layerIndex, loadGeoJSON) {
60
- super(resources, layerIndex, loadGeoJSONTile);
61
- if (loadGeoJSON) {
62
- this.loadGeoJSON = loadGeoJSON;
63
- }
64
- }
65
-
66
12
  /**
67
13
  * Fetches (if appropriate), parses, and index geojson data into tiles. This
68
14
  * preparatory method must be called before {@link GeoJSONWorkerSource#loadTile}
@@ -76,7 +22,7 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
76
22
  * @param callback
77
23
  */
78
24
  loadData(params) {
79
- const data = this.loadGeoJSON(params);
25
+ const data = loadJSON(params.data);
80
26
  this._geoJSONIndex = null;
81
27
  this._createGeoJSONIndex = params.cluster
82
28
  ? () => {
@@ -89,20 +35,46 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
89
35
  };
90
36
  }
91
37
 
92
- /**
93
- * Fetch and parse GeoJSON according to the given params.
94
- *
95
- * GeoJSON is expected as a literal (string or object) `params.data`.
96
- *
97
- * @param params
98
- * @param [params.data] Literal GeoJSON data. Must be provided.
99
- */
100
- loadGeoJSON(params) {
101
- try {
102
- return JSON.parse(params.data);
103
- } catch (e) {
104
- throw new Error('Input data is not a valid GeoJSON object.');
38
+ getTile(tileID) {
39
+ if (!this._geoJSONIndex) {
40
+ if (!this._createGeoJSONIndex) {
41
+ return; // we couldn't load the file
42
+ }
43
+
44
+ try {
45
+ this._geoJSONIndex = this._createGeoJSONIndex();
46
+ } finally {
47
+ this._createGeoJSONIndex = null;
48
+ }
49
+ }
50
+ const { z, x, y } = tileID.canonical;
51
+ return this._geoJSONIndex.getTile(z, x, y);
52
+ }
53
+
54
+ loadVectorData({ tileID }) {
55
+ const geoJSONTile = this.getTile(tileID);
56
+ if (!geoJSONTile) {
57
+ return; // nothing in the given tile
105
58
  }
59
+
60
+ const vectorTile = new GeoJSONWrapper(geoJSONTile.features);
61
+
62
+ return {
63
+ vectorTile
64
+ };
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Fetch and parse GeoJSON according to the given params.
70
+ *
71
+ * @param data Literal GeoJSON data. Must be provided.
72
+ */
73
+ function loadJSON(data) {
74
+ try {
75
+ return typeof data === 'string' ? JSON.parse(data) : data;
76
+ } catch (e) {
77
+ throw new Error('Input data is not a valid GeoJSON object.');
106
78
  }
107
79
  }
108
80
 
@@ -20,6 +20,14 @@ class FeatureWrapper {
20
20
  if ('id' in feature && !isNaN(feature.id)) {
21
21
  this.id = Number.parseInt(feature.id, 10);
22
22
  }
23
+
24
+ // fix geometry - it has to be at least array of 2 points
25
+ if (typeof this._feature.geometry[0] === 'number') {
26
+ this._feature.geometry = [this._feature.geometry];
27
+ if (this._feature.geometry.length === 1) {
28
+ this._feature.geometry.push(this._feature.geometry[0]);
29
+ }
30
+ }
23
31
  }
24
32
 
25
33
  get type() {
@@ -27,7 +35,7 @@ class FeatureWrapper {
27
35
  }
28
36
 
29
37
  get properties() {
30
- return this._feature.tags;
38
+ return this._feature.tags ?? {};
31
39
  }
32
40
 
33
41
  get extent() {
@@ -2,7 +2,6 @@ const { getCoordinatesCenter } = require('../util/util');
2
2
 
3
3
  const { CanonicalTileID } = require('./tile_id');
4
4
  const LngLat = require('../geo/lng_lat');
5
- const { default: Point } = require('@mapbox/point-geometry');
6
5
  const { Event, ErrorEvent, Evented } = require('@mapwhit/events');
7
6
  const loadImage = require('../util/loader/image');
8
7
  const EXTENT = require('../data/extent');
@@ -44,10 +43,9 @@ class ImageSource extends Evented {
44
43
  /**
45
44
  * @private
46
45
  */
47
- constructor(id, options, dispatcher, eventedParent) {
46
+ constructor(id, options, eventedParent) {
48
47
  super();
49
48
  this.id = id;
50
- this.dispatcher = dispatcher;
51
49
  this.coordinates = options.coordinates;
52
50
 
53
51
  this.type = 'image';
@@ -125,10 +123,10 @@ class ImageSource extends Evented {
125
123
  // tile.
126
124
  const tileCoords = cornerZ0Coords.map(coord => {
127
125
  const zoomedCoord = coord.zoomTo(centerCoord.zoom);
128
- return new Point(
129
- Math.round((zoomedCoord.column - centerCoord.column) * EXTENT),
130
- Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)
131
- );
126
+ return {
127
+ x: Math.round((zoomedCoord.column - centerCoord.column) * EXTENT),
128
+ y: Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)
129
+ };
132
130
  });
133
131
 
134
132
  this._boundsArray = new RasterBoundsArray();
@@ -185,21 +183,13 @@ class ImageSource extends Evented {
185
183
  // single tile.
186
184
  if (this.tileID?.equals(tile.tileID.canonical)) {
187
185
  this.tiles[String(tile.tileID.wrap)] = tile;
188
- tile.buckets = {};
186
+ tile.buckets = new Map();
189
187
  } else {
190
188
  tile.state = 'errored';
191
189
  }
192
190
  return Promise.resolve();
193
191
  }
194
192
 
195
- serialize() {
196
- return {
197
- type: 'image',
198
- url: this.options.url,
199
- coordinates: this.coordinates
200
- };
201
- }
202
-
203
193
  hasTransition() {
204
194
  return false;
205
195
  }
@@ -20,14 +20,13 @@ function getPixelPosMatrix(transform, tileID) {
20
20
  function queryIncludes3DLayer(layers, styleLayers, sourceID) {
21
21
  if (layers) {
22
22
  for (const layerID of layers) {
23
- const layer = styleLayers[layerID];
23
+ const layer = styleLayers.get(layerID);
24
24
  if (layer && layer.source === sourceID && layer.type === 'fill-extrusion') {
25
25
  return true;
26
26
  }
27
27
  }
28
- } else {
29
- for (const key in styleLayers) {
30
- const layer = styleLayers[key];
28
+ } else if (styleLayers) {
29
+ for (const layer of styleLayers.values()) {
31
30
  if (layer.source === sourceID && layer.type === 'fill-extrusion') {
32
31
  return true;
33
32
  }
@@ -129,7 +128,7 @@ function queryRenderedSymbols(styleLayers, sourceCaches, queryGeometry, params,
129
128
  for (const layerName in result) {
130
129
  result[layerName].forEach(featureWrapper => {
131
130
  const feature = featureWrapper.feature;
132
- const layer = styleLayers[layerName];
131
+ const layer = styleLayers.get(layerName);
133
132
  const sourceCache = sourceCaches[layer.source];
134
133
  const state = sourceCache.getFeatureState(feature.layer['source-layer'], feature.id);
135
134
  feature.source = feature.layer.source;