@dxos/react-ui-geo 0.8.4-staging.ac66bdf99f → 0.9.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/LICENSE +102 -5
- package/data/countries-10m.ts +12 -0
- package/data/countries-110m.ts +4 -10579
- package/data/countries-50m.ts +12 -0
- package/dist/lib/browser/chunk-SC2FBYFU.mjs +17 -0
- package/dist/lib/browser/chunk-SC2FBYFU.mjs.map +7 -0
- package/dist/lib/browser/countries-10m-CWWDOKH7.mjs +6 -0
- package/dist/lib/browser/countries-10m-CWWDOKH7.mjs.map +7 -0
- package/dist/lib/browser/countries-110m-72QBAA5E.mjs +6 -0
- package/dist/lib/browser/countries-110m-72QBAA5E.mjs.map +7 -0
- package/dist/lib/browser/countries-50m-H7SL7KVF.mjs +6 -0
- package/dist/lib/browser/countries-50m-H7SL7KVF.mjs.map +7 -0
- package/dist/lib/browser/data.mjs +1 -1
- package/dist/lib/browser/index.mjs +774 -223
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +19 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-VZENBYLJ.mjs +19 -0
- package/dist/lib/node-esm/chunk-VZENBYLJ.mjs.map +7 -0
- package/dist/lib/node-esm/countries-10m-DJZV66KG.mjs +8 -0
- package/dist/lib/node-esm/countries-10m-DJZV66KG.mjs.map +7 -0
- package/dist/lib/node-esm/countries-110m-H3WY6K4Q.mjs +8 -0
- package/dist/lib/node-esm/countries-110m-H3WY6K4Q.mjs.map +7 -0
- package/dist/lib/node-esm/countries-50m-ZY7Z3IWD.mjs +8 -0
- package/dist/lib/node-esm/countries-50m-ZY7Z3IWD.mjs.map +7 -0
- package/dist/lib/node-esm/data.mjs +1 -1
- package/dist/lib/node-esm/index.mjs +774 -223
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +21 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/data/airports.d.ts +4 -4
- package/dist/types/data/airports.d.ts.map +1 -1
- package/dist/types/data/cities.d.ts.map +1 -1
- package/dist/types/data/countries-10m.d.ts +8 -0
- package/dist/types/data/countries-10m.d.ts.map +1 -0
- package/dist/types/data/countries-110m.d.ts +2 -30
- package/dist/types/data/countries-110m.d.ts.map +1 -1
- package/dist/types/data/countries-50m.d.ts +8 -0
- package/dist/types/data/countries-50m.d.ts.map +1 -0
- package/dist/types/data/countries-dots-3.d.ts.map +1 -1
- package/dist/types/data/countries-dots-4.d.ts.map +1 -1
- package/dist/types/src/components/Globe/Globe.d.ts +18 -10
- package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
- package/dist/types/src/components/Globe/Globe.stories.d.ts +16 -8
- package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
- package/dist/types/src/components/Map/Map.d.ts +49 -13
- package/dist/types/src/components/Map/Map.d.ts.map +1 -1
- package/dist/types/src/components/Map/Map.stories.d.ts +9 -5
- package/dist/types/src/components/Map/Map.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Controls.d.ts.map +1 -1
- package/dist/types/src/data.d.ts +9 -1
- package/dist/types/src/data.d.ts.map +1 -1
- package/dist/types/src/hooks/context.d.ts +37 -0
- package/dist/types/src/hooks/context.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +3 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useDrag.d.ts +22 -2
- package/dist/types/src/hooks/useDrag.d.ts.map +1 -1
- package/dist/types/src/hooks/useGlobeZoomHandler.d.ts +3 -2
- package/dist/types/src/hooks/useGlobeZoomHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useMapZoomHandler.d.ts +1 -1
- package/dist/types/src/hooks/useMapZoomHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useSimplifiedTopology.d.ts +32 -0
- package/dist/types/src/hooks/useSimplifiedTopology.d.ts.map +1 -0
- package/dist/types/src/hooks/useSpinner.d.ts +1 -1
- package/dist/types/src/hooks/useSpinner.d.ts.map +1 -1
- package/dist/types/src/hooks/useTopology.d.ts +26 -0
- package/dist/types/src/hooks/useTopology.d.ts.map +1 -0
- package/dist/types/src/hooks/useTour.d.ts +3 -2
- package/dist/types/src/hooks/useTour.d.ts.map +1 -1
- package/dist/types/src/hooks/useWheel.d.ts +24 -0
- package/dist/types/src/hooks/useWheel.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +4 -4
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/animation.d.ts +16 -0
- package/dist/types/src/util/animation.d.ts.map +1 -0
- package/dist/types/src/util/debug.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- 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 +25 -1
- package/dist/types/src/util/render.d.ts.map +1 -1
- package/dist/types/src/util/styles.d.ts +4 -0
- package/dist/types/src/util/styles.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +26 -24
- package/src/components/Globe/Globe.stories.tsx +135 -58
- package/src/components/Globe/Globe.tsx +237 -120
- package/src/components/Map/Map.stories.tsx +58 -12
- package/src/components/Map/Map.tsx +293 -91
- package/src/components/Toolbar/Controls.tsx +1 -1
- package/src/data.ts +19 -2
- package/src/hooks/context.tsx +44 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useDrag.ts +33 -5
- package/src/hooks/useGlobeZoomHandler.ts +2 -1
- package/src/hooks/useSimplifiedTopology.ts +81 -0
- package/src/hooks/useSpinner.ts +1 -1
- package/src/hooks/useTopology.ts +95 -0
- package/src/hooks/useTour.ts +70 -81
- package/src/hooks/useWheel.ts +83 -0
- package/src/index.ts +0 -2
- package/src/util/animation.ts +35 -0
- package/src/util/index.ts +2 -0
- package/src/util/inertia.ts +87 -4
- package/src/util/render.ts +105 -16
- package/src/util/styles.ts +62 -0
- package/dist/lib/browser/chunk-GMWLKTLN.mjs +0 -9
- package/dist/lib/browser/chunk-GMWLKTLN.mjs.map +0 -7
- package/dist/lib/browser/countries-110m-ZM3ZIEFS.mjs +0 -37859
- package/dist/lib/browser/countries-110m-ZM3ZIEFS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JODBF4CC.mjs +0 -11
- package/dist/lib/node-esm/chunk-JODBF4CC.mjs.map +0 -7
- package/dist/lib/node-esm/countries-110m-3SFASWVD.mjs +0 -37861
- package/dist/lib/node-esm/countries-110m-3SFASWVD.mjs.map +0 -7
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
loadTopology
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VZENBYLJ.mjs";
|
|
5
5
|
|
|
6
6
|
// src/components/Globe/Globe.tsx
|
|
7
|
-
import { easeLinear, easeSinOut, geoMercator, geoOrthographic, geoPath as geoPath2, geoTransverseMercator, interpolateNumber, transition } from "d3";
|
|
8
|
-
import React2, { forwardRef, useEffect as
|
|
7
|
+
import { selection as d3Selection, easeLinear, easeSinOut, geoMercator, geoOrthographic, geoPath as geoPath2, geoTransverseMercator, interpolateNumber, transition } from "d3";
|
|
8
|
+
import React2, { forwardRef, useCallback as useCallback3, useEffect as useEffect6, useId, useImperativeHandle, useMemo as useMemo2, useRef, useState as useState4 } from "react";
|
|
9
9
|
import { useResizeDetector } from "react-resize-detector";
|
|
10
10
|
import { useComposedRefs, useControlledState, useDynamicRef, useThemeContext } from "@dxos/react-ui";
|
|
11
|
-
import { composable, composableProps
|
|
11
|
+
import { composable, composableProps } from "@dxos/react-ui";
|
|
12
|
+
import { mx } from "@dxos/ui-theme";
|
|
12
13
|
|
|
13
14
|
// src/hooks/context.tsx
|
|
14
15
|
import { createContext, useContext } from "react";
|
|
@@ -22,6 +23,18 @@ var useGlobeContext = () => {
|
|
|
22
23
|
import { select as select2 } from "d3";
|
|
23
24
|
import { useEffect } from "react";
|
|
24
25
|
|
|
26
|
+
// src/util/animation.ts
|
|
27
|
+
import { geoDistance } from "d3";
|
|
28
|
+
import versor from "versor";
|
|
29
|
+
var flyDuration = (p1, p2, base, scale) => Math.max(base, geoDistance(p1, p2) * scale);
|
|
30
|
+
var createRotationTween = (projection, setRotation, r1, r2) => {
|
|
31
|
+
const iv = versor.interpolate(r1, r2);
|
|
32
|
+
return (t) => {
|
|
33
|
+
projection.rotate(iv(t));
|
|
34
|
+
setRotation(projection.rotate());
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
25
38
|
// src/util/debug.ts
|
|
26
39
|
var debug = false;
|
|
27
40
|
var timer = (cb) => {
|
|
@@ -39,7 +52,7 @@ var timer = (cb) => {
|
|
|
39
52
|
|
|
40
53
|
// src/util/inertia.ts
|
|
41
54
|
import { drag, select, timer as timer2 } from "d3";
|
|
42
|
-
import
|
|
55
|
+
import versor2 from "versor";
|
|
43
56
|
var restrictAxis = (axis) => (original, current) => current.map((d, i) => axis[i] ? d : original[i]);
|
|
44
57
|
var geoInertiaDrag = (target, render, projection, options) => {
|
|
45
58
|
if (!options) {
|
|
@@ -49,21 +62,23 @@ var geoInertiaDrag = (target, render, projection, options) => {
|
|
|
49
62
|
target = target.node();
|
|
50
63
|
}
|
|
51
64
|
target = select(target);
|
|
52
|
-
const
|
|
65
|
+
const linear = (options.mode ?? "linear") === "linear";
|
|
66
|
+
const axis = restrictAxis(options.lockTilt ? [
|
|
67
|
+
true,
|
|
68
|
+
false,
|
|
69
|
+
false
|
|
70
|
+
] : [
|
|
71
|
+
true,
|
|
72
|
+
true,
|
|
73
|
+
true
|
|
74
|
+
]);
|
|
75
|
+
const sharedHandlers = {
|
|
53
76
|
projection,
|
|
54
77
|
render: (rotation) => {
|
|
55
78
|
projection.rotate(rotation);
|
|
56
79
|
render && render();
|
|
57
80
|
},
|
|
58
|
-
axis
|
|
59
|
-
true,
|
|
60
|
-
false,
|
|
61
|
-
false
|
|
62
|
-
] : [
|
|
63
|
-
true,
|
|
64
|
-
true,
|
|
65
|
-
true
|
|
66
|
-
]),
|
|
81
|
+
axis,
|
|
67
82
|
start: options.start,
|
|
68
83
|
move: options.move,
|
|
69
84
|
end: options.end,
|
|
@@ -71,7 +86,12 @@ var geoInertiaDrag = (target, render, projection, options) => {
|
|
|
71
86
|
finish: options.finish,
|
|
72
87
|
time: options.time,
|
|
73
88
|
hold: options.hold
|
|
74
|
-
}
|
|
89
|
+
};
|
|
90
|
+
const inertia = linear ? geoInertiaDragLinearHelper({
|
|
91
|
+
...sharedHandlers,
|
|
92
|
+
sensitivity: options.sensitivity,
|
|
93
|
+
getZoom: options.getZoom
|
|
94
|
+
}) : geoInertiaDragHelper(sharedHandlers);
|
|
75
95
|
target.call(drag().on("start", inertia.start).on("drag", inertia.move).on("end", inertia.end));
|
|
76
96
|
return inertia;
|
|
77
97
|
};
|
|
@@ -86,9 +106,9 @@ var geoInertiaDragHelper = (opt) => {
|
|
|
86
106
|
const inertia = inertiaHelper({
|
|
87
107
|
axis: opt.axis,
|
|
88
108
|
start: () => {
|
|
89
|
-
v0 =
|
|
109
|
+
v0 = versor2.cartesian(projection.invert(inertia.position));
|
|
90
110
|
r0 = projection.rotate();
|
|
91
|
-
q0 =
|
|
111
|
+
q0 = versor2(r0);
|
|
92
112
|
opt.start && opt.start();
|
|
93
113
|
},
|
|
94
114
|
move: () => {
|
|
@@ -96,23 +116,23 @@ var geoInertiaDragHelper = (opt) => {
|
|
|
96
116
|
if (isNaN(inv[0])) {
|
|
97
117
|
return;
|
|
98
118
|
}
|
|
99
|
-
const v1 =
|
|
100
|
-
const q1 =
|
|
101
|
-
const r1 =
|
|
119
|
+
const v1 = versor2.cartesian(inv);
|
|
120
|
+
const q1 = versor2.multiply(q0, versor2.delta(v0, v1));
|
|
121
|
+
const r1 = versor2.rotation(q1);
|
|
102
122
|
const r2 = opt.axis(r0, r1);
|
|
103
123
|
opt.render(r2);
|
|
104
124
|
opt.move && opt.move();
|
|
105
125
|
},
|
|
106
126
|
end: () => {
|
|
107
|
-
v10 =
|
|
108
|
-
q10 =
|
|
109
|
-
v11 =
|
|
127
|
+
v10 = versor2.cartesian(projection.invert(inertia.position.map((d, i) => d - inertia.velocity[i] / 1e3)));
|
|
128
|
+
q10 = versor2(projection.rotate());
|
|
129
|
+
v11 = versor2.cartesian(projection.invert(inertia.position));
|
|
110
130
|
opt.end && opt.end();
|
|
111
131
|
},
|
|
112
132
|
stop: opt.stop,
|
|
113
133
|
finish: opt.finish,
|
|
114
134
|
render: (t) => {
|
|
115
|
-
const r1 =
|
|
135
|
+
const r1 = versor2.rotation(versor2.multiply(q10, versor2.delta(v10, v11, t * 1e3)));
|
|
116
136
|
const r2 = opt.axis(r0, r1);
|
|
117
137
|
opt.render && opt.render(r2);
|
|
118
138
|
},
|
|
@@ -120,6 +140,62 @@ var geoInertiaDragHelper = (opt) => {
|
|
|
120
140
|
});
|
|
121
141
|
return inertia;
|
|
122
142
|
};
|
|
143
|
+
var DEFAULT_LINEAR_SENSITIVITY = 0.25;
|
|
144
|
+
var geoInertiaDragLinearHelper = (opt) => {
|
|
145
|
+
const projection = opt.projection;
|
|
146
|
+
const sensitivity = opt.sensitivity ?? DEFAULT_LINEAR_SENSITIVITY;
|
|
147
|
+
const gain = () => sensitivity / Math.max(opt.getZoom?.() ?? 1, 0.1);
|
|
148
|
+
let r0;
|
|
149
|
+
let p0;
|
|
150
|
+
let kStart;
|
|
151
|
+
let rEnd;
|
|
152
|
+
let vEnd;
|
|
153
|
+
const inertia = inertiaHelper({
|
|
154
|
+
axis: opt.axis,
|
|
155
|
+
start: () => {
|
|
156
|
+
r0 = projection.rotate();
|
|
157
|
+
p0 = [
|
|
158
|
+
inertia.position[0],
|
|
159
|
+
inertia.position[1]
|
|
160
|
+
];
|
|
161
|
+
kStart = gain();
|
|
162
|
+
opt.start && opt.start();
|
|
163
|
+
},
|
|
164
|
+
move: () => {
|
|
165
|
+
const dx = inertia.position[0] - p0[0];
|
|
166
|
+
const dy = inertia.position[1] - p0[1];
|
|
167
|
+
const r1 = [
|
|
168
|
+
r0[0] + dx * kStart,
|
|
169
|
+
r0[1] - dy * kStart,
|
|
170
|
+
0
|
|
171
|
+
];
|
|
172
|
+
const r2 = opt.axis(r0, r1);
|
|
173
|
+
opt.render(r2);
|
|
174
|
+
opt.move && opt.move();
|
|
175
|
+
},
|
|
176
|
+
end: () => {
|
|
177
|
+
rEnd = projection.rotate();
|
|
178
|
+
vEnd = [
|
|
179
|
+
inertia.velocity[0],
|
|
180
|
+
inertia.velocity[1]
|
|
181
|
+
];
|
|
182
|
+
opt.end && opt.end();
|
|
183
|
+
},
|
|
184
|
+
stop: opt.stop,
|
|
185
|
+
finish: opt.finish,
|
|
186
|
+
render: (t) => {
|
|
187
|
+
const r1 = [
|
|
188
|
+
rEnd[0] + vEnd[0] * kStart * t,
|
|
189
|
+
rEnd[1] - vEnd[1] * kStart * t,
|
|
190
|
+
0
|
|
191
|
+
];
|
|
192
|
+
const r2 = opt.axis(rEnd, r1);
|
|
193
|
+
opt.render && opt.render(r2);
|
|
194
|
+
},
|
|
195
|
+
time: opt.time
|
|
196
|
+
});
|
|
197
|
+
return inertia;
|
|
198
|
+
};
|
|
123
199
|
function inertiaHelper(opt) {
|
|
124
200
|
const A = opt.time || 5e3;
|
|
125
201
|
const limit = 1.0001;
|
|
@@ -223,9 +299,9 @@ var geoToPosition = ({ lat, lng }) => [
|
|
|
223
299
|
lng,
|
|
224
300
|
lat
|
|
225
301
|
];
|
|
226
|
-
var geoPoint = (
|
|
302
|
+
var geoPoint = (point2) => ({
|
|
227
303
|
type: "Point",
|
|
228
|
-
coordinates: geoToPosition(
|
|
304
|
+
coordinates: geoToPosition(point2)
|
|
229
305
|
});
|
|
230
306
|
var geoCircle = ({ lat, lng }, radius) => d3GeoCircle().radius(radius).center([
|
|
231
307
|
lng,
|
|
@@ -250,11 +326,11 @@ var closestPoint = (points, target) => {
|
|
|
250
326
|
}
|
|
251
327
|
let closestPoint2 = points[0];
|
|
252
328
|
let minDistance = getDistance(points[0], target);
|
|
253
|
-
for (const
|
|
254
|
-
const distance = getDistance(
|
|
329
|
+
for (const point2 of points) {
|
|
330
|
+
const distance = getDistance(point2, target);
|
|
255
331
|
if (distance < minDistance) {
|
|
256
332
|
minDistance = distance;
|
|
257
|
-
closestPoint2 =
|
|
333
|
+
closestPoint2 = point2;
|
|
258
334
|
}
|
|
259
335
|
}
|
|
260
336
|
return closestPoint2;
|
|
@@ -266,8 +342,48 @@ var getDistance = (point1, point2) => {
|
|
|
266
342
|
};
|
|
267
343
|
|
|
268
344
|
// src/util/render.ts
|
|
269
|
-
import { geoGraticule } from "d3";
|
|
345
|
+
import { geoBounds, geoCentroid, geoDistance as geoDistance2, geoGraticule } from "d3";
|
|
270
346
|
import { feature, mesh } from "topojson-client";
|
|
347
|
+
var RAD_TO_DEG = 180 / Math.PI;
|
|
348
|
+
var computeBounds = (geometry) => {
|
|
349
|
+
const feat = {
|
|
350
|
+
type: "Feature",
|
|
351
|
+
geometry,
|
|
352
|
+
properties: {}
|
|
353
|
+
};
|
|
354
|
+
const centroid = geoCentroid(feat);
|
|
355
|
+
const [[w, s], [e, n]] = geoBounds(feat);
|
|
356
|
+
const corners = [
|
|
357
|
+
[
|
|
358
|
+
w,
|
|
359
|
+
s
|
|
360
|
+
],
|
|
361
|
+
[
|
|
362
|
+
w,
|
|
363
|
+
n
|
|
364
|
+
],
|
|
365
|
+
[
|
|
366
|
+
e,
|
|
367
|
+
s
|
|
368
|
+
],
|
|
369
|
+
[
|
|
370
|
+
e,
|
|
371
|
+
n
|
|
372
|
+
]
|
|
373
|
+
];
|
|
374
|
+
let radius = 0;
|
|
375
|
+
for (const corner of corners) {
|
|
376
|
+
const d = geoDistance2(centroid, corner) * RAD_TO_DEG;
|
|
377
|
+
if (d > radius) {
|
|
378
|
+
radius = d;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
geometry,
|
|
383
|
+
centroid,
|
|
384
|
+
radius
|
|
385
|
+
};
|
|
386
|
+
};
|
|
271
387
|
var createLayers = (topology, features, styles) => {
|
|
272
388
|
const layers = [];
|
|
273
389
|
if (styles.water) {
|
|
@@ -288,11 +404,25 @@ var createLayers = (topology, features, styles) => {
|
|
|
288
404
|
});
|
|
289
405
|
}
|
|
290
406
|
if (topology) {
|
|
291
|
-
if (
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
407
|
+
if (styles.land) {
|
|
408
|
+
if (topology.objects.countries) {
|
|
409
|
+
const fc = feature(topology, topology.objects.countries);
|
|
410
|
+
const memberGeoms = fc.features.map((f) => f.geometry);
|
|
411
|
+
const bounds = memberGeoms.map(computeBounds);
|
|
412
|
+
layers.push({
|
|
413
|
+
styles: styles.land,
|
|
414
|
+
path: {
|
|
415
|
+
type: "GeometryCollection",
|
|
416
|
+
geometries: memberGeoms
|
|
417
|
+
},
|
|
418
|
+
cullable: bounds
|
|
419
|
+
});
|
|
420
|
+
} else if (topology.objects.land) {
|
|
421
|
+
layers.push({
|
|
422
|
+
styles: styles.land,
|
|
423
|
+
path: feature(topology, topology.objects.land)
|
|
424
|
+
});
|
|
425
|
+
}
|
|
296
426
|
}
|
|
297
427
|
if (topology.objects.countries && styles.border) {
|
|
298
428
|
layers.push({
|
|
@@ -309,28 +439,28 @@ var createLayers = (topology, features, styles) => {
|
|
|
309
439
|
}
|
|
310
440
|
if (features) {
|
|
311
441
|
const { points, lines } = features;
|
|
312
|
-
if (
|
|
442
|
+
if (lines && styles.line) {
|
|
313
443
|
layers.push({
|
|
314
|
-
styles: styles.
|
|
444
|
+
styles: styles.line,
|
|
315
445
|
path: {
|
|
316
446
|
type: "GeometryCollection",
|
|
317
|
-
geometries:
|
|
447
|
+
geometries: lines.map(({ source, target }) => geoLine(source, target))
|
|
318
448
|
}
|
|
319
449
|
});
|
|
320
450
|
}
|
|
321
|
-
if (
|
|
451
|
+
if (points && styles.point) {
|
|
322
452
|
layers.push({
|
|
323
|
-
styles: styles.
|
|
453
|
+
styles: styles.point,
|
|
324
454
|
path: {
|
|
325
455
|
type: "GeometryCollection",
|
|
326
|
-
geometries:
|
|
456
|
+
geometries: points.map((point2) => geoPoint(point2))
|
|
327
457
|
}
|
|
328
458
|
});
|
|
329
459
|
}
|
|
330
460
|
}
|
|
331
461
|
return layers;
|
|
332
462
|
};
|
|
333
|
-
var renderLayers = (generator, layers = [], scale, styles) => {
|
|
463
|
+
var renderLayers = (generator, layers = [], scale, styles, viewCenter) => {
|
|
334
464
|
const context = generator.context();
|
|
335
465
|
const { canvas: { width, height } } = context;
|
|
336
466
|
context.reset();
|
|
@@ -340,7 +470,8 @@ var renderLayers = (generator, layers = [], scale, styles) => {
|
|
|
340
470
|
} else {
|
|
341
471
|
context.clearRect(0, 0, width, height);
|
|
342
472
|
}
|
|
343
|
-
layers.forEach((
|
|
473
|
+
layers.forEach((layer) => {
|
|
474
|
+
const { path, styles: styles2, cullable } = layer;
|
|
344
475
|
context.save();
|
|
345
476
|
let fill = false;
|
|
346
477
|
let stroke = false;
|
|
@@ -355,8 +486,23 @@ var renderLayers = (generator, layers = [], scale, styles) => {
|
|
|
355
486
|
}
|
|
356
487
|
});
|
|
357
488
|
}
|
|
489
|
+
let renderPath = path;
|
|
490
|
+
if (cullable && viewCenter) {
|
|
491
|
+
const geometries = [];
|
|
492
|
+
for (let index = 0; index < cullable.length; index++) {
|
|
493
|
+
const bounds = cullable[index];
|
|
494
|
+
const angularDistance = geoDistance2(viewCenter, bounds.centroid) * RAD_TO_DEG;
|
|
495
|
+
if (angularDistance < 90 + bounds.radius) {
|
|
496
|
+
geometries.push(bounds.geometry);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
renderPath = {
|
|
500
|
+
type: "GeometryCollection",
|
|
501
|
+
geometries
|
|
502
|
+
};
|
|
503
|
+
}
|
|
358
504
|
context.beginPath();
|
|
359
|
-
generator(
|
|
505
|
+
generator(renderPath);
|
|
360
506
|
fill && context.fill();
|
|
361
507
|
stroke && context.stroke();
|
|
362
508
|
context.restore();
|
|
@@ -364,6 +510,57 @@ var renderLayers = (generator, layers = [], scale, styles) => {
|
|
|
364
510
|
return context;
|
|
365
511
|
};
|
|
366
512
|
|
|
513
|
+
// src/util/styles.ts
|
|
514
|
+
var POINT_COLOR = "rgb(220, 38, 38)";
|
|
515
|
+
var LINE_COLOR = "rgba(220, 38, 38, 0.5)";
|
|
516
|
+
var globeStyles = (themeMode) => themeMode === "dark" ? {
|
|
517
|
+
water: {
|
|
518
|
+
fillStyle: "#191919"
|
|
519
|
+
},
|
|
520
|
+
land: {
|
|
521
|
+
fillStyle: "#444",
|
|
522
|
+
strokeStyle: "#222"
|
|
523
|
+
},
|
|
524
|
+
border: {
|
|
525
|
+
strokeStyle: "#111"
|
|
526
|
+
},
|
|
527
|
+
graticule: {
|
|
528
|
+
strokeStyle: "#111"
|
|
529
|
+
},
|
|
530
|
+
line: {
|
|
531
|
+
lineWidth: 1.5,
|
|
532
|
+
lineDash: [
|
|
533
|
+
4,
|
|
534
|
+
16
|
|
535
|
+
],
|
|
536
|
+
strokeStyle: LINE_COLOR
|
|
537
|
+
},
|
|
538
|
+
point: {
|
|
539
|
+
radius: 0.2,
|
|
540
|
+
fillStyle: POINT_COLOR
|
|
541
|
+
}
|
|
542
|
+
} : {
|
|
543
|
+
water: {
|
|
544
|
+
fillStyle: "#C0DAE4"
|
|
545
|
+
},
|
|
546
|
+
land: {
|
|
547
|
+
fillStyle: "#C2D8B4",
|
|
548
|
+
strokeStyle: "#A6C291"
|
|
549
|
+
},
|
|
550
|
+
line: {
|
|
551
|
+
lineWidth: 1.5,
|
|
552
|
+
lineDash: [
|
|
553
|
+
4,
|
|
554
|
+
16
|
|
555
|
+
],
|
|
556
|
+
strokeStyle: LINE_COLOR
|
|
557
|
+
},
|
|
558
|
+
point: {
|
|
559
|
+
radius: 0.2,
|
|
560
|
+
fillStyle: POINT_COLOR
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
|
|
367
564
|
// src/hooks/useDrag.ts
|
|
368
565
|
var useDrag = (controller, options = {}) => {
|
|
369
566
|
useEffect(() => {
|
|
@@ -371,14 +568,19 @@ var useDrag = (controller, options = {}) => {
|
|
|
371
568
|
if (!canvas || options.disabled) {
|
|
372
569
|
return;
|
|
373
570
|
}
|
|
374
|
-
geoInertiaDrag(select2(canvas), () => {
|
|
571
|
+
const inertia = geoInertiaDrag(select2(canvas), () => {
|
|
375
572
|
controller.setRotation(controller.projection.rotate());
|
|
376
573
|
options.onUpdate?.({
|
|
377
574
|
type: "move",
|
|
378
575
|
controller
|
|
379
576
|
});
|
|
380
577
|
}, controller.projection, {
|
|
381
|
-
|
|
578
|
+
lockTilt: options.lockTilt,
|
|
579
|
+
mode: options.mode,
|
|
580
|
+
sensitivity: options.sensitivity,
|
|
581
|
+
// Zoom-driven gain: matches useWheel — degrees-per-pixel shrinks as the
|
|
582
|
+
// globe gets larger on screen so the drag feel is consistent across zoom.
|
|
583
|
+
getZoom: () => controller.zoom,
|
|
382
584
|
time: 3e3,
|
|
383
585
|
start: () => options.onUpdate?.({
|
|
384
586
|
type: "start",
|
|
@@ -391,6 +593,7 @@ var useDrag = (controller, options = {}) => {
|
|
|
391
593
|
});
|
|
392
594
|
return () => {
|
|
393
595
|
cancelDrag(select2(canvas));
|
|
596
|
+
inertia?.timer?.stop();
|
|
394
597
|
};
|
|
395
598
|
}, [
|
|
396
599
|
controller,
|
|
@@ -448,6 +651,61 @@ var useMapZoomHandler = (controller) => {
|
|
|
448
651
|
]);
|
|
449
652
|
};
|
|
450
653
|
|
|
654
|
+
// src/hooks/useSimplifiedTopology.ts
|
|
655
|
+
import { useMemo } from "react";
|
|
656
|
+
import { presimplify, quantile, simplify } from "topojson-simplify";
|
|
657
|
+
var DEFAULT_TIERS = [
|
|
658
|
+
{
|
|
659
|
+
minZoom: 0,
|
|
660
|
+
percentile: 0.95
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
minZoom: 2,
|
|
664
|
+
percentile: 0.85
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
minZoom: 4,
|
|
668
|
+
percentile: 0.6
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
minZoom: 7,
|
|
672
|
+
percentile: 0.3
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
minZoom: 12,
|
|
676
|
+
percentile: 0
|
|
677
|
+
}
|
|
678
|
+
];
|
|
679
|
+
var pickTier = (zoom, tiers) => {
|
|
680
|
+
let match = tiers[0];
|
|
681
|
+
for (const tier of tiers) {
|
|
682
|
+
if (zoom >= tier.minZoom) {
|
|
683
|
+
match = tier;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return match;
|
|
687
|
+
};
|
|
688
|
+
var useSimplifiedTopology = (topology, zoom, options = {}) => {
|
|
689
|
+
const { tiers = DEFAULT_TIERS } = options;
|
|
690
|
+
const presimplified = useMemo(() => topology ? presimplify(topology) : void 0, [
|
|
691
|
+
topology
|
|
692
|
+
]);
|
|
693
|
+
const tier = pickTier(zoom, tiers);
|
|
694
|
+
return useMemo(() => {
|
|
695
|
+
if (!presimplified) {
|
|
696
|
+
return void 0;
|
|
697
|
+
}
|
|
698
|
+
if (tier.percentile <= 0) {
|
|
699
|
+
return presimplified;
|
|
700
|
+
}
|
|
701
|
+
const minWeight = quantile(presimplified, tier.percentile);
|
|
702
|
+
return simplify(presimplified, minWeight);
|
|
703
|
+
}, [
|
|
704
|
+
presimplified,
|
|
705
|
+
tier
|
|
706
|
+
]);
|
|
707
|
+
};
|
|
708
|
+
|
|
451
709
|
// src/hooks/useSpinner.ts
|
|
452
710
|
import { timer as d3Timer } from "d3";
|
|
453
711
|
import { useEffect as useEffect2, useState } from "react";
|
|
@@ -501,91 +759,139 @@ var useSpinner = (controller, options = {}) => {
|
|
|
501
759
|
];
|
|
502
760
|
};
|
|
503
761
|
|
|
762
|
+
// src/hooks/useTopology.ts
|
|
763
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
764
|
+
import { log } from "@dxos/log";
|
|
765
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-geo/src/hooks/useTopology.ts";
|
|
766
|
+
var DEFAULT_TIERS2 = [
|
|
767
|
+
{
|
|
768
|
+
minZoom: 0,
|
|
769
|
+
level: "110m"
|
|
770
|
+
}
|
|
771
|
+
];
|
|
772
|
+
var pickTier2 = (zoom, tiers) => {
|
|
773
|
+
let match = tiers[0];
|
|
774
|
+
for (const tier of tiers) {
|
|
775
|
+
if (zoom >= tier.minZoom) {
|
|
776
|
+
match = tier;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
return match;
|
|
780
|
+
};
|
|
781
|
+
var topologyCache = /* @__PURE__ */ new Map();
|
|
782
|
+
var useTopology = (zoom, options = {}) => {
|
|
783
|
+
const { tiers = DEFAULT_TIERS2 } = options;
|
|
784
|
+
const level = zoom === void 0 ? "110m" : pickTier2(zoom, tiers).level;
|
|
785
|
+
const [topology, setTopology] = useState2(() => topologyCache.get(level));
|
|
786
|
+
useEffect3(() => {
|
|
787
|
+
const cached = topologyCache.get(level);
|
|
788
|
+
if (cached) {
|
|
789
|
+
setTopology(cached);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
let disposed = false;
|
|
793
|
+
void loadTopology(level).then((loaded) => {
|
|
794
|
+
topologyCache.set(level, loaded);
|
|
795
|
+
if (!disposed) {
|
|
796
|
+
setTopology(loaded);
|
|
797
|
+
}
|
|
798
|
+
}).catch((err) => {
|
|
799
|
+
if (!disposed) {
|
|
800
|
+
log.warn("failed to load topology", {
|
|
801
|
+
level,
|
|
802
|
+
err
|
|
803
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 52, S: void 0 });
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
return () => {
|
|
807
|
+
disposed = true;
|
|
808
|
+
};
|
|
809
|
+
}, [
|
|
810
|
+
level
|
|
811
|
+
]);
|
|
812
|
+
return topology;
|
|
813
|
+
};
|
|
814
|
+
|
|
504
815
|
// src/hooks/useTour.ts
|
|
505
|
-
import {
|
|
506
|
-
import { useEffect as
|
|
507
|
-
import versor2 from "versor";
|
|
508
|
-
var TRANSITION_NAME = "globe-tour";
|
|
816
|
+
import { geoInterpolate, geoPath } from "d3";
|
|
817
|
+
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
509
818
|
var defaultDuration = 1500;
|
|
510
819
|
var useTour = (controller, points, options = {}) => {
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
if (!running) {
|
|
515
|
-
selection.interrupt(TRANSITION_NAME);
|
|
820
|
+
const [running, setRunning] = useState3(options.running ?? false);
|
|
821
|
+
useEffect4(() => {
|
|
822
|
+
if (!controller || !running) {
|
|
516
823
|
return;
|
|
517
824
|
}
|
|
518
|
-
let
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const
|
|
825
|
+
let cancelled = false;
|
|
826
|
+
const t = setTimeout(async () => {
|
|
827
|
+
const { canvas, projection } = controller;
|
|
828
|
+
const context = canvas.getContext("2d", {
|
|
829
|
+
alpha: false
|
|
830
|
+
});
|
|
831
|
+
const path = geoPath(projection, context).pointRadius(2);
|
|
832
|
+
try {
|
|
833
|
+
const tourPoints = [
|
|
834
|
+
...points
|
|
835
|
+
];
|
|
836
|
+
if (options.loop) {
|
|
837
|
+
tourPoints.push(tourPoints[0]);
|
|
838
|
+
}
|
|
527
839
|
let last;
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
];
|
|
532
|
-
if (options.loop) {
|
|
533
|
-
p.push(p[0]);
|
|
840
|
+
for (const next of tourPoints) {
|
|
841
|
+
if (cancelled) {
|
|
842
|
+
break;
|
|
534
843
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
context.fillStyle = options?.styles?.cursor?.fillStyle ?? "orange";
|
|
565
|
-
path.pointRadius((options?.styles?.cursor?.pointRadius ?? 2) * (controller?.zoom ?? 1));
|
|
566
|
-
path({
|
|
567
|
-
type: "Point",
|
|
568
|
-
coordinates: ip(t22)
|
|
569
|
-
});
|
|
570
|
-
context.fill();
|
|
571
|
-
}
|
|
844
|
+
const p1 = last ? geoToPosition(last) : void 0;
|
|
845
|
+
const p2 = geoToPosition(next);
|
|
846
|
+
const ip = geoInterpolate(p1 ?? p2, p2);
|
|
847
|
+
const onTick = (t2) => {
|
|
848
|
+
const t1 = Math.max(0, Math.min(1, t2 * 2 - 1));
|
|
849
|
+
const t22 = Math.min(1, t2 * 2);
|
|
850
|
+
context.save();
|
|
851
|
+
try {
|
|
852
|
+
context.beginPath();
|
|
853
|
+
context.strokeStyle = options.styles?.arc?.strokeStyle ?? "yellow";
|
|
854
|
+
context.lineWidth = (options.styles?.arc?.lineWidth ?? 1.5) * (controller.zoom ?? 1);
|
|
855
|
+
context.setLineDash(options.styles?.arc?.lineDash ?? []);
|
|
856
|
+
path({
|
|
857
|
+
type: "LineString",
|
|
858
|
+
coordinates: [
|
|
859
|
+
ip(t1),
|
|
860
|
+
ip(t22)
|
|
861
|
+
]
|
|
862
|
+
});
|
|
863
|
+
context.stroke();
|
|
864
|
+
context.beginPath();
|
|
865
|
+
context.fillStyle = options.styles?.cursor?.fillStyle ?? "orange";
|
|
866
|
+
path.pointRadius((options.styles?.cursor?.pointRadius ?? 2) * (controller.zoom ?? 1));
|
|
867
|
+
path({
|
|
868
|
+
type: "Point",
|
|
869
|
+
coordinates: ip(t22)
|
|
870
|
+
});
|
|
871
|
+
context.fill();
|
|
872
|
+
} finally {
|
|
572
873
|
context.restore();
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
await controller.flyTo(next, {
|
|
877
|
+
duration: options.duration ?? defaultDuration,
|
|
878
|
+
tilt: options.tilt ?? 0,
|
|
879
|
+
onTick
|
|
880
|
+
});
|
|
881
|
+
last = next;
|
|
882
|
+
}
|
|
883
|
+
} catch {
|
|
884
|
+
} finally {
|
|
885
|
+
if (!cancelled) {
|
|
581
886
|
setRunning(false);
|
|
582
887
|
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
return () => {
|
|
891
|
+
cancelled = true;
|
|
892
|
+
clearTimeout(t);
|
|
893
|
+
controller.cancelFlyTo();
|
|
894
|
+
};
|
|
589
895
|
}, [
|
|
590
896
|
controller,
|
|
591
897
|
running,
|
|
@@ -597,26 +903,55 @@ var useTour = (controller, points, options = {}) => {
|
|
|
597
903
|
];
|
|
598
904
|
};
|
|
599
905
|
|
|
600
|
-
// src/
|
|
601
|
-
import
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
[translationKey]: {
|
|
610
|
-
"zoom-in-icon.button": "Zoom in",
|
|
611
|
-
"zoom-out-icon.button": "Zoom out",
|
|
612
|
-
"start-icon.button": "Start",
|
|
613
|
-
"toggle-icon.button": "Toggle"
|
|
614
|
-
}
|
|
906
|
+
// src/hooks/useWheel.ts
|
|
907
|
+
import { useEffect as useEffect5 } from "react";
|
|
908
|
+
var DEFAULT_SENSITIVITY = 0.25;
|
|
909
|
+
var DEFAULT_ZOOM_SENSITIVITY = 0.01;
|
|
910
|
+
var useWheel = (controller, options = {}) => {
|
|
911
|
+
useEffect5(() => {
|
|
912
|
+
const canvas = controller?.canvas;
|
|
913
|
+
if (!canvas || options.disabled) {
|
|
914
|
+
return;
|
|
615
915
|
}
|
|
616
|
-
|
|
617
|
-
|
|
916
|
+
const sensitivity = options.sensitivity ?? DEFAULT_SENSITIVITY;
|
|
917
|
+
const zoomSensitivity = options.zoomSensitivity ?? DEFAULT_ZOOM_SENSITIVITY;
|
|
918
|
+
const handleWheel = (event) => {
|
|
919
|
+
event.preventDefault();
|
|
920
|
+
if (event.ctrlKey) {
|
|
921
|
+
const factor = Math.exp(-event.deltaY * zoomSensitivity);
|
|
922
|
+
controller.setZoom(controller.zoom * factor);
|
|
923
|
+
} else {
|
|
924
|
+
const [lambda, phi, gamma] = controller.projection.rotate();
|
|
925
|
+
const k = sensitivity / Math.max(controller.zoom, 0.1);
|
|
926
|
+
const next = [
|
|
927
|
+
lambda - event.deltaX * k,
|
|
928
|
+
phi + event.deltaY * k,
|
|
929
|
+
gamma
|
|
930
|
+
];
|
|
931
|
+
controller.projection.rotate(next);
|
|
932
|
+
controller.setRotation(controller.projection.rotate());
|
|
933
|
+
}
|
|
934
|
+
options.onUpdate?.(controller);
|
|
935
|
+
};
|
|
936
|
+
canvas.addEventListener("wheel", handleWheel, {
|
|
937
|
+
passive: false
|
|
938
|
+
});
|
|
939
|
+
return () => {
|
|
940
|
+
canvas.removeEventListener("wheel", handleWheel);
|
|
941
|
+
};
|
|
942
|
+
}, [
|
|
943
|
+
controller,
|
|
944
|
+
options.disabled,
|
|
945
|
+
options.sensitivity,
|
|
946
|
+
options.zoomSensitivity,
|
|
947
|
+
options.onUpdate
|
|
948
|
+
]);
|
|
949
|
+
};
|
|
618
950
|
|
|
619
951
|
// src/components/Toolbar/Controls.tsx
|
|
952
|
+
import React from "react";
|
|
953
|
+
import { IconButton, Toolbar, useTranslation } from "@dxos/react-ui";
|
|
954
|
+
import { translationKey } from "#translations";
|
|
620
955
|
var controlPositions = {
|
|
621
956
|
topleft: "top-2 left-2",
|
|
622
957
|
topright: "top-2 right-2",
|
|
@@ -717,45 +1052,72 @@ var getProjection = (type = "orthographic") => {
|
|
|
717
1052
|
}
|
|
718
1053
|
return type ?? geoOrthographic();
|
|
719
1054
|
};
|
|
720
|
-
var
|
|
721
|
-
|
|
722
|
-
const
|
|
723
|
-
|
|
724
|
-
|
|
1055
|
+
var DEFAULT_ZOOM = 1.5;
|
|
1056
|
+
var GlobeRoot = /* @__PURE__ */ forwardRef(({ children, center: centerProp, zoom: zoomProp = DEFAULT_ZOOM, translation: translationProp, rotation: rotationProp }, forwardedRef) => {
|
|
1057
|
+
const [size, setSize] = useState4({
|
|
1058
|
+
width: 0,
|
|
1059
|
+
height: 0
|
|
725
1060
|
});
|
|
726
1061
|
const [center, setCenter] = useControlledState(centerProp);
|
|
727
|
-
const [zoom, setZoom] = useControlledState(zoomProp
|
|
1062
|
+
const [zoom, setZoom] = useControlledState(zoomProp);
|
|
728
1063
|
const [translation, setTranslation] = useControlledState(translationProp);
|
|
729
1064
|
const [rotation, setRotation] = useControlledState(rotationProp);
|
|
1065
|
+
const [controller, setController] = useState4(null);
|
|
1066
|
+
const registerController = useCallback3((next) => setController(next), []);
|
|
1067
|
+
useImperativeHandle(forwardedRef, () => controller, [
|
|
1068
|
+
controller
|
|
1069
|
+
]);
|
|
730
1070
|
return /* @__PURE__ */ React2.createElement(GlobeContext.Provider, {
|
|
731
1071
|
value: {
|
|
732
|
-
size
|
|
733
|
-
width,
|
|
734
|
-
height
|
|
735
|
-
},
|
|
1072
|
+
size,
|
|
736
1073
|
center,
|
|
737
1074
|
zoom,
|
|
738
1075
|
translation,
|
|
739
1076
|
rotation,
|
|
1077
|
+
setSize,
|
|
740
1078
|
setCenter,
|
|
741
1079
|
setZoom,
|
|
742
1080
|
setTranslation,
|
|
743
|
-
setRotation
|
|
1081
|
+
setRotation,
|
|
1082
|
+
registerController
|
|
744
1083
|
}
|
|
745
|
-
},
|
|
1084
|
+
}, children);
|
|
1085
|
+
});
|
|
1086
|
+
GlobeRoot.displayName = "Globe.Root";
|
|
1087
|
+
var GlobeViewport = composable(({ children, ...props }, forwardedRef) => {
|
|
1088
|
+
const { setSize } = useGlobeContext();
|
|
1089
|
+
const localRef = useRef(null);
|
|
1090
|
+
const composedRef = useComposedRefs(localRef, forwardedRef);
|
|
1091
|
+
const { width, height } = useResizeDetector({
|
|
1092
|
+
targetRef: localRef
|
|
1093
|
+
});
|
|
1094
|
+
useEffect6(() => {
|
|
1095
|
+
setSize({
|
|
1096
|
+
width: width ?? 0,
|
|
1097
|
+
height: height ?? 0
|
|
1098
|
+
});
|
|
1099
|
+
}, [
|
|
1100
|
+
width,
|
|
1101
|
+
height,
|
|
1102
|
+
setSize
|
|
1103
|
+
]);
|
|
1104
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
746
1105
|
...composableProps(props, {
|
|
747
1106
|
classNames: "relative dx-container"
|
|
748
1107
|
}),
|
|
749
1108
|
ref: composedRef
|
|
750
|
-
}, children)
|
|
1109
|
+
}, children);
|
|
751
1110
|
});
|
|
752
|
-
|
|
1111
|
+
GlobeViewport.displayName = "Globe.Viewport";
|
|
1112
|
+
var GlobeCanvas = ({ projection: projectionProp, topology, features, styles: stylesProp }) => {
|
|
753
1113
|
const { themeMode } = useThemeContext();
|
|
754
1114
|
const styles = useMemo2(() => stylesProp ?? defaultStyles[themeMode], [
|
|
755
1115
|
stylesProp,
|
|
756
1116
|
themeMode
|
|
757
1117
|
]);
|
|
758
|
-
const
|
|
1118
|
+
const { size, center, zoom, translation, rotation, setZoom, setTranslation, setRotation, registerController } = useGlobeContext();
|
|
1119
|
+
const zoomRef = useDynamicRef(zoom);
|
|
1120
|
+
const [canvas, setCanvas] = useState4(null);
|
|
759
1121
|
const canvasRef = (canvas2) => setCanvas(canvas2);
|
|
760
1122
|
const projection = useMemo2(() => getProjection(projectionProp), [
|
|
761
1123
|
projectionProp
|
|
@@ -767,28 +1129,31 @@ var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: projectionProp, topo
|
|
|
767
1129
|
features,
|
|
768
1130
|
styles
|
|
769
1131
|
]);
|
|
770
|
-
|
|
771
|
-
const zoomRef = useDynamicRef(zoom);
|
|
772
|
-
useEffect4(() => {
|
|
1132
|
+
useEffect6(() => {
|
|
773
1133
|
if (center) {
|
|
774
|
-
setZoom(1);
|
|
775
1134
|
setRotation(positionToRotation(geoToPosition(center)));
|
|
776
1135
|
}
|
|
777
1136
|
}, [
|
|
778
1137
|
center
|
|
779
1138
|
]);
|
|
1139
|
+
const flyToSelection = useMemo2(() => d3Selection(), []);
|
|
1140
|
+
const flyToTransitionName = `globe-fly-to-${useId()}`;
|
|
1141
|
+
useEffect6(() => () => {
|
|
1142
|
+
flyToSelection.interrupt(flyToTransitionName);
|
|
1143
|
+
}, [
|
|
1144
|
+
flyToSelection,
|
|
1145
|
+
flyToTransitionName
|
|
1146
|
+
]);
|
|
780
1147
|
const zooming = useRef(false);
|
|
781
|
-
|
|
1148
|
+
const controller = useMemo2(() => {
|
|
782
1149
|
return {
|
|
783
1150
|
canvas,
|
|
784
1151
|
projection,
|
|
785
|
-
center,
|
|
786
1152
|
get zoom() {
|
|
787
1153
|
return zoomRef.current;
|
|
788
1154
|
},
|
|
789
1155
|
translation,
|
|
790
1156
|
rotation,
|
|
791
|
-
setCenter,
|
|
792
1157
|
setZoom: (state) => {
|
|
793
1158
|
if (typeof state === "function") {
|
|
794
1159
|
const is = interpolateNumber(zoomRef.current, state(zoomRef.current));
|
|
@@ -800,18 +1165,51 @@ var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: projectionProp, topo
|
|
|
800
1165
|
}
|
|
801
1166
|
},
|
|
802
1167
|
setTranslation,
|
|
803
|
-
setRotation
|
|
1168
|
+
setRotation,
|
|
1169
|
+
flyTo: (target, options = {}) => {
|
|
1170
|
+
const { duration = 1200, tilt = 0, onTick } = options;
|
|
1171
|
+
const p2 = geoToPosition(target);
|
|
1172
|
+
const r1 = projection.rotate();
|
|
1173
|
+
const r2 = positionToRotation(p2, tilt);
|
|
1174
|
+
const p1 = [
|
|
1175
|
+
-r1[0],
|
|
1176
|
+
-r1[1]
|
|
1177
|
+
];
|
|
1178
|
+
const rotationTween = createRotationTween(projection, setRotation, r1, r2);
|
|
1179
|
+
const iz = target.zoom !== void 0 ? interpolateNumber(zoomRef.current, target.zoom) : void 0;
|
|
1180
|
+
flyToSelection.interrupt(flyToTransitionName);
|
|
1181
|
+
const tx = flyToSelection.transition(flyToTransitionName).duration(flyDuration(p1, p2, duration, 1500));
|
|
1182
|
+
if (onTick) {
|
|
1183
|
+
tx.tween("flyToOnTick", () => onTick);
|
|
1184
|
+
}
|
|
1185
|
+
tx.tween("flyToRotation", () => rotationTween);
|
|
1186
|
+
if (iz) {
|
|
1187
|
+
tx.tween("flyToZoom", () => (t) => setZoom(iz(t)));
|
|
1188
|
+
}
|
|
1189
|
+
return tx.end();
|
|
1190
|
+
},
|
|
1191
|
+
cancelFlyTo: () => {
|
|
1192
|
+
flyToSelection.interrupt(flyToTransitionName);
|
|
1193
|
+
}
|
|
804
1194
|
};
|
|
805
1195
|
}, [
|
|
806
|
-
canvas
|
|
1196
|
+
canvas,
|
|
1197
|
+
projection,
|
|
1198
|
+
flyToSelection,
|
|
1199
|
+
flyToTransitionName
|
|
1200
|
+
]);
|
|
1201
|
+
useEffect6(() => {
|
|
1202
|
+
registerController(controller);
|
|
1203
|
+
return () => registerController(null);
|
|
1204
|
+
}, [
|
|
1205
|
+
registerController,
|
|
1206
|
+
controller
|
|
807
1207
|
]);
|
|
808
|
-
const generator = useMemo2(() => canvas && projection && geoPath2(projection, canvas.getContext("2d",
|
|
809
|
-
alpha: false
|
|
810
|
-
})), [
|
|
1208
|
+
const generator = useMemo2(() => canvas && projection && geoPath2(projection, canvas.getContext("2d")), [
|
|
811
1209
|
canvas,
|
|
812
1210
|
projection
|
|
813
1211
|
]);
|
|
814
|
-
|
|
1212
|
+
useEffect6(() => {
|
|
815
1213
|
if (canvas && projection) {
|
|
816
1214
|
timer(() => {
|
|
817
1215
|
projection.scale(Math.min(size.width, size.height) / 2 * zoom).translate([
|
|
@@ -822,7 +1220,17 @@ var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: projectionProp, topo
|
|
|
822
1220
|
0,
|
|
823
1221
|
0
|
|
824
1222
|
]);
|
|
825
|
-
|
|
1223
|
+
const isOrthographic = !projectionProp || projectionProp === "orthographic";
|
|
1224
|
+
const [lambda, phi] = rotation ?? [
|
|
1225
|
+
0,
|
|
1226
|
+
0,
|
|
1227
|
+
0
|
|
1228
|
+
];
|
|
1229
|
+
const viewCenter = isOrthographic ? [
|
|
1230
|
+
-lambda,
|
|
1231
|
+
-phi
|
|
1232
|
+
] : void 0;
|
|
1233
|
+
renderLayers(generator, layers, zoom, styles, viewCenter);
|
|
826
1234
|
});
|
|
827
1235
|
}
|
|
828
1236
|
}, [
|
|
@@ -831,17 +1239,20 @@ var GlobeCanvas = /* @__PURE__ */ forwardRef(({ projection: projectionProp, topo
|
|
|
831
1239
|
zoom,
|
|
832
1240
|
translation,
|
|
833
1241
|
rotation,
|
|
834
|
-
layers
|
|
1242
|
+
layers,
|
|
1243
|
+
projectionProp
|
|
835
1244
|
]);
|
|
836
1245
|
if (!size.width || !size.height) {
|
|
837
1246
|
return null;
|
|
838
1247
|
}
|
|
839
1248
|
return /* @__PURE__ */ React2.createElement("canvas", {
|
|
840
1249
|
ref: canvasRef,
|
|
1250
|
+
className: "bg-base-surface",
|
|
841
1251
|
width: size.width,
|
|
842
1252
|
height: size.height
|
|
843
1253
|
});
|
|
844
|
-
}
|
|
1254
|
+
};
|
|
1255
|
+
GlobeCanvas.displayName = "Globe.Canvas";
|
|
845
1256
|
var GlobeDebug = ({ position = "topleft" }) => {
|
|
846
1257
|
const { size, zoom, translation, rotation } = useGlobeContext();
|
|
847
1258
|
return /* @__PURE__ */ React2.createElement("div", {
|
|
@@ -879,6 +1290,7 @@ var GlobeAction = ({ onAction, position = "bottomright", ...props }) => /* @__PU
|
|
|
879
1290
|
}));
|
|
880
1291
|
var Globe = {
|
|
881
1292
|
Root: GlobeRoot,
|
|
1293
|
+
Viewport: GlobeViewport,
|
|
882
1294
|
Canvas: GlobeCanvas,
|
|
883
1295
|
Zoom: GlobeZoom,
|
|
884
1296
|
Action: GlobeAction,
|
|
@@ -889,12 +1301,13 @@ var Globe = {
|
|
|
889
1301
|
// src/components/Map/Map.tsx
|
|
890
1302
|
import "leaflet/dist/leaflet.css";
|
|
891
1303
|
import { createContext as createContext2 } from "@radix-ui/react-context";
|
|
892
|
-
import L, { Control, DomEvent, DomUtil, latLngBounds } from "leaflet";
|
|
893
|
-
import React3, { forwardRef as forwardRef2, useEffect as
|
|
1304
|
+
import L, { Control, DomEvent, DomUtil, point, latLngBounds } from "leaflet";
|
|
1305
|
+
import React3, { forwardRef as forwardRef2, useCallback as useCallback4, useEffect as useEffect7, useImperativeHandle as useImperativeHandle2, useRef as useRef2, useState as useState5 } from "react";
|
|
894
1306
|
import { createRoot } from "react-dom/client";
|
|
895
|
-
import { MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents } from "react-leaflet";
|
|
1307
|
+
import { MapContainer, Marker, Polyline, Popup, TileLayer, useMap, useMapEvents } from "react-leaflet";
|
|
896
1308
|
import { ThemeProvider, Tooltip } from "@dxos/react-ui";
|
|
897
|
-
import { composable as composable2, composableProps as composableProps2, defaultTx
|
|
1309
|
+
import { composable as composable2, composableProps as composableProps2, defaultTx } from "@dxos/react-ui";
|
|
1310
|
+
import { mx as mx2 } from "@dxos/ui-theme";
|
|
898
1311
|
var defaults = {
|
|
899
1312
|
center: {
|
|
900
1313
|
lat: 51,
|
|
@@ -903,34 +1316,106 @@ var defaults = {
|
|
|
903
1316
|
zoom: 4
|
|
904
1317
|
};
|
|
905
1318
|
var [MapContextProvider, useMapContext] = createContext2("Map");
|
|
906
|
-
var MapRoot =
|
|
907
|
-
const attention = false;
|
|
908
|
-
return /* @__PURE__ */ React3.createElement(MapContextProvider, {
|
|
909
|
-
attention,
|
|
910
|
-
onChange
|
|
911
|
-
}, /* @__PURE__ */ React3.createElement("div", {
|
|
912
|
-
...composableProps2(props, {
|
|
913
|
-
role: "none",
|
|
914
|
-
classNames: "dx-container grid dx-focus-ring-inset"
|
|
915
|
-
}),
|
|
916
|
-
ref: forwardedRef
|
|
917
|
-
}, children));
|
|
918
|
-
});
|
|
919
|
-
MapRoot.displayName = "Map.Root";
|
|
920
|
-
var MAP_CONTENT_NAME = "Map.Content";
|
|
921
|
-
var MapContent = /* @__PURE__ */ forwardRef2(({ classNames, scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center, zoom, children, ...props }, forwardedRef) => {
|
|
922
|
-
const { attention } = useMapContext(MAP_CONTENT_NAME);
|
|
1319
|
+
var MapRoot = /* @__PURE__ */ forwardRef2(({ children, onChange }, forwardedRef) => {
|
|
923
1320
|
const mapRef = useRef2(null);
|
|
924
|
-
const
|
|
1321
|
+
const registerMap = useCallback4((map) => {
|
|
1322
|
+
mapRef.current = map;
|
|
1323
|
+
}, []);
|
|
925
1324
|
useImperativeHandle2(forwardedRef, () => ({
|
|
926
|
-
|
|
927
|
-
mapRef.current?.
|
|
1325
|
+
getCenter: () => {
|
|
1326
|
+
const center = mapRef.current?.getCenter();
|
|
1327
|
+
return center ? {
|
|
1328
|
+
lat: center.lat,
|
|
1329
|
+
lng: center.lng
|
|
1330
|
+
} : void 0;
|
|
1331
|
+
},
|
|
1332
|
+
getZoom: () => mapRef.current?.getZoom(),
|
|
1333
|
+
setCenter: (center, zoom) => {
|
|
1334
|
+
mapRef.current?.setView(center, zoom);
|
|
928
1335
|
},
|
|
929
1336
|
setZoom: (cb) => {
|
|
930
1337
|
mapRef.current?.setZoom(cb(mapRef.current?.getZoom() ?? 0));
|
|
931
1338
|
}
|
|
932
1339
|
}), []);
|
|
933
|
-
|
|
1340
|
+
const attention = false;
|
|
1341
|
+
return /* @__PURE__ */ React3.createElement(MapContextProvider, {
|
|
1342
|
+
attention,
|
|
1343
|
+
onChange,
|
|
1344
|
+
registerMap
|
|
1345
|
+
}, children);
|
|
1346
|
+
});
|
|
1347
|
+
MapRoot.displayName = "Map.Root";
|
|
1348
|
+
var MAP_VIEWPORT_NAME = "Map.Viewport";
|
|
1349
|
+
var MapResize = () => {
|
|
1350
|
+
const map = useMap();
|
|
1351
|
+
useEffect7(() => {
|
|
1352
|
+
const container = map.getContainer();
|
|
1353
|
+
let frame = 0;
|
|
1354
|
+
const observer = new ResizeObserver(() => {
|
|
1355
|
+
cancelAnimationFrame(frame);
|
|
1356
|
+
frame = requestAnimationFrame(() => map.invalidateSize());
|
|
1357
|
+
});
|
|
1358
|
+
observer.observe(container);
|
|
1359
|
+
return () => {
|
|
1360
|
+
cancelAnimationFrame(frame);
|
|
1361
|
+
observer.disconnect();
|
|
1362
|
+
};
|
|
1363
|
+
}, [
|
|
1364
|
+
map
|
|
1365
|
+
]);
|
|
1366
|
+
return null;
|
|
1367
|
+
};
|
|
1368
|
+
var PINCH_ZOOM_SENSITIVITY = 0.03;
|
|
1369
|
+
var MapPinchZoom = () => {
|
|
1370
|
+
const map = useMap();
|
|
1371
|
+
useEffect7(() => {
|
|
1372
|
+
const container = map.getContainer();
|
|
1373
|
+
let frame = 0;
|
|
1374
|
+
let point2;
|
|
1375
|
+
let target;
|
|
1376
|
+
const onWheel = (event) => {
|
|
1377
|
+
if (!event.ctrlKey) {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
event.preventDefault();
|
|
1381
|
+
const rect = container.getBoundingClientRect();
|
|
1382
|
+
point2 = L.point(event.clientX - rect.left, event.clientY - rect.top);
|
|
1383
|
+
target = (target ?? map.getZoom()) - event.deltaY * PINCH_ZOOM_SENSITIVITY;
|
|
1384
|
+
if (!frame) {
|
|
1385
|
+
frame = requestAnimationFrame(() => {
|
|
1386
|
+
frame = 0;
|
|
1387
|
+
if (target !== void 0 && point2) {
|
|
1388
|
+
map.setZoomAround(point2, target, {
|
|
1389
|
+
animate: false
|
|
1390
|
+
});
|
|
1391
|
+
target = void 0;
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
container.addEventListener("wheel", onWheel, {
|
|
1397
|
+
passive: false
|
|
1398
|
+
});
|
|
1399
|
+
return () => {
|
|
1400
|
+
container.removeEventListener("wheel", onWheel);
|
|
1401
|
+
cancelAnimationFrame(frame);
|
|
1402
|
+
};
|
|
1403
|
+
}, [
|
|
1404
|
+
map
|
|
1405
|
+
]);
|
|
1406
|
+
return null;
|
|
1407
|
+
};
|
|
1408
|
+
var MapViewport = composable2((props, _forwardedRef) => {
|
|
1409
|
+
const { scrollWheelZoom = true, doubleClickZoom = true, touchZoom = true, center, zoom, whenReady, children, ...rest } = props;
|
|
1410
|
+
const { attention, registerMap } = useMapContext(MAP_VIEWPORT_NAME);
|
|
1411
|
+
const [map, setMap] = useState5(null);
|
|
1412
|
+
const setMapRef = useCallback4((next) => {
|
|
1413
|
+
setMap(next);
|
|
1414
|
+
registerMap(next);
|
|
1415
|
+
}, [
|
|
1416
|
+
registerMap
|
|
1417
|
+
]);
|
|
1418
|
+
useEffect7(() => {
|
|
934
1419
|
if (!map) {
|
|
935
1420
|
return;
|
|
936
1421
|
}
|
|
@@ -944,27 +1429,31 @@ var MapContent = /* @__PURE__ */ forwardRef2(({ classNames, scrollWheelZoom = tr
|
|
|
944
1429
|
attention
|
|
945
1430
|
]);
|
|
946
1431
|
return /* @__PURE__ */ React3.createElement(MapContainer, {
|
|
947
|
-
...
|
|
948
|
-
|
|
1432
|
+
...composableProps2(rest, {
|
|
1433
|
+
// Frame classes (formerly on Map.Root): focusable grid container.
|
|
1434
|
+
classNames: "dx-container group relative grid dx-focus-ring-inset bg-base-surface!"
|
|
1435
|
+
}),
|
|
949
1436
|
attributionControl: false,
|
|
950
1437
|
zoomControl: false,
|
|
951
1438
|
scrollWheelZoom,
|
|
952
1439
|
doubleClickZoom,
|
|
953
1440
|
touchZoom,
|
|
1441
|
+
// Allow fractional zoom so trackpad pinch (small ctrl+wheel deltas) isn't rounded away.
|
|
1442
|
+
zoomSnap: 0,
|
|
954
1443
|
center: center ?? defaults.center,
|
|
955
1444
|
zoom: zoom ?? defaults.zoom,
|
|
956
|
-
whenReady
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
}, children);
|
|
1445
|
+
whenReady,
|
|
1446
|
+
ref: setMapRef
|
|
1447
|
+
}, /* @__PURE__ */ React3.createElement(MapResize, null), /* @__PURE__ */ React3.createElement(MapPinchZoom, null), children);
|
|
960
1448
|
});
|
|
961
|
-
|
|
1449
|
+
MapViewport.displayName = "Map.Viewport";
|
|
962
1450
|
var MAP_TILES_NAME = "Map.Tiles";
|
|
963
|
-
var
|
|
1451
|
+
var DEFAULT_TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
|
|
1452
|
+
var MapTiles = ({ url = DEFAULT_TILE_URL }) => {
|
|
964
1453
|
const ref = useRef2(null);
|
|
965
1454
|
const { onChange } = useMapContext(MAP_TILES_NAME);
|
|
966
1455
|
useMapEvents({
|
|
967
|
-
|
|
1456
|
+
moveend: (ev) => {
|
|
968
1457
|
onChange?.({
|
|
969
1458
|
center: ev.target.getCenter(),
|
|
970
1459
|
zoom: ev.target.getZoom()
|
|
@@ -972,7 +1461,7 @@ var MapTiles = (_props) => {
|
|
|
972
1461
|
}
|
|
973
1462
|
});
|
|
974
1463
|
const { attention } = useMapContext(MAP_TILES_NAME);
|
|
975
|
-
|
|
1464
|
+
useEffect7(() => {
|
|
976
1465
|
if (ref.current) {
|
|
977
1466
|
ref.current.getContainer().dataset.attention = attention ? "1" : "0";
|
|
978
1467
|
}
|
|
@@ -984,22 +1473,34 @@ var MapTiles = (_props) => {
|
|
|
984
1473
|
"data-attention": attention,
|
|
985
1474
|
detectRetina: true,
|
|
986
1475
|
className: 'dark:grayscale dark:invert data-[attention="0"]:!opacity-80',
|
|
987
|
-
url
|
|
1476
|
+
url,
|
|
988
1477
|
keepBuffer: 4
|
|
989
1478
|
}));
|
|
990
1479
|
};
|
|
991
1480
|
MapTiles.displayName = MAP_TILES_NAME;
|
|
992
|
-
var MapMarkers = ({ selected, markers }) => {
|
|
1481
|
+
var MapMarkers = ({ selected, markers, lines, onSelect }) => {
|
|
993
1482
|
const map = useMap();
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1483
|
+
useEffect7(() => {
|
|
1484
|
+
const points = [
|
|
1485
|
+
...markers?.map((marker) => marker.location) ?? [],
|
|
1486
|
+
...lines?.flatMap((line) => [
|
|
1487
|
+
line.source,
|
|
1488
|
+
line.target
|
|
1489
|
+
]) ?? []
|
|
1490
|
+
];
|
|
1491
|
+
if (points.length > 0) {
|
|
1492
|
+
const bounds = latLngBounds(points);
|
|
1493
|
+
const size = map.getSize();
|
|
1494
|
+
const padding = Math.max(48, Math.min(size.x, size.y) / 6);
|
|
1495
|
+
map.fitBounds(bounds, {
|
|
1496
|
+
padding: point(padding, padding),
|
|
1497
|
+
animate: false
|
|
1498
|
+
});
|
|
1000
1499
|
}
|
|
1001
1500
|
}, [
|
|
1002
|
-
markers
|
|
1501
|
+
markers,
|
|
1502
|
+
lines,
|
|
1503
|
+
map
|
|
1003
1504
|
]);
|
|
1004
1505
|
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, markers?.map(({ id, title, location: { lat, lng } }) => {
|
|
1005
1506
|
return /* @__PURE__ */ React3.createElement(Marker, {
|
|
@@ -1008,6 +1509,9 @@ var MapMarkers = ({ selected, markers }) => {
|
|
|
1008
1509
|
lat,
|
|
1009
1510
|
lng
|
|
1010
1511
|
},
|
|
1512
|
+
eventHandlers: onSelect ? {
|
|
1513
|
+
click: () => onSelect(id)
|
|
1514
|
+
} : void 0,
|
|
1011
1515
|
icon: (
|
|
1012
1516
|
// TODO(burdon): Create custom icon from bundled assets.
|
|
1013
1517
|
// TODO(burdon): Selection state.
|
|
@@ -1037,9 +1541,41 @@ var MapMarkers = ({ selected, markers }) => {
|
|
|
1037
1541
|
}));
|
|
1038
1542
|
};
|
|
1039
1543
|
MapMarkers.displayName = "Map.Markers";
|
|
1544
|
+
var MapLines = ({ lines }) => {
|
|
1545
|
+
if (!lines || lines.length === 0) {
|
|
1546
|
+
return null;
|
|
1547
|
+
}
|
|
1548
|
+
const polylines = [];
|
|
1549
|
+
for (const { source, target, color } of lines) {
|
|
1550
|
+
const last = polylines[polylines.length - 1];
|
|
1551
|
+
const lastPos = last?.positions[last.positions.length - 1];
|
|
1552
|
+
if (last && last.color === color && lastPos?.lat === source.lat && lastPos?.lng === source.lng) {
|
|
1553
|
+
last.positions.push(target);
|
|
1554
|
+
} else {
|
|
1555
|
+
polylines.push({
|
|
1556
|
+
positions: [
|
|
1557
|
+
source,
|
|
1558
|
+
target
|
|
1559
|
+
],
|
|
1560
|
+
color
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, polylines.map(({ positions, color }, index) => /* @__PURE__ */ React3.createElement(Polyline, {
|
|
1565
|
+
key: index,
|
|
1566
|
+
positions,
|
|
1567
|
+
pathOptions: {
|
|
1568
|
+
color,
|
|
1569
|
+
weight: 4,
|
|
1570
|
+
opacity: 0.8
|
|
1571
|
+
}
|
|
1572
|
+
})));
|
|
1573
|
+
};
|
|
1574
|
+
MapLines.displayName = "Map.Lines";
|
|
1040
1575
|
var CustomControl2 = ({ position, children }) => {
|
|
1041
1576
|
const map = useMap();
|
|
1042
|
-
|
|
1577
|
+
const rootRef = useRef2(void 0);
|
|
1578
|
+
useEffect7(() => {
|
|
1043
1579
|
const control = new Control({
|
|
1044
1580
|
position
|
|
1045
1581
|
});
|
|
@@ -1048,6 +1584,7 @@ var CustomControl2 = ({ position, children }) => {
|
|
|
1048
1584
|
DomEvent.disableClickPropagation(container);
|
|
1049
1585
|
DomEvent.disableScrollPropagation(container);
|
|
1050
1586
|
const root = createRoot(container);
|
|
1587
|
+
rootRef.current = root;
|
|
1051
1588
|
root.render(/* @__PURE__ */ React3.createElement(ThemeProvider, {
|
|
1052
1589
|
tx: defaultTx
|
|
1053
1590
|
}, /* @__PURE__ */ React3.createElement(Tooltip.Provider, null, children)));
|
|
@@ -1056,10 +1593,19 @@ var CustomControl2 = ({ position, children }) => {
|
|
|
1056
1593
|
control.addTo(map);
|
|
1057
1594
|
return () => {
|
|
1058
1595
|
control.remove();
|
|
1596
|
+
const root = rootRef.current;
|
|
1597
|
+
rootRef.current = void 0;
|
|
1598
|
+
queueMicrotask(() => root?.unmount());
|
|
1059
1599
|
};
|
|
1060
1600
|
}, [
|
|
1061
1601
|
map,
|
|
1062
|
-
position
|
|
1602
|
+
position
|
|
1603
|
+
]);
|
|
1604
|
+
useEffect7(() => {
|
|
1605
|
+
rootRef.current?.render(/* @__PURE__ */ React3.createElement(ThemeProvider, {
|
|
1606
|
+
tx: defaultTx
|
|
1607
|
+
}, /* @__PURE__ */ React3.createElement(Tooltip.Provider, null, children)));
|
|
1608
|
+
}, [
|
|
1063
1609
|
children
|
|
1064
1610
|
]);
|
|
1065
1611
|
return null;
|
|
@@ -1076,41 +1622,46 @@ var MapAction = ({ onAction, position = "bottomright", ...props }) => /* @__PURE
|
|
|
1076
1622
|
}, /* @__PURE__ */ React3.createElement(ActionControls, {
|
|
1077
1623
|
onAction
|
|
1078
1624
|
}));
|
|
1079
|
-
var
|
|
1625
|
+
var Map2 = {
|
|
1080
1626
|
Root: MapRoot,
|
|
1081
|
-
|
|
1627
|
+
Viewport: MapViewport,
|
|
1082
1628
|
Tiles: MapTiles,
|
|
1083
1629
|
Markers: MapMarkers,
|
|
1630
|
+
Lines: MapLines,
|
|
1084
1631
|
Zoom: MapZoom,
|
|
1085
1632
|
Action: MapAction
|
|
1086
1633
|
};
|
|
1087
1634
|
export {
|
|
1088
1635
|
ActionControls,
|
|
1636
|
+
DEFAULT_TILE_URL,
|
|
1089
1637
|
Globe,
|
|
1090
1638
|
GlobeContext,
|
|
1091
|
-
Map,
|
|
1639
|
+
Map2 as Map,
|
|
1092
1640
|
ZoomControls,
|
|
1093
1641
|
closestPoint,
|
|
1094
1642
|
controlPositions,
|
|
1095
1643
|
createLayers,
|
|
1644
|
+
createRotationTween,
|
|
1645
|
+
flyDuration,
|
|
1096
1646
|
geoCircle,
|
|
1097
1647
|
geoInertiaDrag,
|
|
1098
1648
|
geoLine,
|
|
1099
1649
|
geoPoint,
|
|
1100
1650
|
geoToPosition,
|
|
1101
1651
|
getDistance,
|
|
1102
|
-
|
|
1652
|
+
globeStyles,
|
|
1103
1653
|
positionToRotation,
|
|
1104
1654
|
renderLayers,
|
|
1105
1655
|
restrictAxis,
|
|
1106
1656
|
timer,
|
|
1107
|
-
translationKey,
|
|
1108
|
-
translations,
|
|
1109
1657
|
useDrag,
|
|
1110
1658
|
useGlobeContext,
|
|
1111
1659
|
useGlobeZoomHandler,
|
|
1112
1660
|
useMapZoomHandler,
|
|
1661
|
+
useSimplifiedTopology,
|
|
1113
1662
|
useSpinner,
|
|
1114
|
-
|
|
1663
|
+
useTopology,
|
|
1664
|
+
useTour,
|
|
1665
|
+
useWheel
|
|
1115
1666
|
};
|
|
1116
1667
|
//# sourceMappingURL=index.mjs.map
|