这是我想要封装的一个鼠标画图组件,不停的触发 mouseMove 获取当前的位置,同时又缓存了上一次的位置,连接两个点即可,但是我想要用 hooks 封装,感觉很难,没有头绪。
// When true, moving the mouse draws on the canvas
let isDrawing = false;
let x = 0;
let y = 0;
const myPics = document.getElementById('myPics');
const context = myPics.getContext('2d');
// event.offsetX, event.offsetY gives the (x,y) offset from the edge of the canvas.
// Add the event listeners for mousedown, mousemove, and mouseup
myPics.addEventListener('mousedown', e => {
x = e.offsetX;
y = e.offsetY;
isDrawing = true;
});
myPics.addEventListener('mousemove', e => {
if (isDrawing === true) {
drawLine(context, x, y, e.offsetX, e.offsetY);
x = e.offsetX;
y = e.offsetY;
}
});
window.addEventListener('mouseup', e => {
if (isDrawing === true) {
drawLine(context, x, y, e.offsetX, e.offsetY);
x = 0;
y = 0;
isDrawing = false;
}
});
function drawLine(context, x1, y1, x2, y2) {
context.beginPath();
context.strokeStyle = 'black';
context.lineWidth = 1;
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
context.closePath();
}
这是我写出来的完全不能画图的 hook (我估计是因为没有像上面那样获取上次位置和当前位置的原因
const Canvas = () => {
const canvasRef = React.useRef(null);
//const [paths, setPaths] = useState([]);
const [isDrawing, setIsDrawing] = useState(false);
const [pos, setPos] = useState({
x: 0,
y: 0,
});
const [isMouseDown, setIsMouseDown] = useState(false);
const [isMouseMove, setIsMouseMove] = useState(false);
const [isMouseUp, setIsMouseUp] = useState(false);
useEffect(() => {
const ctx = canvasRef.current.getContext("2d");
if (isDrawing) {
console.log("isDrawing");
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
ctx.closePath();
}
}, [isMouseDown, isDrawing, pos]);
const handleMouseDown = (e) => {
setPos({
x: e.clientX,
y: e.clientY,
});
setIsDrawing(true);
setIsMouseDown(true);
}
const handleMouseUp = () => {
setIsDrawing(false);
setIsMouseUp(false);
}
const handleMouseMove = (e) => {
// console.log(e);
setIsMouseMove(true);
setPos({
x: e.clientX,
y: e.clientY,
});
//console.log(state.ctx);
}
return (
<div className="back-div" >
<canvas ref={canvasRef} id="canvas1" className="paint-canvas" onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp}>
</canvas>
</div>
)
}
1
weimo383 OP 顺带一提,我的 e.offsetX 为什么读出来是 undefined
|
2
weimo383 OP 啊,别沉啊
|
3
frankwei777 2020-11-27 14:48:59 +08:00
react 的 offsetX 在 event.nativeEvent 中
|
4
shenyu1996 2020-11-27 15:27:32 +08:00
https://codesandbox.io/s/busy-saha-rs7f9
稍稍改了一下 可以了 |
5
weimo383 OP @frankwei777 谢谢
|
6
weimo383 OP @shenyu1996 谢谢!
|
7
BUHeF254Lpd1MH06 2020-11-27 15:55:52 +08:00
有啥难的,自己多想想就写出来了
|
8
weimo383 OP @v135ex
还是有点难的,你可以试试,css 改动 canvas 大小的话鼠标位置和 canvas 上绘图坐标是不一致的 |
10
BUHeF254Lpd1MH06 2020-11-28 10:28:07 +08:00
@weimo383 好的 没有尝试过妄下定论了,我也尝试下学习一下
|
11
xrr2016 2020-11-28 14:54:19 +08:00
我的建议是用成熟的绘图库,例如 p5.js 这种,然后在用 hooks 做你需要的功能
|
13
funnyecho 2020-11-30 10:23:59 +08:00 1
个人看法,这里用 react hook ( useState )其实没有什么意义,你第一段代码都自成一体了,直接使用事件驱动来的更快,不需要额外等待 react setState 的调度。
与其说使用 hook,不如把第一段代码封装成一个纯函数,接受一个 ref 来处理绘图,在外部 FC 中调用这个函数来的更好。 |
15
funnyecho 2020-11-30 14:43:20 +08:00
@weimo383
把第一段代码封装成函数: ``` // 函数接受一个 canvas element,并返回 destructor 函数用来 removeListener type draw = ($canvas) => (() => void) ``` 然后,React.FC 中调用 draw 方法,举个例子: ``` useEffect(() => { return draw(canvasRef.current) }, [canvasRef.current]) ``` |
17
funnyecho 2020-11-30 19:07:55 +08:00 via iPhone
@weimo383 看代码就几个状态,每次 mousedown 都会重置,保存在 draw 函数内部的作用域就好了呀。
|
18
weimo383 OP @funnyecho 后续会有返回键按钮,保存在 draw 内部的作用域时怎么返回到上一步,还是保存为内部 state 吧
|