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