您好!欢迎访问家园网-www.jy.wang!

家园网

beginPath() 详细讲解

网络 作者:本站 点击:

一、含义

beginPath() 是 Canvas 2D 上下文中的一个方法,它的作用是开始一条新的路径,或者重置当前路径。调用这个方法后,之前定义的所有路径都会被清除,后续的路径绘制命令(如 lineTo()arc()rect() 等)会开始一个新的路径集合。


二、词源解析

单词词源含义
begin古英语 beginnan(开始)开始、启动
Path古希腊语 pathos(路径)→ 古英语 pæþ路径、轨迹
beginPath组合词开始新路径

词源故事

  • path 本意是“走出来的路”

  • 在计算机图形学中,路径是由一系列点、线、曲线连接而成的轨迹

  • beginPath() 就是“从零开始规划一条新路线”


三、语法


ctx.beginPath();

  • 参数:无

  • 返回值:无

  • 作用:清空当前路径列表,开始一个新的路径


四、为什么需要 beginPath()

类比:一张纸上的不同线条

想象你在纸上画画:

  • 如果你不换笔,一直画下去,所有线条都是连在一起的

  • 有时你希望画独立的图形(比如分开的两个圆)

  • 你需要抬起笔,移动到新位置,再开始画

beginPath() 就是那个“抬起笔”的动作。

代码对比

没有 beginPath() 的问题


// 画第一个圆
ctx.arc(100, 100, 50, 0, 2 * Math.PI);
ctx.strokeStyle = 'red';
ctx.stroke();
// 想画第二个圆(红色)
ctx.arc(200, 100, 50, 0, 2 * Math.PI);
ctx.stroke(); 
// 问题:第二个圆会继承之前的所有路径设置,并且和第一个圆共享路径

有 beginPath() 的正确写法


// 画第一个圆
ctx.beginPath();      // 清空路径,开始新路径
ctx.arc(100, 100, 50, 0, 2 * Math.PI);
ctx.strokeStyle = 'red';
ctx.stroke();         // 只描边第一个圆
// 画第二个圆
ctx.beginPath();      // 再次清空路径,开始全新的路径
ctx.arc(200, 100, 50, 0, 2 * Math.PI);
ctx.strokeStyle = 'red';  // 需要重新设置样式
ctx.stroke();         // 只描边第二个圆


五、路径是什么?

在 Canvas 中,路径是一系列点、线、曲线的集合。

路径的构成


ctx.beginPath();        // 开始新路径
ctx.moveTo(50, 50);     // 移动到起点
ctx.lineTo(150, 50);    // 画一条线到 (150,50)
ctx.lineTo(100, 150);   // 画一条线到 (100,150)
ctx.closePath();        // 关闭路径(画线回到起点)

路径的状态

  • 路径是累积的:每次调用绘图方法都会添加到当前路径

  • 路径是独立的:不同路径之间不会相互影响

  • 路径可以重复使用:同一个路径可以多次描边或填充


六、路径相关的三个关键方法

方法作用类比
beginPath()开始新路径,清空旧路径抬起笔,移动到新位置
closePath()关闭当前路径(画线回到起点)把路径连成封闭图形
stroke()/fill()真正绘制路径落笔,画出线条

示例:绘制两个独立三角形


// 第一个三角形
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(100, 50);
ctx.lineTo(75, 100);
ctx.closePath();    // 自动画线回到 (50,50)
ctx.fillStyle = 'red';
ctx.fill();
// 第二个三角形(不受第一个影响)
ctx.beginPath();    // 关键!不清空的话会和第一个路径混合
ctx.moveTo(150, 50);
ctx.lineTo(200, 50);
ctx.lineTo(175, 100);
ctx.closePath();
ctx.fillStyle = 'blue';
ctx.fill();


七、在五子棋棋盘代码中的作用


for (var j = 0; j < 10; j++) {
    for (var i = 0; i < 10; i++) {
        cav.beginPath();  // ← 每次绘制小方格前都开始新路径
        cav.strokeStyle = "rgb(147,109,70)";
        cav.rect(115 + j * 30, 85 + i * 30, 30, 30);
        cav.stroke();
    }
}

为什么每次循环都要 beginPath()

如果不加 beginPath(),会发生什么?


// 错误示范:没有 beginPath()
for (var j = 0; j < 10; j++) {
    for (var i = 0; i < 10; i++) {
        // cav.beginPath();  // 省略
        cav.rect(115 + j * 30, 85 + i * 30, 30, 30);
        cav.stroke();
    }
}

问题

  • 第一次循环:定义了第1个矩形路径,描边

  • 第二次循环:又添加第2个矩形到同一个路径

  • 第100次循环:路径里堆积了100个矩形

  • 每次 stroke() 都会把路径中所有矩形重新描边一次

结果

  • 越到后面的格子,被重复描边的次数越多

  • 线条颜色会叠加,越画越深

  • 性能也会变差

正确做法的好处

每次 beginPath() 清空旧路径,只保留当前要画的这一个矩形,保证每个格子只被描边一次,线条颜色均匀一致。


八、不调用 beginPath() 的后果示意图


第一次循环后路径: [矩形1]
第二次循环后路径: [矩形1, 矩形2] ← 堆积!
第三次循环后路径: [矩形1, 矩形2, 矩形3]
...
第100次循环后路径: [矩形1, 矩形2, ..., 矩形100]
每次 stroke() 都会把路径中所有矩形重新画一遍!

视觉效果

  • 第一个格子:描边1次 → 正常

  • 第二个格子:描边2次 → 稍深

  • 第三个格子:描边3次 → 更深

  • 第100个格子:描边100次 → 非常深


九、总结

问题答案
beginPath() 是什么?开始新路径的方法
为什么要用?避免路径堆积,确保每个图形独立
不用会怎样?路径会不断累积,图形被重复绘制
在棋盘中作用?保证100个小方格每个只描边一次
类比抬起笔,移动到新位置再落笔

一句话总结
beginPath() 就像画画时的“抬起笔”动作,让你能画出相互独立的图形,而不是把所有线条连在一起。

标签: