React/Next.js,以困难的方式平移 SVG
React/Next.js, panning an SVG the hard way
正在尝试在此处制作交互式平面图。已经看到一些答案,大多数转向 D3.js - 如果问题无法解决,也会这样做。
这给了我一些开始写作的指导https://codepen.io/Mamboleoo/pen/dmjYpR/
我现在的代码:
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>
)}
主要问题是 SVG 在平移过程中不会被鼠标拖动,并且只有在 stopPanSVG
完成后才会进行相当苛刻的移动。可能是由于 useState
分别是异步和触发,或者对重新渲染有限制?用 useEffect
替换它的尝试不太顺利 - 理想情况下我希望它在 startPanSVG
内,所以它只在事件上触发,但这违反了钩子的规则。用钩子包装所述函数会使 e.clientX
未定义,即使以 '?' 为前缀或跳过初始安装也是如此。
也许有更好的选择?可能应该添加 window
/document
/global
由于项目设置而被禁用 - 例如不能 addEventListener
。
我相信这应该可以解决您的问题:
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
}
正在尝试在此处制作交互式平面图。已经看到一些答案,大多数转向 D3.js - 如果问题无法解决,也会这样做。
这给了我一些开始写作的指导https://codepen.io/Mamboleoo/pen/dmjYpR/
我现在的代码:
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>
)}
主要问题是 SVG 在平移过程中不会被鼠标拖动,并且只有在 stopPanSVG
完成后才会进行相当苛刻的移动。可能是由于 useState
分别是异步和触发,或者对重新渲染有限制?用 useEffect
替换它的尝试不太顺利 - 理想情况下我希望它在 startPanSVG
内,所以它只在事件上触发,但这违反了钩子的规则。用钩子包装所述函数会使 e.clientX
未定义,即使以 '?' 为前缀或跳过初始安装也是如此。
也许有更好的选择?可能应该添加 window
/document
/global
由于项目设置而被禁用 - 例如不能 addEventListener
。
我相信这应该可以解决您的问题:
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
}