react-konva 如何实现 根据以鼠标为中心缩放图片?-灵析社区

大厂球袋

解决这个问题,首先要逆变换求出鼠标点击的位置在变换前的位置,然后将这个位置作为新的变换坐标系原点(原点在线性变换中是不动点,利用这个性质,就可以做出跟随鼠标的效果)。 如果图形已经发生过变换,修改原点会导致“跃变”效果,也就是在鼠标开始动的瞬间图形会跑掉(把`setPosition`去掉就可以重现这种现象)。因此需要对“跃变”的副作用进行修正,也就是在修改原点的同时,把图像“拽”回原位置。 const [scale, setScale] = useState(2); const [offset, setOffset] = useState({ x: 80, y: 80, }); const [position, setPosition] = useState({ x: 0, y: 0 }); const wheelCallback = useCallback( ({ //@ts-ignore evt: { layerX, layerY, deltaY }, }: Konva.KonvaEventObject) => { if (!shapeRef.current) return; const currentTransform = shapeRef.current.getTransform(); const currentTransformMatrix = [...currentTransform.getMatrix()]; const { x, y, offsetX, offsetY } = shapeRef.current.attrs; // 当前的变换坐标原点为 [offsetX, offsetY], 为不变点 // 鼠标点击的位置 const currentViewCursorInLayer = { x: layerX, y: layerY, }; // 当前变换矩阵求逆,以便还原鼠标位置在变换前的真实位置 const currentTransformInvert = currentTransform.copy().invert(); // 逆变换求鼠标位置变换前的位置,所以是 Actual ,该位置将作为新的变换原点 // 该位置实际上是在以 [x, y] 为原点的坐标系中表达的,所以是 InShape const currentActualCursorInShape = currentTransformInvert.point( currentViewCursorInLayer ); // 其实赋值前后是完全等效的,这里为了避免困惑,故重命名 const nextOffset = { x: currentActualCursorInShape.x, y: currentActualCursorInShape.y, }; // 修改原点 setOffset(nextOffset); // 跟随滚轮缩放 if (deltaY 0.1) { setScale(scale - 0.1); } else { setScale(0.1); } // 原点位置变更,变更的矢量由旧原点指向新原点,直接移动一下好了 const nextMatrix = [...currentTransformMatrix]; const nextTransform = new Konva.Transform(nextMatrix).translate( -(nextOffset.x - offsetX), -(nextOffset.y - offsetY) ); // 修改原点,会导致位置突变,需要计算突变发生后,鼠标相对于图像的位置会被移动到何处 // 变换只是视觉效果,所以是 View const nextViewCursorInLayer = nextTransform.point(nextOffset); // 鼠标位置在两次变化间的移动矢量 const cursorMoveVector = { x: layerX - nextViewCursorInLayer.x, y: layerY - nextViewCursorInLayer.y, }; // 使用前述移动矢量,修正位置 setPosition({ x: x + cursorMoveVector.x, y: y + cursorMoveVector.y }); }, [scale, shapeRef] ); return > 👆这里用的 Rect ,方便测试,Image 差别应该不大。 以上代码在单层未变换 `Layer` 中测试可用,但没有测试过复杂的复合变换,注意`shapeRef`要作为`Group`的属性,而非`Image`。

阅读量:1

点赞量:0

问AI