画布拖动方案

发布时间 2023-10-17 09:46:18作者: 长安城下翩翩少年


画布拖动策略:为提升性能,防止画布(canvas) 跟随mouseMove事件不断重绘,选择先移动画布容器,在鼠标mouseup 事件执行时,重绘画布,让画布容器的还原。

具体实现
// 视口宽高: 为画板可视区域的宽高,不包含header高度;
const clientRect = {
width:,
height:,
};

// 定义一个偏移量,为视口的宽高:理由是在鼠标从视口左上角拖到到视口的右下角,不需要画布重绘就能直接显示
const initOffset = {
x: clientRect.width,// x 为视口宽度
y: clientRect.height, // y 为视口高度
};
// 初始化偏移量
// containerRef.current.style.transform = translate3d(${-initOffset.x}px,${-initOffset.y}px,0) scale(1)

// 画布容器的宽高,视口正好位于画布容器的正中间
const containerRect = {
width:clientRect.width + 2initOffset.x,
height:clientRect.height + 2
initOffset.y,
}

// 画布的初始坐标
const [stagePos,setStagePos] = useState({
x:0,
y:0,
});

// 事件
// 在stage 上监听mousedown 事件, (为方便陈述,在下面代码先不考虑解绑监听事件情况)
const hanleStageMouseDown = (e:MouseEvent)=>{
const mouseOffset = {
// react 事件中的event 为改装后的,如果需要使用dom原生event = event.nativeEvent
x:e.nativeEvent.offsetX,
y:e.nativeEvent.offsetY
};
// 画布容器外层div (用于设置画布颜色,鼠标样式等),在此用于计算画布容器外层不变的rect位置
const outerContainerRect = outerContainerRef.current.getBoundingClientRect();
// 保存点击事件的鼠标 offsetX,offsetY
window.addEventListener('mousemove',(e:MouseEvent)=>{
const {pageX,pageY} = e;
const translateX = pageX - mouseOffset.x - outerContainerRect.left;
const translateY = pageY - mouseOffset.y - outerContainerRect.top;
// 画布容器移动的距离,用于鼠标mouseup时去更新画布坐标
mouseMoveOffsetRef.current = {
// 总的偏移量 - 初始化偏移量
x:translateX - (-initOffset.x),
y:translateY - (-initOffset.y)
};
// 画布容器进行translate移动
containerRef.current.style.transform = translate3d(${translateX}px,${translateY}px,0) scale(1)
});
window.addEventListener('mouseup',(e:MouseEvent)=>{
// 移除mousemove监听事件
// 更新画布坐标
//updateStagePos(mouseMoveOffsetRef.current);
setStagePos((oldPos)=>{
return {
x:oldPos.x + mouseMoveOffsetRef.current.x,
y:oldPos.y + mouseMoveOffsetRef.current.y,
}
});
// 重置画布容器transform值
containerRef.current.style.transform = translate3d(${-initOffset.x}px,${-initOffset.y}px,0) scale(1)
});
};