Fix token remove for touch devices

This commit is contained in:
Mitchell McCaffrey 2020-05-25 13:12:30 +10:00
parent be7d6c5277
commit 73c7ca91fa

View File

@ -1,4 +1,4 @@
import React, { useContext } from "react"; import React, { useContext, useEffect, useRef, useState } from "react";
import { Box, IconButton } from "theme-ui"; import { Box, IconButton } from "theme-ui";
import RemoveTokenIcon from "../../icons/RemoveTokenIcon"; import RemoveTokenIcon from "../../icons/RemoveTokenIcon";
@ -19,29 +19,92 @@ function TokenDragOverlay({
MapInteractionContext MapInteractionContext
); );
function handleTokenRemove() { const [isRemoveHovered, setIsRemoveHovered] = useState(false);
// Handle other tokens when a vehicle gets deleted const removeTokenRef = useRef();
if (token.isVehicle) {
const layer = tokenImage.getLayer(); // Detect token hover on remove icon manually to support touch devices
const mountedTokens = tokenImage.find(".token"); useEffect(() => {
for (let mountedToken of mountedTokens) { const map = document.querySelector(".map");
// Save and restore token position after moving layer const mapRect = map.getBoundingClientRect();
const position = mountedToken.absolutePosition();
mountedToken.moveTo(layer); function detectRemoveHover() {
mountedToken.absolutePosition(position); const pointerPosition = tokenImage.getStage().getPointerPosition();
onTokenStateChange({ const screenSpacePointerPosition = {
[mountedToken.id()]: { x: pointerPosition.x + mapRect.left,
...mapState.tokens[mountedToken.id()], y: pointerPosition.y + mapRect.top,
x: mountedToken.x() / mapWidth, };
y: mountedToken.y() / mapHeight, const removeIconPosition = removeTokenRef.current.getBoundingClientRect();
lastEditedBy: userId,
}, if (
}); screenSpacePointerPosition.x > removeIconPosition.left &&
screenSpacePointerPosition.y > removeIconPosition.top &&
screenSpacePointerPosition.x < removeIconPosition.right &&
screenSpacePointerPosition.y < removeIconPosition.bottom
) {
if (!isRemoveHovered) {
setIsRemoveHovered(true);
}
} else if (isRemoveHovered) {
setIsRemoveHovered(false);
} }
} }
onTokenStateRemove(tokenState);
setPreventMapInteraction(false); let handler;
} if (tokenState && tokenImage) {
handler = setInterval(detectRemoveHover, 100);
}
return () => {
if (handler) {
clearInterval(handler);
}
};
}, [tokenState, tokenImage, isRemoveHovered]);
// Detect drag end of token image and remove it if it is over the remove icon
useEffect(() => {
function handleTokenDragEnd() {
if (isRemoveHovered) {
// Handle other tokens when a vehicle gets deleted
if (token.isVehicle) {
const layer = tokenImage.getLayer();
const mountedTokens = tokenImage.find(".token");
for (let mountedToken of mountedTokens) {
// Save and restore token position after moving layer
const position = mountedToken.absolutePosition();
mountedToken.moveTo(layer);
mountedToken.absolutePosition(position);
onTokenStateChange({
[mountedToken.id()]: {
...mapState.tokens[mountedToken.id()],
x: mountedToken.x() / mapWidth,
y: mountedToken.y() / mapHeight,
lastEditedBy: userId,
},
});
}
}
onTokenStateRemove(tokenState);
setPreventMapInteraction(false);
}
}
tokenImage.on("dragend", handleTokenDragEnd);
return () => {
tokenImage.off("dragend", handleTokenDragEnd);
};
}, [
tokenImage,
token,
tokenState,
isRemoveHovered,
mapWidth,
mapHeight,
userId,
onTokenStateChange,
onTokenStateRemove,
setPreventMapInteraction,
mapState.tokens,
]);
return ( return (
<Box <Box
@ -50,15 +113,15 @@ function TokenDragOverlay({
bottom: "24px", bottom: "24px",
left: "50%", left: "50%",
borderRadius: "50%", borderRadius: "50%",
transform: "translateX(-50%) scale(1.5)", transform: isRemoveHovered
? "translateX(-50%) scale(2.0)"
: "translateX(-50%) scale(1.5)",
transition: "transform 250ms ease", transition: "transform 250ms ease",
":hover": { color: isRemoveHovered ? "primary" : "text",
transform: "translateX(-50%) scale(2.0)", pointerEvents: "none",
},
}} }}
bg="overlay" bg="overlay"
onMouseUp={handleTokenRemove} ref={removeTokenRef}
onTouchEnd={handleTokenRemove}
> >
<IconButton> <IconButton>
<RemoveTokenIcon /> <RemoveTokenIcon />