核心是监听mousedown、mousemove、mouseup事件,配合beginPath()、moveTo()、lineTo()和stroke()绘图;需用isDrawing状态控制绘制时机,通过getBoundingClientRect()校正坐标,且lineWidth与strokeStyle应在beginPath()后设置以确保样式生效。
如何用
绑定鼠标事件画线
核心是监听
、
、
三个事件,配合
、
、
和
完成绘制。关键点在于:只有在鼠标按下(
)时才调用
,否则每次移动都会连到起点,画出乱线。
常见错误是把
放在
里——这会导致每画一像素都新建路径,线条断开;或者没判断
状态,导致松开鼠标后还在画。
实操建议:
用一个布尔变量
标记是否处于绘画状态,
设为
,
或
设为
中只在
为
时执行绘图逻辑
获取鼠标坐标要用
做偏移校正,不能直接用
,否则在有滚动或外边距时位置偏移
为什么
和
要在
后设置
Canvas 的绘图样式(如颜色、粗细、线帽)属于“当前路径状态”,但它们只对后续的
生效。如果在
前设置,而中间又调用了别的
,就可能被意外覆盖。
立即学习
“
前端免费学习笔记(深入)
”;
更隐蔽的问题是:某些浏览器(特别是旧版 Safari)对
小于 1 的处理不一致,实际渲染可能为 0 —— 所以最小建议设为
。
实操建议:
每次开始新笔画前,先设好
、
、
(推荐
避免锯齿)
不要复用同一个
对象混用不同样式画多条线,除非你明确控制了调用顺序
颜色尽量用十六进制(如
)或
,避免
在部分环境渲染异常
清空画布时为什么不能只用
看似合理,但它会清掉整个位图,包括你可能叠加的背景图、网格线、UI 元素等。真正需要“撤销”或“重置画板”时,往往要保留某些图层。
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
另一个坑是:直接改
也能清空,但会重置所有上下文状态(包括
、
),后续绘图需重新设置。
实操建议:
若需完整清空且保持上下文状态,用
是最轻量的选择
若要支持撤销/重做,应把每次笔画存为路径数组(含点序列、颜色、粗细),用
重绘,而不是操作像素
避免在循环中频繁调用
+ 重绘全部路径,性能差;可考虑双缓冲(两个
,一个画,一个存历史)
移动端触摸事件怎么适配
画板
触摸屏没有
,得用
、
、
,而且
默认会触发页面滚动,必须
。
更大的问题是:触摸点坐标来自
,不是
,且
可能一次返回多个触点,不加过滤就会乱画。
实操建议:
在
和
的事件处理器开头加
统一提取坐标:用
,再通过
计算相对画布位置
给
加上
,防止 iOS Safari 误触发缩放或滚动
注意 Android Chrome 有时会在快速滑动时丢触点,可考虑插值补点,但简单画板通常不需要
最易被忽略的是设备像素比(
):高清屏下若不缩放 canvas 内部尺寸,线条会发虚。初始化时需按比例放大
/
,再用 CSS 缩回显示尺寸——这个步骤漏掉,画出来的线永远不够锐利。
canvasmousedownmousemovemouseupbeginPath()moveTo()lineTo()stroke()mousedownbeginPath()beginPath()mousemoveisDrawingisDrawingmousedowntruemouseupmouseoutfalsemousemoveisDrawingtruegetBoundingClientRect()event.clientX/YlineWidthstrokeStylebeginPath()stroke()beginPath()stroke()lineWidthlineWidth = 1ctx.lineWidthctx.strokeStylectx.lineCap"round"ctx"#333"rgb()hsl()clearRect()clearRect(0, 0, canvas.width, canvas.height)canvas.width = canvas.widthlineWidthstrokeStyleclearRect()drawPath()clearRect()canvascanvasmousemovetouchstarttouchmovetouchendtouchmovepreventDefault()touches[0]clientX/Ytouchmovetouchstarttouchmoveevent.preventDefault()event.touches[0] || event.changedTouches[0]getBoundingClientRect()canvasstyle="touch-action: none;"window.devicePixelRatiocanvas.widthcanvas.height