js使用canvas实现绘制月饼

 更新时间:2023年09月18日 16:06:51   作者:Defineee  
皓月当空,月圆中秋,在这个传统节日里,除了赏月、猜灯谜、赏花灯等习俗外,还有就是品尝美味的月饼,本文就来使用canvas绘制一个精美的月饼吧

皓月当空,月圆中秋,在这个传统节日里,除了赏月、猜灯谜、赏花灯等习俗外,还有就是品尝美味的月饼。关于月饼,大家一定都知道月饼上会印着一个精美的图案与纹路。

效果图

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.clientXe.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,但是如果想要在手机上也能进行绘制,就需要使用PointerEventTouchEvent

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绘制月饼内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解JSON.stringify()的5个秘密特性

    详解JSON.stringify()的5个秘密特性

    这篇文章主要介绍了详解JSON.stringify()的5个秘密特性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • JS代码实现table数据分页效果

    JS代码实现table数据分页效果

    这篇文章主要介绍了JS代码实现table数据分页效果的相关资料,非常不错,代码简答易懂,非常实用,需要的朋友可以参考下
    2016-05-05
  • Bootstrap CSS组件之导航条(navbar)

    Bootstrap CSS组件之导航条(navbar)

    这篇文章主要为大家详细介绍了Bootstrap CSS组件之导航条(navbar),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • 其实你可以少写点if else与switch(推荐)

    其实你可以少写点if else与switch(推荐)

    switch case与if else的区别:switch case会生成一个跳转表来指示实际的case分支的地址,而if...else却需要遍历条件分支直到命中条件,下面这篇文章主要给大家介绍了关于if else与switch在使用中的一些技巧,需要的朋友可以参考下
    2019-01-01
  • 原生js图片轮播效果实现代码

    原生js图片轮播效果实现代码

    这篇文章主要为大家详细介绍了基于原生js实现图片轮播效果的具体代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 温习Javascript基础语法之词法结构

    温习Javascript基础语法之词法结构

    javascript是一门简单的语言,也是一门复杂的语言。这篇文章主要介绍了温习Javascript基础语法之词法结构的相关资料,需要的朋友可以参考下
    2016-05-05
  • bootstrap3 dialog 更强大、更灵活的模态框

    bootstrap3 dialog 更强大、更灵活的模态框

    这篇文章主要介绍了bootstrap3 dialog 更强大、更灵活的模态框,本文通过效果展示实例代码详解,需要的朋友可以参考下
    2017-04-04
  • 原生JS下拉加载插件分享

    原生JS下拉加载插件分享

    本文主要分享了原生JS下拉加载插件的实现代码。具有一定的参考价值,需要的朋友一起来看下吧
    2016-12-12
  • JavaScript获取图片像素颜色并转换为box-shadow显示

    JavaScript获取图片像素颜色并转换为box-shadow显示

    这篇文章主要介绍了JavaScript获取图片像素颜色并转换为box-shadow显示的方法,用到了HTML5中的FileReader API和getImageData,转换为的CSS3 box-shadow也要注意浏览器的兼容问题,需要的朋友可以参考下
    2016-03-03
  • JS简单生成随机数(随机密码)的方法

    JS简单生成随机数(随机密码)的方法

    这篇文章主要介绍了JS简单生成随机数(随机密码)的方法,简单分析了javascript随机数相关函数并结合具体实例形式分析了随机数的相关生成技巧,需要的朋友可以参考下
    2017-05-05

最新评论