@page-speed/maps 0.1.8 → 0.2.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/dist/components/geo-map.cjs +161 -32
- package/dist/components/geo-map.cjs.map +1 -1
- package/dist/components/geo-map.d.cts +5 -1
- package/dist/components/geo-map.d.ts +5 -1
- package/dist/components/geo-map.js +162 -33
- package/dist/components/geo-map.js.map +1 -1
- package/dist/components/index.cjs +161 -32
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +162 -33
- package/dist/components/index.js.map +1 -1
- package/dist/index.cjs +93 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -539,6 +539,74 @@ function MapLibre({
|
|
|
539
539
|
}
|
|
540
540
|
);
|
|
541
541
|
}
|
|
542
|
+
var TILE_SIZE = 512;
|
|
543
|
+
function latToMercatorY(lat) {
|
|
544
|
+
const latRad = lat * Math.PI / 180;
|
|
545
|
+
const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
|
|
546
|
+
return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
|
|
547
|
+
}
|
|
548
|
+
function lngToMercatorX(lng) {
|
|
549
|
+
return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
|
|
550
|
+
}
|
|
551
|
+
function computeDefaultZoom(options) {
|
|
552
|
+
const {
|
|
553
|
+
coordinates,
|
|
554
|
+
mapWidth,
|
|
555
|
+
mapHeight,
|
|
556
|
+
padding = 50,
|
|
557
|
+
maxZoom = 18,
|
|
558
|
+
minZoom = 1
|
|
559
|
+
} = options;
|
|
560
|
+
if (coordinates.length === 0) return null;
|
|
561
|
+
if (coordinates.length === 1) return maxZoom;
|
|
562
|
+
if (mapWidth <= 0 || mapHeight <= 0) return null;
|
|
563
|
+
let minLat = Infinity;
|
|
564
|
+
let maxLat = -Infinity;
|
|
565
|
+
let minLng = Infinity;
|
|
566
|
+
let maxLng = -Infinity;
|
|
567
|
+
for (const coord of coordinates) {
|
|
568
|
+
if (coord.lat < minLat) minLat = coord.lat;
|
|
569
|
+
if (coord.lat > maxLat) maxLat = coord.lat;
|
|
570
|
+
if (coord.lng < minLng) minLng = coord.lng;
|
|
571
|
+
if (coord.lng > maxLng) maxLng = coord.lng;
|
|
572
|
+
}
|
|
573
|
+
const pixelXMin = lngToMercatorX(minLng);
|
|
574
|
+
const pixelXMax = lngToMercatorX(maxLng);
|
|
575
|
+
const pixelYMin = latToMercatorY(maxLat);
|
|
576
|
+
const pixelYMax = latToMercatorY(minLat);
|
|
577
|
+
const dx = Math.abs(pixelXMax - pixelXMin);
|
|
578
|
+
const dy = Math.abs(pixelYMax - pixelYMin);
|
|
579
|
+
const availableWidth = mapWidth - padding * 2;
|
|
580
|
+
const availableHeight = mapHeight - padding * 2;
|
|
581
|
+
if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
|
|
582
|
+
let zoom;
|
|
583
|
+
if (dx === 0 && dy === 0) {
|
|
584
|
+
return maxZoom;
|
|
585
|
+
} else if (dx === 0) {
|
|
586
|
+
zoom = Math.log2(availableHeight / dy);
|
|
587
|
+
} else if (dy === 0) {
|
|
588
|
+
zoom = Math.log2(availableWidth / dx);
|
|
589
|
+
} else {
|
|
590
|
+
const zoomX = Math.log2(availableWidth / dx);
|
|
591
|
+
const zoomY = Math.log2(availableHeight / dy);
|
|
592
|
+
zoom = Math.min(zoomX, zoomY);
|
|
593
|
+
}
|
|
594
|
+
return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
|
|
595
|
+
}
|
|
596
|
+
function useDefaultZoom(options) {
|
|
597
|
+
const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
|
|
598
|
+
return React3.useMemo(
|
|
599
|
+
() => computeDefaultZoom({
|
|
600
|
+
coordinates,
|
|
601
|
+
mapWidth,
|
|
602
|
+
mapHeight,
|
|
603
|
+
padding,
|
|
604
|
+
maxZoom,
|
|
605
|
+
minZoom
|
|
606
|
+
}),
|
|
607
|
+
[coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
|
|
608
|
+
);
|
|
609
|
+
}
|
|
542
610
|
var PANEL_POSITION_CLASS = {
|
|
543
611
|
"top-left": "left-4 top-4",
|
|
544
612
|
"top-right": "right-4 top-4",
|
|
@@ -783,9 +851,50 @@ function GeoMap({
|
|
|
783
851
|
clearSelectionOnMapClick = true,
|
|
784
852
|
mapChildren,
|
|
785
853
|
optixFlowConfig,
|
|
854
|
+
mapSize,
|
|
786
855
|
IconComponent = FallbackIcon,
|
|
787
856
|
ImgComponent = FallbackImg
|
|
788
857
|
}) {
|
|
858
|
+
const containerRef = React3__namespace.useRef(null);
|
|
859
|
+
const [containerDimensions, setContainerDimensions] = React3__namespace.useState({
|
|
860
|
+
width: 800,
|
|
861
|
+
// Default width
|
|
862
|
+
height: 520
|
|
863
|
+
// Default height
|
|
864
|
+
});
|
|
865
|
+
const [isMobile, setIsMobile] = React3__namespace.useState(false);
|
|
866
|
+
React3__namespace.useEffect(() => {
|
|
867
|
+
const checkMobile = () => {
|
|
868
|
+
setIsMobile(window.innerWidth < 768);
|
|
869
|
+
};
|
|
870
|
+
checkMobile();
|
|
871
|
+
window.addEventListener("resize", checkMobile);
|
|
872
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
873
|
+
}, []);
|
|
874
|
+
const calculatedHeight = React3__namespace.useMemo(() => {
|
|
875
|
+
if (mapSize) {
|
|
876
|
+
return isMobile ? mapSize.mobile : mapSize.desktop;
|
|
877
|
+
}
|
|
878
|
+
return isMobile ? 420 : 520;
|
|
879
|
+
}, [mapSize, isMobile]);
|
|
880
|
+
React3__namespace.useEffect(() => {
|
|
881
|
+
if (!containerRef.current) return;
|
|
882
|
+
const updateDimensions = () => {
|
|
883
|
+
if (containerRef.current) {
|
|
884
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
885
|
+
setContainerDimensions({
|
|
886
|
+
width: rect.width || 800,
|
|
887
|
+
height: rect.height || calculatedHeight
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
updateDimensions();
|
|
892
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
893
|
+
const resizeObserver = new ResizeObserver(updateDimensions);
|
|
894
|
+
resizeObserver.observe(containerRef.current);
|
|
895
|
+
return () => resizeObserver.disconnect();
|
|
896
|
+
}
|
|
897
|
+
}, [calculatedHeight]);
|
|
789
898
|
const normalizedStandaloneMarkers = React3__namespace.useMemo(
|
|
790
899
|
() => markers.map((marker, index) => ({
|
|
791
900
|
...marker,
|
|
@@ -869,39 +978,41 @@ function GeoMap({
|
|
|
869
978
|
longitude: DEFAULT_VIEW_STATE.longitude
|
|
870
979
|
};
|
|
871
980
|
}, [normalizedClusters, normalizedStandaloneMarkers]);
|
|
872
|
-
const
|
|
873
|
-
|
|
874
|
-
return markerFocusZoom;
|
|
875
|
-
}
|
|
876
|
-
const allCoords = [];
|
|
981
|
+
const zoomCoordinates = React3__namespace.useMemo(() => {
|
|
982
|
+
const coords = [];
|
|
877
983
|
normalizedStandaloneMarkers.forEach((marker) => {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
984
|
+
coords.push({
|
|
985
|
+
lat: marker.latitude,
|
|
986
|
+
lng: marker.longitude
|
|
881
987
|
});
|
|
882
988
|
});
|
|
883
989
|
normalizedClusters.forEach((cluster) => {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
990
|
+
coords.push({
|
|
991
|
+
lat: cluster.latitude,
|
|
992
|
+
lng: cluster.longitude
|
|
887
993
|
});
|
|
888
994
|
});
|
|
889
|
-
|
|
995
|
+
return coords;
|
|
996
|
+
}, [normalizedStandaloneMarkers, normalizedClusters]);
|
|
997
|
+
const properZoom = useDefaultZoom({
|
|
998
|
+
coordinates: zoomCoordinates,
|
|
999
|
+
mapWidth: containerDimensions.width,
|
|
1000
|
+
mapHeight: containerDimensions.height,
|
|
1001
|
+
padding: 80,
|
|
1002
|
+
// Increased padding for better framing
|
|
1003
|
+
maxZoom: 18,
|
|
1004
|
+
minZoom: 1
|
|
1005
|
+
});
|
|
1006
|
+
const calculatedZoom = React3__namespace.useMemo(() => {
|
|
1007
|
+
if (zoomCoordinates.length === 1) {
|
|
1008
|
+
return markerFocusZoom;
|
|
1009
|
+
}
|
|
1010
|
+
if (zoomCoordinates.length === 0) {
|
|
890
1011
|
return DEFAULT_VIEW_STATE.zoom;
|
|
891
1012
|
}
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
const lngDiff = Math.max(...lngs) - Math.min(...lngs);
|
|
896
|
-
const maxDiff = Math.max(latDiff, lngDiff);
|
|
897
|
-
if (maxDiff > 10) return 3;
|
|
898
|
-
if (maxDiff > 5) return 5;
|
|
899
|
-
if (maxDiff > 2) return 7;
|
|
900
|
-
if (maxDiff > 1) return 9;
|
|
901
|
-
if (maxDiff > 0.5) return 10;
|
|
902
|
-
if (maxDiff > 0.1) return 12;
|
|
903
|
-
return 13;
|
|
904
|
-
}, [normalizedClusters, normalizedStandaloneMarkers, markerFocusZoom]);
|
|
1013
|
+
const adjustedZoom = properZoom ? properZoom - 0.5 : DEFAULT_VIEW_STATE.zoom;
|
|
1014
|
+
return Math.min(adjustedZoom, 15);
|
|
1015
|
+
}, [properZoom, zoomCoordinates.length, markerFocusZoom]);
|
|
905
1016
|
const [uncontrolledViewState, setUncontrolledViewState] = React3__namespace.useState({
|
|
906
1017
|
latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
|
|
907
1018
|
longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
|
|
@@ -1227,25 +1338,35 @@ function GeoMap({
|
|
|
1227
1338
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1228
1339
|
"div",
|
|
1229
1340
|
{
|
|
1341
|
+
ref: containerRef,
|
|
1230
1342
|
className: cn(
|
|
1231
|
-
"relative
|
|
1343
|
+
"relative rounded-2xl border border-border bg-background",
|
|
1344
|
+
// Remove overflow-hidden from outer container to allow panel to overflow
|
|
1232
1345
|
className
|
|
1233
1346
|
),
|
|
1347
|
+
style: {
|
|
1348
|
+
// If className includes height settings, they'll override via CSS specificity
|
|
1349
|
+
height: className?.includes("h-[") || className?.includes("min-h-[") || className?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
|
|
1350
|
+
// Explicitly allow overflow for marker panels
|
|
1351
|
+
overflow: "visible"
|
|
1352
|
+
},
|
|
1234
1353
|
children: [
|
|
1235
1354
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1236
1355
|
"div",
|
|
1237
1356
|
{
|
|
1238
1357
|
className: cn(
|
|
1239
|
-
"w-full",
|
|
1240
|
-
//
|
|
1241
|
-
mapWrapperClassName
|
|
1358
|
+
"w-full rounded-2xl",
|
|
1359
|
+
// Only apply default height class if mapWrapperClassName not provided
|
|
1360
|
+
!mapWrapperClassName && `h-[${calculatedHeight}px]`,
|
|
1361
|
+
mapWrapperClassName
|
|
1242
1362
|
),
|
|
1243
1363
|
style: {
|
|
1244
|
-
//
|
|
1245
|
-
height: mapWrapperClassName ? void 0 :
|
|
1364
|
+
// If mapWrapperClassName includes height, let it handle the height
|
|
1365
|
+
height: mapWrapperClassName?.includes("h-[") || mapWrapperClassName?.includes("min-h-[") || mapWrapperClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
|
|
1246
1366
|
maxHeight: "100vh",
|
|
1247
1367
|
// Prevent excessive growth
|
|
1248
1368
|
position: "relative",
|
|
1369
|
+
// Keep overflow hidden only on the map wrapper to contain the canvas
|
|
1249
1370
|
overflow: "hidden"
|
|
1250
1371
|
},
|
|
1251
1372
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1271,6 +1392,10 @@ function GeoMap({
|
|
|
1271
1392
|
geolocateControlPosition,
|
|
1272
1393
|
flyToOptions,
|
|
1273
1394
|
className: cn("h-full w-full", mapClassName),
|
|
1395
|
+
style: {
|
|
1396
|
+
// Pass the calculated height to MapLibre for better zoom calculations
|
|
1397
|
+
height: mapClassName?.includes("h-[") || mapClassName?.includes("min-h-[") || mapClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`
|
|
1398
|
+
},
|
|
1274
1399
|
children: mapChildren
|
|
1275
1400
|
}
|
|
1276
1401
|
)
|
|
@@ -1280,9 +1405,13 @@ function GeoMap({
|
|
|
1280
1405
|
"div",
|
|
1281
1406
|
{
|
|
1282
1407
|
className: cn(
|
|
1283
|
-
"pointer-events-none absolute z-
|
|
1408
|
+
"pointer-events-none absolute z-30",
|
|
1284
1409
|
PANEL_POSITION_CLASS[panelPosition]
|
|
1285
1410
|
),
|
|
1411
|
+
style: {
|
|
1412
|
+
// Ensure panel can overflow and has higher z-index
|
|
1413
|
+
zIndex: 30
|
|
1414
|
+
},
|
|
1286
1415
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: renderMarkerPanel() })
|
|
1287
1416
|
}
|
|
1288
1417
|
) : null
|