Files
grungnet/src/components/map/MapToken.js

124 lines
3.2 KiB
JavaScript
Raw Normal View History

2020-05-21 16:46:50 +10:00
import React, { useContext, useState, useEffect, useRef } from "react";
import { Image as KonvaImage, Group } from "react-konva";
2020-05-21 16:46:50 +10:00
import useImage from "use-image";
import useDataSource from "../../helpers/useDataSource";
2020-05-21 16:46:50 +10:00
import useDebounce from "../../helpers/useDebounce";
import AuthContext from "../../contexts/AuthContext";
2020-05-21 16:46:50 +10:00
import MapInteractionContext from "../../contexts/MapInteractionContext";
import TokenStatus from "../token/TokenStatus";
import TokenLabel from "../token/TokenLabel";
import { tokenSources, unknownSource } from "../../tokens";
2020-05-21 16:46:50 +10:00
function MapToken({
token,
tokenState,
tokenSizePercent,
onTokenStateChange,
onTokenMenuOpen,
2020-05-21 22:57:44 +10:00
onTokenDragStart,
onTokenDragEnd,
2020-05-21 16:46:50 +10:00
}) {
const { userId } = useContext(AuthContext);
2020-05-21 16:46:50 +10:00
const {
setPreventMapInteraction,
mapWidth,
mapHeight,
stageScale,
} = useContext(MapInteractionContext);
const tokenSource = useDataSource(token, tokenSources, unknownSource);
const [tokenSourceImage, tokenSourceStatus] = useImage(tokenSource);
const [tokenAspectRatio, setTokenAspectRatio] = useState(1);
useEffect(() => {
if (tokenSourceImage) {
setTokenAspectRatio(tokenSourceImage.width / tokenSourceImage.height);
}
}, [tokenSourceImage]);
function handleDragEnd(event) {
setPreventMapInteraction(false);
2020-05-21 16:46:50 +10:00
onTokenStateChange({
...tokenState,
x: event.target.x() / mapWidth,
y: event.target.y() / mapHeight,
lastEditedBy: userId,
});
2020-05-21 22:57:44 +10:00
onTokenDragEnd();
2020-05-21 16:46:50 +10:00
}
function handleClick(event) {
const tokenImage = event.target;
onTokenMenuOpen(tokenState.id, tokenImage);
}
const tokenWidth = tokenSizePercent * mapWidth * tokenState.size;
const tokenHeight =
tokenSizePercent * (mapWidth / tokenAspectRatio) * tokenState.size;
2020-05-21 16:46:50 +10:00
const debouncedStageScale = useDebounce(stageScale, 50);
const imageRef = useRef();
2020-05-21 16:46:50 +10:00
useEffect(() => {
const image = imageRef.current;
2020-05-21 22:57:44 +10:00
if (
image &&
tokenSourceStatus === "loaded" &&
tokenWidth > 0 &&
tokenHeight > 0
) {
2020-05-21 16:46:50 +10:00
image.cache({
pixelRatio: debouncedStageScale,
});
image.drawHitFromCache();
// Force redraw
image.getLayer().draw();
2020-05-21 16:46:50 +10:00
}
}, [debouncedStageScale, tokenWidth, tokenHeight, tokenSourceStatus]);
2020-05-21 22:57:44 +10:00
if (!tokenWidth || !tokenHeight) {
return null;
}
return (
<Group
2020-05-21 16:46:50 +10:00
width={tokenWidth}
height={tokenHeight}
x={tokenState.x * mapWidth}
y={tokenState.y * mapHeight}
draggable
onMouseDown={() => setPreventMapInteraction(true)}
onMouseUp={() => setPreventMapInteraction(false)}
onTouchStart={() => setPreventMapInteraction(true)}
onTouchEnd={() => setPreventMapInteraction(false)}
onClick={handleClick}
onDragEnd={handleDragEnd}
2020-05-21 22:57:44 +10:00
onDragStart={onTokenDragStart}
>
<KonvaImage
ref={imageRef}
width={tokenWidth}
height={tokenHeight}
x={0}
y={0}
image={tokenSourceImage}
/>
<TokenStatus
tokenState={tokenState}
width={tokenWidth}
height={tokenHeight}
/>
<TokenLabel
tokenState={tokenState}
width={tokenWidth}
height={tokenHeight}
/>
</Group>
);
}
export default MapToken;