@guardian/interactive-component-library 0.1.0-alpha.57 → 0.1.0-alpha.59
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.
|
@@ -327,9 +327,9 @@
|
|
|
327
327
|
labelType === LabelType.hanging && !hideLabels && hangingLabelConfig.map((config, i) => renderLabel(config, i))
|
|
328
328
|
] });
|
|
329
329
|
}
|
|
330
|
-
const svg$8 = "
|
|
331
|
-
const previous = "
|
|
332
|
-
const next = "
|
|
330
|
+
const svg$8 = "_svg_8bh9o_6";
|
|
331
|
+
const previous = "_previous_8bh9o_12";
|
|
332
|
+
const next = "_next_8bh9o_16";
|
|
333
333
|
const defaultStyles$u = {
|
|
334
334
|
svg: svg$8,
|
|
335
335
|
previous,
|
|
@@ -493,25 +493,27 @@
|
|
|
493
493
|
circle: circle$1,
|
|
494
494
|
pulse
|
|
495
495
|
};
|
|
496
|
-
const CircleIcon = ({ color: color2, pulse: pulse2 = false, styles: styles2 }) => {
|
|
496
|
+
const CircleIcon = ({ color: color2, pulse: pulse2 = false, diameter = 11, styles: styles2 }) => {
|
|
497
497
|
styles2 = mergeStyles(defaultStyles$r, styles2);
|
|
498
|
+
let radius = diameter / 2;
|
|
499
|
+
let padding = 2;
|
|
498
500
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
499
501
|
"svg",
|
|
500
502
|
{
|
|
501
503
|
style: styles2.svg,
|
|
502
504
|
fill: "none",
|
|
503
|
-
height:
|
|
504
|
-
viewBox:
|
|
505
|
-
width:
|
|
505
|
+
height: diameter + padding,
|
|
506
|
+
viewBox: `0 0 ${diameter + padding} ${diameter + padding}`,
|
|
507
|
+
width: diameter + padding,
|
|
506
508
|
xmlns: "http://www.w3.org/2000/svg",
|
|
507
509
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
508
|
-
"
|
|
510
|
+
"circle",
|
|
509
511
|
{
|
|
510
512
|
className: [styles2.circle, pulse2 && styles2.pulse].join(" "),
|
|
511
513
|
style: { fill: color2 },
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
514
|
+
r: radius,
|
|
515
|
+
cx: radius + padding / 2,
|
|
516
|
+
cy: radius + padding / 2
|
|
515
517
|
}
|
|
516
518
|
)
|
|
517
519
|
}
|
|
@@ -1139,6 +1141,19 @@
|
|
|
1139
1141
|
}
|
|
1140
1142
|
) });
|
|
1141
1143
|
}
|
|
1144
|
+
const style = {
|
|
1145
|
+
"aspect-ratio-box": "_aspect-ratio-box_1e5oy_1"
|
|
1146
|
+
};
|
|
1147
|
+
function AspectRatioBox({ heightAsProportionOfWidth, children }) {
|
|
1148
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1149
|
+
"div",
|
|
1150
|
+
{
|
|
1151
|
+
className: style["aspect-ratio-box"],
|
|
1152
|
+
style: { "--aspect-ratio": heightAsProportionOfWidth },
|
|
1153
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", width: "100%", height: "100%" }, children })
|
|
1154
|
+
}
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1142
1157
|
const sortAscending = (accessor) => {
|
|
1143
1158
|
return (a, b) => {
|
|
1144
1159
|
const valueA = a[accessor];
|
|
@@ -2732,7 +2747,7 @@
|
|
|
2732
2747
|
};
|
|
2733
2748
|
return feature;
|
|
2734
2749
|
}
|
|
2735
|
-
const MapContext = preact.createContext();
|
|
2750
|
+
const MapContext$1 = preact.createContext();
|
|
2736
2751
|
function SVGMapProvider({
|
|
2737
2752
|
id: id2,
|
|
2738
2753
|
mapRef,
|
|
@@ -2811,20 +2826,20 @@
|
|
|
2811
2826
|
findFeatureAtPoint
|
|
2812
2827
|
};
|
|
2813
2828
|
mapRef.current = context;
|
|
2814
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MapContext.Provider, { value: context, children });
|
|
2829
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MapContext$1.Provider, { value: context, children });
|
|
2815
2830
|
}
|
|
2816
2831
|
const path = "_path_1cwd5_9";
|
|
2817
2832
|
const defaultStyles$1 = {
|
|
2818
2833
|
path
|
|
2819
2834
|
};
|
|
2820
2835
|
function CompositionBorders({ styles: styles2 }) {
|
|
2821
|
-
const context = hooks.useContext(MapContext);
|
|
2836
|
+
const context = hooks.useContext(MapContext$1);
|
|
2822
2837
|
const { projection } = context;
|
|
2823
2838
|
styles2 = mergeStyles(defaultStyles$1, styles2);
|
|
2824
2839
|
return /* @__PURE__ */ jsxRuntime.jsx("path", { className: styles2.path, d: projection.getCompositionBorders() });
|
|
2825
2840
|
}
|
|
2826
2841
|
function SVGRenderer({ children }) {
|
|
2827
|
-
const { id: id2, config, size, selectedFeature, padding } = hooks.useContext(MapContext);
|
|
2842
|
+
const { id: id2, config, size, selectedFeature, padding } = hooks.useContext(MapContext$1);
|
|
2828
2843
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2829
2844
|
"svg",
|
|
2830
2845
|
{
|
|
@@ -3262,7 +3277,7 @@
|
|
|
3262
3277
|
zIndex = 0,
|
|
3263
3278
|
styles: styles2
|
|
3264
3279
|
}) {
|
|
3265
|
-
const context = hooks.useContext(MapContext);
|
|
3280
|
+
const context = hooks.useContext(MapContext$1);
|
|
3266
3281
|
const [searchIndex, setSearchIndex] = hooks.useState();
|
|
3267
3282
|
hooks.useEffect(() => {
|
|
3268
3283
|
if (!context.path) return;
|
|
@@ -3320,7 +3335,7 @@
|
|
|
3320
3335
|
}) });
|
|
3321
3336
|
}
|
|
3322
3337
|
function Line({ id: id2, features, stroke = null, strokeWidth = 1, styles: styles2 }) {
|
|
3323
|
-
const context = hooks.useContext(MapContext);
|
|
3338
|
+
const context = hooks.useContext(MapContext$1);
|
|
3324
3339
|
const draw = (ctx, path2) => {
|
|
3325
3340
|
for (const feature of features) {
|
|
3326
3341
|
ctx.beginPath();
|
|
@@ -3361,7 +3376,7 @@
|
|
|
3361
3376
|
}) });
|
|
3362
3377
|
}
|
|
3363
3378
|
function Prerendered({ url }) {
|
|
3364
|
-
const context = hooks.useContext(MapContext);
|
|
3379
|
+
const context = hooks.useContext(MapContext$1);
|
|
3365
3380
|
const { width, height } = context.contentSize;
|
|
3366
3381
|
return /* @__PURE__ */ jsxRuntime.jsx("image", { width, height, href: url });
|
|
3367
3382
|
}
|
|
@@ -3375,7 +3390,7 @@
|
|
|
3375
3390
|
zIndex = 0,
|
|
3376
3391
|
styles: styles2
|
|
3377
3392
|
}) {
|
|
3378
|
-
const context = hooks.useContext(MapContext);
|
|
3393
|
+
const context = hooks.useContext(MapContext$1);
|
|
3379
3394
|
hooks.useEffect(() => {
|
|
3380
3395
|
function findFeatureAtPoint(point) {
|
|
3381
3396
|
for (const [index, feature] of features.entries()) {
|
|
@@ -3515,10 +3530,10 @@
|
|
|
3515
3530
|
);
|
|
3516
3531
|
const containerSize = useContainerSize(containerRef);
|
|
3517
3532
|
const containerStyle = hooks.useMemo(() => {
|
|
3518
|
-
const
|
|
3519
|
-
if (width > 0)
|
|
3520
|
-
if (height > 0)
|
|
3521
|
-
return
|
|
3533
|
+
const style2 = {};
|
|
3534
|
+
if (width > 0) style2["width"] = width;
|
|
3535
|
+
if (height > 0) style2["height"] = height;
|
|
3536
|
+
return style2;
|
|
3522
3537
|
}, [width, height]);
|
|
3523
3538
|
const renderSVG = containerSize && !config.drawToCanvas;
|
|
3524
3539
|
const childrenArray = Array.isArray(children) ? children : [children];
|
|
@@ -3593,6 +3608,254 @@
|
|
|
3593
3608
|
}
|
|
3594
3609
|
return size;
|
|
3595
3610
|
}
|
|
3611
|
+
function bboxFeature(bounds) {
|
|
3612
|
+
const minLon = bounds[0][0];
|
|
3613
|
+
const minLat = bounds[0][1];
|
|
3614
|
+
const maxLon = bounds[1][0];
|
|
3615
|
+
const maxLat = bounds[1][1];
|
|
3616
|
+
const feature = {
|
|
3617
|
+
type: "Feature",
|
|
3618
|
+
properties: {},
|
|
3619
|
+
geometry: {
|
|
3620
|
+
coordinates: [
|
|
3621
|
+
[
|
|
3622
|
+
[minLon, maxLat],
|
|
3623
|
+
[maxLon, maxLat],
|
|
3624
|
+
[maxLon, minLat],
|
|
3625
|
+
[minLon, minLat],
|
|
3626
|
+
[minLon, maxLat]
|
|
3627
|
+
]
|
|
3628
|
+
],
|
|
3629
|
+
type: "Polygon"
|
|
3630
|
+
}
|
|
3631
|
+
};
|
|
3632
|
+
return feature;
|
|
3633
|
+
}
|
|
3634
|
+
const BASE_RESOLUTION = 156543.03392;
|
|
3635
|
+
function zoomLevelToZoomScale(zoomLevel, initialResolution) {
|
|
3636
|
+
const resolution = BASE_RESOLUTION / Math.pow(2, zoomLevel);
|
|
3637
|
+
const zoomScale = initialResolution / resolution;
|
|
3638
|
+
return zoomScale;
|
|
3639
|
+
}
|
|
3640
|
+
function zoomLevelForResolution(currentResolution) {
|
|
3641
|
+
const zoomLevel = Math.log2(BASE_RESOLUTION / currentResolution);
|
|
3642
|
+
return zoomLevel;
|
|
3643
|
+
}
|
|
3644
|
+
function haversineDistance(lat1, lon1, lat2, lon2) {
|
|
3645
|
+
const R2 = 6371e3;
|
|
3646
|
+
const toRadians = (degrees2) => degrees2 * Math.PI / 180;
|
|
3647
|
+
const dLat = toRadians(lat2 - lat1);
|
|
3648
|
+
const dLon = toRadians(lon2 - lon1);
|
|
3649
|
+
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
3650
|
+
const c2 = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
3651
|
+
return R2 * c2;
|
|
3652
|
+
}
|
|
3653
|
+
function resolutionForExtent(extent, viewportSize) {
|
|
3654
|
+
const [lonMin, latMin, lonMax, latMax] = extent;
|
|
3655
|
+
const latMid = (latMin + latMax) / 2;
|
|
3656
|
+
const distance = haversineDistance(latMid, lonMin, latMid, lonMax);
|
|
3657
|
+
const resolution = distance / viewportSize[0];
|
|
3658
|
+
return resolution;
|
|
3659
|
+
}
|
|
3660
|
+
const Projection = {
|
|
3661
|
+
geoIdentity: d3Geo.geoIdentity(),
|
|
3662
|
+
geoMercator: d3Geo.geoMercator(),
|
|
3663
|
+
geoAlbersUS: d3Geo.geoAlbersUsa().scale(1070).translate([487.5, 305]),
|
|
3664
|
+
geoAlbersUKComposite: geoAlbersUk(),
|
|
3665
|
+
geoAlbersEngland: d3Geo.geoAlbers().center([0, 52.7]).rotate([1.1743, 0]).parallels([50, 54])
|
|
3666
|
+
};
|
|
3667
|
+
function validateGeometries(geometries) {
|
|
3668
|
+
if (!Array.isArray(geometries)) {
|
|
3669
|
+
throw new Error("geometries must be an array");
|
|
3670
|
+
}
|
|
3671
|
+
geometries.forEach((geometry) => {
|
|
3672
|
+
var _a;
|
|
3673
|
+
if (!geometry.type) {
|
|
3674
|
+
throw new Error("geometry must have a type");
|
|
3675
|
+
}
|
|
3676
|
+
if (!((_a = geometry.coordinates) == null ? void 0 : _a.length)) {
|
|
3677
|
+
throw new Error("geometry must have coordinates");
|
|
3678
|
+
}
|
|
3679
|
+
});
|
|
3680
|
+
}
|
|
3681
|
+
function generateDebugUrl(feature, convertToGeoJSON = true) {
|
|
3682
|
+
const featureGeoJSON = convertToGeoJSON ? feature.getGeoJSON() : feature;
|
|
3683
|
+
const featureCollection = {
|
|
3684
|
+
type: "FeatureCollection",
|
|
3685
|
+
features: [featureGeoJSON]
|
|
3686
|
+
};
|
|
3687
|
+
const jsonString = encodeURIComponent(JSON.stringify(featureCollection));
|
|
3688
|
+
return `https://geojson.io/#data=data:application/json,${jsonString}`;
|
|
3689
|
+
}
|
|
3690
|
+
class View {
|
|
3691
|
+
constructor({
|
|
3692
|
+
projection = Projection.geoIdentity,
|
|
3693
|
+
extent,
|
|
3694
|
+
minZoom = 1,
|
|
3695
|
+
maxZoom = 10,
|
|
3696
|
+
padding = { top: 0, right: 0, bottom: 0, left: 0 }
|
|
3697
|
+
}, debug = false) {
|
|
3698
|
+
this.debug = debug;
|
|
3699
|
+
projection.revision = 0;
|
|
3700
|
+
this.projection = projection;
|
|
3701
|
+
this.extent = extent;
|
|
3702
|
+
this.minZoom = minZoom;
|
|
3703
|
+
this.maxZoom = maxZoom;
|
|
3704
|
+
this._transform = d3Zoom.zoomIdentity;
|
|
3705
|
+
this._padding = padding;
|
|
3706
|
+
this._viewPortSize = [0, 0];
|
|
3707
|
+
this.pixelRatio = window.devicePixelRatio;
|
|
3708
|
+
}
|
|
3709
|
+
set viewPortSize(size) {
|
|
3710
|
+
const previousSize = this._viewPortSize;
|
|
3711
|
+
this._viewPortSize = size;
|
|
3712
|
+
if (previousSize !== size) {
|
|
3713
|
+
if (this.extent) {
|
|
3714
|
+
this.fitExtent(this.extent);
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
get viewPortSize() {
|
|
3719
|
+
return this._viewPortSize;
|
|
3720
|
+
}
|
|
3721
|
+
set transform(transform) {
|
|
3722
|
+
this._transform = transform;
|
|
3723
|
+
}
|
|
3724
|
+
get transform() {
|
|
3725
|
+
return new d3Zoom.ZoomTransform(
|
|
3726
|
+
this._transform.k,
|
|
3727
|
+
this._transform.x * this.pixelRatio,
|
|
3728
|
+
this._transform.y * this.pixelRatio
|
|
3729
|
+
);
|
|
3730
|
+
}
|
|
3731
|
+
// map size in pixels (i.e. scaled by device pixel ratio)
|
|
3732
|
+
get mapSize() {
|
|
3733
|
+
return scaleSize(this.viewPortSize, this.pixelRatio);
|
|
3734
|
+
}
|
|
3735
|
+
get padding() {
|
|
3736
|
+
return this._padding;
|
|
3737
|
+
}
|
|
3738
|
+
// padding in pixels (i.e. scaled by device pixel ratio)
|
|
3739
|
+
get scaledPadding() {
|
|
3740
|
+
const scaledPadding = { ...this._padding };
|
|
3741
|
+
return scalePadding(scaledPadding, this.pixelRatio);
|
|
3742
|
+
}
|
|
3743
|
+
get baseResolution() {
|
|
3744
|
+
const baseExtent = this.getVisibleExtent(d3Zoom.zoomIdentity, this.projection);
|
|
3745
|
+
const baseResolution = resolutionForExtent(baseExtent, this.viewPortSize);
|
|
3746
|
+
return baseResolution;
|
|
3747
|
+
}
|
|
3748
|
+
// calculates the upper and lower zoom scales
|
|
3749
|
+
get scaleExtent() {
|
|
3750
|
+
const maxScale = zoomLevelToZoomScale(this.maxZoom, this.baseResolution);
|
|
3751
|
+
return [1, maxScale];
|
|
3752
|
+
}
|
|
3753
|
+
setProjection(projection) {
|
|
3754
|
+
this.projection = projection;
|
|
3755
|
+
this.fitObject(bboxFeature(this.extent));
|
|
3756
|
+
}
|
|
3757
|
+
// only set the raw projection when it has already been configured with projection.fitExtent()
|
|
3758
|
+
setRawProjection(projection) {
|
|
3759
|
+
this.projection = projection;
|
|
3760
|
+
}
|
|
3761
|
+
fitExtent(extent) {
|
|
3762
|
+
const extentFeature = bboxFeature(extent);
|
|
3763
|
+
this.fitObject(extentFeature);
|
|
3764
|
+
if (this.debug) {
|
|
3765
|
+
console.log("Fit extent", extent, generateDebugUrl(extentFeature, false));
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
fitObject(geoJSON) {
|
|
3769
|
+
this.projection.fitExtent(this.getMapExtent(), geoJSON);
|
|
3770
|
+
++this.projection.revision;
|
|
3771
|
+
}
|
|
3772
|
+
// returns bounds relative to the viewport
|
|
3773
|
+
boundsForExtent(extent) {
|
|
3774
|
+
const SW = this.projection([extent[0], extent[1]]);
|
|
3775
|
+
const NE = this.projection([extent[2], extent[3]]);
|
|
3776
|
+
const minX = SW[0] / this.pixelRatio;
|
|
3777
|
+
const minY = NE[1] / this.pixelRatio;
|
|
3778
|
+
const maxX = NE[0] / this.pixelRatio;
|
|
3779
|
+
const maxY = SW[1] / this.pixelRatio;
|
|
3780
|
+
const width = maxX - minX;
|
|
3781
|
+
const height = maxY - minY;
|
|
3782
|
+
return [
|
|
3783
|
+
[minX, minY],
|
|
3784
|
+
[width, height]
|
|
3785
|
+
];
|
|
3786
|
+
}
|
|
3787
|
+
invert(point) {
|
|
3788
|
+
const { projection, pixelRatio, transform } = this.getState();
|
|
3789
|
+
const scaledPoint = [point[0] * pixelRatio, point[1] * pixelRatio];
|
|
3790
|
+
const untransformedPoint = transform.invert(scaledPoint);
|
|
3791
|
+
const mapCoordinate = projection.invert(untransformedPoint);
|
|
3792
|
+
return mapCoordinate;
|
|
3793
|
+
}
|
|
3794
|
+
// bounds is defined as [[minX, minY], [maxX, maxY]]
|
|
3795
|
+
invertBounds(bounds) {
|
|
3796
|
+
const topLeft = bounds[0];
|
|
3797
|
+
const topRight = [bounds[1][0], bounds[0][1]];
|
|
3798
|
+
const bottomRight = [bounds[1][0], bounds[1][1]];
|
|
3799
|
+
const bottomLeft = [bounds[0][0], bounds[1][1]];
|
|
3800
|
+
const points = [topLeft, topRight, bottomRight, bottomLeft, topLeft];
|
|
3801
|
+
return points.map((d2) => this.invert(d2));
|
|
3802
|
+
}
|
|
3803
|
+
// map resolution (meters per pixel)
|
|
3804
|
+
getResolution() {
|
|
3805
|
+
return resolutionForExtent(
|
|
3806
|
+
this.getVisibleExtent(this.transform, this.projection),
|
|
3807
|
+
this.viewPortSize
|
|
3808
|
+
);
|
|
3809
|
+
}
|
|
3810
|
+
// map zoom level (0 = the entire world)
|
|
3811
|
+
getZoomLevel() {
|
|
3812
|
+
return zoomLevelForResolution(this.getResolution());
|
|
3813
|
+
}
|
|
3814
|
+
//
|
|
3815
|
+
/**
|
|
3816
|
+
* Function that returns the extent of the view in screen coordinates
|
|
3817
|
+
* The extent is defined as [[minX, minY], [maxX, maxY]]
|
|
3818
|
+
* @function getMapExtent
|
|
3819
|
+
* @returns {[[number, number], [number, number]]}
|
|
3820
|
+
*/
|
|
3821
|
+
getMapExtent() {
|
|
3822
|
+
const mapSizeInPixels = this.mapSize;
|
|
3823
|
+
const paddingInPixels = this.scaledPadding;
|
|
3824
|
+
return [
|
|
3825
|
+
[paddingInPixels.left, paddingInPixels.top],
|
|
3826
|
+
sizeMinusPadding(mapSizeInPixels, {
|
|
3827
|
+
...paddingInPixels,
|
|
3828
|
+
left: 0,
|
|
3829
|
+
top: 0
|
|
3830
|
+
})
|
|
3831
|
+
];
|
|
3832
|
+
}
|
|
3833
|
+
// visible extent in map coordinates
|
|
3834
|
+
getVisibleExtent(transform, projection) {
|
|
3835
|
+
if (this.projection === Projection.geoIdentity) {
|
|
3836
|
+
const [width2, height2] = this.mapSize;
|
|
3837
|
+
return [0, 0, width2, height2];
|
|
3838
|
+
}
|
|
3839
|
+
const [width, height] = this.mapSize;
|
|
3840
|
+
const southWest = projection.invert(transform.invert([0, height]));
|
|
3841
|
+
const northEast = projection.invert(transform.invert([width, 0]));
|
|
3842
|
+
return [southWest[0], southWest[1], northEast[0], northEast[1]];
|
|
3843
|
+
}
|
|
3844
|
+
getState() {
|
|
3845
|
+
const transform = this.transform;
|
|
3846
|
+
const projection = this.projection;
|
|
3847
|
+
return {
|
|
3848
|
+
transform,
|
|
3849
|
+
projection,
|
|
3850
|
+
zoomLevel: transform.k,
|
|
3851
|
+
pixelRatio: this.pixelRatio,
|
|
3852
|
+
padding: this.padding,
|
|
3853
|
+
viewPortSize: this.viewPortSize,
|
|
3854
|
+
sizeInPixels: scaleSize(this.viewPortSize, this.pixelRatio),
|
|
3855
|
+
visibleExtent: this.getVisibleExtent(transform, projection)
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3596
3859
|
function arrayEquals(arr1, arr2) {
|
|
3597
3860
|
const len1 = arr1.length;
|
|
3598
3861
|
if (len1 !== arr2.length) {
|
|
@@ -4085,11 +4348,11 @@
|
|
|
4085
4348
|
this.map = map;
|
|
4086
4349
|
this._element = document.createElement("div");
|
|
4087
4350
|
this._element.className = "gv-layer-container";
|
|
4088
|
-
const
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4351
|
+
const style2 = this._element.style;
|
|
4352
|
+
style2.position = "absolute";
|
|
4353
|
+
style2.width = "100%";
|
|
4354
|
+
style2.height = "100%";
|
|
4355
|
+
style2.zIndex = "0";
|
|
4093
4356
|
const container2 = map.viewPort;
|
|
4094
4357
|
container2.insertBefore(this._element, container2.firstChild || null);
|
|
4095
4358
|
}
|
|
@@ -5472,18 +5735,19 @@
|
|
|
5472
5735
|
d3Selection.selection.prototype.interrupt = selection_interrupt;
|
|
5473
5736
|
d3Selection.selection.prototype.transition = selection_transition;
|
|
5474
5737
|
let Map$2 = class Map {
|
|
5475
|
-
constructor(
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5738
|
+
constructor(config) {
|
|
5739
|
+
if (config.debug) {
|
|
5740
|
+
console.log("Map config", config);
|
|
5741
|
+
}
|
|
5742
|
+
this.options = config;
|
|
5743
|
+
this.view = new View(config.view, config.debug);
|
|
5744
|
+
this.target = config.target;
|
|
5479
5745
|
this.layers = [];
|
|
5480
5746
|
this.dispatcher = new Dispatcher(this);
|
|
5481
5747
|
this._viewport = document.createElement("div");
|
|
5482
5748
|
this._viewport.className = "gv-map";
|
|
5483
5749
|
this._viewport.style.position = "relative";
|
|
5484
5750
|
this._viewport.style.overflow = "hidden";
|
|
5485
|
-
this._viewport.style.top = 0;
|
|
5486
|
-
this._viewport.style.left = 0;
|
|
5487
5751
|
this._viewport.style.width = "100%";
|
|
5488
5752
|
this._viewport.style.height = "100%";
|
|
5489
5753
|
this.target.appendChild(this._viewport);
|
|
@@ -5493,7 +5757,7 @@
|
|
|
5493
5757
|
});
|
|
5494
5758
|
this._resizeObserver.observe(this.target);
|
|
5495
5759
|
this._viewport.addEventListener("touchmove", (event) => {
|
|
5496
|
-
if (event.targetTouches.length < 2 && this.
|
|
5760
|
+
if (event.targetTouches.length < 2 && this._collaborativeGesturesEnabled) {
|
|
5497
5761
|
this._filterEventCallback(true);
|
|
5498
5762
|
}
|
|
5499
5763
|
});
|
|
@@ -5516,6 +5780,10 @@
|
|
|
5516
5780
|
return this._isTransitioning;
|
|
5517
5781
|
}
|
|
5518
5782
|
/** PUBLIC METHODS */
|
|
5783
|
+
collaborativeGesturesEnabled(enabled) {
|
|
5784
|
+
if (enabled === void 0) return this._collaborativeGesturesEnabled;
|
|
5785
|
+
this._collaborativeGesturesEnabled = enabled;
|
|
5786
|
+
}
|
|
5519
5787
|
onFilterEvent(callback) {
|
|
5520
5788
|
this._filterEventCallback = callback;
|
|
5521
5789
|
}
|
|
@@ -5591,6 +5859,18 @@
|
|
|
5591
5859
|
);
|
|
5592
5860
|
d3Selection.select(this._viewport).transition().duration(500).call(this._zoomBehaviour.transform, newTransform, focalPoint);
|
|
5593
5861
|
}
|
|
5862
|
+
/** @param {import("./layers").Layer[]} layers */
|
|
5863
|
+
hasLayers(layers) {
|
|
5864
|
+
if (layers.length !== this.layers.length) {
|
|
5865
|
+
return false;
|
|
5866
|
+
}
|
|
5867
|
+
for (let i = 0; i < layers.length; i++) {
|
|
5868
|
+
if (layers[i] !== this.layers[i]) {
|
|
5869
|
+
return false;
|
|
5870
|
+
}
|
|
5871
|
+
}
|
|
5872
|
+
return true;
|
|
5873
|
+
}
|
|
5594
5874
|
async resetZoom(options) {
|
|
5595
5875
|
return this.zoomTo(1, options);
|
|
5596
5876
|
}
|
|
@@ -5687,201 +5967,13 @@
|
|
|
5687
5967
|
_renderFrame() {
|
|
5688
5968
|
const frameState = {
|
|
5689
5969
|
size: this.size,
|
|
5690
|
-
viewState: this.view.getState()
|
|
5970
|
+
viewState: this.view.getState(),
|
|
5971
|
+
debug: this.options.debug || false
|
|
5691
5972
|
};
|
|
5692
5973
|
this._renderer.renderFrame(frameState);
|
|
5693
5974
|
this._animationFrameRequestID = null;
|
|
5694
5975
|
}
|
|
5695
5976
|
};
|
|
5696
|
-
function bboxFeature(bounds) {
|
|
5697
|
-
const minLon = bounds[0][0];
|
|
5698
|
-
const minLat = bounds[0][1];
|
|
5699
|
-
const maxLon = bounds[1][0];
|
|
5700
|
-
const maxLat = bounds[1][1];
|
|
5701
|
-
const feature = {
|
|
5702
|
-
type: "Feature",
|
|
5703
|
-
properties: {},
|
|
5704
|
-
geometry: {
|
|
5705
|
-
coordinates: [
|
|
5706
|
-
[
|
|
5707
|
-
[minLon, maxLat],
|
|
5708
|
-
[maxLon, maxLat],
|
|
5709
|
-
[maxLon, minLat],
|
|
5710
|
-
[minLon, minLat],
|
|
5711
|
-
[minLon, maxLat]
|
|
5712
|
-
]
|
|
5713
|
-
],
|
|
5714
|
-
type: "Polygon"
|
|
5715
|
-
}
|
|
5716
|
-
};
|
|
5717
|
-
return feature;
|
|
5718
|
-
}
|
|
5719
|
-
const BASE_RESOLUTION = 156543.03392;
|
|
5720
|
-
function zoomLevelToZoomScale(zoomLevel, initialResolution) {
|
|
5721
|
-
const resolution = BASE_RESOLUTION / Math.pow(2, zoomLevel);
|
|
5722
|
-
const zoomScale = initialResolution / resolution;
|
|
5723
|
-
return zoomScale;
|
|
5724
|
-
}
|
|
5725
|
-
function zoomLevelForResolution(currentResolution) {
|
|
5726
|
-
const zoomLevel = Math.log2(BASE_RESOLUTION / currentResolution);
|
|
5727
|
-
return zoomLevel;
|
|
5728
|
-
}
|
|
5729
|
-
function haversineDistance(lat1, lon1, lat2, lon2) {
|
|
5730
|
-
const R2 = 6371e3;
|
|
5731
|
-
const toRadians = (degrees2) => degrees2 * Math.PI / 180;
|
|
5732
|
-
const dLat = toRadians(lat2 - lat1);
|
|
5733
|
-
const dLon = toRadians(lon2 - lon1);
|
|
5734
|
-
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
5735
|
-
const c2 = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
5736
|
-
return R2 * c2;
|
|
5737
|
-
}
|
|
5738
|
-
function resolutionForExtent(extent, viewportSize) {
|
|
5739
|
-
const [lonMin, latMin, lonMax, latMax] = extent;
|
|
5740
|
-
const latMid = (latMin + latMax) / 2;
|
|
5741
|
-
const distance = haversineDistance(latMid, lonMin, latMid, lonMax);
|
|
5742
|
-
const resolution = distance / viewportSize[0];
|
|
5743
|
-
return resolution;
|
|
5744
|
-
}
|
|
5745
|
-
class View {
|
|
5746
|
-
constructor({ projection, extent, minZoom, maxZoom, padding }) {
|
|
5747
|
-
projection.revision = 0;
|
|
5748
|
-
this.projection = projection;
|
|
5749
|
-
this.extent = extent;
|
|
5750
|
-
this.minZoom = minZoom;
|
|
5751
|
-
this.maxZoom = maxZoom;
|
|
5752
|
-
this._transform = d3Zoom.zoomIdentity;
|
|
5753
|
-
this._padding = padding;
|
|
5754
|
-
this._viewPortSize = [0, 0];
|
|
5755
|
-
this.pixelRatio = window.devicePixelRatio;
|
|
5756
|
-
}
|
|
5757
|
-
set viewPortSize(size) {
|
|
5758
|
-
const previousSize = this._viewPortSize;
|
|
5759
|
-
this._viewPortSize = size;
|
|
5760
|
-
if (previousSize !== size) {
|
|
5761
|
-
this.fitObject(bboxFeature(this.extent));
|
|
5762
|
-
const initialExtent = this.getVisibleExtent(d3Zoom.zoomIdentity, this.projection);
|
|
5763
|
-
this.initialResolution = resolutionForExtent(initialExtent, size);
|
|
5764
|
-
}
|
|
5765
|
-
}
|
|
5766
|
-
get viewPortSize() {
|
|
5767
|
-
return this._viewPortSize;
|
|
5768
|
-
}
|
|
5769
|
-
set transform(transform) {
|
|
5770
|
-
this._transform = transform;
|
|
5771
|
-
}
|
|
5772
|
-
get transform() {
|
|
5773
|
-
return new d3Zoom.ZoomTransform(
|
|
5774
|
-
this._transform.k,
|
|
5775
|
-
this._transform.x * this.pixelRatio,
|
|
5776
|
-
this._transform.y * this.pixelRatio
|
|
5777
|
-
);
|
|
5778
|
-
}
|
|
5779
|
-
// map size in pixels (i.e. scaled by device pixel ratio)
|
|
5780
|
-
get mapSize() {
|
|
5781
|
-
return scaleSize(this.viewPortSize, this.pixelRatio);
|
|
5782
|
-
}
|
|
5783
|
-
get padding() {
|
|
5784
|
-
return this._padding;
|
|
5785
|
-
}
|
|
5786
|
-
// padding in pixels (i.e. scaled by device pixel ratio)
|
|
5787
|
-
get scaledPadding() {
|
|
5788
|
-
const scaledPadding = { ...this._padding };
|
|
5789
|
-
return scalePadding(scaledPadding, this.pixelRatio);
|
|
5790
|
-
}
|
|
5791
|
-
// calculates the upper and lower zoom scales
|
|
5792
|
-
get scaleExtent() {
|
|
5793
|
-
const maxScale = zoomLevelToZoomScale(this.maxZoom, this.initialResolution);
|
|
5794
|
-
return [1, maxScale];
|
|
5795
|
-
}
|
|
5796
|
-
setProjection(projection) {
|
|
5797
|
-
this.projection = projection;
|
|
5798
|
-
this.fitObject(bboxFeature(this.extent));
|
|
5799
|
-
}
|
|
5800
|
-
// only set the raw projection when it has already been configured with projection.fitExtent()
|
|
5801
|
-
setRawProjection(projection) {
|
|
5802
|
-
this.projection = projection;
|
|
5803
|
-
}
|
|
5804
|
-
fitObject(geoJSON) {
|
|
5805
|
-
this.projection.fitExtent(this.getMapExtent(), geoJSON);
|
|
5806
|
-
++this.projection.revision;
|
|
5807
|
-
}
|
|
5808
|
-
// returns bounds relative to the viewport
|
|
5809
|
-
boundsForExtent(extent) {
|
|
5810
|
-
const SW = this.projection([extent[0], extent[1]]);
|
|
5811
|
-
const NE = this.projection([extent[2], extent[3]]);
|
|
5812
|
-
const minX = SW[0] / this.pixelRatio;
|
|
5813
|
-
const minY = NE[1] / this.pixelRatio;
|
|
5814
|
-
const maxX = NE[0] / this.pixelRatio;
|
|
5815
|
-
const maxY = SW[1] / this.pixelRatio;
|
|
5816
|
-
const width = maxX - minX;
|
|
5817
|
-
const height = maxY - minY;
|
|
5818
|
-
return [
|
|
5819
|
-
[minX, minY],
|
|
5820
|
-
[width, height]
|
|
5821
|
-
];
|
|
5822
|
-
}
|
|
5823
|
-
invert(point) {
|
|
5824
|
-
const { projection, pixelRatio, transform } = this.getState();
|
|
5825
|
-
const scaledPoint = [point[0] * pixelRatio, point[1] * pixelRatio];
|
|
5826
|
-
const untransformedPoint = transform.invert(scaledPoint);
|
|
5827
|
-
const mapCoordinate = projection.invert(untransformedPoint);
|
|
5828
|
-
return mapCoordinate;
|
|
5829
|
-
}
|
|
5830
|
-
// bounds is defined as [[minX, minY], [maxX, maxY]]
|
|
5831
|
-
invertBounds(bounds) {
|
|
5832
|
-
const topLeft = bounds[0];
|
|
5833
|
-
const topRight = [bounds[1][0], bounds[0][1]];
|
|
5834
|
-
const bottomRight = [bounds[1][0], bounds[1][1]];
|
|
5835
|
-
const bottomLeft = [bounds[0][0], bounds[1][1]];
|
|
5836
|
-
const points = [topLeft, topRight, bottomRight, bottomLeft, topLeft];
|
|
5837
|
-
return points.map((d2) => this.invert(d2));
|
|
5838
|
-
}
|
|
5839
|
-
// map resolution (meters per pixel)
|
|
5840
|
-
getResolution() {
|
|
5841
|
-
return resolutionForExtent(
|
|
5842
|
-
this.getVisibleExtent(this.transform, this.projection),
|
|
5843
|
-
this.viewPortSize
|
|
5844
|
-
);
|
|
5845
|
-
}
|
|
5846
|
-
// map zoom level (0 = the entire world)
|
|
5847
|
-
getZoomLevel() {
|
|
5848
|
-
return zoomLevelForResolution(this.getResolution());
|
|
5849
|
-
}
|
|
5850
|
-
// get extent for drawn map
|
|
5851
|
-
getMapExtent() {
|
|
5852
|
-
const mapSizeInPixels = this.mapSize;
|
|
5853
|
-
const paddingInPixels = this.scaledPadding;
|
|
5854
|
-
return [
|
|
5855
|
-
[paddingInPixels.left, paddingInPixels.top],
|
|
5856
|
-
sizeMinusPadding(mapSizeInPixels, {
|
|
5857
|
-
...paddingInPixels,
|
|
5858
|
-
left: 0,
|
|
5859
|
-
top: 0
|
|
5860
|
-
})
|
|
5861
|
-
];
|
|
5862
|
-
}
|
|
5863
|
-
// visible extent in map coordinates
|
|
5864
|
-
getVisibleExtent(transform, projection) {
|
|
5865
|
-
const [width, height] = this.mapSize;
|
|
5866
|
-
const southWest = projection.invert(transform.invert([0, height]));
|
|
5867
|
-
const northEast = projection.invert(transform.invert([width, 0]));
|
|
5868
|
-
return [southWest[0], southWest[1], northEast[0], northEast[1]];
|
|
5869
|
-
}
|
|
5870
|
-
getState() {
|
|
5871
|
-
const transform = this.transform;
|
|
5872
|
-
const projection = this.projection;
|
|
5873
|
-
return {
|
|
5874
|
-
transform,
|
|
5875
|
-
projection,
|
|
5876
|
-
zoomLevel: transform.k,
|
|
5877
|
-
pixelRatio: this.pixelRatio,
|
|
5878
|
-
padding: this.padding,
|
|
5879
|
-
viewPortSize: this.viewPortSize,
|
|
5880
|
-
sizeInPixels: scaleSize(this.viewPortSize, this.pixelRatio),
|
|
5881
|
-
visibleExtent: this.getVisibleExtent(transform, projection)
|
|
5882
|
-
};
|
|
5883
|
-
}
|
|
5884
|
-
}
|
|
5885
5977
|
const mapContainer = "_mapContainer_1ogf3_9";
|
|
5886
5978
|
const helpTextContainer = "_helpTextContainer_1ogf3_15";
|
|
5887
5979
|
const helpText = "_helpText_1ogf3_15";
|
|
@@ -5894,18 +5986,33 @@
|
|
|
5894
5986
|
desktopHelpText,
|
|
5895
5987
|
mobileHelpText: mobileHelpText$1
|
|
5896
5988
|
};
|
|
5989
|
+
const MapContext = preact.createContext(null);
|
|
5990
|
+
function MapProvider({ map, children }) {
|
|
5991
|
+
const registeredLayers = [];
|
|
5992
|
+
const registerLayer = (layer) => {
|
|
5993
|
+
registeredLayers.push(layer);
|
|
5994
|
+
};
|
|
5995
|
+
hooks.useEffect(() => {
|
|
5996
|
+
if (map && !map.hasLayers(registeredLayers)) {
|
|
5997
|
+
map.setLayers(registeredLayers);
|
|
5998
|
+
}
|
|
5999
|
+
}, [map, children]);
|
|
6000
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MapContext.Provider, { value: { registerLayer }, children });
|
|
6001
|
+
}
|
|
5897
6002
|
const mobileHelpText = "Use two fingers to zoom";
|
|
5898
6003
|
const Map$1 = compat.forwardRef(
|
|
5899
6004
|
({ config, inModalState = false, onLoad, children }, ref) => {
|
|
5900
|
-
const { layers } = children;
|
|
5901
6005
|
const targetRef = hooks.useRef();
|
|
5902
|
-
const [map, setMap] = hooks.useState(
|
|
6006
|
+
const [map, setMap] = hooks.useState(
|
|
6007
|
+
/** @type {_Map | null} */
|
|
6008
|
+
null
|
|
6009
|
+
);
|
|
5903
6010
|
const [zoomHelpText, setZoomHelpText] = hooks.useState("");
|
|
5904
6011
|
const [showHelpText, setShowHelpText] = hooks.useState(false);
|
|
5905
6012
|
hooks.useEffect(() => {
|
|
5906
6013
|
var _a;
|
|
5907
6014
|
const map2 = new Map$2({
|
|
5908
|
-
|
|
6015
|
+
...config,
|
|
5909
6016
|
target: targetRef.current
|
|
5910
6017
|
});
|
|
5911
6018
|
map2.collaborativeGesturesEnabled = true;
|
|
@@ -5921,7 +6028,7 @@
|
|
|
5921
6028
|
map2.destroy();
|
|
5922
6029
|
setMap(null);
|
|
5923
6030
|
};
|
|
5924
|
-
}, [config
|
|
6031
|
+
}, [config]);
|
|
5925
6032
|
hooks.useEffect(() => {
|
|
5926
6033
|
if (!map) return;
|
|
5927
6034
|
let timeoutID;
|
|
@@ -5951,27 +6058,25 @@
|
|
|
5951
6058
|
}
|
|
5952
6059
|
};
|
|
5953
6060
|
}, [map, ref, onLoad]);
|
|
5954
|
-
hooks.useEffect(() => {
|
|
5955
|
-
if (map && layers !== map.layers) {
|
|
5956
|
-
map.setLayers(layers);
|
|
5957
|
-
}
|
|
5958
|
-
}, [map, layers]);
|
|
5959
6061
|
hooks.useEffect(() => {
|
|
5960
6062
|
if (!map) return;
|
|
5961
6063
|
map.collaborativeGesturesEnabled = !inModalState;
|
|
5962
6064
|
}, [map, inModalState]);
|
|
5963
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
6065
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref: targetRef, className: styles$3.mapContainer, children: [
|
|
6066
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6067
|
+
"div",
|
|
6068
|
+
{
|
|
6069
|
+
className: styles$3.helpTextContainer,
|
|
6070
|
+
style: { opacity: showHelpText ? 1 : 0 },
|
|
6071
|
+
"aria-hidden": true,
|
|
6072
|
+
children: [
|
|
6073
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: [styles$3.helpText, styles$3.desktopHelpText].join(" "), children: zoomHelpText }),
|
|
6074
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: [styles$3.helpText, styles$3.mobileHelpText].join(" "), children: mobileHelpText })
|
|
6075
|
+
]
|
|
6076
|
+
}
|
|
6077
|
+
),
|
|
6078
|
+
/* @__PURE__ */ jsxRuntime.jsx(MapProvider, { map, children })
|
|
6079
|
+
] });
|
|
5975
6080
|
}
|
|
5976
6081
|
);
|
|
5977
6082
|
function IconMinus() {
|
|
@@ -6075,17 +6180,12 @@
|
|
|
6075
6180
|
)
|
|
6076
6181
|
] });
|
|
6077
6182
|
}
|
|
6078
|
-
const Projection = {
|
|
6079
|
-
geoAlbersUKComposite: geoAlbersUk(),
|
|
6080
|
-
geoAlbersEngland: d3Geo.geoAlbers().center([0, 52.7]).rotate([1.1743, 0]).parallels([50, 54]),
|
|
6081
|
-
geoMercator: d3Geo.geoMercator()
|
|
6082
|
-
};
|
|
6083
6183
|
class FeatureRenderer {
|
|
6084
6184
|
constructor() {
|
|
6085
6185
|
this.drawingFunction = d3Geo.geoPath();
|
|
6086
6186
|
}
|
|
6087
|
-
setStyle(
|
|
6088
|
-
this.style =
|
|
6187
|
+
setStyle(style2) {
|
|
6188
|
+
this.style = style2;
|
|
6089
6189
|
}
|
|
6090
6190
|
render(frameState, feature, context) {
|
|
6091
6191
|
if (!this.style) {
|
|
@@ -6096,6 +6196,17 @@
|
|
|
6096
6196
|
this.drawingFunction.context(context);
|
|
6097
6197
|
context.beginPath();
|
|
6098
6198
|
const geometries = feature.getProjectedGeometries(projection);
|
|
6199
|
+
if (frameState.debug) {
|
|
6200
|
+
try {
|
|
6201
|
+
validateGeometries(geometries);
|
|
6202
|
+
} catch {
|
|
6203
|
+
console.error(
|
|
6204
|
+
`Invalid geometry. Feature skipped during rendering. Click here to inspect geometry: ${generateDebugUrl(feature)}
|
|
6205
|
+
`,
|
|
6206
|
+
feature
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6099
6210
|
for (const geometry of geometries) {
|
|
6100
6211
|
this.drawingFunction(geometry);
|
|
6101
6212
|
}
|
|
@@ -6122,12 +6233,12 @@
|
|
|
6122
6233
|
this.featureRenderer = new FeatureRenderer();
|
|
6123
6234
|
this._element = document.createElement("div");
|
|
6124
6235
|
this._element.className = "gv-text-layer";
|
|
6125
|
-
const
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6236
|
+
const style2 = this._element.style;
|
|
6237
|
+
style2.position = "absolute";
|
|
6238
|
+
style2.width = "100%";
|
|
6239
|
+
style2.height = "100%";
|
|
6240
|
+
style2.pointerEvents = "none";
|
|
6241
|
+
style2.overflow = "hidden";
|
|
6131
6242
|
}
|
|
6132
6243
|
renderFrame(frameState, targetElement) {
|
|
6133
6244
|
if (this.layer.opacity === 0) return targetElement;
|
|
@@ -6182,20 +6293,20 @@
|
|
|
6182
6293
|
return textElement;
|
|
6183
6294
|
}
|
|
6184
6295
|
styleTextElement(element, textStyle, position) {
|
|
6185
|
-
const
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6296
|
+
const style2 = element.style;
|
|
6297
|
+
style2.position = "absolute";
|
|
6298
|
+
style2.transform = `translate(-50%, -50%)`;
|
|
6299
|
+
style2.left = position.left;
|
|
6300
|
+
style2.top = position.top;
|
|
6301
|
+
style2.textAlign = "center";
|
|
6302
|
+
style2.whiteSpace = "nowrap";
|
|
6303
|
+
style2.fontFamily = textStyle.fontFamily;
|
|
6304
|
+
style2.fontSize = textStyle.fontSize;
|
|
6305
|
+
style2.fontWeight = textStyle.fontWeight;
|
|
6306
|
+
style2.lineHeight = textStyle.lineHeight;
|
|
6307
|
+
style2.color = textStyle.color;
|
|
6308
|
+
style2.textShadow = textStyle.textShadow;
|
|
6309
|
+
style2.padding = `${textPadding.top}px ${textPadding.right}px ${textPadding.bottom}px ${textPadding.left}px`;
|
|
6199
6310
|
}
|
|
6200
6311
|
getElementBBox(element, position) {
|
|
6201
6312
|
if (!element.parentElement) {
|
|
@@ -6214,21 +6325,21 @@
|
|
|
6214
6325
|
}
|
|
6215
6326
|
getCollisionBoxElement(bbox) {
|
|
6216
6327
|
const element = document.createElement("div");
|
|
6217
|
-
const
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6328
|
+
const style2 = element.style;
|
|
6329
|
+
style2.position = "absolute";
|
|
6330
|
+
style2.left = `${bbox.minX}px`;
|
|
6331
|
+
style2.top = `${bbox.minY}px`;
|
|
6332
|
+
style2.width = `${bbox.maxX - bbox.minX}px`;
|
|
6333
|
+
style2.height = `${bbox.maxY - bbox.minY}px`;
|
|
6334
|
+
style2.border = "2px solid black";
|
|
6224
6335
|
return element;
|
|
6225
6336
|
}
|
|
6226
6337
|
}
|
|
6227
6338
|
class Style {
|
|
6228
|
-
constructor(
|
|
6229
|
-
this.stroke =
|
|
6230
|
-
this.fill =
|
|
6231
|
-
this.text =
|
|
6339
|
+
constructor(properties) {
|
|
6340
|
+
this.stroke = properties == null ? void 0 : properties.stroke;
|
|
6341
|
+
this.fill = properties == null ? void 0 : properties.fill;
|
|
6342
|
+
this.text = properties == null ? void 0 : properties.text;
|
|
6232
6343
|
}
|
|
6233
6344
|
clone() {
|
|
6234
6345
|
return new Style({
|
|
@@ -6458,20 +6569,60 @@
|
|
|
6458
6569
|
}
|
|
6459
6570
|
}
|
|
6460
6571
|
class TextLayer {
|
|
6572
|
+
/** @param {TextLayerComponentProps} props */
|
|
6573
|
+
static Component({
|
|
6574
|
+
features,
|
|
6575
|
+
style: style2,
|
|
6576
|
+
minZoom,
|
|
6577
|
+
opacity,
|
|
6578
|
+
declutter,
|
|
6579
|
+
drawCollisionBoxes
|
|
6580
|
+
}) {
|
|
6581
|
+
const { registerLayer } = hooks.useContext(MapContext);
|
|
6582
|
+
const layer = hooks.useMemo(
|
|
6583
|
+
() => TextLayer.with(features, {
|
|
6584
|
+
style: style2,
|
|
6585
|
+
minZoom,
|
|
6586
|
+
opacity,
|
|
6587
|
+
declutter,
|
|
6588
|
+
drawCollisionBoxes
|
|
6589
|
+
}),
|
|
6590
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6591
|
+
[features, minZoom, opacity, declutter, drawCollisionBoxes]
|
|
6592
|
+
);
|
|
6593
|
+
registerLayer(layer);
|
|
6594
|
+
hooks.useEffect(() => {
|
|
6595
|
+
layer.style = style2;
|
|
6596
|
+
}, [style2]);
|
|
6597
|
+
return null;
|
|
6598
|
+
}
|
|
6599
|
+
/**
|
|
6600
|
+
* @param {import("../Feature").Feature[]} features
|
|
6601
|
+
* @param {TextLayerOptions} options
|
|
6602
|
+
*/
|
|
6461
6603
|
static with(features, options) {
|
|
6462
6604
|
const source = new VectorSource({ features });
|
|
6463
6605
|
return new TextLayer({ source, ...options });
|
|
6464
6606
|
}
|
|
6607
|
+
/**
|
|
6608
|
+
* @param {Object} params
|
|
6609
|
+
* @param {VectorSource} params.source
|
|
6610
|
+
* @param {Style} [params.style=undefined]
|
|
6611
|
+
* @param {number} [params.minZoom=0]
|
|
6612
|
+
* @param {number} [params.opacity=1]
|
|
6613
|
+
* @param {boolean} [params.declutter=true]
|
|
6614
|
+
* @param {boolean} [params.drawCollisionBoxes=false]
|
|
6615
|
+
*/
|
|
6465
6616
|
constructor({
|
|
6466
6617
|
source,
|
|
6467
|
-
style,
|
|
6618
|
+
style: style2,
|
|
6468
6619
|
minZoom = 0,
|
|
6469
6620
|
opacity = 1,
|
|
6470
6621
|
declutter = true,
|
|
6471
6622
|
drawCollisionBoxes = false
|
|
6472
6623
|
}) {
|
|
6473
6624
|
this.source = source;
|
|
6474
|
-
this._style =
|
|
6625
|
+
this._style = style2;
|
|
6475
6626
|
this.minZoom = minZoom;
|
|
6476
6627
|
this.opacity = opacity;
|
|
6477
6628
|
this.declutter = declutter;
|
|
@@ -6489,8 +6640,8 @@
|
|
|
6489
6640
|
});
|
|
6490
6641
|
return defaultStyle;
|
|
6491
6642
|
}
|
|
6492
|
-
set style(
|
|
6493
|
-
this._style =
|
|
6643
|
+
set style(style2) {
|
|
6644
|
+
this._style = style2;
|
|
6494
6645
|
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
6495
6646
|
}
|
|
6496
6647
|
getExtent() {
|
|
@@ -6505,10 +6656,10 @@
|
|
|
6505
6656
|
return extent;
|
|
6506
6657
|
}
|
|
6507
6658
|
getStyleFunction() {
|
|
6508
|
-
const
|
|
6509
|
-
if (typeof
|
|
6659
|
+
const style2 = this.style;
|
|
6660
|
+
if (typeof style2 === "function") return style2;
|
|
6510
6661
|
return () => {
|
|
6511
|
-
return
|
|
6662
|
+
return style2;
|
|
6512
6663
|
};
|
|
6513
6664
|
}
|
|
6514
6665
|
renderFrame(frameState, targetElement) {
|
|
@@ -6576,27 +6727,58 @@
|
|
|
6576
6727
|
createContainer() {
|
|
6577
6728
|
const container2 = document.createElement("div");
|
|
6578
6729
|
container2.className = "gv-map-layer";
|
|
6579
|
-
let
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6730
|
+
let style2 = container2.style;
|
|
6731
|
+
style2.position = "absolute";
|
|
6732
|
+
style2.width = "100%";
|
|
6733
|
+
style2.height = "100%";
|
|
6583
6734
|
const canvas = document.createElement("canvas");
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6735
|
+
style2 = canvas.style;
|
|
6736
|
+
style2.position = "absolute";
|
|
6737
|
+
style2.width = "100%";
|
|
6738
|
+
style2.height = "100%";
|
|
6588
6739
|
container2.appendChild(canvas);
|
|
6589
6740
|
return container2;
|
|
6590
6741
|
}
|
|
6591
6742
|
}
|
|
6592
6743
|
class VectorLayer {
|
|
6744
|
+
/** @param {VectorLayerComponentProps} props */
|
|
6745
|
+
static Component({ features, style: style2, minZoom, opacity, hitDetectionEnabled }) {
|
|
6746
|
+
const { registerLayer } = hooks.useContext(MapContext);
|
|
6747
|
+
const layer = hooks.useMemo(
|
|
6748
|
+
() => VectorLayer.with(features, {
|
|
6749
|
+
style: style2,
|
|
6750
|
+
minZoom,
|
|
6751
|
+
opacity,
|
|
6752
|
+
hitDetectionEnabled
|
|
6753
|
+
}),
|
|
6754
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6755
|
+
[features, minZoom, opacity, hitDetectionEnabled]
|
|
6756
|
+
);
|
|
6757
|
+
registerLayer(layer);
|
|
6758
|
+
hooks.useEffect(() => {
|
|
6759
|
+
layer.style = style2;
|
|
6760
|
+
}, [style2]);
|
|
6761
|
+
return null;
|
|
6762
|
+
}
|
|
6763
|
+
/**
|
|
6764
|
+
* @param {import("../Feature").Feature[]} features
|
|
6765
|
+
* @param {VectorLayerOptions} options
|
|
6766
|
+
*/
|
|
6593
6767
|
static with(features, options) {
|
|
6594
6768
|
const source = new VectorSource({ features });
|
|
6595
6769
|
return new VectorLayer({ source, ...options });
|
|
6596
6770
|
}
|
|
6771
|
+
/**
|
|
6772
|
+
* @param {Object} params
|
|
6773
|
+
* @param {VectorSource} params.source
|
|
6774
|
+
* @param {Style | (() => Style)} [params.style=undefined]
|
|
6775
|
+
* @param {number} [params.minZoom=0]
|
|
6776
|
+
* @param {number} [params.opacity=1]
|
|
6777
|
+
* @param {boolean} [params.hitDetectionEnabled=false]
|
|
6778
|
+
*/
|
|
6597
6779
|
constructor({
|
|
6598
6780
|
source,
|
|
6599
|
-
style,
|
|
6781
|
+
style: style2,
|
|
6600
6782
|
minZoom = 0,
|
|
6601
6783
|
opacity = 1,
|
|
6602
6784
|
hitDetectionEnabled = true
|
|
@@ -6604,7 +6786,7 @@
|
|
|
6604
6786
|
this.dispatcher = new Dispatcher(this);
|
|
6605
6787
|
this.renderer = new VectorLayerRenderer(this);
|
|
6606
6788
|
this.source = source;
|
|
6607
|
-
this._style =
|
|
6789
|
+
this._style = style2;
|
|
6608
6790
|
this.minZoom = minZoom;
|
|
6609
6791
|
this.opacity = opacity;
|
|
6610
6792
|
this.hitDetectionEnabled = hitDetectionEnabled;
|
|
@@ -6635,15 +6817,15 @@
|
|
|
6635
6817
|
});
|
|
6636
6818
|
return defaultStyle;
|
|
6637
6819
|
}
|
|
6638
|
-
set style(
|
|
6639
|
-
this._style =
|
|
6820
|
+
set style(style2) {
|
|
6821
|
+
this._style = style2;
|
|
6640
6822
|
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
6641
6823
|
}
|
|
6642
6824
|
getStyleFunction() {
|
|
6643
|
-
const
|
|
6644
|
-
if (typeof
|
|
6825
|
+
const style2 = this.style;
|
|
6826
|
+
if (typeof style2 === "function") return style2;
|
|
6645
6827
|
return () => {
|
|
6646
|
-
return
|
|
6828
|
+
return style2;
|
|
6647
6829
|
};
|
|
6648
6830
|
}
|
|
6649
6831
|
getExtent() {
|
|
@@ -6751,7 +6933,7 @@
|
|
|
6751
6933
|
break;
|
|
6752
6934
|
}
|
|
6753
6935
|
}
|
|
6754
|
-
feature.
|
|
6936
|
+
feature.setGeometry(geometries);
|
|
6755
6937
|
features.push(feature);
|
|
6756
6938
|
}
|
|
6757
6939
|
return features;
|
|
@@ -6815,23 +6997,32 @@
|
|
|
6815
6997
|
};
|
|
6816
6998
|
}
|
|
6817
6999
|
class Feature {
|
|
6818
|
-
|
|
7000
|
+
/**
|
|
7001
|
+
* Represents a feature on the map
|
|
7002
|
+
* @constructor
|
|
7003
|
+
* @param {Object} props - The properties for the feature.
|
|
7004
|
+
* @property {string} id - The unique identifier of the feature
|
|
7005
|
+
* @property {Array} geometries - The geometries of the feature
|
|
7006
|
+
* @property {Object} properties - The properties of the feature
|
|
7007
|
+
* @property {import("./styles").Style | import("./styles").StyleFunction} style - The style of the feature
|
|
7008
|
+
*/
|
|
7009
|
+
constructor({ id: id2, geometries, properties, style: style2 }) {
|
|
6819
7010
|
this.id = id2;
|
|
6820
7011
|
this.geometries = geometries;
|
|
6821
7012
|
this.properties = properties;
|
|
6822
|
-
this.style =
|
|
7013
|
+
this.style = style2;
|
|
6823
7014
|
this.uid = createUid();
|
|
6824
7015
|
}
|
|
6825
7016
|
getExtent() {
|
|
6826
7017
|
if (this._extent) return this._extent;
|
|
6827
|
-
const extent = this.geometries.reduce((combinedExtent,
|
|
6828
|
-
if (!combinedExtent) return
|
|
6829
|
-
return combineExtents(
|
|
7018
|
+
const extent = this.geometries.reduce((combinedExtent, geometries) => {
|
|
7019
|
+
if (!combinedExtent) return geometries.extent;
|
|
7020
|
+
return combineExtents(geometries.extent, combinedExtent);
|
|
6830
7021
|
}, null);
|
|
6831
7022
|
this._extent = extent;
|
|
6832
7023
|
return extent;
|
|
6833
7024
|
}
|
|
6834
|
-
|
|
7025
|
+
setgeometries(geometries) {
|
|
6835
7026
|
this.geometries = geometries;
|
|
6836
7027
|
this._extent = void 0;
|
|
6837
7028
|
}
|
|
@@ -6841,19 +7032,19 @@
|
|
|
6841
7032
|
);
|
|
6842
7033
|
}
|
|
6843
7034
|
getStyleFunction() {
|
|
6844
|
-
const
|
|
6845
|
-
if (!
|
|
6846
|
-
if (typeof
|
|
7035
|
+
const style2 = this.style;
|
|
7036
|
+
if (!style2) return null;
|
|
7037
|
+
if (typeof style2 === "function") return style2;
|
|
6847
7038
|
return () => {
|
|
6848
|
-
return
|
|
7039
|
+
return style2;
|
|
6849
7040
|
};
|
|
6850
7041
|
}
|
|
6851
7042
|
containsCoordinate(coordinate) {
|
|
6852
7043
|
if (!containsCoordinate(this.getExtent(), coordinate)) {
|
|
6853
7044
|
return false;
|
|
6854
7045
|
}
|
|
6855
|
-
for (const
|
|
6856
|
-
if (d3Geo.geoContains(
|
|
7046
|
+
for (const geometries of this.geometries) {
|
|
7047
|
+
if (d3Geo.geoContains(geometries.getGeoJSON(), coordinate)) {
|
|
6857
7048
|
return true;
|
|
6858
7049
|
}
|
|
6859
7050
|
}
|
|
@@ -6867,14 +7058,83 @@
|
|
|
6867
7058
|
style: this.style
|
|
6868
7059
|
});
|
|
6869
7060
|
}
|
|
7061
|
+
/**
|
|
7062
|
+
* Returns the geometries as a GeoJSON object
|
|
7063
|
+
* @returns {Object} The GeoJSON representation of the geometries
|
|
7064
|
+
*/
|
|
7065
|
+
getGeoJSON() {
|
|
7066
|
+
const geometries = this.geometries.map((d2) => d2.getGeoJSON());
|
|
7067
|
+
if (geometries.length === 1) return geometries[0];
|
|
7068
|
+
return {
|
|
7069
|
+
type: "Feature",
|
|
7070
|
+
geometry: this._getGeometryGeoJSON(),
|
|
7071
|
+
properties: this.properties
|
|
7072
|
+
};
|
|
7073
|
+
}
|
|
7074
|
+
_getGeometryGeoJSON() {
|
|
7075
|
+
const geometries = this.geometries.map((d2) => d2.getGeoJSON());
|
|
7076
|
+
if (geometries.length === 0) throw new Error("Feature has no geometries");
|
|
7077
|
+
if (geometries.length === 1) return geometries[0];
|
|
7078
|
+
if (geometries[0].type === "Polygon") {
|
|
7079
|
+
return {
|
|
7080
|
+
type: "MultiPolygon",
|
|
7081
|
+
coordinates: geometries.map((d2) => d2.coordinates)
|
|
7082
|
+
};
|
|
7083
|
+
} else if (geometries[0].type === "LineString") {
|
|
7084
|
+
return {
|
|
7085
|
+
type: "MultiLineString",
|
|
7086
|
+
coordinates: geometries.map((d2) => d2.coordinates)
|
|
7087
|
+
};
|
|
7088
|
+
} else if (geometries[0].type === "Point") {
|
|
7089
|
+
return {
|
|
7090
|
+
type: "MultiPoint",
|
|
7091
|
+
coordinates: geometries.map((d2) => d2.coordinates)
|
|
7092
|
+
};
|
|
7093
|
+
}
|
|
7094
|
+
throw new Error("Could not determine geometry type");
|
|
7095
|
+
}
|
|
6870
7096
|
}
|
|
6871
|
-
class
|
|
6872
|
-
|
|
7097
|
+
class Geometry {
|
|
7098
|
+
/**
|
|
7099
|
+
* Represents vector geometry
|
|
7100
|
+
* @constructor
|
|
7101
|
+
* @param {Object} options
|
|
7102
|
+
* @param {string} options.type - The type of geometry (e.g., 'Point', 'LineString', 'Polygon')
|
|
7103
|
+
* @param {Array} options.extent - The extent of the geometry (e.g., [xmin, ymin, xmax, ymax])
|
|
7104
|
+
* @param {Array} options.coordinates - The coordinates of the geometry (e.g., [[x1, y1], [x2, y2], ...])
|
|
7105
|
+
*/
|
|
7106
|
+
constructor({ type, extent, coordinates }) {
|
|
6873
7107
|
this.type = type;
|
|
6874
7108
|
this.extent = extent;
|
|
6875
7109
|
this.coordinates = coordinates;
|
|
6876
7110
|
this.getProjected = memoise(this._getProjected).bind(this);
|
|
6877
7111
|
}
|
|
7112
|
+
/**
|
|
7113
|
+
* Returns the geometry as a GeoJSON object
|
|
7114
|
+
* @function
|
|
7115
|
+
* @param {import("../projection").Projection} projection - The projection to use for the geometry
|
|
7116
|
+
* @returns {Object} A GeoJSON representation of the projected geometry
|
|
7117
|
+
* @private
|
|
7118
|
+
*/
|
|
7119
|
+
// eslint-disable-next-line no-unused-vars
|
|
7120
|
+
_getProjected(projection) {
|
|
7121
|
+
throw new Error("Not implemented");
|
|
7122
|
+
}
|
|
7123
|
+
/**
|
|
7124
|
+
* Returns the geometry as a GeoJSON object
|
|
7125
|
+
* @returns {Object} The GeoJSON representation of the geometry
|
|
7126
|
+
*/
|
|
7127
|
+
getGeoJSON() {
|
|
7128
|
+
return {
|
|
7129
|
+
type: this.type,
|
|
7130
|
+
coordinates: this.coordinates
|
|
7131
|
+
};
|
|
7132
|
+
}
|
|
7133
|
+
}
|
|
7134
|
+
class LineString extends Geometry {
|
|
7135
|
+
constructor({ type = "LineString", extent, coordinates }) {
|
|
7136
|
+
super({ type, extent, coordinates });
|
|
7137
|
+
}
|
|
6878
7138
|
_getProjected(projection) {
|
|
6879
7139
|
const projected = [];
|
|
6880
7140
|
for (const point of this.coordinates) {
|
|
@@ -6886,23 +7146,26 @@
|
|
|
6886
7146
|
};
|
|
6887
7147
|
}
|
|
6888
7148
|
}
|
|
6889
|
-
class Polygon {
|
|
7149
|
+
class Polygon extends Geometry {
|
|
6890
7150
|
constructor({ type = "Polygon", extent, coordinates }) {
|
|
6891
|
-
|
|
6892
|
-
this.extent = extent;
|
|
6893
|
-
this.coordinates = coordinates;
|
|
6894
|
-
this.getProjected = memoise(this._getProjected).bind(this);
|
|
7151
|
+
super({ type, extent, coordinates });
|
|
6895
7152
|
}
|
|
6896
|
-
|
|
6897
|
-
_getProjected(projection, _revision) {
|
|
7153
|
+
_getProjected(projection) {
|
|
6898
7154
|
const projected = [];
|
|
6899
7155
|
const rings = this.coordinates;
|
|
6900
7156
|
for (const ring of rings) {
|
|
6901
7157
|
const projectedRing = [];
|
|
6902
7158
|
for (const point of ring) {
|
|
6903
|
-
|
|
7159
|
+
const projectedPoint = projection(point);
|
|
7160
|
+
if (projectedPoint) {
|
|
7161
|
+
projectedRing.push(projectedPoint);
|
|
7162
|
+
} else {
|
|
7163
|
+
break;
|
|
7164
|
+
}
|
|
7165
|
+
}
|
|
7166
|
+
if (projectedRing.length > 0) {
|
|
7167
|
+
projected.push(projectedRing);
|
|
6904
7168
|
}
|
|
6905
|
-
projected.push(projectedRing);
|
|
6906
7169
|
}
|
|
6907
7170
|
return {
|
|
6908
7171
|
type: this.type,
|
|
@@ -6918,12 +7181,6 @@
|
|
|
6918
7181
|
setCoordinates(coordinates) {
|
|
6919
7182
|
this.coordinates = coordinates;
|
|
6920
7183
|
}
|
|
6921
|
-
getGeoJSON() {
|
|
6922
|
-
return {
|
|
6923
|
-
type: this.type,
|
|
6924
|
-
coordinates: this.coordinates
|
|
6925
|
-
};
|
|
6926
|
-
}
|
|
6927
7184
|
clone() {
|
|
6928
7185
|
return new Polygon({
|
|
6929
7186
|
extent: this.extent,
|
|
@@ -6931,12 +7188,10 @@
|
|
|
6931
7188
|
});
|
|
6932
7189
|
}
|
|
6933
7190
|
}
|
|
6934
|
-
class Point {
|
|
7191
|
+
class Point extends Geometry {
|
|
6935
7192
|
constructor({ type = "Point", coordinates }) {
|
|
6936
|
-
|
|
7193
|
+
super({ type, extent: null, coordinates });
|
|
6937
7194
|
this.extent = [...coordinates, ...coordinates];
|
|
6938
|
-
this.coordinates = coordinates;
|
|
6939
|
-
this.getProjected = memoise(this._getProjected).bind(this);
|
|
6940
7195
|
}
|
|
6941
7196
|
_getProjected(projection) {
|
|
6942
7197
|
return {
|
|
@@ -7458,6 +7713,7 @@
|
|
|
7458
7713
|
}
|
|
7459
7714
|
exports2.AdSlot = AdSlot;
|
|
7460
7715
|
exports2.ArrowButton = ArrowButton;
|
|
7716
|
+
exports2.AspectRatioBox = AspectRatioBox;
|
|
7461
7717
|
exports2.Button = Button;
|
|
7462
7718
|
exports2.ChangeBar = ChangeBar;
|
|
7463
7719
|
exports2.Chevron = Chevron;
|