@mapwhit/tilerenderer 0.52.0 → 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 +8 -5
  56. package/src/data/bucket/fill_bucket.js +8 -5
  57. package/src/data/bucket/fill_extrusion_bucket.js +8 -5
  58. package/src/data/bucket/heatmap_bucket.js +0 -4
  59. package/src/data/bucket/line_bucket.js +9 -6
  60. package/src/data/bucket/pattern_bucket_features.js +2 -2
  61. package/src/data/bucket/symbol_bucket.js +99 -129
  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 +24 -33
  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 +122 -119
  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 +286 -216
  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 +71 -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 +52 -15
  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
@@ -21,7 +21,7 @@ class CircleStyleLayer extends StyleLayer {
21
21
  return (
22
22
  getMaximumPaintValue('circle-radius', this, circleBucket) +
23
23
  getMaximumPaintValue('circle-stroke-width', this, circleBucket) +
24
- translateDistance(this.paint.get('circle-translate'))
24
+ translateDistance(this._paint.get('circle-translate'))
25
25
  );
26
26
  }
27
27
 
@@ -37,24 +37,29 @@ class CircleStyleLayer extends StyleLayer {
37
37
  ) {
38
38
  const translatedPolygon = translate(
39
39
  queryGeometry,
40
- this.paint.get('circle-translate'),
41
- this.paint.get('circle-translate-anchor'),
40
+ this._paint.get('circle-translate'),
41
+ this._paint.get('circle-translate-anchor'),
42
42
  transform.angle,
43
43
  pixelsToTileUnits
44
44
  );
45
- const radius = this.paint.get('circle-radius').evaluate(feature, featureState);
46
- const stroke = this.paint.get('circle-stroke-width').evaluate(feature, featureState);
45
+ const radius = this._paint.get('circle-radius').evaluate(feature, featureState);
46
+ const stroke = this._paint.get('circle-stroke-width').evaluate(feature, featureState);
47
47
  const size = radius + stroke;
48
48
 
49
49
  // For pitch-alignment: map, compare feature geometry to query geometry in the plane of the tile
50
50
  // // Otherwise, compare geometry in the plane of the viewport
51
51
  // // A circle with fixed scaling relative to the viewport gets larger in tile space as it moves into the distance
52
52
  // // A circle with fixed scaling relative to the map gets smaller in viewport space as it moves into the distance
53
- const alignWithMap = this.paint.get('circle-pitch-alignment') === 'map';
53
+ const pitchScale = this._paint.get('circle-pitch-scale');
54
+ const pitchAlignment = this._paint.get('circle-pitch-alignment');
55
+ const alignWithMap = pitchAlignment === 'map';
56
+ const alignWithViewport = pitchAlignment === 'viewport';
54
57
  const transformedPolygon = alignWithMap
55
58
  ? translatedPolygon
56
59
  : projectQueryGeometry(translatedPolygon, pixelPosMatrix);
57
60
  const transformedSize = alignWithMap ? size * pixelsToTileUnits : size;
61
+ const adjustViewportToMap = pitchScale === 'viewport' && alignWithMap;
62
+ const adjustMapToViewport = pitchScale === 'map' && alignWithViewport;
58
63
 
59
64
  for (const ring of geometry) {
60
65
  for (const point of ring) {
@@ -62,12 +67,9 @@ class CircleStyleLayer extends StyleLayer {
62
67
 
63
68
  let adjustedSize = transformedSize;
64
69
  const projectedCenter = vec4.transformMat4([], [point.x, point.y, 0, 1], pixelPosMatrix);
65
- if (this.paint.get('circle-pitch-scale') === 'viewport' && this.paint.get('circle-pitch-alignment') === 'map') {
70
+ if (adjustViewportToMap) {
66
71
  adjustedSize *= projectedCenter[3] / transform.cameraToCenterDistance;
67
- } else if (
68
- this.paint.get('circle-pitch-scale') === 'map' &&
69
- this.paint.get('circle-pitch-alignment') === 'viewport'
70
- ) {
72
+ } else if (adjustMapToViewport) {
71
73
  adjustedSize *= transform.cameraToCenterDistance / projectedCenter[3];
72
74
  }
73
75
 
@@ -17,7 +17,7 @@ class FillExtrusionStyleLayer extends StyleLayer {
17
17
  }
18
18
 
19
19
  queryRadius() {
20
- return translateDistance(this.paint.get('fill-extrusion-translate'));
20
+ return translateDistance(this._paint.get('fill-extrusion-translate'));
21
21
  }
22
22
 
23
23
  is3D() {
@@ -36,13 +36,13 @@ class FillExtrusionStyleLayer extends StyleLayer {
36
36
  ) {
37
37
  const translatedPolygon = translate(
38
38
  queryGeometry,
39
- this.paint.get('fill-extrusion-translate'),
40
- this.paint.get('fill-extrusion-translate-anchor'),
39
+ this._paint.get('fill-extrusion-translate'),
40
+ this._paint.get('fill-extrusion-translate-anchor'),
41
41
  transform.angle,
42
42
  pixelsToTileUnits
43
43
  );
44
- const height = this.paint.get('fill-extrusion-height').evaluate(feature, featureState);
45
- const base = this.paint.get('fill-extrusion-base').evaluate(feature, featureState);
44
+ const height = this._paint.get('fill-extrusion-height').evaluate(feature, featureState);
45
+ const base = this._paint.get('fill-extrusion-base').evaluate(feature, featureState);
46
46
 
47
47
  const projectedQueryGeometry = projectQueryGeometry(translatedPolygon, pixelPosMatrix, transform, 0);
48
48
 
@@ -66,27 +66,42 @@ function getIntersectionDistance(projectedQueryGeometry, projectedFace) {
66
66
  // triangle of the face, using only the xy plane. It doesn't matter if the
67
67
  // point is outside the first triangle because all the triangles in the face
68
68
  // are in the same plane.
69
- const a = projectedFace[0];
70
- const b = projectedFace[1];
71
- const c = projectedFace[3];
72
- const p = projectedQueryGeometry[0];
73
-
74
- const ab = b.sub(a);
75
- const ac = c.sub(a);
76
- const ap = p.sub(a);
77
-
78
- const dotABAB = dot(ab, ab);
79
- const dotABAC = dot(ab, ac);
80
- const dotACAC = dot(ac, ac);
81
- const dotAPAB = dot(ap, ab);
82
- const dotAPAC = dot(ap, ac);
83
- const denom = dotABAB * dotACAC - dotABAC * dotABAC;
84
- const v = (dotACAC * dotAPAB - dotABAC * dotAPAC) / denom;
85
- const w = (dotABAB * dotAPAC - dotABAC * dotAPAB) / denom;
86
- const u = 1 - v - w;
87
-
88
- // Use the barycentric weighting along with the original triangle z coordinates to get the point of intersection.
89
- return a.z * u + b.z * v + c.z * w;
69
+ //
70
+ // Check whether points are coincident and use other points if they are.
71
+ let i = 0;
72
+ const a = projectedFace[i++];
73
+ let b;
74
+ while (!b || a.equals(b)) {
75
+ b = projectedFace[i++];
76
+ if (!b) return Number.POSITIVE_INFINITY;
77
+ }
78
+
79
+ // Loop until point `c` is not colinear with points `a` and `b`.
80
+ for (; i < projectedFace.length; i++) {
81
+ const c = projectedFace[i];
82
+ const p = projectedQueryGeometry[0];
83
+
84
+ const ab = b.sub(a);
85
+ const ac = c.sub(a);
86
+ const ap = p.sub(a);
87
+
88
+ const dotABAB = dot(ab, ab);
89
+ const dotABAC = dot(ab, ac);
90
+ const dotACAC = dot(ac, ac);
91
+ const dotAPAB = dot(ap, ab);
92
+ const dotAPAC = dot(ap, ac);
93
+ const denom = dotABAB * dotACAC - dotABAC * dotABAC;
94
+
95
+ const v = (dotACAC * dotAPAB - dotABAC * dotAPAC) / denom;
96
+ const w = (dotABAB * dotAPAC - dotABAC * dotAPAB) / denom;
97
+ const u = 1 - v - w;
98
+
99
+ // Use the barycentric weighting along with the original triangle z coordinates to get the point of intersection.
100
+ const distance = a.z * u + b.z * v + c.z * w;
101
+
102
+ if (Number.isFinite(distance)) return distance;
103
+ }
104
+ return Number.POSITIVE_INFINITY;
90
105
  }
91
106
  // The counts as closest is less clear when the query is a box. This
92
107
  // returns the distance to the nearest point on the face, whether it is
@@ -191,4 +206,4 @@ function projectQueryGeometry(queryGeometry, pixelPosMatrix, transform, z) {
191
206
  return projectedQueryGeometry;
192
207
  }
193
208
 
194
- module.exports = FillExtrusionStyleLayer;
209
+ module.exports = { FillExtrusionStyleLayer, getIntersectionDistance };
@@ -13,9 +13,9 @@ class FillStyleLayer extends StyleLayer {
13
13
  recalculate(parameters) {
14
14
  super.recalculate(parameters);
15
15
 
16
- const outlineColor = this.paint._values['fill-outline-color'];
16
+ const outlineColor = this._paint._values['fill-outline-color'];
17
17
  if (outlineColor.value.kind === 'constant' && outlineColor.value.value === undefined) {
18
- this.paint._values['fill-outline-color'] = this.paint._values['fill-color'];
18
+ this._paint._values['fill-outline-color'] = this._paint._values['fill-color'];
19
19
  }
20
20
  }
21
21
 
@@ -24,14 +24,14 @@ class FillStyleLayer extends StyleLayer {
24
24
  }
25
25
 
26
26
  queryRadius() {
27
- return translateDistance(this.paint.get('fill-translate'));
27
+ return translateDistance(this._paint.get('fill-translate'));
28
28
  }
29
29
 
30
30
  queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform, pixelsToTileUnits) {
31
31
  const translatedPolygon = translate(
32
32
  queryGeometry,
33
- this.paint.get('fill-translate'),
34
- this.paint.get('fill-translate-anchor'),
33
+ this._paint.get('fill-translate'),
34
+ this._paint.get('fill-translate-anchor'),
35
35
  transform.angle,
36
36
  pixelsToTileUnits
37
37
  );
@@ -44,7 +44,7 @@ class HeatmapStyleLayer extends StyleLayer {
44
44
  }
45
45
 
46
46
  hasOffscreenPass() {
47
- return this.paint.get('heatmap-opacity') !== 0 && this.visibility !== 'none';
47
+ return this._paint.get('heatmap-opacity') !== 0 && this.visibility !== 'none';
48
48
  }
49
49
  }
50
50
 
@@ -8,7 +8,7 @@ class HillshadeStyleLayer extends StyleLayer {
8
8
  }
9
9
 
10
10
  hasOffscreenPass() {
11
- return this.paint.get('hillshade-exaggeration') !== 0 && this.visibility !== 'none';
11
+ return this._paint.get('hillshade-exaggeration') !== 0 && this.visibility !== 'none';
12
12
  }
13
13
  }
14
14
 
@@ -49,7 +49,7 @@ class LineStyleLayer extends StyleLayer {
49
49
  recalculate(parameters) {
50
50
  super.recalculate(parameters);
51
51
 
52
- this.paint._values['line-floorwidth'] = lineFloorwidthProperty.possiblyEvaluate(
52
+ this._paint._values['line-floorwidth'] = lineFloorwidthProperty.possiblyEvaluate(
53
53
  this._transitioningPaint._values['line-width'].value,
54
54
  parameters
55
55
  );
@@ -66,24 +66,24 @@ class LineStyleLayer extends StyleLayer {
66
66
  getMaximumPaintValue('line-gap-width', this, lineBucket)
67
67
  );
68
68
  const offset = getMaximumPaintValue('line-offset', this, lineBucket);
69
- return width / 2 + Math.abs(offset) + translateDistance(this.paint.get('line-translate'));
69
+ return width / 2 + Math.abs(offset) + translateDistance(this._paint.get('line-translate'));
70
70
  }
71
71
 
72
72
  queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform, pixelsToTileUnits) {
73
73
  const translatedPolygon = translate(
74
74
  queryGeometry,
75
- this.paint.get('line-translate'),
76
- this.paint.get('line-translate-anchor'),
75
+ this._paint.get('line-translate'),
76
+ this._paint.get('line-translate-anchor'),
77
77
  transform.angle,
78
78
  pixelsToTileUnits
79
79
  );
80
80
  const halfWidth =
81
81
  (pixelsToTileUnits / 2) *
82
82
  getLineWidth(
83
- this.paint.get('line-width').evaluate(feature, featureState),
84
- this.paint.get('line-gap-width').evaluate(feature, featureState)
83
+ this._paint.get('line-width').evaluate(feature, featureState),
84
+ this._paint.get('line-gap-width').evaluate(feature, featureState)
85
85
  );
86
- const lineOffset = this.paint.get('line-offset').evaluate(feature, featureState);
86
+ const lineOffset = this._paint.get('line-offset').evaluate(feature, featureState);
87
87
  if (lineOffset) {
88
88
  geometry = offsetLine(geometry, lineOffset * pixelsToTileUnits);
89
89
  }
@@ -105,25 +105,29 @@ function getLineWidth(lineWidth, lineGapWidth) {
105
105
  }
106
106
 
107
107
  function offsetLine(rings, offset) {
108
- const newRings = [];
109
- const zero = new Point(0, 0);
108
+ const newRings = new Array(rings.length);
110
109
  for (let k = 0; k < rings.length; k++) {
111
110
  const ring = rings[k];
112
- const newRing = [];
113
- for (let i = 0; i < ring.length; i++) {
114
- const a = ring[i - 1];
115
- const b = ring[i];
111
+ const newRing = new Array(ring.length);
112
+ newRings[k] = newRing;
113
+
114
+ let b = ring[0];
115
+ let aToB = new Point(0, 0);
116
+ for (let i = 0; i < ring.length - 1; i++) {
116
117
  const c = ring[i + 1];
117
- const aToB = i === 0 ? zero : b.sub(a)._unit()._perp();
118
- const bToC = i === ring.length - 1 ? zero : c.sub(b)._unit()._perp();
118
+ const bToC = c.sub(b)._unit()._perp();
119
119
  const extrude = aToB._add(bToC)._unit();
120
-
121
120
  const cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
122
- extrude._mult(1 / cosHalfAngle);
121
+ if (cosHalfAngle !== 0) {
122
+ extrude._div(cosHalfAngle);
123
+ }
124
+ newRing[i] = extrude._mult(offset)._add(b);
123
125
 
124
- newRing.push(extrude._mult(offset)._add(b));
126
+ b = c;
127
+ aToB = bToC;
125
128
  }
126
- newRings.push(newRing);
129
+
130
+ newRing[ring.length - 1] = aToB._unit()._mult(offset)._add(b);
127
131
  }
128
132
  return newRings;
129
133
  }
@@ -14,33 +14,33 @@ class SymbolStyleLayer extends StyleLayer {
14
14
  recalculate(parameters) {
15
15
  super.recalculate(parameters);
16
16
 
17
- if (this.layout.get('icon-rotation-alignment') === 'auto') {
18
- if (this.layout.get('symbol-placement') !== 'point') {
19
- this.layout._values['icon-rotation-alignment'] = 'map';
17
+ if (this._layout.get('icon-rotation-alignment') === 'auto') {
18
+ if (this._layout.get('symbol-placement') !== 'point') {
19
+ this._layout._values['icon-rotation-alignment'] = 'map';
20
20
  } else {
21
- this.layout._values['icon-rotation-alignment'] = 'viewport';
21
+ this._layout._values['icon-rotation-alignment'] = 'viewport';
22
22
  }
23
23
  }
24
24
 
25
- if (this.layout.get('text-rotation-alignment') === 'auto') {
26
- if (this.layout.get('symbol-placement') !== 'point') {
27
- this.layout._values['text-rotation-alignment'] = 'map';
25
+ if (this._layout.get('text-rotation-alignment') === 'auto') {
26
+ if (this._layout.get('symbol-placement') !== 'point') {
27
+ this._layout._values['text-rotation-alignment'] = 'map';
28
28
  } else {
29
- this.layout._values['text-rotation-alignment'] = 'viewport';
29
+ this._layout._values['text-rotation-alignment'] = 'viewport';
30
30
  }
31
31
  }
32
32
 
33
33
  // If unspecified, `*-pitch-alignment` inherits `*-rotation-alignment`
34
- if (this.layout.get('text-pitch-alignment') === 'auto') {
35
- this.layout._values['text-pitch-alignment'] = this.layout.get('text-rotation-alignment');
34
+ if (this._layout.get('text-pitch-alignment') === 'auto') {
35
+ this._layout._values['text-pitch-alignment'] = this._layout.get('text-rotation-alignment');
36
36
  }
37
- if (this.layout.get('icon-pitch-alignment') === 'auto') {
38
- this.layout._values['icon-pitch-alignment'] = this.layout.get('icon-rotation-alignment');
37
+ if (this._layout.get('icon-pitch-alignment') === 'auto') {
38
+ this._layout._values['icon-pitch-alignment'] = this._layout.get('icon-rotation-alignment');
39
39
  }
40
40
  }
41
41
 
42
42
  getValueAndResolveTokens(name, feature) {
43
- const value = this.layout.get(name).evaluate(feature, {});
43
+ const value = this._layout.get(name).evaluate(feature, {});
44
44
  const unevaluated = this._unevaluatedLayout._values[name];
45
45
  if (!unevaluated.isDataDriven() && !isExpression(unevaluated.value)) {
46
46
  return resolveTokens(feature.properties, value);
@@ -4,10 +4,20 @@ const { Evented } = require('@mapwhit/events');
4
4
  const { Layout, Transitionable, PossiblyEvaluatedPropertyValue } = require('./properties');
5
5
  const { supportsPropertyExpression } = require('@mapwhit/style-expressions');
6
6
  const featureFilter = require('../style-spec/feature_filter');
7
+ const createKey = require('../util/key');
7
8
 
9
+ const keyProperties = ['type', 'minzoom', 'maxzoom', 'filter', 'layout'];
8
10
  const TRANSITION_SUFFIX = '-transition';
9
11
 
12
+ /**
13
+ * Representing a style layer in the map.
14
+ * Properties:
15
+ * `this.paint` - paint properties of the layer as defined in the map style
16
+ * `this._paint` - internal representation of paint properties necessary to calculate expressions
17
+ */
10
18
  class StyleLayer extends Evented {
19
+ #key;
20
+
11
21
  constructor(layer, properties) {
12
22
  super();
13
23
 
@@ -22,7 +32,7 @@ class StyleLayer extends Evented {
22
32
 
23
33
  if (layer.type !== 'background') {
24
34
  this.source = layer.source;
25
- this.sourceLayer = layer['source-layer'];
35
+ this['source-layer'] = this.sourceLayer = layer['source-layer'];
26
36
  this.filter = layer.filter;
27
37
  this._featureFilter = featureFilter(layer.filter);
28
38
  }
@@ -46,10 +56,26 @@ class StyleLayer extends Evented {
46
56
  }
47
57
 
48
58
  setFilter(filter) {
59
+ this.#key = undefined;
49
60
  this.filter = filter;
50
61
  this._featureFilter = featureFilter(filter);
51
62
  }
52
63
 
64
+ _setZoomRange(minzoom, maxzoom) {
65
+ if (this.minzoom === minzoom && this.maxzoom === maxzoom) {
66
+ return;
67
+ }
68
+ if (minzoom != null) {
69
+ this.#key = undefined;
70
+ this.minzoom = minzoom;
71
+ }
72
+ if (maxzoom != null) {
73
+ this.#key = undefined;
74
+ this.maxzoom = maxzoom;
75
+ }
76
+ return true;
77
+ }
78
+
53
79
  getCrossfadeParameters() {
54
80
  return this._crossfadeParameters;
55
81
  }
@@ -87,7 +113,32 @@ class StyleLayer extends Evented {
87
113
  return globalStateRefs;
88
114
  }
89
115
 
116
+ /**
117
+ * Get list of global state references that are used within paint properties.
118
+ * This is used to determine if layer needs to be repainted when global state property changes.
119
+ *
120
+ */
121
+ getPaintAffectingGlobalStateRefs() {
122
+ const globalStateRefs = new Map();
123
+
124
+ if (this._transitionablePaint) {
125
+ for (const propertyName in this._transitionablePaint._values) {
126
+ const value = this._transitionablePaint._values[propertyName].value;
127
+
128
+ for (const globalStateRef of value.getGlobalStateRefs()) {
129
+ const properties = globalStateRefs.get(globalStateRef) ?? [];
130
+ properties.push({ name: propertyName, value: value.value });
131
+ globalStateRefs.set(globalStateRef, properties);
132
+ }
133
+ }
134
+ }
135
+
136
+ return globalStateRefs;
137
+ }
138
+
90
139
  setLayoutProperty(name, value) {
140
+ this.#key = undefined;
141
+ this.layout[name] = value;
91
142
  if (name === 'visibility') {
92
143
  this.visibility = value === 'none' ? value : 'visible';
93
144
  return;
@@ -104,6 +155,7 @@ class StyleLayer extends Evented {
104
155
  }
105
156
 
106
157
  setPaintProperty(name, value) {
158
+ this.paint[name] = value;
107
159
  if (name.endsWith(TRANSITION_SUFFIX)) {
108
160
  this._transitionablePaint.setTransition(name.slice(0, -TRANSITION_SUFFIX.length), value || undefined);
109
161
  return false;
@@ -118,9 +170,19 @@ class StyleLayer extends Evented {
118
170
  this._transitionablePaint.setValue(name, value);
119
171
  const isDataDriven = this._transitionablePaint._values[name].value.isDataDriven();
120
172
  this._handleSpecialPaintPropertyUpdate(name);
173
+ if (isDataDriven !== wasDataDriven || (wasDataDriven && isDataDriven)) {
174
+ // reset transitioning in progress
175
+ this._untransitioned(name);
176
+ }
121
177
  return isDataDriven || wasDataDriven || newCrossFadedValue;
122
178
  }
123
179
 
180
+ _untransitioned(name) {
181
+ if (this._transitioningPaint) {
182
+ this._transitioningPaint._values[name] = this._transitionablePaint._values[name].untransitioned();
183
+ }
184
+ }
185
+
124
186
  _handleSpecialPaintPropertyUpdate() {
125
187
  // No-op; can be overridden by derived classes.
126
188
  }
@@ -144,38 +206,17 @@ class StyleLayer extends Evented {
144
206
  this._crossfadeParameters = parameters.getCrossfadeParameters();
145
207
  }
146
208
  if (this._unevaluatedLayout) {
147
- this.layout = this._unevaluatedLayout.possiblyEvaluate(parameters);
209
+ this._layout = this._unevaluatedLayout.possiblyEvaluate(parameters);
148
210
  }
149
211
 
150
- this.paint = this._transitioningPaint.possiblyEvaluate(parameters);
212
+ this._paint = this._transitioningPaint.possiblyEvaluate(parameters);
151
213
  }
152
214
 
153
- serialize() {
154
- const output = {
155
- id: this.id,
156
- type: this.type,
157
- source: this.source,
158
- 'source-layer': this.sourceLayer,
159
- metadata: this.metadata,
160
- minzoom: this.minzoom,
161
- maxzoom: this.maxzoom,
162
- filter: this.filter,
163
- layout: this._unevaluatedLayout?.serialize(),
164
- paint: this._transitionablePaint?.serialize()
165
- };
166
-
167
- if (this.visibility === 'none') {
168
- output.layout = output.layout || {};
169
- output.layout.visibility = 'none';
215
+ get key() {
216
+ if (!this.#key) {
217
+ this.#key = createKey(keyProperties, this);
170
218
  }
171
-
172
- return filterObject(output, (value, key) => {
173
- return (
174
- value !== undefined &&
175
- !(key === 'layout' && !Object.keys(value).length) &&
176
- !(key === 'paint' && !Object.keys(value).length)
177
- );
178
- });
219
+ return this.#key;
179
220
  }
180
221
 
181
222
  is3D() {
@@ -195,8 +236,8 @@ class StyleLayer extends Evented {
195
236
  }
196
237
 
197
238
  isStateDependent() {
198
- for (const property in this.paint._values) {
199
- const value = this.paint.get(property);
239
+ for (const property in this._paint._values) {
240
+ const value = this._paint.get(property);
200
241
  if (
201
242
  !(value instanceof PossiblyEvaluatedPropertyValue) ||
202
243
  !supportsPropertyExpression(value.property.specification)
@@ -1,54 +1,29 @@
1
- const createStyleLayer = require('./create_style_layer');
2
-
3
- const { values } = require('../util/object');
4
- const featureFilter = require('../style-spec/feature_filter');
5
- const groupByLayout = require('../style-spec/group_by_layout');
1
+ const groupBySource = require('../util/group_layers');
6
2
 
7
3
  class StyleLayerIndex {
8
- #layerConfigs = {};
9
- #layers = {};
4
+ #layers = new Map();
5
+ #fbs = {};
10
6
 
11
- constructor(layerConfigs) {
12
- if (layerConfigs) {
13
- this.update(layerConfigs);
7
+ constructor(layers) {
8
+ if (layers) {
9
+ this.replace(layers);
14
10
  }
15
11
  }
16
12
 
17
- replace(layerConfigs) {
18
- this.#layerConfigs = {};
19
- this.#layers = {};
20
- this.update(layerConfigs);
13
+ replace(layers) {
14
+ this.#layers = layers;
15
+ this.#fbs = null;
21
16
  }
22
17
 
23
- update(layerConfigs, removedIds = []) {
24
- for (const layerConfig of layerConfigs) {
25
- this.#layerConfigs[layerConfig.id] = layerConfig;
26
-
27
- const layer = (this.#layers[layerConfig.id] = createStyleLayer(layerConfig));
28
- layer._featureFilter = featureFilter(layer.filter);
29
- }
30
- for (const id of removedIds) {
31
- delete this.#layerConfigs[id];
32
- delete this.#layers[id];
33
- }
34
-
35
- this.familiesBySource = {};
36
-
37
- const groups = groupByLayout(values(this.#layerConfigs));
38
-
39
- for (const layerConfigs of groups) {
40
- const layers = layerConfigs.map(layerConfig => this.#layers[layerConfig.id]);
41
-
42
- const layer = layers[0];
43
- if (layer.visibility === 'none') {
44
- continue;
45
- }
18
+ update() {
19
+ this.#fbs = null;
20
+ }
46
21
 
47
- const { source = '', sourceLayer = '_geojsonTileLayer' } = layer;
48
- const sourceGroup = (this.familiesBySource[source] ??= {});
49
- const sourceLayerFamilies = (sourceGroup[sourceLayer] ??= []);
50
- sourceLayerFamilies.push(layers);
22
+ get familiesBySource() {
23
+ if (!this.#fbs) {
24
+ this.#fbs = groupBySource(this.#layers.values());
51
25
  }
26
+ return this.#fbs;
52
27
  }
53
28
  }
54
29
 
@@ -1,7 +1,5 @@
1
1
  const { default: Point } = require('@mapbox/point-geometry');
2
2
 
3
- const { register } = require('../util/transfer_registry');
4
-
5
3
  class Anchor extends Point {
6
4
  constructor(x, y, angle, segment) {
7
5
  super(x, y);
@@ -16,6 +14,4 @@ class Anchor extends Point {
16
14
  }
17
15
  }
18
16
 
19
- register('Anchor', Anchor);
20
-
21
17
  module.exports = Anchor;
@@ -260,12 +260,9 @@ class CrossTileSymbolIndex {
260
260
  }
261
261
 
262
262
  pruneUnusedLayers(usedLayers) {
263
- const usedLayerMap = {};
264
- usedLayers.forEach(usedLayer => {
265
- usedLayerMap[usedLayer] = true;
266
- });
263
+ const usedLayersSet = new Set(usedLayers);
267
264
  for (const layerId in this.layerIndexes) {
268
- if (!usedLayerMap[layerId]) {
265
+ if (!usedLayersSet.has(layerId)) {
269
266
  delete this.layerIndexes[layerId];
270
267
  }
271
268
  }
@@ -1,5 +1,3 @@
1
- const { register } = require('../util/transfer_registry');
2
-
3
1
  class OpacityState {
4
2
  constructor() {
5
3
  this.opacity = 0;
@@ -16,6 +14,4 @@ class OpacityState {
16
14
  }
17
15
  }
18
16
 
19
- register('OpacityState', OpacityState);
20
-
21
17
  module.exports = OpacityState;
@@ -100,7 +100,7 @@ class Placement {
100
100
 
101
101
  const collisionBoxArray = tile.collisionBoxArray;
102
102
 
103
- const layout = symbolBucket.layers[0].layout;
103
+ const layout = symbolBucket.layers[0]._layout;
104
104
 
105
105
  const scale = 2 ** (this.transform.zoom - tile.tileID.overscaledZ);
106
106
  const textPixelRatio = tile.tileSize / EXTENT;
@@ -159,7 +159,7 @@ class Placement {
159
159
  seenCrossTileIDs,
160
160
  collisionBoxArray
161
161
  ) {
162
- const layout = bucket.layers[0].layout;
162
+ const layout = bucket.layers[0]._layout;
163
163
 
164
164
  const partiallyEvaluatedTextSize = symbolSize.evaluateSizeForZoom(
165
165
  bucket.textSizeData,
@@ -411,7 +411,7 @@ class Placement {
411
411
  if (bucket.hasCollisionBoxData()) bucket.collisionBox.collisionVertexArray.clear();
412
412
  if (bucket.hasCollisionCircleData()) bucket.collisionCircle.collisionVertexArray.clear();
413
413
 
414
- const layout = bucket.layers[0].layout;
414
+ const layout = bucket.layers[0]._layout;
415
415
  const duplicateOpacityState = new JointOpacityState(null, 0, false, false, true);
416
416
  const textAllowOverlap = layout.get('text-allow-overlap');
417
417
  const iconAllowOverlap = layout.get('icon-allow-overlap');