@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.
- package/README.md +59 -2
- package/dist/core.js +36923 -0
- package/dist/core.js.map +6 -0
- package/dist/index.js +32 -0
- package/dist/loaders-gl-worker.js +82 -0
- package/dist/loaders-gl-worker.js.map +6 -0
- package/dist/map-logic.js +2 -0
- package/dist/map-logic.js.map +6 -0
- package/dist/projected-basemaps-worker.js +3 -0
- package/dist/projected-basemaps-worker.js.map +6 -0
- package/dist/shader-modules.js +141 -0
- package/dist/shader-modules.js.map +6 -0
- package/dist/style-schema.js +126 -0
- package/dist/style-schema.js.map +6 -0
- package/dist/tangram-style.schema.json +882 -0
- package/dist/tangram.debug.mjs +37139 -0
- package/dist/tangram.debug.mjs.map +6 -0
- package/dist/tangram.min.mjs +4950 -0
- package/dist/types/builders/earcut.d.ts +15 -0
- package/dist/types/core.d.ts +29 -0
- package/dist/types/gl/constants.d.ts +2 -0
- package/dist/types/gl/globe_mesh.d.ts +48 -0
- package/dist/types/gl/glsl.d.ts +17 -0
- package/dist/types/gl/vertex-constants.d.ts +4 -0
- package/dist/types/gl/vertex-types.d.ts +34 -0
- package/dist/types/gl/vertex_data.d.ts +32 -0
- package/dist/types/gl/vertex_elements.d.ts +8 -0
- package/dist/types/gl/vertex_layout.d.ts +32 -0
- package/dist/types/glsl.d.ts +14 -0
- package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
- package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
- package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
- package/dist/types/index.d.ts +155 -0
- package/dist/types/lights/light-definitions.d.ts +121 -0
- package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
- package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
- package/dist/types/map-logic/globe-terrain.d.ts +54 -0
- package/dist/types/map-logic/index.d.ts +33 -0
- package/dist/types/map-logic/label-identity.d.ts +22 -0
- package/dist/types/map-logic/label-placement.d.ts +32 -0
- package/dist/types/map-logic/screen-bounds.d.ts +15 -0
- package/dist/types/map-logic/terrain-data.d.ts +55 -0
- package/dist/types/map-logic/terrain-error.d.ts +51 -0
- package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
- package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
- package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
- package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
- package/dist/types/map-logic/terrain-query.d.ts +33 -0
- package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
- package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
- package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
- package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
- package/dist/types/map-logic/tile-residency.d.ts +17 -0
- package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
- package/dist/types/procedures/js-yaml.d.ts +15 -0
- package/dist/types/procedures/mesh-projector.d.ts +107 -0
- package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
- package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
- package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
- package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
- package/dist/types/procedures/terrain-draping.d.ts +165 -0
- package/dist/types/procedures/terrain-globe.d.ts +6 -0
- package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
- package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
- package/dist/types/procedures/web-mercator-math.d.ts +4 -0
- package/dist/types/scene/globals.d.ts +11 -0
- package/dist/types/scene/ground_footprint.d.ts +16 -0
- package/dist/types/scene/host_frame.d.ts +54 -0
- package/dist/types/scene/projection_math.d.ts +52 -0
- package/dist/types/scene/scene-resource-types.d.ts +177 -0
- package/dist/types/scene/scene_bundle.d.ts +69 -0
- package/dist/types/scene/visibility_adapter.d.ts +106 -0
- package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
- package/dist/types/selection/terrain_surface.d.ts +149 -0
- package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
- package/dist/types/shader-modules/height-decode.d.ts +13 -0
- package/dist/types/shader-modules/hillshade.d.ts +13 -0
- package/dist/types/shader-modules/index.d.ts +6 -0
- package/dist/types/shader-modules/planar.d.ts +12 -0
- package/dist/types/shader-modules/sphere-map.d.ts +13 -0
- package/dist/types/shader-modules/triplanar.d.ts +15 -0
- package/dist/types/sources/decoded_tile_store.d.ts +95 -0
- package/dist/types/sources/tile_source_metadata.d.ts +32 -0
- package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
- package/dist/types/tile/tile_id.d.ts +37 -0
- package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
- package/dist/types/types.d.ts +293 -0
- package/dist/types/utils/geo.d.ts +57 -0
- package/dist/types/utils/hash.d.ts +1 -0
- package/dist/types/utils/log.d.ts +27 -0
- package/dist/types/utils/props.d.ts +6 -0
- package/dist/types/utils/subscribe.d.ts +10 -0
- package/dist/types/utils/thread.d.ts +6 -0
- package/dist/types/utils/urls.d.ts +26 -0
- package/dist/types/utils/utils.d.ts +26 -0
- package/dist/types/utils/version.d.ts +2 -0
- package/dist/types/utils/worker-types.d.ts +68 -0
- package/dist/types/utils/worker_broker.d.ts +3 -0
- package/package.json +103 -3
- package/src/builders/common.ts +41 -0
- package/src/builders/earcut.d.ts +15 -0
- package/src/builders/geometry-types.ts +60 -0
- package/src/builders/points.ts +115 -0
- package/src/builders/polygons.ts +225 -0
- package/src/builders/polylines.ts +682 -0
- package/src/builders/wireframe.ts +31 -0
- package/src/core.d.ts +29 -0
- package/src/core.ts +33 -0
- package/src/experimental/loaders-gl-worker.ts +19 -0
- package/src/experimental/projected-basemaps-worker.ts +13 -0
- package/src/experimental/projected-mesh-cache.ts +137 -0
- package/src/experimental/projected-mesh-domain.ts +110 -0
- package/src/experimental/projected-mesh-refinement.ts +193 -0
- package/src/experimental/projected-mesh.ts +399 -0
- package/src/experimental/projected-normal.ts +26 -0
- package/src/experimental/projected-symbol-mesh.ts +74 -0
- package/src/gl/constants.ts +18 -0
- package/src/gl/context.ts +103 -0
- package/src/gl/extensions.ts +30 -0
- package/src/gl/globe_mesh.ts +285 -0
- package/src/gl/glsl.ts +257 -0
- package/src/gl/mesh-types.ts +56 -0
- package/src/gl/render_state.ts +111 -0
- package/src/gl/shader_program.ts +1310 -0
- package/src/gl/texture.ts +814 -0
- package/src/gl/uniform_buffer.ts +340 -0
- package/src/gl/vao.ts +154 -0
- package/src/gl/vbo_mesh.ts +349 -0
- package/src/gl/vertex-constants.ts +19 -0
- package/src/gl/vertex-types.ts +35 -0
- package/src/gl/vertex_data.ts +126 -0
- package/src/gl/vertex_elements.ts +54 -0
- package/src/gl/vertex_layout.ts +241 -0
- package/src/glsl.d.ts +14 -0
- package/src/gpu/luma_device_renderer.ts +579 -0
- package/src/gpu/pixel_readback.ts +51 -0
- package/src/gpu/resource_lifecycle.ts +32 -0
- package/src/gpu/tangram_gpu_backend.ts +195 -0
- package/src/index.d.ts +155 -0
- package/src/index.ts +105 -0
- package/src/labels/collision-types.ts +94 -0
- package/src/labels/collision.ts +273 -0
- package/src/labels/collision_grid.ts +61 -0
- package/src/labels/intersect.ts +30 -0
- package/src/labels/label-types.ts +91 -0
- package/src/labels/label.ts +207 -0
- package/src/labels/label_line.ts +801 -0
- package/src/labels/label_point.ts +131 -0
- package/src/labels/main-pass-types.ts +73 -0
- package/src/labels/main_pass.ts +221 -0
- package/src/labels/point_anchor.ts +100 -0
- package/src/labels/point_placement.ts +150 -0
- package/src/labels/projected-pass.ts +259 -0
- package/src/labels/repeat_group.ts +72 -0
- package/src/lights/ambient_light.glsl +18 -0
- package/src/lights/directional_light.glsl +39 -0
- package/src/lights/geographic-lights.ts +21 -0
- package/src/lights/light-definitions.ts +285 -0
- package/src/lights/light.ts +590 -0
- package/src/lights/lighting-uniforms.ts +80 -0
- package/src/lights/lighting-wgsl.ts +116 -0
- package/src/lights/material.glsl +237 -0
- package/src/lights/material.ts +145 -0
- package/src/lights/native-falloff.ts +37 -0
- package/src/lights/point_light.glsl +96 -0
- package/src/lights/spot_light.glsl +111 -0
- package/src/map-logic/draped-terrain-bounds.ts +71 -0
- package/src/map-logic/globe-terrain-preparation.ts +217 -0
- package/src/map-logic/globe-terrain.ts +296 -0
- package/src/map-logic/index.ts +37 -0
- package/src/map-logic/label-identity.ts +36 -0
- package/src/map-logic/label-placement.ts +117 -0
- package/src/map-logic/screen-bounds.ts +34 -0
- package/src/map-logic/terrain-data.ts +107 -0
- package/src/map-logic/terrain-error.ts +134 -0
- package/src/map-logic/terrain-ground-topology.ts +164 -0
- package/src/map-logic/terrain-height-field.ts +254 -0
- package/src/map-logic/terrain-navigation.ts +50 -0
- package/src/map-logic/terrain-neighborhood.ts +43 -0
- package/src/map-logic/terrain-query.ts +51 -0
- package/src/map-logic/terrain-resource-budget.ts +124 -0
- package/src/map-logic/terrain-transition-topology.ts +164 -0
- package/src/map-logic/tile-build-queue.ts +110 -0
- package/src/map-logic/tile-cache-policy.ts +89 -0
- package/src/map-logic/tile-residency.ts +50 -0
- package/src/map-logic/triangle-query-index.ts +265 -0
- package/src/procedures/js-yaml.d.ts +15 -0
- package/src/procedures/mesh-projector.ts +191 -0
- package/src/procedures/mlt-loaders.ts +55 -0
- package/src/procedures/mvt-dependencies.d.ts +20 -0
- package/src/procedures/mvt-legacy.ts +150 -0
- package/src/procedures/mvt-loaders.ts +53 -0
- package/src/procedures/mvt-parser.ts +48 -0
- package/src/procedures/mvt-properties.ts +36 -0
- package/src/procedures/mvt-tile-provider.ts +72 -0
- package/src/procedures/pmtiles-loader.ts +75 -0
- package/src/procedures/projected-coordinate-transform.ts +79 -0
- package/src/procedures/projection-batch-executor.ts +140 -0
- package/src/procedures/scene-yaml-legacy.ts +16 -0
- package/src/procedures/scene-yaml-loaders.ts +10 -0
- package/src/procedures/terrain-draping.ts +713 -0
- package/src/procedures/terrain-globe.ts +32 -0
- package/src/procedures/terrain-styled-topology.ts +184 -0
- package/src/procedures/web-mercator-legacy.ts +24 -0
- package/src/procedures/web-mercator-math.ts +50 -0
- package/src/scene/camera.ts +298 -0
- package/src/scene/camera_base.ts +116 -0
- package/src/scene/classic_scene.ts +20 -0
- package/src/scene/external_camera.ts +101 -0
- package/src/scene/globals.ts +120 -0
- package/src/scene/ground_footprint.ts +139 -0
- package/src/scene/host_frame.ts +326 -0
- package/src/scene/projected_tile_lod.ts +125 -0
- package/src/scene/projection_math.ts +142 -0
- package/src/scene/projection_shaders.ts +183 -0
- package/src/scene/renderer.ts +516 -0
- package/src/scene/scene-resource-types.ts +174 -0
- package/src/scene/scene.ts +2378 -0
- package/src/scene/scene_bundle.ts +304 -0
- package/src/scene/scene_debug.ts +129 -0
- package/src/scene/scene_loader.ts +402 -0
- package/src/scene/scene_worker.ts +528 -0
- package/src/scene/view.ts +683 -0
- package/src/scene/visibility_adapter.ts +319 -0
- package/src/scene/worker_url.ts +15 -0
- package/src/selection/draped-terrain-surface.ts +377 -0
- package/src/selection/selection-types.ts +79 -0
- package/src/selection/selection.ts +542 -0
- package/src/selection/selection_fragment.glsl +18 -0
- package/src/selection/selection_globals.glsl +9 -0
- package/src/selection/selection_pixels.ts +59 -0
- package/src/selection/selection_vertex.glsl +15 -0
- package/src/selection/terrain_surface.ts +298 -0
- package/src/shader-modules/globe-horizon.ts +52 -0
- package/src/shader-modules/height-decode.ts +41 -0
- package/src/shader-modules/hillshade.ts +70 -0
- package/src/shader-modules/index.ts +10 -0
- package/src/shader-modules/planar.ts +24 -0
- package/src/shader-modules/sphere-map.ts +38 -0
- package/src/shader-modules/triplanar.ts +45 -0
- package/src/sources/aligned_tile_source.ts +122 -0
- package/src/sources/data_source.ts +655 -0
- package/src/sources/decoded_tile_store.ts +245 -0
- package/src/sources/geojson.ts +300 -0
- package/src/sources/mvt.ts +247 -0
- package/src/sources/raster.ts +341 -0
- package/src/sources/shared_tile_source_adapter.ts +117 -0
- package/src/sources/sources.ts +10 -0
- package/src/sources/tile_source_adapter.ts +84 -0
- package/src/sources/tile_source_metadata.ts +65 -0
- package/src/sources/tile_source_state.ts +112 -0
- package/src/sources/topojson.ts +90 -0
- package/src/styles/feature_annotations.ts +16 -0
- package/src/styles/filter.ts +190 -0
- package/src/styles/geometry-style-types.ts +209 -0
- package/src/styles/globe_visibility_wgsl.ts +22 -0
- package/src/styles/layer-types.ts +45 -0
- package/src/styles/layer.ts +586 -0
- package/src/styles/lines/dasharray.ts +49 -0
- package/src/styles/lines/lines.ts +707 -0
- package/src/styles/lines/lines_wgsl.ts +224 -0
- package/src/styles/points/point-runtime-types.ts +125 -0
- package/src/styles/points/points.ts +1079 -0
- package/src/styles/points/points_fragment.glsl +126 -0
- package/src/styles/points/points_vertex.glsl +230 -0
- package/src/styles/points/points_wgsl.ts +189 -0
- package/src/styles/polygons/polygons.ts +268 -0
- package/src/styles/polygons/polygons_fragment.glsl +173 -0
- package/src/styles/polygons/polygons_vertex.glsl +213 -0
- package/src/styles/polygons/polygons_wgsl.ts +127 -0
- package/src/styles/property-types.ts +125 -0
- package/src/styles/raster/raster.ts +33 -0
- package/src/styles/raster/raster_globals.glsl +46 -0
- package/src/styles/style-mixing-types.ts +101 -0
- package/src/styles/style-runtime-types.ts +220 -0
- package/src/styles/style-schema.ts +133 -0
- package/src/styles/style.ts +1033 -0
- package/src/styles/style_globals.glsl +69 -0
- package/src/styles/style_manager.ts +464 -0
- package/src/styles/style_parser.ts +620 -0
- package/src/styles/text/font_manager.ts +180 -0
- package/src/styles/text/fontfaceobserver.d.ts +10 -0
- package/src/styles/text/text-types.ts +220 -0
- package/src/styles/text/text.ts +378 -0
- package/src/styles/text/text_canvas.ts +773 -0
- package/src/styles/text/text_labels.ts +436 -0
- package/src/styles/text/text_segments.ts +142 -0
- package/src/styles/text/text_settings.ts +228 -0
- package/src/styles/text/text_wgsl.ts +159 -0
- package/src/styles/text/text_wrap.ts +194 -0
- package/src/tile/globe_tile_preload.ts +40 -0
- package/src/tile/tangram_tileset_2d.ts +108 -0
- package/src/tile/tile-build-types.ts +155 -0
- package/src/tile/tile.ts +807 -0
- package/src/tile/tile_id.ts +172 -0
- package/src/tile/tile_manager.ts +889 -0
- package/src/tile/tile_pyramid.ts +119 -0
- package/src/tile/tile_resource_cache.ts +91 -0
- package/src/tile/tile_traversal_adapter.ts +132 -0
- package/src/types.ts +332 -0
- package/src/utils/debounce.ts +17 -0
- package/src/utils/debug_settings.ts +43 -0
- package/src/utils/errors.ts +12 -0
- package/src/utils/functions.ts +95 -0
- package/src/utils/geo.ts +364 -0
- package/src/utils/hash.ts +14 -0
- package/src/utils/log.ts +108 -0
- package/src/utils/media_capture.ts +193 -0
- package/src/utils/merge.ts +44 -0
- package/src/utils/obb.ts +134 -0
- package/src/utils/props.ts +43 -0
- package/src/utils/slice.ts +14 -0
- package/src/utils/subscribe.ts +58 -0
- package/src/utils/task.ts +154 -0
- package/src/utils/thread.ts +26 -0
- package/src/utils/urls.ts +223 -0
- package/src/utils/utils.ts +310 -0
- package/src/utils/vector.ts +197 -0
- package/src/utils/version.ts +8 -0
- package/src/utils/worker-types.ts +79 -0
- package/src/utils/worker_broker.ts +523 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Tangram
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) 2013-2016 Brett Camper and Mapzen
|
|
4
|
+
|
|
5
|
+
// Debounce a function
|
|
6
|
+
// https://davidwalsh.name/javascript-debounce-function
|
|
7
|
+
export default function debounce<ThisType, Arguments extends unknown[]>(
|
|
8
|
+
func: (this: ThisType, ...arguments_: Arguments) => void,
|
|
9
|
+
wait: number
|
|
10
|
+
): (this: ThisType, ...arguments_: Arguments) => void {
|
|
11
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
12
|
+
|
|
13
|
+
return function debounced(this: ThisType, ...arguments_: Arguments): void {
|
|
14
|
+
clearTimeout(timeout);
|
|
15
|
+
timeout = setTimeout(() => func.apply(this, arguments_), wait);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
export type DebugSettings = {
|
|
7
|
+
draw_label_collision_boxes: boolean;
|
|
8
|
+
draw_label_texture_boxes: boolean;
|
|
9
|
+
suppress_label_fade_in: boolean;
|
|
10
|
+
suppress_label_snap_animation: boolean;
|
|
11
|
+
show_hidden_labels: boolean;
|
|
12
|
+
layer_stats: boolean;
|
|
13
|
+
wireframe: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const debugSettings: DebugSettings = {
|
|
17
|
+
// draws a blue rectangle border around the collision box of a label
|
|
18
|
+
draw_label_collision_boxes: false,
|
|
19
|
+
|
|
20
|
+
// draws a green rectangle border within the texture box of a label
|
|
21
|
+
draw_label_texture_boxes: false,
|
|
22
|
+
|
|
23
|
+
// suppresses fade-in of labels
|
|
24
|
+
suppress_label_fade_in: false,
|
|
25
|
+
|
|
26
|
+
// suppresses animation of label snap to pixel grid
|
|
27
|
+
suppress_label_snap_animation: false,
|
|
28
|
+
|
|
29
|
+
// show hidden labels for debugging
|
|
30
|
+
show_hidden_labels: false,
|
|
31
|
+
|
|
32
|
+
// collect feature/geometry stats on styling layers
|
|
33
|
+
layer_stats: false,
|
|
34
|
+
|
|
35
|
+
// draw scene in wireframe mode
|
|
36
|
+
wireframe: false
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default debugSettings;
|
|
40
|
+
|
|
41
|
+
export function mergeDebugSettings(settings: Partial<DebugSettings>): void {
|
|
42
|
+
Object.assign(debugSettings, settings);
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
export class MethodNotImplemented extends Error {
|
|
7
|
+
constructor(methodName: string) {
|
|
8
|
+
super();
|
|
9
|
+
this.name = 'MethodNotImplemented';
|
|
10
|
+
this.message = 'Method ' + methodName + ' must be implemented in subclass';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
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 hashString from './hash';
|
|
7
|
+
|
|
8
|
+
export type CompiledFunction = ((...arguments_: unknown[]) => unknown) & {source: string};
|
|
9
|
+
export type FunctionStringWrapper = (source: string) => string;
|
|
10
|
+
export type FunctionStringCache = {
|
|
11
|
+
functions: Record<number, CompiledFunction>;
|
|
12
|
+
num_functions: number;
|
|
13
|
+
num_cached: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// cache of functions, keyed by unique source
|
|
17
|
+
const cache: FunctionStringCache = {
|
|
18
|
+
functions: {},
|
|
19
|
+
num_functions: 0,
|
|
20
|
+
num_cached: 0
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { cache as functionStringCache };
|
|
24
|
+
|
|
25
|
+
export function clearFunctionStringCache(): void {
|
|
26
|
+
cache.functions = {};
|
|
27
|
+
cache.num_functions = 0;
|
|
28
|
+
cache.num_cached = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Recursively parse an object, compiling string properties that look like functions
|
|
32
|
+
export function compileFunctionStrings<Value extends object>(value: Value, wrap?: FunctionStringWrapper): Value;
|
|
33
|
+
export function compileFunctionStrings<Value>(value: Value, wrap?: FunctionStringWrapper): Value | CompiledFunction;
|
|
34
|
+
export function compileFunctionStrings<Value>(
|
|
35
|
+
value: Value,
|
|
36
|
+
wrap?: FunctionStringWrapper
|
|
37
|
+
): Value | CompiledFunction {
|
|
38
|
+
// Convert string
|
|
39
|
+
if (typeof value === 'string') {
|
|
40
|
+
return compileFunctionString(value, wrap) as Value | CompiledFunction;
|
|
41
|
+
}
|
|
42
|
+
// Loop through object properties
|
|
43
|
+
if (value != null && typeof value === 'object') {
|
|
44
|
+
const record = value as Record<string, unknown>;
|
|
45
|
+
for (const property in record) {
|
|
46
|
+
record[property] = compileFunctionStrings(record[property], wrap);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Compile a string that looks like a function
|
|
53
|
+
export function compileFunctionString<Value>(
|
|
54
|
+
value: Value,
|
|
55
|
+
wrap?: FunctionStringWrapper
|
|
56
|
+
): Value | CompiledFunction {
|
|
57
|
+
// Parse function signature and body
|
|
58
|
+
const functionMatch =
|
|
59
|
+
typeof value === 'string' && value.match(/^\s*function[^(]*\(([^)]*)\)\s*?\{([\s\S]*)\}$/m);
|
|
60
|
+
|
|
61
|
+
if (functionMatch && functionMatch.length > 2) {
|
|
62
|
+
try {
|
|
63
|
+
// function body
|
|
64
|
+
const body = functionMatch[2];
|
|
65
|
+
const source = wrap ? wrap(body) : body;
|
|
66
|
+
|
|
67
|
+
// compile and cache by unique function source
|
|
68
|
+
const key = hashString(source);
|
|
69
|
+
if (cache.functions[key] === undefined) {
|
|
70
|
+
// function arguments extracted from signature
|
|
71
|
+
const parsedArguments = functionMatch[1]
|
|
72
|
+
.split(',')
|
|
73
|
+
.map(argument => argument.trim())
|
|
74
|
+
.filter(Boolean);
|
|
75
|
+
const functionArguments = parsedArguments.length > 0 ? parsedArguments : ['context'];
|
|
76
|
+
|
|
77
|
+
const compiledFunction = new Function(
|
|
78
|
+
functionArguments.toString(),
|
|
79
|
+
source
|
|
80
|
+
) as CompiledFunction;
|
|
81
|
+
compiledFunction.source = body;
|
|
82
|
+
cache.functions[key] = compiledFunction;
|
|
83
|
+
cache.num_functions++;
|
|
84
|
+
} else {
|
|
85
|
+
cache.num_cached++;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return cache.functions[key];
|
|
89
|
+
} catch {
|
|
90
|
+
// fall back to original value if parsing failed
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
}
|
package/src/utils/geo.ts
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
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
|
+
// Miscellaneous geo functions
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
projectLngLatToMetersWithMath,
|
|
10
|
+
unprojectMetersToLngLatWithMath
|
|
11
|
+
} from '../procedures/web-mercator-math';
|
|
12
|
+
import {PROJECTION_CONSTANTS, getMercatorMetersPerPixel} from '../scene/projection_math';
|
|
13
|
+
import {PACKED_HEIGHT_SCALE} from '../gl/vertex-constants';
|
|
14
|
+
|
|
15
|
+
export type Coordinate = number[];
|
|
16
|
+
export type Meters = {x: number; y: number};
|
|
17
|
+
export type Tile = {x: number; y: number; z: number};
|
|
18
|
+
export type Bounds = {sw: Meters; ne: Meters};
|
|
19
|
+
export type Geometry = {type: string; coordinates: unknown};
|
|
20
|
+
export type Transform = (coordinate: Coordinate) => void;
|
|
21
|
+
|
|
22
|
+
interface GeoNamespace {
|
|
23
|
+
default_source_max_zoom: number;
|
|
24
|
+
default_view_max_zoom: number;
|
|
25
|
+
max_style_zoom: number;
|
|
26
|
+
tile_size: number;
|
|
27
|
+
half_circumference_meters: number;
|
|
28
|
+
circumference_meters: number;
|
|
29
|
+
min_zoom_meters_per_pixel: number;
|
|
30
|
+
tile_scale: number;
|
|
31
|
+
units_per_pixel: number;
|
|
32
|
+
height_scale: number;
|
|
33
|
+
metersPerPixel(z: number): number;
|
|
34
|
+
metersPerTile(z: number): number;
|
|
35
|
+
unitsPerMeter(z: number): number;
|
|
36
|
+
metersForTile(tile: Tile): Meters;
|
|
37
|
+
tileForMeters(coordinates: Coordinate, zoom: number): Tile;
|
|
38
|
+
wrapTile(tile: Tile, mask?: {x: boolean; y: boolean}): Tile;
|
|
39
|
+
metersToLatLng(coordinates: Coordinate): Coordinate;
|
|
40
|
+
latLngToMeters(coordinates: Coordinate): Coordinate;
|
|
41
|
+
tileSpaceToLatlng(geometry: Geometry, z: number, min: Meters): Geometry;
|
|
42
|
+
copyGeometry(geometry: Geometry | null): Geometry | undefined;
|
|
43
|
+
transformGeometry(geometry: Geometry | null, transform: Transform): void;
|
|
44
|
+
boxIntersect(first: Bounds, second: Bounds): boolean;
|
|
45
|
+
findBoundingBox(polygon: Coordinate[][]): [number, number, number, number];
|
|
46
|
+
geometryType(type: string): 'point' | 'line' | 'polygon' | undefined;
|
|
47
|
+
centroid(polygon: Coordinate[][], relative?: boolean): Coordinate | undefined;
|
|
48
|
+
multiCentroid(polygons: Coordinate[][][]): Coordinate | null;
|
|
49
|
+
signedPolygonRingAreaSum(ring: Coordinate[]): number;
|
|
50
|
+
polygonRingArea(ring: Coordinate[]): number;
|
|
51
|
+
polygonArea(polygon: Coordinate[][] | null): number | undefined;
|
|
52
|
+
multiPolygonArea(polygons: Coordinate[][][]): number;
|
|
53
|
+
ringWinding(ring: Coordinate[]): 'CW' | 'CCW' | undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const Geo = {} as GeoNamespace;
|
|
57
|
+
export default Geo;
|
|
58
|
+
|
|
59
|
+
// Projection constants
|
|
60
|
+
Geo.default_source_max_zoom = 18;
|
|
61
|
+
Geo.default_view_max_zoom = 20;
|
|
62
|
+
Geo.max_style_zoom = 25; // max zoom at which styles will be evaluated
|
|
63
|
+
Geo.tile_size = PROJECTION_CONSTANTS.tileSize;
|
|
64
|
+
Geo.half_circumference_meters = Math.PI * PROJECTION_CONSTANTS.mercatorRadius;
|
|
65
|
+
Geo.circumference_meters = Geo.half_circumference_meters * 2;
|
|
66
|
+
Geo.min_zoom_meters_per_pixel = Geo.circumference_meters / Geo.tile_size; // min zoom draws world as 2 tiles wide
|
|
67
|
+
|
|
68
|
+
const meters_per_pixel: number[] = [];
|
|
69
|
+
Geo.metersPerPixel = function (z: number): number {
|
|
70
|
+
meters_per_pixel[z] = meters_per_pixel[z] || getMercatorMetersPerPixel(z);
|
|
71
|
+
return meters_per_pixel[z];
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const meters_per_tile: number[] = [];
|
|
75
|
+
Geo.metersPerTile = function (z: number): number {
|
|
76
|
+
meters_per_tile[z] = meters_per_tile[z] || Geo.circumference_meters / Math.pow(2, z);
|
|
77
|
+
return meters_per_tile[z];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Conversion functions based on an defined tile scale
|
|
81
|
+
Geo.tile_scale = 4096; // coordinates are locally scaled to the range [0, tile_scale]
|
|
82
|
+
Geo.units_per_pixel = Geo.tile_scale / Geo.tile_size;
|
|
83
|
+
Geo.height_scale = PACKED_HEIGHT_SCALE; // provides sub-meter precision for height values (16ths of a meters)
|
|
84
|
+
|
|
85
|
+
const units_per_meter: number[] = [];
|
|
86
|
+
Geo.unitsPerMeter = function (z: number): number {
|
|
87
|
+
units_per_meter[z] = units_per_meter[z] || Geo.tile_scale / (Geo.tile_size * Geo.metersPerPixel(z));
|
|
88
|
+
return units_per_meter[z];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Convert tile location to mercator meters - multiply by pixels per tile, then by meters per pixel, adjust for map origin
|
|
92
|
+
Geo.metersForTile = function (tile: Tile): Meters {
|
|
93
|
+
return {
|
|
94
|
+
x: tile.x * Geo.circumference_meters / Math.pow(2, tile.z) - Geo.half_circumference_meters,
|
|
95
|
+
y: -(tile.y * Geo.circumference_meters / Math.pow(2, tile.z) - Geo.half_circumference_meters)
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
Given a point in mercator meters and a zoom level, return the tile X/Y/Z that the point lies in
|
|
101
|
+
*/
|
|
102
|
+
Geo.tileForMeters = function ([x, y]: Coordinate, zoom: number): Tile {
|
|
103
|
+
return {
|
|
104
|
+
x: Math.floor((x + Geo.half_circumference_meters) / (Geo.circumference_meters / Math.pow(2, zoom))),
|
|
105
|
+
y: Math.floor((-y + Geo.half_circumference_meters) / (Geo.circumference_meters / Math.pow(2, zoom))),
|
|
106
|
+
z: zoom
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Wrap a tile to positive #s for zoom
|
|
111
|
+
// Optionally specify the axes to wrap
|
|
112
|
+
Geo.wrapTile = function({ x, y, z }: Tile, mask = { x: true, y: false }): Tile {
|
|
113
|
+
var m = (1 << z) - 1;
|
|
114
|
+
if (mask.x) {
|
|
115
|
+
x = x & m;
|
|
116
|
+
}
|
|
117
|
+
if (mask.y) {
|
|
118
|
+
y = y & m;
|
|
119
|
+
}
|
|
120
|
+
return { x, y, z };
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
Convert mercator meters to lat-lng, in-place
|
|
125
|
+
*/
|
|
126
|
+
Geo.metersToLatLng = function (c: Coordinate): Coordinate {
|
|
127
|
+
const converted = unprojectMetersToLngLatWithMath([c[0], c[1]]);
|
|
128
|
+
c[0] = converted[0];
|
|
129
|
+
c[1] = converted[1];
|
|
130
|
+
return c;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
Convert lat-lng to mercator meters, in-place
|
|
135
|
+
*/
|
|
136
|
+
Geo.latLngToMeters = function (c: Coordinate): Coordinate {
|
|
137
|
+
const converted = projectLngLatToMetersWithMath([c[0], c[1]]);
|
|
138
|
+
c[0] = converted[0];
|
|
139
|
+
c[1] = converted[1];
|
|
140
|
+
return c;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Transform from local tile coordinats to lat lng
|
|
144
|
+
Geo.tileSpaceToLatlng = function (geometry: Geometry, z: number, min: Meters): Geometry {
|
|
145
|
+
const units_per_meter = Geo.unitsPerMeter(z);
|
|
146
|
+
Geo.transformGeometry(geometry, (coord: Coordinate) => {
|
|
147
|
+
coord[0] = (coord[0] / units_per_meter) + min.x;
|
|
148
|
+
coord[1] = (coord[1] / units_per_meter) + min.y;
|
|
149
|
+
Geo.metersToLatLng(coord);
|
|
150
|
+
});
|
|
151
|
+
return geometry;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Copy GeoJSON geometry
|
|
155
|
+
Geo.copyGeometry = function (geometry: Geometry | null): Geometry | undefined {
|
|
156
|
+
if (geometry == null) {
|
|
157
|
+
return; // skip if missing geometry (valid GeoJSON)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const sourceCoordinates = geometry.coordinates as any;
|
|
161
|
+
const copy: Geometry = { type: geometry.type, coordinates: undefined };
|
|
162
|
+
|
|
163
|
+
if (geometry.type === 'Point') {
|
|
164
|
+
copy.coordinates = [sourceCoordinates[0], sourceCoordinates[1]];
|
|
165
|
+
}
|
|
166
|
+
else if (geometry.type === 'LineString' || geometry.type === 'MultiPoint') {
|
|
167
|
+
copy.coordinates = sourceCoordinates.map((c: Coordinate) => [c[0], c[1]]);
|
|
168
|
+
}
|
|
169
|
+
else if (geometry.type === 'Polygon' || geometry.type === 'MultiLineString') {
|
|
170
|
+
copy.coordinates = sourceCoordinates.map((ring: Coordinate[]) => ring.map(c => [c[0], c[1]]));
|
|
171
|
+
}
|
|
172
|
+
else if (geometry.type === 'MultiPolygon') {
|
|
173
|
+
copy.coordinates = sourceCoordinates.map((polygon: Coordinate[][]) => {
|
|
174
|
+
return polygon.map(ring => ring.map(c => [c[0], c[1]]));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// TODO: support GeometryCollection
|
|
178
|
+
return copy;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Run an in-place transform function on each cooordinate in a GeoJSON geometry
|
|
182
|
+
Geo.transformGeometry = function (geometry: Geometry | null, transform: Transform): void {
|
|
183
|
+
if (geometry == null) {
|
|
184
|
+
return; // skip if missing geometry (valid GeoJSON)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (geometry.type === 'Point') {
|
|
188
|
+
transform(geometry.coordinates as Coordinate);
|
|
189
|
+
}
|
|
190
|
+
else if (geometry.type === 'LineString' || geometry.type === 'MultiPoint') {
|
|
191
|
+
(geometry.coordinates as Coordinate[]).forEach(transform);
|
|
192
|
+
}
|
|
193
|
+
else if (geometry.type === 'Polygon' || geometry.type === 'MultiLineString') {
|
|
194
|
+
(geometry.coordinates as Coordinate[][]).forEach(ring => ring.forEach(transform));
|
|
195
|
+
}
|
|
196
|
+
else if (geometry.type === 'MultiPolygon') {
|
|
197
|
+
(geometry.coordinates as Coordinate[][][]).forEach(polygon => {
|
|
198
|
+
polygon.forEach(ring => ring.forEach(transform));
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// TODO: support GeometryCollection
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
Geo.boxIntersect = function (b1: Bounds, b2: Bounds): boolean {
|
|
205
|
+
return !(
|
|
206
|
+
b2.sw.x > b1.ne.x ||
|
|
207
|
+
b2.ne.x < b1.sw.x ||
|
|
208
|
+
b2.sw.y > b1.ne.y ||
|
|
209
|
+
b2.ne.y < b1.sw.y
|
|
210
|
+
);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Finds the axis-aligned bounding box for a polygon
|
|
214
|
+
Geo.findBoundingBox = function (polygon: Coordinate[][]): [number, number, number, number] {
|
|
215
|
+
var min_x = Infinity,
|
|
216
|
+
max_x = -Infinity,
|
|
217
|
+
min_y = Infinity,
|
|
218
|
+
max_y = -Infinity;
|
|
219
|
+
|
|
220
|
+
// Only need to examine outer ring (polygon[0])
|
|
221
|
+
var num_coords = polygon[0].length;
|
|
222
|
+
for (var c=0; c < num_coords; c++) {
|
|
223
|
+
var coord = polygon[0][c];
|
|
224
|
+
|
|
225
|
+
if (coord[0] < min_x) {
|
|
226
|
+
min_x = coord[0];
|
|
227
|
+
}
|
|
228
|
+
if (coord[1] < min_y) {
|
|
229
|
+
min_y = coord[1];
|
|
230
|
+
}
|
|
231
|
+
if (coord[0] > max_x) {
|
|
232
|
+
max_x = coord[0];
|
|
233
|
+
}
|
|
234
|
+
if (coord[1] > max_y) {
|
|
235
|
+
max_y = coord[1];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return [min_x, min_y, max_x, max_y];
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Convert geometry type to one of: 'point', 'line', 'polygon'
|
|
243
|
+
Geo.geometryType = function(type: string): 'point' | 'line' | 'polygon' | undefined {
|
|
244
|
+
if (type === 'Polygon' || type === 'MultiPolygon') {
|
|
245
|
+
return 'polygon';
|
|
246
|
+
}
|
|
247
|
+
else if (type === 'LineString' || type === 'MultiLineString') {
|
|
248
|
+
return 'line';
|
|
249
|
+
}
|
|
250
|
+
if (type === 'Point' || type === 'MultiPoint') {
|
|
251
|
+
return 'point';
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Geometric / weighted centroid of polygon
|
|
256
|
+
// Adapted from https://github.com/Leaflet/Leaflet/blob/c10f405a112142b19785967ce0e142132a6095ad/src/layer/vector/Polygon.js#L57
|
|
257
|
+
Geo.centroid = function (polygon: Coordinate[][], relative = true): Coordinate | undefined {
|
|
258
|
+
if (!polygon || polygon.length === 0) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let x = 0, y = 0, area = 0;
|
|
263
|
+
let ring = polygon[0]; // only use first ring for now
|
|
264
|
+
let len = ring.length;
|
|
265
|
+
|
|
266
|
+
// optionally calculate relative to first coordinate to avoid precision issues w/small polygons
|
|
267
|
+
let origin: Coordinate | undefined;
|
|
268
|
+
if (relative) {
|
|
269
|
+
const originCoordinate = ring[0];
|
|
270
|
+
origin = originCoordinate;
|
|
271
|
+
ring = ring.map(v => [v[0] - originCoordinate[0], v[1] - originCoordinate[1]]);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (let i = 0, j = len - 1; i < len; j = i, i++) {
|
|
275
|
+
let p0 = ring[i];
|
|
276
|
+
let p1 = ring[j];
|
|
277
|
+
let f = p0[1] * p1[0] - p1[1] * p0[0];
|
|
278
|
+
|
|
279
|
+
x += (p0[0] + p1[0]) * f;
|
|
280
|
+
y += (p0[1] + p1[1]) * f;
|
|
281
|
+
area += f * 3;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!area) {
|
|
285
|
+
return; // skip degenerate polygons
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const c: Coordinate = [x / area, y / area];
|
|
289
|
+
if (relative) {
|
|
290
|
+
c[0] += origin![0];
|
|
291
|
+
c[1] += origin![1];
|
|
292
|
+
}
|
|
293
|
+
return c;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
Geo.multiCentroid = function (polygons: Coordinate[][][]): Coordinate | null {
|
|
297
|
+
let n = 0;
|
|
298
|
+
let centroid: Coordinate | null = null;
|
|
299
|
+
|
|
300
|
+
for (let p=0; p < polygons.length; p++) {
|
|
301
|
+
let c = Geo.centroid(polygons[p]);
|
|
302
|
+
if (c) { // skip degenerate polygons
|
|
303
|
+
centroid = centroid || [0, 0];
|
|
304
|
+
centroid[0] += c[0];
|
|
305
|
+
centroid[1] += c[1];
|
|
306
|
+
n++;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (n > 0) {
|
|
311
|
+
centroid![0] /= n;
|
|
312
|
+
centroid![1] /= n;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return centroid; // will return null if all polygons were degenerate
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
Geo.signedPolygonRingAreaSum = function (ring: Coordinate[]): number {
|
|
319
|
+
let area = 0;
|
|
320
|
+
let n = ring.length;
|
|
321
|
+
|
|
322
|
+
for (let i = 0; i < n - 1; i++) {
|
|
323
|
+
let p0 = ring[i];
|
|
324
|
+
let p1 = ring[i+1];
|
|
325
|
+
|
|
326
|
+
area += p0[0] * p1[1] - p1[0] * p0[1];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
area += ring[n - 1][0] * ring[0][1] - ring[0][0] * ring[n - 1][1];
|
|
330
|
+
return area;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
Geo.polygonRingArea = function (ring: Coordinate[]): number {
|
|
334
|
+
return Math.abs(Geo.signedPolygonRingAreaSum(ring)) / 2;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// TODO: subtract inner rings
|
|
338
|
+
Geo.polygonArea = function (polygon: Coordinate[][] | null): number | undefined {
|
|
339
|
+
if (!polygon) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
return Geo.polygonRingArea(polygon[0]);
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
Geo.multiPolygonArea = function (polygons: Coordinate[][][]): number {
|
|
346
|
+
let area = 0;
|
|
347
|
+
|
|
348
|
+
for (let p=0; p < polygons.length; p++) {
|
|
349
|
+
area += Geo.polygonArea(polygons[p]) || 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return area;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
Geo.ringWinding = function (ring: Coordinate[]): 'CW' | 'CCW' | undefined {
|
|
356
|
+
let area = Geo.signedPolygonRingAreaSum(ring);
|
|
357
|
+
if (area > 0) {
|
|
358
|
+
return 'CW';
|
|
359
|
+
}
|
|
360
|
+
else if (area < 0) {
|
|
361
|
+
return 'CCW';
|
|
362
|
+
}
|
|
363
|
+
// return undefined on zero area polygon
|
|
364
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Tangram
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) 2013-2016 Brett Camper and Mapzen
|
|
4
|
+
|
|
5
|
+
// http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
|
|
6
|
+
export default function hashString(string: string): number {
|
|
7
|
+
let hash = 0;
|
|
8
|
+
|
|
9
|
+
for (let index = 0; index < string.length; index++) {
|
|
10
|
+
hash = (hash << 5) - hash + string.charCodeAt(index);
|
|
11
|
+
hash |= 0;
|
|
12
|
+
}
|
|
13
|
+
return hash;
|
|
14
|
+
}
|
package/src/utils/log.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
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 version from './version';
|
|
7
|
+
import Thread from './thread';
|
|
8
|
+
import WorkerBroker from './worker_broker';
|
|
9
|
+
|
|
10
|
+
import type {BrokerWorker} from './worker-types';
|
|
11
|
+
|
|
12
|
+
const workerBroker = WorkerBroker;
|
|
13
|
+
|
|
14
|
+
const LEVELS = {
|
|
15
|
+
silent: -1,
|
|
16
|
+
error: 0,
|
|
17
|
+
warn: 1,
|
|
18
|
+
info: 2,
|
|
19
|
+
debug: 3,
|
|
20
|
+
trace: 4
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
/** Supported renderer log levels. */
|
|
24
|
+
export type LogLevel = keyof typeof LEVELS;
|
|
25
|
+
|
|
26
|
+
/** Per-message renderer logging options. */
|
|
27
|
+
export type LogOptions = {level: LogLevel; once?: boolean};
|
|
28
|
+
|
|
29
|
+
type ConsoleMethod = (...messages: unknown[]) => void;
|
|
30
|
+
|
|
31
|
+
/** Renderer logger with shared level and worker controls. */
|
|
32
|
+
export interface Logger {
|
|
33
|
+
(options: LogLevel | LogOptions, ...messages: unknown[]): Promise<boolean>;
|
|
34
|
+
level: LogLevel;
|
|
35
|
+
workers: BrokerWorker[] | null;
|
|
36
|
+
setLevel(level: LogLevel): void;
|
|
37
|
+
setWorkers?(workers: BrokerWorker[] | null): void;
|
|
38
|
+
reset?(): void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const methods: Partial<Record<LogLevel, ConsoleMethod>> = {};
|
|
42
|
+
let loggedOnce: Record<string, true> = {};
|
|
43
|
+
|
|
44
|
+
function getMethodForLevel(level: LogLevel): ConsoleMethod | undefined {
|
|
45
|
+
if (!methods[level]) {
|
|
46
|
+
const consoleMethods = console as unknown as Record<string, ConsoleMethod | undefined>;
|
|
47
|
+
methods[level] = (consoleMethods[level] || console.log).bind(console);
|
|
48
|
+
}
|
|
49
|
+
return methods[level];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const log = (async (
|
|
53
|
+
options: LogLevel | LogOptions,
|
|
54
|
+
...messages: unknown[]
|
|
55
|
+
): Promise<boolean> => {
|
|
56
|
+
const level = typeof options === 'object' ? options.level : options;
|
|
57
|
+
if (LEVELS[level] > LEVELS[log.level]) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (Thread.is_worker) {
|
|
62
|
+
return workerBroker.postMessage<boolean>(
|
|
63
|
+
{method: '_logProxy', stringify: true},
|
|
64
|
+
options,
|
|
65
|
+
...messages
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof options === 'object' && options.once === true) {
|
|
70
|
+
const key = JSON.stringify(messages);
|
|
71
|
+
if (loggedOnce[key]) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
loggedOnce[key] = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const logger = getMethodForLevel(level);
|
|
78
|
+
if (messages.length > 1) {
|
|
79
|
+
logger!(`Tangram ${version} [${level}]: ${messages[0]}`, ...messages.slice(1));
|
|
80
|
+
} else {
|
|
81
|
+
logger!(`Tangram ${version} [${level}]: ${messages[0]}`);
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}) as Logger;
|
|
85
|
+
|
|
86
|
+
log.level = 'info';
|
|
87
|
+
log.workers = null;
|
|
88
|
+
|
|
89
|
+
log.setLevel = (level: LogLevel): void => {
|
|
90
|
+
log.level = level;
|
|
91
|
+
if (Thread.is_main && Array.isArray(log.workers)) {
|
|
92
|
+
workerBroker.postMessage(log.workers, '_logSetLevelProxy', level);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
if (!Thread.is_worker) {
|
|
97
|
+
log.setWorkers = (workers: BrokerWorker[] | null): void => {
|
|
98
|
+
log.workers = workers;
|
|
99
|
+
};
|
|
100
|
+
log.reset = (): void => {
|
|
101
|
+
loggedOnce = {};
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
WorkerBroker.addTarget('_logProxy', log);
|
|
106
|
+
WorkerBroker.addTarget('_logSetLevelProxy', log.setLevel);
|
|
107
|
+
|
|
108
|
+
export default log;
|