我正在开发一个使用HTML5画布的协作白板.我想用鼠标绘制形状,为此,我要清除整个画布,重新绘制之前在画布上的元素,然后在上面添加新的形状.虽然这很管用,但它会产生如下口吃:
The stutter:
如果我不清除画布,我会得到这样的结果:
Multiple shapes drawn when I don't clear:
我正在使用Socket.IO在客户端之间发送数据.在画布的鼠标释放事件侦听器上,我发出如下数据:
canvas.addEventListener('mouseup', function () {
canvas.removeEventListener('mousemove', onPaint, false);
canvas.isDrawing = false;
let canvasImg = canvas.toDataURL('image/png')
socket.emit('canvas-data', canvasImg)
}, false);
然后我有一个react 挂钩来接收套接字事件并设置白板图像.然后将其绘制到画布上,如下所示:
useEffect(() => {
if (open) {
let image = new Image();
let canvas = canvasRef.current;
canvas.whiteboardImage = whiteboardImage
let ctx = canvas.getContext('2d');
image.onload = () => {
ctx.drawImage(image, 0, 0)
}
image.src = whiteboardImage
}
}, [whiteboardImage, open])
在绘制形状时,我在鼠标移动事件侦听器中如下所示:
if (canvas.toolState === 'line') {
if (canvas.isDrawing) {
// clear and get old whiteboard image
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
let image = new Image();
image.onload = () => {
ctx.drawImage(image, 0, 0)
}
image.src = canvas.whiteboardImage
// draw new line
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
ctx.lineTo(shape_start.x, shape_start.y);
ctx.stroke();
}
} // ... all the other shapes
这个问题发生在所有形状上,但不是铅笔工具,因为当我用铅笔作画时,我不必清理画布.
据我所知,只清除一次是不可能的.即使我将绘制的所有内容存储为对象及其路径,我仍然必须清除画布并重新绘制,这仍然会导致卡顿.
有什么我能做的吗?我如何让它变得顺畅?
A Minimal, Reproducable Example个
const Whiteboard = ({ open }) => {
const canvasRef = useRef(null);
const [whiteboardImage, setWhiteboardImage] = useState(null)
// socket event to receive whiteboard data from other clients
useEffect(() => {
socket.on('canvas-data', (data) => {
let image = new Image();
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
image.onload = () => {
ctx.drawImage(image, 0, 0)
}
image.src = data
setWhiteboardImage(data)
})
}, [])
// sets up mouselisteners if the canvas is open
useEffect(() => {
if (open) {
drawOnCanvas()
}
}, [open, canvasRef])
const drawOnCanvas = () => {
let canvas = canvasRef.current;
if (canvas) {
let ctx = canvas.getContext('2d');
let rect = canvas.getBoundingClientRect();
let sketch = document.querySelector('#sketch');
let sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
// initializing objects
let mouse = { x: 0, y: 0 };
let last_mouse = { x: 0, y: 0 };
let shape_start = { x: 0, y: 0 };
/* Mouse Capturing Work */
canvas.addEventListener('mousemove', function (e) {
mouse.x = e.pageX - rect.x;
mouse.y = e.pageY - rect.y;
}, false);
/* Drawing on Paint App */
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';
canvas.addEventListener('mousedown', function (e) {
shape_start = { x: mouse.x, y: mouse.y }
canvas.isDrawing = true;
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function () {
canvas.removeEventListener('mousemove', onPaint, false);
canvas.isDrawing = false;
let canvasImg = canvas.toDataURL('image/png')
socket.emit('canvas-data', canvasImg)
}, false);
// draws straight line with mouse
let onPaint = function () {
// clear and get old whiteboard image
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
if (whiteboardImage) {
let image = new Image();
image.onload = () => {
ctx.drawImage(image, 0, 0)
}
image.src = whiteboardImage
}
// draw new line
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
ctx.lineTo(shape_start.x, shape_start.y);
ctx.stroke();
}
}
return (
<div>
<canvas ref={canvasRef} />
</div>
)
}
我试着把它弄得尽可能少.在本例中,您只能绘制线条,没有像gif中那样的画笔工具.卡顿来自于我在onPaint函数中绘制形状的方式.清算和重新提款是问题所在.