Created
September 9, 2023 12:22
-
-
Save tschoffelen/0937ec3d446d241caf403f20f0555e41 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use client"; | |
import React, { useEffect, useRef } from "react"; | |
import axios from "axios"; | |
const loadMapkitJs = () => | |
new Promise((resolve) => { | |
if (typeof window === undefined) { | |
return; | |
} | |
if ("mapkit" in window && window.mapkit) { | |
resolve(window.mapkit); | |
return; | |
} | |
const element = document.createElement("script"); | |
element.addEventListener("load", async () => { | |
if (!("mapkit" in window)) { | |
return; | |
} | |
await window.mapkit.init({ | |
authorizationCallback: async (done) => { | |
const { data } = await axios.get("/api/frontend/mapkit"); | |
done(data.token); | |
}, | |
}); | |
resolve(window.mapkit); | |
}); | |
element.src = "https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"; | |
document.head.appendChild(element); | |
}); | |
const toCompatibleBounds = (region) => ({ | |
getSouthWest: () => [region.southLatitude, region.westLongitude], | |
getNorthEast: () => [region.northLatitude, region.eastLongitude], | |
}); | |
const AppleMap = ({ | |
centerPoint, | |
mapOptions = {}, | |
zoom, | |
onBoundsChanged, | |
className, | |
style, | |
markers = [], | |
}) => { | |
const div = useRef(null); | |
const mapRef = useRef(null); | |
const markerRefs = useRef({}); | |
const renderMarkers = (markers) => { | |
if (!mapRef.current || !markers) { | |
return; | |
} | |
const [map, mapkit] = mapRef.current; | |
const newAnnotations = []; | |
for (const marker of markers) { | |
if (!marker.key) { | |
throw new Error("Marker must have a key."); | |
} | |
if (markerRefs.current[marker.key]) { | |
continue; | |
} | |
const coord = new mapkit.Coordinate( | |
Number(marker.location.lat), | |
Number(marker.location.lng) | |
); | |
const ann = new mapkit[ | |
marker.marker ? "ImageAnnotation" : "MarkerAnnotation" | |
](coord, { | |
data: { key: marker.key }, | |
title: marker.title, | |
color: marker.color || "#e30a17", | |
url: marker.marker ? { 1: marker.marker } : undefined, | |
clusteringIdentifier: "markers", | |
collisionMode: mapkit.Annotation.CollisionMode.Circle, | |
displayPriority: mapkit.Annotation.DisplayPriority.Low, | |
size: marker.marker ? { width: 58, height: 63 } : undefined, | |
}); | |
newAnnotations.push(ann); | |
markerRefs.current[marker.key] = marker; | |
} | |
if (newAnnotations.length) { | |
map.addAnnotations(newAnnotations); | |
} | |
}; | |
useEffect(() => { | |
if (!div.current || mapRef.current) { | |
return; | |
} | |
loadMapkitJs().then((mapkit) => { | |
if (mapRef.current) { | |
return; | |
} | |
div.current.innerHTML = ""; | |
const map = new mapkit.Map(div.current, mapOptions); | |
mapRef.current = [map, mapkit]; | |
// Set initial region | |
const zoomLevel = Math.min(21, zoom + 1 || 12); | |
const delta = (1 / Math.exp(zoomLevel * Math.LN2)) * 360; | |
map.region = new mapkit.CoordinateRegion( | |
new mapkit.Coordinate(Number(centerPoint[0]), Number(centerPoint[1])), | |
new mapkit.CoordinateSpan(delta, delta) | |
); | |
map.annotationForCluster = function (clusterAnnnotation) { | |
clusterAnnnotation.color = | |
clusterAnnnotation.memberAnnotations[0].color; | |
}; | |
map.addEventListener("select", function (event) { | |
markerRefs.current[event.annotation.data.key]?.onClick?.(); | |
}); | |
if (onBoundsChanged) { | |
onBoundsChanged(toCompatibleBounds(map.region.toBoundingRegion())); | |
map.addEventListener("region-change-end", function (event) { | |
console.log("Region Change ended", event); | |
onBoundsChanged( | |
toCompatibleBounds(event.target.region.toBoundingRegion()) | |
); | |
}); | |
} | |
renderMarkers(markers); | |
}); | |
}, [div]); | |
useEffect(() => { | |
renderMarkers(markers); | |
}, [markers]); | |
return ( | |
<div | |
ref={div} | |
className={className} | |
style={style || { height: "100vh", width: "100vw" }} | |
/> | |
); | |
}; | |
export default AppleMap; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment