@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,245 @@
1
+ // tangram-layers
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /** One consumer's interest in a decoded tile; releasing it cannot cancel another consumer. */
6
+ export interface DecodedTileLease<ValueT> {
7
+ /** Independent completion, rejected promptly when this lease is released before completion. */
8
+ readonly promise: Promise<ValueT>;
9
+ /** Whether this consumer still owns a lease, including after synchronous source invalidation. */
10
+ isActive(): boolean;
11
+ /** Idempotently release this consumer's residency and request ownership. */
12
+ release(): void;
13
+ }
14
+
15
+ /** Source revision and unwrapped normalized data identity, never a mesh/style key. */
16
+ export interface DecodedTileAcquisition<ValueT> {
17
+ /** Opaque source-instance revision, owned by the worker adapter. */
18
+ readonly source: object;
19
+ /** Normalized data coordinate key, preserving world-copy distinctions. */
20
+ readonly key: string;
21
+ /** Original acquisition/decode procedure; invoked once for compatible concurrent leases. */
22
+ load(signal: AbortSignal): Promise<ValueT>;
23
+ }
24
+
25
+ /** Detached diagnostics; missing allocation estimates never masquerade as zero decoded bytes. */
26
+ export interface DecodedTileStatistics {
27
+ /** Pending unique acquisitions, including queued work. */
28
+ loadingTiles: number;
29
+ /** Unique acquisitions waiting for a source-procedure slot. */
30
+ queuedTiles: number;
31
+ /** Running source procedures, including cancelled procedures that have not settled. */
32
+ activeAcquisitions: number;
33
+ /** Configured source-procedure limit; undefined means unlimited. */
34
+ maxConcurrentLoads: number | undefined;
35
+ /** Ready records protected by live leases; there is no unreferenced warm cache. */
36
+ readyTiles: number;
37
+ /** Live consumer leases across pending and ready records. */
38
+ consumers: number;
39
+ /** Actual acquisition attempts since store creation. */
40
+ acquisitions: number;
41
+ /** Acquisitions served by an existing pending or ready record. */
42
+ sharedAcquisitions: number;
43
+ /** Requests cancelled when their final lease or source revision was released. */
44
+ cancelledAcquisitions: number;
45
+ /** Rejected acquisition attempts, excluding invalidated late completions. */
46
+ failedAcquisitions: number;
47
+ /** Ready payload bytes, undefined if any live ready record has unknown size. */
48
+ decodedBytes: number | undefined;
49
+ }
50
+
51
+ /** Request capacity is independent of styled mesh-build scheduling and residency. */
52
+ export interface DecodedTileStoreOptions {
53
+ /** Positive safe integer; omission preserves unlimited acquisition. */
54
+ maxConcurrentLoads?: number;
55
+ }
56
+
57
+ /** Validate an optional load budget before creating resources or worker state. */
58
+ export function validateConcurrentTileLoads(value: unknown): number | undefined {
59
+ if (value === undefined) return undefined;
60
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {
61
+ throw new Error('maxConcurrentTileLoadsPerWorker must be a positive safe integer');
62
+ }
63
+ return value;
64
+ }
65
+
66
+ /** Consumer settlement hooks do not contain renderer or worker tile objects. */
67
+ interface LeaseSettlement<ValueT> {
68
+ /** Resolve only this lease. */
69
+ resolve(value: ValueT): void;
70
+ /** Reject only this lease. */
71
+ reject(error: unknown): void;
72
+ }
73
+
74
+ /** One source/data acquisition, independent of styled meshes and build generations. */
75
+ interface DecodedRecord<ValueT> {
76
+ /** Cancellation belongs to the unique acquisition, not its first consumer. */
77
+ readonly controller: AbortController;
78
+ /** Live consumers, including ready records retained for overzoom/rebuild reuse. */
79
+ readonly consumers: Set<LeaseSettlement<ValueT>>;
80
+ /** Successful content publication, absent while acquisition is pending. */
81
+ result?: {value: ValueT};
82
+ }
83
+
84
+ /** Portable cancellation error for leases, source invalidation, and stale publication. */
85
+ export function createTileLeaseAbortError(): Error {
86
+ const error = new Error('Decoded tile lease released');
87
+ error.name = 'AbortError';
88
+ return error;
89
+ }
90
+
91
+ /** Worker-local shared acquisition with source-instance revisions and zero warm retention. */
92
+ export default class DecodedTileStore<ValueT> {
93
+ /** Source revisions stay retained only while they have live records. */
94
+ private readonly sources = new Map<object, Map<string, DecodedRecord<ValueT>>>();
95
+ /** Optional decoded allocation estimator; encoded network bytes are not a substitute. */
96
+ private readonly getByteLength: (value: ValueT) => number | undefined;
97
+ /** FIFO unique-content queue; duplicate leases never consume another slot. */
98
+ private readonly queued = new Map<DecodedRecord<ValueT>, DecodedTileAcquisition<ValueT>>();
99
+ /** Fixed worker-local source-procedure limit, unrelated to GPU mesh ownership. */
100
+ private readonly maxConcurrentLoads: number | undefined;
101
+ /** Settling an aborted but non-cooperative procedure still releases exactly one slot. */
102
+ private activeAcquisitions = 0;
103
+ /** Batch synchronous leases and cancellation before starting their providers. */
104
+ private scheduled = false;
105
+ /** Actual unique acquisition attempts. */
106
+ private acquisitions = 0;
107
+ /** Reused pending/ready acquisitions. */
108
+ private sharedAcquisitions = 0;
109
+ /** Underlying requests cancelled at final release or invalidation. */
110
+ private cancelledAcquisitions = 0;
111
+ /** Underlying acquisition failures. */
112
+ private failedAcquisitions = 0;
113
+
114
+ /** Create an empty store without fetch, decode, traversal, or GPU dependencies. */
115
+ constructor(getByteLength: (value: ValueT) => number | undefined = () => undefined, options: DecodedTileStoreOptions = {}) {
116
+ this.getByteLength = getByteLength;
117
+ this.maxConcurrentLoads = validateConcurrentTileLoads(options.maxConcurrentLoads);
118
+ }
119
+
120
+ /** Acquire one consumer lease, sharing only the exact source revision and data key. */
121
+ acquireTile(request: DecodedTileAcquisition<ValueT>): DecodedTileLease<ValueT> {
122
+ let records = this.sources.get(request.source);
123
+ if (!records) { records = new Map(); this.sources.set(request.source, records); }
124
+ let record = records.get(request.key);
125
+ const created = !record;
126
+ if (!record) {
127
+ record = {controller: new AbortController(), consumers: new Set()};
128
+ records.set(request.key, record);
129
+ } else this.sharedAcquisitions++;
130
+ const current = record;
131
+ let resolveLease: (value: ValueT) => void = () => {};
132
+ let rejectLease: (error: unknown) => void = () => {};
133
+ const promise = new Promise<ValueT>((resolve, reject) => {
134
+ resolveLease = resolve;
135
+ rejectLease = reject;
136
+ });
137
+ const consumer = {resolve: resolveLease, reject: rejectLease};
138
+ current.consumers.add(consumer);
139
+ if (current.result) consumer.resolve(current.result.value);
140
+ if (created) {
141
+ this.queued.set(current, request);
142
+ this.scheduleAcquisitions();
143
+ }
144
+ return {promise, isActive: () => current.consumers.has(consumer), release: () => {
145
+ if (!current.consumers.delete(consumer)) return;
146
+ if (!current.result) consumer.reject(createTileLeaseAbortError());
147
+ if (current.consumers.size === 0) {
148
+ this.forgetRecord(request.source, request.key, current);
149
+ this.cancelRecord(current);
150
+ }
151
+ }};
152
+ }
153
+
154
+ /** Release one obsolete source revision without touching a successor source instance. */
155
+ invalidateSource(source: object): void {
156
+ const records = this.sources.get(source);
157
+ if (!records) return;
158
+ this.sources.delete(source);
159
+ for (const record of records.values()) {
160
+ for (const lease of record.consumers) lease.reject(createTileLeaseAbortError());
161
+ record.consumers.clear();
162
+ this.cancelRecord(record);
163
+ }
164
+ }
165
+
166
+ /** Return unique content and consumer counts without retaining or exposing internal records. */
167
+ getStatistics(): DecodedTileStatistics {
168
+ let loadingTiles = 0, readyTiles = 0, consumers = 0, decodedBytes: number | undefined = 0;
169
+ for (const records of this.sources.values()) for (const record of records.values()) {
170
+ consumers += record.consumers.size;
171
+ if (!record.result) { loadingTiles++; continue; }
172
+ readyTiles++;
173
+ const bytes = this.getByteLength(record.result.value);
174
+ if (bytes === undefined || !Number.isFinite(bytes) || bytes < 0) decodedBytes = undefined;
175
+ else if (decodedBytes !== undefined) decodedBytes += bytes;
176
+ }
177
+ return {loadingTiles, queuedTiles: this.queued.size, activeAcquisitions: this.activeAcquisitions,
178
+ maxConcurrentLoads: this.maxConcurrentLoads, readyTiles, consumers, decodedBytes, acquisitions: this.acquisitions,
179
+ sharedAcquisitions: this.sharedAcquisitions, cancelledAcquisitions: this.cancelledAcquisitions,
180
+ failedAcquisitions: this.failedAcquisitions};
181
+ }
182
+
183
+ /** Cancel all pending work and release content; subsequent use starts from an empty store. */
184
+ finalize(): void { for (const source of this.sources.keys()) this.invalidateSource(source); }
185
+
186
+ /** Drain only when a source procedure settles, not when its styled mesh finishes. */
187
+ private scheduleAcquisitions(): void {
188
+ if (this.scheduled || this.queued.size === 0) return;
189
+ this.scheduled = true;
190
+ void Promise.resolve().then(() => {
191
+ this.scheduled = false;
192
+ for (const [record, request] of this.queued) {
193
+ if (this.activeAcquisitions >= (this.maxConcurrentLoads ?? Infinity)) break;
194
+ this.queued.delete(record);
195
+ if (!this.isCurrent(request.source, request.key, record)) continue;
196
+ this.startAcquisition(request, record);
197
+ }
198
+ });
199
+ }
200
+
201
+ /** A slot follows the original procedure even if all consumer leases are released early. */
202
+ private startAcquisition(request: DecodedTileAcquisition<ValueT>, record: DecodedRecord<ValueT>): void {
203
+ this.activeAcquisitions++;
204
+ this.acquisitions++;
205
+ let loading: Promise<ValueT>;
206
+ try { loading = request.load(record.controller.signal); }
207
+ catch (error) { loading = Promise.reject(error); }
208
+ void Promise.resolve(loading).then(value => {
209
+ if (!this.isCurrent(request.source, request.key, record)) return;
210
+ record.result = {value};
211
+ for (const lease of record.consumers) lease.resolve(value);
212
+ }, error => {
213
+ if (!this.isCurrent(request.source, request.key, record)) return;
214
+ this.failedAcquisitions++;
215
+ this.forgetRecord(request.source, request.key, record);
216
+ for (const lease of record.consumers) lease.reject(error);
217
+ record.consumers.clear();
218
+ }).finally(() => {
219
+ this.activeAcquisitions--;
220
+ this.scheduleAcquisitions();
221
+ });
222
+ }
223
+
224
+ /** A late completion cannot publish over a replacement attempt for the same coordinate. */
225
+ private isCurrent(source: object, key: string, record: DecodedRecord<ValueT>): boolean {
226
+ return !record.controller.signal.aborted && this.sources.get(source)?.get(key) === record;
227
+ }
228
+
229
+ /** Forget only the matching attempt and release empty source maps immediately. */
230
+ private forgetRecord(source: object, key: string, record: DecodedRecord<ValueT>): void {
231
+ const records = this.sources.get(source);
232
+ if (records?.get(key) !== record) return;
233
+ records.delete(key);
234
+ if (records.size === 0) this.sources.delete(source);
235
+ }
236
+
237
+ /** Ready content has no pending request; cancellation is issued at most once. */
238
+ private cancelRecord(record: DecodedRecord<ValueT>): void {
239
+ if (!record.result && !record.controller.signal.aborted) {
240
+ this.cancelledAcquisitions++;
241
+ record.controller.abort();
242
+ this.queued.delete(record);
243
+ }
244
+ }
245
+ }
@@ -0,0 +1,300 @@
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 log from '../utils/log';
7
+ import DataSource, {NetworkSource, NetworkTileSource} from './data_source';
8
+ import {decodeMultiPolygon} from './mvt';
9
+ import Geo from '../utils/geo';
10
+
11
+ // For tiling GeoJSON client-side
12
+ import geojsonvt from 'geojson-vt';
13
+
14
+ type SourceConfig = Record<string, any>;
15
+
16
+ /**
17
+ GeoJSON standalone (non-tiled) source
18
+ Uses geojson-vt split into tiles client-side
19
+ */
20
+
21
+ export class GeoJSONSource extends NetworkSource {
22
+
23
+ load_data: Promise<any> | null = null;
24
+ tile_indexes!: Record<string, any>;
25
+ loaded = false;
26
+
27
+ constructor(source: SourceConfig, sources?: Record<string, unknown>) {
28
+ super(source, sources);
29
+ this.load_data = null;
30
+ this.tile_indexes = {}; // geojson-vt tile indices, by layer name
31
+ this.setTileSize(512); // auto-tile to 512px tiles for fewer internal tiles
32
+ this.pad_scale = 0; // we don't want padding on auto-tiled sources
33
+ }
34
+
35
+ _load(dest?: any): Promise<any> {
36
+ if (!dest) {
37
+ throw new Error('GeoJSON source loading requires a destination tile');
38
+ }
39
+ if (!this.load_data) {
40
+ this.load_data = super._load({ source_data: { layers: {} } }).then(data => {
41
+ // Warn and continue on data source error
42
+ if (data.source_data.error) {
43
+ log('warn', `data source load error(s) for source '${this.name}', URL '${this.url}': ${data.source_data.error}`);
44
+ }
45
+
46
+ let layers = data.source_data.layers;
47
+ for (let layer_name in layers) {
48
+ this.tile_indexes[layer_name] = geojsonvt(layers[layer_name], {
49
+ maxZoom: this.max_zoom, // max zoom to preserve detail on
50
+ tolerance: 1.5, // simplification tolerance (higher means simpler) NB: half the default to accomodate 512px tiles
51
+ extent: Geo.tile_scale, // tile extent (both width and height)
52
+ buffer: 0.0001 // tile buffer on each side
53
+ });
54
+ }
55
+
56
+ this.loaded = true;
57
+ return data;
58
+ });
59
+ }
60
+
61
+ return this.load_data.then(() => {
62
+ for (let layer_name in this.tile_indexes) {
63
+ dest.source_data.layers[layer_name] = this.getTileFeatures(dest, layer_name);
64
+ }
65
+ return dest;
66
+ });
67
+ }
68
+
69
+ getTileFeatures(tile: any, layer_name: string): any {
70
+ let coords = Geo.wrapTile(tile.coords, {x: true, y: false});
71
+
72
+ // request a particular tile
73
+ let t = this.tile_indexes[layer_name].getTile(coords.z, coords.x, coords.y);
74
+
75
+ // Convert from MVT-style JSON struct to GeoJSON
76
+ let collection;
77
+ if (t && t.features) {
78
+ collection = {
79
+ type: 'FeatureCollection',
80
+ features: [] as any[]
81
+ };
82
+
83
+ for (let i=0; i < t.features.length; i++) {
84
+ const feature = t.features[i];
85
+
86
+ // GeoJSON feature
87
+ let f: any = {
88
+ type: 'Feature',
89
+ geometry: {},
90
+ id: feature.id,
91
+ properties: feature.tags
92
+ };
93
+
94
+ if (feature.type === 1) {
95
+ f.geometry.coordinates = feature.geometry.map((coord: any) => [coord[0], coord[1]]);
96
+ f.geometry.type = 'MultiPoint';
97
+ }
98
+ else if (feature.type === 2 || feature.type === 3) {
99
+ f.geometry.coordinates = feature.geometry.map((ring: any[]) =>
100
+ ring.map((coord: any) => [coord[0], coord[1]])
101
+ );
102
+
103
+ if (feature.type === 2) {
104
+ f.geometry.type = 'MultiLineString';
105
+ }
106
+ else {
107
+ f.geometry = decodeMultiPolygon(f.geometry); // un-flatten rings
108
+ if (f.geometry == null) { // skip polys that couldn't be decoded (e.g. degenerate)
109
+ continue;
110
+ }
111
+ }
112
+ }
113
+ else {
114
+ continue;
115
+ }
116
+
117
+ collection.features.push(f);
118
+ }
119
+ }
120
+
121
+ return collection;
122
+ }
123
+
124
+ formatURL () {
125
+ return this.url;
126
+ }
127
+
128
+ parseSourceData (tile?: any, source?: any, response?: any): void {
129
+ if (!tile || !source) {
130
+ throw new Error('GeoJSON source parsing requires a tile and source data');
131
+ }
132
+ let data = typeof response === 'string' ? JSON.parse(response) : response;
133
+ let layers = this.getLayers(data);
134
+ source.layers = this.preprocessLayers(layers, tile);
135
+ }
136
+
137
+ preprocessLayers (layers: any, tile: any): any {
138
+ for (let key in layers) {
139
+ let layer = layers[key];
140
+ layer.features = this.preprocessFeatures(layer.features);
141
+ }
142
+
143
+ // Apply optional data transform
144
+ if (typeof this.transform === 'function') {
145
+ const tile_data = {
146
+ min: Object.assign({}, tile.min),
147
+ max: Object.assign({}, tile.max),
148
+ coords: Object.assign({}, tile.coords)
149
+ };
150
+ if (Object.keys(layers).length === 1 && layers._default) {
151
+ layers._default = this.transform(layers._default, this.extra_data, tile_data); // single-layer
152
+ }
153
+ else {
154
+ layers = this.transform(layers, this.extra_data, tile_data); // multiple layers
155
+ }
156
+ }
157
+
158
+ return layers;
159
+ }
160
+
161
+ // Preprocess features. Currently used to add a new "centroid" feature for polygon labeling
162
+ preprocessFeatures (features: any[]): any[] {
163
+ // Remove features without geometry (which is valid GeoJSON)
164
+ features = features.filter(f => f.geometry != null);
165
+
166
+ // Define centroids for polygons for centroid label placement
167
+ // Avoids redundant label placement for each generated tile at higher zoom levels
168
+ if (this.config.generate_label_centroids){
169
+ let features_centroid: any[] = [];
170
+ let centroid_properties = {'label_placement' : true};
171
+
172
+ features.forEach(feature => {
173
+ let coordinates, centroid_feature;
174
+ if (feature.geometry.type === 'Polygon') {
175
+ coordinates = feature.geometry.coordinates;
176
+ centroid_feature = getCentroidFeatureForPolygon(coordinates, feature.id, feature.properties, centroid_properties);
177
+ features_centroid.push(centroid_feature);
178
+ }
179
+ else if (feature.geometry.type === 'MultiPolygon') {
180
+ // Add centroid feature for largest polygon
181
+ coordinates = feature.geometry.coordinates;
182
+ let max_area = -Infinity;
183
+ let max_area_index = 0;
184
+ for (let index = 0; index < coordinates.length; index++) {
185
+ let area = Geo.polygonArea(coordinates[index]) || 0;
186
+ if (area > max_area) {
187
+ max_area = area;
188
+ max_area_index = index;
189
+ }
190
+ }
191
+ centroid_feature = getCentroidFeatureForPolygon(coordinates[max_area_index], feature.id, feature.properties, centroid_properties);
192
+ features_centroid.push(centroid_feature);
193
+ }
194
+ });
195
+
196
+ // append centroid features to features array
197
+ features_centroid = features_centroid.filter(x => x); // remove null features
198
+ Array.prototype.push.apply(features, features_centroid);
199
+ }
200
+
201
+ return features;
202
+ }
203
+
204
+ // Detect single or multiple layers in returned data
205
+ getLayers (data: any): any {
206
+ if (data.type === 'Feature') {
207
+ return {
208
+ _default: {
209
+ type: 'FeatureCollection',
210
+ features: [data]
211
+ }
212
+ };
213
+ }
214
+ else if (data.type === 'FeatureCollection') {
215
+ return {
216
+ _default: data
217
+ };
218
+ }
219
+ else {
220
+ return data;
221
+ }
222
+ }
223
+
224
+ }
225
+
226
+ /**
227
+ GeoJSON vector tiles
228
+ @class GeoJSONTileSource
229
+ */
230
+ export class GeoJSONTileSource extends NetworkTileSource {
231
+
232
+ constructor(source: SourceConfig, sources?: Record<string, unknown>) {
233
+ super(source, sources);
234
+ }
235
+
236
+ parseSourceData (tile?: any, source?: any, response?: any): void {
237
+ if (!tile || !source) {
238
+ throw new Error('GeoJSON tile parsing requires a tile and source data');
239
+ }
240
+ let data = typeof response === 'string' ? JSON.parse(response) : response;
241
+ this.prepareGeoJSON(data, tile, source);
242
+ }
243
+
244
+ prepareGeoJSON (data: any, tile: any, source: any): void {
245
+ // Apply optional data transform
246
+ if (typeof this.transform === 'function') {
247
+ const tile_data = {
248
+ min: Object.assign({}, tile.min),
249
+ max: Object.assign({}, tile.max),
250
+ coords: Object.assign({}, tile.coords)
251
+ };
252
+ data = this.transform(data, this.extra_data, tile_data);
253
+ }
254
+
255
+ source.layers = GeoJSONSource.prototype.getLayers(data);
256
+
257
+ // A "synthetic" tile that adjusts the tile min anchor to account for tile longitude wrapping
258
+ let anchor = {
259
+ coords: tile.coords,
260
+ min: Geo.metersForTile(Geo.wrapTile(tile.coords, {x: true, y: false}))
261
+ };
262
+
263
+ DataSource.projectData(source); // mercator projection
264
+ DataSource.scaleData(source, anchor); // re-scale from meters to local tile coords
265
+ }
266
+
267
+ }
268
+
269
+ // Check for URL tile pattern, if not found, treat as standalone GeoJSON/TopoJSON object
270
+ DataSource.register('GeoJSON', (source: SourceConfig) => {
271
+ return GeoJSONTileSource.urlHasTilePattern(source.url) ? GeoJSONTileSource : GeoJSONSource;
272
+ });
273
+
274
+
275
+ // Helper function to create centroid point feature from polygon coordinates and provided feature meta-data
276
+ function getCentroidFeatureForPolygon (
277
+ coordinates: any,
278
+ id: string | number | undefined,
279
+ properties: Record<string, unknown>,
280
+ newProperties: Record<string, unknown>
281
+ ): any {
282
+ let centroid = Geo.centroid(coordinates);
283
+ if (!centroid) {
284
+ return;
285
+ }
286
+
287
+ // clone properties and mixix newProperties
288
+ let centroid_properties = {};
289
+ Object.assign(centroid_properties, properties, newProperties);
290
+
291
+ return {
292
+ type: 'Feature',
293
+ id,
294
+ properties: centroid_properties,
295
+ geometry: {
296
+ type: 'Point',
297
+ coordinates: centroid
298
+ }
299
+ };
300
+ }