feat(SW-1616): Added clustering on destination country/city pages * feat(SW-1616): Added clustering on destination country/city pages Approved-by: Fredrik Thorsson Approved-by: Matilda Landström
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
// Hook to use supercluster with @visgl/react-google-map.
|
|
// Implemented according to https://github.com/visgl/react-google-maps/tree/main/examples/custom-marker-clustering
|
|
|
|
import { useMap } from "@vis.gl/react-google-maps"
|
|
import { useEffect, useState } from "react"
|
|
|
|
import type { BBox } from "geojson"
|
|
|
|
type MapViewportOptions = {
|
|
padding?: number
|
|
}
|
|
|
|
export function useMapViewport({ padding = 0 }: MapViewportOptions = {}) {
|
|
const map = useMap()
|
|
const [bbox, setBbox] = useState<BBox>([-180, -90, 180, 90])
|
|
const [zoom, setZoom] = useState(0)
|
|
|
|
// observe the map to get current bounds
|
|
useEffect(() => {
|
|
if (!map) return
|
|
|
|
const listener = map.addListener("bounds_changed", () => {
|
|
const bounds = map.getBounds()
|
|
const zoom = map.getZoom()
|
|
const projection = map.getProjection()
|
|
|
|
if (!bounds || !zoom || !projection) return
|
|
|
|
const sw = bounds.getSouthWest()
|
|
const ne = bounds.getNorthEast()
|
|
|
|
const paddingDegrees = degreesPerPixel(zoom) * padding
|
|
|
|
const n = Math.min(90, ne.lat() + paddingDegrees)
|
|
const s = Math.max(-90, sw.lat() - paddingDegrees)
|
|
|
|
const w = sw.lng() - paddingDegrees
|
|
const e = ne.lng() + paddingDegrees
|
|
|
|
setBbox([w, s, e, n])
|
|
setZoom(zoom)
|
|
})
|
|
|
|
return () => listener.remove()
|
|
}, [map, padding])
|
|
|
|
return { bbox, zoom }
|
|
}
|
|
|
|
function degreesPerPixel(zoomLevel: number) {
|
|
// 360° divided by the number of pixels at the zoom-level
|
|
return 360 / (Math.pow(2, zoomLevel) * 256)
|
|
}
|