@mapwhit/tilerenderer 0.47.2 → 0.49.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 (43) hide show
  1. package/build/min/package.json +1 -1
  2. package/package.json +3 -2
  3. package/src/data/array_types.js +169 -0
  4. package/src/data/bucket/symbol_attributes.js +18 -0
  5. package/src/data/bucket/symbol_bucket.js +116 -73
  6. package/src/data/program_configuration.js +18 -10
  7. package/src/geo/transform.js +17 -7
  8. package/src/index.js +1 -1
  9. package/src/render/glyph_atlas.js +3 -6
  10. package/src/render/image_atlas.js +3 -6
  11. package/src/render/image_manager.js +41 -41
  12. package/src/source/rtl_text_plugin.js +1 -0
  13. package/src/source/source_cache.js +1 -1
  14. package/src/source/tile.js +6 -5
  15. package/src/source/worker.js +1 -10
  16. package/src/style/style.js +4 -19
  17. package/src/style/style_layer/symbol_style_layer_properties.js +7 -1
  18. package/src/style-spec/expression/compound_expression.js +30 -16
  19. package/src/style-spec/expression/definitions/assertion.js +52 -5
  20. package/src/style-spec/expression/definitions/coercion.js +13 -0
  21. package/src/style-spec/expression/definitions/comparison.js +193 -0
  22. package/src/style-spec/expression/definitions/formatted.js +123 -0
  23. package/src/style-spec/expression/definitions/index.js +11 -62
  24. package/src/style-spec/expression/definitions/interpolate.js +17 -7
  25. package/src/style-spec/expression/definitions/literal.js +5 -0
  26. package/src/style-spec/expression/parsing_context.js +6 -7
  27. package/src/style-spec/expression/types.js +12 -1
  28. package/src/style-spec/feature_filter/convert.js +197 -0
  29. package/src/style-spec/feature_filter/index.js +5 -2
  30. package/src/style-spec/function/convert.js +78 -100
  31. package/src/style-spec/reference/v8.json +160 -52
  32. package/src/symbol/collision_index.js +0 -1
  33. package/src/symbol/cross_tile_symbol_index.js +12 -7
  34. package/src/symbol/get_anchors.js +11 -22
  35. package/src/symbol/mergelines.js +4 -1
  36. package/src/symbol/placement.js +58 -54
  37. package/src/symbol/quads.js +7 -6
  38. package/src/symbol/shaping.js +185 -40
  39. package/src/symbol/symbol_layout.js +40 -37
  40. package/src/symbol/transform_text.js +12 -1
  41. package/src/ui/map.js +8 -25
  42. package/src/style-spec/expression/definitions/array.js +0 -82
  43. package/src/style-spec/expression/definitions/equals.js +0 -93
@@ -12,6 +12,8 @@ const classifyRings = require('../util/classify_rings');
12
12
  const EXTENT = require('../data/extent');
13
13
  const SymbolBucket = require('../data/bucket/symbol_bucket');
14
14
  const EvaluationParameters = require('../style/evaluation_parameters');
15
+ const { Formatted } = require('../style-spec/expression/definitions/formatted');
16
+ const murmur3 = require('murmurhash-js');
15
17
 
16
18
  // The symbol layout process needs `text-size` evaluated at up to five different zoom levels, and
17
19
  // `icon-size` at up to three:
@@ -30,7 +32,6 @@ const EvaluationParameters = require('../style/evaluation_parameters');
30
32
 
