Make map translation smoother by removing it from the state

This commit is contained in:
Mitchell McCaffrey 2020-05-25 14:09:45 +10:00
parent 73c7ca91fa
commit 8932ceb1e3
2 changed files with 23 additions and 13 deletions

View File

@ -26,7 +26,6 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
const [stageWidth, setStageWidth] = useState(1); const [stageWidth, setStageWidth] = useState(1);
const [stageHeight, setStageHeight] = useState(1); const [stageHeight, setStageHeight] = useState(1);
const [stageScale, setStageScale] = useState(1); const [stageScale, setStageScale] = useState(1);
const [stageTranslate, setStageTranslate] = useState({ x: 0, y: 0 });
// "none" | "first" | "dragging" | "last" // "none" | "first" | "dragging" | "last"
const [stageDragState, setStageDragState] = useState("none"); const [stageDragState, setStageDragState] = useState("none");
const [preventMapInteraction, setPreventMapInteraction] = useState(false); const [preventMapInteraction, setPreventMapInteraction] = useState(false);
@ -34,13 +33,21 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
const stageWidthRef = useRef(stageWidth); const stageWidthRef = useRef(stageWidth);
const stageHeightRef = useRef(stageHeight); const stageHeightRef = useRef(stageHeight);
const stageScaleRef = useRef(stageScale); // Avoid state udpates when panning the map by using a ref and updating the konva element directly
const stageTranslateRef = useRef(stageTranslate); const stageTranslateRef = useRef({ x: 0, y: 0 });
useEffect(() => { useEffect(() => {
if (map) { const layer = mapLayerRef.current;
if (map && layer) {
const mapHeight = stageWidthRef.current * (map.height / map.width); const mapHeight = stageWidthRef.current * (map.height / map.width);
setStageTranslate({ x: 0, y: -(mapHeight - stageHeightRef.current) / 2 }); const newTranslate = {
x: 0,
y: -(mapHeight - stageHeightRef.current) / 2,
};
layer.x(newTranslate.x);
layer.y(newTranslate.y);
layer.draw();
stageTranslateRef.current = newTranslate;
} }
}, [map]); }, [map]);
@ -70,7 +77,6 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
maxZoom maxZoom
); );
setStageScale(newScale); setStageScale(newScale);
stageScaleRef.current = newScale;
}, },
onPinch: ({ offset }) => { onPinch: ({ offset }) => {
const [d] = offset; const [d] = offset;
@ -79,22 +85,27 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
maxZoom maxZoom
); );
setStageScale(newScale); setStageScale(newScale);
stageScaleRef.current = newScale;
}, },
onDrag: ({ delta, xy, first, last }) => { onDrag: ({ delta, xy, first, last }) => {
if (preventMapInteraction) { if (preventMapInteraction) {
return; return;
} }
setMapDragPosition(getMapDragPosition(xy));
setStageDragState(first ? "first" : last ? "last" : "dragging");
const [dx, dy] = delta; const [dx, dy] = delta;
const stageTranslate = stageTranslateRef.current;
const layer = mapLayerRef.current;
if (selectedToolId === "pan") { if (selectedToolId === "pan") {
const newTranslate = { const newTranslate = {
x: stageTranslate.x + dx / stageScale, x: stageTranslate.x + dx / stageScale,
y: stageTranslate.y + dy / stageScale, y: stageTranslate.y + dy / stageScale,
}; };
setStageTranslate(newTranslate); layer.x(newTranslate.x);
layer.y(newTranslate.y);
layer.draw();
stageTranslateRef.current = newTranslate; stageTranslateRef.current = newTranslate;
} else {
setMapDragPosition(getMapDragPosition(xy));
setStageDragState(first ? "first" : last ? "last" : "dragging");
} }
}, },
onDragEnd: () => { onDragEnd: () => {
@ -129,12 +140,12 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
const mapHeight = map ? stageWidth * (map.height / map.width) : stageHeight; const mapHeight = map ? stageWidth * (map.height / map.width) : stageHeight;
const mapStageRef = useContext(MapStageContext); const mapStageRef = useContext(MapStageContext);
const mapLayerRef = useRef();
const mapImageRef = useRef(); const mapImageRef = useRef();
const auth = useContext(AuthContext); const auth = useContext(AuthContext);
const mapInteraction = { const mapInteraction = {
stageTranslate,
stageScale, stageScale,
stageWidth, stageWidth,
stageHeight, stageHeight,
@ -167,7 +178,7 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
offset={{ x: stageWidth / 2, y: stageHeight / 2 }} offset={{ x: stageWidth / 2, y: stageHeight / 2 }}
ref={mapStageRef} ref={mapStageRef}
> >
<Layer x={stageTranslate.x} y={stageTranslate.y}> <Layer ref={mapLayerRef}>
<Image <Image
image={mapSourceImage} image={mapSourceImage}
width={mapWidth} width={mapWidth}

View File

@ -1,7 +1,6 @@
import React from "react"; import React from "react";
const MapInteractionContext = React.createContext({ const MapInteractionContext = React.createContext({
stageTranslate: { x: 0, y: 0 },
stageScale: 1, stageScale: 1,
stageWidth: 1, stageWidth: 1,
stageHeight: 1, stageHeight: 1,