@versatiles/svg-renderer 0.5.2 → 0.6.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/README.md +26 -23
- package/dist/index.cjs +375 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +375 -15
- package/dist/index.js.map +1 -1
- package/dist/maplibre.cjs +396 -21
- package/dist/maplibre.cjs.map +1 -1
- package/dist/maplibre.d.ts +1 -0
- package/dist/maplibre.js +396 -21
- package/dist/maplibre.js.map +1 -1
- package/dist/maplibre.umd.js +396 -21
- package/dist/maplibre.umd.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -135,7 +135,7 @@ subgraph 0["src"]
|
|
|
135
135
|
2["index.ts"]
|
|
136
136
|
subgraph 3["pipeline"]
|
|
137
137
|
4["render.ts"]
|
|
138
|
-
|
|
138
|
+
E["style_layer.ts"]
|
|
139
139
|
end
|
|
140
140
|
subgraph 5["sources"]
|
|
141
141
|
6["index.ts"]
|
|
@@ -143,43 +143,46 @@ subgraph 5["sources"]
|
|
|
143
143
|
9["merge.ts"]
|
|
144
144
|
A["raster.ts"]
|
|
145
145
|
B["tiles.ts"]
|
|
146
|
-
C["
|
|
146
|
+
C["sprite.ts"]
|
|
147
|
+
D["vector.ts"]
|
|
147
148
|
end
|
|
148
149
|
8["geometry.ts"]
|
|
149
|
-
subgraph
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
subgraph F["renderer"]
|
|
151
|
+
G["svg.ts"]
|
|
152
|
+
H["color.ts"]
|
|
153
|
+
I["svg_path.ts"]
|
|
154
|
+
N["types.ts"]
|
|
154
155
|
end
|
|
155
|
-
subgraph
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
subgraph J["maplibre"]
|
|
157
|
+
K["control.ts"]
|
|
158
|
+
L["panel_css.ts"]
|
|
159
|
+
M["index.ts"]
|
|
159
160
|
end
|
|
160
161
|
end
|
|
161
162
|
1-->2
|
|
162
163
|
2-->4
|
|
163
|
-
2-->
|
|
164
|
+
2-->G
|
|
164
165
|
4-->6
|
|
165
|
-
4-->
|
|
166
|
+
4-->C
|
|
167
|
+
4-->E
|
|
166
168
|
6-->7
|
|
167
169
|
6-->9
|
|
168
170
|
6-->A
|
|
169
171
|
6-->C
|
|
172
|
+
6-->D
|
|
170
173
|
7-->8
|
|
171
174
|
9-->8
|
|
172
175
|
A-->B
|
|
173
176
|
B-->8
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
class 0,3,5,
|
|
177
|
+
D-->8
|
|
178
|
+
D-->B
|
|
179
|
+
G-->H
|
|
180
|
+
G-->I
|
|
181
|
+
K-->2
|
|
182
|
+
K-->L
|
|
183
|
+
M-->2
|
|
184
|
+
M-->K
|
|
185
|
+
|
|
186
|
+
class 0,3,5,F,J subgraphs;
|
|
184
187
|
classDef subgraphs fill-opacity:0.1, fill:#888, color:#888, stroke:#888;
|
|
185
188
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -2828,6 +2828,23 @@ var paint_raster = {
|
|
|
2828
2828
|
},
|
|
2829
2829
|
"property-type": "data-constant"
|
|
2830
2830
|
},
|
|
2831
|
+
resampling: {
|
|
2832
|
+
type: "enum",
|
|
2833
|
+
values: {
|
|
2834
|
+
linear: {
|
|
2835
|
+
},
|
|
2836
|
+
nearest: {
|
|
2837
|
+
}
|
|
2838
|
+
},
|
|
2839
|
+
"default": "linear",
|
|
2840
|
+
expression: {
|
|
2841
|
+
interpolated: false,
|
|
2842
|
+
parameters: [
|
|
2843
|
+
"zoom"
|
|
2844
|
+
]
|
|
2845
|
+
},
|
|
2846
|
+
"property-type": "data-constant"
|
|
2847
|
+
},
|
|
2831
2848
|
"raster-resampling": {
|
|
2832
2849
|
type: "enum",
|
|
2833
2850
|
values: {
|
|
@@ -2978,6 +2995,23 @@ var paint_hillshade = {
|
|
|
2978
2995
|
]
|
|
2979
2996
|
},
|
|
2980
2997
|
"property-type": "data-constant"
|
|
2998
|
+
},
|
|
2999
|
+
resampling: {
|
|
3000
|
+
type: "enum",
|
|
3001
|
+
values: {
|
|
3002
|
+
linear: {
|
|
3003
|
+
},
|
|
3004
|
+
nearest: {
|
|
3005
|
+
}
|
|
3006
|
+
},
|
|
3007
|
+
"default": "linear",
|
|
3008
|
+
expression: {
|
|
3009
|
+
interpolated: false,
|
|
3010
|
+
parameters: [
|
|
3011
|
+
"zoom"
|
|
3012
|
+
]
|
|
3013
|
+
},
|
|
3014
|
+
"property-type": "data-constant"
|
|
2981
3015
|
}
|
|
2982
3016
|
};
|
|
2983
3017
|
var paint_background = {
|
|
@@ -3398,6 +3432,23 @@ var v8Spec = {
|
|
|
3398
3432
|
]
|
|
3399
3433
|
},
|
|
3400
3434
|
"property-type": "color-ramp"
|
|
3435
|
+
},
|
|
3436
|
+
resampling: {
|
|
3437
|
+
type: "enum",
|
|
3438
|
+
values: {
|
|
3439
|
+
linear: {
|
|
3440
|
+
},
|
|
3441
|
+
nearest: {
|
|
3442
|
+
}
|
|
3443
|
+
},
|
|
3444
|
+
"default": "linear",
|
|
3445
|
+
expression: {
|
|
3446
|
+
interpolated: false,
|
|
3447
|
+
parameters: [
|
|
3448
|
+
"zoom"
|
|
3449
|
+
]
|
|
3450
|
+
},
|
|
3451
|
+
"property-type": "data-constant"
|
|
3401
3452
|
}
|
|
3402
3453
|
},
|
|
3403
3454
|
paint_background: paint_background,
|
|
@@ -6242,11 +6293,12 @@ class CollatorExpression {
|
|
|
6242
6293
|
}
|
|
6243
6294
|
|
|
6244
6295
|
class NumberFormat {
|
|
6245
|
-
constructor(number, locale, currency, minFractionDigits, maxFractionDigits) {
|
|
6296
|
+
constructor(number, locale, currency, unit, minFractionDigits, maxFractionDigits) {
|
|
6246
6297
|
this.type = StringType;
|
|
6247
6298
|
this.number = number;
|
|
6248
6299
|
this.locale = locale;
|
|
6249
6300
|
this.currency = currency;
|
|
6301
|
+
this.unit = unit;
|
|
6250
6302
|
this.minFractionDigits = minFractionDigits;
|
|
6251
6303
|
this.maxFractionDigits = maxFractionDigits;
|
|
6252
6304
|
}
|
|
@@ -6271,6 +6323,15 @@ class NumberFormat {
|
|
|
6271
6323
|
if (!currency)
|
|
6272
6324
|
return null;
|
|
6273
6325
|
}
|
|
6326
|
+
let unit = null;
|
|
6327
|
+
if (options['unit']) {
|
|
6328
|
+
unit = context.parse(options['unit'], 1, StringType);
|
|
6329
|
+
if (!unit)
|
|
6330
|
+
return null;
|
|
6331
|
+
}
|
|
6332
|
+
if (currency && unit) {
|
|
6333
|
+
return context.error('NumberFormat options `currency` and `unit` are mutually exclusive');
|
|
6334
|
+
}
|
|
6274
6335
|
let minFractionDigits = null;
|
|
6275
6336
|
if (options['min-fraction-digits']) {
|
|
6276
6337
|
minFractionDigits = context.parse(options['min-fraction-digits'], 1, NumberType);
|
|
@@ -6283,12 +6344,13 @@ class NumberFormat {
|
|
|
6283
6344
|
if (!maxFractionDigits)
|
|
6284
6345
|
return null;
|
|
6285
6346
|
}
|
|
6286
|
-
return new NumberFormat(number, locale, currency, minFractionDigits, maxFractionDigits);
|
|
6347
|
+
return new NumberFormat(number, locale, currency, unit, minFractionDigits, maxFractionDigits);
|
|
6287
6348
|
}
|
|
6288
6349
|
evaluate(ctx) {
|
|
6289
6350
|
return new Intl.NumberFormat(this.locale ? this.locale.evaluate(ctx) : [], {
|
|
6290
|
-
style: this.currency ? 'currency' : 'decimal',
|
|
6351
|
+
style: this.currency ? 'currency' : this.unit ? 'unit' : 'decimal',
|
|
6291
6352
|
currency: this.currency ? this.currency.evaluate(ctx) : undefined,
|
|
6353
|
+
unit: this.unit ? this.unit.evaluate(ctx) : undefined,
|
|
6292
6354
|
minimumFractionDigits: this.minFractionDigits
|
|
6293
6355
|
? this.minFractionDigits.evaluate(ctx)
|
|
6294
6356
|
: undefined,
|
|
@@ -6305,6 +6367,9 @@ class NumberFormat {
|
|
|
6305
6367
|
if (this.currency) {
|
|
6306
6368
|
fn(this.currency);
|
|
6307
6369
|
}
|
|
6370
|
+
if (this.unit) {
|
|
6371
|
+
fn(this.unit);
|
|
6372
|
+
}
|
|
6308
6373
|
if (this.minFractionDigits) {
|
|
6309
6374
|
fn(this.minFractionDigits);
|
|
6310
6375
|
}
|
|
@@ -8043,6 +8108,16 @@ CompoundExpression.register(expressions$1, {
|
|
|
8043
8108
|
varargs(ValueType),
|
|
8044
8109
|
(ctx, args) => args.map((arg) => valueToString(arg.evaluate(ctx))).join('')
|
|
8045
8110
|
],
|
|
8111
|
+
split: [
|
|
8112
|
+
array(StringType),
|
|
8113
|
+
[StringType, StringType],
|
|
8114
|
+
(ctx, [s, delim]) => s.evaluate(ctx).split(delim.evaluate(ctx))
|
|
8115
|
+
],
|
|
8116
|
+
join: [
|
|
8117
|
+
StringType,
|
|
8118
|
+
[array(StringType), StringType],
|
|
8119
|
+
(ctx, [arr, delim]) => arr.value.join(delim.evaluate(ctx))
|
|
8120
|
+
],
|
|
8046
8121
|
'resolved-locale': [
|
|
8047
8122
|
StringType,
|
|
8048
8123
|
[CollatorType],
|
|
@@ -9199,7 +9274,7 @@ class SVGRenderer {
|
|
|
9199
9274
|
color.alpha *= style.opacity;
|
|
9200
9275
|
this.#backgroundColor = color;
|
|
9201
9276
|
}
|
|
9202
|
-
drawPolygons(features) {
|
|
9277
|
+
drawPolygons(id, features) {
|
|
9203
9278
|
if (features.length === 0)
|
|
9204
9279
|
return;
|
|
9205
9280
|
const groups = new Map();
|
|
@@ -9223,12 +9298,14 @@ class SVGRenderer {
|
|
|
9223
9298
|
group.segments.push(ring.map((p) => roundXY(p.x, p.y)));
|
|
9224
9299
|
});
|
|
9225
9300
|
});
|
|
9301
|
+
this.#svg.push(`<g id="${escapeXml(id)}">`);
|
|
9226
9302
|
for (const { segments, attrs } of groups.values()) {
|
|
9227
9303
|
const d = segmentsToPath(segments, true);
|
|
9228
9304
|
this.#svg.push(`<path d="${d}" ${attrs} />`);
|
|
9229
9305
|
}
|
|
9306
|
+
this.#svg.push('</g>');
|
|
9230
9307
|
}
|
|
9231
|
-
drawLineStrings(features) {
|
|
9308
|
+
drawLineStrings(id, features) {
|
|
9232
9309
|
if (features.length === 0)
|
|
9233
9310
|
return;
|
|
9234
9311
|
const groups = new Map();
|
|
@@ -9277,13 +9354,15 @@ class SVGRenderer {
|
|
|
9277
9354
|
group.segments.push(line.map((p) => roundXY(p.x, p.y)));
|
|
9278
9355
|
});
|
|
9279
9356
|
});
|
|
9357
|
+
this.#svg.push(`<g id="${escapeXml(id)}">`);
|
|
9280
9358
|
for (const { segments, attrs } of groups.values()) {
|
|
9281
9359
|
const chains = chainSegments(segments);
|
|
9282
9360
|
const d = segmentsToPath(chains);
|
|
9283
9361
|
this.#svg.push(`<path d="${d}" ${attrs} />`);
|
|
9284
9362
|
}
|
|
9363
|
+
this.#svg.push('</g>');
|
|
9285
9364
|
}
|
|
9286
|
-
drawCircles(features) {
|
|
9365
|
+
drawCircles(id, features) {
|
|
9287
9366
|
if (features.length === 0)
|
|
9288
9367
|
return;
|
|
9289
9368
|
const groups = new Map();
|
|
@@ -9315,13 +9394,108 @@ class SVGRenderer {
|
|
|
9315
9394
|
group.points.push(roundXY(p.x, p.y));
|
|
9316
9395
|
});
|
|
9317
9396
|
});
|
|
9397
|
+
this.#svg.push(`<g id="${escapeXml(id)}">`);
|
|
9318
9398
|
for (const { points, attrs } of groups.values()) {
|
|
9319
9399
|
for (const [x, y] of points) {
|
|
9320
9400
|
this.#svg.push(`<circle cx="${formatNum(x)}" cy="${formatNum(y)}" ${attrs} />`);
|
|
9321
9401
|
}
|
|
9322
9402
|
}
|
|
9403
|
+
this.#svg.push('</g>');
|
|
9404
|
+
}
|
|
9405
|
+
drawLabels(id, features) {
|
|
9406
|
+
if (features.length === 0)
|
|
9407
|
+
return;
|
|
9408
|
+
this.#svg.push(`<g id="${escapeXml(id)}">`);
|
|
9409
|
+
for (const [feature, style] of features) {
|
|
9410
|
+
if (style.opacity <= 0 || !style.text)
|
|
9411
|
+
continue;
|
|
9412
|
+
const color = new Color(style.color);
|
|
9413
|
+
if (color.alpha <= 0)
|
|
9414
|
+
continue;
|
|
9415
|
+
const ring = feature.geometry[0];
|
|
9416
|
+
if (!ring || ring.length === 0)
|
|
9417
|
+
continue;
|
|
9418
|
+
const point = ring[Math.floor(ring.length / 2)];
|
|
9419
|
+
const [px, py] = roundXY(point.x, point.y);
|
|
9420
|
+
const fontSize = formatScaled(style.size);
|
|
9421
|
+
const fontFamily = style.font.join(', ') + ', Helvetica, Arial, sans-serif';
|
|
9422
|
+
const [svgAnchor, baseline] = mapTextAnchor(style.anchor);
|
|
9423
|
+
const offsetX = style.offset[0] * style.size;
|
|
9424
|
+
const offsetY = style.offset[1] * style.size;
|
|
9425
|
+
const [dx, dy] = roundXY(offsetX, offsetY);
|
|
9426
|
+
const attrs = [
|
|
9427
|
+
`x="${formatNum(px)}"`,
|
|
9428
|
+
`y="${formatNum(py)}"`,
|
|
9429
|
+
`font-family="${escapeXml(fontFamily)}"`,
|
|
9430
|
+
`font-size="${fontSize}"`,
|
|
9431
|
+
`text-anchor="${svgAnchor}"`,
|
|
9432
|
+
`dominant-baseline="${baseline}"`,
|
|
9433
|
+
];
|
|
9434
|
+
if (dx !== 0)
|
|
9435
|
+
attrs.push(`dx="${formatNum(dx)}"`);
|
|
9436
|
+
if (dy !== 0)
|
|
9437
|
+
attrs.push(`dy="${formatNum(dy)}"`);
|
|
9438
|
+
if (style.rotate !== 0) {
|
|
9439
|
+
attrs.push(`transform="rotate(${String(style.rotate)},${formatNum(px)},${formatNum(py)})"`);
|
|
9440
|
+
}
|
|
9441
|
+
const haloColor = new Color(style.haloColor);
|
|
9442
|
+
if (style.haloWidth > 0 && haloColor.alpha > 0) {
|
|
9443
|
+
const haloWidth = formatScaled(style.haloWidth);
|
|
9444
|
+
attrs.push('paint-order="stroke fill"', `stroke="${haloColor.rgb}"`, `stroke-width="${haloWidth}"`, 'stroke-linejoin="round"');
|
|
9445
|
+
if (haloColor.alpha < 255)
|
|
9446
|
+
attrs.push(`stroke-opacity="${haloColor.opacity.toFixed(3)}"`);
|
|
9447
|
+
}
|
|
9448
|
+
attrs.push(fillAttr(color));
|
|
9449
|
+
if (style.opacity < 1)
|
|
9450
|
+
attrs.push(`opacity="${style.opacity.toFixed(3)}"`);
|
|
9451
|
+
this.#svg.push(`<text ${attrs.join(' ')}>${escapeXml(style.text)}</text>`);
|
|
9452
|
+
}
|
|
9453
|
+
this.#svg.push('</g>');
|
|
9454
|
+
}
|
|
9455
|
+
drawIcons(id, features, spriteAtlas) {
|
|
9456
|
+
if (features.length === 0)
|
|
9457
|
+
return;
|
|
9458
|
+
this.#svg.push(`<g id="${escapeXml(id)}">`);
|
|
9459
|
+
for (const [feature, style] of features) {
|
|
9460
|
+
if (style.opacity <= 0)
|
|
9461
|
+
continue;
|
|
9462
|
+
const sprite = spriteAtlas.get(style.image);
|
|
9463
|
+
if (!sprite)
|
|
9464
|
+
continue;
|
|
9465
|
+
const ring = feature.geometry[0];
|
|
9466
|
+
if (!ring || ring.length === 0)
|
|
9467
|
+
continue;
|
|
9468
|
+
const point = ring[Math.floor(ring.length / 2)];
|
|
9469
|
+
const scale = style.size / sprite.pixelRatio;
|
|
9470
|
+
const iconW = sprite.width * scale;
|
|
9471
|
+
const iconH = sprite.height * scale;
|
|
9472
|
+
const [anchorDx, anchorDy] = mapIconAnchor(style.anchor, iconW, iconH);
|
|
9473
|
+
const ox = style.offset[0] * style.size + anchorDx;
|
|
9474
|
+
const oy = style.offset[1] * style.size + anchorDy;
|
|
9475
|
+
const x = point.x + ox;
|
|
9476
|
+
const y = point.y + oy;
|
|
9477
|
+
const [sx, sy] = roundXY(x, y);
|
|
9478
|
+
const [sw, sh] = roundXY(iconW, iconH);
|
|
9479
|
+
const viewBox = `${String(sprite.x)} ${String(sprite.y)} ${String(sprite.width)} ${String(sprite.height)}`;
|
|
9480
|
+
const attrs = [
|
|
9481
|
+
`x="${formatNum(sx)}"`,
|
|
9482
|
+
`y="${formatNum(sy)}"`,
|
|
9483
|
+
`width="${formatNum(sw)}"`,
|
|
9484
|
+
`height="${formatNum(sh)}"`,
|
|
9485
|
+
];
|
|
9486
|
+
if (style.opacity < 1)
|
|
9487
|
+
attrs.push(`opacity="${style.opacity.toFixed(3)}"`);
|
|
9488
|
+
if (style.rotate !== 0) {
|
|
9489
|
+
const [cx, cy] = roundXY(point.x + style.offset[0] * style.size, point.y + style.offset[1] * style.size);
|
|
9490
|
+
attrs.push(`transform="rotate(${String(style.rotate)},${formatNum(cx)},${formatNum(cy)})"`);
|
|
9491
|
+
}
|
|
9492
|
+
this.#svg.push(`<svg ${attrs.join(' ')} viewBox="${viewBox}" xmlns="http://www.w3.org/2000/svg">` +
|
|
9493
|
+
`<image width="${String(sprite.sheetWidth)}" height="${String(sprite.sheetHeight)}" href="${sprite.sheetDataUri}" />` +
|
|
9494
|
+
`</svg>`);
|
|
9495
|
+
}
|
|
9496
|
+
this.#svg.push('</g>');
|
|
9323
9497
|
}
|
|
9324
|
-
drawRasterTiles(tiles, style) {
|
|
9498
|
+
drawRasterTiles(id, tiles, style) {
|
|
9325
9499
|
if (tiles.length === 0)
|
|
9326
9500
|
return;
|
|
9327
9501
|
if (style.opacity <= 0)
|
|
@@ -9337,7 +9511,7 @@ class SVGRenderer {
|
|
|
9337
9511
|
const brightness = (style.brightnessMin + style.brightnessMax) / 2;
|
|
9338
9512
|
filters.push(`brightness(${String(brightness)})`);
|
|
9339
9513
|
}
|
|
9340
|
-
let gAttrs = `opacity="${String(style.opacity)}"`;
|
|
9514
|
+
let gAttrs = `id="${escapeXml(id)}" opacity="${String(style.opacity)}"`;
|
|
9341
9515
|
if (filters.length > 0)
|
|
9342
9516
|
gAttrs += ` filter="${filters.join(' ')}"`;
|
|
9343
9517
|
this.#svg.push(`<g ${gAttrs}>`);
|
|
@@ -9388,6 +9562,57 @@ function formatPoint(p) {
|
|
|
9388
9562
|
const [x, y] = roundXY(p[0], p[1]);
|
|
9389
9563
|
return formatNum(x) + ',' + formatNum(y);
|
|
9390
9564
|
}
|
|
9565
|
+
function mapTextAnchor(anchor) {
|
|
9566
|
+
switch (anchor) {
|
|
9567
|
+
case 'left':
|
|
9568
|
+
return ['start', 'central'];
|
|
9569
|
+
case 'right':
|
|
9570
|
+
return ['end', 'central'];
|
|
9571
|
+
case 'top':
|
|
9572
|
+
return ['middle', 'text-before-edge'];
|
|
9573
|
+
case 'bottom':
|
|
9574
|
+
return ['middle', 'text-after-edge'];
|
|
9575
|
+
case 'top-left':
|
|
9576
|
+
return ['start', 'text-before-edge'];
|
|
9577
|
+
case 'top-right':
|
|
9578
|
+
return ['end', 'text-before-edge'];
|
|
9579
|
+
case 'bottom-left':
|
|
9580
|
+
return ['start', 'text-after-edge'];
|
|
9581
|
+
case 'bottom-right':
|
|
9582
|
+
return ['end', 'text-after-edge'];
|
|
9583
|
+
default:
|
|
9584
|
+
return ['middle', 'central'];
|
|
9585
|
+
}
|
|
9586
|
+
}
|
|
9587
|
+
function mapIconAnchor(anchor, w, h) {
|
|
9588
|
+
switch (anchor) {
|
|
9589
|
+
case 'left':
|
|
9590
|
+
return [0, -h / 2];
|
|
9591
|
+
case 'right':
|
|
9592
|
+
return [-w, -h / 2];
|
|
9593
|
+
case 'top':
|
|
9594
|
+
return [-w / 2, 0];
|
|
9595
|
+
case 'bottom':
|
|
9596
|
+
return [-w / 2, -h];
|
|
9597
|
+
case 'top-left':
|
|
9598
|
+
return [0, 0];
|
|
9599
|
+
case 'top-right':
|
|
9600
|
+
return [-w, 0];
|
|
9601
|
+
case 'bottom-left':
|
|
9602
|
+
return [0, -h];
|
|
9603
|
+
case 'bottom-right':
|
|
9604
|
+
return [-w, -h];
|
|
9605
|
+
default:
|
|
9606
|
+
return [-w / 2, -h / 2];
|
|
9607
|
+
}
|
|
9608
|
+
}
|
|
9609
|
+
function escapeXml(s) {
|
|
9610
|
+
return s
|
|
9611
|
+
.replace(/&/g, '&')
|
|
9612
|
+
.replace(/</g, '<')
|
|
9613
|
+
.replace(/>/g, '>')
|
|
9614
|
+
.replace(/"/g, '"');
|
|
9615
|
+
}
|
|
9391
9616
|
|
|
9392
9617
|
/*
|
|
9393
9618
|
* bignumber.js v9.3.1
|
|
@@ -15936,6 +16161,65 @@ async function getRasterTiles(job, sourceName) {
|
|
|
15936
16161
|
return rasterTiles.filter((tile) => tile !== null);
|
|
15937
16162
|
}
|
|
15938
16163
|
|
|
16164
|
+
async function loadSpriteAtlas(style) {
|
|
16165
|
+
const atlas = new Map();
|
|
16166
|
+
const sprite = style.sprite;
|
|
16167
|
+
if (!sprite)
|
|
16168
|
+
return atlas;
|
|
16169
|
+
const sources = [];
|
|
16170
|
+
if (typeof sprite === 'string') {
|
|
16171
|
+
sources.push({ id: 'default', url: sprite });
|
|
16172
|
+
}
|
|
16173
|
+
else if (Array.isArray(sprite)) {
|
|
16174
|
+
for (const s of sprite) {
|
|
16175
|
+
sources.push({
|
|
16176
|
+
id: s.id,
|
|
16177
|
+
url: s.url,
|
|
16178
|
+
});
|
|
16179
|
+
}
|
|
16180
|
+
}
|
|
16181
|
+
await Promise.all(sources.map(async ({ id, url }) => {
|
|
16182
|
+
try {
|
|
16183
|
+
const [jsonResponse, imageResponse] = await Promise.all([
|
|
16184
|
+
fetch(`${url}.json`),
|
|
16185
|
+
fetch(`${url}.png`),
|
|
16186
|
+
]);
|
|
16187
|
+
if (!jsonResponse.ok || !imageResponse.ok)
|
|
16188
|
+
return;
|
|
16189
|
+
const json = (await jsonResponse.json());
|
|
16190
|
+
const imageBuffer = await imageResponse.arrayBuffer();
|
|
16191
|
+
const base64 = typeof Buffer !== 'undefined'
|
|
16192
|
+
? Buffer.from(imageBuffer).toString('base64')
|
|
16193
|
+
: btoa(String.fromCharCode(...new Uint8Array(imageBuffer)));
|
|
16194
|
+
const sheetDataUri = `data:image/png;base64,${base64}`;
|
|
16195
|
+
// Estimate sheet dimensions from sprite entries
|
|
16196
|
+
let sheetWidth = 0;
|
|
16197
|
+
let sheetHeight = 0;
|
|
16198
|
+
for (const entry of Object.values(json)) {
|
|
16199
|
+
sheetWidth = Math.max(sheetWidth, entry.x + entry.width);
|
|
16200
|
+
sheetHeight = Math.max(sheetHeight, entry.y + entry.height);
|
|
16201
|
+
}
|
|
16202
|
+
const prefix = id === 'default' ? '' : `${id}:`;
|
|
16203
|
+
for (const [name, entry] of Object.entries(json)) {
|
|
16204
|
+
atlas.set(`${prefix}${name}`, {
|
|
16205
|
+
width: entry.width,
|
|
16206
|
+
height: entry.height,
|
|
16207
|
+
x: entry.x,
|
|
16208
|
+
y: entry.y,
|
|
16209
|
+
pixelRatio: entry.pixelRatio ?? 1,
|
|
16210
|
+
sheetDataUri,
|
|
16211
|
+
sheetWidth,
|
|
16212
|
+
sheetHeight,
|
|
16213
|
+
});
|
|
16214
|
+
}
|
|
16215
|
+
}
|
|
16216
|
+
catch {
|
|
16217
|
+
// Silently skip failed sprite loads
|
|
16218
|
+
}
|
|
16219
|
+
}));
|
|
16220
|
+
return atlas;
|
|
16221
|
+
}
|
|
16222
|
+
|
|
15939
16223
|
async function getLayerFeatures(job) {
|
|
15940
16224
|
const { width, height } = job.renderer;
|
|
15941
16225
|
const { zoom, center } = job.view;
|
|
@@ -16096,6 +16380,12 @@ function getLayerStyles(layers) {
|
|
|
16096
16380
|
return layers.map(createStyleLayer);
|
|
16097
16381
|
}
|
|
16098
16382
|
|
|
16383
|
+
function resolveTokens(text, properties) {
|
|
16384
|
+
return text.replace(/\{([^}]+)\}/g, (_, key) => {
|
|
16385
|
+
const value = properties[key];
|
|
16386
|
+
return value != null ? String(value) : '';
|
|
16387
|
+
});
|
|
16388
|
+
}
|
|
16099
16389
|
async function renderMap(job) {
|
|
16100
16390
|
await render(job);
|
|
16101
16391
|
return job.renderer.getString();
|
|
@@ -16106,9 +16396,12 @@ function getFeatures(layerFeatures, layerStyle) {
|
|
|
16106
16396
|
async function render(job) {
|
|
16107
16397
|
const { renderer } = job;
|
|
16108
16398
|
const { zoom } = job.view;
|
|
16109
|
-
const layerFeatures = await
|
|
16399
|
+
const [layerFeatures, spriteAtlas] = await Promise.all([
|
|
16400
|
+
getLayerFeatures(job),
|
|
16401
|
+
job.renderLabels ? loadSpriteAtlas(job.style) : Promise.resolve(new Map()),
|
|
16402
|
+
]);
|
|
16110
16403
|
const layerStyles = getLayerStyles(job.style.layers);
|
|
16111
|
-
const availableImages = [];
|
|
16404
|
+
const availableImages = [...spriteAtlas.keys()];
|
|
16112
16405
|
const featureState = {};
|
|
16113
16406
|
for (const layerStyle of layerStyles) {
|
|
16114
16407
|
if (layerStyle.isHidden(zoom))
|
|
@@ -16129,6 +16422,7 @@ async function render(job) {
|
|
|
16129
16422
|
function getLayout(key, feature) {
|
|
16130
16423
|
return getStyleValue(layerStyle.layout, key, feature);
|
|
16131
16424
|
}
|
|
16425
|
+
const layerId = layerStyle.id;
|
|
16132
16426
|
switch (layerStyle.type) {
|
|
16133
16427
|
case 'background':
|
|
16134
16428
|
{
|
|
@@ -16148,7 +16442,7 @@ async function render(job) {
|
|
|
16148
16442
|
: polygons;
|
|
16149
16443
|
if (polygonFeatures.length === 0)
|
|
16150
16444
|
continue;
|
|
16151
|
-
renderer.drawPolygons(polygonFeatures.map((feature) => [
|
|
16445
|
+
renderer.drawPolygons(layerId, polygonFeatures.map((feature) => [
|
|
16152
16446
|
feature,
|
|
16153
16447
|
{
|
|
16154
16448
|
color: getPaint('fill-color', feature),
|
|
@@ -16168,7 +16462,7 @@ async function render(job) {
|
|
|
16168
16462
|
: lineStrings;
|
|
16169
16463
|
if (lineStringFeatures.length === 0)
|
|
16170
16464
|
continue;
|
|
16171
|
-
renderer.drawLineStrings(lineStringFeatures.map((feature) => [
|
|
16465
|
+
renderer.drawLineStrings(layerId, lineStringFeatures.map((feature) => [
|
|
16172
16466
|
feature,
|
|
16173
16467
|
{
|
|
16174
16468
|
color: getPaint('line-color', feature),
|
|
@@ -16187,7 +16481,7 @@ async function render(job) {
|
|
|
16187
16481
|
case 'raster':
|
|
16188
16482
|
{
|
|
16189
16483
|
const tiles = await getRasterTiles(job, layerStyle.source);
|
|
16190
|
-
renderer.drawRasterTiles(tiles, {
|
|
16484
|
+
renderer.drawRasterTiles(layerId, tiles, {
|
|
16191
16485
|
opacity: getPaint('raster-opacity'),
|
|
16192
16486
|
hueRotate: getPaint('raster-hue-rotate'),
|
|
16193
16487
|
brightnessMin: getPaint('raster-brightness-min'),
|
|
@@ -16208,7 +16502,7 @@ async function render(job) {
|
|
|
16208
16502
|
: points;
|
|
16209
16503
|
if (pointFeatures.length === 0)
|
|
16210
16504
|
continue;
|
|
16211
|
-
renderer.drawCircles(pointFeatures.map((feature) => [
|
|
16505
|
+
renderer.drawCircles(layerId, pointFeatures.map((feature) => [
|
|
16212
16506
|
feature,
|
|
16213
16507
|
{
|
|
16214
16508
|
color: getPaint('circle-color', feature),
|
|
@@ -16221,11 +16515,76 @@ async function render(job) {
|
|
|
16221
16515
|
]));
|
|
16222
16516
|
}
|
|
16223
16517
|
continue;
|
|
16518
|
+
case 'symbol':
|
|
16519
|
+
{
|
|
16520
|
+
if (!job.renderLabels)
|
|
16521
|
+
continue;
|
|
16522
|
+
const features = getFeatures(layerFeatures, layerStyle);
|
|
16523
|
+
const allFeatures = [
|
|
16524
|
+
...(features?.points ?? []),
|
|
16525
|
+
...(features?.linestrings ?? []),
|
|
16526
|
+
...(features?.polygons ?? []),
|
|
16527
|
+
];
|
|
16528
|
+
if (allFeatures.length === 0)
|
|
16529
|
+
continue;
|
|
16530
|
+
const symbolFeatures = layerStyle.filterFn
|
|
16531
|
+
? allFeatures.filter((feature) => layerStyle.filterFn.filter({ zoom }, feature))
|
|
16532
|
+
: allFeatures;
|
|
16533
|
+
if (symbolFeatures.length === 0)
|
|
16534
|
+
continue;
|
|
16535
|
+
// Render icons first (underneath text)
|
|
16536
|
+
renderer.drawIcons(`${layerId}-icons`, symbolFeatures.flatMap((feature) => {
|
|
16537
|
+
const iconImage = getLayout('icon-image', feature);
|
|
16538
|
+
const iconName = iconImage != null
|
|
16539
|
+
? resolveTokens(iconImage.toString(), feature.properties)
|
|
16540
|
+
: '';
|
|
16541
|
+
if (!iconName || !spriteAtlas.has(iconName))
|
|
16542
|
+
return [];
|
|
16543
|
+
return [
|
|
16544
|
+
[
|
|
16545
|
+
feature,
|
|
16546
|
+
{
|
|
16547
|
+
image: iconName,
|
|
16548
|
+
size: getLayout('icon-size', feature),
|
|
16549
|
+
anchor: getLayout('icon-anchor', feature),
|
|
16550
|
+
offset: getLayout('icon-offset', feature),
|
|
16551
|
+
rotate: getLayout('icon-rotate', feature),
|
|
16552
|
+
opacity: getPaint('icon-opacity', feature),
|
|
16553
|
+
},
|
|
16554
|
+
],
|
|
16555
|
+
];
|
|
16556
|
+
}), spriteAtlas);
|
|
16557
|
+
// Render text labels on top
|
|
16558
|
+
renderer.drawLabels(`${layerId}-labels`, symbolFeatures.flatMap((feature) => {
|
|
16559
|
+
const textField = getLayout('text-field', feature);
|
|
16560
|
+
const textRaw = textField != null ? textField.toString() : '';
|
|
16561
|
+
const text = resolveTokens(textRaw, feature.properties);
|
|
16562
|
+
if (!text)
|
|
16563
|
+
return [];
|
|
16564
|
+
return [
|
|
16565
|
+
[
|
|
16566
|
+
feature,
|
|
16567
|
+
{
|
|
16568
|
+
text,
|
|
16569
|
+
size: getLayout('text-size', feature),
|
|
16570
|
+
font: getLayout('text-font', feature),
|
|
16571
|
+
anchor: getLayout('text-anchor', feature),
|
|
16572
|
+
offset: getLayout('text-offset', feature),
|
|
16573
|
+
rotate: getLayout('text-rotate', feature),
|
|
16574
|
+
color: getPaint('text-color', feature),
|
|
16575
|
+
opacity: getPaint('text-opacity', feature),
|
|
16576
|
+
haloColor: getPaint('text-halo-color', feature),
|
|
16577
|
+
haloWidth: getPaint('text-halo-width', feature),
|
|
16578
|
+
},
|
|
16579
|
+
],
|
|
16580
|
+
];
|
|
16581
|
+
}));
|
|
16582
|
+
}
|
|
16583
|
+
continue;
|
|
16224
16584
|
case 'color-relief':
|
|
16225
16585
|
case 'fill-extrusion':
|
|
16226
16586
|
case 'heatmap':
|
|
16227
16587
|
case 'hillshade':
|
|
16228
|
-
case 'symbol':
|
|
16229
16588
|
continue;
|
|
16230
16589
|
default:
|
|
16231
16590
|
throw Error('layerStyle.type: ' + String(layerStyle.type));
|
|
@@ -16247,6 +16606,7 @@ async function renderToSVG(options) {
|
|
|
16247
16606
|
center: [options.lon ?? 0, options.lat ?? 0],
|
|
16248
16607
|
zoom: options.zoom ?? 2,
|
|
16249
16608
|
},
|
|
16609
|
+
renderLabels: options.renderLabels ?? false,
|
|
16250
16610
|
});
|
|
16251
16611
|
}
|
|
16252
16612
|
|