31
33
  function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePositions, showCollisionBoxes) {
32
34
  bucket.createArrays();
33
- bucket.symbolInstances = [];
34
35
 
35
36
  const tileSize = 512 * bucket.overscaling;
36
37
  bucket.tilePixelRatio = EXTENT / tileSize;
@@ -73,18 +74,18 @@ function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePo
73
74
 
74
75
  for (const feature of bucket.features) {
75
76
  const fontstack = layout.get('text-font').evaluate(feature, {}).join(',');
76
- const glyphs = glyphMap[fontstack] || {};
77
- const glyphPositionMap = glyphPositions[fontstack] || {};
77
+ const glyphPositionMap = glyphPositions;
78
78
 
79
79
  const shapedTextOrientations = {};
80
80
  const text = feature.text;
81
81
  if (text) {
82
+ const unformattedText = text instanceof Formatted ? text.toString() : text;
82
83
  const textOffset = layout
83
84
  .get('text-offset')
84
85
  .evaluate(feature, {})
85
86
  .map(t => t * oneEm);
86
87
  const spacing = layout.get('text-letter-spacing').evaluate(feature, {}) * oneEm;
87
- const spacingIfAllowed = allowsLetterSpacing(text) ? spacing : 0;
88
+ const spacingIfAllowed = allowsLetterSpacing(unformattedText) ? spacing : 0;
88
89
  const textAnchor = layout.get('text-anchor').evaluate(feature, {});
89
90
  const textJustify = layout.get('text-justify').evaluate(feature, {});
90
91
  const maxWidth =
@@ -92,7 +93,8 @@ function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePo
92
93
 
93
94
  shapedTextOrientations.horizontal = shapeText(
94
95
  text,
95
- glyphs,
96
+ glyphMap,
97
+ fontstack,
96
98
  maxWidth,
97
99
  lineHeight,
98
100
  textAnchor,
@@ -102,10 +104,11 @@ function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePo
102
104
  oneEm,
103
105
  WritingMode.horizontal
104
106
  );
105
- if (allowsVerticalWritingMode(text) && textAlongLine && keepUpright) {
107
+ if (allowsVerticalWritingMode(unformattedText) && textAlongLine && keepUpright) {
106
108
  shapedTextOrientations.vertical = shapeText(
107
109
  text,
108
- glyphs,
110
+ glyphMap,
111
+ fontstack,
109
112
  maxWidth,
110
113
  lineHeight,
111
114
  textAnchor,
@@ -196,30 +199,28 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPo
196
199
  return;
197
200
  }
198
201
 
199
- bucket.symbolInstances.push(
200
- addSymbol(
201
- bucket,
202
- anchor,
203
- line,
204
- shapedTextOrientations,
205
- shapedIcon,
206
- bucket.layers[0],
207
- bucket.collisionBoxArray,
208
- feature.index,
209
- feature.sourceLayerIndex,
210
- bucket.index,
211
- textBoxScale,
212
- textPadding,
213
- textAlongLine,
214
- textOffset,
215
- iconBoxScale,
216
- iconPadding,
217
- iconAlongLine,
218
- iconOffset,
219
- feature,
220
- glyphPositionMap,
221
- sizes
222
- )
202
+ addSymbol(
203
+ bucket,
204
+ anchor,
205
+ line,
206
+ shapedTextOrientations,
207
+ shapedIcon,
208
+ bucket.layers[0],
209
+ bucket.collisionBoxArray,
210
+ feature.index,
211
+ feature.sourceLayerIndex,
212
+ bucket.index,
213
+ textBoxScale,
214
+ textPadding,
215
+ textAlongLine,
216
+ textOffset,
217
+ iconBoxScale,
218
+ iconPadding,
219
+ iconAlongLine,
220
+ iconOffset,
221
+ feature,
222
+ glyphPositionMap,
223
+ sizes
223
224
  );
224
225
  };
225
226
 
@@ -365,7 +366,7 @@ function addSymbol(
365
366
  let numIconVertices = 0;
366
367
  let numGlyphVertices = 0;
367
368
  let numVerticalGlyphVertices = 0;
368
- const key = shapedTextOrientations.horizontal ? shapedTextOrientations.horizontal.text : '';
369
+ const key = murmur3(shapedTextOrientations.horizontal ? shapedTextOrientations.horizontal.text : '');
369
370
  const placedTextSymbolIndices = [];
370
371
  if (shapedTextOrientations.horizontal) {
371
372
  // As a collision approximation, we can use either the vertical or the horizontal version of the feature
@@ -480,20 +481,22 @@ function addSymbol(
480
481
  if (bucket.glyphOffsetArray.length >= SymbolBucket.MAX_GLYPHS)
481
482
  warn.once('Too many glyphs being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907');
482
483
 
483
- return {
484
+ bucket.symbolInstances.emplaceBack(
485
+ anchor.x,
486
+ anchor.y,
487
+ placedTextSymbolIndices.length > 0 ? placedTextSymbolIndices[0] : -1,
488
+ placedTextSymbolIndices.length > 1 ? placedTextSymbolIndices[1] : -1,
484
489
  key,
485
490
  textBoxStartIndex,
486
491
  textBoxEndIndex,
487
492
  iconBoxStartIndex,
488
493
  iconBoxEndIndex,
489
- anchor,
490
494
  featureIndex,
491
495
  numGlyphVertices,
492
496
  numVerticalGlyphVertices,
493
497
  numIconVertices,
494
- placedTextSymbolIndices,
495
- crossTileID: 0
496
- };
498
+ 0
499
+ );
497
500
  }
498
501
 
499
502
  function anchorIsTooClose(bucket, text, repeatDistance, anchor) {
@@ -1,6 +1,7 @@
1
1
  const { plugin: rtlTextPlugin } = require('../source/rtl_text_plugin');
2
+ const { Formatted } = require('../style-spec/expression/definitions/formatted');
2
3
 
3
- module.exports = function (text, layer, feature) {
4
+ function transformText(text, layer, feature) {
4
5
  const transform = layer.layout.get('text-transform').evaluate(feature, {});
5
6
  if (transform === 'uppercase') {
6
7
  text = text.toLocaleUpperCase();
@@ -13,4 +14,14 @@ module.exports = function (text, layer, feature) {
13
14
  }
14
15
 
15
16
  return text;
17
+ }
18
+
19
+ module.exports = function (text, layer, feature) {
20
+ if (text instanceof Formatted) {
21
+ text.sections.forEach(section => {
22
+ section.text = transformText(section.text, layer, feature);
23
+ });
24
+ return text;
25
+ }
26
+ return transformText(text, layer, feature);
16
27
  };
package/src/ui/map.js CHANGED
@@ -289,22 +289,17 @@ class Map extends Camera {
289
289
  }
290
290
 
291
291
  /**
292
- * Returns the map's geographical bounds.
292
+ * Returns the map's geographical bounds. When the bearing or pitch is non-zero, the visible region is not
293
+ * an axis-aligned rectangle, and the result is the smallest bounds that encompasses the visible region.
293
294
  *
294
- * @returns {LngLatBounds} The map's geographical bounds.
295
+ * @returns {LngLatBounds}
295
296
  */
296
297
  getBounds() {
297
- const bounds = new LngLatBounds(
298
- this.transform.pointLocation(new Point(0, this.transform.height)),
299
- this.transform.pointLocation(new Point(this.transform.width, 0))
300
- );
301
-
302
- if (this.transform.angle || this.transform.pitch) {
303
- bounds.extend(this.transform.pointLocation(new Point(this.transform.size.x, 0)));
304
- bounds.extend(this.transform.pointLocation(new Point(0, this.transform.size.y)));
305
- }
306
-
307
- return bounds;
298
+ return new LngLatBounds()
299
+ .extend(this.transform.pointLocation(new Point(0, 0)))
300
+ .extend(this.transform.pointLocation(new Point(this.transform.width, 0)))
301
+ .extend(this.transform.pointLocation(new Point(this.transform.width, this.transform.height)))
302
+ .extend(this.transform.pointLocation(new Point(0, this.transform.height)));
308
303
  }
309
304
 
310
305
  /**
@@ -772,18 +767,6 @@ class Map extends Camera {
772
767
  return true;
773
768
  }
774
769
 
775
- /**
776
- * Adds a [custom source type](#Custom Sources), making it available for use with
777
- * {@link Map#addSource}.
778
- * @private
779
- * @param {string} name The name of the source type; source definition objects use this name in the `{type: ...}` field.
780
- * @param {Function} SourceType A {@link Source} constructor.
781
- * @param {Function} callback Called when the source type is ready or with an error argument if there is an error.
782
- */
783
- addSourceType(name, SourceType, callback) {
784
- return this.style.addSourceType(name, SourceType, callback);
785
- }
786
-
787
770
  /**
788
771
  * Removes a source from the map's style.
789
772
  *
@@ -1,82 +0,0 @@
1
- const { toString, array, ValueType, StringType, NumberType, BooleanType, checkSubtype } = require('../types');
2
-
3
- const { typeOf } = require('../values');
4
- const RuntimeError = require('../runtime_error');
5
-
6
- const types = {
7
- string: StringType,
8
- number: NumberType,
9
- boolean: BooleanType
10
- };
11
-
12
- class ArrayAssertion {
13
- constructor(type, input) {
14
- this.type = type;
15
- this.input = input;
16
- }
17
-
18
- static parse(args, context) {
19
- if (args.length < 2 || args.length > 4)
20
- return context.error(`Expected 1, 2, or 3 arguments, but found ${args.length - 1} instead.`);
21
-
22
- let itemType;
23
- let N;
24
- if (args.length > 2) {
25
- const type = args[1];
26
- if (typeof type !== 'string' || !(type in types))
27
- return context.error('The item type argument of "array" must be one of string, number, boolean', 1);
28
- itemType = types[type];
29
- } else {
30
- itemType = ValueType;
31
- }
32
-
33
- if (args.length > 3) {
34
- if (typeof args[2] !== 'number' || args[2] < 0 || args[2] !== Math.floor(args[2])) {
35
- return context.error('The length argument to "array" must be a positive integer literal', 2);
36
- }
37
- N = args[2];
38
- }
39
-
40
- const type = array(itemType, N);
41
-
42
- const input = context.parse(args[args.length - 1], args.length - 1, ValueType);
43
- if (!input) return null;
44
-
45
- return new ArrayAssertion(type, input);
46
- }
47
-
48
- evaluate(ctx) {
49
- const value = this.input.evaluate(ctx);
50
- const error = checkSubtype(this.type, typeOf(value));
51
- if (error) {
52
- throw new RuntimeError(
53
- `Expected value to be of type ${toString(this.type)}, but found ${toString(typeOf(value))} instead.`
54
- );
55
- }
56
- return value;
57
- }
58
-
59
- eachChild(fn) {
60
- fn(this.input);
61
- }
62
-
63
- possibleOutputs() {
64
- return this.input.possibleOutputs();
65
- }
66
-
67
- serialize() {
68
- const serialized = ['array'];
69
- const itemType = this.type.itemType;
70
- if (itemType.kind === 'string' || itemType.kind === 'number' || itemType.kind === 'boolean') {
71
- serialized.push(itemType.kind);
72
- const N = this.type.N;
73
- if (typeof N === 'number') {
74
- serialized.push(N);
75
- }
76
- }
77
- serialized.push(this.input.serialize());
78
- return serialized;
79
- }
80
- }
81
-
82
- module.exports = ArrayAssertion;
@@ -1,93 +0,0 @@
1
- const { toString, ValueType, BooleanType, CollatorType } = require('../types');
2
-
3
- function isComparableType(type) {
4
- return type.kind === 'string' || type.kind === 'number' || type.kind === 'boolean' || type.kind === 'null';
5
- }
6
-
7
- /**
8
- * Special form for ==, !=, implementing the following signatures:
9
- * - (T1: Comparable, T2: Comparable) => boolean { T1 == T2 }
10
- * - (Comparable, value) => boolean
11
- * - (value, Comparable) => boolean
12
- *
13
- * Where Comparable = string | number | boolean | null.
14
- *
15
- * Evaluation semantics for the value cases are equivalent to Javascript's
16
- * strict equality (===/!==) -- i.e., when the value argument's type doesn't
17
- * match that of the Comparable argument, == evaluates to false, != to true.
18
- *
19
- * @private
20
- */
21
- function makeComparison(op, negate) {
22
- return class Comparison {
23
- constructor(lhs, rhs, collator) {
24
- this.type = BooleanType;
25
- this.lhs = lhs;
26
- this.rhs = rhs;
27
- this.collator = collator;
28
- }
29
-
30
- static parse(args, context) {
31
- if (args.length !== 3 && args.length !== 4) return context.error('Expected two or three arguments.');
32
-
33
- const lhs = context.parse(args[1], 1, ValueType);
34
- if (!lhs) return null;
35
- const rhs = context.parse(args[2], 2, ValueType);
36
- if (!rhs) return null;
37
-
38
- if (!isComparableType(lhs.type) && !isComparableType(rhs.type)) {
39
- return context.error(
40
- `Expected at least one argument to be a string, number, boolean, or null, but found (${toString(lhs.type)}, ${toString(rhs.type)}) instead.`
41
- );
42
- }
43
-
44
- if (lhs.type.kind !== rhs.type.kind && lhs.type.kind !== 'value' && rhs.type.kind !== 'value') {
45
- return context.error(`Cannot compare ${toString(lhs.type)} and ${toString(rhs.type)}.`);
46
- }
47
-
48
- let collator = null;
49
- if (args.length === 4) {
50
- if (lhs.type.kind !== 'string' && rhs.type.kind !== 'string') {
51
- return context.error('Cannot use collator to compare non-string types.');
52
- }
53
- collator = context.parse(args[3], 3, CollatorType);
54
- if (!collator) return null;
55
- }
56
-
57
- return new Comparison(lhs, rhs, collator);
58
- }
59
-
60
- evaluate(ctx) {
61
- const equal = this.collator
62
- ? this.collator.evaluate(ctx).compare(this.lhs.evaluate(ctx), this.rhs.evaluate(ctx)) === 0
63
- : this.lhs.evaluate(ctx) === this.rhs.evaluate(ctx);
64
-
65
- return negate ? !equal : equal;
66
- }
67
-
68
- eachChild(fn) {
69
- fn(this.lhs);
70
- fn(this.rhs);
71
- if (this.collator) {
72
- fn(this.collator);
73
- }
74
- }
75
-
76
- possibleOutputs() {
77
- return [true, false];
78
- }
79
-
80
- serialize() {
81
- const serialized = [op];
82
- this.eachChild(child => {
83
- serialized.push(child.serialize());
84
- });
85
- return serialized;
86
- }
87
- };
88
- }
89
-
90
- module.exports = {
91
- Equals: makeComparison('==', false),
92
- NotEquals: makeComparison('!=', true)
93
- };