| | |
| | | // Canvas上下文 |
| | | let ctx = null; |
| | | let isDrawing = false; |
| | | let lastX = 0; |
| | | let lastY = 0; |
| | | let lastDrawPoint = null; // 上次绘制到的位置(用于线段连接) |
| | | |
| | | // 渲染控制(解决低性能机型 draw 异步导致丢帧断点) |
| | | let needsRender = false; // 是否有待渲染的指令 |
| | | let renderLoop = null; // 渲染循环定时器 |
| | | let isRendering = false; // 是否正在执行 draw |
| | | let renderTimeout = null; // draw 超时保护 |
| | | |
| | | // 配置 |
| | | const colors = ['#000000', '#FF0000', '#0000FF', '#4CAF50']; |
| | |
| | | // 初始化Canvas |
| | | const initCanvas = () => { |
| | | console.log('初始化Canvas...'); |
| | | console.log('Canvas尺寸:', props.canvasWidth, 'x', props.canvasHeight); |
| | | |
| | | // 停止可能存在的渲染循环 |
| | | stopRenderLoop(); |
| | | |
| | | // 清空已有上下文 |
| | | ctx = null; |
| | |
| | | return; |
| | | } |
| | | |
| | | console.log('触摸开始:', e.touches[0]); |
| | | isDrawing = true; |
| | | hasDrawing.value = true; |
| | | |
| | | const touch = e.touches[0]; |
| | | lastX = touch.x; |
| | | lastY = touch.y; |
| | | lastDrawPoint = { x: touch.x, y: touch.y }; |
| | | |
| | | // 开始新路径 |
| | | // 起笔画一个圆点(解决点击不画的问题) |
| | | ctx.beginPath(); |
| | | ctx.moveTo(lastX, lastY); |
| | | ctx.draw(true); |
| | | ctx.arc(touch.x, touch.y, currentWidth.value / 2, 0, 2 * Math.PI); |
| | | ctx.setFillStyle(currentColor.value); |
| | | ctx.fill(); |
| | | needsRender = true; |
| | | |
| | | // 启动渲染循环 |
| | | startRenderLoop(); |
| | | }; |
| | | |
| | | // 触摸移动 |
| | | // 触摸移动(每次直接画线段,用渲染循环控制 draw 频率) |
| | | const onTouchMove = (e) => { |
| | | if (!isDrawing || !ctx) return; |
| | | |
| | |
| | | const x = touch.x; |
| | | const y = touch.y; |
| | | |
| | | // 绘制线条 |
| | | // 立即画线段(指令加入队列,不调 draw) |
| | | ctx.beginPath(); |
| | | ctx.moveTo(lastDrawPoint.x, lastDrawPoint.y); |
| | | ctx.lineTo(x, y); |
| | | ctx.setStrokeStyle(currentColor.value); |
| | | ctx.setLineWidth(currentWidth.value); |
| | | ctx.setLineCap('round'); |
| | | ctx.setLineJoin('round'); |
| | | ctx.stroke(); |
| | | ctx.draw(true); |
| | | |
| | | // 更新最后位置 |
| | | lastX = x; |
| | | lastY = y; |
| | | lastDrawPoint = { x, y }; |
| | | needsRender = true; |
| | | }; |
| | | |
| | | // 启动渲染循环(定时批量调用 draw,避免每次 touchmove 都 draw 导致丢帧) |
| | | const startRenderLoop = () => { |
| | | if (renderLoop) return; |
| | | renderLoop = setInterval(() => { |
| | | if (needsRender && !isRendering) { |
| | | needsRender = false; |
| | | isRendering = true; |
| | | ctx.draw(true, () => { |
| | | isRendering = false; |
| | | }); |
| | | // 超时保护:防止 draw 回调不执行导致卡死 |
| | | if (renderTimeout) clearTimeout(renderTimeout); |
| | | renderTimeout = setTimeout(() => { |
| | | isRendering = false; |
| | | }, 50); |
| | | } |
| | | }, 16); |
| | | }; |
| | | |
| | | // 停止渲染循环 |
| | | const stopRenderLoop = () => { |
| | | if (renderLoop) { |
| | | clearInterval(renderLoop); |
| | | renderLoop = null; |
| | | } |
| | | if (renderTimeout) { |
| | | clearTimeout(renderTimeout); |
| | | renderTimeout = null; |
| | | } |
| | | isRendering = false; |
| | | }; |
| | | |
| | | // 触摸结束 |
| | | const onTouchEnd = () => { |
| | | console.log('触摸结束'); |
| | | isDrawing = false; |
| | | // 停止渲染循环 |
| | | stopRenderLoop(); |
| | | // 确保最后的指令被渲染 |
| | | if (needsRender) { |
| | | needsRender = false; |
| | | ctx.draw(true); |
| | | } |
| | | }; |
| | | |
| | | // 选择颜色 |
| | |
| | | return; |
| | | } |
| | | |
| | | console.log('清空画布'); |
| | | // 停止渲染循环 |
| | | stopRenderLoop(); |
| | | needsRender = false; |
| | | |
| | | // 清空画布 |
| | | ctx.setFillStyle('#FFFFFF'); |