js使用canvas实现绘制月饼
作者:Defineee
皓月当空,月圆中秋,在这个传统节日里,除了赏月、猜灯谜、赏花灯等习俗外,还有就是品尝美味的月饼。关于月饼,大家一定都知道月饼上会印着一个精美的图案与纹路。
效果图
HTML
这个 HTML 片段的主要组成部分包括一个canvas画布、一个背景图片、文字以及一组按钮功能。 关于css部分过于冗长大家可以直接去码上掘金阅读。
<div class="banner"> <canvas id="canvas" width="500" height="500"> </canvas> <div class="basebg"> </div> <img src="./bg.png" alt="" class="bg"> <img src="./sc1.png" alt="" class="sc1"> <div class="text">———— 但愿人长久,千里共婵娟 ————</div> <div class="btn"> <div class="model" onclick="model(1)">单笔</div> <div class="model" onclick="model(8)">对称</div> <div class="reset" onclick="reset()">清空画布</div> </div> </div>
初步绘制
我们来看一下绘制的逻辑,首先通过了事件监听器绑定了pointerdown、pointermove、pointerup。
pointerdown:当用户按下鼠标左键或触摸屏幕时,isDrawing
的变量设置为 true
,表示用户开启绘制。
pointermove:当用户在Canvas上移动鼠标或手指时,首先判断isDrawing
的值,确定用户是否开启绘制,如果为开启绘制,则获取鼠标或触摸事件的坐标信息(e.clientX
和 e.clientY
)并根据Canvas的相对位置(使用 getBoundingClientRect()
方法计算)将坐标信息转换为Canvas内部的坐标(以左上角为原点)。将其赋值给 point对象(point对象中的表示一条线段的起点与终点),调用draw函数绘制线条。
pointerup:用户释放鼠标左键或手指时触发将 isDrawing
变量设置为 false
,表示用户停止绘制。
const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const width = canvas.width; const height = canvas.height; let point = {}; let lineNum = 8; let isDrawing = false; canvas.addEventListener('pointerdown', (e) => { isDrawing = true; }); canvas.addEventListener('pointermove', (e) => { if (!isDrawing) return; const x = e.clientX - canvas.getBoundingClientRect().left const y = e.clientY - canvas.getBoundingClientRect().top point.x1 = x; point.y1 = y; draw(ctx, "#fdbb07", 5); point.x2 = x; point.y2 = y; }); canvas.addEventListener('pointerup', (e) => { isDrawing = false; });
pointerevnet与touchevent
一般来讲在电脑上我们都会使用MouseEvent,但是如果想要在手机上也能进行绘制,就需要使用PointerEvent和TouchEvent。
PointerEvent
是一个通用的事件类型,用于处理多种输入设备(包括鼠标、触摸屏、触控笔等)的输入事件。TouchEvent
用于处理触摸屏输入事件,如触摸、滑动等。所有在这里我们使用了PointerEvent
,因为它更加具备通用性。
不过在实际开发中,pointermove
事件出现绘制中断的情况,于是只能再添加一个touchmove
监听器。 需要注意的是TouchEvent
获取坐标的方式与PointerEvent
略有不同。
e.touches[0].clientX e.touches[0].clientY
getBoundingClientRect()
在获取坐标时,我们还做了一个操作,减去getBoundingClientRect()的top和left。
getBoundingClientRect返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有 left, top, right, bottom, x, y, width, 和 height 这几个以像素为单位的只读属性用于描述整个边框。除了 width 和 height 以外的属性是相对于视图窗口的左上角来计算的。
这步其实可有可无,是因为在一开始还没写css时发现的一个没写* {margin: 0;padding: 0;}
导致的问题。直接来看一下区别,一开始写了css还可能发现不了。
绘制函数
接下来是绘制的函数,传入了canvas对象、画笔颜色和线条宽度,再通过point中线段的起点与终点进行绘制。
function draw(canvas, color, lineWidth) { canvas.strokeStyle = color; canvas.lineWidth = lineWidth; canvas.lineCap = "round"; canvas.moveTo(point.x1, point.y1); canvas.lineTo(point.x2, point.y2); canvas.stroke(); }
对称绘制
上一步简单了实现了绘制功能,已经可以绘制月饼的图案,不过有的月饼上都是一些对称的的图案,简单的靠一支画笔完全不可能画出对称的效果。所以还需要一个能绘制对称图案的功能。 大致的方案是通过rotate
进行旋转,为了保证画笔的点位正常,需要使用translate
将坐标原点移动到 Canvas 的中心位置,对point坐标都要进行偏移操作。
function draw(canvas, color, lineWidth) { canvas.strokeStyle = color; canvas.lineWidth = lineWidth; canvas.lineCap = "round"; var r = 360 / lineNum * Math.PI / 180; for (let i = 0; i < lineNum; i++) { canvas.save(); canvas.translate(width / 2, height / 2); canvas.rotate(r * i); canvas.beginPath(); canvas.moveTo(point.x1 - width / 2, point.y1 - height / 2); canvas.lineTo(point.x2 - width / 2, point.y2 - height / 2); canvas.stroke(); canvas.restore(); } }
结语
至此,绘制的相关功能写完了,还有一个额外的操作是,对于图案线条添加了边框,本意是想增加线条的立体感,但是写完发现一点也感觉不到。由于在绘制过程中线条交叉会导致边框覆盖之前线条的情况,于是使用了一个简单粗暴的方案,在这个canvas中下面在添加一个canvas进行同步绘制单独的边框效果。
到此这篇关于js使用canvas实现绘制月饼的文章就介绍到这了,更多相关js canvas绘制月饼内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!