ts-maps 0.3.3 → 0.3.5
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.
|
@@ -86,6 +86,7 @@ export declare interface VectorTileLayoutProperties {
|
|
|
86
86
|
'text-font'?: string | string[]
|
|
87
87
|
'text-italic'?: boolean
|
|
88
88
|
'text-bold'?: boolean
|
|
89
|
+
'text-letter-spacing'?: number | unknown
|
|
89
90
|
'icon-image'?: string | unknown
|
|
90
91
|
'icon-size'?: number
|
|
91
92
|
'icon-rotate'?: number
|
|
@@ -1428,6 +1428,23 @@ function registerLogicalOps() {
|
|
|
1428
1428
|
registerOperator("in", (args, compile, path) => {
|
|
1429
1429
|
if (args.length < 1)
|
|
1430
1430
|
throw new ExpressionError('"in" expects at least 1 argument', ["in", ...args], path);
|
|
1431
|
+
if (args.length === 2 && Array.isArray(args[1])) {
|
|
1432
|
+
const needle = compile(args[0], "value", path.concat(1));
|
|
1433
|
+
const haystack2 = compile(args[1], "value", path.concat(2));
|
|
1434
|
+
return {
|
|
1435
|
+
evaluate: (ctx) => {
|
|
1436
|
+
const x = needle.evaluate(ctx);
|
|
1437
|
+
const hay = haystack2.evaluate(ctx);
|
|
1438
|
+
if (Array.isArray(hay))
|
|
1439
|
+
return hay.some((value) => strictEq(x, value));
|
|
1440
|
+
if (typeof hay === "string")
|
|
1441
|
+
return typeof x === "string" && hay.includes(x);
|
|
1442
|
+
return false;
|
|
1443
|
+
},
|
|
1444
|
+
returnType: "boolean",
|
|
1445
|
+
...mergeDeps4([needle, haystack2])
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1431
1448
|
const input = compile(args[0], "value", path.concat(1));
|
|
1432
1449
|
const haystack = args.slice(1);
|
|
1433
1450
|
return {
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
// GlyphAtlas — rasterises font glyphs to a single backing canvas and packs
|
|
2
|
-
// them via a simple shelf-packer. Each glyph gets an approximate signed
|
|
3
|
-
// distance field generated by a cheap 2-pass Chamfer 3-4 scan so callers can
|
|
4
|
-
// resample the atlas at any target size with tolerably smooth edges.
|
|
5
|
-
//
|
|
6
|
-
// Zero runtime deps. Designed to live alongside Canvas2D rendering today and
|
|
7
|
-
// graduate to WebGL sampling later without changing the public API.
|
|
8
1
|
export declare interface GlyphMetrics {
|
|
9
2
|
codePoint: number
|
|
10
3
|
x: number
|
|
@@ -26,8 +19,8 @@ export declare class GlyphAtlas {
|
|
|
26
19
|
constructor(opts?: GlyphAtlasOptions);
|
|
27
20
|
getOrAddGlyph(codePoint: number, style?: { italic?: boolean, bold?: boolean }): GlyphMetrics;
|
|
28
21
|
measure(text: string, style?: { italic?: boolean, bold?: boolean, family?: string }): { width: number, height: number };
|
|
29
|
-
advances(text: string, size: number, style?: { italic?: boolean, bold?: boolean, family?: string }): Array<{ char: string, advance: number }>;
|
|
30
|
-
measureText(text: string, size: number, style?: { italic?: boolean, bold?: boolean, family?: string }): { width: number, height: number, ascent: number, descent: number };
|
|
22
|
+
advances(text: string, size: number, style?: { italic?: boolean, bold?: boolean, family?: string, letterSpacing?: number }): Array<{ char: string, advance: number }>;
|
|
23
|
+
measureText(text: string, size: number, style?: { italic?: boolean, bold?: boolean, family?: string, letterSpacing?: number }): { width: number, height: number, ascent: number, descent: number };
|
|
31
24
|
fontString(size: number, style?: { italic?: boolean, bold?: boolean, family?: string }): string;
|
|
32
25
|
resolveFont(textFont: string | string[] | undefined): { family: string, bold: boolean, italic: boolean };
|
|
33
26
|
drawText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, options: {
|
|
@@ -38,6 +31,7 @@ export declare class GlyphAtlas {
|
|
|
38
31
|
italic?: boolean
|
|
39
32
|
bold?: boolean
|
|
40
33
|
family?: string
|
|
34
|
+
letterSpacing?: number
|
|
41
35
|
}): void;
|
|
42
36
|
_buildSDF(imageData: ImageData): ImageData;
|
|
43
37
|
}
|
|
@@ -168,6 +168,23 @@ var exports_GlyphAtlas = {};
|
|
|
168
168
|
__export(exports_GlyphAtlas, {
|
|
169
169
|
GlyphAtlas: () => GlyphAtlas
|
|
170
170
|
});
|
|
171
|
+
function applyTracking(ctx, spacing) {
|
|
172
|
+
if (!spacing)
|
|
173
|
+
return true;
|
|
174
|
+
if (!("letterSpacing" in ctx))
|
|
175
|
+
return false;
|
|
176
|
+
const tracked = ctx;
|
|
177
|
+
tracked.letterSpacing = `${spacing}px`;
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
function trackingWidth(text, spacing) {
|
|
181
|
+
if (!spacing)
|
|
182
|
+
return 0;
|
|
183
|
+
let count = 0;
|
|
184
|
+
for (const _ of text)
|
|
185
|
+
count++;
|
|
186
|
+
return count * spacing;
|
|
187
|
+
}
|
|
171
188
|
function styleKey(k) {
|
|
172
189
|
if (!k)
|
|
173
190
|
return "r";
|
|
@@ -230,8 +247,9 @@ class GlyphAtlas {
|
|
|
230
247
|
if (ctx) {
|
|
231
248
|
ctx.save();
|
|
232
249
|
ctx.font = this.fontString(size, style);
|
|
250
|
+
const tracking = style?.letterSpacing ?? 0;
|
|
233
251
|
for (const ch of text)
|
|
234
|
-
out.push({ char: ch, advance: ctx.measureText(ch).width });
|
|
252
|
+
out.push({ char: ch, advance: ctx.measureText(ch).width + tracking });
|
|
235
253
|
ctx.restore();
|
|
236
254
|
return out;
|
|
237
255
|
}
|
|
@@ -249,15 +267,18 @@ class GlyphAtlas {
|
|
|
249
267
|
const atlas = this.measure(text, style);
|
|
250
268
|
const scale = size / this._fontSize;
|
|
251
269
|
const height = atlas.height * scale;
|
|
252
|
-
|
|
270
|
+
const tracking = trackingWidth(text, style?.letterSpacing);
|
|
271
|
+
return { width: atlas.width * scale + tracking, height, ascent: height * 0.8, descent: height * 0.2 };
|
|
253
272
|
}
|
|
254
273
|
ctx.save();
|
|
255
274
|
ctx.font = this.fontString(size, style);
|
|
275
|
+
const spaced = applyTracking(ctx, style?.letterSpacing);
|
|
256
276
|
const m = ctx.measureText(text);
|
|
277
|
+
const width = spaced ? m.width : m.width + trackingWidth(text, style?.letterSpacing);
|
|
257
278
|
ctx.restore();
|
|
258
279
|
const ascent = m.fontBoundingBoxAscent || m.actualBoundingBoxAscent || size * 0.8;
|
|
259
280
|
const descent = m.fontBoundingBoxDescent || m.actualBoundingBoxDescent || size * 0.2;
|
|
260
|
-
return { width
|
|
281
|
+
return { width, height: ascent + descent, ascent, descent };
|
|
261
282
|
}
|
|
262
283
|
fontString(size, style) {
|
|
263
284
|
const parts = [];
|
|
@@ -312,6 +333,7 @@ class GlyphAtlas {
|
|
|
312
333
|
const style = { italic: !!options.italic, bold: !!options.bold, family: options.family };
|
|
313
334
|
ctx.save();
|
|
314
335
|
ctx.font = this.fontString(options.size, style);
|
|
336
|
+
applyTracking(ctx, options.letterSpacing);
|
|
315
337
|
ctx.textAlign = "left";
|
|
316
338
|
ctx.textBaseline = "alphabetic";
|
|
317
339
|
if (options.haloColor && options.haloWidth && options.haloWidth > 0) {
|
package/dist/index.js
CHANGED
|
@@ -4725,6 +4725,23 @@ function registerLogicalOps() {
|
|
|
4725
4725
|
registerOperator("in", (args, compile, path) => {
|
|
4726
4726
|
if (args.length < 1)
|
|
4727
4727
|
throw new ExpressionError('"in" expects at least 1 argument', ["in", ...args], path);
|
|
4728
|
+
if (args.length === 2 && Array.isArray(args[1])) {
|
|
4729
|
+
const needle = compile(args[0], "value", path.concat(1));
|
|
4730
|
+
const haystack2 = compile(args[1], "value", path.concat(2));
|
|
4731
|
+
return {
|
|
4732
|
+
evaluate: (ctx) => {
|
|
4733
|
+
const x = needle.evaluate(ctx);
|
|
4734
|
+
const hay = haystack2.evaluate(ctx);
|
|
4735
|
+
if (Array.isArray(hay))
|
|
4736
|
+
return hay.some((value) => strictEq(x, value));
|
|
4737
|
+
if (typeof hay === "string")
|
|
4738
|
+
return typeof x === "string" && hay.includes(x);
|
|
4739
|
+
return false;
|
|
4740
|
+
},
|
|
4741
|
+
returnType: "boolean",
|
|
4742
|
+
...mergeDeps4([needle, haystack2])
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4728
4745
|
const input = compile(args[0], "value", path.concat(1));
|
|
4729
4746
|
const haystack = args.slice(1);
|
|
4730
4747
|
return {
|
|
@@ -8302,6 +8319,23 @@ var exports_GlyphAtlas = {};
|
|
|
8302
8319
|
__export(exports_GlyphAtlas, {
|
|
8303
8320
|
GlyphAtlas: () => GlyphAtlas
|
|
8304
8321
|
});
|
|
8322
|
+
function applyTracking(ctx, spacing) {
|
|
8323
|
+
if (!spacing)
|
|
8324
|
+
return true;
|
|
8325
|
+
if (!("letterSpacing" in ctx))
|
|
8326
|
+
return false;
|
|
8327
|
+
const tracked = ctx;
|
|
8328
|
+
tracked.letterSpacing = `${spacing}px`;
|
|
8329
|
+
return true;
|
|
8330
|
+
}
|
|
8331
|
+
function trackingWidth(text, spacing) {
|
|
8332
|
+
if (!spacing)
|
|
8333
|
+
return 0;
|
|
8334
|
+
let count = 0;
|
|
8335
|
+
for (const _ of text)
|
|
8336
|
+
count++;
|
|
8337
|
+
return count * spacing;
|
|
8338
|
+
}
|
|
8305
8339
|
function styleKey(k) {
|
|
8306
8340
|
if (!k)
|
|
8307
8341
|
return "r";
|
|
@@ -8364,8 +8398,9 @@ class GlyphAtlas {
|
|
|
8364
8398
|
if (ctx) {
|
|
8365
8399
|
ctx.save();
|
|
8366
8400
|
ctx.font = this.fontString(size, style);
|
|
8401
|
+
const tracking = style?.letterSpacing ?? 0;
|
|
8367
8402
|
for (const ch of text)
|
|
8368
|
-
out.push({ char: ch, advance: ctx.measureText(ch).width });
|
|
8403
|
+
out.push({ char: ch, advance: ctx.measureText(ch).width + tracking });
|
|
8369
8404
|
ctx.restore();
|
|
8370
8405
|
return out;
|
|
8371
8406
|
}
|
|
@@ -8383,15 +8418,18 @@ class GlyphAtlas {
|
|
|
8383
8418
|
const atlas = this.measure(text, style);
|
|
8384
8419
|
const scale = size / this._fontSize;
|
|
8385
8420
|
const height = atlas.height * scale;
|
|
8386
|
-
|
|
8421
|
+
const tracking = trackingWidth(text, style?.letterSpacing);
|
|
8422
|
+
return { width: atlas.width * scale + tracking, height, ascent: height * 0.8, descent: height * 0.2 };
|
|
8387
8423
|
}
|
|
8388
8424
|
ctx.save();
|
|
8389
8425
|
ctx.font = this.fontString(size, style);
|
|
8426
|
+
const spaced = applyTracking(ctx, style?.letterSpacing);
|
|
8390
8427
|
const m = ctx.measureText(text);
|
|
8428
|
+
const width = spaced ? m.width : m.width + trackingWidth(text, style?.letterSpacing);
|
|
8391
8429
|
ctx.restore();
|
|
8392
8430
|
const ascent = m.fontBoundingBoxAscent || m.actualBoundingBoxAscent || size * 0.8;
|
|
8393
8431
|
const descent = m.fontBoundingBoxDescent || m.actualBoundingBoxDescent || size * 0.2;
|
|
8394
|
-
return { width
|
|
8432
|
+
return { width, height: ascent + descent, ascent, descent };
|
|
8395
8433
|
}
|
|
8396
8434
|
fontString(size, style) {
|
|
8397
8435
|
const parts = [];
|
|
@@ -8446,6 +8484,7 @@ class GlyphAtlas {
|
|
|
8446
8484
|
const style = { italic: !!options.italic, bold: !!options.bold, family: options.family };
|
|
8447
8485
|
ctx.save();
|
|
8448
8486
|
ctx.font = this.fontString(options.size, style);
|
|
8487
|
+
applyTracking(ctx, options.letterSpacing);
|
|
8449
8488
|
ctx.textAlign = "left";
|
|
8450
8489
|
ctx.textBaseline = "alphabetic";
|
|
8451
8490
|
if (options.haloColor && options.haloWidth && options.haloWidth > 0) {
|
|
@@ -11535,8 +11574,9 @@ function drawSymbol(ctx, rings, styleLayer, feature, zoom, featureState, glyphAt
|
|
|
11535
11574
|
return !collision.hits({ ...box, priority });
|
|
11536
11575
|
return collision.tryInsert({ ...box, priority });
|
|
11537
11576
|
};
|
|
11538
|
-
const
|
|
11539
|
-
const
|
|
11577
|
+
const letterSpacing = (resolveLayoutExpression(layout?.["text-letter-spacing"], zoom, feature, featureState) ?? 0) * textSize;
|
|
11578
|
+
const textStyle = { italic, bold, family: font.family, letterSpacing };
|
|
11579
|
+
const drawOptions = { color: textColor, haloColor, haloWidth, size: textSize, italic, bold, family: font.family, letterSpacing };
|
|
11540
11580
|
const placeAlongLine = layout?.["symbol-placement"] === "line" || layout?.["symbol-placement"] === "line-center";
|
|
11541
11581
|
if (placeAlongLine && text && feature.type !== 1) {
|
|
11542
11582
|
drawLineLabel(ctx, rings, project, {
|