@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,655 @@
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
+ /*jshint worker: true */
7
+ import Geo from '../utils/geo';
8
+ import {MethodNotImplemented} from '../utils/errors';
9
+ import Utils from '../utils/utils';
10
+ import sliceObject from '../utils/slice';
11
+ import * as URLs from '../utils/urls';
12
+ import log from '../utils/log';
13
+ import {createTileSourceMetadata} from './tile_source_metadata';
14
+ import type {TangramTileSourceMetadata} from './tile_source_metadata';
15
+ import {applyTilePayload, captureTilePayload, updateTileSourceRequest} from './tile_source_state';
16
+
17
+ type SourceConfig = Record<string, any>;
18
+ type Tile = any;
19
+ type SourceData = any;
20
+ type DataSourceFactory = (source: SourceConfig) => any;
21
+
22
+ export default class DataSource {
23
+
24
+ static types: Record<string, DataSourceFactory> = {};
25
+ config!: SourceConfig;
26
+ sources!: Record<string, any>;
27
+ id!: string | number;
28
+ name!: string;
29
+ pad_scale!: number;
30
+ default_winding!: string | null | undefined;
31
+ rasters!: string[];
32
+ preprocess: any;
33
+ transform: any;
34
+ extra_data: any;
35
+ scripts: any;
36
+ max_zoom!: number;
37
+ zooms!: number[];
38
+ zoom_offset!: number;
39
+ tile_size!: number;
40
+ zoom_bias!: number;
41
+ min_display_zoom!: number;
42
+ max_display_zoom!: number | null;
43
+ /** Main-thread geometry admission assigned from top-level scene layers. */
44
+ declare builds_geometry_tiles: boolean | undefined;
45
+ /** Optional worker-owned provider identity, retained from source configuration. */
46
+ declare tile_provider?: string;
47
+ /** Provider credits discovered in TileJSON, kept separate from scene-authored credits. */
48
+ protected metadata_attribution?: string;
49
+
50
+ constructor (config: SourceConfig, sources?: Record<string, any>) {
51
+ this.validate(config);
52
+
53
+ this.config = config; // save original config
54
+ this.sources = sources as Record<string, any>; // full set of data sources TODO: centralize these like textures?
55
+ this.id = config.id;
56
+ this.name = config.name;
57
+ this.pad_scale = config.pad_scale || 0.00001; // scale tile up by small factor to cover seams
58
+ this.default_winding = null; // winding order will adapt to data source
59
+ this.rasters = []; // attached raster tile sources
60
+ if (Array.isArray(config.rasters)) { // copy unique set of raster sources
61
+ config.rasters.forEach(r => {
62
+ if (this.rasters.indexOf(r) === -1) {
63
+ this.rasters.push(r);
64
+ }
65
+ });
66
+ }
67
+
68
+ // Optional function to preprocess source data
69
+ this.preprocess = config.preprocess;
70
+ if (typeof this.preprocess === 'function') {
71
+ this.preprocess.bind(this);
72
+ }
73
+
74
+ // Optional function to transform source data
75
+ this.transform = config.transform;
76
+ if (typeof this.transform === 'function') {
77
+ this.transform.bind(this);
78
+ }
79
+
80
+ // Optional additional data to pass to the transform function
81
+ this.extra_data = config.extra_data;
82
+
83
+ // Optional additional scripts made available to the transform function
84
+ // NOTE: these are loaded alongside the library when the workers are instantiated
85
+ this.scripts = config.scripts;
86
+
87
+ // Configure zoom ranges at which new data will be loaded
88
+ this.setZooms(config);
89
+
90
+ // set a custom extra overzoom adjustment factor to load consistently lower zoom levels
91
+ // than the current map zoom level – eg a zoom_offset of 1 would load z3 data at z4
92
+ this.zoom_offset = (config.zoom_offset != null) ? config.zoom_offset : 0;
93
+ if (this.zoom_offset < 0) {
94
+ let msg = `Data source '${this.name}' zoom_offset must not be negative – setting to 0.`;
95
+ log({ level: 'warn', once: true }, msg);
96
+ this.zoom_offset = 0;
97
+ }
98
+
99
+ this.setTileSize(config.tile_size);
100
+
101
+ // no tiles will be requested or displayed outside of these min/max values
102
+ this.min_display_zoom = Math.max(config.min_display_zoom || 0, this.zooms[0]);
103
+ this.max_display_zoom = (config.max_display_zoom != null) ? config.max_display_zoom : null;
104
+ }
105
+
106
+ /** Returns source-authored and discovered provider HTML without inserting it into a DOM. */
107
+ getAttributions(): string[] {
108
+ const values: unknown[] = [this.config.attribution, this.metadata_attribution];
109
+ return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)
110
+ .map(value => value.trim()))];
111
+ }
112
+
113
+ /** Metadata for aligned source consumers; does not alter the legacy source zoom/bounds policy. */
114
+ getMetadata(): Promise<TangramTileSourceMetadata> {
115
+ return Promise.resolve(createTileSourceMetadata(this));
116
+ }
117
+
118
+ /** Release source-owned resources. Stateless sources intentionally have nothing to release. */
119
+ dispose(): void {
120
+ }
121
+
122
+ // Register a new data source type name, providing a function that returns the class name
123
+ // to instantiate based on the source definition in the scene
124
+ static register (type_name: string, type_func: DataSourceFactory): void {
125
+ if (!type_name || !type_func) {
126
+ return;
127
+ }
128
+
129
+ DataSource.types[type_name] = type_func;
130
+ }
131
+
132
+ // Create a data source, factory-style
133
+ static create (source: SourceConfig, sources?: Record<string, any>): DataSource | undefined {
134
+ // Find the class to instantiate based on the source definition
135
+ if (typeof DataSource.types[source.type] === 'function') {
136
+ const source_class = DataSource.types[source.type](source);
137
+ if (source_class) {
138
+ return new source_class(source, sources);
139
+ }
140
+ }
141
+ }
142
+
143
+ // Check if a data source definition changed in a way that could affect which tiles are in view
144
+ static tileLayoutChanged (source: any, prev_source: any): boolean {
145
+ if (!source || !prev_source) {
146
+ return true;
147
+ }
148
+
149
+ // subset of parameters that affect tile layout
150
+ const rebuild_params = [
151
+ 'max_zoom',
152
+ 'zooms',
153
+ 'min_display_zoom',
154
+ 'max_display_zoom',
155
+ 'bounds',
156
+ 'tile_size',
157
+ 'zoom_offset'
158
+ ];
159
+ const cur = sliceObject(source.config, rebuild_params);
160
+ const prev = sliceObject(prev_source.config, rebuild_params);
161
+
162
+ return JSON.stringify(cur) !== JSON.stringify(prev);
163
+ }
164
+
165
+ // Mercator projection
166
+ static projectData (source: SourceData): void {
167
+ var timer = +new Date();
168
+ for (var t in source.layers) {
169
+ var num_features = source.layers[t].features.length;
170
+ for (var f=0; f < num_features; f++) {
171
+ var feature = source.layers[t].features[f];
172
+ Geo.transformGeometry(feature.geometry, this.projectCoord);
173
+ }
174
+ }
175
+
176
+ if (source.debug !== undefined) {
177
+ source.debug.projection = +new Date() - timer;
178
+ }
179
+ }
180
+
181
+ static projectCoord (coord: number[]): void {
182
+ Geo.latLngToMeters(coord);
183
+ }
184
+
185
+ /**
186
+ Re-scale geometries within each source to internal tile units
187
+ */
188
+ static scaleData (source: SourceData, {coords: {z}, min}: any): void {
189
+ let units_per_meter = Geo.unitsPerMeter(z);
190
+ for (var t in source.layers) {
191
+ var num_features = source.layers[t].features.length;
192
+ for (var f=0; f < num_features; f++) {
193
+ var feature = source.layers[t].features[f];
194
+ Geo.transformGeometry(feature.geometry, coord => {
195
+ coord[0] = (coord[0] - min.x) * units_per_meter;
196
+ coord[1] = (coord[1] - min.y) * units_per_meter * -1; // flip coords positive
197
+ });
198
+ }
199
+ }
200
+ }
201
+
202
+ load (dest: Tile): Promise<Tile> {
203
+ dest.source_data = {};
204
+ dest.source_data.layers = {};
205
+ dest.pad_scale = this.pad_scale;
206
+ dest.rasters = [...this.rasters]; // copy list of rasters to load for tile
207
+
208
+ return this._load(dest).then((dest) => {
209
+ // Post-processing
210
+ for (let layer in dest.source_data.layers) {
211
+ let data = dest.source_data.layers[layer];
212
+ if (data && data.features) {
213
+ data.features.forEach((feature: any) => {
214
+ Geo.transformGeometry(feature.geometry, coord => {
215
+ // Flip Y coords
216
+ coord[1] = -coord[1];
217
+
218
+ // Slightly scale up tile to cover seams
219
+ if (this.pad_scale) {
220
+ coord[0] = Math.round(coord[0] * (1 + this.pad_scale) - (Geo.tile_scale * this.pad_scale/2));
221
+ coord[1] = Math.round(coord[1] * (1 + this.pad_scale) - (Geo.tile_scale * this.pad_scale/2));
222
+ }
223
+ });
224
+
225
+ // Use first encountered polygon winding order as default for data source
226
+ this.updateDefaultWinding(feature.geometry);
227
+ });
228
+ }
229
+ }
230
+
231
+ dest.default_winding = this.default_winding || 'CCW';
232
+ captureTilePayload(dest);
233
+ return dest;
234
+ });
235
+ }
236
+
237
+ // Sub-classes must implement
238
+ _load (_dest?: Tile): Promise<Tile> {
239
+ throw new MethodNotImplemented('_load');
240
+ }
241
+
242
+ // Copy source data from another tile (so we can reuse source data for overzoomed tiles)
243
+ copyTileData (source: Tile, dest: Tile): Tile {
244
+ log('trace', `Copy tile data from ${source.key} to ${dest.key}`);
245
+ applyTilePayload(dest, {layers: source.source_data.layers, rasters: [...source.rasters],
246
+ padScale: source.pad_scale, defaultWinding: source.default_winding});
247
+ return dest;
248
+ }
249
+
250
+ // Configure zoom ranges at which new data will be loaded
251
+ // e.g. can be used to skip fetching data for some zooms, reusing data from next lowest available zoom instead
252
+ setZooms ({max_zoom, zooms}: SourceConfig): void {
253
+ // overzoom will apply for zooms higher than this
254
+ this.max_zoom = (max_zoom != null) ? max_zoom : Geo.default_source_max_zoom;
255
+ if (Array.isArray(zooms)) {
256
+ this.zooms = zooms; // TODO: support range parsing, e.g. [0-4, 6-7, 12]?
257
+ this.max_zoom = this.zooms[this.zooms.length-1]; // overrides `max_zoom` when both are present
258
+ }
259
+ else {
260
+ this.zooms = [];
261
+ for (let i = 0; i <= this.max_zoom; i++) {
262
+ this.zooms[i] = i;
263
+ }
264
+ }
265
+ }
266
+
267
+ // Set the internal tile size in pixels, e.g. '256px' (default), '512px', etc.
268
+ // Must be a power of 2, and greater than or equal to 256
269
+ setTileSize (tile_size?: number): void {
270
+ this.tile_size = tile_size || 256;
271
+ if (typeof this.tile_size !== 'number' || this.tile_size < 256 || !Utils.isPowerOf2(this.tile_size)) {
272
+ log({ level: 'warn', once: true },
273
+ `Data source '${this.name}': 'tile_size' parameter must be a number that is a power of 2 greater than or equal to 256, but was '${tile_size}'`);
274
+ this.tile_size = 256;
275
+ }
276
+
277
+ // # of zoom levels bigger than 256px tiles - 8 in place of log2(256)
278
+ // Many Tangram functions assume 256px tiles, this factor adjusts for the
279
+ // case of bigger tile sizes - eg 512px tiles are 1 zoom level bigger,
280
+ // 1024px tiles are 2 levels bigger
281
+ this.zoom_bias = Math.log2(this.tile_size) - 8 + this.zoom_offset;
282
+ }
283
+
284
+ // Infer winding for data source from first ring of provided geometry
285
+ updateDefaultWinding (geom: any): string | null | undefined {
286
+ if (this.default_winding == null) {
287
+ if (geom.type === 'Polygon') {
288
+ this.default_winding = Geo.ringWinding(geom.coordinates[0]);
289
+ }
290
+ else if (geom.type === 'MultiPolygon') {
291
+ this.default_winding = Geo.ringWinding(geom.coordinates[0][0]);
292
+ }
293
+ }
294
+ return this.default_winding;
295
+ }
296
+
297
+ // All data sources support a min zoom, tiled sources can subclass for more specific limits (e.g. bounding box)
298
+ includesTile (coords: any, style_z: number): boolean {
299
+ // Limit by this data source
300
+ if (coords.z < this.min_display_zoom || (this.max_display_zoom != null && style_z > this.max_display_zoom)) {
301
+ return false;
302
+ }
303
+
304
+ // Limit by any dependent raster sources
305
+ for (let r=0; r < this.rasters.length; r++) {
306
+ const source_name = this.rasters[r];
307
+ if (this.sources[source_name] &&
308
+ this.sources[source_name] !== this &&
309
+ !this.sources[source_name].includesTile(coords, coords.z)) {
310
+ return false;
311
+ }
312
+ }
313
+
314
+ return true;
315
+ }
316
+
317
+ validate (_source?: SourceConfig): void {
318
+ }
319
+
320
+ }
321
+
322
+ /*** Generic network loading source - abstract class ***/
323
+
324
+ let network_request_id = 0; // used to namespace URL requests
325
+
326
+ export class NetworkSource extends DataSource {
327
+
328
+ response_type!: string;
329
+ tilejson: any;
330
+ url_params: any;
331
+ url: string | null;
332
+ request_headers?: Record<string, string>;
333
+ tilejson_promise?: Promise<string>;
334
+ /** Discovered TileJSON metadata for aligned consumers, separate from layout policy. */
335
+ protected tile_metadata?: Record<string, unknown>;
336
+ /** TileJSON request identity belongs to the source, not to any individual tile consumer. */
337
+ private metadata_request_id?: string;
338
+ /** Source replacement must not allow late metadata to initialize a retired source. */
339
+ protected source_disposed = false;
340
+
341
+ constructor (source: SourceConfig, sources?: Record<string, any>) {
342
+ super(source, sources);
343
+ this.response_type = ''; // use to set explicit XHR type
344
+
345
+ this.tilejson = source.tilejson;
346
+ this.url_params = source.url_params;
347
+ this.url = source.url ? this.addURLParams(source.url) : null;
348
+
349
+ // Optional HTTP request headers to send
350
+ if (source.request_headers && typeof source.request_headers === 'object') {
351
+ this.request_headers = source.request_headers;
352
+ }
353
+ }
354
+
355
+ _load (dest?: Tile): Promise<Tile> {
356
+ return this.resolveURL().then(url => this.loadURL(dest, url)).catch(error => {
357
+ updateTileSourceRequest(dest, {error: error.stack});
358
+ return dest;
359
+ });
360
+ }
361
+
362
+ resolveURL (): Promise<string> {
363
+ if (this.source_disposed) return Promise.reject(new Error('Network source is disposed'));
364
+ if (this.url) {
365
+ return Promise.resolve(this.url);
366
+ }
367
+
368
+ if (!this.tilejson_promise) {
369
+ this.metadata_request_id = `metadata-${network_request_id++}-${this.tilejson}`;
370
+ this.tilejson_promise = Utils.io(this.tilejson, 60 * 1000, 'text', 'GET', this.request_headers, this.metadata_request_id)
371
+ .then(({ body }) => {
372
+ if (this.source_disposed) throw new Error('Network source is disposed');
373
+ const metadata = (typeof body === 'string') ? JSON.parse(body) : body;
374
+ if (!metadata || !Array.isArray(metadata.tiles) || typeof metadata.tiles[0] !== 'string') {
375
+ throw Error(`Data source '${this.name}': TileJSON must provide at least one tile URL`);
376
+ }
377
+ this.url = this.addURLParams(URLs.addBaseURL(metadata.tiles[0], this.tilejson));
378
+ this.metadata_attribution = typeof metadata.attribution === 'string' ? metadata.attribution : undefined;
379
+ this.tile_metadata = metadata;
380
+ return this.url;
381
+ }).finally(() => { this.metadata_request_id = undefined; });
382
+ }
383
+ return this.tilejson_promise;
384
+ }
385
+
386
+ /** Resolve TileJSON before exposing metadata while preserving explicit scene options. */
387
+ async getMetadata(): Promise<TangramTileSourceMetadata> {
388
+ await this.resolveURL();
389
+ return createTileSourceMetadata(this, this.tile_metadata);
390
+ }
391
+
392
+ /** Cancel metadata initialization and prevent deferred URL resolution after removal. */
393
+ dispose(): void {
394
+ this.source_disposed = true;
395
+ if (this.metadata_request_id) Utils.cancelRequest(this.metadata_request_id);
396
+ this.metadata_request_id = undefined;
397
+ }
398
+
399
+ addURLParams (url: string): string {
400
+ const [resolved_url, dupes] = URLs.addParamsToURL(url, this.url_params);
401
+ dupes.forEach(([param, value]) => {
402
+ log({ level: 'warn', once: true },
403
+ `Data source '${this.name}': parameter '${param}' already present in URL '${url}', ` +
404
+ `skipping value '${param}=${value}' specified in 'url_params'`);
405
+ });
406
+ return resolved_url;
407
+ }
408
+
409
+ loadURL (dest: Tile, url_template: string): Promise<Tile> {
410
+ let url = this.formatURL(url_template, dest) as string;
411
+
412
+ let source_data = dest.source_data;
413
+ updateTileSourceRequest(dest, {url});
414
+ dest.debug = dest.debug || {};
415
+ dest.debug.network = +new Date();
416
+
417
+ return new Promise(resolve => {
418
+ let request_id = (network_request_id++) + '-' + url;
419
+ let promise: Promise<any> = Utils.io(
420
+ url,
421
+ 60 * 1000,
422
+ this.response_type as any,
423
+ 'GET',
424
+ this.request_headers,
425
+ request_id
426
+ ) as Promise<any>;
427
+
428
+ updateTileSourceRequest(dest, {requestId: request_id, error: null});
429
+
430
+ promise.then(({ body }) => {
431
+ dest.debug.response_size = body && (body.length || body.byteLength);
432
+ dest.debug.network = +new Date() - dest.debug.network;
433
+ dest.debug.parsing = +new Date();
434
+
435
+ // Apply optional data transform on raw network response
436
+ if (body != null && typeof this.preprocess === 'function') {
437
+ body = this.preprocess(body);
438
+ }
439
+
440
+ // Return data immediately, or after user-returned promise resolves
441
+ body = (body instanceof Promise) ? body : Promise.resolve(body);
442
+ body.then((body: any) => {
443
+ if (body != null) {
444
+ this.parseSourceData(dest, source_data, body);
445
+ }
446
+ else {
447
+ source_data.layers = {}; // for cases where server returned no content (e.g. 204 response)
448
+ }
449
+ dest.debug.parsing = +new Date() - dest.debug.parsing;
450
+ resolve(dest);
451
+ });
452
+ }).catch((error) => {
453
+ updateTileSourceRequest(dest, {error: error.stack});
454
+ resolve(dest); // resolve request but pass along error
455
+ });
456
+ });
457
+ }
458
+
459
+ validate (source: SourceConfig): void {
460
+ if (typeof source.url !== 'string' && typeof source.tilejson !== 'string') {
461
+ throw Error('Network data source must provide a string `url` or `tilejson` property');
462
+ }
463
+ }
464
+
465
+ // Sub-classes must implement:
466
+
467
+ formatURL (_url_template?: string, _dest?: Tile): string | null {
468
+ throw new MethodNotImplemented('formatURL');
469
+ }
470
+
471
+ parseSourceData (_dest?: Tile, _source?: SourceData, _response?: any): void {
472
+ throw new MethodNotImplemented('parseSourceData');
473
+ }
474
+ }
475
+
476
+
477
+ /*** Generic network tile loading - abstract class ***/
478
+
479
+ export class NetworkTileSource extends NetworkSource {
480
+
481
+ tiled!: boolean;
482
+ bounds: any;
483
+ declare builds_geometry_tiles: boolean;
484
+ tms!: boolean;
485
+ url_subdomains?: string[];
486
+ next_url_subdomain?: number;
487
+ url_density_scales?: number[];
488
+
489
+ constructor (source: SourceConfig, sources?: Record<string, any>) {
490
+ super(source, sources);
491
+
492
+ this.tiled = true;
493
+ this.bounds = this.parseBounds(source);
494
+
495
+ // indicates if source should build geometry tiles, enabled for sources referenced in the scene's layers,
496
+ // and left disabled for sources that are never referenced, or only used as raster textures
497
+ this.builds_geometry_tiles = false;
498
+
499
+ this.tms = (source.tms === true); // optionally flip tile coords for TMS
500
+
501
+ // optional list of subdomains to round-robin through
502
+ if (this.url && this.url.search('{s}') > -1) {
503
+ if (Array.isArray(source.url_subdomains) && source.url_subdomains.length > 0) {
504
+ this.url_subdomains = source.url_subdomains;
505
+ this.next_url_subdomain = 0;
506
+ }
507
+ else {
508
+ log({ level: 'warn', once: true },
509
+ `Data source '${this.name}': source URL includes '{s}' subdomain marker ('${this.url}'), but no subdomains ` +
510
+ 'were specified in \'url_subdomains\' parameter');
511
+ }
512
+ }
513
+
514
+ // optional list of pixel density scale modifiers
515
+ if (this.url && this.url.search('{r}') > -1) {
516
+ if (Array.isArray(source.url_density_scales) && source.url_density_scales.length > 0) {
517
+ this.url_density_scales = source.url_density_scales;
518
+ }
519
+ else {
520
+ this.url_density_scales = [1, 2]; // default to supporting 1x and 2x display densities
521
+ }
522
+ }
523
+ }
524
+
525
+ // Get bounds from source config parameters
526
+ parseBounds (source: SourceConfig): any {
527
+ if (Array.isArray(source.bounds) && source.bounds.length === 4) {
528
+ const [w, s, e, n] = source.bounds;
529
+ return {
530
+ latlng: [...source.bounds],
531
+ meters: {
532
+ min: Geo.latLngToMeters([w, n]),
533
+ max: Geo.latLngToMeters([e, s]),
534
+ },
535
+ tiles: { // max tile bounds per zoom (lazily evaluated)
536
+ min: {},
537
+ max: {}
538
+ }
539
+ };
540
+ }
541
+ }
542
+
543
+ // Returns false if tile is outside data source's bounds, true if within
544
+ checkBounds (coords: any, bounds: any): boolean {
545
+ // Check tile bounds
546
+ if (bounds) {
547
+ // get tile and bounds coords at current zoom, wrapping to keep x coords in positive range
548
+ coords = Geo.wrapTile(coords);
549
+
550
+ let min = bounds.tiles.min[coords.z];
551
+ if (!min) {
552
+ min = bounds.tiles.min[coords.z] = Geo.tileForMeters(bounds.meters.min, coords.z);
553
+ }
554
+
555
+ let max = bounds.tiles.max[coords.z];
556
+ if (!max) {
557
+ max = bounds.tiles.max[coords.z] = Geo.tileForMeters(bounds.meters.max, coords.z);
558
+ }
559
+
560
+ // check latitude
561
+ if (coords.y < min.y || coords.y > max.y) {
562
+ return false;
563
+ }
564
+
565
+ // longitude bounds are between meridians
566
+ if (min.x <= max.x) {
567
+ if (coords.x < min.x || coords.x > max.x) {
568
+ return false;
569
+ }
570
+ }
571
+ // longitude bounds cross the antimeridian
572
+ else if (coords.x > max.x && coords.x < min.x) {
573
+ return false;
574
+ }
575
+ }
576
+ return true;
577
+ }
578
+
579
+ includesTile (coords: any, style_z: number): boolean {
580
+ if (!super.includesTile(coords, style_z)) {
581
+ return false;
582
+ }
583
+
584
+ // Check tile bounds
585
+ if (!this.checkBounds(coords, this.bounds)) {
586
+ return false;
587
+ }
588
+ return true;
589
+ }
590
+
591
+ formatURL (url_template: string, tile: Tile): string {
592
+ let coords = Geo.wrapTile(tile.coords, {x: true} as any);
593
+
594
+ if (this.tms) {
595
+ coords.y = Math.pow(2, coords.z) - 1 - coords.y; // optionally flip tile coords for TMS
596
+ }
597
+
598
+ // tile URL template replacement
599
+ let url = url_template
600
+ .replace('{x}', String(coords.x))
601
+ .replace('{y}', String(coords.y))
602
+ .replace('{z}', String(coords.z))
603
+ .replace('{r}', this.getDensityModifier()) // modify URL by display density (e.g. @2x)
604
+ .replace('{q}', this.toQuadKey(coords)); // quadkey for tile coordinates
605
+
606
+ if (this.url_subdomains != null) {
607
+ url = url.replace('{s}', this.url_subdomains[this.next_url_subdomain as number]);
608
+ this.next_url_subdomain = ((this.next_url_subdomain as number) + 1) % this.url_subdomains.length;
609
+ }
610
+ return url;
611
+ }
612
+
613
+ // Find the right tile URL modifier based on the display density, e.g. add `@2x` for sources supporting 2x tiles.
614
+ // Source `url_density_scales` param can specify an array of densities supported by the source,
615
+ // each entry serves as a threshold based on the current display density.
616
+ getDensityModifier (): string {
617
+ if (this.url_density_scales) {
618
+ // find the highest matching density
619
+ const dpr = Utils.device_pixel_ratio as number;
620
+ let scale = this.url_density_scales
621
+ .filter(s => dpr >= s)
622
+ .reverse()[0];
623
+
624
+ // default to first scale if none matched
625
+ scale = (scale != null ? scale : this.url_density_scales[0]);
626
+
627
+ // scales higher than 1x use the `@` modifier (e.g. `@2x`)
628
+ if (scale > 1) {
629
+ return `@${scale}x`;
630
+ }
631
+ }
632
+ return ''; // for 1x (or less) displays, no URL modifier is used (following @2x URL convention)
633
+ }
634
+
635
+ toQuadKey ({x, y, z}: {x: number; y: number; z: number}): string {
636
+ let quadkey = '';
637
+ for (let i = z; i > 0; i--) {
638
+ let b = 0;
639
+ let mask = 1 << (i - 1);
640
+ if ((x & mask) !== 0) b++;
641
+ if ((y & mask) !== 0) b += 2;
642
+ quadkey += b.toString();
643
+ }
644
+ return quadkey;
645
+ }
646
+
647
+ // Checks for the x/y/z tile pattern in URL template
648
+ static urlHasTilePattern (url?: string | null): any {
649
+ return url && (
650
+ (url.search('{x}') > -1 && url.search('{y}') > -1 && url.search('{z}') > -1) ||
651
+ url.search('{q}') > -1
652
+ );
653
+ }
654
+
655
+ }