@loaders.gl/services 5.0.0-alpha.7 → 5.0.0-alpha.9
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 +7 -46
- package/dist/authentication.d.ts +22 -9
- package/dist/authentication.d.ts.map +1 -1
- package/dist/authentication.js +28 -11
- package/dist/authentication.js.map +1 -1
- package/dist/index.cjs +301 -23886
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +2 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -20
- package/dist/index.js.map +1 -1
- package/package.json +6 -16
- package/src/authentication.ts +31 -19
- package/src/index.ts +3 -84
- package/dist/arcgis/arcgis-capability-graph.d.ts +0 -48
- package/dist/arcgis/arcgis-capability-graph.d.ts.map +0 -1
- package/dist/arcgis/arcgis-capability-graph.js +0 -220
- package/dist/arcgis/arcgis-capability-graph.js.map +0 -1
- package/dist/arcgis/arcgis-feature-server-source-loader.d.ts +0 -94
- package/dist/arcgis/arcgis-feature-server-source-loader.d.ts.map +0 -1
- package/dist/arcgis/arcgis-feature-server-source-loader.js +0 -231
- package/dist/arcgis/arcgis-feature-server-source-loader.js.map +0 -1
- package/dist/arcgis/arcgis-image-server-source-loader.d.ts +0 -96
- package/dist/arcgis/arcgis-image-server-source-loader.d.ts.map +0 -1
- package/dist/arcgis/arcgis-image-server-source-loader.js +0 -143
- package/dist/arcgis/arcgis-image-server-source-loader.js.map +0 -1
- package/dist/arcgis/arcgis-image-tile-source-loader.d.ts +0 -71
- package/dist/arcgis/arcgis-image-tile-source-loader.d.ts.map +0 -1
- package/dist/arcgis/arcgis-image-tile-source-loader.js +0 -153
- package/dist/arcgis/arcgis-image-tile-source-loader.js.map +0 -1
- package/dist/arcgis/arcgis-map-tile-source-loader.d.ts +0 -106
- package/dist/arcgis/arcgis-map-tile-source-loader.d.ts.map +0 -1
- package/dist/arcgis/arcgis-map-tile-source-loader.js +0 -202
- package/dist/arcgis/arcgis-map-tile-source-loader.js.map +0 -1
- package/dist/arcgis/arcgis-scene-aggregation.d.ts +0 -34
- package/dist/arcgis/arcgis-scene-aggregation.d.ts.map +0 -1
- package/dist/arcgis/arcgis-scene-aggregation.js +0 -57
- package/dist/arcgis/arcgis-scene-aggregation.js.map +0 -1
- package/dist/arcgis/arcgis-scene-server-source-loader.d.ts +0 -112
- package/dist/arcgis/arcgis-scene-server-source-loader.d.ts.map +0 -1
- package/dist/arcgis/arcgis-scene-server-source-loader.js +0 -157
- package/dist/arcgis/arcgis-scene-server-source-loader.js.map +0 -1
- package/dist/arcgis/arcgis-server.d.ts +0 -15
- package/dist/arcgis/arcgis-server.d.ts.map +0 -1
- package/dist/arcgis/arcgis-server.js +0 -41
- package/dist/arcgis/arcgis-server.js.map +0 -1
- package/dist/arcgis/arcgis-url-utils.d.ts +0 -3
- package/dist/arcgis/arcgis-url-utils.d.ts.map +0 -1
- package/dist/arcgis/arcgis-url-utils.js +0 -23
- package/dist/arcgis/arcgis-url-utils.js.map +0 -1
- package/dist/arcgis/arcgis-vector-tile-server-source-loader.d.ts +0 -115
- package/dist/arcgis/arcgis-vector-tile-server-source-loader.d.ts.map +0 -1
- package/dist/arcgis/arcgis-vector-tile-server-source-loader.js +0 -156
- package/dist/arcgis/arcgis-vector-tile-server-source-loader.js.map +0 -1
- package/dist/service-registry.d.ts +0 -18
- package/dist/service-registry.d.ts.map +0 -1
- package/dist/service-registry.js +0 -29
- package/dist/service-registry.js.map +0 -1
- package/src/arcgis/arcgis-capability-graph.ts +0 -295
- package/src/arcgis/arcgis-feature-server-source-loader.ts +0 -346
- package/src/arcgis/arcgis-image-server-source-loader.ts +0 -242
- package/src/arcgis/arcgis-image-tile-source-loader.ts +0 -206
- package/src/arcgis/arcgis-map-tile-source-loader.ts +0 -286
- package/src/arcgis/arcgis-scene-aggregation.ts +0 -90
- package/src/arcgis/arcgis-scene-server-source-loader.ts +0 -258
- package/src/arcgis/arcgis-server.ts +0 -61
- package/src/arcgis/arcgis-url-utils.ts +0 -26
- package/src/arcgis/arcgis-vector-tile-server-source-loader.ts +0 -233
- package/src/service-registry.ts +0 -43
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
// loaders.gl
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Copyright (c) vis.gl contributors
|
|
4
|
-
|
|
5
|
-
import type {ImageType} from '@loaders.gl/images';
|
|
6
|
-
import {ImageLoader} from '@loaders.gl/images';
|
|
7
|
-
import type {
|
|
8
|
-
CoreAPI,
|
|
9
|
-
DataSourceOptions,
|
|
10
|
-
GetTileDataParameters,
|
|
11
|
-
GetTileParameters,
|
|
12
|
-
SourceLoader,
|
|
13
|
-
TileSource,
|
|
14
|
-
TileSourceMetadata
|
|
15
|
-
} from '@loaders.gl/loader-utils';
|
|
16
|
-
import {DataSource} from '@loaders.gl/loader-utils';
|
|
17
|
-
import type {LERCData} from '@loaders.gl/lerc';
|
|
18
|
-
import {LERCLoader} from '@loaders.gl/lerc';
|
|
19
|
-
|
|
20
|
-
/** Options for the ArcGIS ImageServer tile source. */
|
|
21
|
-
export type ArcGISImageTileSourceLoaderOptions = DataSourceOptions & {
|
|
22
|
-
'arcgis-image-server-tiles'?: {
|
|
23
|
-
/** Tile size used for exportImage requests. */
|
|
24
|
-
tileSize?: number;
|
|
25
|
-
/** Optional service URL pool for simple request distribution. */
|
|
26
|
-
urls?: string[];
|
|
27
|
-
/** Additional exportImage parameters. */
|
|
28
|
-
parameters?: Record<string, string | number | boolean>;
|
|
29
|
-
/** Response format, using LERC for analytical raster tiles. */
|
|
30
|
-
format?: 'png32' | 'lerc';
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/** A tile source that renders ArcGIS ImageServer exports as deck.gl tiles. */
|
|
35
|
-
export class ArcGISImageTileSource
|
|
36
|
-
extends DataSource<string, ArcGISImageTileSourceLoaderOptions>
|
|
37
|
-
implements TileSource
|
|
38
|
-
{
|
|
39
|
-
/** MIME type represented by the tile response. */
|
|
40
|
-
readonly mimeType: string;
|
|
41
|
-
|
|
42
|
-
/** Cached ImageServer metadata. */
|
|
43
|
-
private _metadata: any | null = null;
|
|
44
|
-
/** In-flight metadata request shared by concurrent callers. */
|
|
45
|
-
private _metadataPromise: Promise<any> | null = null;
|
|
46
|
-
/** Parameters applied to subsequent export requests. */
|
|
47
|
-
private _runtimeParameters: Record<string, string | number | boolean> = {};
|
|
48
|
-
|
|
49
|
-
/** Creates an ArcGIS ImageServer tile source. */
|
|
50
|
-
constructor(url: string, options: ArcGISImageTileSourceLoaderOptions = {}, coreApi?: CoreAPI) {
|
|
51
|
-
super(url.replace(/\/$/, ''), options, ArcGISImageTileSourceLoader.defaultOptions, coreApi);
|
|
52
|
-
this.mimeType = this._getResponseFormat() === 'lerc' ? 'application/octet-stream' : 'image/png';
|
|
53
|
-
this.getTileData = this.getTileData.bind(this);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Returns normalized ImageServer metadata. */
|
|
57
|
-
async getMetadata(): Promise<TileSourceMetadata> {
|
|
58
|
-
const metadata = await this._getMetadata();
|
|
59
|
-
const extent = metadata.fullExtent || metadata.extent;
|
|
60
|
-
const spatialReference = metadata.spatialReference || extent?.spatialReference;
|
|
61
|
-
return {
|
|
62
|
-
name: metadata.name || metadata.serviceDescription || '',
|
|
63
|
-
title: metadata.name || metadata.serviceDescription || '',
|
|
64
|
-
abstract: metadata.description || metadata.serviceDescription || '',
|
|
65
|
-
attributions: metadata.copyrightText ? [metadata.copyrightText] : undefined,
|
|
66
|
-
boundingBox: extent
|
|
67
|
-
? [
|
|
68
|
-
[extent.xmin, extent.ymin],
|
|
69
|
-
[extent.xmax, extent.ymax]
|
|
70
|
-
]
|
|
71
|
-
: undefined,
|
|
72
|
-
layer: {
|
|
73
|
-
name: metadata.name || '',
|
|
74
|
-
srs: spatialReference?.wkid ? [`EPSG:${spatialReference.wkid}`] : [],
|
|
75
|
-
layers: []
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Fetches one ImageServer export tile. */
|
|
81
|
-
async getTile(
|
|
82
|
-
parameters: GetTileParameters,
|
|
83
|
-
signal?: AbortSignal
|
|
84
|
-
): Promise<ImageType | LERCData | null> {
|
|
85
|
-
const response = await this.fetch(this.getTileURL(parameters), signal ? {signal} : undefined);
|
|
86
|
-
if (!response.ok) {
|
|
87
|
-
throw new Error(
|
|
88
|
-
`ArcGIS ImageServer tile request failed: ${response.status} ${response.statusText}`
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
const loader = this._getResponseFormat() === 'lerc' ? LERCLoader : ImageLoader;
|
|
92
|
-
return (await this.coreApi.parse(
|
|
93
|
-
await response.arrayBuffer(),
|
|
94
|
-
loader,
|
|
95
|
-
this.loadOptions
|
|
96
|
-
)) as ImageType;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** Fetches a tile using the deck.gl-compatible request shape. */
|
|
100
|
-
async getTileData(parameters: GetTileDataParameters): Promise<ImageType | LERCData | null> {
|
|
101
|
-
return this.getTile(parameters.index, parameters.signal);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** Updates parameters applied to subsequent ImageServer export requests. */
|
|
105
|
-
updateParameters(parameters: Record<string, string | number | boolean>): void {
|
|
106
|
-
this._runtimeParameters = {...this._runtimeParameters, ...parameters};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Builds an ImageServer exportImage URL for one web-mercator tile. */
|
|
110
|
-
getTileURL(parameters: GetTileParameters, tileSize?: number): string {
|
|
111
|
-
const options = this.options['arcgis-image-server-tiles'] || {};
|
|
112
|
-
const resolvedTileSize = tileSize || options.tileSize || 256;
|
|
113
|
-
const [west, south, east, north] = getWebMercatorTileBounds(parameters);
|
|
114
|
-
const url = new URL(this.getServiceURL(parameters));
|
|
115
|
-
url.pathname = `${url.pathname.replace(/\/$/, '')}/exportImage`;
|
|
116
|
-
const requestParameters = {
|
|
117
|
-
f: 'image',
|
|
118
|
-
bbox: `${west},${south},${east},${north}`,
|
|
119
|
-
bboxSR: 3857,
|
|
120
|
-
imageSR: 3857,
|
|
121
|
-
size: `${resolvedTileSize},${resolvedTileSize}`,
|
|
122
|
-
format: this._getResponseFormat(),
|
|
123
|
-
transparent: true,
|
|
124
|
-
...options.parameters,
|
|
125
|
-
...this._runtimeParameters
|
|
126
|
-
};
|
|
127
|
-
for (const [key, value] of Object.entries(requestParameters)) {
|
|
128
|
-
url.searchParams.set(key, String(value));
|
|
129
|
-
}
|
|
130
|
-
return url.toString();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Fetches the ImageServer metadata document. */
|
|
134
|
-
private async _loadMetadata(): Promise<any> {
|
|
135
|
-
const url = new URL(this.url);
|
|
136
|
-
url.searchParams.set('f', 'pjson');
|
|
137
|
-
const response = await this.fetch(url.toString());
|
|
138
|
-
if (!response.ok) {
|
|
139
|
-
throw new Error(`ArcGIS ImageServer metadata request failed: ${response.status}`);
|
|
140
|
-
}
|
|
141
|
-
return response.json();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Returns cached metadata and shares a single request among concurrent callers. */
|
|
145
|
-
private async _getMetadata(): Promise<any> {
|
|
146
|
-
if (this._metadata) return this._metadata;
|
|
147
|
-
if (!this._metadataPromise) {
|
|
148
|
-
this._metadataPromise = this._loadMetadata();
|
|
149
|
-
}
|
|
150
|
-
try {
|
|
151
|
-
const metadata = await this._metadataPromise;
|
|
152
|
-
this._metadata = metadata;
|
|
153
|
-
return metadata;
|
|
154
|
-
} finally {
|
|
155
|
-
this._metadataPromise = null;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** Selects a service endpoint for a tile using a stable URL-pool mapping. */
|
|
160
|
-
private getServiceURL(parameters: GetTileParameters): string {
|
|
161
|
-
const urls = this.options['arcgis-image-server-tiles']?.urls;
|
|
162
|
-
return urls?.length ? urls[(parameters.x + parameters.y) % urls.length] : this.url;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/** Returns the response format after applying configured and runtime overrides. */
|
|
166
|
-
private _getResponseFormat(): 'png32' | 'lerc' {
|
|
167
|
-
const options = this.options['arcgis-image-server-tiles'] || {};
|
|
168
|
-
const format = this._runtimeParameters.format || options.parameters?.format || options.format;
|
|
169
|
-
return format === 'lerc' ? 'lerc' : 'png32';
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** Source loader for ArcGIS ImageServer export tiles. */
|
|
174
|
-
export const ArcGISImageTileSourceLoader = {
|
|
175
|
-
dataType: null as unknown as ArcGISImageTileSource,
|
|
176
|
-
batchType: null as never,
|
|
177
|
-
name: 'ArcGIS ImageServer tiles',
|
|
178
|
-
id: 'arcgis-image-server-tiles',
|
|
179
|
-
module: 'services',
|
|
180
|
-
version: '0.0.0',
|
|
181
|
-
extensions: [],
|
|
182
|
-
mimeTypes: [],
|
|
183
|
-
type: 'arcgis-image-server-tiles',
|
|
184
|
-
fromUrl: true,
|
|
185
|
-
fromBlob: false,
|
|
186
|
-
options: {'arcgis-image-server-tiles': {}},
|
|
187
|
-
defaultOptions: {'arcgis-image-server-tiles': {}},
|
|
188
|
-
testURL: (url: string): boolean => /imageserver/i.test(url),
|
|
189
|
-
createDataSource: (
|
|
190
|
-
url: string,
|
|
191
|
-
options: ArcGISImageTileSourceLoaderOptions = {},
|
|
192
|
-
coreApi?: CoreAPI
|
|
193
|
-
) => new ArcGISImageTileSource(url, options, coreApi)
|
|
194
|
-
} as const satisfies SourceLoader<ArcGISImageTileSource>;
|
|
195
|
-
|
|
196
|
-
/** Calculates the Web Mercator extent represented by an XYZ tile. */
|
|
197
|
-
function getWebMercatorTileBounds(parameters: GetTileParameters): [number, number, number, number] {
|
|
198
|
-
const worldSize = 20037508.342789244;
|
|
199
|
-
const tileCount = 2 ** parameters.z;
|
|
200
|
-
const tileSize = (worldSize * 2) / tileCount;
|
|
201
|
-
const west = -worldSize + parameters.x * tileSize;
|
|
202
|
-
const east = west + tileSize;
|
|
203
|
-
const north = worldSize - parameters.y * tileSize;
|
|
204
|
-
const south = north - tileSize;
|
|
205
|
-
return [west, south, east, north];
|
|
206
|
-
}
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
// loaders.gl
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Copyright (c) vis.gl contributors
|
|
4
|
-
|
|
5
|
-
import type {ImageType} from '@loaders.gl/images';
|
|
6
|
-
import {ImageLoader} from '@loaders.gl/images';
|
|
7
|
-
import type {
|
|
8
|
-
CoreAPI,
|
|
9
|
-
DataSourceOptions,
|
|
10
|
-
GetTileDataParameters,
|
|
11
|
-
GetTileParameters,
|
|
12
|
-
SourceLoader,
|
|
13
|
-
TileSource,
|
|
14
|
-
TileSourceMetadata
|
|
15
|
-
} from '@loaders.gl/loader-utils';
|
|
16
|
-
import {DataSource} from '@loaders.gl/loader-utils';
|
|
17
|
-
|
|
18
|
-
/** Options for an ArcGIS cached MapServer tile source. */
|
|
19
|
-
export type ArcGISMapTileSourceLoaderOptions = DataSourceOptions & {
|
|
20
|
-
'arcgis-map-server'?: {
|
|
21
|
-
/** Select cached tiles, dynamic export tiles, or automatic metadata-based selection. */
|
|
22
|
-
mode?: 'cached' | 'dynamic' | 'auto';
|
|
23
|
-
/** Tile size used for dynamic export requests. */
|
|
24
|
-
tileSize?: number;
|
|
25
|
-
/** Optional custom tile URL template. */
|
|
26
|
-
urlTemplate?: string;
|
|
27
|
-
/** Optional service URL pool for simple request distribution. */
|
|
28
|
-
urls?: string[];
|
|
29
|
-
/** Additional query parameters sent to the metadata endpoint. */
|
|
30
|
-
parameters?: Record<string, string>;
|
|
31
|
-
/** Metadata document supplied by the application. */
|
|
32
|
-
metadata?: ArcGISMapServerMetadata;
|
|
33
|
-
/** Default parameters forwarded to MapServer `export` requests. */
|
|
34
|
-
exportParameters?: Record<string, string | number | boolean>;
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/** Relevant normalized fields from an ArcGIS MapServer metadata document. */
|
|
39
|
-
export type ArcGISMapServerMetadata = {
|
|
40
|
-
name?: string;
|
|
41
|
-
description?: string;
|
|
42
|
-
serviceDescription?: string;
|
|
43
|
-
copyrightText?: string;
|
|
44
|
-
fullExtent?: {xmin: number; ymin: number; xmax: number; ymax: number; spatialReference?: unknown};
|
|
45
|
-
spatialReference?: unknown;
|
|
46
|
-
tileInfo?: {
|
|
47
|
-
lods?: {level: number}[];
|
|
48
|
-
rows?: number;
|
|
49
|
-
cols?: number;
|
|
50
|
-
format?: string;
|
|
51
|
-
spatialReference?: unknown;
|
|
52
|
-
origin?: {x: number; y: number};
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/** Parameters that can be changed between ArcGIS map tile requests. */
|
|
57
|
-
export type ArcGISMapTileParameters = Record<string, string | number | boolean>;
|
|
58
|
-
|
|
59
|
-
/** ArcGIS MapServer source for cached `/tile/{z}/{y}/{x}` image tiles. */
|
|
60
|
-
export class ArcGISMapTileSource
|
|
61
|
-
extends DataSource<string, ArcGISMapTileSourceLoaderOptions>
|
|
62
|
-
implements TileSource
|
|
63
|
-
{
|
|
64
|
-
/** MIME type rendered by the generic deck.gl tile adapter. */
|
|
65
|
-
readonly mimeType = 'image/png';
|
|
66
|
-
|
|
67
|
-
/** Cached service metadata. */
|
|
68
|
-
private _metadata: ArcGISMapServerMetadata | null = null;
|
|
69
|
-
/** In-flight metadata request shared by concurrent callers. */
|
|
70
|
-
private _metadataPromise: Promise<ArcGISMapServerMetadata> | null = null;
|
|
71
|
-
/** Parameters applied to subsequent dynamic exports. */
|
|
72
|
-
private _runtimeParameters: ArcGISMapTileParameters = {};
|
|
73
|
-
|
|
74
|
-
/** Creates an ArcGIS MapServer tile source. */
|
|
75
|
-
constructor(url: string, options: ArcGISMapTileSourceLoaderOptions = {}, coreApi?: CoreAPI) {
|
|
76
|
-
super(url.replace(/\/$/, ''), options, ArcGISMapTileSourceLoader.defaultOptions, coreApi);
|
|
77
|
-
this.getTileData = this.getTileData.bind(this);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Loads and normalizes ArcGIS service metadata. */
|
|
81
|
-
async getMetadata(): Promise<TileSourceMetadata> {
|
|
82
|
-
const metadata = await this._getMetadata();
|
|
83
|
-
const extent = metadata.fullExtent;
|
|
84
|
-
const spatialReference = metadata.spatialReference || extent?.spatialReference;
|
|
85
|
-
const spatialReferenceWkid = (spatialReference as {wkid?: number} | undefined)?.wkid;
|
|
86
|
-
return {
|
|
87
|
-
name: metadata.name || '',
|
|
88
|
-
title: metadata.name || '',
|
|
89
|
-
abstract: metadata.description || metadata.serviceDescription || '',
|
|
90
|
-
attributions: metadata.copyrightText ? [metadata.copyrightText] : undefined,
|
|
91
|
-
minZoom: 0,
|
|
92
|
-
maxZoom: metadata.tileInfo?.lods?.length
|
|
93
|
-
? Math.max(...metadata.tileInfo.lods.map(lod => lod.level))
|
|
94
|
-
: undefined,
|
|
95
|
-
boundingBox: extent
|
|
96
|
-
? [
|
|
97
|
-
[extent.xmin, extent.ymin],
|
|
98
|
-
[extent.xmax, extent.ymax]
|
|
99
|
-
]
|
|
100
|
-
: undefined,
|
|
101
|
-
layer: {
|
|
102
|
-
name: metadata.name || '',
|
|
103
|
-
srs: spatialReferenceWkid ? [`EPSG:${spatialReferenceWkid}`] : [],
|
|
104
|
-
layers: []
|
|
105
|
-
},
|
|
106
|
-
tileGrid: metadata.tileInfo
|
|
107
|
-
? {
|
|
108
|
-
crs: (metadata.tileInfo.spatialReference as {wkid?: number} | undefined)?.wkid
|
|
109
|
-
? `EPSG:${(metadata.tileInfo.spatialReference as {wkid: number}).wkid}`
|
|
110
|
-
: undefined,
|
|
111
|
-
tileSize:
|
|
112
|
-
metadata.tileInfo.rows && metadata.tileInfo.cols
|
|
113
|
-
? [metadata.tileInfo.cols, metadata.tileInfo.rows]
|
|
114
|
-
: undefined,
|
|
115
|
-
origin: metadata.tileInfo.origin
|
|
116
|
-
? [metadata.tileInfo.origin.x, metadata.tileInfo.origin.y]
|
|
117
|
-
: undefined,
|
|
118
|
-
matrixIds: metadata.tileInfo.lods?.map(lod => String(lod.level))
|
|
119
|
-
}
|
|
120
|
-
: undefined
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Fetches and decodes one cached ArcGIS tile. */
|
|
125
|
-
async getTile(parameters: GetTileParameters, signal?: AbortSignal): Promise<ImageType | null> {
|
|
126
|
-
const options = this.options['arcgis-map-server'] || {};
|
|
127
|
-
const mode = options.mode || 'auto';
|
|
128
|
-
const metadata = mode === 'auto' ? await this._getMetadata() : null;
|
|
129
|
-
const useCachedTiles = mode === 'cached' || (mode === 'auto' && isCompatibleCache(metadata));
|
|
130
|
-
const tileURL = useCachedTiles
|
|
131
|
-
? this.getTileURL(parameters)
|
|
132
|
-
: this.getExportTileURL(parameters, options.tileSize || 256);
|
|
133
|
-
const response = await this.fetch(tileURL, signal ? {signal} : undefined);
|
|
134
|
-
if (!response.ok) {
|
|
135
|
-
throw new Error(
|
|
136
|
-
`ArcGIS MapServer tile request failed: ${response.status} ${response.statusText}`
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
return (await this.coreApi.parse(
|
|
140
|
-
await response.arrayBuffer(),
|
|
141
|
-
ImageLoader,
|
|
142
|
-
this.loadOptions
|
|
143
|
-
)) as ImageType;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Fetches a tile using the deck.gl-compatible request shape. */
|
|
147
|
-
async getTileData(parameters: GetTileDataParameters): Promise<ImageType | null> {
|
|
148
|
-
return this.getTile(parameters.index, parameters.signal);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** Builds the standard ArcGIS cached tile URL. */
|
|
152
|
-
getTileURL(parameters: GetTileParameters): string {
|
|
153
|
-
const template = this.options['arcgis-map-server']?.urlTemplate;
|
|
154
|
-
if (template) {
|
|
155
|
-
const templateURL = new URL(
|
|
156
|
-
template
|
|
157
|
-
.replaceAll('{z}', String(parameters.z))
|
|
158
|
-
.replaceAll('{y}', String(parameters.y))
|
|
159
|
-
.replaceAll('{x}', String(parameters.x))
|
|
160
|
-
);
|
|
161
|
-
return templateURL.toString();
|
|
162
|
-
}
|
|
163
|
-
const url = new URL(this.getServiceURL(parameters));
|
|
164
|
-
url.pathname = `${url.pathname.replace(/\/$/, '')}/tile/${parameters.z}/${parameters.y}/${parameters.x}`;
|
|
165
|
-
return url.toString();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/** Updates parameters applied to subsequent dynamic MapServer export requests. */
|
|
169
|
-
updateParameters(parameters: ArcGISMapTileParameters): void {
|
|
170
|
-
this._runtimeParameters = {...this._runtimeParameters, ...parameters};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** Builds a dynamic MapServer `export` request for one web-mercator tile. */
|
|
174
|
-
getExportTileURL(parameters: GetTileParameters, tileSize?: number): string {
|
|
175
|
-
const options = this.options['arcgis-map-server'] || {};
|
|
176
|
-
const resolvedTileSize = tileSize || options.tileSize || 256;
|
|
177
|
-
const [west, south, east, north] = getWebMercatorTileBounds(parameters);
|
|
178
|
-
const url = new URL(this.getServiceURL(parameters));
|
|
179
|
-
url.pathname = `${url.pathname.replace(/\/$/, '')}/export`;
|
|
180
|
-
const searchParameters: ArcGISMapTileParameters = {
|
|
181
|
-
f: 'image',
|
|
182
|
-
bbox: `${west},${south},${east},${north}`,
|
|
183
|
-
bboxSR: 3857,
|
|
184
|
-
imageSR: 3857,
|
|
185
|
-
size: `${resolvedTileSize},${resolvedTileSize}`,
|
|
186
|
-
format: 'png32',
|
|
187
|
-
transparent: true,
|
|
188
|
-
...options.exportParameters,
|
|
189
|
-
...this._runtimeParameters
|
|
190
|
-
};
|
|
191
|
-
for (const [key, value] of Object.entries(searchParameters)) {
|
|
192
|
-
url.searchParams.set(key, String(value));
|
|
193
|
-
}
|
|
194
|
-
return url.toString();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** Fetches the MapServer metadata document and applies configured parameters. */
|
|
198
|
-
private async _loadMetadata(): Promise<ArcGISMapServerMetadata> {
|
|
199
|
-
const configuredMetadata = this.options['arcgis-map-server']?.metadata;
|
|
200
|
-
if (configuredMetadata) return configuredMetadata;
|
|
201
|
-
const url = new URL(this.url);
|
|
202
|
-
url.searchParams.set('f', 'pjson');
|
|
203
|
-
for (const [key, value] of Object.entries(
|
|
204
|
-
this.options['arcgis-map-server']?.parameters || {}
|
|
205
|
-
)) {
|
|
206
|
-
url.searchParams.set(key, value);
|
|
207
|
-
}
|
|
208
|
-
const response = await this.fetch(url.toString());
|
|
209
|
-
if (!response.ok) {
|
|
210
|
-
throw new Error(
|
|
211
|
-
`ArcGIS MapServer metadata request failed: ${response.status} ${response.statusText}`
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
return response.json();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** Returns cached metadata and shares a single request among concurrent callers. */
|
|
218
|
-
private async _getMetadata(): Promise<ArcGISMapServerMetadata> {
|
|
219
|
-
if (this._metadata) return this._metadata;
|
|
220
|
-
if (!this._metadataPromise) {
|
|
221
|
-
this._metadataPromise = this._loadMetadata();
|
|
222
|
-
}
|
|
223
|
-
try {
|
|
224
|
-
const metadata = await this._metadataPromise;
|
|
225
|
-
this._metadata = metadata;
|
|
226
|
-
return metadata;
|
|
227
|
-
} finally {
|
|
228
|
-
this._metadataPromise = null;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** Selects a service endpoint for a tile using a stable URL-pool mapping. */
|
|
233
|
-
private getServiceURL(parameters: GetTileParameters): string {
|
|
234
|
-
const urls = this.options['arcgis-map-server']?.urls;
|
|
235
|
-
return urls?.length ? urls[(parameters.x + parameters.y) % urls.length] : this.url;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function isCompatibleCache(metadata: ArcGISMapServerMetadata | null): boolean {
|
|
240
|
-
const tileInfo = metadata?.tileInfo;
|
|
241
|
-
if (!tileInfo || tileInfo.rows !== 256 || tileInfo.cols !== 256) return false;
|
|
242
|
-
const spatialReference = tileInfo.spatialReference || metadata?.spatialReference;
|
|
243
|
-
const wkid = (spatialReference as {wkid?: number; latestWkid?: number} | undefined)?.wkid;
|
|
244
|
-
if (wkid !== 3857 && wkid !== 102100 && wkid !== 102113) return false;
|
|
245
|
-
const origin = tileInfo.origin;
|
|
246
|
-
return (
|
|
247
|
-
!origin ||
|
|
248
|
-
(Math.abs(origin.x + 20037508.342789244) < 1 && Math.abs(origin.y - 20037508.342789244) < 1)
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/** Calculates the Web Mercator extent represented by an XYZ tile. */
|
|
253
|
-
function getWebMercatorTileBounds(parameters: GetTileParameters): [number, number, number, number] {
|
|
254
|
-
const worldSize = 20037508.342789244;
|
|
255
|
-
const tileCount = 2 ** parameters.z;
|
|
256
|
-
const tileSize = (worldSize * 2) / tileCount;
|
|
257
|
-
const west = -worldSize + parameters.x * tileSize;
|
|
258
|
-
const east = west + tileSize;
|
|
259
|
-
const north = worldSize - parameters.y * tileSize;
|
|
260
|
-
const south = north - tileSize;
|
|
261
|
-
return [west, south, east, north];
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/** Source loader for ArcGIS cached MapServer tiles. */
|
|
265
|
-
export const ArcGISMapTileSourceLoader = {
|
|
266
|
-
dataType: null as unknown as ArcGISMapTileSource,
|
|
267
|
-
batchType: null as never,
|
|
268
|
-
name: 'ArcGIS MapServer tiles',
|
|
269
|
-
id: 'arcgis-map-server',
|
|
270
|
-
module: 'services',
|
|
271
|
-
version: '0.0.0',
|
|
272
|
-
extensions: [],
|
|
273
|
-
mimeTypes: [],
|
|
274
|
-
type: 'arcgis-map-server',
|
|
275
|
-
fromUrl: true,
|
|
276
|
-
fromBlob: false,
|
|
277
|
-
options: {'arcgis-map-server': {}},
|
|
278
|
-
defaultOptions: {'arcgis-map-server': {}},
|
|
279
|
-
testURL: (url: string): boolean =>
|
|
280
|
-
/mapserver/i.test(url) && !/imageserver|featureserver/i.test(url),
|
|
281
|
-
createDataSource: (
|
|
282
|
-
url: string,
|
|
283
|
-
options: ArcGISMapTileSourceLoaderOptions = {},
|
|
284
|
-
coreApi?: CoreAPI
|
|
285
|
-
) => new ArcGISMapTileSource(url, options, coreApi)
|
|
286
|
-
} as const satisfies SourceLoader<ArcGISMapTileSource>;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// loaders.gl
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Copyright (c) vis.gl contributors
|
|
4
|
-
|
|
5
|
-
/** Aggregation operation supported by the SceneServer client helper. */
|
|
6
|
-
export type ArcGISSceneAggregationOperation = 'count' | 'sum' | 'min' | 'max' | 'average';
|
|
7
|
-
|
|
8
|
-
/** A single aggregation specification. */
|
|
9
|
-
export type ArcGISSceneAggregationSpec = {
|
|
10
|
-
/** Output field name. */
|
|
11
|
-
name: string;
|
|
12
|
-
/** Input property used by numeric operations. */
|
|
13
|
-
field?: string;
|
|
14
|
-
/** Operation to apply. */
|
|
15
|
-
operation: ArcGISSceneAggregationOperation;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/** Options for deterministic client-side feature aggregation. */
|
|
19
|
-
export type ArcGISSceneAggregationOptions = {
|
|
20
|
-
/** Features represented as ArcGIS feature objects or plain attribute records. */
|
|
21
|
-
features: unknown[];
|
|
22
|
-
/** Optional property used to create groups. */
|
|
23
|
-
groupBy?: string;
|
|
24
|
-
/** Aggregations to compute for each group. */
|
|
25
|
-
aggregations: ArcGISSceneAggregationSpec[];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/** Result of one group in a client-side aggregation. */
|
|
29
|
-
export type ArcGISSceneAggregationGroup = {
|
|
30
|
-
/** Group key, or `undefined` when no grouping was requested. */
|
|
31
|
-
group: unknown;
|
|
32
|
-
/** Aggregated values keyed by specification name. */
|
|
33
|
-
values: Record<string, number>;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Aggregates SceneServer features without evaluating renderer or Arcade expressions.
|
|
38
|
-
* Missing and non-numeric values are ignored by numeric operations; `count` counts
|
|
39
|
-
* records regardless of field presence.
|
|
40
|
-
*/
|
|
41
|
-
export function aggregateArcGISSceneFeatures(
|
|
42
|
-
options: ArcGISSceneAggregationOptions
|
|
43
|
-
): ArcGISSceneAggregationGroup[] {
|
|
44
|
-
const groups = new Map<unknown, unknown[]>();
|
|
45
|
-
for (const feature of options.features) {
|
|
46
|
-
const attributes = getFeatureAttributes(feature);
|
|
47
|
-
const key = options.groupBy ? attributes[options.groupBy] : undefined;
|
|
48
|
-
const group = groups.get(key);
|
|
49
|
-
if (group) group.push(feature);
|
|
50
|
-
else groups.set(key, [feature]);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return [...groups.entries()].map(([group, features]) => ({
|
|
54
|
-
group,
|
|
55
|
-
values: Object.fromEntries(
|
|
56
|
-
options.aggregations.map(spec => [spec.name, aggregateValues(features, spec)])
|
|
57
|
-
)
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function aggregateValues(features: unknown[], specification: ArcGISSceneAggregationSpec): number {
|
|
62
|
-
if (specification.operation === 'count') return features.length;
|
|
63
|
-
const values = features
|
|
64
|
-
.map(feature => getFeatureAttributes(feature)[specification.field || ''])
|
|
65
|
-
.filter(value => value !== null && value !== undefined && value !== '')
|
|
66
|
-
.map(value => (typeof value === 'number' ? value : Number(value)))
|
|
67
|
-
.filter(Number.isFinite);
|
|
68
|
-
if (!values.length) return 0;
|
|
69
|
-
switch (specification.operation) {
|
|
70
|
-
case 'sum':
|
|
71
|
-
return values.reduce((sum, value) => sum + value, 0);
|
|
72
|
-
case 'min':
|
|
73
|
-
return Math.min(...values);
|
|
74
|
-
case 'max':
|
|
75
|
-
return Math.max(...values);
|
|
76
|
-
case 'average':
|
|
77
|
-
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
78
|
-
default:
|
|
79
|
-
return 0;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function getFeatureAttributes(feature: unknown): Record<string, unknown> {
|
|
84
|
-
if (!feature || typeof feature !== 'object') return {};
|
|
85
|
-
const candidate = feature as {attributes?: unknown};
|
|
86
|
-
if (candidate.attributes && typeof candidate.attributes === 'object') {
|
|
87
|
-
return candidate.attributes as Record<string, unknown>;
|
|
88
|
-
}
|
|
89
|
-
return feature as Record<string, unknown>;
|
|
90
|
-
}
|