@mapwhit/tilerenderer 0.49.0 → 0.51.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 (147) hide show
  1. package/build/min/package.json +1 -1
  2. package/build/min/src/shaders/.dir +0 -0
  3. package/build/min/src/shaders/_prelude.fragment.glsl.js +14 -0
  4. package/build/min/src/shaders/_prelude.vertex.glsl.js +14 -0
  5. package/build/min/src/shaders/background.fragment.glsl.js +5 -0
  6. package/build/min/src/shaders/background.vertex.glsl.js +1 -0
  7. package/build/min/src/shaders/background_pattern.fragment.glsl.js +5 -0
  8. package/build/min/src/shaders/background_pattern.vertex.glsl.js +1 -0
  9. package/build/min/src/shaders/circle.fragment.glsl.js +20 -0
  10. package/build/min/src/shaders/circle.vertex.glsl.js +17 -0
  11. package/build/min/src/shaders/clipping_mask.fragment.glsl.js +1 -0
  12. package/build/min/src/shaders/clipping_mask.vertex.glsl.js +1 -0
  13. package/build/min/src/shaders/collision_box.fragment.glsl.js +1 -0
  14. package/build/min/src/shaders/collision_box.vertex.glsl.js +1 -0
  15. package/build/min/src/shaders/collision_circle.fragment.glsl.js +1 -0
  16. package/build/min/src/shaders/collision_circle.vertex.glsl.js +1 -0
  17. package/build/min/src/shaders/debug.fragment.glsl.js +1 -0
  18. package/build/min/src/shaders/debug.vertex.glsl.js +1 -0
  19. package/build/min/src/shaders/fill.fragment.glsl.js +10 -0
  20. package/build/min/src/shaders/fill.vertex.glsl.js +7 -0
  21. package/build/min/src/shaders/fill_extrusion.fragment.glsl.js +5 -0
  22. package/build/min/src/shaders/fill_extrusion.fragment.glsl.txt +1 -9
  23. package/build/min/src/shaders/fill_extrusion.vertex.glsl.js +9 -0
  24. package/build/min/src/shaders/fill_extrusion.vertex.glsl.txt +4 -4
  25. package/build/min/src/shaders/fill_extrusion_pattern.fragment.glsl.js +15 -0
  26. package/build/min/src/shaders/fill_extrusion_pattern.vertex.glsl.js +11 -0
  27. package/build/min/src/shaders/fill_outline.fragment.glsl.js +10 -0
  28. package/build/min/src/shaders/fill_outline.vertex.glsl.js +7 -0
  29. package/build/min/src/shaders/fill_outline_pattern.fragment.glsl.js +13 -0
  30. package/build/min/src/shaders/fill_outline_pattern.vertex.glsl.js +9 -0
  31. package/build/min/src/shaders/fill_pattern.fragment.glsl.js +13 -0
  32. package/build/min/src/shaders/fill_pattern.vertex.glsl.js +9 -0
  33. package/build/min/src/shaders/heatmap.fragment.glsl.js +10 -0
  34. package/build/min/src/shaders/heatmap.vertex.glsl.js +8 -0
  35. package/build/min/src/shaders/heatmap_texture.fragment.glsl.js +5 -0
  36. package/build/min/src/shaders/heatmap_texture.vertex.glsl.js +1 -0
  37. package/build/min/src/shaders/hillshade.fragment.glsl.js +7 -0
  38. package/build/min/src/shaders/hillshade.vertex.glsl.js +1 -0
  39. package/build/min/src/shaders/hillshade_prepare.fragment.glsl.js +8 -0
  40. package/build/min/src/shaders/hillshade_prepare.vertex.glsl.js +1 -0
  41. package/build/min/src/shaders/line.fragment.glsl.js +12 -0
  42. package/build/min/src/shaders/line.vertex.glsl.js +17 -0
  43. package/build/min/src/shaders/line_gradient.fragment.glsl.js +10 -0
  44. package/build/min/src/shaders/line_gradient.vertex.glsl.js +16 -0
  45. package/build/min/src/shaders/line_pattern.fragment.glsl.js +15 -0
  46. package/build/min/src/shaders/line_pattern.vertex.glsl.js +20 -0
  47. package/build/min/src/shaders/line_sdf.fragment.glsl.js +17 -0
  48. package/build/min/src/shaders/line_sdf.vertex.glsl.js +20 -0
  49. package/build/min/src/shaders/raster.fragment.glsl.js +5 -0
  50. package/build/min/src/shaders/raster.vertex.glsl.js +1 -0
  51. package/build/min/src/shaders/symbol_icon.fragment.glsl.js +9 -0
  52. package/build/min/src/shaders/symbol_icon.vertex.glsl.js +5 -0
  53. package/build/min/src/shaders/symbol_sdf.fragment.glsl.js +19 -0
  54. package/build/min/src/shaders/symbol_sdf.vertex.glsl.js +13 -0
  55. package/package.json +7 -7
  56. package/src/data/bucket/fill_bucket.js +1 -1
  57. package/src/data/bucket/fill_extrusion_bucket.js +2 -2
  58. package/src/data/bucket/line_bucket.js +1 -1
  59. package/src/data/bucket/symbol_bucket.js +16 -15
  60. package/src/data/feature_index.js +1 -1
  61. package/src/data/program_configuration.js +1 -1
  62. package/src/gl/color_mode.js +1 -1
  63. package/src/gl/value.js +1 -1
  64. package/src/render/draw_debug.js +1 -1
  65. package/src/render/draw_fill.js +1 -1
  66. package/src/render/draw_heatmap.js +1 -1
  67. package/src/render/glyph_manager.js +6 -130
  68. package/src/render/painter.js +1 -1
  69. package/src/render/uniform_binding.js +1 -1
  70. package/src/shaders/fill_extrusion.fragment.glsl +0 -7
  71. package/src/shaders/fill_extrusion.vertex.glsl +4 -4
  72. package/src/shaders/index.js +50 -50
  73. package/src/source/geojson_worker_source.js +4 -4
  74. package/src/source/geojson_wrapper.js +34 -26
  75. package/src/source/resources/glyphs.js +73 -0
  76. package/src/source/resources/images.js +68 -0
  77. package/src/source/resources/index.js +22 -0
  78. package/src/source/vector_tile_worker_source.js +5 -5
  79. package/src/source/worker.js +6 -5
  80. package/src/source/worker_tile.js +4 -4
  81. package/src/style/properties.js +1 -2
  82. package/src/style/style.js +3 -3
  83. package/src/style/style_layer/symbol_style_layer.js +1 -1
  84. package/src/style/style_layer.js +1 -1
  85. package/src/style-spec/feature_filter/index.js +43 -34
  86. package/src/style-spec/group_by_layout.js +10 -32
  87. package/src/style-spec/reference/v8.json +1 -1
  88. package/src/symbol/mergelines.js +1 -3
  89. package/src/symbol/placement.js +21 -2
  90. package/src/symbol/shaping.js +9 -18
  91. package/src/symbol/symbol_layout.js +1 -2
  92. package/src/symbol/symbol_size.js +1 -1
  93. package/src/symbol/transform_text.js +4 -8
  94. package/src/ui/map.js +11 -39
  95. package/src/util/browser.js +3 -18
  96. package/src/util/classify_rings.js +1 -1
  97. package/src/util/dom.js +0 -88
  98. package/src/util/find_pole_of_inaccessibility.js +2 -2
  99. package/src/util/web_worker_transfer.js +4 -4
  100. package/src/style/load_glyph_range.js +0 -17
  101. package/src/style-spec/expression/compound_expression.js +0 -132
  102. package/src/style-spec/expression/definitions/assertion.js +0 -116
  103. package/src/style-spec/expression/definitions/at.js +0 -57
  104. package/src/style-spec/expression/definitions/case.js +0 -73
  105. package/src/style-spec/expression/definitions/coalesce.js +0 -68
  106. package/src/style-spec/expression/definitions/coercion.js +0 -109
  107. package/src/style-spec/expression/definitions/collator.js +0 -102
  108. package/src/style-spec/expression/definitions/comparison.js +0 -193
  109. package/src/style-spec/expression/definitions/formatted.js +0 -123
  110. package/src/style-spec/expression/definitions/index.js +0 -356
  111. package/src/style-spec/expression/definitions/interpolate.js +0 -245
  112. package/src/style-spec/expression/definitions/length.js +0 -54
  113. package/src/style-spec/expression/definitions/let.js +0 -60
  114. package/src/style-spec/expression/definitions/literal.js +0 -69
  115. package/src/style-spec/expression/definitions/match.js +0 -142
  116. package/src/style-spec/expression/definitions/step.js +0 -116
  117. package/src/style-spec/expression/definitions/var.js +0 -38
  118. package/src/style-spec/expression/evaluation_context.js +0 -35
  119. package/src/style-spec/expression/index.js +0 -329
  120. package/src/style-spec/expression/is_constant.js +0 -63
  121. package/src/style-spec/expression/parsing_context.js +0 -212
  122. package/src/style-spec/expression/parsing_error.js +0 -9
  123. package/src/style-spec/expression/runtime_error.js +0 -12
  124. package/src/style-spec/expression/scope.js +0 -34
  125. package/src/style-spec/expression/stops.js +0 -37
  126. package/src/style-spec/expression/types.js +0 -88
  127. package/src/style-spec/expression/values.js +0 -126
  128. package/src/style-spec/function/convert.js +0 -234
  129. package/src/style-spec/function/index.js +0 -299
  130. package/src/style-spec/util/color.js +0 -73
  131. package/src/style-spec/util/color_spaces.js +0 -128
  132. package/src/style-spec/util/get_type.js +0 -18
  133. package/src/style-spec/util/interpolate.js +0 -21
  134. package/src/style-spec/util/properties.js +0 -17
  135. package/src/style-spec/util/result.js +0 -19
  136. package/src/ui/anchor.js +0 -24
  137. package/src/ui/bind_handlers.js +0 -199
  138. package/src/ui/events.js +0 -210
  139. package/src/ui/handler/box_zoom.js +0 -151
  140. package/src/ui/handler/dblclick_zoom.js +0 -91
  141. package/src/ui/handler/drag_pan.js +0 -285
  142. package/src/ui/handler/drag_rotate.js +0 -290
  143. package/src/ui/handler/frame.js +0 -28
  144. package/src/ui/handler/inertia.js +0 -45
  145. package/src/ui/handler/keyboard.js +0 -148
  146. package/src/ui/handler/scroll_zoom.js +0 -284
  147. package/src/ui/handler/touch_zoom_rotate.js +0 -263
