用Canvas画一棵树

721 阅读1分钟

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

点生线,线生面,只要有了基本的构图元素,我们可以用canvas画出各种图案,画棵树简直就是小case了。

画树的思路很简单,大树干分叉出若干的树枝,以不同角度和长度延伸出去并逐渐变细,树枝的末端再延伸树枝,所以很容易想到用递归来实现。

所以递归函数里是在画一层树枝,需要的参数就是:

startX:树枝起始的x轴坐标

startY:树枝起始的y轴坐标

length:长度

angle:分叉角度

depth:剩余层数

branchWidth:该层的树枝粗细

于是我们可以实现画出躯干的函数:

drawTree(startX, startY, length, angle, depth, branchWidth) {
      let _this = this;
      var newLength,
        newAngle,
        newDepth,
        endX,
        endY,
        maxAngle = (2 * Math.PI) / 5,
        subBranches;
      //开始绘制路径
      _this.ctx.beginPath();
      _this.ctx.moveTo(startX, startY);
      endX = startX + Math.cos(angle) * length;
      endY = startY + Math.sin(angle) * length;
 
      _this.ctx.lineCap = "round";
      _this.ctx.lineWidth = branchWidth;
      _this.ctx.lineTo(endX, endY);
 
      _this.ctx.strokeStyle = "#442525"; // 树干棕色
 
      _this.ctx.stroke();
      if (depth <= 4) {
        _this.leafArr.push([endX, endY]);
      }
      newDepth = depth - 1;
      if (newDepth <= 0) {
        return; // 如果绘制到叶子节点后就结束递归
      }
 
      subBranches = _this.getRandomInt(2, 3);
      branchWidth *= 0.75;
      for (var i = 0; i < subBranches; i++) {
        newLength = length * 0.75 + 0.25 * length *  Math.random();
        newAngle = angle +  Math.random() * maxAngle - maxAngle * 0.5;
        _this.drawTree(endX, endY, newLength, newAngle, newDepth, branchWidth);
      }
}

image.png

然后是画树叶,树叶是分布在比较末端的树枝周围的,所以用leafArr数组记录一下靠末端树枝路径的终结点坐标,然后画出叶子:

drawAllLeaves() {
      let _this = this;
 
      _this.leafArr.forEach(item => {
        _this.drawLeaf(item[0], item[1], _this.getRandomInt(15, 25));
      });
},
drawLeaf(x, y, num) {
      let _this = this;
      for (let i = 0; i < num; i++) {
        x += (Math.random() - 0.5) * _this.getRandomInt(0, 25);
        y += (Math.random() - 0.5) * _this.getRandomInt(0, 25);
        _this.ctx.beginPath();
        let num1 = Math.random();
        _this.ctx.fillStyle =
          "rgba(247," +
          (Math.random() * 190) +
          ",190," +
          (num1 >= 0.5 ? num1 - 0.2 : num1) +
          ")";
        _this.ctx.arc(x, y, _this.getRandomInt(2, 5), 0, 2 * Math.PI);
        _this.ctx.fill();
      }
  }

image.png

image.png