@treasuryspatial/map-react 0.1.7 → 0.1.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.
|
@@ -14,7 +14,7 @@ export type MapModeViewportHandle = {
|
|
|
14
14
|
animateToView: (_viewKey: string) => void;
|
|
15
15
|
capturePngDataUrl: () => string;
|
|
16
16
|
};
|
|
17
|
-
export type ApplyLightingPreset = (scene: THREE.Scene, presetKey: string) => void;
|
|
17
|
+
export type ApplyLightingPreset = (scene: THREE.Scene, renderer: THREE.WebGLRenderer, presetKey: string) => void;
|
|
18
18
|
export type ResolveMeshGroup = (geometry3dm: string) => Promise<THREE.Group | null>;
|
|
19
19
|
export type MapModeViewportProps = {
|
|
20
20
|
active: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapModeViewport.d.ts","sourceRoot":"","sources":["../src/MapModeViewport.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"MapModeViewport.d.ts","sourceRoot":"","sources":["../src/MapModeViewport.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA6F,MAAM,OAAO,CAAC;AAElH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEhD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EASL,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC3B,MAAM,0BAA0B,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,qBAAqB,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC;IACxB,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,iBAAiB,EAAE,MAAM,MAAM,CAAC;CACjC,CAAC;AAIF,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;AACjH,MAAM,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;AAEpF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,aAAa,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;IACpC,iBAAiB,EAAE,CAAC,SAAS,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAMF,eAAO,MAAM,eAAe,oGAma1B,CAAC"}
|
package/dist/MapModeViewport.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
|
|
5
5
|
import * as THREE from 'three';
|
|
6
6
|
import { buildGeoJsonPolygon, computeCentroid, computeFootprintStats, createMapThreeLayer, ensureFootprintLayers, getOuterRing, toLocalMeters, toPolygonFeature, } from '@treasuryspatial/map-kit';
|
|
@@ -25,6 +25,17 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
25
25
|
const reverseGeocodeRequestRef = useRef(0);
|
|
26
26
|
const [mapReady, setMapReady] = useState(false);
|
|
27
27
|
const [mapError, setMapError] = useState('');
|
|
28
|
+
const debug = useMemo(() => {
|
|
29
|
+
if (typeof window === 'undefined')
|
|
30
|
+
return false;
|
|
31
|
+
const params = new URLSearchParams(window.location.search);
|
|
32
|
+
return params.has('mapDebug') || process.env.NODE_ENV !== 'production';
|
|
33
|
+
}, []);
|
|
34
|
+
const log = useCallback((...args) => {
|
|
35
|
+
if (!debug)
|
|
36
|
+
return;
|
|
37
|
+
console.info('[map-react]', ...args);
|
|
38
|
+
}, [debug]);
|
|
28
39
|
useEffect(() => {
|
|
29
40
|
lightingPresetRef.current = lightingPreset;
|
|
30
41
|
}, [lightingPreset]);
|
|
@@ -44,8 +55,8 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
44
55
|
useImperativeHandle(ref, () => ({
|
|
45
56
|
setLightingPreset: (presetKey) => {
|
|
46
57
|
lightingPresetRef.current = presetKey;
|
|
47
|
-
if (sceneRef.current) {
|
|
48
|
-
(applyLightingPreset ?? defaultApplyLightingPreset)(sceneRef.current, presetKey);
|
|
58
|
+
if (sceneRef.current && rendererRef.current) {
|
|
59
|
+
(applyLightingPreset ?? defaultApplyLightingPreset)(sceneRef.current, rendererRef.current, presetKey);
|
|
49
60
|
}
|
|
50
61
|
},
|
|
51
62
|
animateToView: () => { },
|
|
@@ -71,6 +82,8 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
71
82
|
return;
|
|
72
83
|
}
|
|
73
84
|
let cancelled = false;
|
|
85
|
+
let cleanupCanvasEvents = null;
|
|
86
|
+
let cleanupMapEvents = null;
|
|
74
87
|
const boot = async () => {
|
|
75
88
|
try {
|
|
76
89
|
const module = await import('mapbox-gl');
|
|
@@ -95,6 +108,13 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
95
108
|
preserveDrawingBuffer: true,
|
|
96
109
|
attributionControl: false,
|
|
97
110
|
});
|
|
111
|
+
log('map init', {
|
|
112
|
+
style: mapStyle,
|
|
113
|
+
center: [startCenter.lng, startCenter.lat],
|
|
114
|
+
zoom: startZoom,
|
|
115
|
+
bearing: startBearing,
|
|
116
|
+
pitch: startPitch,
|
|
117
|
+
});
|
|
98
118
|
map.addControl(new mapboxgl.NavigationControl({ visualizePitch: true }), 'bottom-right');
|
|
99
119
|
const geocoder = new MapboxGeocoder({
|
|
100
120
|
accessToken,
|
|
@@ -106,6 +126,30 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
106
126
|
});
|
|
107
127
|
map.addControl(geocoder, 'top-left');
|
|
108
128
|
mapRef.current = map;
|
|
129
|
+
const onMapError = (event) => {
|
|
130
|
+
const err = event?.error ?? event;
|
|
131
|
+
console.error('[map-react] Mapbox error', err);
|
|
132
|
+
};
|
|
133
|
+
map.on('error', onMapError);
|
|
134
|
+
cleanupMapEvents = () => {
|
|
135
|
+
map.off('error', onMapError);
|
|
136
|
+
};
|
|
137
|
+
const canvas = map.getCanvas();
|
|
138
|
+
const onContextLost = (event) => {
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
console.error('[map-react] WebGL context lost');
|
|
141
|
+
setMapError('WebGL context lost.');
|
|
142
|
+
};
|
|
143
|
+
const onContextRestored = () => {
|
|
144
|
+
console.info('[map-react] WebGL context restored');
|
|
145
|
+
setMapError('');
|
|
146
|
+
};
|
|
147
|
+
canvas.addEventListener('webglcontextlost', onContextLost, { passive: false });
|
|
148
|
+
canvas.addEventListener('webglcontextrestored', onContextRestored);
|
|
149
|
+
cleanupCanvasEvents = () => {
|
|
150
|
+
canvas.removeEventListener('webglcontextlost', onContextLost);
|
|
151
|
+
canvas.removeEventListener('webglcontextrestored', onContextRestored);
|
|
152
|
+
};
|
|
109
153
|
map.on('style.load', () => {
|
|
110
154
|
if (!map.isStyleLoaded())
|
|
111
155
|
return;
|
|
@@ -153,6 +197,8 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
153
197
|
threeLayerRef.current = null;
|
|
154
198
|
setMapReady(false);
|
|
155
199
|
handlersBoundRef.current = false;
|
|
200
|
+
cleanupCanvasEvents?.();
|
|
201
|
+
cleanupMapEvents?.();
|
|
156
202
|
};
|
|
157
203
|
}, [active, accessToken, mapStyle, mapVisibility]);
|
|
158
204
|
useEffect(() => {
|
|
@@ -223,12 +269,13 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
223
269
|
threeLayerRef.current = createMapThreeLayer({
|
|
224
270
|
id: 'courtyard-mesh',
|
|
225
271
|
zOffsetMeters: 0.05,
|
|
272
|
+
debug,
|
|
226
273
|
onInit: (scene, renderer) => {
|
|
227
274
|
sceneRef.current = scene;
|
|
228
275
|
rendererRef.current = renderer;
|
|
229
|
-
renderer.
|
|
230
|
-
renderer.
|
|
231
|
-
(applyLightingPreset ?? defaultApplyLightingPreset)(scene, lightingPresetRef.current);
|
|
276
|
+
renderer.shadowMap.enabled = true;
|
|
277
|
+
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
278
|
+
(applyLightingPreset ?? defaultApplyLightingPreset)(scene, renderer, lightingPresetRef.current);
|
|
232
279
|
},
|
|
233
280
|
});
|
|
234
281
|
}
|
|
@@ -313,6 +360,31 @@ export const MapModeViewport = forwardRef(function MapModeViewport({ active, geo
|
|
|
313
360
|
};
|
|
314
361
|
return (_jsxs("div", { className: "absolute inset-0", children: [_jsx("div", { ref: containerRef, className: "w-full h-full" }), !accessToken && (_jsx("div", { className: "absolute inset-0 z-[2] flex items-center justify-center bg-black/70 text-xs text-white font-nunito", children: "Mapbox access token missing." })), mapError && (_jsx("div", { className: "absolute inset-0 z-[2] flex items-center justify-center bg-black/70 text-xs text-white font-nunito", children: mapError })), !mapReady && !mapError && accessToken && (_jsx("div", { className: "absolute inset-0 z-[2] flex items-center justify-center bg-black/60 text-xs text-white font-nunito", children: "loading map\u2026" }))] }));
|
|
315
362
|
});
|
|
363
|
+
const ensureGeometryUvs = (geometry) => {
|
|
364
|
+
if (geometry.getAttribute('uv'))
|
|
365
|
+
return;
|
|
366
|
+
const pos = geometry.getAttribute('position');
|
|
367
|
+
if (!pos)
|
|
368
|
+
return;
|
|
369
|
+
geometry.computeBoundingBox();
|
|
370
|
+
const bbox = geometry.boundingBox;
|
|
371
|
+
if (!bbox)
|
|
372
|
+
return;
|
|
373
|
+
const size = new THREE.Vector3();
|
|
374
|
+
bbox.getSize(size);
|
|
375
|
+
const uvs = new Float32Array(pos.count * 2);
|
|
376
|
+
const denomX = size.x || 1;
|
|
377
|
+
const denomZ = size.z || 1;
|
|
378
|
+
for (let i = 0; i < pos.count; i += 1) {
|
|
379
|
+
const x = pos.getX(i);
|
|
380
|
+
const z = pos.getZ(i);
|
|
381
|
+
const u = (x - bbox.min.x) / denomX;
|
|
382
|
+
const v = (z - bbox.min.z) / denomZ;
|
|
383
|
+
uvs[i * 2] = u;
|
|
384
|
+
uvs[i * 2 + 1] = v;
|
|
385
|
+
}
|
|
386
|
+
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
|
|
387
|
+
};
|
|
316
388
|
function applyMaterialOverrides(group, settings) {
|
|
317
389
|
const color = new THREE.Color(settings?.color ?? '#ffffff');
|
|
318
390
|
const textureUrl = settings?.textureUrl;
|
|
@@ -337,9 +409,12 @@ function applyMaterialOverrides(group, settings) {
|
|
|
337
409
|
else
|
|
338
410
|
material?.dispose?.();
|
|
339
411
|
}
|
|
412
|
+
if (texture) {
|
|
413
|
+
ensureGeometryUvs(mesh.geometry);
|
|
414
|
+
}
|
|
340
415
|
mesh.material = new THREE.MeshStandardMaterial({
|
|
341
416
|
color,
|
|
342
|
-
roughness: 0.
|
|
417
|
+
roughness: 0.75,
|
|
343
418
|
metalness: 0,
|
|
344
419
|
side: THREE.DoubleSide,
|
|
345
420
|
map: texture ?? null,
|
|
@@ -347,10 +422,12 @@ function applyMaterialOverrides(group, settings) {
|
|
|
347
422
|
mesh.material.polygonOffset = true;
|
|
348
423
|
mesh.material.polygonOffsetFactor = 1.0;
|
|
349
424
|
mesh.material.polygonOffsetUnits = 1.0;
|
|
425
|
+
mesh.castShadow = false;
|
|
426
|
+
mesh.receiveShadow = false;
|
|
350
427
|
});
|
|
351
428
|
}
|
|
352
|
-
function defaultApplyLightingPreset(scene, _presetKey) {
|
|
353
|
-
scene.background =
|
|
429
|
+
function defaultApplyLightingPreset(scene, renderer, _presetKey) {
|
|
430
|
+
scene.background = new THREE.Color('#ffffff');
|
|
354
431
|
const lightsToRemove = scene.children.filter((child) => child instanceof THREE.Light);
|
|
355
432
|
lightsToRemove.forEach((light) => scene.remove(light));
|
|
356
433
|
scene.add(new THREE.AmbientLight('#ffffff', 0.6));
|
|
@@ -361,6 +438,8 @@ function defaultApplyLightingPreset(scene, _presetKey) {
|
|
|
361
438
|
const fill = new THREE.DirectionalLight('#ffffff', 0.4);
|
|
362
439
|
fill.position.set(-6, 8, -6);
|
|
363
440
|
scene.add(fill);
|
|
441
|
+
renderer.toneMapping = THREE.NeutralToneMapping;
|
|
442
|
+
renderer.toneMappingExposure = 1.05;
|
|
364
443
|
}
|
|
365
444
|
function applyMapVisibility(map, mode, cacheRef) {
|
|
366
445
|
if (!map?.getStyle?.())
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treasuryspatial/map-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@treasuryspatial/map-kit": "^0.1.
|
|
21
|
+
"@treasuryspatial/map-kit": "^0.1.4"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"react": ">=18",
|