Trying to do an interactive floor map over here. Already seen some answers, most move on to D3.js - in case the issue is impossible to solve, will do likewise.
This gave me some pointers to start writing https://codepen.io/Mamboleoo/pen/dmjYpR/
The code I have now:
const Scheme1 = function (){
const svg = useRef(null);
const [isPanning, setIsPanning] = useState(false);
const [cursorPos, setCursorPos] = useState({ x:0, y:0 });
const [newSVGPos, setNewSVGPos] = useState({ x:0, y:0 });
const [SVGViewbox, setSVGViewbox] = useState({ x:0, y:0, width:2472.3, height: 1467.24 });
let startPanSVG = (e) => {
setIsPanning(true);
setCursorPos({ x:e.clientX, y:e.clientY });
}
let panSVG = (e) => {
if(!isPanning) {
return;
}
e.stopPropagation();
e.preventDefault();
let SVGDimensions = e.target.getBoundingClientRect();
let ratio = SVGViewbox.width/SVGDimensions.width;
let newX = SVGViewbox.x - ((e.clientX - cursorPos.x) * ratio);
let newY = SVGViewbox.y - ((e.clientY - cursorPos.y) * ratio);
setNewSVGPos({ x:newX, y:newY });
}
let stopPanSVG = () => {
setIsPanning(false);
setSVGViewbox({ ...SVGViewbox, x:newSVGPos.x, y:newSVGPos.y });
}
return (
<svg ref={svg} viewBox={Object.values(SVGViewbox).join(" ")} onPointerDown={startPanSVG} onPointerMove={panSVG} onPointerLeave={stopPanSVG} onPointerUp={stopPanSVG} version="1.1" id="svg1003">
...
</svg>
)}
The main issue is the SVG doesn't get dragged with the mouse during the pan, and does a rather harsh move only after stopPanSVG
is done. Probably due to useState
being asynchronous and triggering respectively, or having a limit on re-renders? Attempts to replace it with useEffect
didn't go all too well - ideally I'd want it inside startPanSVG
, so it only triggers on event, but that's against the hook's rules. Wrapping said function with the hook makes e.clientX
undefined, even when prefixed with '?'s or skipping initial mount.
Perhaps there's a better option? Should probably add that window
/document
/global
are disabled due to project settings - can't addEventListener
, for example.
CodePudding user response:
I believe this should fix your problem:
let panSVG = (e) => {
if(!isPanning) {
return;
}
e.stopPropagation();
e.preventDefault();
let SVGDimensions = e.target.getBoundingClientRect();
let ratio = SVGViewbox.width/SVGDimensions.width;
let newX = SVGViewbox.x - ((e.clientX - cursorPos.x) * ratio);
let newY = SVGViewbox.y - ((e.clientY - cursorPos.y) * ratio);
// change the viewport here
setSVGViewbox({ ...SVGViewbox, x: newX, y: newY });
}
let stopPanSVG = () => {
setIsPanning(false);
// don't change viewport here
}