@vcmap/core 6.3.2 → 6.3.4
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/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/src/cesium/wallpaperMaterial.js +2 -2
- package/dist/src/cesium/wallpaperMaterial.js.map +1 -1
- package/dist/src/featureProvider/mapboxFeatureProvider.d.ts +1 -1
- package/dist/src/featureProvider/mapboxFeatureProvider.js +10 -1
- package/dist/src/featureProvider/mapboxFeatureProvider.js.map +1 -1
- package/dist/src/interaction/panoramaFeatureHighlight.d.ts +1 -0
- package/dist/src/interaction/panoramaFeatureHighlight.js +18 -11
- package/dist/src/interaction/panoramaFeatureHighlight.js.map +1 -1
- package/dist/src/interaction/panoramaImageSelection.js +46 -2
- package/dist/src/interaction/panoramaImageSelection.js.map +1 -1
- package/dist/src/layer/cesium/cogCesiumImpl.js +1 -1
- package/dist/src/layer/cesium/cogCesiumImpl.js.map +1 -1
- package/dist/src/layer/cesium/imageryProvider/abstractVcsImageryProvider.d.ts +47 -0
- package/dist/src/layer/cesium/imageryProvider/abstractVcsImageryProvider.js +71 -0
- package/dist/src/layer/cesium/imageryProvider/abstractVcsImageryProvider.js.map +1 -0
- package/dist/src/layer/cesium/imageryProvider/cogImageryProvider.d.ts +17 -0
- package/dist/src/layer/cesium/{cogImageryProvider.js → imageryProvider/cogImageryProvider.js} +17 -67
- package/dist/src/layer/cesium/imageryProvider/cogImageryProvider.js.map +1 -0
- package/dist/src/layer/cesium/{mapboxStyleImageryProvider.d.ts → imageryProvider/mapboxStyleImageryProvider.d.ts} +5 -9
- package/dist/src/layer/cesium/imageryProvider/mapboxStyleImageryProvider.js +37 -0
- package/dist/src/layer/cesium/imageryProvider/mapboxStyleImageryProvider.js.map +1 -0
- package/dist/src/layer/cesium/imageryProvider/olImageRenderer.d.ts +18 -0
- package/dist/src/layer/cesium/imageryProvider/olImageRenderer.js +144 -0
- package/dist/src/layer/cesium/imageryProvider/olImageRenderer.js.map +1 -0
- package/dist/src/layer/cesium/imageryProvider/panoramaDatasetImageryProvider.d.ts +12 -0
- package/dist/src/layer/cesium/imageryProvider/panoramaDatasetImageryProvider.js +45 -0
- package/dist/src/layer/cesium/imageryProvider/panoramaDatasetImageryProvider.js.map +1 -0
- package/dist/src/layer/cesium/{vectorTileImageryProvider.d.ts → imageryProvider/vectorTileImageryProvider.d.ts} +5 -24
- package/dist/src/layer/cesium/{vectorTileImageryProvider.js → imageryProvider/vectorTileImageryProvider.js} +16 -65
- package/dist/src/layer/cesium/imageryProvider/vectorTileImageryProvider.js.map +1 -0
- package/dist/src/layer/cesium/mapboxStyleCesiumImpl.d.ts +1 -1
- package/dist/src/layer/cesium/mapboxStyleCesiumImpl.js +1 -1
- package/dist/src/layer/cesium/mapboxStyleCesiumImpl.js.map +1 -1
- package/dist/src/layer/cesium/panoramaDatasetCesiumImpl.d.ts +5 -0
- package/dist/src/layer/cesium/panoramaDatasetCesiumImpl.js +12 -0
- package/dist/src/layer/cesium/panoramaDatasetCesiumImpl.js.map +1 -0
- package/dist/src/layer/cesium/vectorRasterTileCesiumImpl.d.ts +4 -2
- package/dist/src/layer/cesium/vectorRasterTileCesiumImpl.js +10 -3
- package/dist/src/layer/cesium/vectorRasterTileCesiumImpl.js.map +1 -1
- package/dist/src/layer/mapboxStyleLayer.js +27 -0
- package/dist/src/layer/mapboxStyleLayer.js.map +1 -1
- package/dist/src/layer/panoramaDatasetLayer.js +11 -1
- package/dist/src/layer/panoramaDatasetLayer.js.map +1 -1
- package/dist/src/layer/vectorTileLayer.d.ts +1 -0
- package/dist/src/layer/vectorTileLayer.js +3 -0
- package/dist/src/layer/vectorTileLayer.js.map +1 -1
- package/index.ts +11 -2
- package/package.json +6 -3
- package/src/cesium/wallpaperMaterial.js +2 -2
- package/src/featureProvider/mapboxFeatureProvider.ts +15 -2
- package/src/interaction/panoramaFeatureHighlight.ts +23 -16
- package/src/interaction/panoramaImageSelection.ts +58 -5
- package/src/layer/cesium/cogCesiumImpl.ts +1 -1
- package/src/layer/cesium/imageryProvider/abstractVcsImageryProvider.ts +126 -0
- package/src/layer/cesium/{cogImageryProvider.ts → imageryProvider/cogImageryProvider.ts} +23 -81
- package/src/layer/cesium/imageryProvider/mapboxStyleImageryProvider.ts +63 -0
- package/src/layer/cesium/imageryProvider/olImageRenderer.ts +219 -0
- package/src/layer/cesium/imageryProvider/panoramaDatasetImageryProvider.ts +73 -0
- package/src/layer/cesium/{vectorTileImageryProvider.ts → imageryProvider/vectorTileImageryProvider.ts} +19 -92
- package/src/layer/cesium/mapboxStyleCesiumImpl.ts +1 -1
- package/src/layer/cesium/panoramaDatasetCesiumImpl.ts +13 -0
- package/src/layer/cesium/vectorRasterTileCesiumImpl.ts +14 -4
- package/src/layer/mapboxStyleLayer.ts +42 -2
- package/src/layer/panoramaDatasetLayer.ts +12 -1
- package/src/layer/vectorTileLayer.ts +4 -0
- package/dist/src/layer/cesium/cogImageryProvider.d.ts +0 -31
- package/dist/src/layer/cesium/cogImageryProvider.js.map +0 -1
- package/dist/src/layer/cesium/mapboxStyleImageryProvider.js +0 -147
- package/dist/src/layer/cesium/mapboxStyleImageryProvider.js.map +0 -1
- package/dist/src/layer/cesium/vectorTileImageryProvider.js.map +0 -1
- package/src/layer/cesium/mapboxStyleImageryProvider.ts +0 -214
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Event as CesiumEvent,
|
|
3
|
+
type ImageryTypes,
|
|
4
|
+
type Rectangle,
|
|
5
|
+
type TilingScheme,
|
|
6
|
+
} from '@vcmap-cesium/engine';
|
|
7
|
+
import type { Size } from 'ol/size.js';
|
|
8
|
+
|
|
9
|
+
export type AbstractVcsImageryProviderOptions = {
|
|
10
|
+
tilingScheme: TilingScheme;
|
|
11
|
+
tileSize: Size;
|
|
12
|
+
minLevel: number;
|
|
13
|
+
maxLevel: number;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default abstract class AbstractVcsImageryProvider {
|
|
18
|
+
protected _tilingScheme: TilingScheme;
|
|
19
|
+
|
|
20
|
+
private _tileSize: Size;
|
|
21
|
+
|
|
22
|
+
private _errorEvent = new CesiumEvent();
|
|
23
|
+
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
|
|
26
|
+
emptyCanvas: HTMLCanvasElement;
|
|
27
|
+
|
|
28
|
+
minLevel: number;
|
|
29
|
+
|
|
30
|
+
maxLevel: number;
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
33
|
+
_reload: undefined | (() => void) = undefined;
|
|
34
|
+
|
|
35
|
+
constructor(options: AbstractVcsImageryProviderOptions) {
|
|
36
|
+
this._tilingScheme = options.tilingScheme;
|
|
37
|
+
this._tileSize = options.tileSize;
|
|
38
|
+
this.minLevel = options.minLevel;
|
|
39
|
+
this.maxLevel = options.maxLevel;
|
|
40
|
+
this._errorEvent = new CesiumEvent();
|
|
41
|
+
|
|
42
|
+
this.emptyCanvas = document.createElement('canvas');
|
|
43
|
+
this.emptyCanvas.width = this.tileWidth;
|
|
44
|
+
this.emptyCanvas.height = this.tileHeight;
|
|
45
|
+
this.headers = options.headers;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// eslint-disable-next-line class-methods-use-this,@typescript-eslint/naming-convention
|
|
49
|
+
get _ready(): boolean {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// eslint-disable-next-line class-methods-use-this
|
|
54
|
+
get ready(): boolean {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get rectangle(): Rectangle {
|
|
59
|
+
return this._tilingScheme.rectangle;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get tileWidth(): number {
|
|
63
|
+
return this._tileSize[0];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get tileHeight(): number {
|
|
67
|
+
return this._tileSize[1];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get maximumLevel(): number {
|
|
71
|
+
return this.maxLevel;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get minimumLevel(): number {
|
|
75
|
+
return this.minLevel;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get tilingScheme(): TilingScheme {
|
|
79
|
+
return this._tilingScheme;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// eslint-disable-next-line class-methods-use-this
|
|
83
|
+
get tileDiscardPolicy(): undefined {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get errorEvent(): CesiumEvent {
|
|
88
|
+
return this._errorEvent;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line class-methods-use-this
|
|
92
|
+
get credit(): undefined {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// eslint-disable-next-line class-methods-use-this
|
|
97
|
+
get proxy(): undefined {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// eslint-disable-next-line class-methods-use-this
|
|
102
|
+
get hasAlphaChannel(): boolean {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Requests the image for a given tile. This function should
|
|
108
|
+
* not be called before returns true.
|
|
109
|
+
*
|
|
110
|
+
* @param x The tile X coordinate.
|
|
111
|
+
* @param y The tile Y coordinate.
|
|
112
|
+
* @param level The tile level.
|
|
113
|
+
* @returns A promise for the image that will resolve when the image is available, or
|
|
114
|
+
* undefined if there are too many active requests to the server, and the request
|
|
115
|
+
* should be retried later. The resolved image may be either an
|
|
116
|
+
* Image or a Canvas DOM object.
|
|
117
|
+
*/
|
|
118
|
+
abstract requestImage(
|
|
119
|
+
x: number,
|
|
120
|
+
y: number,
|
|
121
|
+
level: number,
|
|
122
|
+
): Promise<ImageryTypes> | undefined;
|
|
123
|
+
|
|
124
|
+
// eslint-disable-next-line class-methods-use-this
|
|
125
|
+
destroy(): void {}
|
|
126
|
+
}
|
|
@@ -11,7 +11,6 @@ import type { Size } from 'ol/size.js';
|
|
|
11
11
|
import TileState from 'ol/TileState.js';
|
|
12
12
|
import {
|
|
13
13
|
Cartesian2,
|
|
14
|
-
Event as CesiumEvent,
|
|
15
14
|
GeographicTilingScheme,
|
|
16
15
|
type ImageryTypes,
|
|
17
16
|
Math as CesiumMath,
|
|
@@ -24,7 +23,8 @@ import type TileGrid from 'ol/tilegrid/TileGrid.js';
|
|
|
24
23
|
import {
|
|
25
24
|
mercatorExtentToRectangle,
|
|
26
25
|
rectangleToMercatorExtent,
|
|
27
|
-
} from '
|
|
26
|
+
} from '../../../util/math.js';
|
|
27
|
+
import AbstractVcsImageryProvider from './abstractVcsImageryProvider.js';
|
|
28
28
|
|
|
29
29
|
export function createEmptyCanvas(
|
|
30
30
|
width: number,
|
|
@@ -134,10 +134,10 @@ function drawData(
|
|
|
134
134
|
ctx.putImageData(imageData, offsetX, offsetY);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
function getMaximumTileSize(
|
|
137
|
+
function getMaximumTileSize(source: GeoTIFFSource): Size {
|
|
138
138
|
let width = 0;
|
|
139
139
|
let height = 0;
|
|
140
|
-
const numResolutions =
|
|
140
|
+
const numResolutions = source.getTileGrid()!.getResolutions().length;
|
|
141
141
|
for (let i = 0; i < numResolutions; i++) {
|
|
142
142
|
// @ts-expect-error protected
|
|
143
143
|
const size = source.getTileSize(i);
|
|
@@ -150,16 +150,12 @@ function getMaximumTileSize(tileGrid: TileGrid, source: GeoTIFFSource): Size {
|
|
|
150
150
|
return [width, height];
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
export default class COGImageryProvider {
|
|
154
|
-
private _emptyCanvas: HTMLCanvasElement;
|
|
155
|
-
|
|
153
|
+
export default class COGImageryProvider extends AbstractVcsImageryProvider {
|
|
156
154
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
157
155
|
_reload: undefined | (() => void) = undefined;
|
|
158
156
|
|
|
159
157
|
private _projection: Projection;
|
|
160
158
|
|
|
161
|
-
private _tilingScheme: TilingScheme;
|
|
162
|
-
|
|
163
159
|
private _tileGrid: TileGrid;
|
|
164
160
|
|
|
165
161
|
private _boundTileLoader: (
|
|
@@ -168,84 +164,26 @@ export default class COGImageryProvider {
|
|
|
168
164
|
level: number,
|
|
169
165
|
) => Promise<ImageryTypes>;
|
|
170
166
|
|
|
171
|
-
readonly tileWidth: number = 256;
|
|
172
|
-
|
|
173
|
-
readonly tileHeight: number = 256;
|
|
174
|
-
|
|
175
167
|
constructor(private _source: GeoTIFFSource) {
|
|
168
|
+
const tileSize = getMaximumTileSize(_source);
|
|
169
|
+
const maxLevel = _source.getTileGrid()?.getMaxZoom?.() ?? 26;
|
|
170
|
+
|
|
171
|
+
super({
|
|
172
|
+
tilingScheme: getTilingSchemeFromSource(_source),
|
|
173
|
+
tileSize,
|
|
174
|
+
minLevel: 0,
|
|
175
|
+
maxLevel,
|
|
176
|
+
});
|
|
177
|
+
|
|
176
178
|
this._projection = this._source.getProjection()!;
|
|
177
179
|
this._tileGrid = this._source.getTileGrid()!;
|
|
178
|
-
this._tilingScheme = getTilingSchemeFromSource(this._source);
|
|
179
180
|
if (areGridsAligned(this._tileGrid, this._tilingScheme, this._source)) {
|
|
180
181
|
this._boundTileLoader = this._loadAlignedTile.bind(this);
|
|
181
182
|
} else {
|
|
182
183
|
this._boundTileLoader = this._loadUnalignedTile.bind(this);
|
|
183
184
|
}
|
|
184
|
-
const [width, height] = getMaximumTileSize(this._tileGrid, this._source);
|
|
185
|
-
this.tileWidth = width;
|
|
186
|
-
this.tileHeight = height;
|
|
187
|
-
this._emptyCanvas = createEmptyCanvas(this.tileWidth, this.tileHeight);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// eslint-disable-next-line class-methods-use-this,@typescript-eslint/naming-convention
|
|
191
|
-
get _ready(): boolean {
|
|
192
|
-
return true;
|
|
193
185
|
}
|
|
194
186
|
|
|
195
|
-
// eslint-disable-next-line class-methods-use-this
|
|
196
|
-
get ready(): boolean {
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
get rectangle(): Rectangle {
|
|
201
|
-
return this._tilingScheme.rectangle;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
get tilingScheme(): TilingScheme {
|
|
205
|
-
return this._tilingScheme;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
readonly errorEvent: CesiumEvent = new CesiumEvent();
|
|
209
|
-
|
|
210
|
-
// eslint-disable-next-line class-methods-use-this
|
|
211
|
-
get credit(): undefined {
|
|
212
|
-
return undefined;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// eslint-disable-next-line class-methods-use-this
|
|
216
|
-
get proxy(): undefined {
|
|
217
|
-
return undefined;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
get maximumLevel(): number {
|
|
221
|
-
const tileGrid = this._source.getTileGrid();
|
|
222
|
-
if (tileGrid) {
|
|
223
|
-
return tileGrid.getMaxZoom();
|
|
224
|
-
} else {
|
|
225
|
-
return 18; // some arbitrary value
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// eslint-disable-next-line class-methods-use-this
|
|
230
|
-
get minimumLevel(): number {
|
|
231
|
-
// WARNING: Do not use the minimum level (at least until the extent is
|
|
232
|
-
// properly set). Cesium assumes the minimumLevel to contain only
|
|
233
|
-
// a few tiles and tries to load them all at once -- this can
|
|
234
|
-
// freeze and/or crash the browser !
|
|
235
|
-
return 0;
|
|
236
|
-
//var tg = this._source.getTileGrid();
|
|
237
|
-
//return tg ? tg.getMinZoom() : 0;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// eslint-disable-next-line class-methods-use-this
|
|
241
|
-
get tileDiscardPolicy(): undefined {
|
|
242
|
-
return undefined;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// eslint-disable-next-line class-methods-use-this
|
|
246
|
-
get hasAlphaChannel(): boolean {
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
187
|
private _getTileSizeForLevel(level: number): [number, number] {
|
|
250
188
|
// @ts-expect-error protected
|
|
251
189
|
const [width, height] = this._source.getTileSize(level);
|
|
@@ -306,7 +244,7 @@ export default class COGImageryProvider {
|
|
|
306
244
|
return canvas;
|
|
307
245
|
}
|
|
308
246
|
|
|
309
|
-
return this.
|
|
247
|
+
return this.emptyCanvas;
|
|
310
248
|
}
|
|
311
249
|
|
|
312
250
|
private async _loadUnalignedTile(
|
|
@@ -335,7 +273,7 @@ export default class COGImageryProvider {
|
|
|
335
273
|
|
|
336
274
|
const ctx = canvas.getContext('2d');
|
|
337
275
|
if (!ctx) {
|
|
338
|
-
return this.
|
|
276
|
+
return this.emptyCanvas;
|
|
339
277
|
}
|
|
340
278
|
|
|
341
279
|
const promises: Promise<void>[] = [];
|
|
@@ -413,10 +351,14 @@ export default class COGImageryProvider {
|
|
|
413
351
|
return windowCanvas;
|
|
414
352
|
}
|
|
415
353
|
|
|
416
|
-
return this.
|
|
354
|
+
return this.emptyCanvas;
|
|
417
355
|
}
|
|
418
356
|
|
|
419
|
-
requestImage(
|
|
357
|
+
requestImage(
|
|
358
|
+
x: number,
|
|
359
|
+
y: number,
|
|
360
|
+
level: number,
|
|
361
|
+
): Promise<ImageryTypes> | undefined {
|
|
420
362
|
return this._boundTileLoader(x, y, level);
|
|
421
363
|
}
|
|
422
364
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type LayerGroup from 'ol/layer/Group.js';
|
|
2
|
+
import type { VectorTileImageryProviderOptions } from './vectorTileImageryProvider.js';
|
|
3
|
+
import {
|
|
4
|
+
createOLImageRenderer,
|
|
5
|
+
type OLImageRenderer,
|
|
6
|
+
} from './olImageRenderer.js';
|
|
7
|
+
import AbstractVcsImageryProvider from './abstractVcsImageryProvider.js';
|
|
8
|
+
import type TileProvider from '../../tileProvider/tileProvider.js';
|
|
9
|
+
|
|
10
|
+
export type MapboxStyleImageryProviderOptions =
|
|
11
|
+
VectorTileImageryProviderOptions & {
|
|
12
|
+
styledMapboxLayerGroup: LayerGroup;
|
|
13
|
+
minimumTerrainLevel?: number;
|
|
14
|
+
maximumTerrainLevel?: number;
|
|
15
|
+
tileCacheSize?: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Implementation of Cesium ImageryProvider Interface for Mapbox Style Tiles
|
|
20
|
+
*/
|
|
21
|
+
class MapboxStyleImageryProvider extends AbstractVcsImageryProvider {
|
|
22
|
+
static get className(): string {
|
|
23
|
+
return 'MapboxStyleImageryProvider';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
tileProvider: TileProvider;
|
|
27
|
+
|
|
28
|
+
private _olImageRenderer: OLImageRenderer;
|
|
29
|
+
|
|
30
|
+
constructor(options: MapboxStyleImageryProviderOptions) {
|
|
31
|
+
super({
|
|
32
|
+
tilingScheme: options.tileProvider.tilingScheme,
|
|
33
|
+
tileSize: options.tileSize,
|
|
34
|
+
minLevel: 0,
|
|
35
|
+
maxLevel: 26,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
this.tileProvider = options.tileProvider;
|
|
39
|
+
|
|
40
|
+
this._olImageRenderer = createOLImageRenderer({
|
|
41
|
+
tilingScheme: this.tileProvider.tilingScheme,
|
|
42
|
+
tileWidth: this.tileWidth,
|
|
43
|
+
tileHeight: this.tileHeight,
|
|
44
|
+
tileCacheSize: options.tileCacheSize,
|
|
45
|
+
emptyCanvas: this.emptyCanvas,
|
|
46
|
+
});
|
|
47
|
+
this._olImageRenderer.map.addLayer(options.styledMapboxLayerGroup);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
requestImage(
|
|
51
|
+
x: number,
|
|
52
|
+
y: number,
|
|
53
|
+
level: number,
|
|
54
|
+
): Promise<HTMLImageElement | HTMLCanvasElement> | undefined {
|
|
55
|
+
return this._olImageRenderer.requestImage(x, y, level);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
destroy(): void {
|
|
59
|
+
this._olImageRenderer.destroy();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default MapboxStyleImageryProvider;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { TilingScheme } from '@vcmap-cesium/engine';
|
|
2
|
+
import OLMap from 'ol/Map.js';
|
|
3
|
+
import LRUCache from 'ol/structs/LRUCache.js';
|
|
4
|
+
import { buffer, type Extent, getCenter } from 'ol/extent.js';
|
|
5
|
+
import { getLogger } from '@vcsuite/logger';
|
|
6
|
+
import { parseInteger } from '@vcsuite/parsers';
|
|
7
|
+
import { rectangleToMercatorExtent } from '../../../util/math.js';
|
|
8
|
+
|
|
9
|
+
export type OLImageRenderer = {
|
|
10
|
+
readonly isRendering: boolean;
|
|
11
|
+
readonly map: OLMap;
|
|
12
|
+
requestImage(
|
|
13
|
+
x: number,
|
|
14
|
+
y: number,
|
|
15
|
+
level: number,
|
|
16
|
+
): Promise<HTMLImageElement | HTMLCanvasElement> | undefined;
|
|
17
|
+
destroy(): void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type OLImageRendererOptions = {
|
|
21
|
+
tilingScheme: TilingScheme;
|
|
22
|
+
tileWidth: number;
|
|
23
|
+
tileHeight: number;
|
|
24
|
+
emptyCanvas: HTMLCanvasElement;
|
|
25
|
+
tileCacheSize?: number;
|
|
26
|
+
fetchFeatures?: (
|
|
27
|
+
x: number,
|
|
28
|
+
y: number,
|
|
29
|
+
level: number,
|
|
30
|
+
extent: Extent,
|
|
31
|
+
) => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function getTileCacheKey(x: number, y: number, level: number): string {
|
|
35
|
+
return `${x}-${y}-${level}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getGutterSize(level: number): number {
|
|
39
|
+
if (level < 12) {
|
|
40
|
+
return 32;
|
|
41
|
+
}
|
|
42
|
+
if (level < 15) {
|
|
43
|
+
return 48;
|
|
44
|
+
}
|
|
45
|
+
return 64;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createOLImageRenderer(
|
|
49
|
+
options: OLImageRendererOptions,
|
|
50
|
+
): OLImageRenderer {
|
|
51
|
+
const maxCacheSize = parseInteger(options.tileCacheSize, 100);
|
|
52
|
+
const { tilingScheme, tileWidth, tileHeight, emptyCanvas, fetchFeatures } =
|
|
53
|
+
options;
|
|
54
|
+
const renderMap = new OLMap({
|
|
55
|
+
target: document.createElement('div'),
|
|
56
|
+
});
|
|
57
|
+
const tileCacheByLevel = new Map<number, LRUCache<HTMLCanvasElement>>();
|
|
58
|
+
|
|
59
|
+
let isRendering = false;
|
|
60
|
+
|
|
61
|
+
function getLevelCache(level: number): LRUCache<HTMLCanvasElement> {
|
|
62
|
+
const existing = tileCacheByLevel.get(level);
|
|
63
|
+
if (existing) {
|
|
64
|
+
return existing;
|
|
65
|
+
}
|
|
66
|
+
const cache = new LRUCache<HTMLCanvasElement>(maxCacheSize);
|
|
67
|
+
tileCacheByLevel.set(level, cache);
|
|
68
|
+
return cache;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function renderTile(
|
|
72
|
+
level: number,
|
|
73
|
+
extent: Extent,
|
|
74
|
+
gutterSize: number,
|
|
75
|
+
): Promise<HTMLCanvasElement> {
|
|
76
|
+
const TIMEOUT_MS = 2500;
|
|
77
|
+
return new Promise((resolve) => {
|
|
78
|
+
let isFinished = false;
|
|
79
|
+
const finish = (canvas: HTMLCanvasElement): void => {
|
|
80
|
+
if (isFinished) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
isFinished = true;
|
|
84
|
+
resolve(canvas);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
if (!renderMap) {
|
|
89
|
+
finish(emptyCanvas);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const renderWidth = tileWidth + 2 * gutterSize;
|
|
94
|
+
const renderHeight = tileHeight + 2 * gutterSize;
|
|
95
|
+
|
|
96
|
+
const view = renderMap.getView();
|
|
97
|
+
view.setCenter(getCenter(extent));
|
|
98
|
+
view.setZoom(level);
|
|
99
|
+
renderMap.setSize([renderWidth, renderHeight]);
|
|
100
|
+
|
|
101
|
+
const handleRenderComplete = (): void => {
|
|
102
|
+
renderMap?.un('rendercomplete', handleRenderComplete);
|
|
103
|
+
|
|
104
|
+
const renderedCanvas = renderMap
|
|
105
|
+
?.getViewport()
|
|
106
|
+
.querySelector('canvas');
|
|
107
|
+
|
|
108
|
+
if (!renderedCanvas) {
|
|
109
|
+
finish(emptyCanvas);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Crop the canvas to extract the center portion (original tile size)
|
|
114
|
+
const tileCanvas = document.createElement('canvas');
|
|
115
|
+
tileCanvas.width = tileWidth;
|
|
116
|
+
tileCanvas.height = tileHeight;
|
|
117
|
+
const ctx = tileCanvas.getContext('2d');
|
|
118
|
+
if (ctx) {
|
|
119
|
+
const scaleX = renderedCanvas.width / renderWidth;
|
|
120
|
+
const scaleY = renderedCanvas.height / renderHeight;
|
|
121
|
+
ctx.drawImage(
|
|
122
|
+
renderedCanvas,
|
|
123
|
+
gutterSize * scaleX,
|
|
124
|
+
gutterSize * scaleY,
|
|
125
|
+
tileWidth * scaleX,
|
|
126
|
+
tileHeight * scaleY,
|
|
127
|
+
0,
|
|
128
|
+
0,
|
|
129
|
+
tileWidth,
|
|
130
|
+
tileHeight,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
finish(tileCanvas);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const timeoutId = window.setTimeout(() => {
|
|
138
|
+
renderMap?.un('rendercomplete', handleRenderComplete);
|
|
139
|
+
getLogger('MapboxVectorTileImageryProvider').warning(
|
|
140
|
+
'Tile render timed out; returning empty tile.',
|
|
141
|
+
);
|
|
142
|
+
finish(emptyCanvas);
|
|
143
|
+
}, TIMEOUT_MS);
|
|
144
|
+
|
|
145
|
+
const wrappedHandleRenderComplete = (): void => {
|
|
146
|
+
window.clearTimeout(timeoutId);
|
|
147
|
+
handleRenderComplete();
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
renderMap.once('rendercomplete', wrappedHandleRenderComplete);
|
|
151
|
+
renderMap.render();
|
|
152
|
+
} catch (e: unknown) {
|
|
153
|
+
getLogger('MapboxVectorTileImageryProvider').error(
|
|
154
|
+
`Error rendering tile: ${(e as Error).message}`,
|
|
155
|
+
);
|
|
156
|
+
finish(emptyCanvas);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function doRequestImage(
|
|
162
|
+
x: number,
|
|
163
|
+
y: number,
|
|
164
|
+
level: number,
|
|
165
|
+
cacheKey: string,
|
|
166
|
+
): Promise<HTMLImageElement | HTMLCanvasElement> {
|
|
167
|
+
const rectangle = tilingScheme.tileXYToRectangle(x, y, level);
|
|
168
|
+
const extent = rectangleToMercatorExtent(rectangle);
|
|
169
|
+
|
|
170
|
+
// Add gutters to prevent labels from being cut off
|
|
171
|
+
const gutterSize = getGutterSize(level);
|
|
172
|
+
const gutter = ((extent[2] - extent[0]) / tileWidth) * gutterSize;
|
|
173
|
+
const expandedExtent = buffer(extent, gutter);
|
|
174
|
+
|
|
175
|
+
isRendering = true;
|
|
176
|
+
if (fetchFeatures) {
|
|
177
|
+
await fetchFeatures(x, y, level, expandedExtent);
|
|
178
|
+
}
|
|
179
|
+
const renderedTile = await renderTile(level, expandedExtent, gutterSize);
|
|
180
|
+
isRendering = false;
|
|
181
|
+
const levelCache = getLevelCache(level);
|
|
182
|
+
levelCache.set(cacheKey, renderedTile);
|
|
183
|
+
levelCache.expireCache();
|
|
184
|
+
return renderedTile;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
get map(): OLMap {
|
|
189
|
+
return renderMap;
|
|
190
|
+
},
|
|
191
|
+
get isRendering(): boolean {
|
|
192
|
+
return isRendering;
|
|
193
|
+
},
|
|
194
|
+
requestImage(
|
|
195
|
+
x: number,
|
|
196
|
+
y: number,
|
|
197
|
+
level: number,
|
|
198
|
+
): Promise<HTMLImageElement | HTMLCanvasElement> | undefined {
|
|
199
|
+
const cacheKey = getTileCacheKey(x, y, level);
|
|
200
|
+
const levelCache = getLevelCache(level);
|
|
201
|
+
if (levelCache.containsKey(cacheKey)) {
|
|
202
|
+
return Promise.resolve(levelCache.get(cacheKey));
|
|
203
|
+
}
|
|
204
|
+
if (isRendering) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
return doRequestImage(x, y, level, cacheKey);
|
|
208
|
+
},
|
|
209
|
+
destroy(): void {
|
|
210
|
+
for (const cache of tileCacheByLevel.values()) {
|
|
211
|
+
cache.clear();
|
|
212
|
+
}
|
|
213
|
+
tileCacheByLevel.clear();
|
|
214
|
+
isRendering = false;
|
|
215
|
+
renderMap.setTarget(undefined);
|
|
216
|
+
renderMap.dispose();
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type Extent as OLExtent } from 'ol/extent.js';
|
|
2
|
+
import VectorSource from 'ol/source/Vector.js';
|
|
3
|
+
import VectorLayer from 'ol/layer/Vector.js';
|
|
4
|
+
import { type VectorTileImageryProviderOptions } from './vectorTileImageryProvider.js';
|
|
5
|
+
import {
|
|
6
|
+
createOLImageRenderer,
|
|
7
|
+
type OLImageRenderer,
|
|
8
|
+
} from './olImageRenderer.js';
|
|
9
|
+
import Extent from '../../../util/extent.js';
|
|
10
|
+
import { mercatorProjection } from '../../../util/projection.js';
|
|
11
|
+
import AbstractVcsImageryProvider from './abstractVcsImageryProvider.js';
|
|
12
|
+
import type TileProvider from '../../tileProvider/tileProvider.js';
|
|
13
|
+
|
|
14
|
+
export default class PanoramaDatasetImageryProvider extends AbstractVcsImageryProvider {
|
|
15
|
+
private _source = new VectorSource({ useSpatialIndex: false });
|
|
16
|
+
|
|
17
|
+
private _olImageRenderer: OLImageRenderer;
|
|
18
|
+
|
|
19
|
+
tileProvider: TileProvider;
|
|
20
|
+
|
|
21
|
+
constructor(options: VectorTileImageryProviderOptions) {
|
|
22
|
+
super({
|
|
23
|
+
tilingScheme: options.tileProvider.tilingScheme,
|
|
24
|
+
tileSize: options.tileSize,
|
|
25
|
+
minLevel: 0,
|
|
26
|
+
maxLevel: 26,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.tileProvider = options.tileProvider;
|
|
30
|
+
|
|
31
|
+
this._olImageRenderer = createOLImageRenderer({
|
|
32
|
+
tilingScheme: this.tileProvider.tilingScheme,
|
|
33
|
+
tileWidth: this.tileWidth,
|
|
34
|
+
tileHeight: this.tileHeight,
|
|
35
|
+
emptyCanvas: this.emptyCanvas,
|
|
36
|
+
fetchFeatures: this._fetchFeatures.bind(this),
|
|
37
|
+
});
|
|
38
|
+
this._olImageRenderer.map.addLayer(
|
|
39
|
+
new VectorLayer({ source: this._source, declutter: true }),
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
requestImage(
|
|
44
|
+
x: number,
|
|
45
|
+
y: number,
|
|
46
|
+
level: number,
|
|
47
|
+
): Promise<HTMLImageElement | HTMLCanvasElement> | undefined {
|
|
48
|
+
return this._olImageRenderer.requestImage(x, y, level);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private async _fetchFeatures(
|
|
52
|
+
_x: number,
|
|
53
|
+
_y: number,
|
|
54
|
+
level: number,
|
|
55
|
+
extent: OLExtent,
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
const vcsExtent = new Extent({
|
|
58
|
+
coordinates: extent,
|
|
59
|
+
projection: mercatorProjection.toJSON(),
|
|
60
|
+
});
|
|
61
|
+
const features = await this.tileProvider.getFeaturesForExtent(
|
|
62
|
+
vcsExtent,
|
|
63
|
+
level,
|
|
64
|
+
);
|
|
65
|
+
this._source.clear(true);
|
|
66
|
+
this._source.addFeatures(features);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
destroy(): void {
|
|
70
|
+
this._source.dispose();
|
|
71
|
+
this._olImageRenderer.destroy();
|
|
72
|
+
}
|
|
73
|
+
}
|