@tangram.gl/tangram-renderer 0.0.0-stage → 0.0.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.
Files changed (321) hide show
  1. package/README.md +59 -2
  2. package/dist/core.js +36923 -0
  3. package/dist/core.js.map +6 -0
  4. package/dist/index.js +32 -0
  5. package/dist/loaders-gl-worker.js +82 -0
  6. package/dist/loaders-gl-worker.js.map +6 -0
  7. package/dist/map-logic.js +2 -0
  8. package/dist/map-logic.js.map +6 -0
  9. package/dist/projected-basemaps-worker.js +3 -0
  10. package/dist/projected-basemaps-worker.js.map +6 -0
  11. package/dist/shader-modules.js +141 -0
  12. package/dist/shader-modules.js.map +6 -0
  13. package/dist/style-schema.js +126 -0
  14. package/dist/style-schema.js.map +6 -0
  15. package/dist/tangram-style.schema.json +882 -0
  16. package/dist/tangram.debug.mjs +37139 -0
  17. package/dist/tangram.debug.mjs.map +6 -0
  18. package/dist/tangram.min.mjs +4950 -0
  19. package/dist/types/builders/earcut.d.ts +15 -0
  20. package/dist/types/core.d.ts +29 -0
  21. package/dist/types/gl/constants.d.ts +2 -0
  22. package/dist/types/gl/globe_mesh.d.ts +48 -0
  23. package/dist/types/gl/glsl.d.ts +17 -0
  24. package/dist/types/gl/vertex-constants.d.ts +4 -0
  25. package/dist/types/gl/vertex-types.d.ts +34 -0
  26. package/dist/types/gl/vertex_data.d.ts +32 -0
  27. package/dist/types/gl/vertex_elements.d.ts +8 -0
  28. package/dist/types/gl/vertex_layout.d.ts +32 -0
  29. package/dist/types/glsl.d.ts +14 -0
  30. package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
  31. package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
  32. package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
  33. package/dist/types/index.d.ts +155 -0
  34. package/dist/types/lights/light-definitions.d.ts +121 -0
  35. package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
  36. package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
  37. package/dist/types/map-logic/globe-terrain.d.ts +54 -0
  38. package/dist/types/map-logic/index.d.ts +33 -0
  39. package/dist/types/map-logic/label-identity.d.ts +22 -0
  40. package/dist/types/map-logic/label-placement.d.ts +32 -0
  41. package/dist/types/map-logic/screen-bounds.d.ts +15 -0
  42. package/dist/types/map-logic/terrain-data.d.ts +55 -0
  43. package/dist/types/map-logic/terrain-error.d.ts +51 -0
  44. package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
  45. package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
  46. package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
  47. package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
  48. package/dist/types/map-logic/terrain-query.d.ts +33 -0
  49. package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
  50. package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
  51. package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
  52. package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
  53. package/dist/types/map-logic/tile-residency.d.ts +17 -0
  54. package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
  55. package/dist/types/procedures/js-yaml.d.ts +15 -0
  56. package/dist/types/procedures/mesh-projector.d.ts +107 -0
  57. package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
  58. package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
  59. package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
  60. package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
  61. package/dist/types/procedures/terrain-draping.d.ts +165 -0
  62. package/dist/types/procedures/terrain-globe.d.ts +6 -0
  63. package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
  64. package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
  65. package/dist/types/procedures/web-mercator-math.d.ts +4 -0
  66. package/dist/types/scene/globals.d.ts +11 -0
  67. package/dist/types/scene/ground_footprint.d.ts +16 -0
  68. package/dist/types/scene/host_frame.d.ts +54 -0
  69. package/dist/types/scene/projection_math.d.ts +52 -0
  70. package/dist/types/scene/scene-resource-types.d.ts +177 -0
  71. package/dist/types/scene/scene_bundle.d.ts +69 -0
  72. package/dist/types/scene/visibility_adapter.d.ts +106 -0
  73. package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
  74. package/dist/types/selection/terrain_surface.d.ts +149 -0
  75. package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
  76. package/dist/types/shader-modules/height-decode.d.ts +13 -0
  77. package/dist/types/shader-modules/hillshade.d.ts +13 -0
  78. package/dist/types/shader-modules/index.d.ts +6 -0
  79. package/dist/types/shader-modules/planar.d.ts +12 -0
  80. package/dist/types/shader-modules/sphere-map.d.ts +13 -0
  81. package/dist/types/shader-modules/triplanar.d.ts +15 -0
  82. package/dist/types/sources/decoded_tile_store.d.ts +95 -0
  83. package/dist/types/sources/tile_source_metadata.d.ts +32 -0
  84. package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
  85. package/dist/types/tile/tile_id.d.ts +37 -0
  86. package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
  87. package/dist/types/types.d.ts +293 -0
  88. package/dist/types/utils/geo.d.ts +57 -0
  89. package/dist/types/utils/hash.d.ts +1 -0
  90. package/dist/types/utils/log.d.ts +27 -0
  91. package/dist/types/utils/props.d.ts +6 -0
  92. package/dist/types/utils/subscribe.d.ts +10 -0
  93. package/dist/types/utils/thread.d.ts +6 -0
  94. package/dist/types/utils/urls.d.ts +26 -0
  95. package/dist/types/utils/utils.d.ts +26 -0
  96. package/dist/types/utils/version.d.ts +2 -0
  97. package/dist/types/utils/worker-types.d.ts +68 -0
  98. package/dist/types/utils/worker_broker.d.ts +3 -0
  99. package/package.json +103 -3
  100. package/src/builders/common.ts +41 -0
  101. package/src/builders/earcut.d.ts +15 -0
  102. package/src/builders/geometry-types.ts +60 -0
  103. package/src/builders/points.ts +115 -0
  104. package/src/builders/polygons.ts +225 -0
  105. package/src/builders/polylines.ts +682 -0
  106. package/src/builders/wireframe.ts +31 -0
  107. package/src/core.d.ts +29 -0
  108. package/src/core.ts +33 -0
  109. package/src/experimental/loaders-gl-worker.ts +19 -0
  110. package/src/experimental/projected-basemaps-worker.ts +13 -0
  111. package/src/experimental/projected-mesh-cache.ts +137 -0
  112. package/src/experimental/projected-mesh-domain.ts +110 -0
  113. package/src/experimental/projected-mesh-refinement.ts +193 -0
  114. package/src/experimental/projected-mesh.ts +399 -0
  115. package/src/experimental/projected-normal.ts +26 -0
  116. package/src/experimental/projected-symbol-mesh.ts +74 -0
  117. package/src/gl/constants.ts +18 -0
  118. package/src/gl/context.ts +103 -0
  119. package/src/gl/extensions.ts +30 -0
  120. package/src/gl/globe_mesh.ts +285 -0
  121. package/src/gl/glsl.ts +257 -0
  122. package/src/gl/mesh-types.ts +56 -0
  123. package/src/gl/render_state.ts +111 -0
  124. package/src/gl/shader_program.ts +1310 -0
  125. package/src/gl/texture.ts +814 -0
  126. package/src/gl/uniform_buffer.ts +340 -0
  127. package/src/gl/vao.ts +154 -0
  128. package/src/gl/vbo_mesh.ts +349 -0
  129. package/src/gl/vertex-constants.ts +19 -0
  130. package/src/gl/vertex-types.ts +35 -0
  131. package/src/gl/vertex_data.ts +126 -0
  132. package/src/gl/vertex_elements.ts +54 -0
  133. package/src/gl/vertex_layout.ts +241 -0
  134. package/src/glsl.d.ts +14 -0
  135. package/src/gpu/luma_device_renderer.ts +579 -0
  136. package/src/gpu/pixel_readback.ts +51 -0
  137. package/src/gpu/resource_lifecycle.ts +32 -0
  138. package/src/gpu/tangram_gpu_backend.ts +195 -0
  139. package/src/index.d.ts +155 -0
  140. package/src/index.ts +105 -0
  141. package/src/labels/collision-types.ts +94 -0
  142. package/src/labels/collision.ts +273 -0
  143. package/src/labels/collision_grid.ts +61 -0
  144. package/src/labels/intersect.ts +30 -0
  145. package/src/labels/label-types.ts +91 -0
  146. package/src/labels/label.ts +207 -0
  147. package/src/labels/label_line.ts +801 -0
  148. package/src/labels/label_point.ts +131 -0
  149. package/src/labels/main-pass-types.ts +73 -0
  150. package/src/labels/main_pass.ts +221 -0
  151. package/src/labels/point_anchor.ts +100 -0
  152. package/src/labels/point_placement.ts +150 -0
  153. package/src/labels/projected-pass.ts +259 -0
  154. package/src/labels/repeat_group.ts +72 -0
  155. package/src/lights/ambient_light.glsl +18 -0
  156. package/src/lights/directional_light.glsl +39 -0
  157. package/src/lights/geographic-lights.ts +21 -0
  158. package/src/lights/light-definitions.ts +285 -0
  159. package/src/lights/light.ts +590 -0
  160. package/src/lights/lighting-uniforms.ts +80 -0
  161. package/src/lights/lighting-wgsl.ts +116 -0
  162. package/src/lights/material.glsl +237 -0
  163. package/src/lights/material.ts +145 -0
  164. package/src/lights/native-falloff.ts +37 -0
  165. package/src/lights/point_light.glsl +96 -0
  166. package/src/lights/spot_light.glsl +111 -0
  167. package/src/map-logic/draped-terrain-bounds.ts +71 -0
  168. package/src/map-logic/globe-terrain-preparation.ts +217 -0
  169. package/src/map-logic/globe-terrain.ts +296 -0
  170. package/src/map-logic/index.ts +37 -0
  171. package/src/map-logic/label-identity.ts +36 -0
  172. package/src/map-logic/label-placement.ts +117 -0
  173. package/src/map-logic/screen-bounds.ts +34 -0
  174. package/src/map-logic/terrain-data.ts +107 -0
  175. package/src/map-logic/terrain-error.ts +134 -0
  176. package/src/map-logic/terrain-ground-topology.ts +164 -0
  177. package/src/map-logic/terrain-height-field.ts +254 -0
  178. package/src/map-logic/terrain-navigation.ts +50 -0
  179. package/src/map-logic/terrain-neighborhood.ts +43 -0
  180. package/src/map-logic/terrain-query.ts +51 -0
  181. package/src/map-logic/terrain-resource-budget.ts +124 -0
  182. package/src/map-logic/terrain-transition-topology.ts +164 -0
  183. package/src/map-logic/tile-build-queue.ts +110 -0
  184. package/src/map-logic/tile-cache-policy.ts +89 -0
  185. package/src/map-logic/tile-residency.ts +50 -0
  186. package/src/map-logic/triangle-query-index.ts +265 -0
  187. package/src/procedures/js-yaml.d.ts +15 -0
  188. package/src/procedures/mesh-projector.ts +191 -0
  189. package/src/procedures/mlt-loaders.ts +55 -0
  190. package/src/procedures/mvt-dependencies.d.ts +20 -0
  191. package/src/procedures/mvt-legacy.ts +150 -0
  192. package/src/procedures/mvt-loaders.ts +53 -0
  193. package/src/procedures/mvt-parser.ts +48 -0
  194. package/src/procedures/mvt-properties.ts +36 -0
  195. package/src/procedures/mvt-tile-provider.ts +72 -0
  196. package/src/procedures/pmtiles-loader.ts +75 -0
  197. package/src/procedures/projected-coordinate-transform.ts +79 -0
  198. package/src/procedures/projection-batch-executor.ts +140 -0
  199. package/src/procedures/scene-yaml-legacy.ts +16 -0
  200. package/src/procedures/scene-yaml-loaders.ts +10 -0
  201. package/src/procedures/terrain-draping.ts +713 -0
  202. package/src/procedures/terrain-globe.ts +32 -0
  203. package/src/procedures/terrain-styled-topology.ts +184 -0
  204. package/src/procedures/web-mercator-legacy.ts +24 -0
  205. package/src/procedures/web-mercator-math.ts +50 -0
  206. package/src/scene/camera.ts +298 -0
  207. package/src/scene/camera_base.ts +116 -0
  208. package/src/scene/classic_scene.ts +20 -0
  209. package/src/scene/external_camera.ts +101 -0
  210. package/src/scene/globals.ts +120 -0
  211. package/src/scene/ground_footprint.ts +139 -0
  212. package/src/scene/host_frame.ts +326 -0
  213. package/src/scene/projected_tile_lod.ts +125 -0
  214. package/src/scene/projection_math.ts +142 -0
  215. package/src/scene/projection_shaders.ts +183 -0
  216. package/src/scene/renderer.ts +516 -0
  217. package/src/scene/scene-resource-types.ts +174 -0
  218. package/src/scene/scene.ts +2378 -0
  219. package/src/scene/scene_bundle.ts +304 -0
  220. package/src/scene/scene_debug.ts +129 -0
  221. package/src/scene/scene_loader.ts +402 -0
  222. package/src/scene/scene_worker.ts +528 -0
  223. package/src/scene/view.ts +683 -0
  224. package/src/scene/visibility_adapter.ts +319 -0
  225. package/src/scene/worker_url.ts +15 -0
  226. package/src/selection/draped-terrain-surface.ts +377 -0
  227. package/src/selection/selection-types.ts +79 -0
  228. package/src/selection/selection.ts +542 -0
  229. package/src/selection/selection_fragment.glsl +18 -0
  230. package/src/selection/selection_globals.glsl +9 -0
  231. package/src/selection/selection_pixels.ts +59 -0
  232. package/src/selection/selection_vertex.glsl +15 -0
  233. package/src/selection/terrain_surface.ts +298 -0
  234. package/src/shader-modules/globe-horizon.ts +52 -0
  235. package/src/shader-modules/height-decode.ts +41 -0
  236. package/src/shader-modules/hillshade.ts +70 -0
  237. package/src/shader-modules/index.ts +10 -0
  238. package/src/shader-modules/planar.ts +24 -0
  239. package/src/shader-modules/sphere-map.ts +38 -0
  240. package/src/shader-modules/triplanar.ts +45 -0
  241. package/src/sources/aligned_tile_source.ts +122 -0
  242. package/src/sources/data_source.ts +655 -0
  243. package/src/sources/decoded_tile_store.ts +245 -0
  244. package/src/sources/geojson.ts +300 -0
  245. package/src/sources/mvt.ts +247 -0
  246. package/src/sources/raster.ts +341 -0
  247. package/src/sources/shared_tile_source_adapter.ts +117 -0
  248. package/src/sources/sources.ts +10 -0
  249. package/src/sources/tile_source_adapter.ts +84 -0
  250. package/src/sources/tile_source_metadata.ts +65 -0
  251. package/src/sources/tile_source_state.ts +112 -0
  252. package/src/sources/topojson.ts +90 -0
  253. package/src/styles/feature_annotations.ts +16 -0
  254. package/src/styles/filter.ts +190 -0
  255. package/src/styles/geometry-style-types.ts +209 -0
  256. package/src/styles/globe_visibility_wgsl.ts +22 -0
  257. package/src/styles/layer-types.ts +45 -0
  258. package/src/styles/layer.ts +586 -0
  259. package/src/styles/lines/dasharray.ts +49 -0
  260. package/src/styles/lines/lines.ts +707 -0
  261. package/src/styles/lines/lines_wgsl.ts +224 -0
  262. package/src/styles/points/point-runtime-types.ts +125 -0
  263. package/src/styles/points/points.ts +1079 -0
  264. package/src/styles/points/points_fragment.glsl +126 -0
  265. package/src/styles/points/points_vertex.glsl +230 -0
  266. package/src/styles/points/points_wgsl.ts +189 -0
  267. package/src/styles/polygons/polygons.ts +268 -0
  268. package/src/styles/polygons/polygons_fragment.glsl +173 -0
  269. package/src/styles/polygons/polygons_vertex.glsl +213 -0
  270. package/src/styles/polygons/polygons_wgsl.ts +127 -0
  271. package/src/styles/property-types.ts +125 -0
  272. package/src/styles/raster/raster.ts +33 -0
  273. package/src/styles/raster/raster_globals.glsl +46 -0
  274. package/src/styles/style-mixing-types.ts +101 -0
  275. package/src/styles/style-runtime-types.ts +220 -0
  276. package/src/styles/style-schema.ts +133 -0
  277. package/src/styles/style.ts +1033 -0
  278. package/src/styles/style_globals.glsl +69 -0
  279. package/src/styles/style_manager.ts +464 -0
  280. package/src/styles/style_parser.ts +620 -0
  281. package/src/styles/text/font_manager.ts +180 -0
  282. package/src/styles/text/fontfaceobserver.d.ts +10 -0
  283. package/src/styles/text/text-types.ts +220 -0
  284. package/src/styles/text/text.ts +378 -0
  285. package/src/styles/text/text_canvas.ts +773 -0
  286. package/src/styles/text/text_labels.ts +436 -0
  287. package/src/styles/text/text_segments.ts +142 -0
  288. package/src/styles/text/text_settings.ts +228 -0
  289. package/src/styles/text/text_wgsl.ts +159 -0
  290. package/src/styles/text/text_wrap.ts +194 -0
  291. package/src/tile/globe_tile_preload.ts +40 -0
  292. package/src/tile/tangram_tileset_2d.ts +108 -0
  293. package/src/tile/tile-build-types.ts +155 -0
  294. package/src/tile/tile.ts +807 -0
  295. package/src/tile/tile_id.ts +172 -0
  296. package/src/tile/tile_manager.ts +889 -0
  297. package/src/tile/tile_pyramid.ts +119 -0
  298. package/src/tile/tile_resource_cache.ts +91 -0
  299. package/src/tile/tile_traversal_adapter.ts +132 -0
  300. package/src/types.ts +332 -0
  301. package/src/utils/debounce.ts +17 -0
  302. package/src/utils/debug_settings.ts +43 -0
  303. package/src/utils/errors.ts +12 -0
  304. package/src/utils/functions.ts +95 -0
  305. package/src/utils/geo.ts +364 -0
  306. package/src/utils/hash.ts +14 -0
  307. package/src/utils/log.ts +108 -0
  308. package/src/utils/media_capture.ts +193 -0
  309. package/src/utils/merge.ts +44 -0
  310. package/src/utils/obb.ts +134 -0
  311. package/src/utils/props.ts +43 -0
  312. package/src/utils/slice.ts +14 -0
  313. package/src/utils/subscribe.ts +58 -0
  314. package/src/utils/task.ts +154 -0
  315. package/src/utils/thread.ts +26 -0
  316. package/src/utils/urls.ts +223 -0
  317. package/src/utils/utils.ts +310 -0
  318. package/src/utils/vector.ts +197 -0
  319. package/src/utils/version.ts +8 -0
  320. package/src/utils/worker-types.ts +79 -0
  321. package/src/utils/worker_broker.ts +523 -0
