@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.cjs CHANGED
@@ -770,6 +770,19 @@ var PANEL_POSITION_CLASS = {
770
770
  "bottom-left": "bottom-4 left-4",
771
771
  "bottom-right": "bottom-4 right-4"
772
772
  };
773
+ function getOptimalPanelPosition(markerLat, markerLng, mapCenter) {
774
+ const isNorth = markerLat >= mapCenter.latitude;
775
+ const isEast = markerLng >= mapCenter.longitude;
776
+ if (isNorth && isEast) {
777
+ return "bottom-left";
778
+ } else if (isNorth && !isEast) {
779
+ return "bottom-right";
780
+ } else if (!isNorth && isEast) {
781
+ return "top-left";
782
+ } else {
783
+ return "top-right";
784
+ }
785
+ }
773
786
  var DEFAULT_VIEW_STATE = {
774
787
  latitude: 39.5,
775
788
  longitude: -98.35,
@@ -1012,6 +1025,13 @@ function GeoMap({
1012
1025
  IconComponent = FallbackIcon,
1013
1026
  ImgComponent = FallbackImg
1014
1027
  }) {
1028
+ const containerRef = React3__namespace.useRef(null);
1029
+ const [containerDimensions, setContainerDimensions] = React3__namespace.useState({
1030
+ width: 800,
1031
+ // Default width
1032
+ height: 520
1033
+ // Default height
1034
+ });
1015
1035
  const [isMobile, setIsMobile] = React3__namespace.useState(false);
1016
1036
  React3__namespace.useEffect(() => {
1017
1037
  const checkMobile = () => {
@@ -1027,6 +1047,24 @@ function GeoMap({
1027
1047
  }
1028
1048
  return isMobile ? 420 : 520;
1029
1049
  }, [mapSize, isMobile]);
1050
+ React3__namespace.useEffect(() => {
1051
+ if (!containerRef.current) return;
1052
+ const updateDimensions = () => {
1053
+ if (containerRef.current) {
1054
+ const rect = containerRef.current.getBoundingClientRect();
1055
+ setContainerDimensions({
1056
+ width: rect.width || 800,
1057
+ height: rect.height || calculatedHeight
1058
+ });
1059
+ }
1060
+ };
1061
+ updateDimensions();
1062
+ if (typeof ResizeObserver !== "undefined") {
1063
+ const resizeObserver = new ResizeObserver(updateDimensions);
1064
+ resizeObserver.observe(containerRef.current);
1065
+ return () => resizeObserver.disconnect();
1066
+ }
1067
+ }, [calculatedHeight]);
1030
1068
  const normalizedStandaloneMarkers = React3__namespace.useMemo(
1031
1069
  () => markers.map((marker, index) => ({
1032
1070
  ...marker,
@@ -1110,47 +1148,49 @@ function GeoMap({
1110
1148
  longitude: DEFAULT_VIEW_STATE.longitude
1111
1149
  };
1112
1150
  }, [normalizedClusters, normalizedStandaloneMarkers]);
1113
- const calculatedZoom = React3__namespace.useMemo(() => {
1114
- if (normalizedStandaloneMarkers.length + normalizedClusters.length <= 1) {
1115
- return markerFocusZoom;
1116
- }
1117
- const allCoords = [];
1151
+ const zoomCoordinates = React3__namespace.useMemo(() => {
1152
+ const coords = [];
1118
1153
  normalizedStandaloneMarkers.forEach((marker) => {
1119
- allCoords.push({
1120
- latitude: marker.latitude,
1121
- longitude: marker.longitude
1154
+ coords.push({
1155
+ lat: marker.latitude,
1156
+ lng: marker.longitude
1122
1157
  });
1123
1158
  });
1124
1159
  normalizedClusters.forEach((cluster) => {
1125
- allCoords.push({
1126
- latitude: cluster.latitude,
1127
- longitude: cluster.longitude
1160
+ coords.push({
1161
+ lat: cluster.latitude,
1162
+ lng: cluster.longitude
1128
1163
  });
1129
1164
  });
1130
- if (allCoords.length === 0) {
1165
+ return coords;
1166
+ }, [normalizedStandaloneMarkers, normalizedClusters]);
1167
+ const properZoom = useDefaultZoom({
1168
+ coordinates: zoomCoordinates,
1169
+ mapWidth: containerDimensions.width,
1170
+ mapHeight: containerDimensions.height,
1171
+ padding: 80,
1172
+ // Increased padding for better framing
1173
+ maxZoom: 18,
1174
+ minZoom: 1
1175
+ });
1176
+ const calculatedZoom = React3__namespace.useMemo(() => {
1177
+ if (zoomCoordinates.length === 1) {
1178
+ return markerFocusZoom;
1179
+ }
1180
+ if (zoomCoordinates.length === 0) {
1131
1181
  return DEFAULT_VIEW_STATE.zoom;
1132
1182
  }
1133
- const lats = allCoords.map((c) => c.latitude);
1134
- const lngs = allCoords.map((c) => c.longitude);
1135
- const latDiff = Math.max(...lats) - Math.min(...lats);
1136
- const lngDiff = Math.max(...lngs) - Math.min(...lngs);
1137
- const maxDiff = Math.max(latDiff, lngDiff);
1138
- const heightFactor = calculatedHeight / 520;
1139
- const paddingFactor = 0.85;
1140
- if (maxDiff > 10) return Math.max(2, 3 * heightFactor * paddingFactor);
1141
- if (maxDiff > 5) return Math.max(4, 5 * heightFactor * paddingFactor);
1142
- if (maxDiff > 2) return Math.max(6, 7 * heightFactor * paddingFactor);
1143
- if (maxDiff > 1) return Math.max(8, 9 * heightFactor * paddingFactor);
1144
- if (maxDiff > 0.5) return Math.max(9, 10 * heightFactor * paddingFactor);
1145
- if (maxDiff > 0.1) return Math.max(11, 12 * heightFactor * paddingFactor);
1146
- if (maxDiff > 0.01) return Math.max(12, 13 * heightFactor * paddingFactor);
1147
- return Math.max(11, 12 * heightFactor * paddingFactor);
1148
- }, [normalizedClusters, normalizedStandaloneMarkers, markerFocusZoom, calculatedHeight]);
1183
+ const adjustedZoom = properZoom ? properZoom - 0.5 : DEFAULT_VIEW_STATE.zoom;
1184
+ return Math.min(adjustedZoom, 15);
1185
+ }, [properZoom, zoomCoordinates.length, markerFocusZoom]);
1149
1186
  const [uncontrolledViewState, setUncontrolledViewState] = React3__namespace.useState({
1150
1187
  latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
1151
1188
  longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
1152
1189
  zoom: defaultViewState?.zoom ?? calculatedZoom
1153
1190
  });
1191
+ const [dynamicPanelPosition, setDynamicPanelPosition] = React3__namespace.useState(
1192
+ panelPosition
1193
+ );
1154
1194
  React3__namespace.useEffect(() => {
1155
1195
  if (!viewState && !defaultViewState) {
1156
1196
  setUncontrolledViewState({
@@ -1230,6 +1270,19 @@ function GeoMap({
1230
1270
  markerId: marker.id,
1231
1271
  clusterId: marker.clusterId
1232
1272
  });
1273
+ const currentCenter = resolvedViewState || {
1274
+ latitude: firstCoordinate.latitude,
1275
+ longitude: firstCoordinate.longitude
1276
+ };
1277
+ const optimalPosition = getOptimalPanelPosition(
1278
+ marker.latitude,
1279
+ marker.longitude,
1280
+ {
1281
+ latitude: currentCenter.latitude ?? firstCoordinate.latitude,
1282
+ longitude: currentCenter.longitude ?? firstCoordinate.longitude
1283
+ }
1284
+ );
1285
+ setDynamicPanelPosition(optimalPosition);
1233
1286
  applyViewState({
1234
1287
  latitude: marker.latitude,
1235
1288
  longitude: marker.longitude,
@@ -1237,7 +1290,7 @@ function GeoMap({
1237
1290
  });
1238
1291
  emitSelectionChange({ type: "marker", marker });
1239
1292
  },
1240
- [applyViewState, emitSelectionChange, markerFocusZoom]
1293
+ [applyViewState, emitSelectionChange, markerFocusZoom, resolvedViewState, firstCoordinate]
1241
1294
  );
1242
1295
  const selectCluster = React3__namespace.useCallback(
1243
1296
  (cluster) => {
@@ -1245,6 +1298,19 @@ function GeoMap({
1245
1298
  type: "cluster",
1246
1299
  clusterId: cluster.id
1247
1300
  });
1301
+ const currentCenter = resolvedViewState || {
1302
+ latitude: firstCoordinate.latitude,
1303
+ longitude: firstCoordinate.longitude
1304
+ };
1305
+ const optimalPosition = getOptimalPanelPosition(
1306
+ cluster.latitude,
1307
+ cluster.longitude,
1308
+ {
1309
+ latitude: currentCenter.latitude ?? firstCoordinate.latitude,
1310
+ longitude: currentCenter.longitude ?? firstCoordinate.longitude
1311
+ }
1312
+ );
1313
+ setDynamicPanelPosition(optimalPosition);
1248
1314
  applyViewState({
1249
1315
  latitude: cluster.latitude,
1250
1316
  longitude: cluster.longitude,
@@ -1252,7 +1318,7 @@ function GeoMap({
1252
1318
  });
1253
1319
  emitSelectionChange({ type: "cluster", cluster });
1254
1320
  },
1255
- [applyViewState, clusterFocusZoom, emitSelectionChange]
1321
+ [applyViewState, clusterFocusZoom, emitSelectionChange, resolvedViewState, firstCoordinate]
1256
1322
  );
1257
1323
  const clearSelection = React3__namespace.useCallback(() => {
1258
1324
  setSelection({ type: "none" });
@@ -1471,6 +1537,7 @@ function GeoMap({
1471
1537
  return /* @__PURE__ */ jsxRuntime.jsxs(
1472
1538
  "div",
1473
1539
  {
1540
+ ref: containerRef,
1474
1541
  className: cn(
1475
1542
  "relative rounded-2xl border border-border bg-background",
1476
1543
  // Remove overflow-hidden from outer container to allow panel to overflow
@@ -1538,7 +1605,7 @@ function GeoMap({
1538
1605
  {
1539
1606
  className: cn(
1540
1607
  "pointer-events-none absolute z-30",
1541
- PANEL_POSITION_CLASS[panelPosition]
1608
+ PANEL_POSITION_CLASS[dynamicPanelPosition]
1542
1609
  ),
1543
1610
  style: {
1544
1611
  // Ensure panel can overflow and has higher z-index