@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.
- package/build/min/package.json +1 -1
- package/package.json +3 -2
- package/src/data/array_types.js +169 -0
- package/src/data/bucket/symbol_attributes.js +18 -0
- package/src/data/bucket/symbol_bucket.js +116 -73
- package/src/data/program_configuration.js +18 -10
- package/src/geo/transform.js +17 -7
- package/src/index.js +1 -1
- package/src/render/glyph_atlas.js +3 -6
- package/src/render/image_atlas.js +3 -6
- package/src/render/image_manager.js +41 -41
- package/src/source/rtl_text_plugin.js +1 -0
- package/src/source/source_cache.js +1 -1
- package/src/source/tile.js +6 -5
- package/src/source/worker.js +1 -10
- package/src/style/style.js +4 -19
- package/src/style/style_layer/symbol_style_layer_properties.js +7 -1
- package/src/style-spec/expression/compound_expression.js +30 -16
- package/src/style-spec/expression/definitions/assertion.js +52 -5
- package/src/style-spec/expression/definitions/coercion.js +13 -0
- package/src/style-spec/expression/definitions/comparison.js +193 -0
- package/src/style-spec/expression/definitions/formatted.js +123 -0
- package/src/style-spec/expression/definitions/index.js +11 -62
- package/src/style-spec/expression/definitions/interpolate.js +17 -7
- package/src/style-spec/expression/definitions/literal.js +5 -0
- package/src/style-spec/expression/parsing_context.js +6 -7
- package/src/style-spec/expression/types.js +12 -1
- package/src/style-spec/feature_filter/convert.js +197 -0
- package/src/style-spec/feature_filter/index.js +5 -2
- package/src/style-spec/function/convert.js +78 -100
- package/src/style-spec/reference/v8.json +160 -52
- package/src/symbol/collision_index.js +0 -1
- package/src/symbol/cross_tile_symbol_index.js +12 -7
- package/src/symbol/get_anchors.js +11 -22
- package/src/symbol/mergelines.js +4 -1
- package/src/symbol/placement.js +58 -54
- package/src/symbol/quads.js +7 -6
- package/src/symbol/shaping.js +185 -40
- package/src/symbol/symbol_layout.js +40 -37
- package/src/symbol/transform_text.js +12 -1
- package/src/ui/map.js +8 -25
- package/src/style-spec/expression/definitions/array.js +0 -82
- 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
|
|
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(
|
|
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
|
-
|
|
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(
|
|
107
|
+
if (allowsVerticalWritingMode(unformattedText) && textAlongLine && keepUpright) {
|
|
106
108
|
shapedTextOrientations.vertical = shapeText(
|
|
107
109
|
text,
|
|
108
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
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
|
-
|
|
495
|
-
|
|
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
|
-
|
|
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}
|
|
295
|
+
* @returns {LngLatBounds}
|
|
295
296
|
*/
|
|
296
297
|
getBounds() {
|
|
297
|
-
|
|
298
|
-
this.transform.pointLocation(new Point(0,
|
|
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
|
-
};
|