@loaders.gl/services 5.0.0-alpha.7 → 5.0.0-alpha.8
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,346 +0,0 @@
|
|
|
1
|
-
// loaders.gl
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Copyright (c) vis.gl contributors
|
|
4
|
-
|
|
5
|
-
import type {DataType, Schema, GeoJSONTable} from '@loaders.gl/schema';
|
|
6
|
-
import {
|
|
7
|
-
convertFeaturesToWKBArrowTable,
|
|
8
|
-
convertGeojsonToBinaryFeatureCollection
|
|
9
|
-
} from '@loaders.gl/gis';
|
|
10
|
-
import type {
|
|
11
|
-
CoreAPI,
|
|
12
|
-
DataSourceOptions,
|
|
13
|
-
VectorSourceMetadata,
|
|
14
|
-
GetFeaturesParameters,
|
|
15
|
-
VectorSource,
|
|
16
|
-
VectorSourceData
|
|
17
|
-
} from '@loaders.gl/loader-utils';
|
|
18
|
-
import type {SourceLoader} from '@loaders.gl/loader-utils';
|
|
19
|
-
import {DataSource} from '@loaders.gl/loader-utils';
|
|
20
|
-
import {buildArcGISResourceURL} from './arcgis-url-utils';
|
|
21
|
-
|
|
22
|
-
/** Parameters for ArcGIS FeatureServer query requests. */
|
|
23
|
-
export type ArcGISFeatureServiceQueryOptions = {
|
|
24
|
-
/** Include feature geometries in the response. */
|
|
25
|
-
returnGeometry?: boolean;
|
|
26
|
-
/** SQL where clause. */
|
|
27
|
-
where?: string;
|
|
28
|
-
/** Output spatial reference. */
|
|
29
|
-
outSR?: string | number;
|
|
30
|
-
/** Output fields. */
|
|
31
|
-
outFields?: string | string[];
|
|
32
|
-
/** Input spatial reference for supplied geometry. */
|
|
33
|
-
inSR?: string | number;
|
|
34
|
-
/** Filter geometry as an ArcGIS REST geometry string. */
|
|
35
|
-
geometry?: string;
|
|
36
|
-
/** Filter geometry type. */
|
|
37
|
-
geometryType?:
|
|
38
|
-
| 'esriGeometryEnvelope'
|
|
39
|
-
| 'esriGeometryPoint'
|
|
40
|
-
| 'esriGeometryPolyline'
|
|
41
|
-
| 'esriGeometryPolygon';
|
|
42
|
-
/** Spatial relationship for geometry filters. */
|
|
43
|
-
spatialRel?:
|
|
44
|
-
| 'esriSpatialRelIntersects'
|
|
45
|
-
| 'esriSpatialRelContains'
|
|
46
|
-
| 'esriSpatialRelCrosses'
|
|
47
|
-
| 'esriSpatialRelEnvelopeIntersects'
|
|
48
|
-
| 'esriSpatialRelIndexIntersects'
|
|
49
|
-
| 'esriSpatialRelOverlaps'
|
|
50
|
-
| 'esriSpatialRelTouches'
|
|
51
|
-
| 'esriSpatialRelWithin';
|
|
52
|
-
/** Geometry precision. */
|
|
53
|
-
geometryPrecision?: number;
|
|
54
|
-
/** Query result type. */
|
|
55
|
-
resultType?: 'none' | 'standard' | 'tile';
|
|
56
|
-
/** ArcGIS response format. */
|
|
57
|
-
f?: 'geojson' | 'json' | 'pjson';
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/** Options for the ArcGIS FeatureServer source. */
|
|
61
|
-
export type ArcGISFeatureServerSourceLoaderOptions = DataSourceOptions & {
|
|
62
|
-
'arcgis-feature-server'?: {
|
|
63
|
-
/** Default ArcGIS query request parameters. */
|
|
64
|
-
queryParameters?: Partial<ArcGISFeatureServiceQueryOptions>;
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @see https://developers.arcgis.com/rest/services-reference/enterprise/feature-service.htm
|
|
70
|
-
*/
|
|
71
|
-
export const ArcGISFeatureServerSourceLoader = {
|
|
72
|
-
dataType: null as unknown as ArcGISVectorSource,
|
|
73
|
-
batchType: null as never,
|
|
74
|
-
name: 'ArcGISFeatureServer',
|
|
75
|
-
id: 'arcgis-feature-server',
|
|
76
|
-
module: 'services',
|
|
77
|
-
version: '0.0.0',
|
|
78
|
-
extensions: [],
|
|
79
|
-
mimeTypes: [],
|
|
80
|
-
type: 'arcgis-feature-server',
|
|
81
|
-
fromUrl: true,
|
|
82
|
-
fromBlob: false,
|
|
83
|
-
|
|
84
|
-
options: {
|
|
85
|
-
url: undefined!,
|
|
86
|
-
'arcgis-feature-server': {}
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
defaultOptions: {
|
|
90
|
-
url: undefined!,
|
|
91
|
-
'arcgis-feature-server': {}
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
testURL: (url: string): boolean => url.toLowerCase().includes('featureserver'),
|
|
95
|
-
createDataSource: (
|
|
96
|
-
url: string,
|
|
97
|
-
options: ArcGISFeatureServerSourceLoaderOptions,
|
|
98
|
-
coreApi?: CoreAPI
|
|
99
|
-
): ArcGISVectorSource => new ArcGISVectorSource(url, options, coreApi)
|
|
100
|
-
} as const satisfies SourceLoader<ArcGISVectorSource>;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* ArcGIS FeatureServer
|
|
104
|
-
* Note - exports a big API, that could be exposed here if there is a use case
|
|
105
|
-
* @see https://developers.arcgis.com/rest/services-reference/enterprise/feature-service.htm
|
|
106
|
-
*/
|
|
107
|
-
export class ArcGISVectorSource
|
|
108
|
-
extends DataSource<string, ArcGISFeatureServerSourceLoaderOptions>
|
|
109
|
-
implements VectorSource
|
|
110
|
-
{
|
|
111
|
-
/** Cached ArcGIS FeatureServer metadata request. */
|
|
112
|
-
protected formatSpecificMetadata: Promise<any> | null = null;
|
|
113
|
-
|
|
114
|
-
constructor(url: string, options: ArcGISFeatureServerSourceLoaderOptions, coreApi?: CoreAPI) {
|
|
115
|
-
super(url, options, ArcGISFeatureServerSourceLoader.defaultOptions, coreApi);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** Returns a schema inferred from ArcGIS FeatureServer metadata fields. */
|
|
119
|
-
async getSchema(): Promise<Schema> {
|
|
120
|
-
const metadata = await this.getFormatSpecificMetadata();
|
|
121
|
-
return parseArcGISFeatureServerSchema(metadata);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Returns normalized VectorSource metadata. */
|
|
125
|
-
async getMetadata(
|
|
126
|
-
options: {formatSpecificMetadata?: boolean} = {}
|
|
127
|
-
): Promise<VectorSourceMetadata> {
|
|
128
|
-
// Wait for raw metadata to load
|
|
129
|
-
const formatSpecificMetadata = await this.getFormatSpecificMetadata();
|
|
130
|
-
|
|
131
|
-
const metadata = parseArcGISFeatureServerMetadata(formatSpecificMetadata);
|
|
132
|
-
|
|
133
|
-
// Only add the big blob of source metadata if explicitly requested
|
|
134
|
-
if (options.formatSpecificMetadata) {
|
|
135
|
-
metadata.formatSpecificMetadata = formatSpecificMetadata;
|
|
136
|
-
}
|
|
137
|
-
return metadata;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Requests features from the ArcGIS FeatureServer query endpoint. */
|
|
141
|
-
async getFeatures(parameters: GetFeaturesParameters): Promise<VectorSourceData> {
|
|
142
|
-
const url = this.getFeaturesURL(parameters);
|
|
143
|
-
const response = await this.fetch(
|
|
144
|
-
url,
|
|
145
|
-
parameters.signal ? {signal: parameters.signal} : undefined
|
|
146
|
-
);
|
|
147
|
-
await this.checkResponse(response);
|
|
148
|
-
const geoJsonTable = parseGeoJSONTable(await response.json());
|
|
149
|
-
const format = parameters.format || 'arrow';
|
|
150
|
-
|
|
151
|
-
switch (format) {
|
|
152
|
-
case 'binary':
|
|
153
|
-
return convertGeojsonToBinaryFeatureCollection(geoJsonTable.features);
|
|
154
|
-
case 'geojson':
|
|
155
|
-
return geoJsonTable;
|
|
156
|
-
case 'arrow':
|
|
157
|
-
default:
|
|
158
|
-
return convertFeaturesToWKBArrowTable(geoJsonTable.features, {
|
|
159
|
-
encodingPreference: parameters.geoarrow?.encodingPreference
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** Requests the raw ArcGIS FeatureServer metadata document. */
|
|
165
|
-
protected async _getFormatSpecificMetadata() {
|
|
166
|
-
// PJSON is formatted by a bit slower than JSON
|
|
167
|
-
const url = this.metadataURL();
|
|
168
|
-
const response = await this.fetch(url);
|
|
169
|
-
await this.checkResponse(response);
|
|
170
|
-
return await response.json();
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** Loads and caches the raw ArcGIS FeatureServer metadata. */
|
|
174
|
-
protected async getFormatSpecificMetadata(): Promise<any> {
|
|
175
|
-
this.formatSpecificMetadata ||= this._getFormatSpecificMetadata();
|
|
176
|
-
return await this.formatSpecificMetadata;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/** Builds a metadata URL for the ArcGIS FeatureServer endpoint. */
|
|
180
|
-
metadataURL(options?: {parameters?: Record<string, unknown>}): string {
|
|
181
|
-
return this.getUrl('', {f: 'pjson', ...options?.parameters});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/** Builds a query URL from generic vector source parameters. */
|
|
185
|
-
getFeaturesURL(parameters: GetFeaturesParameters): string {
|
|
186
|
-
const defaultParameters = this.options['arcgis-feature-server']?.queryParameters || {};
|
|
187
|
-
const outputSpatialReference = normalizeArcGISSpatialReference(parameters.crs) || 4326;
|
|
188
|
-
const requestSpatialReference =
|
|
189
|
-
normalizeArcGISSpatialReference(parameters.requestCrs) || outputSpatialReference;
|
|
190
|
-
const queryParameters: ArcGISFeatureServiceQueryOptions = {
|
|
191
|
-
returnGeometry: true,
|
|
192
|
-
where: '1=1',
|
|
193
|
-
outFields: '*',
|
|
194
|
-
outSR: outputSpatialReference,
|
|
195
|
-
inSR: requestSpatialReference,
|
|
196
|
-
f: 'geojson',
|
|
197
|
-
...defaultParameters
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
if (parameters.boundingBox) {
|
|
201
|
-
queryParameters.geometry = [
|
|
202
|
-
parameters.boundingBox[0][0],
|
|
203
|
-
parameters.boundingBox[0][1],
|
|
204
|
-
parameters.boundingBox[1][0],
|
|
205
|
-
parameters.boundingBox[1][1]
|
|
206
|
-
].join(',');
|
|
207
|
-
queryParameters.geometryType = 'esriGeometryEnvelope';
|
|
208
|
-
queryParameters.spatialRel ||= 'esriSpatialRelIntersects';
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const layer = Array.isArray(parameters.layers) ? parameters.layers[0] : parameters.layers;
|
|
212
|
-
const isLayerEndpoint = /\/FeatureServer\/\d+\/?(?:\?|$)/i.test(this.url);
|
|
213
|
-
const resourcePath = isLayerEndpoint || !layer ? 'query' : `${layer}/query`;
|
|
214
|
-
return this.getUrl(resourcePath, queryParameters);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** Builds an ArcGIS FeatureServer URL. */
|
|
218
|
-
protected getUrl(
|
|
219
|
-
path: string,
|
|
220
|
-
options: Record<string, unknown>,
|
|
221
|
-
extra?: Record<string, unknown>
|
|
222
|
-
): string {
|
|
223
|
-
return buildArcGISResourceURL(this.url, path, {...options, ...extra});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/** Checks an ArcGIS FeatureServer response. */
|
|
227
|
-
protected async checkResponse(response: Response): Promise<void> {
|
|
228
|
-
if (!response.ok) {
|
|
229
|
-
throw new Error(
|
|
230
|
-
response.statusText || `ArcGIS FeatureServer request failed: ${response.status}`
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function parseArcGISFeatureServerMetadata(json: any): VectorSourceMetadata {
|
|
237
|
-
const layers: VectorSourceMetadata['layers'] = [];
|
|
238
|
-
for (const layer of json.layers || []) {
|
|
239
|
-
const extent = layer.extent;
|
|
240
|
-
const spatialReference = layer.spatialReference || extent?.spatialReference;
|
|
241
|
-
layers.push({
|
|
242
|
-
name: layer.id === undefined ? layer.name : String(layer.id),
|
|
243
|
-
title: layer.name,
|
|
244
|
-
crs: getArcGISCoordinateReferenceSystems(spatialReference),
|
|
245
|
-
boundingBox: normalizeArcGISExtent(extent)
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (!layers.length && (json.id !== undefined || json.name)) {
|
|
250
|
-
const extent = json.extent;
|
|
251
|
-
layers.push({
|
|
252
|
-
name: json.id === undefined ? json.name : String(json.id),
|
|
253
|
-
title: json.name,
|
|
254
|
-
crs: getArcGISCoordinateReferenceSystems(json.spatialReference || extent?.spatialReference),
|
|
255
|
-
boundingBox: normalizeArcGISExtent(extent)
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
// version: json.currentVersion || '',
|
|
261
|
-
title: json.serviceDescription || '',
|
|
262
|
-
name: json.serviceDescription || '',
|
|
263
|
-
abstract: json.description || '',
|
|
264
|
-
keywords: [],
|
|
265
|
-
// attrribution: json.copyrightText || ''.
|
|
266
|
-
// crs: 'EPSG:4326',
|
|
267
|
-
layers
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/** Normalizes an ArcGIS spatial reference to a one-element CRS list. */
|
|
272
|
-
function getArcGISCoordinateReferenceSystems(
|
|
273
|
-
spatialReference: {wkid?: number; latestWkid?: number} | undefined
|
|
274
|
-
): string[] | undefined {
|
|
275
|
-
const wellKnownIdentifier = spatialReference?.latestWkid || spatialReference?.wkid;
|
|
276
|
-
return wellKnownIdentifier ? [`EPSG:${wellKnownIdentifier}`] : undefined;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/** Normalizes an ArcGIS extent to the loaders.gl two-corner shape. */
|
|
280
|
-
function normalizeArcGISExtent(
|
|
281
|
-
extent: {xmin?: number; ymin?: number; xmax?: number; ymax?: number} | undefined
|
|
282
|
-
): [[number, number], [number, number]] | undefined {
|
|
283
|
-
return extent && [extent.xmin, extent.ymin, extent.xmax, extent.ymax].every(Number.isFinite)
|
|
284
|
-
? [
|
|
285
|
-
[extent.xmin!, extent.ymin!],
|
|
286
|
-
[extent.xmax!, extent.ymax!]
|
|
287
|
-
]
|
|
288
|
-
: undefined;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/** Normalizes EPSG-prefixed CRS strings to ArcGIS WKID values. */
|
|
292
|
-
function normalizeArcGISSpatialReference(
|
|
293
|
-
spatialReference: string | number | undefined
|
|
294
|
-
): string | number | undefined {
|
|
295
|
-
if (typeof spatialReference === 'string') {
|
|
296
|
-
const match = /^EPSG:(\d+)$/i.exec(spatialReference);
|
|
297
|
-
if (match) {
|
|
298
|
-
return match[1];
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
return spatialReference;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/** Builds a schema from ArcGIS FeatureServer metadata fields. */
|
|
305
|
-
function parseArcGISFeatureServerSchema(json: any): Schema {
|
|
306
|
-
const fields = Array.isArray(json.fields)
|
|
307
|
-
? json.fields.map((field: any) => ({
|
|
308
|
-
name: field.name,
|
|
309
|
-
type: getSchemaTypeFromArcGISFieldType(field.type),
|
|
310
|
-
nullable: field.nullable
|
|
311
|
-
}))
|
|
312
|
-
: [];
|
|
313
|
-
|
|
314
|
-
return {metadata: {}, fields};
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/** Maps common ArcGIS field types to loaders.gl schema type strings. */
|
|
318
|
-
function getSchemaTypeFromArcGISFieldType(type: string): DataType {
|
|
319
|
-
switch (type) {
|
|
320
|
-
case 'esriFieldTypeDouble':
|
|
321
|
-
return 'float64';
|
|
322
|
-
case 'esriFieldTypeSingle':
|
|
323
|
-
return 'float32';
|
|
324
|
-
case 'esriFieldTypeInteger':
|
|
325
|
-
case 'esriFieldTypeSmallInteger':
|
|
326
|
-
case 'esriFieldTypeOID':
|
|
327
|
-
return 'int32';
|
|
328
|
-
case 'esriFieldTypeDate':
|
|
329
|
-
return 'timestamp-millisecond';
|
|
330
|
-
default:
|
|
331
|
-
return 'utf8';
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/** Parses a GeoJSON FeatureCollection into the loaders.gl GeoJSON table shape. */
|
|
336
|
-
function parseGeoJSONTable(json: any): GeoJSONTable {
|
|
337
|
-
if (json?.type === 'FeatureCollection' && Array.isArray(json.features)) {
|
|
338
|
-
return {
|
|
339
|
-
shape: 'geojson-table',
|
|
340
|
-
type: 'FeatureCollection',
|
|
341
|
-
features: json.features
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
throw new Error('ArcGIS FeatureServer query did not return a GeoJSON FeatureCollection');
|
|
346
|
-
}
|
|
@@ -1,242 +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
|
-
SourceLoader,
|
|
10
|
-
DataSourceOptions,
|
|
11
|
-
ImageSource,
|
|
12
|
-
ImageSourceMetadata,
|
|
13
|
-
GetImageParameters
|
|
14
|
-
} from '@loaders.gl/loader-utils';
|
|
15
|
-
import {DataSource} from '@loaders.gl/loader-utils';
|
|
16
|
-
import type {LERCData} from '@loaders.gl/lerc';
|
|
17
|
-
import {LERCLoader} from '@loaders.gl/lerc';
|
|
18
|
-
import {buildArcGISResourceURL} from './arcgis-url-utils';
|
|
19
|
-
|
|
20
|
-
/** Options for the ArcGIS ImageServer source. */
|
|
21
|
-
export type ArcGISImageSourceLoaderProps = DataSourceOptions & {
|
|
22
|
-
'arcgis-image-server'?: {
|
|
23
|
-
/** Default ArcGIS exportImage request parameters. */
|
|
24
|
-
exportImageParameters?: Partial<ArcGISExportImageParameters>;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/** Parameters for ArcGIS ImageServer exportImage requests. */
|
|
29
|
-
export type ArcGISExportImageParameters = {
|
|
30
|
-
/** Bounding box of the requested image. */
|
|
31
|
-
bbox: [number, number, number, number];
|
|
32
|
-
/** Spatial reference of the supplied bbox. */
|
|
33
|
-
bboxSR?: string | number;
|
|
34
|
-
/** Pixel width of returned image. */
|
|
35
|
-
width: number;
|
|
36
|
-
/** Pixel height of returned image. */
|
|
37
|
-
height: number;
|
|
38
|
-
/** Spatial reference of the returned image. */
|
|
39
|
-
imageSR?: string | number;
|
|
40
|
-
/** Requested image format. */
|
|
41
|
-
format?: 'jpgpng' | 'png' | 'png8' | 'png24' | 'jpg' | 'bmp' | 'gif' | 'tiff' | 'png32' | 'lerc';
|
|
42
|
-
/** Requested pixel type. */
|
|
43
|
-
pixelType?: 'U1' | 'U2' | 'U4' | 'U8' | 'S8' | 'U16' | 'S16' | 'U32' | 'S32' | 'F32' | 'F64';
|
|
44
|
-
/** NoData pixel value. */
|
|
45
|
-
noData?: string | number;
|
|
46
|
-
/** NoData interpretation mode. */
|
|
47
|
-
noDataInterpretation?: 'esriNoDataMatchAny' | 'esriNoDataMatchAll';
|
|
48
|
-
/** Resampling interpolation. */
|
|
49
|
-
interpolation?: string;
|
|
50
|
-
/** Compression type. */
|
|
51
|
-
compression?: string;
|
|
52
|
-
/** Compression quality. */
|
|
53
|
-
compressionQuality?: number;
|
|
54
|
-
/** Band ids to export. */
|
|
55
|
-
bandIds?: string | number[];
|
|
56
|
-
/** Mosaic rule JSON string or object. */
|
|
57
|
-
mosaicRule?: string | Record<string, unknown>;
|
|
58
|
-
/** Rendering rule JSON string or object. */
|
|
59
|
-
renderingRule?: string | Record<string, unknown>;
|
|
60
|
-
/** ArcGIS response format. */
|
|
61
|
-
f?: 'image' | 'json' | 'pjson';
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const ArcGISImageServerSourceLoader = {
|
|
65
|
-
dataType: null as unknown as ArcGISImageSource,
|
|
66
|
-
batchType: null as never,
|
|
67
|
-
name: 'ArcGISImageServer',
|
|
68
|
-
id: 'arcgis-image-server',
|
|
69
|
-
module: 'services',
|
|
70
|
-
version: '0.0.0',
|
|
71
|
-
extensions: [],
|
|
72
|
-
mimeTypes: [],
|
|
73
|
-
type: 'arcgis-image-server',
|
|
74
|
-
fromUrl: true,
|
|
75
|
-
fromBlob: false,
|
|
76
|
-
|
|
77
|
-
options: {
|
|
78
|
-
'arcgis-image-server': {
|
|
79
|
-
// TODO - add options here
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
defaultOptions: {
|
|
84
|
-
'arcgis-image-server': {
|
|
85
|
-
// TODO - add options here
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
testURL: (url: string): boolean => url.toLowerCase().includes('imageserver'),
|
|
90
|
-
createDataSource: (
|
|
91
|
-
url: string,
|
|
92
|
-
props: ArcGISImageSourceLoaderProps,
|
|
93
|
-
coreApi?: CoreAPI
|
|
94
|
-
): ArcGISImageSource => new ArcGISImageSource(url, props, coreApi)
|
|
95
|
-
} as const satisfies SourceLoader<ArcGISImageSource>;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* ArcGIS ImageServer
|
|
99
|
-
* Note - exports a big API, that could be exposed here if there is a use case
|
|
100
|
-
* @see https://developers.arcgis.com/rest/services-reference/enterprise/image-service.htm
|
|
101
|
-
*/
|
|
102
|
-
export class ArcGISImageSource
|
|
103
|
-
extends DataSource<string, ArcGISImageSourceLoaderProps>
|
|
104
|
-
implements ImageSource
|
|
105
|
-
{
|
|
106
|
-
constructor(url: string, props: ArcGISImageSourceLoaderProps, coreApi?: CoreAPI) {
|
|
107
|
-
super(url, props, ArcGISImageServerSourceLoader.defaultOptions, coreApi);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** Returns normalized ImageSource metadata. */
|
|
111
|
-
async getMetadata(): Promise<ImageSourceMetadata> {
|
|
112
|
-
return normalizeArcGISImageServerMetadata(await this.metadata());
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Requests an image from generic ImageSource parameters. */
|
|
116
|
-
async getImage(parameters: GetImageParameters): Promise<ImageType> {
|
|
117
|
-
const {boundingBox, width, height, crs, format, signal} = parameters;
|
|
118
|
-
const spatialReference = normalizeArcGISSpatialReference(crs) || '4326';
|
|
119
|
-
const imageParameters: ArcGISExportImageParameters = {
|
|
120
|
-
bbox: [...boundingBox[0], ...boundingBox[1]],
|
|
121
|
-
bboxSR: spatialReference,
|
|
122
|
-
imageSR: spatialReference,
|
|
123
|
-
width,
|
|
124
|
-
height,
|
|
125
|
-
format: format === 'image/png' ? 'png' : undefined
|
|
126
|
-
};
|
|
127
|
-
return await this.exportImage(imageParameters, signal);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** Requests the ArcGIS ImageServer metadata document. */
|
|
131
|
-
async metadata(): Promise<unknown> {
|
|
132
|
-
const response = await this.fetch(this.metadataURL());
|
|
133
|
-
await this.checkResponse(response);
|
|
134
|
-
return await response.json();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** Requests an exported image from the ArcGIS ImageServer endpoint. */
|
|
138
|
-
async exportImage(
|
|
139
|
-
options: ArcGISExportImageParameters,
|
|
140
|
-
signal?: AbortSignal
|
|
141
|
-
): Promise<ImageType> {
|
|
142
|
-
const response = await this.fetch(this.exportImageURL(options), signal ? {signal} : undefined);
|
|
143
|
-
await this.checkResponse(response);
|
|
144
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
145
|
-
return (await this.coreApi.parse(arrayBuffer, ImageLoader, this.loadOptions)) as ImageType;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** Requests an analytical LERC raster from the ArcGIS ImageServer endpoint. */
|
|
149
|
-
async exportRaster(
|
|
150
|
-
options: ArcGISExportImageParameters,
|
|
151
|
-
signal?: AbortSignal
|
|
152
|
-
): Promise<LERCData> {
|
|
153
|
-
const response = await this.fetch(
|
|
154
|
-
this.exportImageURL({...options, format: 'lerc'}),
|
|
155
|
-
signal ? {signal} : undefined
|
|
156
|
-
);
|
|
157
|
-
await this.checkResponse(response);
|
|
158
|
-
return (await this.coreApi.parse(
|
|
159
|
-
await response.arrayBuffer(),
|
|
160
|
-
LERCLoader,
|
|
161
|
-
this.loadOptions
|
|
162
|
-
)) as LERCData;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/** Builds a metadata URL for the ArcGIS ImageServer endpoint. */
|
|
166
|
-
metadataURL(options?: {parameters?: Record<string, unknown>}): string {
|
|
167
|
-
return this.getUrl('', {f: 'pjson', ...options?.parameters});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** Builds an exportImage URL for the ArcGIS ImageServer endpoint. */
|
|
171
|
-
exportImageURL(options: ArcGISExportImageParameters): string {
|
|
172
|
-
const defaultParameters = this.options['arcgis-image-server']?.exportImageParameters || {};
|
|
173
|
-
const {width, height, ...parameters} = {...defaultParameters, ...options};
|
|
174
|
-
return this.getUrl('exportImage', {
|
|
175
|
-
...parameters,
|
|
176
|
-
bbox: parameters.bbox,
|
|
177
|
-
size: [width, height],
|
|
178
|
-
f: parameters.f || 'image'
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/** Builds an ArcGIS ImageServer URL. */
|
|
183
|
-
protected getUrl(
|
|
184
|
-
path: string,
|
|
185
|
-
options: Record<string, unknown>,
|
|
186
|
-
extra?: Record<string, unknown>
|
|
187
|
-
): string {
|
|
188
|
-
return buildArcGISResourceURL(this.url, path, {...options, ...extra});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** Checks an ArcGIS ImageServer response. */
|
|
192
|
-
protected async checkResponse(response: Response): Promise<void> {
|
|
193
|
-
if (!response.ok) {
|
|
194
|
-
throw new Error(
|
|
195
|
-
response.statusText || `ArcGIS ImageServer request failed: ${response.status}`
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** Normalizes EPSG-prefixed CRS strings to ArcGIS WKID values. */
|
|
202
|
-
function normalizeArcGISSpatialReference(
|
|
203
|
-
spatialReference: string | number | undefined
|
|
204
|
-
): string | number | undefined {
|
|
205
|
-
if (typeof spatialReference === 'string') {
|
|
206
|
-
const match = /^EPSG:(\d+)$/i.exec(spatialReference);
|
|
207
|
-
if (match) {
|
|
208
|
-
return match[1];
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return spatialReference;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** Normalizes ArcGIS ImageServer metadata to the generic ImageSource metadata shape. */
|
|
215
|
-
function normalizeArcGISImageServerMetadata(metadata: unknown): ImageSourceMetadata {
|
|
216
|
-
const arcgisMetadata = metadata as any;
|
|
217
|
-
const extent = arcgisMetadata.fullExtent || arcgisMetadata.extent;
|
|
218
|
-
const spatialReference = arcgisMetadata.spatialReference || extent?.spatialReference;
|
|
219
|
-
const wellKnownIdentifier = spatialReference?.latestWkid || spatialReference?.wkid;
|
|
220
|
-
const boundingBox =
|
|
221
|
-
extent && [extent.xmin, extent.ymin, extent.xmax, extent.ymax].every(Number.isFinite)
|
|
222
|
-
? ([
|
|
223
|
-
[extent.xmin, extent.ymin],
|
|
224
|
-
[extent.xmax, extent.ymax]
|
|
225
|
-
] as [[number, number], [number, number]])
|
|
226
|
-
: undefined;
|
|
227
|
-
const name = arcgisMetadata.name || arcgisMetadata.serviceDescription || '';
|
|
228
|
-
return {
|
|
229
|
-
name,
|
|
230
|
-
title: name,
|
|
231
|
-
abstract: arcgisMetadata.description || arcgisMetadata.serviceDescription || '',
|
|
232
|
-
keywords: Array.isArray(arcgisMetadata.keywords) ? arcgisMetadata.keywords : [],
|
|
233
|
-
layers: [
|
|
234
|
-
{
|
|
235
|
-
name,
|
|
236
|
-
title: name,
|
|
237
|
-
crs: wellKnownIdentifier ? [`EPSG:${wellKnownIdentifier}`] : undefined,
|
|
238
|
-
boundingBox
|
|
239
|
-
}
|
|
240
|
-
]
|
|
241
|
-
};
|
|
242
|
-
}
|