@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,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
|
+
}
|