@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.
Files changed (105) hide show
  1. package/README.md +34 -2
  2. package/THIRD-PARTY-NOTICES.md +205 -0
  3. package/dist/geojson-worker.js +2160 -0
  4. package/dist/geojson-worker.js.map +6 -0
  5. package/dist/index.cjs +11388 -0
  6. package/dist/index.cjs.map +6 -0
  7. package/dist/index.js +11369 -0
  8. package/dist/index.js.map +6 -0
  9. package/dist/map-style.cjs +445 -0
  10. package/dist/map-style.cjs.map +6 -0
  11. package/dist/map-style.js +431 -0
  12. package/dist/map-style.js.map +6 -0
  13. package/dist/types/arabic-shaping.d.ts +7 -0
  14. package/dist/types/atmosphere-layer.d.ts +10 -0
  15. package/dist/types/basemap-layer.d.ts +150 -0
  16. package/dist/types/bidi.d.ts +8 -0
  17. package/dist/types/circle-layer.d.ts +49 -0
  18. package/dist/types/fill-extrusion-lighting-extension.d.ts +49 -0
  19. package/dist/types/fill-outline-extension.d.ts +22 -0
  20. package/dist/types/fill-pattern.d.ts +99 -0
  21. package/dist/types/fill-style-extensions.d.ts +100 -0
  22. package/dist/types/geojson-source.d.ts +29 -0
  23. package/dist/types/geojson-tiler.d.ts +48 -0
  24. package/dist/types/geojson-worker.d.ts +40 -0
  25. package/dist/types/globe-horizon-extension.d.ts +61 -0
  26. package/dist/types/globe-layers.d.ts +239 -0
  27. package/dist/types/globe-line-angle-extension.d.ts +37 -0
  28. package/dist/types/glyph-font-renderer.d.ts +37 -0
  29. package/dist/types/glyph-pbf.d.ts +37 -0
  30. package/dist/types/glyph-store.d.ts +103 -0
  31. package/dist/types/grid-index.d.ts +47 -0
  32. package/dist/types/hillshade-layer.d.ts +154 -0
  33. package/dist/types/index.d.ts +9 -0
  34. package/dist/types/is-globe-viewport.d.ts +2 -0
  35. package/dist/types/label-font-renderer.d.ts +18 -0
  36. package/dist/types/label-placement.d.ts +247 -0
  37. package/dist/types/label-text-layer.d.ts +231 -0
  38. package/dist/types/line-blur-extension.d.ts +73 -0
  39. package/dist/types/line-glyphs.d.ts +60 -0
  40. package/dist/types/line-placement.d.ts +93 -0
  41. package/dist/types/map-style-loader.d.ts +48 -0
  42. package/dist/types/map-style-schema.d.ts +72 -0
  43. package/dist/types/map-style.d.ts +6 -0
  44. package/dist/types/mapbox-style.d.ts +40 -0
  45. package/dist/types/mvt-label-layer.d.ts +923 -0
  46. package/dist/types/polylabel.d.ts +17 -0
  47. package/dist/types/raster-color-extension.d.ts +146 -0
  48. package/dist/types/shared-texture.d.ts +34 -0
  49. package/dist/types/sort-key.d.ts +10 -0
  50. package/dist/types/sprite.d.ts +82 -0
  51. package/dist/types/style-accessor.d.ts +45 -0
  52. package/dist/types/style-expression.d.ts +83 -0
  53. package/dist/types/style-resolver.d.ts +94 -0
  54. package/dist/types/text-font.d.ts +36 -0
  55. package/dist/types/text-halo-blur-extension.d.ts +55 -0
  56. package/dist/types/text-layout.d.ts +71 -0
  57. package/dist/types/util.d.ts +22 -0
  58. package/dist/types/zoom-paint-extension.d.ts +72 -0
  59. package/package.json +80 -3
  60. package/src/arabic-shaping.ts +366 -0
  61. package/src/atmosphere-layer.ts +19 -0
  62. package/src/basemap-layer.ts +533 -0
  63. package/src/bidi.ts +199 -0
  64. package/src/circle-layer.ts +191 -0
  65. package/src/fill-extrusion-lighting-extension.ts +206 -0
  66. package/src/fill-outline-extension.ts +70 -0
  67. package/src/fill-pattern.ts +400 -0
  68. package/src/fill-style-extensions.ts +177 -0
  69. package/src/geojson-source.ts +318 -0
  70. package/src/geojson-tiler.ts +185 -0
  71. package/src/geojson-worker.ts +98 -0
  72. package/src/globe-horizon-extension.ts +64 -0
  73. package/src/globe-layers.ts +3487 -0
  74. package/src/globe-line-angle-extension.ts +131 -0
  75. package/src/glyph-font-renderer.ts +173 -0
  76. package/src/glyph-pbf.ts +164 -0
  77. package/src/glyph-store.ts +326 -0
  78. package/src/grid-index.ts +177 -0
  79. package/src/hillshade-layer.ts +775 -0
  80. package/src/index.ts +18 -0
  81. package/src/is-globe-viewport.ts +24 -0
  82. package/src/label-font-renderer.ts +159 -0
  83. package/src/label-placement.ts +727 -0
  84. package/src/label-text-layer.ts +913 -0
  85. package/src/line-blur-extension.ts +237 -0
  86. package/src/line-glyphs.ts +364 -0
  87. package/src/line-placement.ts +446 -0
  88. package/src/map-style-loader.ts +56 -0
  89. package/src/map-style-schema.ts +83 -0
  90. package/src/map-style.ts +23 -0
  91. package/src/mapbox-style.ts +168 -0
  92. package/src/mvt-label-layer.ts +3744 -0
  93. package/src/polylabel.ts +312 -0
  94. package/src/raster-color-extension.ts +245 -0
  95. package/src/shared-texture.ts +153 -0
  96. package/src/sort-key.ts +63 -0
  97. package/src/sprite.ts +244 -0
  98. package/src/style-accessor.ts +95 -0
  99. package/src/style-expression.ts +327 -0
  100. package/src/style-resolver.ts +301 -0
  101. package/src/text-font.ts +150 -0
  102. package/src/text-halo-blur-extension.ts +115 -0
  103. package/src/text-layout.ts +441 -0
  104. package/src/util.ts +47 -0
  105. package/src/zoom-paint-extension.ts +207 -0
@@ -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
+ }