@tangram.gl/basemap-layers 0.0.0-stage → 0.0.1
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 +34 -2
- package/THIRD-PARTY-NOTICES.md +205 -0
- package/dist/geojson-worker.js +2160 -0
- package/dist/geojson-worker.js.map +6 -0
- package/dist/index.cjs +11388 -0
- package/dist/index.cjs.map +6 -0
- package/dist/index.js +11369 -0
- package/dist/index.js.map +6 -0
- package/dist/map-style.cjs +445 -0
- package/dist/map-style.cjs.map +6 -0
- package/dist/map-style.js +431 -0
- package/dist/map-style.js.map +6 -0
- package/dist/types/arabic-shaping.d.ts +7 -0
- package/dist/types/atmosphere-layer.d.ts +10 -0
- package/dist/types/basemap-layer.d.ts +150 -0
- package/dist/types/bidi.d.ts +8 -0
- package/dist/types/circle-layer.d.ts +49 -0
- package/dist/types/fill-extrusion-lighting-extension.d.ts +49 -0
- package/dist/types/fill-outline-extension.d.ts +22 -0
- package/dist/types/fill-pattern.d.ts +99 -0
- package/dist/types/fill-style-extensions.d.ts +100 -0
- package/dist/types/geojson-source.d.ts +29 -0
- package/dist/types/geojson-tiler.d.ts +48 -0
- package/dist/types/geojson-worker.d.ts +40 -0
- package/dist/types/globe-horizon-extension.d.ts +61 -0
- package/dist/types/globe-layers.d.ts +239 -0
- package/dist/types/globe-line-angle-extension.d.ts +37 -0
- package/dist/types/glyph-font-renderer.d.ts +37 -0
- package/dist/types/glyph-pbf.d.ts +37 -0
- package/dist/types/glyph-store.d.ts +103 -0
- package/dist/types/grid-index.d.ts +47 -0
- package/dist/types/hillshade-layer.d.ts +154 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/is-globe-viewport.d.ts +2 -0
- package/dist/types/label-font-renderer.d.ts +18 -0
- package/dist/types/label-placement.d.ts +247 -0
- package/dist/types/label-text-layer.d.ts +231 -0
- package/dist/types/line-blur-extension.d.ts +73 -0
- package/dist/types/line-glyphs.d.ts +60 -0
- package/dist/types/line-placement.d.ts +93 -0
- package/dist/types/map-style-loader.d.ts +48 -0
- package/dist/types/map-style-schema.d.ts +72 -0
- package/dist/types/map-style.d.ts +6 -0
- package/dist/types/mapbox-style.d.ts +40 -0
- package/dist/types/mvt-label-layer.d.ts +923 -0
- package/dist/types/polylabel.d.ts +17 -0
- package/dist/types/raster-color-extension.d.ts +146 -0
- package/dist/types/shared-texture.d.ts +34 -0
- package/dist/types/sort-key.d.ts +10 -0
- package/dist/types/sprite.d.ts +82 -0
- package/dist/types/style-accessor.d.ts +45 -0
- package/dist/types/style-expression.d.ts +83 -0
- package/dist/types/style-resolver.d.ts +94 -0
- package/dist/types/text-font.d.ts +36 -0
- package/dist/types/text-halo-blur-extension.d.ts +55 -0
- package/dist/types/text-layout.d.ts +71 -0
- package/dist/types/util.d.ts +22 -0
- package/dist/types/zoom-paint-extension.d.ts +72 -0
- package/package.json +80 -3
- package/src/arabic-shaping.ts +366 -0
- package/src/atmosphere-layer.ts +19 -0
- package/src/basemap-layer.ts +533 -0
- package/src/bidi.ts +199 -0
- package/src/circle-layer.ts +191 -0
- package/src/fill-extrusion-lighting-extension.ts +206 -0
- package/src/fill-outline-extension.ts +70 -0
- package/src/fill-pattern.ts +400 -0
- package/src/fill-style-extensions.ts +177 -0
- package/src/geojson-source.ts +318 -0
- package/src/geojson-tiler.ts +185 -0
- package/src/geojson-worker.ts +98 -0
- package/src/globe-horizon-extension.ts +64 -0
- package/src/globe-layers.ts +3487 -0
- package/src/globe-line-angle-extension.ts +131 -0
- package/src/glyph-font-renderer.ts +173 -0
- package/src/glyph-pbf.ts +164 -0
- package/src/glyph-store.ts +326 -0
- package/src/grid-index.ts +177 -0
- package/src/hillshade-layer.ts +775 -0
- package/src/index.ts +18 -0
- package/src/is-globe-viewport.ts +24 -0
- package/src/label-font-renderer.ts +159 -0
- package/src/label-placement.ts +727 -0
- package/src/label-text-layer.ts +913 -0
- package/src/line-blur-extension.ts +237 -0
- package/src/line-glyphs.ts +364 -0
- package/src/line-placement.ts +446 -0
- package/src/map-style-loader.ts +56 -0
- package/src/map-style-schema.ts +83 -0
- package/src/map-style.ts +23 -0
- package/src/mapbox-style.ts +168 -0
- package/src/mvt-label-layer.ts +3744 -0
- package/src/polylabel.ts +312 -0
- package/src/raster-color-extension.ts +245 -0
- package/src/shared-texture.ts +153 -0
- package/src/sort-key.ts +63 -0
- package/src/sprite.ts +244 -0
- package/src/style-accessor.ts +95 -0
- package/src/style-expression.ts +327 -0
- package/src/style-resolver.ts +301 -0
- package/src/text-font.ts +150 -0
- package/src/text-halo-blur-extension.ts +115 -0
- package/src/text-layout.ts +441 -0
- package/src/util.ts +47 -0
- package/src/zoom-paint-extension.ts +207 -0
package/src/text-font.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// tangram-layers
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A label font as CSS: a family list ending with a generic family, a numeric weight and a style.
|
|
7
|
+
*/
|
|
8
|
+
export type LabelFont = {
|
|
9
|
+
/** CSS `font-family` list, e.g. `"Noto Sans", sans-serif`. */
|
|
10
|
+
fontFamily: string;
|
|
11
|
+
/** CSS numeric `font-weight`, 100-900. */
|
|
12
|
+
fontWeight: number;
|
|
13
|
+
/** CSS `font-style`. */
|
|
14
|
+
fontStyle: 'normal' | 'italic';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Overrides the label font derived from `text-font`. A string is the CSS family list for every
|
|
19
|
+
* label; the weight and style still come from `text-font`. A function receives the evaluated
|
|
20
|
+
* `text-font` names and returns a CSS family list, or any of the {@link LabelFont} fields; fields
|
|
21
|
+
* it leaves out, or a `null` result, keep the mapped values.
|
|
22
|
+
*/
|
|
23
|
+
export type LabelFontFamily =
|
|
24
|
+
| string
|
|
25
|
+
| ((fontStack: string[]) => string | Partial<LabelFont> | null | undefined);
|
|
26
|
+
|
|
27
|
+
/** The style specification's default `text-font`. */
|
|
28
|
+
export const DEFAULT_TEXT_FONT = ['Open Sans Regular', 'Arial Unicode MS Regular'];
|
|
29
|
+
|
|
30
|
+
const FONT_WEIGHTS = new Map<string, number>([
|
|
31
|
+
['thin', 100],
|
|
32
|
+
['hairline', 100],
|
|
33
|
+
['extralight', 200],
|
|
34
|
+
['ultralight', 200],
|
|
35
|
+
['light', 300],
|
|
36
|
+
['regular', 400],
|
|
37
|
+
['normal', 400],
|
|
38
|
+
['book', 400],
|
|
39
|
+
['roman', 400],
|
|
40
|
+
['medium', 500],
|
|
41
|
+
['semibold', 600],
|
|
42
|
+
['demibold', 600],
|
|
43
|
+
['bold', 700],
|
|
44
|
+
['extrabold', 800],
|
|
45
|
+
['ultrabold', 800],
|
|
46
|
+
['black', 900],
|
|
47
|
+
['heavy', 900]
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
/** First words of two-word weights such as `Semi Bold` and `Extra Light`. */
|
|
51
|
+
const WEIGHT_PREFIXES = new Set(['semi', 'demi', 'extra', 'ultra']);
|
|
52
|
+
|
|
53
|
+
const FONT_STYLES = ['italic', 'oblique'];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Splits a font name such as `Open Sans Semibold Italic` into its family and its trailing weight
|
|
57
|
+
* and style words. Only trailing words are read, and a name is never reduced to nothing.
|
|
58
|
+
*/
|
|
59
|
+
function parseFontName(name: string): {family: string; fontWeight: number; italic: boolean} {
|
|
60
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
61
|
+
let fontWeight = 400;
|
|
62
|
+
let italic = false;
|
|
63
|
+
|
|
64
|
+
const last = words.at(-1)?.toLowerCase() || '';
|
|
65
|
+
const style = FONT_STYLES.find(suffix => last.endsWith(suffix));
|
|
66
|
+
const styleWeight = style ? last.slice(0, -style.length) : '';
|
|
67
|
+
if (style && words.length > 1 && (!styleWeight || FONT_WEIGHTS.has(styleWeight))) {
|
|
68
|
+
italic = true;
|
|
69
|
+
words.pop();
|
|
70
|
+
if (styleWeight) {
|
|
71
|
+
// A combined word such as `BoldItalic`.
|
|
72
|
+
return {family: words.join(' '), fontWeight: FONT_WEIGHTS.get(styleWeight)!, italic};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const weightWord = words.at(-1)?.toLowerCase() || '';
|
|
77
|
+
if (words.length > 1 && FONT_WEIGHTS.has(weightWord)) {
|
|
78
|
+
fontWeight = FONT_WEIGHTS.get(weightWord)!;
|
|
79
|
+
words.pop();
|
|
80
|
+
const prefix = words.at(-1)?.toLowerCase() || '';
|
|
81
|
+
if (words.length > 1 && WEIGHT_PREFIXES.has(prefix) && FONT_WEIGHTS.has(prefix + weightWord)) {
|
|
82
|
+
fontWeight = FONT_WEIGHTS.get(prefix + weightWord)!;
|
|
83
|
+
words.pop();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {family: words.join(' '), fontWeight, italic};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The generic CSS family a font name implies: serif or monospace when it says so. */
|
|
91
|
+
function getGenericFamily(family: string): string {
|
|
92
|
+
const words = family.toLowerCase().split(' ');
|
|
93
|
+
if (words.includes('mono') || words.includes('monospace')) {
|
|
94
|
+
return 'monospace';
|
|
95
|
+
}
|
|
96
|
+
if (words.includes('serif') && !words.includes('sans')) {
|
|
97
|
+
return 'serif';
|
|
98
|
+
}
|
|
99
|
+
return 'sans-serif';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function quoteFamily(family: string): string {
|
|
103
|
+
return `"${family.replace(/["\\]/g, '\\$&')}"`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Maps a style's `text-font` stack to a CSS font. Each name's trailing weight and style words
|
|
108
|
+
* (`Regular`, `Bold`, `Semibold Italic`, ...) are stripped to give its family; the families are
|
|
109
|
+
* listed in stack order and end with a generic family, so labels still draw when none of the
|
|
110
|
+
* fonts is installed. `TextLayer` takes one weight per layer, so the weight and style come from
|
|
111
|
+
* the first font of the stack.
|
|
112
|
+
*/
|
|
113
|
+
export function getLabelFont(fontStack: string[]): LabelFont {
|
|
114
|
+
const fonts = fontStack.map(parseFontName);
|
|
115
|
+
const families = [...new Set(fonts.map(font => font.family))];
|
|
116
|
+
const generic = families.length ? getGenericFamily(families[0]) : 'sans-serif';
|
|
117
|
+
return {
|
|
118
|
+
fontFamily: [...families.map(quoteFamily), generic].join(', '),
|
|
119
|
+
fontWeight: fonts[0]?.fontWeight ?? 400,
|
|
120
|
+
fontStyle: fonts[0]?.italic ? 'italic' : 'normal'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** {@link getLabelFont}, with the caller's {@link LabelFontFamily} override applied. */
|
|
125
|
+
export function resolveLabelFont(
|
|
126
|
+
fontStack: string[],
|
|
127
|
+
fontFamily?: LabelFontFamily | null
|
|
128
|
+
): LabelFont {
|
|
129
|
+
const font = getLabelFont(fontStack);
|
|
130
|
+
const override = typeof fontFamily === 'function' ? fontFamily(fontStack) : fontFamily;
|
|
131
|
+
if (typeof override === 'string') {
|
|
132
|
+
return {...font, fontFamily: override};
|
|
133
|
+
}
|
|
134
|
+
if (!override) {
|
|
135
|
+
return font;
|
|
136
|
+
}
|
|
137
|
+
const fields = Object.entries(override).filter(
|
|
138
|
+
([, value]) => value !== undefined && value !== null
|
|
139
|
+
);
|
|
140
|
+
return {...font, ...Object.fromEntries(fields)};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* `TextLayer`'s `fontWeight` prop for a font. `TextLayer` has no `fontStyle` prop and writes
|
|
145
|
+
* `fontWeight` in front of the size in the canvas font string, so an italic font puts its style
|
|
146
|
+
* in front of the weight there (`italic 400`), which is valid CSS font shorthand.
|
|
147
|
+
*/
|
|
148
|
+
export function getTextLayerFontWeight(font: LabelFont): number | string {
|
|
149
|
+
return font.fontStyle === 'italic' ? `italic ${font.fontWeight}` : font.fontWeight;
|
|
150
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// tangram-layers
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
// deck.gl-community
|
|
6
|
+
// SPDX-License-Identifier: MIT
|
|
7
|
+
// Copyright (c) vis.gl contributors
|
|
8
|
+
|
|
9
|
+
import {LayerExtension} from '@deck.gl/core';
|
|
10
|
+
import type {Layer} from '@deck.gl/core';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* MapLibre GL JS's symbol shader widens the halo edge by `text-halo-blur * 1.19` pixels on each
|
|
14
|
+
* side of the halo edge, on top of the edge's own antialiasing.
|
|
15
|
+
*/
|
|
16
|
+
const MAPLIBRE_HALO_BLUR_SCALE = 1.19;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Converts a `text-halo-blur`, in pixels, to the signed distance by which `TextLayer`'s halo edge
|
|
20
|
+
* fades on each side, beyond the edge's own smoothing, for text of `textSize` pixels drawn from a
|
|
21
|
+
* font atlas of `fontSize` pixels whose distance field reaches `radius` atlas pixels. As in
|
|
22
|
+
* MapLibre, the fade is `1.19 * blur` screen pixels on each side of the halo edge; an atlas pixel
|
|
23
|
+
* is `textSize / fontSize` screen pixels and `1 / radius` of the distance field.
|
|
24
|
+
*/
|
|
25
|
+
export function getHaloBlurGamma(
|
|
26
|
+
haloBlur: number,
|
|
27
|
+
textSize: number,
|
|
28
|
+
{fontSize, radius}: {fontSize: number; radius: number}
|
|
29
|
+
): number {
|
|
30
|
+
if (!(haloBlur > 0) || !(textSize > 0)) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
const atlasPixels = (MAPLIBRE_HALO_BLUR_SCALE * haloBlur * fontSize) / textSize;
|
|
34
|
+
// Rounded so that labels whose blurs differ imperceptibly share one text sublayer.
|
|
35
|
+
return Math.round((atlasPixels / radius) * 1000) / 1000;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const textHaloBlurModule = {
|
|
39
|
+
name: 'textHaloBlur',
|
|
40
|
+
fs: /* glsl */ `\
|
|
41
|
+
layout(std140) uniform textHaloBlurUniforms {
|
|
42
|
+
float gamma;
|
|
43
|
+
float capped;
|
|
44
|
+
} textHaloBlur;
|
|
45
|
+
`,
|
|
46
|
+
uniformTypes: {gamma: 'f32', capped: 'f32'}
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `LabelCharactersLayer` (the characters of a `LabelTextLayer`) sets the alpha of a halo with this
|
|
51
|
+
* statement, from the halo edge's own antialiasing, `labelHaloGamma`. It runs in the halo pass
|
|
52
|
+
* only: the pass that draws the glyphs on top draws no outline. `haloGamma`, the width the halo
|
|
53
|
+
* fades over, is also the width of the ring's inner edge, which the layer draws next.
|
|
54
|
+
*/
|
|
55
|
+
const OUTLINE_ALPHA_STATEMENT = 'alpha = inBorder;';
|
|
56
|
+
|
|
57
|
+
const injection = {
|
|
58
|
+
[OUTLINE_ALPHA_STATEMENT]: /* glsl */ `
|
|
59
|
+
if (textHaloBlur.gamma > 0.0) {
|
|
60
|
+
// Fades the halo over the wider edge. The blur widens by 1 / cos(pitch) on a pitched map,
|
|
61
|
+
// as the edge's own antialiasing does: MapLibre divides both by its u_gamma_scale. With
|
|
62
|
+
// 'capped', capped so that the halo is transparent where the distance field ends, at the
|
|
63
|
+
// edge of the glyph's quad: the font atlas stores a few 1/255 steps of distance there.
|
|
64
|
+
// Uncapped, as MapLibre draws its glyphs, the faintest part of a wide fade is cut there.
|
|
65
|
+
haloGamma = labelHaloGamma + textHaloBlur.gamma / labelEdge.foreshortening;
|
|
66
|
+
if (textHaloBlur.capped > 0.5) {
|
|
67
|
+
haloGamma = max(labelHaloGamma, min(haloGamma, sdf.outlineBuffer - 4.0 / 255.0));
|
|
68
|
+
}
|
|
69
|
+
alpha = smoothstep(sdf.outlineBuffer - haloGamma, sdf.outlineBuffer + haloGamma, distance);
|
|
70
|
+
}
|
|
71
|
+
`
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type TextHaloBlurExtensionProps = {
|
|
75
|
+
/** Distance by which the halo edge fades on each side, see {@link getHaloBlurGamma}. */
|
|
76
|
+
textHaloBlurGamma?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Whether the fade ends where the distance field does (default), or reaches past it and is cut
|
|
79
|
+
* at the glyph's quad, as MapLibre GL JS draws its glyphs.
|
|
80
|
+
*/
|
|
81
|
+
textHaloBlurCapped?: boolean;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Blurs the halo of a `LabelTextLayer`, as MapLibre GL JS draws `text-halo-blur`: the halo edge
|
|
86
|
+
* fades over `textHaloBlurGamma` more distance on each side, beyond its own antialiasing of 0.84
|
|
87
|
+
* device pixels (see `LabelCharactersLayer`), as MapLibre's. Labels that lie on a pitched map fade
|
|
88
|
+
* over 1 / cos(pitch) times that distance, blur and antialiasing alike, as MapLibre's (see
|
|
89
|
+
* `getLabelForeshortening`). The glyphs stay as sharp as without the extension. WebGL only; on
|
|
90
|
+
* WebGPU the halo draws without blur.
|
|
91
|
+
*/
|
|
92
|
+
export class TextHaloBlurExtension extends LayerExtension {
|
|
93
|
+
static extensionName = 'TextHaloBlurExtension';
|
|
94
|
+
static defaultProps = {textHaloBlurGamma: 0, textHaloBlurCapped: true};
|
|
95
|
+
|
|
96
|
+
getShaders(this: Layer<TextHaloBlurExtensionProps>) {
|
|
97
|
+
if (this.context.device.type === 'webgpu') {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
// The statement is only in the characters' shader, so the text background is unchanged.
|
|
101
|
+
return {modules: [textHaloBlurModule], inject: injection};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
draw(this: Layer<TextHaloBlurExtensionProps>) {
|
|
105
|
+
if (this.context.device.type === 'webgpu') {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.setShaderModuleProps({
|
|
109
|
+
textHaloBlur: {
|
|
110
|
+
gamma: this.props.textHaloBlurGamma ?? 0,
|
|
111
|
+
capped: this.props.textHaloBlurCapped === false ? 0 : 1
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|