anymap-ts 0.10.0 → 0.11.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/anymap_ts/static/cesium.css +1 -0
- package/anymap_ts/static/cesium.js +16543 -1
- package/anymap_ts/static/leaflet.css +1 -1
- package/anymap_ts/static/leaflet.js +1 -1
- package/anymap_ts/static/openlayers.css +1 -1
- package/anymap_ts/static/openlayers.js +602 -7
- package/package.json +3 -2
- package/src/cesium/index.ts +43 -99
- package/src/leaflet/LeafletRenderer.ts +684 -113
- package/src/leaflet/index.ts +23 -0
- package/src/leaflet/leaflet-overrides.css +31 -0
- package/src/leaflet/leaflet-setup.ts +13 -0
- package/src/openlayers/OpenLayersRenderer.ts +1275 -181
- package/src/openlayers/index.ts +1 -0
- package/src/styles/openlayers.css +39 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anymap-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "TypeScript frontend for anymap-ts interactive maps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"build:leaflet": "esbuild src/leaflet/index.ts --bundle --format=esm --outfile=anymap_ts/static/leaflet.js --loader:.css=css --loader:.png=dataurl --minify",
|
|
11
11
|
"build:deckgl": "esbuild src/deckgl/index.ts --bundle --format=esm --outfile=anymap_ts/static/deckgl.js --loader:.css=css --external:path --external:fs --minify",
|
|
12
12
|
"build:openlayers": "esbuild src/openlayers/index.ts --bundle --format=esm --outfile=anymap_ts/static/openlayers.js --loader:.css=css --minify",
|
|
13
|
-
"build:cesium": "esbuild src/cesium/index.ts --bundle --format=esm --outfile=anymap_ts/static/cesium.js --loader:.css=css --minify",
|
|
13
|
+
"build:cesium": "esbuild src/cesium/index.ts --bundle --format=esm --outfile=anymap_ts/static/cesium.js --loader:.css=css --alias:cesium=./node_modules/cesium/Build/Cesium/index.js --alias:cesium-widgets-css=./node_modules/cesium/Build/Cesium/Widgets/widgets.css --define:CESIUM_BASE_URL='\"https://cesium.com/downloads/cesiumjs/releases/1.138/Build/Cesium/\"' --minify",
|
|
14
14
|
"build:keplergl": "esbuild src/keplergl/index.ts --bundle --format=esm --outfile=anymap_ts/static/keplergl.js --loader:.css=css --minify",
|
|
15
15
|
"build:potree": "esbuild src/potree/index.ts --bundle --format=esm --outfile=anymap_ts/static/potree.js --loader:.css=css --minify",
|
|
16
16
|
"build:custom-css": "esbuild src/styles/maplibre.css --bundle --outfile=anymap_ts/static/custom.css --loader:.css=css --minify",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"geotiff-geokeys-to-proj4": "^2024.4.13",
|
|
53
53
|
"jspdf": "^4.1.0",
|
|
54
54
|
"leaflet": "^1.9.4",
|
|
55
|
+
"leaflet.heat": "^0.2.0",
|
|
55
56
|
"mapbox-gl": "^3.18.1",
|
|
56
57
|
"maplibre-gl": ">=5.14.0",
|
|
57
58
|
"maplibre-gl-components": "^0.15.0",
|
package/src/cesium/index.ts
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cesium 3D globe widget entry point.
|
|
3
3
|
*
|
|
4
|
-
* Cesium is
|
|
5
|
-
*
|
|
4
|
+
* Cesium is bundled from the npm package to avoid CORS issues
|
|
5
|
+
* in VS Code/Cursor notebook webviews.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { AnyModel } from '@anywidget/types';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
9
|
+
import {
|
|
10
|
+
Viewer,
|
|
11
|
+
Cartesian3,
|
|
12
|
+
Ion,
|
|
13
|
+
UrlTemplateImageryProvider,
|
|
14
|
+
Terrain,
|
|
15
|
+
GeoJsonDataSource,
|
|
16
|
+
Color,
|
|
17
|
+
Math as CesiumMath,
|
|
18
|
+
} from 'cesium';
|
|
19
|
+
|
|
20
|
+
// Import Cesium widget CSS from the pre-built bundle
|
|
21
|
+
import 'cesium-widgets-css';
|
|
23
22
|
|
|
24
23
|
interface CesiumModel extends AnyModel {
|
|
25
24
|
get(key: 'center'): [number, number];
|
|
@@ -30,50 +29,6 @@ interface CesiumModel extends AnyModel {
|
|
|
30
29
|
get(key: '_js_calls'): Array<{ id: number; method: string; args: unknown[]; kwargs: Record<string, unknown> }>;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
/**
|
|
34
|
-
* Load Cesium CSS dynamically.
|
|
35
|
-
*/
|
|
36
|
-
function loadCesiumCSS(): void {
|
|
37
|
-
if (!document.querySelector(`link[href="${CESIUM_CSS_URL}"]`)) {
|
|
38
|
-
const link = document.createElement('link');
|
|
39
|
-
link.rel = 'stylesheet';
|
|
40
|
-
link.href = CESIUM_CSS_URL;
|
|
41
|
-
document.head.appendChild(link);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Load Cesium JS dynamically.
|
|
47
|
-
*/
|
|
48
|
-
function loadCesiumJS(): Promise<void> {
|
|
49
|
-
return new Promise((resolve, reject) => {
|
|
50
|
-
// Check if already loaded
|
|
51
|
-
if (window.Cesium) {
|
|
52
|
-
resolve();
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Check if script is already loading
|
|
57
|
-
const existingScript = document.querySelector(`script[src="${CESIUM_JS_URL}"]`);
|
|
58
|
-
if (existingScript) {
|
|
59
|
-
existingScript.addEventListener('load', () => resolve());
|
|
60
|
-
existingScript.addEventListener('error', () => reject(new Error('Failed to load Cesium')));
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Set Cesium base URL for asset loading
|
|
65
|
-
window.CESIUM_BASE_URL = CESIUM_BASE_URL;
|
|
66
|
-
|
|
67
|
-
// Load script
|
|
68
|
-
const script = document.createElement('script');
|
|
69
|
-
script.src = CESIUM_JS_URL;
|
|
70
|
-
script.async = true;
|
|
71
|
-
script.onload = () => resolve();
|
|
72
|
-
script.onerror = () => reject(new Error('Failed to load Cesium'));
|
|
73
|
-
document.head.appendChild(script);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
32
|
/**
|
|
78
33
|
* Convert zoom level to camera height.
|
|
79
34
|
*/
|
|
@@ -100,18 +55,13 @@ class CesiumWidget {
|
|
|
100
55
|
}
|
|
101
56
|
|
|
102
57
|
async initialize(): Promise<void> {
|
|
103
|
-
const Cesium = window.Cesium;
|
|
104
|
-
if (!Cesium) {
|
|
105
|
-
throw new Error('Cesium not loaded');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
58
|
const accessToken = this.model.get('access_token') || '';
|
|
109
59
|
const center = this.model.get('center') || [0, 0];
|
|
110
60
|
const zoom = this.model.get('zoom') || 2;
|
|
111
61
|
|
|
112
62
|
// Set access token
|
|
113
63
|
if (accessToken) {
|
|
114
|
-
|
|
64
|
+
Ion.defaultAccessToken = accessToken;
|
|
115
65
|
}
|
|
116
66
|
|
|
117
67
|
// Set up parent element
|
|
@@ -129,8 +79,9 @@ class CesiumWidget {
|
|
|
129
79
|
// Calculate camera height from zoom
|
|
130
80
|
const height = zoomToHeight(zoom);
|
|
131
81
|
|
|
132
|
-
// Create viewer
|
|
133
|
-
|
|
82
|
+
// Create viewer without default Ion imagery (which fails in VS Code webviews due to CORS).
|
|
83
|
+
// Use OpenStreetMap as the default base layer instead.
|
|
84
|
+
this.viewer = new Viewer(this.container, {
|
|
134
85
|
baseLayerPicker: false,
|
|
135
86
|
geocoder: false,
|
|
136
87
|
homeButton: false,
|
|
@@ -142,11 +93,19 @@ class CesiumWidget {
|
|
|
142
93
|
vrButton: false,
|
|
143
94
|
selectionIndicator: false,
|
|
144
95
|
infoBox: false,
|
|
96
|
+
baseLayer: false,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Add OpenStreetMap as default basemap
|
|
100
|
+
const osmProvider = new UrlTemplateImageryProvider({
|
|
101
|
+
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
|
102
|
+
maximumLevel: 19,
|
|
145
103
|
});
|
|
104
|
+
this.viewer.imageryLayers.addImageryProvider(osmProvider);
|
|
146
105
|
|
|
147
106
|
// Set initial camera position
|
|
148
107
|
this.viewer.camera.setView({
|
|
149
|
-
destination:
|
|
108
|
+
destination: Cartesian3.fromDegrees(center[0], center[1], height),
|
|
150
109
|
});
|
|
151
110
|
|
|
152
111
|
// Process pending JS calls
|
|
@@ -182,37 +141,34 @@ class CesiumWidget {
|
|
|
182
141
|
}
|
|
183
142
|
|
|
184
143
|
private onCenterChange(): void {
|
|
185
|
-
const Cesium = window.Cesium;
|
|
186
144
|
const newCenter = this.model.get('center');
|
|
187
|
-
if (this.viewer
|
|
145
|
+
if (this.viewer) {
|
|
188
146
|
const currentHeight = this.viewer.camera.positionCartographic.height;
|
|
189
147
|
this.viewer.camera.flyTo({
|
|
190
|
-
destination:
|
|
148
|
+
destination: Cartesian3.fromDegrees(newCenter[0], newCenter[1], currentHeight),
|
|
191
149
|
});
|
|
192
150
|
}
|
|
193
151
|
}
|
|
194
152
|
|
|
195
153
|
// Method handlers
|
|
196
154
|
handle_addBasemap(args: unknown[], kwargs: Record<string, unknown>): void {
|
|
197
|
-
|
|
198
|
-
if (!this.viewer || !Cesium) return;
|
|
155
|
+
if (!this.viewer) return;
|
|
199
156
|
|
|
200
157
|
const url = args[0] as string;
|
|
201
158
|
const name = kwargs.name as string || 'basemap';
|
|
202
159
|
|
|
203
|
-
const imageryProvider = new
|
|
160
|
+
const imageryProvider = new UrlTemplateImageryProvider({ url });
|
|
204
161
|
const layer = this.viewer.imageryLayers.addImageryProvider(imageryProvider);
|
|
205
162
|
this.imageryLayers.set(name, layer);
|
|
206
163
|
}
|
|
207
164
|
|
|
208
165
|
handle_setTerrain(args: unknown[], kwargs: Record<string, unknown>): void {
|
|
209
|
-
|
|
210
|
-
if (!this.viewer || !Cesium) return;
|
|
166
|
+
if (!this.viewer) return;
|
|
211
167
|
|
|
212
168
|
const url = kwargs.url as string;
|
|
213
169
|
if (url === 'cesium-world-terrain' || !url) {
|
|
214
170
|
this.viewer.scene.setTerrain(
|
|
215
|
-
|
|
171
|
+
Terrain.fromWorldTerrain({
|
|
216
172
|
requestVertexNormals: true,
|
|
217
173
|
requestWaterMask: true,
|
|
218
174
|
})
|
|
@@ -221,8 +177,7 @@ class CesiumWidget {
|
|
|
221
177
|
}
|
|
222
178
|
|
|
223
179
|
handle_flyTo(args: unknown[], kwargs: Record<string, unknown>): void {
|
|
224
|
-
|
|
225
|
-
if (!this.viewer || !Cesium) return;
|
|
180
|
+
if (!this.viewer) return;
|
|
226
181
|
|
|
227
182
|
const lng = args[0] as number;
|
|
228
183
|
const lat = args[1] as number;
|
|
@@ -232,10 +187,10 @@ class CesiumWidget {
|
|
|
232
187
|
const duration = kwargs.duration as number ?? 2;
|
|
233
188
|
|
|
234
189
|
this.viewer.camera.flyTo({
|
|
235
|
-
destination:
|
|
190
|
+
destination: Cartesian3.fromDegrees(lng, lat, height),
|
|
236
191
|
orientation: {
|
|
237
|
-
heading:
|
|
238
|
-
pitch:
|
|
192
|
+
heading: CesiumMath.toRadians(heading),
|
|
193
|
+
pitch: CesiumMath.toRadians(pitch),
|
|
239
194
|
roll: 0,
|
|
240
195
|
},
|
|
241
196
|
duration: duration,
|
|
@@ -248,8 +203,7 @@ class CesiumWidget {
|
|
|
248
203
|
}
|
|
249
204
|
|
|
250
205
|
async handle_addGeoJSON(args: unknown[], kwargs: Record<string, unknown>): Promise<void> {
|
|
251
|
-
|
|
252
|
-
if (!this.viewer || !Cesium) return;
|
|
206
|
+
if (!this.viewer) return;
|
|
253
207
|
|
|
254
208
|
const data = kwargs.data as object;
|
|
255
209
|
const name = kwargs.name as string || `geojson-${this.dataSources.size}`;
|
|
@@ -257,9 +211,9 @@ class CesiumWidget {
|
|
|
257
211
|
const fill = kwargs.fill as string || 'rgba(51, 136, 255, 0.5)';
|
|
258
212
|
|
|
259
213
|
try {
|
|
260
|
-
const dataSource = await
|
|
261
|
-
stroke:
|
|
262
|
-
fill:
|
|
214
|
+
const dataSource = await GeoJsonDataSource.load(data, {
|
|
215
|
+
stroke: Color.fromCssColorString(stroke),
|
|
216
|
+
fill: Color.fromCssColorString(fill),
|
|
263
217
|
clampToGround: true,
|
|
264
218
|
});
|
|
265
219
|
|
|
@@ -294,17 +248,6 @@ let widget: CesiumWidget | null = null;
|
|
|
294
248
|
* anywidget render function.
|
|
295
249
|
*/
|
|
296
250
|
async function render({ model, el }: { model: CesiumModel; el: HTMLElement }): Promise<() => void> {
|
|
297
|
-
// Load Cesium CSS and JS
|
|
298
|
-
loadCesiumCSS();
|
|
299
|
-
|
|
300
|
-
try {
|
|
301
|
-
await loadCesiumJS();
|
|
302
|
-
} catch (error) {
|
|
303
|
-
console.error('Failed to load Cesium:', error);
|
|
304
|
-
el.innerHTML = '<div style="padding: 20px; color: red;">Failed to load Cesium library</div>';
|
|
305
|
-
return () => {};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
251
|
// Create widget
|
|
309
252
|
widget = new CesiumWidget(model as CesiumModel, el);
|
|
310
253
|
|
|
@@ -313,6 +256,7 @@ async function render({ model, el }: { model: CesiumModel; el: HTMLElement }): P
|
|
|
313
256
|
await widget.initialize();
|
|
314
257
|
} catch (error) {
|
|
315
258
|
console.error('Failed to initialize Cesium viewer:', error);
|
|
259
|
+
el.innerHTML = '<div style="padding: 20px; color: red;">Failed to initialize Cesium viewer</div>';
|
|
316
260
|
}
|
|
317
261
|
|
|
318
262
|
// Return cleanup function
|