@page-speed/maps 0.1.9 → 0.2.1

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/index.js CHANGED
@@ -749,6 +749,19 @@ var PANEL_POSITION_CLASS = {
749
749
  "bottom-left": "bottom-4 left-4",
750
750
  "bottom-right": "bottom-4 right-4"
751
751
  };
752
+ function getOptimalPanelPosition(markerLat, markerLng, mapCenter) {
753
+ const isNorth = markerLat >= mapCenter.latitude;
754
+ const isEast = markerLng >= mapCenter.longitude;
755
+ if (isNorth && isEast) {
756
+ return "bottom-left";
757
+ } else if (isNorth && !isEast) {
758
+ return "bottom-right";
759
+ } else if (!isNorth && isEast) {
760
+ return "top-left";
761
+ } else {
762
+ return "top-right";
763
+ }
764
+ }
752
765
  var DEFAULT_VIEW_STATE = {
753
766
  latitude: 39.5,
754
767
  longitude: -98.35,
@@ -991,6 +1004,13 @@ function GeoMap({
991
1004
  IconComponent = FallbackIcon,
992
1005
  ImgComponent = FallbackImg
993
1006
  }) {
1007
+ const containerRef = React3.useRef(null);
1008
+ const [containerDimensions, setContainerDimensions] = React3.useState({
1009
+ width: 800,
1010
+ // Default width
1011
+ height: 520
1012
+ // Default height
1013
+ });
994
1014
  const [isMobile, setIsMobile] = React3.useState(false);
995
1015
  React3.useEffect(() => {
996
1016
  const checkMobile = () => {
@@ -1006,6 +1026,24 @@ function GeoMap({
1006
1026
  }
1007
1027
  return isMobile ? 420 : 520;
1008
1028
  }, [mapSize, isMobile]);
1029
+ React3.useEffect(() => {
1030
+ if (!containerRef.current) return;
1031
+ const updateDimensions = () => {
1032
+ if (containerRef.current) {
1033
+ const rect = containerRef.current.getBoundingClientRect();
1034
+ setContainerDimensions({
1035
+ width: rect.width || 800,
1036
+ height: rect.height || calculatedHeight
1037
+ });
1038
+ }
1039
+ };
1040
+ updateDimensions();
1041
+ if (typeof ResizeObserver !== "undefined") {
1042
+ const resizeObserver = new ResizeObserver(updateDimensions);
1043
+ resizeObserver.observe(containerRef.current);
1044
+ return () => resizeObserver.disconnect();
1045
+ }
1046
+ }, [calculatedHeight]);
1009
1047
  const normalizedStandaloneMarkers = React3.useMemo(
1010
1048
  () => markers.map((marker, index) => ({
1011
1049
  ...marker,
@@ -1089,47 +1127,49 @@ function GeoMap({
1089
1127
  longitude: DEFAULT_VIEW_STATE.longitude
1090
1128
  };
1091
1129
  }, [normalizedClusters, normalizedStandaloneMarkers]);
1092
- const calculatedZoom = React3.useMemo(() => {
1093
- if (normalizedStandaloneMarkers.length + normalizedClusters.length <= 1) {
1094
- return markerFocusZoom;
1095
- }
1096
- const allCoords = [];
1130
+ const zoomCoordinates = React3.useMemo(() => {
1131
+ const coords = [];
1097
1132
  normalizedStandaloneMarkers.forEach((marker) => {
1098
- allCoords.push({
1099
- latitude: marker.latitude,
1100
- longitude: marker.longitude
1133
+ coords.push({
1134
+ lat: marker.latitude,
1135
+ lng: marker.longitude
1101
1136
  });
1102
1137
  });
1103
1138
  normalizedClusters.forEach((cluster) => {
1104
- allCoords.push({
1105
- latitude: cluster.latitude,
1106
- longitude: cluster.longitude
1139
+ coords.push({
1140
+ lat: cluster.latitude,
1141
+ lng: cluster.longitude
1107
1142
  });
1108
1143
  });
1109
- if (allCoords.length === 0) {
1144
+ return coords;
1145
+ }, [normalizedStandaloneMarkers, normalizedClusters]);
1146
+ const properZoom = useDefaultZoom({
1147
+ coordinates: zoomCoordinates,
1148
+ mapWidth: containerDimensions.width,
1149
+ mapHeight: containerDimensions.height,
1150
+ padding: 80,
1151
+ // Increased padding for better framing
1152
+ maxZoom: 18,
1153
+ minZoom: 1
1154
+ });
1155
+ const calculatedZoom = React3.useMemo(() => {
1156
+ if (zoomCoordinates.length === 1) {
1157
+ return markerFocusZoom;
1158
+ }
1159
+ if (zoomCoordinates.length === 0) {
1110
1160
  return DEFAULT_VIEW_STATE.zoom;
1111
1161
  }
1112
- const lats = allCoords.map((c) => c.latitude);
1113
- const lngs = allCoords.map((c) => c.longitude);
1114
- const latDiff = Math.max(...lats) - Math.min(...lats);
1115
- const lngDiff = Math.max(...lngs) - Math.min(...lngs);
1116
- const maxDiff = Math.max(latDiff, lngDiff);
1117
- const heightFactor = calculatedHeight / 520;
1118
- const paddingFactor = 0.85;
1119
- if (maxDiff > 10) return Math.max(2, 3 * heightFactor * paddingFactor);
1120
- if (maxDiff > 5) return Math.max(4, 5 * heightFactor * paddingFactor);
1121
- if (maxDiff > 2) return Math.max(6, 7 * heightFactor * paddingFactor);
1122
- if (maxDiff > 1) return Math.max(8, 9 * heightFactor * paddingFactor);
1123
- if (maxDiff > 0.5) return Math.max(9, 10 * heightFactor * paddingFactor);
1124
- if (maxDiff > 0.1) return Math.max(11, 12 * heightFactor * paddingFactor);
1125
- if (maxDiff > 0.01) return Math.max(12, 13 * heightFactor * paddingFactor);
1126
- return Math.max(11, 12 * heightFactor * paddingFactor);
1127
- }, [normalizedClusters, normalizedStandaloneMarkers, markerFocusZoom, calculatedHeight]);
1162
+ const adjustedZoom = properZoom ? properZoom - 0.5 : DEFAULT_VIEW_STATE.zoom;
1163
+ return Math.min(adjustedZoom, 15);
1164
+ }, [properZoom, zoomCoordinates.length, markerFocusZoom]);
1128
1165
  const [uncontrolledViewState, setUncontrolledViewState] = React3.useState({
1129
1166
  latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
1130
1167
  longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
1131
1168
  zoom: defaultViewState?.zoom ?? calculatedZoom
1132
1169
  });
1170
+ const [dynamicPanelPosition, setDynamicPanelPosition] = React3.useState(
1171
+ panelPosition
1172
+ );
1133
1173
  React3.useEffect(() => {
1134
1174
  if (!viewState && !defaultViewState) {
1135
1175
  setUncontrolledViewState({
@@ -1209,6 +1249,19 @@ function GeoMap({
1209
1249
  markerId: marker.id,
1210
1250
  clusterId: marker.clusterId
1211
1251
  });
1252
+ const currentCenter = resolvedViewState || {
1253
+ latitude: firstCoordinate.latitude,
1254
+ longitude: firstCoordinate.longitude
1255
+ };
1256
+ const optimalPosition = getOptimalPanelPosition(
1257
+ marker.latitude,
1258
+ marker.longitude,
1259
+ {
1260
+ latitude: currentCenter.latitude ?? firstCoordinate.latitude,
1261
+ longitude: currentCenter.longitude ?? firstCoordinate.longitude
1262
+ }
1263
+ );
1264
+ setDynamicPanelPosition(optimalPosition);
1212
1265
  applyViewState({
1213
1266
  latitude: marker.latitude,
1214
1267
  longitude: marker.longitude,
@@ -1216,7 +1269,7 @@ function GeoMap({
1216
1269
  });
1217
1270
  emitSelectionChange({ type: "marker", marker });
1218
1271
  },
1219
- [applyViewState, emitSelectionChange, markerFocusZoom]
1272
+ [applyViewState, emitSelectionChange, markerFocusZoom, resolvedViewState, firstCoordinate]
1220
1273
  );
1221
1274
  const selectCluster = React3.useCallback(
1222
1275
  (cluster) => {
@@ -1224,6 +1277,19 @@ function GeoMap({
1224
1277
  type: "cluster",
1225
1278
  clusterId: cluster.id
1226
1279
  });
1280
+ const currentCenter = resolvedViewState || {
1281
+ latitude: firstCoordinate.latitude,
1282
+ longitude: firstCoordinate.longitude
1283
+ };
1284
+ const optimalPosition = getOptimalPanelPosition(
1285
+ cluster.latitude,
1286
+ cluster.longitude,
1287
+ {
1288
+ latitude: currentCenter.latitude ?? firstCoordinate.latitude,
1289
+ longitude: currentCenter.longitude ?? firstCoordinate.longitude
1290
+ }
1291
+ );
1292
+ setDynamicPanelPosition(optimalPosition);
1227
1293
  applyViewState({
1228
1294
  latitude: cluster.latitude,
1229
1295
  longitude: cluster.longitude,
@@ -1231,7 +1297,7 @@ function GeoMap({
1231
1297
  });
1232
1298
  emitSelectionChange({ type: "cluster", cluster });
1233
1299
  },
1234
- [applyViewState, clusterFocusZoom, emitSelectionChange]
1300
+ [applyViewState, clusterFocusZoom, emitSelectionChange, resolvedViewState, firstCoordinate]
1235
1301
  );
1236
1302
  const clearSelection = React3.useCallback(() => {
1237
1303
  setSelection({ type: "none" });
@@ -1450,6 +1516,7 @@ function GeoMap({
1450
1516
  return /* @__PURE__ */ jsxs(
1451
1517
  "div",
1452
1518
  {
1519
+ ref: containerRef,
1453
1520
  className: cn(
1454
1521
  "relative rounded-2xl border border-border bg-background",
1455
1522
  // Remove overflow-hidden from outer container to allow panel to overflow
@@ -1517,7 +1584,7 @@ function GeoMap({
1517
1584
  {
1518
1585
  className: cn(
1519
1586
  "pointer-events-none absolute z-30",
1520
- PANEL_POSITION_CLASS[panelPosition]
1587
+ PANEL_POSITION_CLASS[dynamicPanelPosition]
1521
1588
  ),
1522
1589
  style: {
1523
1590
  // Ensure panel can overflow and has higher z-index