@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
package/dist/components/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { clsx } from 'clsx';
|
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import * as React3 from 'react';
|
|
5
|
-
import React3__default from 'react';
|
|
5
|
+
import React3__default, { useMemo } from 'react';
|
|
6
6
|
import { Marker, Map as Map$1, GeolocateControl, NavigationControl } from 'react-map-gl/maplibre';
|
|
7
7
|
|
|
8
8
|
// src/utils/cn.ts
|
|
@@ -637,6 +637,74 @@ function MapLibre({
|
|
|
637
637
|
}
|
|
638
638
|
);
|
|
639
639
|
}
|
|
640
|
+
var TILE_SIZE = 512;
|
|
641
|
+
function latToMercatorY(lat) {
|
|
642
|
+
const latRad = lat * Math.PI / 180;
|
|
643
|
+
const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
|
|
644
|
+
return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
|
|
645
|
+
}
|
|
646
|
+
function lngToMercatorX(lng) {
|
|
647
|
+
return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
|
|
648
|
+
}
|
|
649
|
+
function computeDefaultZoom(options) {
|
|
650
|
+
const {
|
|
651
|
+
coordinates,
|
|
652
|
+
mapWidth,
|
|
653
|
+
mapHeight,
|
|
654
|
+
padding = 50,
|
|
655
|
+
maxZoom = 18,
|
|
656
|
+
minZoom = 1
|
|
657
|
+
} = options;
|
|
658
|
+
if (coordinates.length === 0) return null;
|
|
659
|
+
if (coordinates.length === 1) return maxZoom;
|
|
660
|
+
if (mapWidth <= 0 || mapHeight <= 0) return null;
|
|
661
|
+
let minLat = Infinity;
|
|
662
|
+
let maxLat = -Infinity;
|
|
663
|
+
let minLng = Infinity;
|
|
664
|
+
let maxLng = -Infinity;
|
|
665
|
+
for (const coord of coordinates) {
|
|
666
|
+
if (coord.lat < minLat) minLat = coord.lat;
|
|
667
|
+
if (coord.lat > maxLat) maxLat = coord.lat;
|
|
668
|
+
if (coord.lng < minLng) minLng = coord.lng;
|
|
669
|
+
if (coord.lng > maxLng) maxLng = coord.lng;
|
|
670
|
+
}
|
|
671
|
+
const pixelXMin = lngToMercatorX(minLng);
|
|
672
|
+
const pixelXMax = lngToMercatorX(maxLng);
|
|
673
|
+
const pixelYMin = latToMercatorY(maxLat);
|
|
674
|
+
const pixelYMax = latToMercatorY(minLat);
|
|
675
|
+
const dx = Math.abs(pixelXMax - pixelXMin);
|
|
676
|
+
const dy = Math.abs(pixelYMax - pixelYMin);
|
|
677
|
+
const availableWidth = mapWidth - padding * 2;
|
|
678
|
+
const availableHeight = mapHeight - padding * 2;
|
|
679
|
+
if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
|
|
680
|
+
let zoom;
|
|
681
|
+
if (dx === 0 && dy === 0) {
|
|
682
|
+
return maxZoom;
|
|
683
|
+
} else if (dx === 0) {
|
|
684
|
+
zoom = Math.log2(availableHeight / dy);
|
|
685
|
+
} else if (dy === 0) {
|
|
686
|
+
zoom = Math.log2(availableWidth / dx);
|
|
687
|
+
} else {
|
|
688
|
+
const zoomX = Math.log2(availableWidth / dx);
|
|
689
|
+
const zoomY = Math.log2(availableHeight / dy);
|
|
690
|
+
zoom = Math.min(zoomX, zoomY);
|
|
691
|
+
}
|
|
692
|
+
return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
|
|
693
|
+
}
|
|
694
|
+
function useDefaultZoom(options) {
|
|
695
|
+
const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
|
|
696
|
+
return useMemo(
|
|
697
|
+
() => computeDefaultZoom({
|
|
698
|
+
coordinates,
|
|
699
|
+
mapWidth,
|
|
700
|
+
mapHeight,
|
|
701
|
+
padding,
|
|
702
|
+
maxZoom,
|
|
703
|
+
minZoom
|
|
704
|
+
}),
|
|
705
|
+
[coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
|
|
706
|
+
);
|
|
707
|
+
}
|
|
640
708
|
var PANEL_POSITION_CLASS = {
|
|
641
709
|
"top-left": "left-4 top-4",
|
|
642
710
|
"top-right": "right-4 top-4",
|
|
@@ -881,9 +949,50 @@ function GeoMap({
|
|
|
881
949
|
clearSelectionOnMapClick = true,
|
|
882
950
|
mapChildren,
|
|
883
951
|
optixFlowConfig,
|
|
952
|
+
mapSize,
|
|
884
953
|
IconComponent = FallbackIcon,
|
|
885
954
|
ImgComponent = FallbackImg
|
|
886
955
|
}) {
|
|
956
|
+
const containerRef = React3.useRef(null);
|
|
957
|
+
const [containerDimensions, setContainerDimensions] = React3.useState({
|
|
958
|
+
width: 800,
|
|
959
|
+
// Default width
|
|
960
|
+
height: 520
|
|
961
|
+
// Default height
|
|
962
|
+
});
|
|
963
|
+
const [isMobile, setIsMobile] = React3.useState(false);
|
|
964
|
+
React3.useEffect(() => {
|
|
965
|
+
const checkMobile = () => {
|
|
966
|
+
setIsMobile(window.innerWidth < 768);
|
|
967
|
+
};
|
|
968
|
+
checkMobile();
|
|
969
|
+
window.addEventListener("resize", checkMobile);
|
|
970
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
971
|
+
}, []);
|
|
972
|
+
const calculatedHeight = React3.useMemo(() => {
|
|
973
|
+
if (mapSize) {
|
|
974
|
+
return isMobile ? mapSize.mobile : mapSize.desktop;
|
|
975
|
+
}
|
|
976
|
+
return isMobile ? 420 : 520;
|
|
977
|
+
}, [mapSize, isMobile]);
|
|
978
|
+
React3.useEffect(() => {
|
|
979
|
+
if (!containerRef.current) return;
|
|
980
|
+
const updateDimensions = () => {
|
|
981
|
+
if (containerRef.current) {
|
|
982
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
983
|
+
setContainerDimensions({
|
|
984
|
+
width: rect.width || 800,
|
|
985
|
+
height: rect.height || calculatedHeight
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
updateDimensions();
|
|
990
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
991
|
+
const resizeObserver = new ResizeObserver(updateDimensions);
|
|
992
|
+
resizeObserver.observe(containerRef.current);
|
|
993
|
+
return () => resizeObserver.disconnect();
|
|
994
|
+
}
|
|
995
|
+
}, [calculatedHeight]);
|
|
887
996
|
const normalizedStandaloneMarkers = React3.useMemo(
|
|
888
997
|
() => markers.map((marker, index) => ({
|
|
889
998
|
...marker,
|
|
@@ -967,39 +1076,41 @@ function GeoMap({
|
|
|
967
1076
|
longitude: DEFAULT_VIEW_STATE.longitude
|
|
968
1077
|
};
|
|
969
1078
|
}, [normalizedClusters, normalizedStandaloneMarkers]);
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
return markerFocusZoom;
|
|
973
|
-
}
|
|
974
|
-
const allCoords = [];
|
|
1079
|
+
const zoomCoordinates = React3.useMemo(() => {
|
|
1080
|
+
const coords = [];
|
|
975
1081
|
normalizedStandaloneMarkers.forEach((marker) => {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1082
|
+
coords.push({
|
|
1083
|
+
lat: marker.latitude,
|
|
1084
|
+
lng: marker.longitude
|
|
979
1085
|
});
|
|
980
1086
|
});
|
|
981
1087
|
normalizedClusters.forEach((cluster) => {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1088
|
+
coords.push({
|
|
1089
|
+
lat: cluster.latitude,
|
|
1090
|
+
lng: cluster.longitude
|
|
985
1091
|
});
|
|
986
1092
|
});
|
|
987
|
-
|
|
1093
|
+
return coords;
|
|
1094
|
+
}, [normalizedStandaloneMarkers, normalizedClusters]);
|
|
1095
|
+
const properZoom = useDefaultZoom({
|
|
1096
|
+
coordinates: zoomCoordinates,
|
|
1097
|
+
mapWidth: containerDimensions.width,
|
|
1098
|
+
mapHeight: containerDimensions.height,
|
|
1099
|
+
padding: 80,
|
|
1100
|
+
// Increased padding for better framing
|
|
1101
|
+
maxZoom: 18,
|
|
1102
|
+
minZoom: 1
|
|
1103
|
+
});
|
|
1104
|
+
const calculatedZoom = React3.useMemo(() => {
|
|
1105
|
+
if (zoomCoordinates.length === 1) {
|
|
1106
|
+
return markerFocusZoom;
|
|
1107
|
+
}
|
|
1108
|
+
if (zoomCoordinates.length === 0) {
|
|
988
1109
|
return DEFAULT_VIEW_STATE.zoom;
|
|
989
1110
|
}
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
const lngDiff = Math.max(...lngs) - Math.min(...lngs);
|
|
994
|
-
const maxDiff = Math.max(latDiff, lngDiff);
|
|
995
|
-
if (maxDiff > 10) return 3;
|
|
996
|
-
if (maxDiff > 5) return 5;
|
|
997
|
-
if (maxDiff > 2) return 7;
|
|
998
|
-
if (maxDiff > 1) return 9;
|
|
999
|
-
if (maxDiff > 0.5) return 10;
|
|
1000
|
-
if (maxDiff > 0.1) return 12;
|
|
1001
|
-
return 13;
|
|
1002
|
-
}, [normalizedClusters, normalizedStandaloneMarkers, markerFocusZoom]);
|
|
1111
|
+
const adjustedZoom = properZoom ? properZoom - 0.5 : DEFAULT_VIEW_STATE.zoom;
|
|
1112
|
+
return Math.min(adjustedZoom, 15);
|
|
1113
|
+
}, [properZoom, zoomCoordinates.length, markerFocusZoom]);
|
|
1003
1114
|
const [uncontrolledViewState, setUncontrolledViewState] = React3.useState({
|
|
1004
1115
|
latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
|
|
1005
1116
|
longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
|
|
@@ -1325,25 +1436,35 @@ function GeoMap({
|
|
|
1325
1436
|
return /* @__PURE__ */ jsxs(
|
|
1326
1437
|
"div",
|
|
1327
1438
|
{
|
|
1439
|
+
ref: containerRef,
|
|
1328
1440
|
className: cn(
|
|
1329
|
-
"relative
|
|
1441
|
+
"relative rounded-2xl border border-border bg-background",
|
|
1442
|
+
// Remove overflow-hidden from outer container to allow panel to overflow
|
|
1330
1443
|
className
|
|
1331
1444
|
),
|
|
1445
|
+
style: {
|
|
1446
|
+
// If className includes height settings, they'll override via CSS specificity
|
|
1447
|
+
height: className?.includes("h-[") || className?.includes("min-h-[") || className?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
|
|
1448
|
+
// Explicitly allow overflow for marker panels
|
|
1449
|
+
overflow: "visible"
|
|
1450
|
+
},
|
|
1332
1451
|
children: [
|
|
1333
1452
|
/* @__PURE__ */ jsx(
|
|
1334
1453
|
"div",
|
|
1335
1454
|
{
|
|
1336
1455
|
className: cn(
|
|
1337
|
-
"w-full",
|
|
1338
|
-
//
|
|
1339
|
-
mapWrapperClassName
|
|
1456
|
+
"w-full rounded-2xl",
|
|
1457
|
+
// Only apply default height class if mapWrapperClassName not provided
|
|
1458
|
+
!mapWrapperClassName && `h-[${calculatedHeight}px]`,
|
|
1459
|
+
mapWrapperClassName
|
|
1340
1460
|
),
|
|
1341
1461
|
style: {
|
|
1342
|
-
//
|
|
1343
|
-
height: mapWrapperClassName ? void 0 :
|
|
1462
|
+
// If mapWrapperClassName includes height, let it handle the height
|
|
1463
|
+
height: mapWrapperClassName?.includes("h-[") || mapWrapperClassName?.includes("min-h-[") || mapWrapperClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
|
|
1344
1464
|
maxHeight: "100vh",
|
|
1345
1465
|
// Prevent excessive growth
|
|
1346
1466
|
position: "relative",
|
|
1467
|
+
// Keep overflow hidden only on the map wrapper to contain the canvas
|
|
1347
1468
|
overflow: "hidden"
|
|
1348
1469
|
},
|
|
1349
1470
|
children: /* @__PURE__ */ jsx(
|
|
@@ -1369,6 +1490,10 @@ function GeoMap({
|
|
|
1369
1490
|
geolocateControlPosition,
|
|
1370
1491
|
flyToOptions,
|
|
1371
1492
|
className: cn("h-full w-full", mapClassName),
|
|
1493
|
+
style: {
|
|
1494
|
+
// Pass the calculated height to MapLibre for better zoom calculations
|
|
1495
|
+
height: mapClassName?.includes("h-[") || mapClassName?.includes("min-h-[") || mapClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`
|
|
1496
|
+
},
|
|
1372
1497
|
children: mapChildren
|
|
1373
1498
|
}
|
|
1374
1499
|
)
|
|
@@ -1378,9 +1503,13 @@ function GeoMap({
|
|
|
1378
1503
|
"div",
|
|
1379
1504
|
{
|
|
1380
1505
|
className: cn(
|
|
1381
|
-
"pointer-events-none absolute z-
|
|
1506
|
+
"pointer-events-none absolute z-30",
|
|
1382
1507
|
PANEL_POSITION_CLASS[panelPosition]
|
|
1383
1508
|
),
|
|
1509
|
+
style: {
|
|
1510
|
+
// Ensure panel can overflow and has higher z-index
|
|
1511
|
+
zIndex: 30
|
|
1512
|
+
},
|
|
1384
1513
|
children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: renderMarkerPanel() })
|
|
1385
1514
|
}
|
|
1386
1515
|
) : null
|