画一棵樱桃树

Published on
/
/趣玩前端
<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <title>画一颗樱桃树</title>
    <style>
      * {
        margin: 0;
        box-sizing: border-box;
        overflow: hidden;
      }

      body {
        background: #e6e2ca;
        width: 100%;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      body canvas {
        box-shadow: 0.2em 0.2em 2em #0008;
        border: none;
        outline: none;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <script src="https://cdn.jsdelivr.net/processing.js/1.4.8/processing.min.js"></script>
    <script>
      var sketchProc = function (processingInstance) {
        with (processingInstance) {
          size(600, 600);
          frameRate(60);
          smooth();

          textAlign(CENTER, CENTER);
          textSize(25);
          strokeCap(PROJECT);

          //used for controlling the animation
          var lenBranches = 0,
            lenLeaves = 0,
            lenFlowers = 0;

          //define the tree object/properties
          var tree = {
            x: 300,
            y: 500,
            len: 100,
            depth: 6,
            angle: -90,
            branches: [],
            leaves: [],
            flowers: [],
            colors: {
              from: color(59, 39, 8),
              to: color(145, 108, 49),
            },
          };

          //the recursive function (will be called from within itself)
          var addBranch = function (x, y, depth, angle, len) {
            //if the depth is zero then end the recursion
            if (depth === 0) {
              return;
            }

            //calculate the end points of the branch
            var x2 = x + cos((angle * Math.PI) / 180) * len;
            var y2 = y + sin((angle * Math.PI) / 180) * len;

            //add the new branch to the tree
            tree.branches.push({
              x1: x,
              y1: y,
              x2: x2,
              y2: y2,
              depth: depth,
              color: lerpColor(
                tree.colors.from,
                tree.colors.to,
                map(depth, tree.depth, 1, 0, 1)
              ),
            });

            //add some random leaves to the branches
            if (depth > 0 && depth < tree.depth - 3 && random() < 0.3) {
              for (var i = 0; i < 2; i++) {
                var l = len * random(0.1, 0.9);
                var tx = x + cos((angle * Math.PI) / 180) * l;
                var ty = y + sin((angle * Math.PI) / 180) * l;

                tree.leaves.push({
                  x: tx,
                  y: ty,
                  diameter: random(5, 10),
                  color: color(
                    random(80, 100),
                    random(150, 180),
                    random(90, 110)
                  ),
                  angle: random(angle - 60, angle + 60),
                });
              }
            }

            //add some random flowers to the end of the branches
            if (
              (depth === 1 && random() < 0.5) ||
              (depth === 2 && random() < 0.3)
            ) {
              tree.flowers.push({
                x: x2,
                y: y2,
                diameter: depth === 1 ? random(15, 25) : random(10, 15),
                color: color(
                  random(200, 255),
                  random(60, 100),
                  random(90, 120)
                ),
                angle: angle,
                gap: random(0, 90),
              });
            }

            //reduce the depth (extremely important to end your recursion)
            depth--;

            var l = len * random(0.6, 0.8);
            var x3 = x + cos((angle * Math.PI) / 180) * l;
            var y3 = y + sin((angle * Math.PI) / 180) * l;

            //call this function recursively
            addBranch(
              x2,
              y2,
              depth,
              angle - random(10, 50),
              len * random(0.75, 0.85)
            );
            addBranch(
              x2,
              y2,
              depth,
              angle + random(10, 50),
              len * random(0.75, 0.85)
            );
            addBranch(
              x3,
              y3,
              depth,
              angle + random(-30, 30),
              len * random(0.75, 0.85)
            );
          };

          //call the recusive function
          addBranch(tree.x, tree.y, tree.depth, tree.angle, tree.len);

          draw = function () {
            background(230, 226, 202);

            noStroke();
            fill(50, 30);
            ellipse(tree.x, tree.y + 5, 200, 35);

            //draw the trees
            for (var i = 0; i < lenBranches; i++) {
              var branch = tree.branches[i];

              //set the stroke opacity based on the branch depth
              stroke(branch.color, 50 + branch.depth * 35);

              //set the stroke thickness based on the branch depth
              strokeWeight(1 + branch.depth);

              //draw the branch
              line(branch.x1, branch.y1, branch.x2, branch.y2);
            }

            //used for animating the branches
            lenBranches = constrain(lenBranches + 1, 0, tree.branches.length);

            //if all the branches are displayed then show the leaves
            if (lenBranches === tree.branches.length) {
              //draw the leaves
              for (var i = 0; i < lenLeaves; i++) {
                var leaf = tree.leaves[i];

                pushStyle();
                noStroke();
                fill(leaf.color);
                arc(
                  leaf.x,
                  leaf.y,
                  leaf.diameter,
                  leaf.diameter,
                  ((leaf.angle + 70) * Math.PI) / 180,
                  ((leaf.angle + 290) * Math.PI) / 180
                );
                popStyle();
              }

              //used for animating the leaves
              lenLeaves = constrain(lenLeaves + 1, 0, tree.leaves.length);
            }

            //if all the leaves are displayed then show the flowers
            if (lenLeaves === tree.leaves.length) {
              //draw the flowers
              for (var i = 0; i < lenFlowers; i++) {
                var flower = tree.flowers[i];

                pushStyle();
                noStroke();
                fill(flower.color);
                arc(
                  flower.x,
                  flower.y,
                  flower.diameter,
                  flower.diameter,
                  ((flower.angle + flower.gap) * Math.PI) / 180,
                  ((flower.angle + 360 - flower.gap) * Math.PI) / 180
                );
                popStyle();
              }

              if (++lenFlowers === tree.flowers.length + 1) {
                noLoop();
              }
            }

            //display how many branches there are
            fill(50, 50);
            // text(
            //   tree.branches.length +
            //     ' branches, ' +
            //     tree.leaves.length +
            //     ' leaves, ' +
            //     tree.flowers.length +
            //     ' flowers',
            //   300,
            //   30
            // );
            text('点击画一棵樱桃树', 300, 570);
          };

          mouseClicked = function () {
            tree.branches.length = 0;
            tree.leaves.length = 0;
            tree.flowers.length = 0;

            lenBranches = 0;
            lenLeaves = 0;
            lenFlowers = 0;

            tree.angle = random(-100, -80);

            addBranch(tree.x, tree.y, tree.depth, tree.angle, tree.len);

            loop();
          };
        }
      };

      var canvas = document.getElementById('canvas');
      var processingInstance = new Processing(canvas, sketchProc);
    </script>
  </body>
</html>