import React, { useRef, useEffect, useState } from "react";
import { Box, Image } from "theme-ui";
import interact from "interactjs";
import ProxyToken from "../components/ProxyToken";
import AddMapButton from "../components/AddMapButton";
import TokenMenu from "../components/TokenMenu";
import MapToken from "../components/MapToken";
const mapTokenClassName = "map-token";
const zoomSpeed = -0.005;
const minZoom = 0.1;
const maxZoom = 5;
function Map({
mapSource,
mapData,
tokens,
onMapTokenChange,
onMapTokenRemove,
onMapChange,
}) {
function handleProxyDragEnd(isOnMap, token) {
if (isOnMap && onMapTokenChange) {
onMapTokenChange(token);
}
if (!isOnMap && onMapTokenRemove) {
onMapTokenRemove(token);
}
}
const [mapTranslate, setMapTranslate] = useState({ x: 0, y: 0 });
const [mapScale, setMapScale] = useState(1);
useEffect(() => {
interact(".map")
.gesturable({
listeners: {
move: (event) => {
setMapScale((previousMapScale) =>
Math.max(Math.min(previousMapScale + event.ds, maxZoom), minZoom)
);
setMapTranslate((previousMapTranslate) => ({
x: previousMapTranslate.x + event.dx,
y: previousMapTranslate.y + event.dy,
}));
},
},
})
.draggable({
inertia: true,
listeners: {
move: (event) => {
setMapTranslate((previousMapTranslate) => ({
x: previousMapTranslate.x + event.dx,
y: previousMapTranslate.y + event.dy,
}));
},
},
});
interact(".map").on("doubletap", (event) => {
event.preventDefault();
setMapTranslate({ x: 0, y: 0 });
setMapScale(1);
});
}, []);
// Reset map transform when map changes
useEffect(() => {
setMapTranslate({ x: 0, y: 0 });
setMapScale(1);
}, [mapSource]);
// Bind the wheel event of the map via a ref
// in order to support non-passive event listening
// to allow the track pad zoom to be interrupted
// see https://github.com/facebook/react/issues/14856
useEffect(() => {
const mapContainer = mapContainerRef.current;
function handleZoom(event) {
// Stop overscroll on chrome and safari
// also stop pinch to zoom on chrome
event.preventDefault();
const deltaY = event.deltaY * zoomSpeed;
setMapScale((previousMapScale) =>
Math.max(Math.min(previousMapScale + deltaY, maxZoom), minZoom)
);
}
if (mapContainer) {
mapContainer.addEventListener("wheel", handleZoom, {
passive: false,
});
}
return () => {
if (mapContainer) {
mapContainer.removeEventListener("wheel", handleZoom);
}
};
}, []);
const mapRef = useRef(null);
const mapContainerRef = useRef();
const rows = mapData && mapData.rows;
const tokenSizePercent = (1 / rows) * 100;
const aspectRatio = (mapData && mapData.width / mapData.height) || 1;
const mapImage = (
);
const mapTokens = (
{Object.values(tokens).map((token) => (
))}
);
const mapActions = (
);
return (
<>
{mapImage}
{mapTokens}
{mapActions}
>
);
}
export default Map;