@dxos/react-ui-geo 0.8.1 → 0.8.2-main.2f9c567
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/lib/browser/index.mjs +45 -55
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +40 -50
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +45 -55
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
- package/dist/types/src/components/Map/Map.stories.d.ts +5 -4
- package/dist/types/src/components/Map/Map.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useTour.d.ts +1 -1
- package/dist/types/src/hooks/useTour.d.ts.map +1 -1
- package/dist/types/src/util/inertia.d.ts +1 -2
- package/dist/types/src/util/inertia.d.ts.map +1 -1
- package/dist/types/src/util/path.d.ts.map +1 -1
- package/dist/types/src/util/render.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/components/Globe/Globe.tsx +20 -11
- package/src/components/Map/Map.stories.tsx +4 -4
- package/src/hooks/useDrag.ts +3 -3
- package/src/hooks/useSpinner.ts +2 -2
- package/src/hooks/useTour.ts +9 -13
- package/src/util/inertia.ts +4 -5
- package/src/util/path.ts +2 -5
- package/src/util/render.ts +5 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-geo",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2-main.2f9c567",
|
|
4
4
|
"description": "Geo components.",
|
|
5
5
|
"homepage": "https://github.com/dxos",
|
|
6
6
|
"bugs": "https://github.com/dxos/issues",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"topojson-client": "^3.1.0",
|
|
46
46
|
"topojson-simplify": "^3.0.3",
|
|
47
47
|
"versor": "^0.2.0",
|
|
48
|
-
"@dxos/async": "0.8.
|
|
49
|
-
"@dxos/debug": "0.8.
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/
|
|
48
|
+
"@dxos/async": "0.8.2-main.2f9c567",
|
|
49
|
+
"@dxos/debug": "0.8.2-main.2f9c567",
|
|
50
|
+
"@dxos/log": "0.8.2-main.2f9c567",
|
|
51
|
+
"@dxos/util": "0.8.2-main.2f9c567",
|
|
52
|
+
"@dxos/node-std": "0.8.2-main.2f9c567"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@react-three/drei": "^9.99.0",
|
|
@@ -69,15 +69,15 @@
|
|
|
69
69
|
"react": "~18.2.0",
|
|
70
70
|
"react-dom": "~18.2.0",
|
|
71
71
|
"three": "0.165.0",
|
|
72
|
-
"@dxos/react-ui": "0.8.
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
72
|
+
"@dxos/react-ui": "0.8.2-main.2f9c567",
|
|
73
|
+
"@dxos/react-ui-theme": "0.8.2-main.2f9c567",
|
|
74
|
+
"@dxos/storybook-utils": "0.8.2-main.2f9c567"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"react": "~18.2.0",
|
|
78
78
|
"react-dom": "~18.2.0",
|
|
79
|
-
"@dxos/react-ui
|
|
80
|
-
"@dxos/react-ui": "0.8.
|
|
79
|
+
"@dxos/react-ui": "0.8.2-main.2f9c567",
|
|
80
|
+
"@dxos/react-ui-theme": "0.8.2-main.2f9c567"
|
|
81
81
|
},
|
|
82
82
|
"publishConfig": {
|
|
83
83
|
"access": "public"
|
|
@@ -2,8 +2,17 @@
|
|
|
2
2
|
// Copyright 2018 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
type GeoProjection,
|
|
7
|
+
geoMercator,
|
|
8
|
+
geoOrthographic,
|
|
9
|
+
geoPath,
|
|
10
|
+
geoTransverseMercator,
|
|
11
|
+
interpolateNumber,
|
|
12
|
+
transition,
|
|
13
|
+
easeLinear,
|
|
14
|
+
easeSinOut,
|
|
15
|
+
} from 'd3';
|
|
7
16
|
import { type ControlPosition } from 'leaflet';
|
|
8
17
|
import React, {
|
|
9
18
|
type PropsWithChildren,
|
|
@@ -99,18 +108,18 @@ export type GlobeController = {
|
|
|
99
108
|
export type ProjectionType = 'orthographic' | 'mercator' | 'transverse-mercator';
|
|
100
109
|
|
|
101
110
|
const projectionMap: Record<ProjectionType, () => GeoProjection> = {
|
|
102
|
-
orthographic:
|
|
103
|
-
mercator:
|
|
104
|
-
'transverse-mercator':
|
|
111
|
+
orthographic: geoOrthographic,
|
|
112
|
+
mercator: geoMercator,
|
|
113
|
+
'transverse-mercator': geoTransverseMercator,
|
|
105
114
|
};
|
|
106
115
|
|
|
107
116
|
const getProjection = (type: GlobeCanvasProps['projection'] = 'orthographic'): GeoProjection => {
|
|
108
117
|
if (typeof type === 'string') {
|
|
109
|
-
const constructor = projectionMap[type] ??
|
|
118
|
+
const constructor = projectionMap[type] ?? geoOrthographic;
|
|
110
119
|
return constructor();
|
|
111
120
|
}
|
|
112
121
|
|
|
113
|
-
return type ??
|
|
122
|
+
return type ?? geoOrthographic();
|
|
114
123
|
};
|
|
115
124
|
|
|
116
125
|
//
|
|
@@ -194,10 +203,10 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
|
|
|
194
203
|
setCenter,
|
|
195
204
|
setScale: (s) => {
|
|
196
205
|
if (typeof s === 'function') {
|
|
197
|
-
const is =
|
|
206
|
+
const is = interpolateNumber(scaleRef.current, s(scaleRef.current));
|
|
198
207
|
// Stop easing if already zooming.
|
|
199
|
-
|
|
200
|
-
.ease(zooming.current ?
|
|
208
|
+
transition()
|
|
209
|
+
.ease(zooming.current ? easeLinear : easeSinOut)
|
|
201
210
|
.duration(200)
|
|
202
211
|
.tween('scale', () => (t) => setScale(is(t)))
|
|
203
212
|
.on('end', () => {
|
|
@@ -217,7 +226,7 @@ const GlobeCanvas = forwardRef<GlobeController, GlobeCanvasProps>(
|
|
|
217
226
|
// https://d3js.org/d3-geo/path#geoPath
|
|
218
227
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext
|
|
219
228
|
const generator = useMemo(
|
|
220
|
-
() => canvas && projection &&
|
|
229
|
+
() => canvas && projection && geoPath(projection, canvas.getContext('2d', { alpha: false })),
|
|
221
230
|
[canvas, projection],
|
|
222
231
|
);
|
|
223
232
|
|
|
@@ -13,7 +13,7 @@ import { Map, type MapController } from './Map';
|
|
|
13
13
|
import { useMapZoomHandler } from '../../hooks';
|
|
14
14
|
import { type MapMarker } from '../../types';
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const DefaultStory = ({ markers = [] }: { markers?: MapMarker[] }) => {
|
|
17
17
|
const [controller, setController] = useState<MapController>();
|
|
18
18
|
const handleZoomAction = useMapZoomHandler(controller);
|
|
19
19
|
|
|
@@ -26,15 +26,15 @@ const Render = ({ markers }) => {
|
|
|
26
26
|
);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const meta: Meta<typeof
|
|
29
|
+
const meta: Meta<typeof DefaultStory> = {
|
|
30
30
|
title: 'ui/react-ui-geo/Map',
|
|
31
|
-
|
|
31
|
+
render: DefaultStory,
|
|
32
32
|
decorators: [withTheme, withLayout({ fullscreen: true, tooltips: true })],
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export default meta;
|
|
36
36
|
|
|
37
|
-
type Story = StoryObj<typeof
|
|
37
|
+
type Story = StoryObj<typeof DefaultStory>;
|
|
38
38
|
|
|
39
39
|
export const Default: Story = {};
|
|
40
40
|
|
package/src/hooks/useDrag.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import { select } from 'd3';
|
|
6
6
|
import { useEffect } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type GlobeController } from '../components';
|
|
@@ -31,7 +31,7 @@ export const useDrag = (controller?: GlobeController | null, options: DragOption
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
geoInertiaDrag(
|
|
34
|
-
|
|
34
|
+
select(canvas),
|
|
35
35
|
() => {
|
|
36
36
|
controller.setRotation(controller.projection.rotate());
|
|
37
37
|
options.onUpdate?.({ type: 'move', controller });
|
|
@@ -47,7 +47,7 @@ export const useDrag = (controller?: GlobeController | null, options: DragOption
|
|
|
47
47
|
|
|
48
48
|
// TODO(burdon): Cancel drag timer.
|
|
49
49
|
return () => {
|
|
50
|
-
cancelDrag(
|
|
50
|
+
cancelDrag(select(canvas));
|
|
51
51
|
};
|
|
52
52
|
}, [controller, JSON.stringify(options)]);
|
|
53
53
|
};
|
package/src/hooks/useSpinner.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import { timer as d3Timer } from 'd3';
|
|
6
6
|
import { type Timer } from 'd3';
|
|
7
7
|
import { useEffect, useState } from 'react';
|
|
8
8
|
|
|
@@ -27,7 +27,7 @@ export const useSpinner = (controller?: GlobeController | null, options: Spinner
|
|
|
27
27
|
|
|
28
28
|
let t = 0;
|
|
29
29
|
let lastRotation = controller.projection.rotate();
|
|
30
|
-
timer =
|
|
30
|
+
timer = d3Timer((elapsed) => {
|
|
31
31
|
const dt = elapsed - t;
|
|
32
32
|
t = elapsed;
|
|
33
33
|
|
package/src/hooks/useTour.ts
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import { type
|
|
5
|
+
import { geoPath, geoInterpolate, geoDistance, selection as d3Selection } from 'd3';
|
|
6
|
+
import { type SetStateAction, type Dispatch, useEffect, useState, useMemo } from 'react';
|
|
7
7
|
import versor from 'versor';
|
|
8
8
|
|
|
9
|
-
import { log } from '@dxos/log';
|
|
10
|
-
|
|
11
9
|
import type { GlobeController } from '../components';
|
|
12
10
|
import { geoToPosition, type LatLng, positionToRotation, type StyleSet } from '../util';
|
|
13
11
|
|
|
@@ -34,7 +32,7 @@ export const useTour = (
|
|
|
34
32
|
points?: LatLng[],
|
|
35
33
|
options: TourOptions = {},
|
|
36
34
|
): [boolean, Dispatch<SetStateAction<boolean>>] => {
|
|
37
|
-
const selection =
|
|
35
|
+
const selection = useMemo(() => d3Selection(), []);
|
|
38
36
|
const [running, setRunning] = useState(options.running ?? false);
|
|
39
37
|
useEffect(() => {
|
|
40
38
|
if (!running) {
|
|
@@ -47,7 +45,7 @@ export const useTour = (
|
|
|
47
45
|
t = setTimeout(async () => {
|
|
48
46
|
const { canvas, projection, setRotation } = controller;
|
|
49
47
|
const context = canvas.getContext('2d', { alpha: false });
|
|
50
|
-
const path =
|
|
48
|
+
const path = geoPath(projection, context).pointRadius(2);
|
|
51
49
|
|
|
52
50
|
const tilt = options.tilt ?? 0;
|
|
53
51
|
let last: LatLng;
|
|
@@ -65,8 +63,8 @@ export const useTour = (
|
|
|
65
63
|
// Points.
|
|
66
64
|
const p1 = last ? geoToPosition(last) : undefined;
|
|
67
65
|
const p2 = geoToPosition(next);
|
|
68
|
-
const ip =
|
|
69
|
-
const distance =
|
|
66
|
+
const ip = geoInterpolate(p1 || p2, p2);
|
|
67
|
+
const distance = geoDistance(p1 || p2, p2);
|
|
70
68
|
|
|
71
69
|
// Rotation.
|
|
72
70
|
const r1 = p1 ? positionToRotation(p1, tilt) : controller.projection.rotate();
|
|
@@ -98,10 +96,8 @@ export const useTour = (
|
|
|
98
96
|
context.restore();
|
|
99
97
|
|
|
100
98
|
// TODO(burdon): This has to come after rendering above. Add to features to correct order?
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
setRotation(projection.rotate());
|
|
104
|
-
}
|
|
99
|
+
projection.rotate(iv(t));
|
|
100
|
+
setRotation(projection.rotate());
|
|
105
101
|
});
|
|
106
102
|
|
|
107
103
|
// Throws if interrupted.
|
|
@@ -109,7 +105,7 @@ export const useTour = (
|
|
|
109
105
|
last = next;
|
|
110
106
|
}
|
|
111
107
|
} catch (err) {
|
|
112
|
-
|
|
108
|
+
// Ignore.
|
|
113
109
|
} finally {
|
|
114
110
|
setRunning(false);
|
|
115
111
|
}
|
package/src/util/inertia.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// https://github.com/Fil/d3-inertia
|
|
5
5
|
//
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import { select, drag, timer } from 'd3';
|
|
8
8
|
import versor from 'versor';
|
|
9
9
|
|
|
10
10
|
export const restrictAxis =
|
|
@@ -26,7 +26,7 @@ export const geoInertiaDrag = (target, render, projection, options) => {
|
|
|
26
26
|
if (target.node) {
|
|
27
27
|
target = target.node();
|
|
28
28
|
}
|
|
29
|
-
target =
|
|
29
|
+
target = select(target);
|
|
30
30
|
|
|
31
31
|
// Complete params: (projection, render, startDrag, dragging, endDrag).
|
|
32
32
|
const inertia = geoInertiaDragHelper({
|
|
@@ -45,7 +45,7 @@ export const geoInertiaDrag = (target, render, projection, options) => {
|
|
|
45
45
|
hold: options.hold,
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
target.call(
|
|
48
|
+
target.call(drag().on('start', inertia.start).on('drag', inertia.move).on('end', inertia.end));
|
|
49
49
|
return inertia;
|
|
50
50
|
};
|
|
51
51
|
|
|
@@ -119,7 +119,7 @@ function inertiaHelper(opt) {
|
|
|
119
119
|
const inertia = {
|
|
120
120
|
position: [0, 0],
|
|
121
121
|
velocity: [0, 0], // Velocity in pixels/s.
|
|
122
|
-
timer:
|
|
122
|
+
timer: timer(() => {}),
|
|
123
123
|
time: 0,
|
|
124
124
|
t: 0,
|
|
125
125
|
|
|
@@ -135,7 +135,6 @@ function inertiaHelper(opt) {
|
|
|
135
135
|
|
|
136
136
|
move: function (ev) {
|
|
137
137
|
const position = [ev.x, ev.y];
|
|
138
|
-
|
|
139
138
|
const time = performance.now();
|
|
140
139
|
const deltaTime = time - inertia.time;
|
|
141
140
|
const decay = 1 - Math.exp(-deltaTime / 1_000);
|
package/src/util/path.ts
CHANGED
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import { type GeoGeometryObjects } from 'd3';
|
|
5
|
+
import { type GeoGeometryObjects, geoCircle as d3GeoCircle } from 'd3';
|
|
7
6
|
import { type Point, type Polygon, type Position } from 'geojson';
|
|
8
7
|
|
|
9
8
|
import type { Vector } from '../hooks';
|
|
10
9
|
|
|
11
10
|
export type LatLng = { lat: number; lng: number };
|
|
12
11
|
|
|
13
|
-
// TODO(burdon): Clean-up.
|
|
14
|
-
|
|
15
12
|
export const positionToRotation = ([lng, lat]: [number, number], tilt = 0): Vector => [-lng, tilt - lat, 0];
|
|
16
13
|
|
|
17
14
|
export const geoToPosition = ({ lat, lng }: LatLng): [number, number] => [lng, lat];
|
|
@@ -20,7 +17,7 @@ export const geoPoint = (point: LatLng): Point => ({ type: 'Point', coordinates:
|
|
|
20
17
|
|
|
21
18
|
// https://github.com/d3/d3-geo#geoCircle
|
|
22
19
|
export const geoCircle = ({ lat, lng }: LatLng, radius: number): Polygon =>
|
|
23
|
-
|
|
20
|
+
d3GeoCircle().radius(radius).center([lng, lat])();
|
|
24
21
|
|
|
25
22
|
export const geoLine = (p1: LatLng, p2: LatLng): GeoGeometryObjects => ({
|
|
26
23
|
type: 'LineString',
|
package/src/util/render.ts
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import * as topojson from 'topojson-client';
|
|
5
|
+
import { type GeoPath, type GeoPermissibleObjects, geoGraticule } from 'd3';
|
|
6
|
+
import { feature, mesh } from 'topojson-client';
|
|
8
7
|
import { type Topology } from 'topojson-specification';
|
|
9
8
|
|
|
10
9
|
import { type LatLng, geoLine, geoPoint } from './path';
|
|
@@ -53,7 +52,7 @@ export const createLayers = (topology: Topology, features: Features, styles: Sty
|
|
|
53
52
|
if (styles.graticule) {
|
|
54
53
|
layers.push({
|
|
55
54
|
styles: styles.graticule,
|
|
56
|
-
path:
|
|
55
|
+
path: geoGraticule().step([6, 6])(),
|
|
57
56
|
});
|
|
58
57
|
}
|
|
59
58
|
|
|
@@ -65,14 +64,14 @@ export const createLayers = (topology: Topology, features: Features, styles: Sty
|
|
|
65
64
|
if (topology.objects.land && styles.land) {
|
|
66
65
|
layers.push({
|
|
67
66
|
styles: styles.land,
|
|
68
|
-
path:
|
|
67
|
+
path: feature(topology, topology.objects.land),
|
|
69
68
|
});
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
if (topology.objects.countries && styles.border) {
|
|
73
72
|
layers.push({
|
|
74
73
|
styles: styles.border,
|
|
75
|
-
path:
|
|
74
|
+
path: mesh(topology, topology.objects.countries, (a: any, b: any) => a !== b),
|
|
76
75
|
});
|
|
77
76
|
}
|
|
78
77
|
|