分形图案核心是用代码生成自相似结构,需通过递归让每个形状分裂出更小自身;分形树只画主干而无分支,常因递归终止条件过早触发或深度参数未正确递减所致。

Canvas 做分形图案不是靠“画完就完”,而是靠递归、迭代或像素级复数运算——核心是「用代码生成自相似结构」,不是手动画。直接写 ctx.fillRect 一堆方块没用,得让每个形状主动分裂出更小的自己。
分形树为什么只画了一根线?drawTree 递归没触发
常见现象:页面只显示主干,分支全无;控制台没报错,但 drawTree 函数调用后没进入下一层递归。
- 检查递归终止条件是否过早触发,比如
if (depth 但初始 <code>depth传了0或负数 - 确认角度单位是弧度(
Math.PI / 180换算别漏),cos/sin输入角度制会返回 NaN,导致坐标计算失败,后续lineTo不生效 -
ctx.moveTo和ctx.lineTo必须成对出现且在beginPath()之后,否则线条不会渲染——尤其递归中容易忘记每次进函数都重置路径 - 示例片段里常把 y 轴翻转(
-y),如果没同步改moveTo的 y 参数,分支会画到画布外不可见区域
SierpinskiTriangle 三角形空心不填充?fill() 和 stroke() 混用问题
谢尔宾斯基三角形看起来只有轮廓、内部空白,或者干脆啥都不显示。
- 确保每次
triangle()调用后执行了ctx.fill()或ctx.stroke();只调moveTo/lineTo不会自动绘制 - 注意
fillStyle是否被覆盖(比如前面设置了ctx.fillStyle = 'transparent'),可加一句ctx.fillStyle = '#000'显式重置 - 递归中若用
fill(),需保证路径闭合(closePath()或显式回到起点);若用stroke(),则lineWidth太小(如0.1)在高 DPI 屏上可能不可见,建议设为1或2 - 性能提示:深度超过 8 层后,用
fill()会产生大量小三角形,帧率骤降;可改用stroke()+ 粗线模拟视觉密度
Mandelbrot 颜色全是黑的?z = z*z + c 迭代发散判断失效
曼德博集合渲染出来一片漆黑,或只有边缘一点杂色,说明绝大多数点都被判为“发散”,没走到收敛逻辑。
- 检查复数乘法是否手写错误,正确形式是:
newRe = re*re - im*im + cRe; newIm = 2*re*im + cIm;——漏掉2*或符号反了会导致全部发散 - 迭代上限(如
maxIter = 100)太低,z还没来得及表现收敛性就退出循环;建议从 50 起步,逐步试到 200 - 坐标映射错误:画布像素
(x, y)应映射到复平面c = (x/w * 3 - 2) + (y/h * 3 - 1.5)i这类范围,若直接用像素值当实部虚部,整个集合会缩成一个点 - 颜色映射时,若用
iter % 256取色,而iter全是 0 或 1,结果就是纯黑;应改为iter === maxIter ? 0 : iter * 255 / maxIter分档着色
动画卡顿、CPU 占满?requestAnimationFrame 里做了重绘但没节流
分形动画跑几秒就卡死,浏览器任务管理器里 JS 线程吃满 100%。
- 避免每帧都清空并重绘整个分形:谢尔宾斯基或分形树这类结构一旦生成就不变,只需首帧绘制,后续用
setTimeout控制生长节奏,而非requestAnimationFrame死循环 - 若真要动(如 Mandelbrot 缩放),必须限制每秒计算像素数——例如每次只算 1000 个点,剩余留到下一帧,用队列 +
requestIdleCallback更稳妥 - 别在动画循环里反复创建数组或对象(如每次新建
newArray(0,0)),提前分配好顶点池,复用内存 - 开启
ctx.globalCompositeOperation = 'lighter'可避免clearRect,适合粒子叠加类分形(如龙形曲线动画),但不适用于需要精确擦除的场景
真正难的不是写出第一个分形,而是控制它的“生长节奏”和“计算边界”——递归深度、迭代次数、坐标缩放系数,这三个数调错一个,图案就消失或卡死。它们不是魔法参数,而是数学约束在代码里的具象表达。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











