JavaScript Canvas实现月饼图案绘制:从单笔到对称绘图

作者:小圆点

时间:2026-10-31

浏览:620

本文详解如何使用HTML5 Canvas与JavaScript实现月饼图案绘制功能。通过监听PointerEvent处理鼠标与触摸事件,解决坐标偏移问题,并基于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,标识绘制状态已开启。

在Canvas上移动鼠标或手指时,触发pointermove事件。系统首先检查isDrawing的值以确认是否处于绘制状态。若已开启,则获取鼠标或触摸事件的坐标信息(e.clientX 和 e.clientY),并通过getBoundingClientRect()方法计算Canvas的相对位置,将屏幕坐标转换为Canvas内部坐标(以左上角为原点)。随后,将这些坐标赋值给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外,其他属性均相对于视口左上角计算。

效果图

此步骤看似可选,实则源于早期未编写* {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实现月饼绘制的完整流程,包括事件处理、坐标转换及对称算法。更多相关技术细节可参考本站过往文章或继续浏览后续内容,感谢支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章