@@ -1,9 +1,9 @@
1
1
  const Point = require('@mapbox/point-geometry');
2
-
3
- const mvt = require('@mapbox/vector-tile');
4
- const toGeoJSON = mvt.VectorTileFeature.prototype.toGeoJSON;
2
+ const { VectorTileFeature } = require('@mapwhit/vector-tile');
5
3
  const EXTENT = require('../data/extent');
6
4
 
5
+ const { toGeoJSON } = VectorTileFeature.prototype;
6
+
7
7
  // The feature type used by geojson-vt and supercluster. Should be extracted to
8
8
  // global type and used in module definitions for those two modules.
9
9
 
@@ -11,10 +11,6 @@ class FeatureWrapper {
11
11
  constructor(feature) {
12
12
  this._feature = feature;
13
13
 
14
- this.extent = EXTENT;
15
- this.type = feature.type;
16
- this.properties = feature.tags;
17
-
18
14
  // If the feature has a top-level `id` property, copy it over, but only
19
15
  // if it can be coerced to an integer, because this wrapper is used for
20
16
  // serializing geojson feature data into vector tile PBF data, and the
@@ -26,23 +22,22 @@ class FeatureWrapper {
26
22
  }
27
23
  }
28
24
 
25
+ get type() {
26
+ return this._feature.type;
27
+ }
28
+
29
+ get properties() {
30
+ return this._feature.tags;
31
+ }
32
+
33
+ get extent() {
34
+ return EXTENT;
35
+ }
36
+
29
37
  loadGeometry() {
30
- if (this._feature.type === 1) {
31
- const geometry = [];
32
- for (const point of this._feature.geometry) {
33
- geometry.push([new Point(point[0], point[1])]);
34
- }
35
- return geometry;
36
- }
37
- const geometry = [];
38
- for (const ring of this._feature.geometry) {
39
- const newRing = [];
40
- for (const point of ring) {
41
- newRing.push(new Point(point[0], point[1]));
42
- }
43
- geometry.push(newRing);
44
- }
45
- return geometry;
38
+ return this.type === 1
39
+ ? this._feature.geometry.map(p => [makePoint(p)])
40
+ : this._feature.geometry.map(ring => ring.map(makePoint));
46
41
  }
47
42
 
48
43
  toGeoJSON(x, y, z) {
@@ -53,15 +48,28 @@ class FeatureWrapper {
53
48
  class GeoJSONWrapper {
54
49
  constructor(features) {
55
50
  this.layers = { _geojsonTileLayer: this };
56
- this.name = '_geojsonTileLayer';
57
- this.extent = EXTENT;
58
- this.length = features.length;
59
51
  this._features = features;
60
52
  }
61
53
 
54
+ get extent() {
55
+ return EXTENT;
56
+ }
57
+
58
+ get length() {
59
+ return this._features.length;
60
+ }
61
+
62
+ get name() {
63
+ return '_geojsonTileLayer';
64
+ }
65
+
62
66
  feature(i) {
63
67
  return new FeatureWrapper(this._features[i]);
64
68
  }
65
69
  }
66
70
 
67
71
  module.exports = GeoJSONWrapper;
72
+
73
+ function makePoint(arr) {
74
+ return new Point(arr[0], arr[1]);
75
+ }
@@ -0,0 +1,73 @@
1
+ const parseGlyphPBF = require('../../style/parse_glyph_pbf');
2
+
3
+ module.exports = glyphCache;
4
+
5
+ const MAX_GLYPH_ID = 65535;
6
+
7
+ function glyphCache({ actor, mapId, parseGlyphs = parseGlyphPBF }) {
8
+ const entries = {};
9
+
10
+ return {
11
+ getGlyphs
12
+ };
13
+
14
+ async function getGlyphs({ stacks }) {
15
+ const all = [];
16
+ for (const [stack, ids] of Object.entries(stacks)) {
17
+ const addedRanges = new Set();
18
+ for (const id of ids) {
19
+ if (id > MAX_GLYPH_ID) {
20
+ continue;
21
+ }
22
+ const range = Math.floor(id / 256);
23
+ if (!addedRanges.has(range) && !hasRange(stack, range)) {
24
+ addedRanges.add(range);
25
+ all.push(retrieveGlyphRange({ stack, range }));
26
+ }
27
+ }
28
+ }
29
+ if (all.length > 0) {
30
+ await Promise.all(all);
31
+ }
32
+ const result = {};
33
+ for (const [stack, ids] of Object.entries(stacks)) {
34
+ const entry = getEntry(stack);
35
+ const resultStack = (result[stack] ??= {});
36
+ for (const id of ids) {
37
+ if (id <= MAX_GLYPH_ID) {
38
+ resultStack[id] = entry.glyphs[id] ?? null;
39
+ } else {
40
+ resultStack[id] = null;
41
+ }
42
+ }
43
+ }
44
+ return result;
45
+ }
46
+
47
+ async function retrieveGlyphRange({ stack, range }) {
48
+ const entry = getEntry(stack);
49
+ const data = await loadGlyphRange(entry, stack, range);
50
+ if (!data) {
51
+ return null;
52
+ }
53
+ for (const glyph of parseGlyphs(data)) {
54
+ entry.glyphs[glyph.id] = glyph;
55
+ }
56
+ }
57
+
58
+ async function loadGlyphRange(entry, stack, range) {
59
+ const promise = (entry.requests[range] ??= actor.send('loadGlyphRange', { stack, range }, mapId));
60
+ const data = await promise;
61
+ delete entry.requests[range];
62
+ entry.ranges[range] = true;
63
+ return data;
64
+ }
65
+
66
+ function getEntry(stack) {
67
+ return (entries[stack] ??= { glyphs: {}, requests: {}, ranges: {} });
68
+ }
69
+
70
+ function hasRange(stack, range) {
71
+ return getEntry(stack).ranges[range];
72
+ }
73
+ }
@@ -0,0 +1,68 @@
1
+ module.exports = images;
2
+
3
+ function images({ actor, mapId }) {
4
+ const cache = new Map(); // id -> image
5
+ const inProgress = new Map(); // id -> promise
6
+
7
+ return {
8
+ getImages
9
+ };
10
+
11
+ async function getImages({ icons }) {
12
+ const missing = new Set();
13
+ const result = {};
14
+ for (const id of icons) {
15
+ if (cache.has(id)) {
16
+ const image = cache.get(id);
17
+ if (image) {
18
+ result[id] = image;
19
+ }
20
+ } else {
21
+ missing.add(id);
22
+ }
23
+ }
24
+ if (missing.size === 0) {
25
+ // All images are already in the cache
26
+ return result;
27
+ }
28
+ const active = new Set();
29
+ const needed = [...missing];
30
+ // Check if any of the missing images are already being fetched
31
+ for (const id of missing) {
32
+ if (inProgress.has(id)) {
33
+ active.add(inProgress.get(id));
34
+ missing.delete(id);
35
+ }
36
+ }
37
+ if (missing.size > 0) {
38
+ // Fetch the remaining images
39
+ await fetchMissing([...missing]);
40
+ }
41
+ if (active.size > 0) {
42
+ await Promise.all(active);
43
+ }
44
+ for (const id of needed) {
45
+ const image = cache.get(id);
46
+ if (image) {
47
+ result[id] = image;
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+
53
+ async function fetchMissing(icons) {
54
+ const promise = actor.send('getImages', { icons }, mapId);
55
+ for (const id of icons) {
56
+ inProgress.set(id, promise);
57
+ }
58
+ const result = await promise;
59
+ // Add the fetched images to the cache
60
+ for (const id of icons) {
61
+ cache.set(id, result[id]);
62
+ }
63
+ // Remove the fetched images from the inProgress set
64
+ for (const id of icons) {
65
+ inProgress.delete(id);
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,22 @@
1
+ const makeGlyphs = require('./glyphs');
2
+ const makeImages = require('./images');
3
+
4
+ module.exports = { resources };
5
+
6
+ function resources(actor, mapId) {
7
+ const glyphs = makeGlyphs({ actor, mapId });
8
+ const images = makeImages({ actor, mapId });
9
+
10
+ return {
11
+ getGlyphs,
12
+ getImages
13
+ };
14
+
15
+ function getGlyphs(params) {
16
+ return glyphs.getGlyphs(params);
17
+ }
18
+
19
+ function getImages(params) {
20
+ return images.getImages(params);
21
+ }
22
+ }
@@ -1,4 +1,4 @@
1
- const { VectorTile } = require('@mapbox/vector-tile');
1
+ const { VectorTile } = require('@mapwhit/vector-tile');
2
2
  const Protobuf = require('@mapwhit/pbf');
3
3
  const WorkerTile = require('./worker_tile');
4
4
 
@@ -20,7 +20,7 @@ function loadVectorTile(params) {
20
20
  * This class is designed to be easily reused to support custom source types
21
21
  * for data formats that can be parsed/converted into an in-memory VectorTile
22
22
  * representation. To do so, create it with
23
- * `new VectorTileWorkerSource(actor, styleLayers, customLoadVectorDataFunction)`.
23
+ * `new VectorTileWorkerSource(resources, styleLayers, customLoadVectorDataFunction)`.
24
24
  *
25
25
  * @private
26
26
  */
@@ -31,8 +31,8 @@ class VectorTileWorkerSource {
31
31
  * {@link VectorTileWorkerSource#loadTile}. The default implementation simply
32
32
  * loads the pbf at `params.url`.
33
33
  */
34
- constructor(actor, layerIndex, loadVectorData = loadVectorTile) {
35
- this.actor = actor;
34
+ constructor(resources, layerIndex, loadVectorData = loadVectorTile) {
35
+ this.resources = resources;
36
36
  this.layerIndex = layerIndex;
37
37
  this.loadVectorData = loadVectorData;
38
38
  }
@@ -50,7 +50,7 @@ class VectorTileWorkerSource {
50
50
  const { vectorTile, rawData } = response;
51
51
  const workerTile = new WorkerTile(params);
52
52
  workerTile.vectorTile = vectorTile;
53
- const result = await workerTile.parse(vectorTile, this.layerIndex, this.actor);
53
+ const result = await workerTile.parse(vectorTile, this.layerIndex, this.resources);
54
54
  if (rawData) {
55
55
  result.rawTileData = rawData;
56
56
  }
@@ -8,8 +8,11 @@ const GeoJSONWorkerSource = require('./geojson_worker_source');
8
8
  const assert = require('assert');
9
9
  const { plugin: globalRTLTextPlugin } = require('./rtl_text_plugin');
10
10
  const DEMData = require('../data/dem_data');
11
+ const { resources } = require('./resources');
11
12
 
12
13
  class Worker {
14
+ #resources = {};
15
+
13
16
  constructor(self) {
14
17
  this.self = self;
15
18
  this.actor = new Actor(self, this);
@@ -85,10 +88,8 @@ class Worker {
85
88
  return (this.layerIndexes[mapId] ??= new StyleLayerIndex());
86
89
  }
87
90
 
88
- getActor(mapId) {
89
- return (this.actors[mapId] ??= {
90
- send: (type, data) => this.actor.send(type, data, mapId)
91
- });
91
+ getResources(mapId) {
92
+ return (this.#resources[mapId] ??= resources(this.actor, mapId));
92
93
  }
93
94
 
94
95
  getWorkerSource(mapId, type, source) {
@@ -100,7 +101,7 @@ class Worker {
100
101
 
101
102
  createWorkerSource(type, mapId) {
102
103
  const WorkerSource = this.workerSourceTypes[type];
103
- return new WorkerSource(this.getActor(mapId), this.getLayerIndex(mapId));
104
+ return new WorkerSource(this.getResources(mapId), this.getLayerIndex(mapId));
104
105
  }
105
106
  }
106
107
 
@@ -33,7 +33,7 @@ class WorkerTile {
33
33
  this.showCollisionBoxes = params.showCollisionBoxes;
34
34
  }
35
35
 
36
- async parse(data, layerIndex, actor) {
36
+ async parse(data, layerIndex, resources) {
37
37
  this.status = 'parsing';
38
38
  this.data = data;
39
39
 
@@ -103,9 +103,9 @@ class WorkerTile {
103
103
  const icons = Object.keys(options.iconDependencies);
104
104
  const patterns = Object.keys(options.patternDependencies);
105
105
  const tasks = [
106
- Object.keys(stacks).length ? actor.send('getGlyphs', { uid: this.uid, stacks }) : {},
107
- icons.length ? actor.send('getImages', { icons }) : {},
108
- patterns.length ? actor.send('getImages', { icons: patterns }) : {}
106
+ Object.keys(stacks).length ? resources.getGlyphs({ uid: this.uid, stacks }) : {},
107
+ icons.length ? resources.getImages({ icons }) : {},
108
+ patterns.length ? resources.getImages({ icons: patterns }) : {}
109
109
  ];
110
110
  const [glyphMap, iconMap, patternMap] = await Promise.all(tasks);
111
111
  const glyphAtlas = new GlyphAtlas(glyphMap);
@@ -2,8 +2,7 @@ const assert = require('assert');
2
2
 
3
3
  const { clone } = require('../util/object');
4
4
  const { easeCubicInOut } = require('../util/util');
5
- const interpolate = require('../style-spec/util/interpolate');
6
- const { normalizePropertyExpression } = require('../style-spec/expression');
5
+ const { interpolate, normalizePropertyExpression } = require('@mapwhit/style-expressions');
7
6
  const { register } = require('../util/transfer_registry');
8
7
  const EvaluationParameters = require('./evaluation_parameters');
9
8
 
@@ -32,7 +32,7 @@ class Style extends Evented {
32
32
  this.map = map;
33
33
  this.dispatcher = dispatcher(getWorkerPool(), this);
34
34
  this.imageManager = new ImageManager();
35
- this.glyphManager = new GlyphManager(options.localIdeographFontFamily);
35
+ this.glyphManager = new GlyphManager();
36
36
  this.lineAtlas = new LineAtlas(256, 512);
37
37
  this.crossTileSymbolIndex = new CrossTileSymbolIndex();
38
38
 
@@ -928,8 +928,8 @@ class Style extends Evented {
928
928
  return this.imageManager.getImages(icons);
929
929
  }
930
930
 
931
- getGlyphs(_mapId, { stacks }) {
932
- return this.glyphManager.getGlyphs(stacks);
931
+ loadGlyphRange(_mapId, { stack, range }) {
932
+ return this.glyphManager.loadGlyphRange(stack, range);
933
933
  }
934
934
  }
935
935
 
@@ -2,7 +2,7 @@ const StyleLayer = require('../style_layer');
2
2
 
3
3
  const SymbolBucket = require('../../data/bucket/symbol_bucket');
4
4
  const resolveTokens = require('../../util/token');
5
- const { isExpression } = require('../../style-spec/expression');
5
+ const { isExpression } = require('@mapwhit/style-expressions');
6
6
  const assert = require('assert');
7
7
  const properties = require('./symbol_style_layer_properties');
8
8
 
@@ -2,7 +2,7 @@ const { filterObject } = require('../util/object');
2
2
 
3
3
  const { Evented } = require('../util/evented');
4
4
  const { Layout, Transitionable, PossiblyEvaluatedPropertyValue } = require('./properties');
5
- const { supportsPropertyExpression } = require('../style-spec/util/properties');
5
+ const { supportsPropertyExpression } = require('@mapwhit/style-expressions');
6
6
 
7
7
  const TRANSITION_SUFFIX = '-transition';
8
8
 
@@ -1,4 +1,4 @@
1
- const { createExpression } = require('../expression');
1
+ const { createExpression } = require('@mapwhit/style-expressions');
2
2
 
3
3
  module.exports = createFilter;
4
4
 
@@ -31,8 +31,9 @@ function isExpressionFilter(filter) {
31
31
 
32
32
  case 'any':
33
33
  case 'all':
34
- for (const f of filter.slice(1)) {
35
- if (!isExpressionFilter(f) && typeof f !== 'boolean') {
34
+ for (let i = 1; i < filter.length; i++) {
35
+ const f = filter[i];
36
+ if (typeof f !== 'boolean' && !isExpressionFilter(f)) {
36
37
  return false;
37
38
  }
38
39
  }
@@ -86,34 +87,37 @@ function compare(a, b) {
86
87
 
87
88
  function convertFilter(filter) {
88
89
  if (!filter) return true;
89
- const op = filter[0];
90
+ const [op, ...args] = filter;
90
91
  if (filter.length <= 1) return op !== 'any';
91
- const converted =
92
- op === '=='
93
- ? convertComparisonOp(filter[1], filter[2], '==')
94
- : op === '!='
95
- ? convertNegation(convertComparisonOp(filter[1], filter[2], '=='))
96
- : op === '<' || op === '>' || op === '<=' || op === '>='
97
- ? convertComparisonOp(filter[1], filter[2], op)
98
- : op === 'any'
99
- ? convertDisjunctionOp(filter.slice(1))
100
- : op === 'all'
101
- ? ['all'].concat(filter.slice(1).map(convertFilter))
102
- : op === 'none'
103
- ? ['all'].concat(filter.slice(1).map(convertFilter).map(convertNegation))
104
- : op === 'in'
105
- ? convertInOp(filter[1], filter.slice(2))
106
- : op === '!in'
107
- ? convertNegation(convertInOp(filter[1], filter.slice(2)))
108
- : op === 'has'
109
- ? convertHasOp(filter[1])
110
- : op === '!has'
111
- ? convertNegation(convertHasOp(filter[1]))
112
- : true;
113
- return converted;
92
+ switch (op) {
93
+ case '!=':
94
+ return convertNegation(convertComparisonOp('==', ...args));
95
+ case '==':
96
+ case '<':
97
+ case '>':
98
+ case '<=':
99
+ case '>=':
100
+ return convertComparisonOp(op, ...args);
101
+ case 'any':
102
+ return convertDisjunctionOp(args);
103
+ case 'all':
104
+ return ['all', ...args.map(convertFilter)];
105
+ case 'none':
106
+ return ['all', ...args.map(convertFilter).map(convertNegation)];
107
+ case 'in':
108
+ return convertInOp(args);
109
+ case '!in':
110
+ return convertNegation(convertInOp(args));
111
+ case 'has':
112
+ return convertHasOp(args[0]);
113
+ case '!has':
114
+ return convertNegation(convertHasOp(args[0]));
115
+ default:
116
+ return true;
117
+ }
114
118
  }
115
119
 
116
- function convertComparisonOp(property, value, op) {
120
+ function convertComparisonOp(op, property, value) {
117
121
  switch (property) {
118
122
  case '$type':
119
123
  return [`filter-type-${op}`, value];
@@ -125,10 +129,10 @@ function convertComparisonOp(property, value, op) {
125
129
  }
126
130
 
127
131
  function convertDisjunctionOp(filters) {
128
- return ['any'].concat(filters.map(convertFilter));
132
+ return ['any', ...filters.map(convertFilter)];
129
133
  }
130
134
 
131
- function convertInOp(property, values) {
135
+ function convertInOp([property, ...values]) {
132
136
  if (values.length === 0) {
133
137
  return false;
134
138
  }
@@ -138,13 +142,18 @@ function convertInOp(property, values) {
138
142
  case '$id':
139
143
  return ['filter-id-in', ['literal', values]];
140
144
  default:
141
- if (values.length > 200 && !values.some(v => typeof v !== typeof values[0])) {
142
- return ['filter-in-large', property, ['literal', values.sort(compare)]];
143
- }
144
- return ['filter-in-small', property, ['literal', values]];
145
+ return isUniformLarge(values)
146
+ ? ['filter-in-large', property, ['literal', values.sort(compare)]]
147
+ : ['filter-in-small', property, ['literal', values]];
145
148
  }
146
149
  }
147
150
 
151
+ function isUniformLarge(values) {
152
+ if (values.length < 200) return false;
153
+ const type = typeof values[0];
154
+ return values.every(v => typeof v === type);
155
+ }
156
+
148
157
  function convertHasOp(property) {
149
158
  switch (property) {
150
159
  case '$type':
@@ -1,33 +1,20 @@
1
1
  const refProperties = require('./util/ref_properties');
2
2
 
3
3
  function stringify(obj) {
4
+ if (obj == null) return 'null';
4
5
  const type = typeof obj;
5
- if (type === 'number' || type === 'boolean' || type === 'string' || obj === undefined || obj === null)
6
- return JSON.stringify(obj);
6
+ if (type === 'number' || type === 'boolean' || type === 'string') return obj;
7
7
 
8
8
  if (Array.isArray(obj)) {
9
- let str = '[';
10
- for (const val of obj) {
11
- str += `${stringify(val)},`;
12
- }
13
- return `${str}]`;
9
+ return '[' + obj.map(val => stringify(val)).join(',') + ']';
14
10
  }
15
11
 
16
12
  const keys = Object.keys(obj).sort();
17
-
18
- let str = '{';
19
- for (let i = 0; i < keys.length; i++) {
20
- str += `${JSON.stringify(keys[i])}:${stringify(obj[keys[i]])},`;
21
- }
22
- return `${str}}`;
13
+ return '{' + keys.map(key => `${key}:${stringify(obj[key])}`).join(',') + '}';
23
14
  }
24
15
 
25
16
  function getKey(layer) {
26
- let key = '';
27
- for (const k of refProperties) {
28
- key += `/${stringify(layer[k])}`;
29
- }
30
- return key;
17
+ return refProperties.map(k => stringify(layer[k])).join('/');
31
18
  }
32
19
 
33
20
  module.exports = groupByLayout;
@@ -49,20 +36,11 @@ module.exports = groupByLayout;
49
36
  function groupByLayout(layers) {
50
37
  const groups = {};
51
38
 
52
- for (let i = 0; i < layers.length; i++) {
53
- const k = getKey(layers[i]);
54
- let group = groups[k];
55
- if (!group) {
56
- group = groups[k] = [];
57
- }
58
- group.push(layers[i]);
59
- }
60
-
61
- const result = [];
62
-
63
- for (const k in groups) {
64
- result.push(groups[k]);
39
+ for (const l of layers) {
40
+ const k = getKey(l);
41
+ const group = (groups[k] ??= []);
42
+ group.push(l);
65
43
  }
66
44
 
67
- return result;
45
+ return Object.values(groups);
68
46
  }
@@ -3148,7 +3148,7 @@
3148
3148
  }
3149
3149
  },
3150
3150
  "concat": {
3151
- "doc": "Returns a `string` consisting of the concatenation of the inputs. If any inputs are `formatted`, returns a `formatted` with default formatting options for all unformatted inputs.",
3151
+ "doc": "Returns a `string` consisting of the concatenation of the inputs. Each input is converted to a string as if by `to-string`.",
3152
3152
  "group": "String",
3153
3153
  "sdk-support": {
3154
3154
  "basic functionality": {
@@ -1,5 +1,3 @@
1
- const { Formatted } = require('../style-spec/expression/definitions/formatted');
2
-
3
1
  module.exports = function (features) {
4
2
  const leftIndex = new Map();
5
3
  const rightIndex = new Map();
@@ -8,7 +6,7 @@ module.exports = function (features) {
8
6
 
9
7
  for (let k = 0; k < features.length; k++) {
10
8
  const { geometry, text: featureText } = features[k];
11
- const text = featureText instanceof Formatted ? featureText.toString() : featureText;
9
+ const text = featureText ? featureText.toString() : null;
12
10
 
13
11
  if (!text) {
14
12
  add(k);
@@ -170,6 +170,25 @@ class Placement {
170
170
  const textOptional = layout.get('text-optional');
171
171
  const iconOptional = layout.get('icon-optional');
172
172
 
173
+ const textAllowOverlap = layout.get('text-allow-overlap');
174
+ const iconAllowOverlap = layout.get('icon-allow-overlap');
175
+ // This logic is similar to the "defaultOpacityState" logic below in updateBucketOpacities
176
+ // If we know a symbol is always supposed to show, force it to be marked visible even if
177
+ // it wasn't placed into the collision index (because some or all of it was outside the range
178
+ // of the collision grid).
179
+ // There is a subtle edge case here we're accepting:
180
+ // Symbol A has text-allow-overlap: true, icon-allow-overlap: true, icon-optional: false
181
+ // A's icon is outside the grid, so doesn't get placed
182
+ // A's text would be inside grid, but doesn't get placed because of icon-optional: false
183
+ // We still show A because of the allow-overlap settings.
184
+ // Symbol B has allow-overlap: false, and gets placed where A's text would be
185
+ // On panning in, there is a short period when Symbol B and Symbol A will overlap
186
+ // This is the reverse of our normal policy of "fade in on pan", but should look like any other
187
+ // collision and hopefully not be too noticeable.
188
+ // See https://github.com/mapbox/mapbox-gl-js/issues/7172
189
+ const alwaysShowText = textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || iconOptional);
190
+ const alwaysShowIcon = iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || textOptional);
191
+
173
192
  const collisionGroup = this.collisionGroups.get(bucket.sourceID);
174
193
 
175
194
  if (!bucket.collisionArrays && collisionBoxArray) {
@@ -304,8 +323,8 @@ class Placement {
304
323
  assert(bucket.bucketInstanceId !== 0);
305
324
 
306
325
  this.placements[symbolInstance.crossTileID] = new JointPlacement(
307
- placeText,
308
- placeIcon,
326
+ placeText || (alwaysShowText && placedGlyphBoxes),
327
+ placeIcon || alwaysShowIcon,
309
328
  offscreen || bucket.justReloaded
310
329
  );
311
330
  seenCrossTileIDs[symbolInstance.crossTileID] = true;