@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React3 from 'react';
|
|
2
|
-
import React3__default from 'react';
|
|
2
|
+
import React3__default, { useMemo } from 'react';
|
|
3
3
|
import { Marker, Map as Map$1, GeolocateControl, NavigationControl } from 'react-map-gl/maplibre';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -518,6 +518,74 @@ function MapLibre({
|
|
|
518
518
|
}
|
|
519
519
|
);
|
|
520
520
|
}
|
|
521
|
+
var TILE_SIZE = 512;
|
|
522
|
+
function latToMercatorY(lat) {
|
|
523
|
+
const latRad = lat * Math.PI / 180;
|
|
524
|
+
const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
|
|
525
|
+
return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
|
|
526
|
+
}
|
|
527
|
+
function lngToMercatorX(lng) {
|
|
528
|
+
return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
|
|
529
|
+
}
|
|
530
|
+
function computeDefaultZoom(options) {
|
|
531
|
+
const {
|
|
532
|
+
coordinates,
|
|
533
|
+
mapWidth,
|
|
534
|
+
mapHeight,
|
|
535
|
+
padding = 50,
|
|
536
|
+
maxZoom = 18,
|
|
537
|
+
minZoom = 1
|
|
538
|
+
} = options;
|
|
539
|
+
if (coordinates.length === 0) return null;
|
|
540
|
+
if (coordinates.length === 1) return maxZoom;
|
|
541
|
+
if (mapWidth <= 0 || mapHeight <= 0) return null;
|
|
542
|
+
let minLat = Infinity;
|
|
543
|
+
let maxLat = -Infinity;
|
|
544
|
+
let minLng = Infinity;
|
|
545
|
+
let maxLng = -Infinity;
|
|
546
|
+
for (const coord of coordinates) {
|
|
547
|
+
if (coord.lat < minLat) minLat = coord.lat;
|
|
548
|
+
if (coord.lat > maxLat) maxLat = coord.lat;
|
|
549
|
+
if (coord.lng < minLng) minLng = coord.lng;
|
|
550
|
+
if (coord.lng > maxLng) maxLng = coord.lng;
|
|
551
|
+
}
|
|
552
|
+
const pixelXMin = lngToMercatorX(minLng);
|
|
553
|
+
const pixelXMax = lngToMercatorX(maxLng);
|
|
554
|
+
const pixelYMin = latToMercatorY(maxLat);
|
|
555
|
+
const pixelYMax = latToMercatorY(minLat);
|
|
556
|
+
const dx = Math.abs(pixelXMax - pixelXMin);
|
|
557
|
+
const dy = Math.abs(pixelYMax - pixelYMin);
|
|
558
|
+
const availableWidth = mapWidth - padding * 2;
|
|
559
|
+
const availableHeight = mapHeight - padding * 2;
|
|
560
|
+
if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
|
|
561
|
+
let zoom;
|
|
562
|
+
if (dx === 0 && dy === 0) {
|
|
563
|
+
return maxZoom;
|
|
564
|
+
} else if (dx === 0) {
|
|
565
|
+
zoom = Math.log2(availableHeight / dy);
|
|
566
|
+
} else if (dy === 0) {
|
|
567
|
+
zoom = Math.log2(availableWidth / dx);
|
|
568
|
+
} else {
|
|
569
|
+
const zoomX = Math.log2(availableWidth / dx);
|
|
570
|
+
const zoomY = Math.log2(availableHeight / dy);
|
|
571
|
+
zoom = Math.min(zoomX, zoomY);
|
|
572
|
+
}
|
|
573
|
+
return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
|
|
574
|
+
}
|
|
575
|
+
function useDefaultZoom(options) {
|
|
576
|
+
const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
|
|
577
|
+
return useMemo(
|
|
578
|
+
() => computeDefaultZoom({
|
|
579
|
+
coordinates,
|
|
580
|
+
mapWidth,
|
|
581
|
+
mapHeight,
|
|
582
|
+
padding,
|
|
583
|
+
maxZoom,
|
|
584
|
+
minZoom
|
|
585
|
+
}),
|
|
586
|
+
[coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
|
|
587
|
+
);
|
|
588
|
+
}
|
|
521
589
|
var PANEL_POSITION_CLASS = {
|
|
522
590
|
"top-left": "left-4 top-4",
|
|
523
591
|
"top-right": "right-4 top-4",
|
|
@@ -762,9 +830,50 @@ function GeoMap({
|
|
|
762
830
|
clearSelectionOnMapClick = true,
|
|
763
831
|
mapChildren,
|
|
764
832
|
optixFlowConfig,
|
|
833
|
+
mapSize,
|
|
765
834
|
IconComponent = FallbackIcon,
|
|
766
835
|
ImgComponent = FallbackImg
|
|
767
836
|
}) {
|
|
837
|
+
const containerRef = React3.useRef(null);
|
|
838
|
+
const [containerDimensions, setContainerDimensions] = React3.useState({
|
|
839
|
+
width: 800,
|
|
840
|
+
// Default width
|
|
841
|
+
height: 520
|
|
842
|
+
// Default height
|
|
843
|
+
});
|
|
844
|
+
const [isMobile, setIsMobile] = React3.useState(false);
|
|
845
|
+
React3.useEffect(() => {
|
|
846
|
+
const checkMobile = () => {
|
|
847
|
+
setIsMobile(window.innerWidth < 768);
|
|
848
|
+
};
|
|
849
|
+
checkMobile();
|
|
850
|
+
window.addEventListener("resize", checkMobile);
|
|
851
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
852
|
+
}, []);
|
|
853
|
+
const calculatedHeight = React3.useMemo(() => {
|
|
854
|
+
if (mapSize) {
|
|
855
|
+
return isMobile ? mapSize.mobile : mapSize.desktop;
|
|
856
|
+
}
|
|
857
|
+
return isMobile ? 420 : 520;
|
|
858
|
+
}, [mapSize, isMobile]);
|
|
859
|
+
React3.useEffect(() => {
|
|
860
|
+
if (!containerRef.current) return;
|
|
861
|
+
const updateDimensions = () => {
|
|
862
|
+
if (containerRef.current) {
|
|
863
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
864
|
+
setContainerDimensions({
|
|
865
|
+
width: rect.width || 800,
|
|
866
|
+
height: rect.height || calculatedHeight
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
updateDimensions();
|
|
871
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
872
|
+
const resizeObserver = new ResizeObserver(updateDimensions);
|
|
873
|
+
resizeObserver.observe(containerRef.current);
|
|
874
|
+
return () => resizeObserver.disconnect();
|
|
875
|
+
}
|
|
876
|
+
}, [calculatedHeight]);
|
|
768
877
|
const normalizedStandaloneMarkers = React3.useMemo(
|
|
769
878
|
() => markers.map((marker, index) => ({
|
|
770
879
|
...marker,
|
|
@@ -848,39 +957,41 @@ function GeoMap({
|
|
|
848
957
|
longitude: DEFAULT_VIEW_STATE.longitude
|
|
849
958
|
};
|
|
850
959
|
}, [normalizedClusters, normalizedStandaloneMarkers]);
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
return markerFocusZoom;
|
|
854
|
-
}
|
|
855
|
-
const allCoords = [];
|
|
960
|
+
const zoomCoordinates = React3.useMemo(() => {
|
|
961
|
+
const coords = [];
|
|
856
962
|
normalizedStandaloneMarkers.forEach((marker) => {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
963
|
+
coords.push({
|
|
964
|
+
lat: marker.latitude,
|
|
965
|
+
lng: marker.longitude
|
|
860
966
|
});
|
|
861
967
|
});
|
|
862
968
|
normalizedClusters.forEach((cluster) => {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
969
|
+
coords.push({
|
|
970
|
+
lat: cluster.latitude,
|
|
971
|
+
lng: cluster.longitude
|
|
866
972
|
});
|
|
867
973
|
});
|
|
868
|
-
|
|
974
|
+
return coords;
|
|
975
|
+
}, [normalizedStandaloneMarkers, normalizedClusters]);
|
|
976
|
+
const properZoom = useDefaultZoom({
|
|
977
|
+
coordinates: zoomCoordinates,
|
|
978
|
+
mapWidth: containerDimensions.width,
|
|
979
|
+
mapHeight: containerDimensions.height,
|
|
980
|
+
padding: 80,
|
|
981
|
+
// Increased padding for better framing
|
|
982
|
+
maxZoom: 18,
|
|
983
|
+
minZoom: 1
|
|
984
|
+
});
|
|
985
|
+
const calculatedZoom = React3.useMemo(() => {
|
|
986
|
+
if (zoomCoordinates.length === 1) {
|
|
987
|
+
return markerFocusZoom;
|
|
988
|
+
}
|
|
989
|
+
if (zoomCoordinates.length === 0) {
|
|
869
990
|
return DEFAULT_VIEW_STATE.zoom;
|
|
870
991
|
}
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
const lngDiff = Math.max(...lngs) - Math.min(...lngs);
|
|
875
|
-
const maxDiff = Math.max(latDiff, lngDiff);
|
|
876
|
-
if (maxDiff > 10) return 3;
|
|
877
|
-
if (maxDiff > 5) return 5;
|
|
878
|
-
if (maxDiff > 2) return 7;
|
|
879
|
-
if (maxDiff > 1) return 9;
|
|
880
|
-
if (maxDiff > 0.5) return 10;
|
|
881
|
-
if (maxDiff > 0.1) return 12;
|
|
882
|
-
return 13;
|
|
883
|
-
}, [normalizedClusters, normalizedStandaloneMarkers, markerFocusZoom]);
|
|
992
|
+
const adjustedZoom = properZoom ? properZoom - 0.5 : DEFAULT_VIEW_STATE.zoom;
|
|
993
|
+
return Math.min(adjustedZoom, 15);
|
|
994
|
+
}, [properZoom, zoomCoordinates.length, markerFocusZoom]);
|
|
884
995
|
const [uncontrolledViewState, setUncontrolledViewState] = React3.useState({
|
|
885
996
|
latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
|
|
886
997
|
longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
|
|
@@ -1206,25 +1317,35 @@ function GeoMap({
|
|
|
1206
1317
|
return /* @__PURE__ */ jsxs(
|
|
1207
1318
|
"div",
|
|
1208
1319
|
{
|
|
1320
|
+
ref: containerRef,
|
|
1209
1321
|
className: cn(
|
|
1210
|
-
"relative
|
|
1322
|
+
"relative rounded-2xl border border-border bg-background",
|
|
1323
|
+
// Remove overflow-hidden from outer container to allow panel to overflow
|
|
1211
1324
|
className
|
|
1212
1325
|
),
|
|
1326
|
+
style: {
|
|
1327
|
+
// If className includes height settings, they'll override via CSS specificity
|
|
1328
|
+
height: className?.includes("h-[") || className?.includes("min-h-[") || className?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
|
|
1329
|
+
// Explicitly allow overflow for marker panels
|
|
1330
|
+
overflow: "visible"
|
|
1331
|
+
},
|
|
1213
1332
|
children: [
|
|
1214
1333
|
/* @__PURE__ */ jsx(
|
|
1215
1334
|
"div",
|
|
1216
1335
|
{
|
|
1217
1336
|
className: cn(
|
|
1218
|
-
"w-full",
|
|
1219
|
-
//
|
|
1220
|
-
mapWrapperClassName
|
|
1337
|
+
"w-full rounded-2xl",
|
|
1338
|
+
// Only apply default height class if mapWrapperClassName not provided
|
|
1339
|
+
!mapWrapperClassName && `h-[${calculatedHeight}px]`,
|
|
1340
|
+
mapWrapperClassName
|
|
1221
1341
|
),
|
|
1222
1342
|
style: {
|
|
1223
|
-
//
|
|
1224
|
-
height: mapWrapperClassName ? void 0 :
|
|
1343
|
+
// If mapWrapperClassName includes height, let it handle the height
|
|
1344
|
+
height: mapWrapperClassName?.includes("h-[") || mapWrapperClassName?.includes("min-h-[") || mapWrapperClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
|
|
1225
1345
|
maxHeight: "100vh",
|
|
1226
1346
|
// Prevent excessive growth
|
|
1227
1347
|
position: "relative",
|
|
1348
|
+
// Keep overflow hidden only on the map wrapper to contain the canvas
|
|
1228
1349
|
overflow: "hidden"
|
|
1229
1350
|
},
|
|
1230
1351
|
children: /* @__PURE__ */ jsx(
|
|
@@ -1250,6 +1371,10 @@ function GeoMap({
|
|
|
1250
1371
|
geolocateControlPosition,
|
|
1251
1372
|
flyToOptions,
|
|
1252
1373
|
className: cn("h-full w-full", mapClassName),
|
|
1374
|
+
style: {
|
|
1375
|
+
// Pass the calculated height to MapLibre for better zoom calculations
|
|
1376
|
+
height: mapClassName?.includes("h-[") || mapClassName?.includes("min-h-[") || mapClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`
|
|
1377
|
+
},
|
|
1253
1378
|
children: mapChildren
|
|
1254
1379
|
}
|
|
1255
1380
|
)
|
|
@@ -1259,9 +1384,13 @@ function GeoMap({
|
|
|
1259
1384
|
"div",
|
|
1260
1385
|
{
|
|
1261
1386
|
className: cn(
|
|
1262
|
-
"pointer-events-none absolute z-
|
|
1387
|
+
"pointer-events-none absolute z-30",
|
|
1263
1388
|
PANEL_POSITION_CLASS[panelPosition]
|
|
1264
1389
|
),
|
|
1390
|
+
style: {
|
|
1391
|
+
// Ensure panel can overflow and has higher z-index
|
|
1392
|
+
zIndex: 30
|
|
1393
|
+
},
|
|
1265
1394
|
children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: renderMarkerPanel() })
|
|
1266
1395
|
}
|
|
1267
1396
|
) : null
|