Canvas入门-绘制线

237 阅读2分钟

我有一棵发光树

背景

突然有一天,我想要用canvas绘制一棵二叉树,最好能来点发光特效。

IMG_202402288357_300x300 (1).png

绘制发光树思路

svg (1).svg

  • 递归绘制,根据输入起点坐标、长度、倾斜角度、深度等信息绘制树干
  • 每次绘制,长度、宽度、深度递减,深度为0时终止

具体实现

1、改变坐标系

众所周知,canvas的坐标原点是在左上角,X轴正方形向右,Y轴正方形下下。这个设置和向上生长的树有些差异,所以,我们简单更改一下坐标系。

svg (2).svg

2、绘制函数

/**
 * 绘制树
 * @param {Number} startX 起点X坐标
 * @param {Number} startY 起点Y坐标
 * @param {Number} length 树干长度
 * @param {Number} angle  倾斜角度,用弧度计算
 * @param {Number} depth  当前深度,为0时终止
 **/
 
function drawTree(startX, startY, length, angle, depth) {
  // TODO
}

3、每一根树干的起终点,小学生都会的数学计算

      // 已知 startX,startY, angle, length
      const endX = startX + Math.cos(angle) * length;
      const endY = startY + Math.sin(angle) * length;

4、随机颜色,最简单的随机rgb

    function random(n) {
      return Math.floor(Math.random() * n);
    }

    function randomColor() {
      return `rgb(${random(255)}, ${random(255)}, ${random(255)})`
    }

5、手把手教学,canvasAPI

   // 开始绘制
   ctx.beginPath();
   // 移动到起点位置
   ctx.moveTo(startX, startY);
   // 画线到终点位置
   ctx.lineTo(endX, endY);
   
   const color = randomColor();
   // 设置画笔颜色
   ctx.strokeStyle = color;
   // 设置限宽,随深度降低而变细
   ctx.lineWidth = depth * 1.5;
   
   // 设置一下连接处的样式
   ctx.lineCap = 'round';
   ctx.lineJoin = 'round';
   
   // 发光吧少年
   ctx.shadowBlur = 25;
   ctx.shadowColor= color;
   
   // 完成
   ctx.stroke();
   

5、递归搞起来

   // 从第二次开始,每层偏转30度
   const branchAngle = Math.PI / 6;
   // 修改这个值可以控制每个分支的长度缩放比例
   const branchLength = 0.7;
   
   // 左分枝
   drawTree(endX, endY, length * branchLength, angle - branchAngle, depth - 1);
   // 右分枝
   drawTree(endX, endY, length * branchLength, angle + branchAngle, depth - 1);

6、别忘记了首次调用

    function reset() {
      const { innerWidth: w, innerHeight: h, devicePixelRatio: dpr } = window;
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      // 改变坐标系
      ctx.translate(canvas.width / 2, canvas.height);
      ctx.scale(1, -1);
      const width = canvas.width;
      const height = canvas.height;

      const startX = 0;
      const startY = height / 3;
      const length = Math.min(w, h, 600) / 2;
      const angle = Math.PI / 2;
      const depth = 10;
      ctx.clearRect(-canvas.width / 2, 0, canvas.width, canvas.height);
      drawTree(startX, startY, length, angle, depth);
    }

上才艺