@@ -0,0 +1,586 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ import type {LayerConfig, LayerDrawGroup, LayerDrawGroups, LayerMatchContext, LayerPropertyMatch, LayerCombinationCache, SceneLayer, SceneLayerDefinition} from './layer-types';
7
+ import type {PropertyFunction} from './property-types';
8
+
9
+ import StyleParser from './style_parser';
10
+ import { compileFunctionStrings } from '../utils/functions';
11
+ import log from '../utils/log';
12
+ import mergeObjects from '../utils/merge';
13
+ import Geo from '../utils/geo';
14
+ import { buildFilter } from './filter';
15
+
16
+ // N.B.: 'visible' is legacy compatibility for 'enabled'
17
+ const reserved = ['filter', 'draw', 'visible', 'enabled', 'data', 'exclusive', 'priority'];
18
+
19
+ let layer_cache: LayerCombinationCache = {};
20
+ export function layerCache () {
21
+ return layer_cache;
22
+ }
23
+
24
+ function cacheKey (layers: number[]): string | number {
25
+ if (layers.length > 1) {
26
+ var k = layers[0] as string | number;
27
+ for (var i=1; i < layers.length; i++) {
28
+ k += '/' + layers[i];
29
+ }
30
+
31
+ return k;
32
+ }
33
+ return layers[0];
34
+ }
35
+
36
+ // Merge matching layer trees into a final draw group
37
+ export function mergeTrees(matchingTrees: (Array<LayerDrawGroups | undefined> | false | undefined)[], group: string): LayerDrawGroup | null {
38
+ let draws: LayerDrawGroup[], treeDepth = 0;
39
+
40
+ // Find deepest tree
41
+ for (let t=0; t < matchingTrees.length; t++) {
42
+ if ((matchingTrees[t] as Array<LayerDrawGroups | undefined>).length > treeDepth) {
43
+ treeDepth = (matchingTrees[t] as Array<LayerDrawGroups | undefined>).length;
44
+ }
45
+ }
46
+
47
+ // No layers to parse
48
+ if (treeDepth === 0) {
49
+ return null;
50
+ }
51
+
52
+ // Merged draw group object
53
+ let draw: LayerDrawGroup = {
54
+ visible: true, // visible by default
55
+ };
56
+
57
+ // Iterate trees in parallel
58
+ for (let x=0; x < treeDepth; x++) {
59
+ // Pull out the requested draw group, for each tree, at this depth (avoiding duplicates at the same level in tree)
60
+ draws = [];
61
+ matchingTrees.forEach(tree => {
62
+ if ((tree as LayerDrawGroups[])[x] && (tree as LayerDrawGroups[])[x][group]! && draws.indexOf((tree as LayerDrawGroups[])[x][group]!) === -1) {
63
+ draws.push((tree as LayerDrawGroups[])[x][group]!);
64
+ }
65
+ });
66
+ if (draws.length === 0) {
67
+ continue;
68
+ }
69
+
70
+ // Merge draw objects
71
+ mergeObjects(draw, ...draws);
72
+ }
73
+
74
+ // Short-circuit if not visible
75
+ if (draw.visible === false) {
76
+ return null;
77
+ }
78
+
79
+ return draw;
80
+ }
81
+
82
+ const blacklist = ['any', 'all', 'not', 'none'];
83
+
84
+ /** Lazy feature-filter and inherited draw state shared by tree and leaf nodes. */
85
+ class Layer {
86
+ declare static id: number;
87
+ declare id: number;
88
+ declare config_data: {source?: unknown; layer?: unknown; all_layers?: unknown} | null | undefined;
89
+ declare parent: LayerTree | null | undefined;
90
+ declare name: string;
91
+ declare full_name: string;
92
+ declare draw: LayerDrawGroups | undefined;
93
+ declare filter: unknown;
94
+ declare filter_original: unknown;
95
+ declare exclusive: boolean;
96
+ declare priority: number;
97
+ declare styles: Record<string, unknown> | undefined;
98
+ declare is_built: boolean;
99
+ declare enabled: boolean;
100
+ declare visible?: boolean;
101
+ declare calculatedDraw: Array<LayerDrawGroups | undefined>;
102
+ declare zooms?: Record<number, boolean>;
103
+ declare feature_prop_matches?: LayerPropertyMatch[];
104
+ declare context_prop_matches?: LayerPropertyMatch[];
105
+ declare children_to_parse?: SceneLayerDefinition | null;
106
+ declare is_leaf?: boolean;
107
+ declare is_tree?: boolean;
108
+ /** Children exist only on tree nodes, not leaf objects. */
109
+ declare layers?: SceneLayer[];
110
+
111
+ constructor({ layer, name, parent, draw, visible, enabled, filter, exclusive, priority, styles }: LayerConfig) {
112
+ this.id = Layer.id++;
113
+ this.config_data = layer.data == null ? layer.data : isLayerData(layer.data) ? layer.data : undefined;
114
+ this.parent = parent;
115
+ this.name = name;
116
+ this.full_name = this.parent ? (this.parent.full_name + ':' + this.name) : this.name;
117
+ this.draw = draw as LayerDrawGroups | undefined;
118
+ this.filter = filter;
119
+ this.exclusive = (exclusive === true);
120
+ this.priority = (priority != null ? priority : Number.MAX_SAFE_INTEGER);
121
+ this.styles = styles;
122
+ this.is_built = false;
123
+
124
+ enabled = (enabled === undefined) ? visible : enabled; // `visible` property is backwards compatible for `enabled`
125
+ this.enabled = (enabled !== false); // layer is enabled unless explicitly set to disabled
126
+
127
+ // Denormalize layer name to draw groups
128
+ if (this.draw) {
129
+ for (let group in this.draw) {
130
+ this.draw[group] = (this.draw[group] == null) ? {} : this.draw[group];
131
+ if (typeof this.draw[group] !== 'object') {
132
+ // Invalid draw group
133
+ let msg = `Draw group '${group}' for layer ${this.full_name} is invalid, must be an object, `;
134
+ msg += `but was set to \`${group}: ${this.draw[group]}\` instead`;
135
+ log('warn', msg); // TODO: fire external event that clients to subscribe to
136
+
137
+ delete this.draw[group];
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ build () {
144
+ log('trace', `Building layer '${this.full_name}'`);
145
+ this.buildFilter();
146
+ this.buildDraw();
147
+ this.is_built = true;
148
+ }
149
+
150
+ buildDraw() {
151
+ this.draw = compileFunctionStrings(this.draw, StyleParser.wrapFunction) as LayerDrawGroups | undefined;
152
+ this.calculatedDraw = calculateDraw(this);
153
+ }
154
+
155
+ buildFilter() {
156
+ this.filter_original = this.filter;
157
+ this.filter = compileFunctionStrings(this.filter, StyleParser.wrapFunction);
158
+
159
+ let type = typeof this.filter;
160
+ if (this.filter != null && type !== 'object' && type !== 'function') {
161
+ // Invalid filter
162
+ let msg = `Filter for layer ${this.full_name} is invalid, filter value must be an object or function, `;
163
+ msg += `but was set to \`filter: ${this.filter}\` instead`;
164
+ log('warn', msg); // TODO: fire external event that clients to subscribe to
165
+ return;
166
+ }
167
+
168
+ try {
169
+ this.buildZooms();
170
+ this.buildPropMatches();
171
+ if (this.filter != null && (typeof this.filter === 'function' || Object.keys(this.filter).length > 0)) {
172
+ this.filter = buildFilter(this.filter, FilterOptions);
173
+ }
174
+ else {
175
+ this.filter = null;
176
+ }
177
+ }
178
+ catch(e) {
179
+ // Invalid filter
180
+ let msg = `Filter for layer ${this.full_name} is invalid, \`filter: ${JSON.stringify(this.filter)}\` `;
181
+ msg += `failed with error '${(e as Error).message}', stack trace: ${(e as Error).stack}`;
182
+ log('warn', msg); // TODO: fire external event that clients to subscribe to
183
+ }
184
+ }
185
+
186
+ // Zooms often cull large swaths of the layer tree, so they get special treatment and are checked first
187
+ buildZooms() {
188
+ let zoom = this.filter && (this.filter as Record<string, unknown>).$zoom; // has an explicit zoom filter
189
+ let ztype = typeof zoom;
190
+ if (zoom != null) {
191
+ this.zooms = {};
192
+
193
+ if (ztype === 'number') {
194
+ this.zooms[zoom as number] = true;
195
+ }
196
+ else if (Array.isArray(zoom)) {
197
+ for (let z=0; z < zoom.length; z++) {
198
+ this.zooms[zoom[z]] = true;
199
+ }
200
+ }
201
+ else if (ztype === 'object' && ((zoom as {min?: number}).min != null || (zoom as {max?: number}).max != null)) {
202
+ let zmin = (zoom as {min?: number}).min || 0;
203
+ let zmax = (zoom as {max?: number}).max || Geo.max_style_zoom;
204
+ for (let z=zmin; z < zmax; z++) {
205
+ this.zooms[z] = true;
206
+ }
207
+ }
208
+
209
+ delete (this.filter as Record<string, unknown>).$zoom; // don't process zoom through usual generic filter logic
210
+ }
211
+ }
212
+
213
+ buildPropMatches() {
214
+ if (!this.filter || Array.isArray(this.filter) || typeof this.filter === 'function') {
215
+ return;
216
+ }
217
+
218
+ Object.keys(this.filter).forEach(key => {
219
+ if (blacklist.indexOf(key) === -1) {
220
+ let val = (this.filter as Record<string, unknown>)[key];
221
+ let type = typeof val;
222
+ let array = Array.isArray(val);
223
+
224
+ if (!(array || type === 'string' || type === 'number')) {
225
+ return;
226
+ }
227
+
228
+ if (key[0] === '$') {
229
+ // Context property
230
+ this.context_prop_matches = this.context_prop_matches || [];
231
+ this.context_prop_matches.push([key.substring(1), array ? val as unknown[] : [val]]);
232
+ delete (this.filter as Record<string, unknown>)[key];
233
+ }
234
+ else if (key.indexOf('.') === -1) { // exclude nested feature properties
235
+ // Single-level feature property
236
+ this.feature_prop_matches = this.feature_prop_matches || [];
237
+ this.feature_prop_matches.push([key, array ? val as unknown[] : [val]]);
238
+ delete (this.filter as Record<string, unknown>)[key];
239
+ }
240
+ }
241
+ });
242
+ }
243
+
244
+ doPropMatches (context: LayerMatchContext): boolean {
245
+ if (this.feature_prop_matches) {
246
+ for (let r=0; r < this.feature_prop_matches.length; r++) {
247
+ let match = this.feature_prop_matches[r];
248
+ let val = context.feature.properties[match[0]];
249
+ if (val == null || match[1].indexOf(val) === -1) {
250
+ return false;
251
+ }
252
+ }
253
+ }
254
+
255
+ if (this.context_prop_matches) {
256
+ for (let r=0; r < this.context_prop_matches.length; r++) {
257
+ let match = this.context_prop_matches[r];
258
+ let val = context[match[0]];
259
+ if (val == null || match[1].indexOf(val) === -1) {
260
+ return false;
261
+ }
262
+ }
263
+ }
264
+
265
+ return true;
266
+ }
267
+
268
+ doesMatch (context: LayerMatchContext): boolean {
269
+ if (!this.enabled) {
270
+ return false;
271
+ }
272
+
273
+ if (!this.is_built) {
274
+ this.build();
275
+ }
276
+
277
+ // zoom pre-filter: skip rest of filter if out of layer zoom range
278
+ if (this.zooms != null && !this.zooms[context.zoom]) {
279
+ return false;
280
+ }
281
+
282
+ // direct feature property matches
283
+ if (!this.doPropMatches(context)) {
284
+ return false;
285
+ }
286
+
287
+ // any remaining filter (more complex matches or dynamic function)
288
+ let match;
289
+ if (this.filter instanceof Function){
290
+ try {
291
+ match = (this.filter as PropertyFunction)(context);
292
+ }
293
+ catch (error) {
294
+ // Filter function error
295
+ let msg = `Filter for this ${this.full_name}: \`filter: ${this.filter_original}\` `;
296
+ msg += `failed with error '${(error as Error).message}', stack trace: ${(error as Error).stack}`;
297
+ log('error', msg, context.feature);
298
+ }
299
+ }
300
+ else {
301
+ match = this.filter == null;
302
+ }
303
+
304
+ if (match) {
305
+ if (this.children_to_parse) {
306
+ // Only tree nodes schedule non-empty children. The lazy state is
307
+ // retained on the shared base class for legacy construction.
308
+ parseLayerChildren(this as unknown as LayerTree, this.children_to_parse, this.styles);
309
+ delete this.children_to_parse;
310
+ }
311
+
312
+ return true;
313
+ }
314
+ return false;
315
+ }
316
+
317
+ }
318
+
319
+ Layer.id = 0;
320
+
321
+
322
+ /** Terminal scene node with no child traversal state. */
323
+ export class LayerLeaf extends Layer {
324
+ constructor (config: LayerConfig) {
325
+ super(config);
326
+ this.is_leaf = true;
327
+ }
328
+
329
+ }
330
+
331
+ /** Root/branch node with deferred children and cached matching draw combinations. */
332
+ export class LayerTree extends Layer {
333
+ /** Traversable children, populated only after the parent matches. */
334
+ declare layers: SceneLayer[];
335
+ constructor (config: LayerConfig) {
336
+ super(config);
337
+ this.is_tree = true;
338
+ this.layers = config.layers || [];
339
+ }
340
+
341
+ addLayer (layer: SceneLayer): void {
342
+ this.layers.push(layer);
343
+ }
344
+
345
+ buildDrawGroups (context: LayerMatchContext): LayerDrawGroups | null | undefined {
346
+ let layers: SceneLayer[] = [], layer_ids: number[] = [];
347
+ matchFeature(context, [this], layers, layer_ids);
348
+
349
+ if (layers.length > 0) {
350
+ let cache_key = cacheKey(layer_ids);
351
+
352
+ // Only evaluate each layer combination once (undefined means not yet evaluated,
353
+ // null means evaluated with no draw object)
354
+ if (layer_cache[cache_key] === undefined) {
355
+ // Find all the unique visible draw blocks for this layer tree
356
+ let draw_groups = layers.map(x => x && x.visible !== false && x.calculatedDraw);
357
+ let draw_keys: Record<string, boolean> = {};
358
+
359
+ for (let r=0; r < draw_groups.length; r++) {
360
+ let stack = draw_groups[r];
361
+ if (!stack) {
362
+ continue;
363
+ }
364
+ for (let g=0; g < stack.length; g++) {
365
+ let group = stack[g];
366
+ for (let key in group) {
367
+ draw_keys[key] = true;
368
+ }
369
+ }
370
+ }
371
+
372
+ // Calculate each draw group
373
+ for (let draw_key in draw_keys) {
374
+ layer_cache[cache_key] = layer_cache[cache_key] || {};
375
+ layer_cache[cache_key]![draw_key] = mergeTrees(draw_groups, draw_key);
376
+
377
+ // Only save the ones that weren't null
378
+ if (!layer_cache[cache_key]![draw_key]) {
379
+ delete layer_cache[cache_key]![draw_key];
380
+ }
381
+ else {
382
+ layer_cache[cache_key]![draw_key]!.key = cache_key + '/' + draw_key;
383
+ layer_cache[cache_key]![draw_key]!.layers = layers.map(x => x && x.full_name);
384
+ layer_cache[cache_key]![draw_key]!.group = draw_key;
385
+ }
386
+ }
387
+
388
+ // No layers evaluated
389
+ if (layer_cache[cache_key] && Object.keys(layer_cache[cache_key]).length === 0) {
390
+ layer_cache[cache_key] = null;
391
+ }
392
+ }
393
+ return layer_cache[cache_key];
394
+ }
395
+ }
396
+
397
+ }
398
+
399
+ export const FilterOptions = {
400
+ // Handle unit conversions on filter ranges
401
+ rangeTransform(val: unknown): unknown {
402
+ if (typeof val === 'string' && val.trim().slice(-3) === 'px2') {
403
+ return `${parseFloat(val)} * context.meters_per_pixel_sq`;
404
+ }
405
+ return val;
406
+ }
407
+ };
408
+
409
+ export function isReserved(key: string): boolean {
410
+ return reserved.indexOf(key) > -1;
411
+ }
412
+
413
+ function isEmpty(obj: object): boolean {
414
+ return Object.keys(obj).length === 0;
415
+ }
416
+
417
+ export function groupProps(obj: SceneLayerDefinition): [SceneLayerDefinition, SceneLayerDefinition] {
418
+ let reserved: SceneLayerDefinition = {}, children: SceneLayerDefinition = {};
419
+
420
+ for (let key in obj) {
421
+ if (isReserved(key)) {
422
+ reserved[key] = obj[key];
423
+ } else {
424
+ children[key] = obj[key];
425
+ }
426
+ }
427
+ return [reserved, children];
428
+ }
429
+
430
+ export function calculateDraw(layer: Layer): Array<LayerDrawGroups | undefined> {
431
+
432
+ let draw: Array<LayerDrawGroups | undefined> = [];
433
+
434
+ if (layer.parent) {
435
+ let cs = layer.parent.calculatedDraw || [];
436
+ draw.push(...cs);
437
+ }
438
+
439
+ draw.push(layer.draw);
440
+ return draw;
441
+ }
442
+
443
+ export function parseLayerNode(name: string, layer: SceneLayerDefinition | null | undefined, parent: null, styles?: Record<string, unknown>): LayerTree;
444
+ export function parseLayerNode(name: string, layer: SceneLayerDefinition | null | undefined, parent?: LayerTree | null, styles?: Record<string, unknown>): SceneLayer;
445
+ export function parseLayerNode(name: string, layer: SceneLayerDefinition | null | undefined, parent?: LayerTree | null, styles?: Record<string, unknown>): SceneLayer {
446
+
447
+ layer = (layer == null) ? {} : layer;
448
+
449
+ let properties = { name, layer, parent, styles };
450
+ let [reserved, children] = groupProps(layer);
451
+ let empty = isEmpty(children);
452
+ let Create;
453
+
454
+ if (empty && parent != null) {
455
+ Create = LayerLeaf;
456
+ } else {
457
+ Create = LayerTree;
458
+ }
459
+
460
+ let r = new Create(Object.assign(properties, reserved) as LayerConfig);
461
+
462
+ // only process child layers if this layer is enabled
463
+ if (r.enabled) {
464
+ if (parent) {
465
+ parent.addLayer(r);
466
+ }
467
+ r.children_to_parse = empty ? null : children;
468
+ }
469
+
470
+ return r;
471
+ }
472
+
473
+ function parseLayerChildren (parent: LayerTree, children: SceneLayerDefinition, styles?: Record<string, unknown>): void {
474
+ for (let key in children) {
475
+ let child = children[key];
476
+ if (typeof child === 'object' && !Array.isArray(child)) {
477
+ parseLayerNode(key, child as SceneLayerDefinition | null, parent, styles);
478
+ } else {
479
+ // Invalid layer
480
+ let msg = `Layer value must be an object: cannot create layer '${key}: ${JSON.stringify(child)}'`;
481
+ msg += `, under parent layer '${parent.full_name}'.`;
482
+
483
+ // If the parent is a style name, this may be an incorrectly nested layer
484
+ if (styles![parent.name]) {
485
+ msg += ` The parent name '${parent.name}' is also the name of a style, did you mean to create a 'draw' group`;
486
+ if (parent.parent) {
487
+ msg += ` under '${parent.parent.name}'`;
488
+ }
489
+ msg += ' instead?';
490
+ }
491
+ log('warn', msg); // TODO: fire external event that clients to subscribe to
492
+ }
493
+ }
494
+
495
+ // Sort sub-layers so they are applied deterministically when multiple layers modify the same properties
496
+ // Sort order is: exclusive layers first, then by explicit layer priority, then by layer name
497
+ parent.layers.sort(((a: SceneLayer, b: SceneLayer) => {
498
+ // Exclusive layers come first
499
+ // If an exclusive layer matches, no further sibling layers are matched
500
+ if (a.exclusive < b.exclusive) return 1;
501
+ else if (a.exclusive > b.exclusive) return -1;
502
+
503
+ // When sub-sorting exclusive layers, sort the higher priority layers first, since only one exlcusive layer
504
+ // can match and the first one that matches should be the highest priority.
505
+ // When sub-sorting non-exclusive layers, sort the lower priority layers first, since multiple layers may
506
+ // match, and when they are merged in order, the later layers will overwrite the earlier ones -- so we want
507
+ // the higher priority ones to match last so that they "win".
508
+ const direction = (a.exclusive ? 1 : -1);
509
+
510
+ // Sub-sort by explicit priority
511
+ if (a.priority > b.priority) return direction;
512
+ else if (a.priority < b.priority) return -direction;
513
+
514
+ // Sub-sort by layer name as last resort
515
+ if (a.full_name < b.full_name) return direction;
516
+ else if (a.full_name > b.full_name) return -direction;
517
+ }) as (a: SceneLayer, b: SceneLayer) => number);
518
+ }
519
+
520
+
521
+ /** Source selectors must be objects; malformed scalar metadata cannot select a source. */
522
+ function isLayerData(value: unknown): value is {source?: unknown; layer?: unknown; all_layers?: unknown} {
523
+ return value !== null && typeof value === 'object';
524
+ }
525
+
526
+ export function parseLayers (layers: Record<string, SceneLayerDefinition | null | undefined>, styles?: Record<string, unknown>): Record<string, LayerTree> {
527
+ layer_cache = {}; // clear layer cache
528
+ let layer_trees: Record<string, LayerTree> = {};
529
+
530
+ for (let key in layers) {
531
+ let layer = layers[key];
532
+ if (layer) {
533
+ layer_trees[key] = parseLayerNode(key, layer, null, styles);
534
+ }
535
+ }
536
+
537
+ return layer_trees;
538
+ }
539
+
540
+ export function matchFeature(context: LayerMatchContext, layers: SceneLayer[], collected_layers: SceneLayer[], collected_layers_ids: number[]): boolean | undefined {
541
+ let matched = false;
542
+ let child_matched: boolean | undefined = false;
543
+
544
+ if (layers.length === 0) {
545
+ return;
546
+ }
547
+
548
+ for (let r=0; r < layers.length; r++) {
549
+ let current = layers[r];
550
+
551
+ if (current.is_leaf) {
552
+ if (current.doesMatch(context)) {
553
+ matched = true;
554
+ collected_layers.push(current);
555
+ collected_layers_ids.push(current.id);
556
+
557
+ if (current.exclusive) {
558
+ break; // only one exclusive layer can match, stop matching further sibling layers
559
+ }
560
+ }
561
+
562
+ } else if (current.is_tree) {
563
+ if (current.doesMatch(context)) {
564
+ matched = true;
565
+
566
+ child_matched = matchFeature(
567
+ context,
568
+ current.layers!,
569
+ collected_layers,
570
+ collected_layers_ids
571
+ );
572
+
573
+ if (!child_matched) {
574
+ collected_layers.push(current);
575
+ collected_layers_ids.push(current.id);
576
+ }
577
+
578
+ if (current.exclusive) {
579
+ break; // only one exclusive layer can match, stop matching further sibling layers
580
+ }
581
+ }
582
+ }
583
+ }
584
+
585
+ return matched;
586
+ }
@@ -0,0 +1,49 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ // Renders an array specifying a line pattern of alternating dashes and spaces,
7
+ // similar to an SVG `dasharray` or Canvas setLineDash(), into a byte array of RGBA pixels
8
+ // Returns:
9
+ // {
10
+ // pixel: rendered image in Uint8Array buffer
11
+ // length: pixel length of rendered dash pattern (sum of all dashes and spaces)
12
+ // }
13
+ //
14
+ // https://www.w3.org/TR/SVG/painting.html#StrokeDasharrayProperty
15
+ // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
16
+ // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
17
+
18
+ const default_dash_color = [255, 255, 255, 255];
19
+ const default_background_color = [0, 0, 0, 0];
20
+
21
+ type DashArrayOptions = {dash_color?: number[]; background_color?: number[]; scale?: number};
22
+
23
+ export default function renderDashArray (pattern: number[], options: DashArrayOptions = {}): {pixels: Uint8Array; length: number} {
24
+ const dash_pixel = options.dash_color || default_dash_color;
25
+ const background_color = options.background_color || default_background_color;
26
+ const dashes = pattern;
27
+ const scale = options.scale || 1;
28
+
29
+ // If pattern is odd, repeat it to make it even (see SVG spec)
30
+ if (dashes.length % 2 === 1) {
31
+ Array.prototype.push.apply(dashes, dashes);
32
+ }
33
+
34
+ let dash = true;
35
+ let pixels: any = [];
36
+ for (let i=0; i < dashes.length; i++) {
37
+ let segment = Math.floor(dashes[i] * scale);
38
+ for (let s=0; s < segment; s++) {
39
+ Array.prototype.push.apply(pixels, dash ? dash_pixel : background_color);
40
+ }
41
+ dash = !dash; // alternate between dashes and spaces
42
+ }
43
+
44
+ pixels.reverse(); // flip Y (GL textures are upside down)
45
+ pixels = new Uint8Array(pixels); // convert to typed array
46
+ const length = pixels.length / 4; // one RGBA byte sequences to one pixel
47
+
48
+ return { pixels, length };
49
+ }