@mapwhit/tilerenderer 1.2.2 → 1.4.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 +1 -1
- package/src/data/array_types.js +115 -64
- package/src/data/bucket/circle_bucket.js +42 -5
- package/src/data/bucket/fill_bucket.js +31 -13
- package/src/data/bucket/fill_extrusion_bucket.js +8 -6
- package/src/data/bucket/line_bucket.js +38 -14
- package/src/data/bucket/symbol_attributes.js +13 -5
- package/src/data/bucket/symbol_bucket.js +87 -33
- package/src/data/bucket/symbol_collision_buffers.js +1 -1
- package/src/data/bucket.js +3 -1
- package/src/data/feature_index.js +24 -11
- package/src/data/segment.js +15 -7
- package/src/render/draw_circle.js +45 -4
- package/src/render/draw_symbol.js +190 -22
- package/src/render/painter.js +1 -1
- package/src/source/geojson_source.js +118 -21
- package/src/source/geojson_source_diff.js +148 -0
- package/src/source/geojson_tiler.js +89 -0
- package/src/source/source.js +16 -5
- package/src/source/source_cache.js +6 -6
- package/src/source/source_state.js +4 -2
- package/src/source/tile.js +5 -3
- package/src/source/vector_tile_source.js +2 -0
- package/src/source/worker_tile.js +4 -2
- package/src/style/pauseable_placement.js +39 -7
- package/src/style/style.js +86 -34
- package/src/style/style_layer/circle_style_layer_properties.js +8 -1
- package/src/style/style_layer/fill_style_layer_properties.js +8 -1
- package/src/style/style_layer/line_style_layer_properties.js +4 -0
- package/src/style/style_layer/symbol_style_layer_properties.js +17 -2
- package/src/style-spec/reference/v8.json +161 -4
- package/src/symbol/one_em.js +4 -0
- package/src/symbol/placement.js +406 -173
- package/src/symbol/projection.js +3 -3
- package/src/symbol/quads.js +1 -6
- package/src/symbol/shaping.js +16 -27
- package/src/symbol/symbol_layout.js +243 -81
- package/src/util/vectortile_to_geojson.js +3 -4
- package/src/source/geojson_worker_source.js +0 -97
package/src/symbol/projection.js
CHANGED
|
@@ -324,8 +324,8 @@ function placeGlyphsAlongLine(
|
|
|
324
324
|
aspectRatio
|
|
325
325
|
) {
|
|
326
326
|
const fontScale = fontSize / 24;
|
|
327
|
-
const lineOffsetX = symbol.lineOffsetX *
|
|
328
|
-
const lineOffsetY = symbol.lineOffsetY *
|
|
327
|
+
const lineOffsetX = symbol.lineOffsetX * fontScale;
|
|
328
|
+
const lineOffsetY = symbol.lineOffsetY * fontScale;
|
|
329
329
|
|
|
330
330
|
let placedGlyphs;
|
|
331
331
|
if (symbol.numGlyphs > 1) {
|
|
@@ -580,7 +580,7 @@ const hiddenGlyphAttributes = new Float32Array([
|
|
|
580
580
|
|
|
581
581
|
// Hide them by moving them offscreen. We still need to add them to the buffer
|
|
582
582
|
// because the dynamic buffer is paired with a static buffer that doesn't get updated.
|
|
583
|
-
function hideGlyphs(num, dynamicLayoutVertexArray) {
|
|
583
|
+
export function hideGlyphs(num, dynamicLayoutVertexArray) {
|
|
584
584
|
for (let i = 0; i < num; i++) {
|
|
585
585
|
const offset = dynamicLayoutVertexArray.length;
|
|
586
586
|
dynamicLayoutVertexArray.resize(offset + 4);
|
package/src/symbol/quads.js
CHANGED
|
@@ -91,13 +91,8 @@ export function getIconQuads(anchor, shapedIcon, layer, alongLine, shapedText, f
|
|
|
91
91
|
* Create the quads used for rendering a text label.
|
|
92
92
|
* @private
|
|
93
93
|
*/
|
|
94
|
-
export function getGlyphQuads(anchor, shaping, layer, alongLine, feature, positions) {
|
|
95
|
-
const oneEm = 24;
|
|
94
|
+
export function getGlyphQuads(anchor, shaping, textOffset, layer, alongLine, feature, positions) {
|
|
96
95
|
const textRotate = (layer._layout.get('text-rotate').evaluate(feature, {}) * Math.PI) / 180;
|
|
97
|
-
const textOffset = layer._layout
|
|
98
|
-
.get('text-offset')
|
|
99
|
-
.evaluate(feature, {})
|
|
100
|
-
.map(t => t * oneEm);
|
|
101
96
|
|
|
102
97
|
const positionedGlyphs = shaping.positionedGlyphs;
|
|
103
98
|
const quads = [];
|
package/src/symbol/shaping.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { plugin as rtlTextPlugin } from '../source/rtl_text_plugin.js';
|
|
2
2
|
import { charAllowsIdeographicBreaking, charHasUprightVerticalOrientation } from '../util/script_detection.js';
|
|
3
3
|
import verticalizePunctuation from '../util/verticalize_punctuation.js';
|
|
4
|
+
import ONE_EM from './one_em.js';
|
|
4
5
|
|
|
5
6
|
export const WritingMode = {
|
|
6
7
|
horizontal: 1,
|
|
@@ -102,7 +103,6 @@ export function shapeText(
|
|
|
102
103
|
textJustify,
|
|
103
104
|
spacing,
|
|
104
105
|
translate,
|
|
105
|
-
verticalHeight,
|
|
106
106
|
writingMode
|
|
107
107
|
) {
|
|
108
108
|
const logicalInput = TaggedString.fromFeature(text, defaultFontStack);
|
|
@@ -110,17 +110,6 @@ export function shapeText(
|
|
|
110
110
|
logicalInput.verticalizePunctuation();
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
const positionedGlyphs = [];
|
|
114
|
-
const shaping = {
|
|
115
|
-
positionedGlyphs,
|
|
116
|
-
text: logicalInput,
|
|
117
|
-
top: translate[1],
|
|
118
|
-
bottom: translate[1],
|
|
119
|
-
left: translate[0],
|
|
120
|
-
right: translate[0],
|
|
121
|
-
writingMode
|
|
122
|
-
};
|
|
123
|
-
|
|
124
113
|
let lines;
|
|
125
114
|
|
|
126
115
|
const { processBidirectionalText, processStyledBidirectionalText } = rtlTextPlugin;
|
|
@@ -160,13 +149,23 @@ export function shapeText(
|
|
|
160
149
|
lines = breakLines(logicalInput, determineLineBreaks(logicalInput, spacing, maxWidth, glyphs));
|
|
161
150
|
}
|
|
162
151
|
|
|
163
|
-
|
|
152
|
+
const positionedGlyphs = [];
|
|
153
|
+
const shaping = {
|
|
154
|
+
positionedGlyphs,
|
|
155
|
+
text: logicalInput.toString(),
|
|
156
|
+
top: translate[1],
|
|
157
|
+
bottom: translate[1],
|
|
158
|
+
left: translate[0],
|
|
159
|
+
right: translate[0],
|
|
160
|
+
writingMode,
|
|
161
|
+
lineCount: lines.length
|
|
162
|
+
};
|
|
164
163
|
|
|
164
|
+
shapeLines(shaping, glyphs, lines, lineHeight, textAnchor, textJustify, writingMode, spacing);
|
|
165
165
|
if (!positionedGlyphs.length) {
|
|
166
166
|
return false;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
shaping.text = shaping.text.toString();
|
|
170
169
|
return shaping;
|
|
171
170
|
}
|
|
172
171
|
|
|
@@ -323,7 +322,7 @@ function determineLineBreaks(logicalInput, spacing, maxWidth, glyphMap) {
|
|
|
323
322
|
return leastBadBreaks(evaluateBreak(logicalInput.length(), currentX, targetWidth, potentialLineBreaks, 0, true));
|
|
324
323
|
}
|
|
325
324
|
|
|
326
|
-
function getAnchorAlignment(anchor) {
|
|
325
|
+
export function getAnchorAlignment(anchor) {
|
|
327
326
|
let horizontalAlign = 0.5;
|
|
328
327
|
let verticalAlign = 0.5;
|
|
329
328
|
|
|
@@ -356,17 +355,7 @@ function getAnchorAlignment(anchor) {
|
|
|
356
355
|
return { horizontalAlign, verticalAlign };
|
|
357
356
|
}
|
|
358
357
|
|
|
359
|
-
function shapeLines(
|
|
360
|
-
shaping,
|
|
361
|
-
glyphMap,
|
|
362
|
-
lines,
|
|
363
|
-
lineHeight,
|
|
364
|
-
textAnchor,
|
|
365
|
-
textJustify,
|
|
366
|
-
writingMode,
|
|
367
|
-
spacing,
|
|
368
|
-
verticalHeight
|
|
369
|
-
) {
|
|
358
|
+
function shapeLines(shaping, glyphMap, lines, lineHeight, textAnchor, textJustify, writingMode, spacing) {
|
|
370
359
|
// the y offset *should* be part of the font metadata
|
|
371
360
|
const yOffset = -17;
|
|
372
361
|
|
|
@@ -422,7 +411,7 @@ function shapeLines(
|
|
|
422
411
|
scale: section.scale,
|
|
423
412
|
fontStack: section.fontStack
|
|
424
413
|
});
|
|
425
|
-
x +=
|
|
414
|
+
x += ONE_EM * section.scale + spacing;
|
|
426
415
|
}
|
|
427
416
|
}
|
|
428
417
|
|
|
@@ -9,6 +9,7 @@ import warn from '../util/warn.js';
|
|
|
9
9
|
import Anchor from './anchor.js';
|
|
10
10
|
import CollisionFeature from './collision_feature.js';
|
|
11
11
|
import { getAnchors, getCenterAnchor } from './get_anchors.js';
|
|
12
|
+
import ONE_EM from './one_em.js';
|
|
12
13
|
import { getGlyphQuads, getIconQuads } from './quads.js';
|
|
13
14
|
import { shapeIcon, shapeText, WritingMode } from './shaping.js';
|
|
14
15
|
|
|
@@ -27,6 +28,56 @@ import { shapeIcon, shapeText, WritingMode } from './shaping.js';
|
|
|
27
28
|
// (1) and (2) are stored in `bucket.layers[0]._layout`. The remainder are below.
|
|
28
29
|
//
|
|
29
30
|
|
|
31
|
+
// The radial offset is to the edge of the text box
|
|
32
|
+
// In the horizontal direction, the edge of the text box is where glyphs start
|
|
33
|
+
// But in the vertical direction, the glyphs appear to "start" at the baseline
|
|
34
|
+
// We don't actually load baseline data, but we assume an offset of ONE_EM - 17
|
|
35
|
+
// (see "yOffset" in shaping.js)
|
|
36
|
+
const baselineOffset = 7;
|
|
37
|
+
|
|
38
|
+
export function evaluateRadialOffset(anchor, radialOffset) {
|
|
39
|
+
let x = 0;
|
|
40
|
+
let y = 0;
|
|
41
|
+
// solve for r where r^2 + r^2 = radialOffset^2
|
|
42
|
+
const hypotenuse = radialOffset / Math.sqrt(2);
|
|
43
|
+
|
|
44
|
+
switch (anchor) {
|
|
45
|
+
case 'top-right':
|
|
46
|
+
case 'top-left':
|
|
47
|
+
y = hypotenuse - baselineOffset;
|
|
48
|
+
break;
|
|
49
|
+
case 'bottom-right':
|
|
50
|
+
case 'bottom-left':
|
|
51
|
+
y = -hypotenuse + baselineOffset;
|
|
52
|
+
break;
|
|
53
|
+
case 'bottom':
|
|
54
|
+
y = -radialOffset + baselineOffset;
|
|
55
|
+
break;
|
|
56
|
+
case 'top':
|
|
57
|
+
y = radialOffset - baselineOffset;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
switch (anchor) {
|
|
62
|
+
case 'top-right':
|
|
63
|
+
case 'bottom-right':
|
|
64
|
+
x = -hypotenuse;
|
|
65
|
+
break;
|
|
66
|
+
case 'top-left':
|
|
67
|
+
case 'bottom-left':
|
|
68
|
+
x = hypotenuse;
|
|
69
|
+
break;
|
|
70
|
+
case 'left':
|
|
71
|
+
x = radialOffset;
|
|
72
|
+
break;
|
|
73
|
+
case 'right':
|
|
74
|
+
x = -radialOffset;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return [x, y];
|
|
79
|
+
}
|
|
80
|
+
|
|
30
81
|
export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePositions, showCollisionBoxes) {
|
|
31
82
|
bucket.createArrays();
|
|
32
83
|
|
|
@@ -64,8 +115,7 @@ export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap,
|
|
|
64
115
|
);
|
|
65
116
|
sizes.textMaxSize = unevaluatedLayoutValues['text-size'].possiblyEvaluate(new EvaluationParameters(18));
|
|
66
117
|
|
|
67
|
-
const
|
|
68
|
-
const lineHeight = layout.get('text-line-height') * oneEm;
|
|
118
|
+
const lineHeight = layout.get('text-line-height') * ONE_EM;
|
|
69
119
|
const textAlongLine = layout.get('text-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point';
|
|
70
120
|
const keepUpright = layout.get('text-keep-upright');
|
|
71
121
|
|
|
@@ -73,36 +123,82 @@ export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap,
|
|
|
73
123
|
const fontstack = layout.get('text-font').evaluate(feature, {}).join(',');
|
|
74
124
|
const glyphPositionMap = glyphPositions;
|
|
75
125
|
|
|
76
|
-
const shapedTextOrientations = {
|
|
126
|
+
const shapedTextOrientations = {
|
|
127
|
+
horizontal: {},
|
|
128
|
+
vertical: undefined
|
|
129
|
+
};
|
|
77
130
|
const text = feature.text;
|
|
131
|
+
let textOffset = [0, 0];
|
|
78
132
|
if (text) {
|
|
79
133
|
const unformattedText = text.toString();
|
|
80
|
-
const
|
|
81
|
-
.get('text-offset')
|
|
82
|
-
.evaluate(feature, {})
|
|
83
|
-
.map(t => t * oneEm);
|
|
84
|
-
const spacing = layout.get('text-letter-spacing').evaluate(feature, {}) * oneEm;
|
|
134
|
+
const spacing = layout.get('text-letter-spacing').evaluate(feature, {}) * ONE_EM;
|
|
85
135
|
const spacingIfAllowed = allowsLetterSpacing(unformattedText) ? spacing : 0;
|
|
136
|
+
|
|
86
137
|
const textAnchor = layout.get('text-anchor').evaluate(feature, {});
|
|
87
|
-
const
|
|
138
|
+
const variableTextAnchor = layout.get('text-variable-anchor');
|
|
139
|
+
const radialOffset = layout.get('text-radial-offset').evaluate(feature, {});
|
|
140
|
+
|
|
141
|
+
if (!variableTextAnchor) {
|
|
142
|
+
// Layers with variable anchors use the `text-radial-offset` property and the [x, y] offset vector
|
|
143
|
+
// is calculated at placement time instead of layout time
|
|
144
|
+
if (radialOffset) {
|
|
145
|
+
// The style spec says don't use `text-offset` and `text-radial-offset` together
|
|
146
|
+
// but doesn't actually specify what happens if you use both. We go with the radial offset.
|
|
147
|
+
textOffset = evaluateRadialOffset(textAnchor, radialOffset * ONE_EM);
|
|
148
|
+
} else {
|
|
149
|
+
textOffset = layout
|
|
150
|
+
.get('text-offset')
|
|
151
|
+
.evaluate(feature, {})
|
|
152
|
+
.map(t => t * ONE_EM);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let textJustify = textAlongLine ? 'center' : layout.get('text-justify').evaluate(feature, {});
|
|
157
|
+
|
|
88
158
|
const maxWidth =
|
|
89
|
-
layout.get('symbol-placement') === 'point' ? layout.get('text-max-width').evaluate(feature, {}) *
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
159
|
+
layout.get('symbol-placement') === 'point' ? layout.get('text-max-width').evaluate(feature, {}) * ONE_EM : 0;
|
|
160
|
+
|
|
161
|
+
// If this layer uses text-variable-anchor, generate shapings for all justification possibilities.
|
|
162
|
+
if (!textAlongLine && variableTextAnchor) {
|
|
163
|
+
const justifications =
|
|
164
|
+
textJustify === 'auto' ? variableTextAnchor.map(a => getAnchorJustification(a)) : [textJustify];
|
|
165
|
+
|
|
166
|
+
let singleLine = false;
|
|
167
|
+
for (let i = 0; i < justifications.length; i++) {
|
|
168
|
+
const justification = justifications[i];
|
|
169
|
+
if (shapedTextOrientations.horizontal[justification]) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (singleLine) {
|
|
173
|
+
// If the shaping for the first justification was only a single line, we
|
|
174
|
+
// can re-use it for the other justifications
|
|
175
|
+
shapedTextOrientations.horizontal[justification] = shapedTextOrientations.horizontal[0];
|
|
176
|
+
} else {
|
|
177
|
+
// If using text-variable-anchor for the layer, we use a center anchor for all shapings and apply
|
|
178
|
+
// the offsets for the anchor in the placement step.
|
|
179
|
+
const shaping = shapeText(
|
|
180
|
+
text,
|
|
181
|
+
glyphMap,
|
|
182
|
+
fontstack,
|
|
183
|
+
maxWidth,
|
|
184
|
+
lineHeight,
|
|
185
|
+
'center',
|
|
186
|
+
justification,
|
|
187
|
+
spacingIfAllowed,
|
|
188
|
+
textOffset,
|
|
189
|
+
WritingMode.horizontal
|
|
190
|
+
);
|
|
191
|
+
if (shaping) {
|
|
192
|
+
shapedTextOrientations.horizontal[justification] = shaping;
|
|
193
|
+
singleLine = shaping.lineCount === 1;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
if (textJustify === 'auto') {
|
|
199
|
+
textJustify = getAnchorJustification(textAnchor);
|
|
200
|
+
}
|
|
201
|
+
const shaping = shapeText(
|
|
106
202
|
text,
|
|
107
203
|
glyphMap,
|
|
108
204
|
fontstack,
|
|
@@ -112,9 +208,26 @@ export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap,
|
|
|
112
208
|
textJustify,
|
|
113
209
|
spacingIfAllowed,
|
|
114
210
|
textOffset,
|
|
115
|
-
|
|
116
|
-
WritingMode.vertical
|
|
211
|
+
WritingMode.horizontal
|
|
117
212
|
);
|
|
213
|
+
if (shaping) {
|
|
214
|
+
shapedTextOrientations.horizontal[textJustify] = shaping;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (allowsVerticalWritingMode(unformattedText) && textAlongLine && keepUpright) {
|
|
218
|
+
shapedTextOrientations.vertical = shapeText(
|
|
219
|
+
text,
|
|
220
|
+
glyphMap,
|
|
221
|
+
fontstack,
|
|
222
|
+
maxWidth,
|
|
223
|
+
lineHeight,
|
|
224
|
+
textAnchor,
|
|
225
|
+
textJustify,
|
|
226
|
+
spacingIfAllowed,
|
|
227
|
+
textOffset,
|
|
228
|
+
WritingMode.vertical
|
|
229
|
+
);
|
|
230
|
+
}
|
|
118
231
|
}
|
|
119
232
|
}
|
|
120
233
|
|
|
@@ -140,8 +253,8 @@ export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap,
|
|
|
140
253
|
}
|
|
141
254
|
}
|
|
142
255
|
|
|
143
|
-
if (shapedTextOrientations.horizontal || shapedIcon) {
|
|
144
|
-
addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPositionMap, sizes);
|
|
256
|
+
if (Object.keys(shapedTextOrientations.horizontal).length || shapedIcon) {
|
|
257
|
+
addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPositionMap, sizes, textOffset);
|
|
145
258
|
}
|
|
146
259
|
}
|
|
147
260
|
|
|
@@ -150,6 +263,21 @@ export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap,
|
|
|
150
263
|
}
|
|
151
264
|
}
|
|
152
265
|
|
|
266
|
+
// Choose the justification that matches the direction of the TextAnchor
|
|
267
|
+
export function getAnchorJustification(anchor) {
|
|
268
|
+
switch (anchor) {
|
|
269
|
+
case 'right':
|
|
270
|
+
case 'top-right':
|
|
271
|
+
case 'bottom-right':
|
|
272
|
+
return 'right';
|
|
273
|
+
case 'left':
|
|
274
|
+
case 'top-left':
|
|
275
|
+
case 'bottom-left':
|
|
276
|
+
return 'left';
|
|
277
|
+
}
|
|
278
|
+
return 'center';
|
|
279
|
+
}
|
|
280
|
+
|
|
153
281
|
/**
|
|
154
282
|
* Given a feature and its shaped text and icon data, add a 'symbol
|
|
155
283
|
* instance' for each _possible_ placement of the symbol feature.
|
|
@@ -157,7 +285,7 @@ export function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap,
|
|
|
157
285
|
* show or hide based on collisions with symbols in other layers.)
|
|
158
286
|
* @private
|
|
159
287
|
*/
|
|
160
|
-
function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPositionMap, sizes) {
|
|
288
|
+
function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPositionMap, sizes, textOffset) {
|
|
161
289
|
const layoutTextSize = sizes.layoutTextSize.evaluate(feature, {});
|
|
162
290
|
const layoutIconSize = sizes.layoutIconSize.evaluate(feature, {});
|
|
163
291
|
|
|
@@ -171,9 +299,8 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPo
|
|
|
171
299
|
}
|
|
172
300
|
|
|
173
301
|
const layout = bucket.layers[0]._layout;
|
|
174
|
-
const textOffset = layout.get('text-offset').evaluate(feature, {});
|
|
175
302
|
const iconOffset = layout.get('icon-offset').evaluate(feature, {});
|
|
176
|
-
|
|
303
|
+
const defaultHorizontalShaping = getDefaultHorizontalShaping(shapedTextOrientations.horizontal);
|
|
177
304
|
const glyphSize = 24;
|
|
178
305
|
const fontScale = layoutTextSize / glyphSize;
|
|
179
306
|
const textBoxScale = bucket.tilePixelRatio * fontScale;
|
|
@@ -227,7 +354,7 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPo
|
|
|
227
354
|
line,
|
|
228
355
|
symbolMinDistance,
|
|
229
356
|
textMaxAngle,
|
|
230
|
-
shapedTextOrientations.vertical ||
|
|
357
|
+
shapedTextOrientations.vertical || defaultHorizontalShaping,
|
|
231
358
|
shapedIcon,
|
|
232
359
|
glyphSize,
|
|
233
360
|
textMaxBoxScale,
|
|
@@ -235,7 +362,7 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPo
|
|
|
235
362
|
EXTENT
|
|
236
363
|
);
|
|
237
364
|
for (const anchor of anchors) {
|
|
238
|
-
const shapedText =
|
|
365
|
+
const shapedText = defaultHorizontalShaping;
|
|
239
366
|
if (!shapedText || !anchorIsTooClose(bucket, shapedText.text, textRepeatDistance, anchor)) {
|
|
240
367
|
addSymbolAtAnchor(line, anchor);
|
|
241
368
|
}
|
|
@@ -249,7 +376,7 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPo
|
|
|
249
376
|
const anchor = getCenterAnchor(
|
|
250
377
|
line,
|
|
251
378
|
textMaxAngle,
|
|
252
|
-
shapedTextOrientations.vertical ||
|
|
379
|
+
shapedTextOrientations.vertical || defaultHorizontalShaping,
|
|
253
380
|
shapedIcon,
|
|
254
381
|
glyphSize,
|
|
255
382
|
textMaxBoxScale
|
|
@@ -289,11 +416,12 @@ function addTextVertices(
|
|
|
289
416
|
textOffset,
|
|
290
417
|
lineArray,
|
|
291
418
|
writingMode,
|
|
419
|
+
placementTypes,
|
|
292
420
|
placedTextSymbolIndices,
|
|
293
421
|
glyphPositionMap,
|
|
294
422
|
sizes
|
|
295
423
|
) {
|
|
296
|
-
const glyphQuads = getGlyphQuads(anchor, shapedText, layer, textAlongLine, feature, glyphPositionMap);
|
|
424
|
+
const glyphQuads = getGlyphQuads(anchor, shapedText, textOffset, layer, textAlongLine, feature, glyphPositionMap);
|
|
297
425
|
|
|
298
426
|
const sizeData = bucket.textSizeData;
|
|
299
427
|
let textSizeData = null;
|
|
@@ -322,11 +450,22 @@ function addTextVertices(
|
|
|
322
450
|
|
|
323
451
|
// The placedSymbolArray is used at render time in drawTileSymbols
|
|
324
452
|
// These indices allow access to the array at collision detection time
|
|
325
|
-
|
|
453
|
+
for (const placementType of placementTypes) {
|
|
454
|
+
placedTextSymbolIndices[placementType] = bucket.text.placedSymbolArray.length - 1;
|
|
455
|
+
}
|
|
326
456
|
|
|
327
457
|
return glyphQuads.length * 4;
|
|
328
458
|
}
|
|
329
459
|
|
|
460
|
+
function getDefaultHorizontalShaping(horizontalShaping) {
|
|
461
|
+
// We don't care which shaping we get because this is used for collision purposes
|
|
462
|
+
// and all the justifications have the same collision box
|
|
463
|
+
for (const justification in horizontalShaping) {
|
|
464
|
+
return horizontalShaping[justification];
|
|
465
|
+
}
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
|
|
330
469
|
/**
|
|
331
470
|
* Add a single label & icon placement.
|
|
332
471
|
*
|
|
@@ -361,61 +500,76 @@ function addSymbol(
|
|
|
361
500
|
let iconCollisionFeature;
|
|
362
501
|
|
|
363
502
|
let numIconVertices = 0;
|
|
364
|
-
let
|
|
503
|
+
let numHorizontalGlyphVertices = 0;
|
|
365
504
|
let numVerticalGlyphVertices = 0;
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
505
|
+
const placedTextSymbolIndices = {};
|
|
506
|
+
let key = murmur3('');
|
|
507
|
+
const radialTextOffset = (layer._layout.get('text-radial-offset').evaluate(feature, {}) || 0) * ONE_EM;
|
|
508
|
+
|
|
509
|
+
for (const justification in shapedTextOrientations.horizontal) {
|
|
510
|
+
const shaping = shapedTextOrientations.horizontal[justification];
|
|
511
|
+
|
|
512
|
+
if (!textCollisionFeature) {
|
|
513
|
+
key = murmur3(shaping.text);
|
|
514
|
+
const textRotate = layer._layout.get('text-rotate').evaluate(feature, {});
|
|
515
|
+
// As a collision approximation, we can use either the vertical or any of the horizontal versions of the feature
|
|
516
|
+
// We're counting on all versions having similar dimensions
|
|
517
|
+
textCollisionFeature = new CollisionFeature(
|
|
518
|
+
collisionBoxArray,
|
|
519
|
+
line,
|
|
520
|
+
anchor,
|
|
521
|
+
featureIndex,
|
|
522
|
+
sourceLayerIndex,
|
|
523
|
+
bucketIndex,
|
|
524
|
+
shaping,
|
|
525
|
+
textBoxScale,
|
|
526
|
+
textPadding,
|
|
527
|
+
textAlongLine,
|
|
528
|
+
bucket.overscaling,
|
|
529
|
+
textRotate
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const singleLine = shaping.lineCount === 1;
|
|
534
|
+
numHorizontalGlyphVertices += addTextVertices(
|
|
387
535
|
bucket,
|
|
388
536
|
anchor,
|
|
389
|
-
|
|
537
|
+
shaping,
|
|
390
538
|
layer,
|
|
391
539
|
textAlongLine,
|
|
392
540
|
feature,
|
|
393
541
|
textOffset,
|
|
394
542
|
lineArray,
|
|
395
543
|
shapedTextOrientations.vertical ? WritingMode.horizontal : WritingMode.horizontalOnly,
|
|
544
|
+
singleLine ? Object.keys(shapedTextOrientations.horizontal) : [justification],
|
|
396
545
|
placedTextSymbolIndices,
|
|
397
546
|
glyphPositionMap,
|
|
398
547
|
sizes
|
|
399
548
|
);
|
|
400
549
|
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
bucket,
|
|
404
|
-
anchor,
|
|
405
|
-
shapedTextOrientations.vertical,
|
|
406
|
-
layer,
|
|
407
|
-
textAlongLine,
|
|
408
|
-
feature,
|
|
409
|
-
textOffset,
|
|
410
|
-
lineArray,
|
|
411
|
-
WritingMode.vertical,
|
|
412
|
-
placedTextSymbolIndices,
|
|
413
|
-
glyphPositionMap,
|
|
414
|
-
sizes
|
|
415
|
-
);
|
|
550
|
+
if (singleLine) {
|
|
551
|
+
break;
|
|
416
552
|
}
|
|
417
553
|
}
|
|
418
554
|
|
|
555
|
+
if (shapedTextOrientations.vertical) {
|
|
556
|
+
numVerticalGlyphVertices += addTextVertices(
|
|
557
|
+
bucket,
|
|
558
|
+
anchor,
|
|
559
|
+
shapedTextOrientations.vertical,
|
|
560
|
+
layer,
|
|
561
|
+
textAlongLine,
|
|
562
|
+
feature,
|
|
563
|
+
textOffset,
|
|
564
|
+
lineArray,
|
|
565
|
+
WritingMode.vertical,
|
|
566
|
+
['vertical'],
|
|
567
|
+
placedTextSymbolIndices,
|
|
568
|
+
glyphPositionMap,
|
|
569
|
+
sizes
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
|
|
419
573
|
const textBoxStartIndex = textCollisionFeature ? textCollisionFeature.boxStartIndex : bucket.collisionBoxArray.length;
|
|
420
574
|
const textBoxEndIndex = textCollisionFeature ? textCollisionFeature.boxEndIndex : bucket.collisionBoxArray.length;
|
|
421
575
|
|
|
@@ -425,7 +579,7 @@ function addSymbol(
|
|
|
425
579
|
shapedIcon,
|
|
426
580
|
layer,
|
|
427
581
|
iconAlongLine,
|
|
428
|
-
shapedTextOrientations.horizontal,
|
|
582
|
+
getDefaultHorizontalShaping(shapedTextOrientations.horizontal),
|
|
429
583
|
feature
|
|
430
584
|
);
|
|
431
585
|
const iconRotate = layer._layout.get('icon-rotate').evaluate(feature, {});
|
|
@@ -479,21 +633,29 @@ function addSymbol(
|
|
|
479
633
|
warn.once('Too many glyphs being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907');
|
|
480
634
|
}
|
|
481
635
|
|
|
636
|
+
if (feature.sortKey !== undefined) {
|
|
637
|
+
bucket.addToSortKeyRanges(bucket.symbolInstances.length, feature.sortKey);
|
|
638
|
+
}
|
|
639
|
+
|
|
482
640
|
bucket.symbolInstances.emplaceBack(
|
|
483
641
|
anchor.x,
|
|
484
642
|
anchor.y,
|
|
485
|
-
placedTextSymbolIndices.
|
|
486
|
-
placedTextSymbolIndices.
|
|
643
|
+
placedTextSymbolIndices.right >= 0 ? placedTextSymbolIndices.right : -1,
|
|
644
|
+
placedTextSymbolIndices.center >= 0 ? placedTextSymbolIndices.center : -1,
|
|
645
|
+
placedTextSymbolIndices.left >= 0 ? placedTextSymbolIndices.left : -1,
|
|
646
|
+
placedTextSymbolIndices.vertical || -1,
|
|
487
647
|
key,
|
|
488
648
|
textBoxStartIndex,
|
|
489
649
|
textBoxEndIndex,
|
|
490
650
|
iconBoxStartIndex,
|
|
491
651
|
iconBoxEndIndex,
|
|
492
652
|
featureIndex,
|
|
493
|
-
|
|
653
|
+
numHorizontalGlyphVertices,
|
|
494
654
|
numVerticalGlyphVertices,
|
|
495
655
|
numIconVertices,
|
|
496
|
-
0
|
|
656
|
+
0,
|
|
657
|
+
textBoxScale,
|
|
658
|
+
radialTextOffset
|
|
497
659
|
);
|
|
498
660
|
}
|
|
499
661
|
|
|
@@ -6,16 +6,15 @@ export default class GeoJSONFeature {
|
|
|
6
6
|
#geometry;
|
|
7
7
|
#xyz;
|
|
8
8
|
|
|
9
|
-
constructor(vectorTileFeature, z, x, y) {
|
|
9
|
+
constructor(vectorTileFeature, z, x, y, id) {
|
|
10
10
|
this.type = 'Feature';
|
|
11
11
|
|
|
12
12
|
this.#vectorTileFeature = vectorTileFeature;
|
|
13
13
|
this.#xyz = { z, x, y };
|
|
14
14
|
|
|
15
15
|
this.properties = vectorTileFeature.properties;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.id = vectorTileFeature.id;
|
|
16
|
+
if (id !== undefined) {
|
|
17
|
+
this.id = id;
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
|