canvas绘制漫天飞舞的樱花

首先,先看效果。

猛戳这里查看效果

接下来,我们看看具体怎么实现这个效果

第一步,我们先画出一棵树的主体。

画树的使用的原理是,定义一个起始点,从这个点开始,向一个角度移动一段距离。得到另一个点。画出一条线连接两个点。以新得到的点,依旧向这个角度,移动一段距离。得到第三个点,连写第二第三个点。以此类推。一定步长之后,就得到一条射线。我们根据自然界中的真实树的情况,这条线越来越细,直到最细地方结束。

var treeCanvas = document.getElementById("tree"),
    cw = window.innerWidth,
    ch = window.innerWidth,
    tCxt = treeCanvas.getContext("2d"),
    rootTop = ch - 200,
    treeColor = "#FFF";
treeCanvas.width = window.innerWidth;
treeCanvas.height = window.innerHeight ;
function drawTree(x, y, deg, step){
    var x1 = x + Math.cos(deg) * step ;//越细的枝干越短,所以以步长来做
    var y1 = y + Math.sin(deg) * step ;
    tCxt.beginPath();
    tCxt.lineWidth = step / 3;//树干越来越细
    tCxt.moveTo(x, y);
    tCxt.lineTo(x1, y1);
    tCxt.strokeStyle = treeColor ;
    tCxt.stroke();
    step -- ;
    if(step > 0){
        drawTree(x1,y1,deg,step);
    }
}
drawTree(treeCanvas.width/2,rootTop,-Math.PI/2,30);

树干出来之后,要做分叉,每个分叉其实就是向另一个方向的树干。而且分叉要比主干细一些。我们在第二阶段树干位置,每三步向左右分叉。

if(step > 0){
    drawTree(x1, y1, deg, step);
    if(step % 3 == 1)
        drawTree(x1, y1, deg+0.5, Math.round(step/1.13));//右分叉
    if(step % 3 == 0)
        drawTree(x1, y1, deg-0.5, Math.round(step/1.13));//左分叉
}

这样一棵树的主干基本上就已经完成了。我们在树的末端几个节点,画一个粉色的半透明的圆。当做樱花。为了保证所有樱花不是千篇一律的一个角度,我们可以随机一个起始角度。

function drawTree(x, y, deg, step){
    var x1 = x + Math.cos(deg) * step ;//越细的枝干越短,所以以步长来做
    var y1 = y + Math.sin(deg) * step ;
    tCxt.beginPath();
    tCxt.lineWidth = step/3;//树干越来越细
    tCxt.moveTo(x, y);
    tCxt.lineTo(x1, y1);
    tCxt.strokeStyle = treeColor ;
    tCxt.stroke();
    if(step < 5 ){//在末端五个节点,画一个半圆,作为樱花效果 var r = 2 + Math.random() * 2 tCxt.fillStyle = flowerColor; tCxt.arc(x1 + Math.random()*3, y1 + Math.random() * 3, r, 0, Math.PI) tCxt.fill(); } step -- ; if(step > 0){
        drawTree(x1, y1, deg, step);
        if(step % 3 == 1)
            drawTree(x1, y1, deg + 0.5, Math.round(step/1.13));//右分叉
        if(step % 3 == 0)
            drawTree(x1, y1, deg-0.5, Math.round(step/1.13));//左分叉
    }
}

这个时候,如果没有特别的要求的,基本算是已经完成了。

之后再要做的就是精益求精,对现在效果做出微调。

1、树干都是直线,在计算下一个点的时候,做一些偏移。

2、樱花树形态比较扁平。给X轴方向上偏移稍微大点,Y轴稍微偏小一点。

3、至少做两种花瓣颜色,一种稍微深一些,一种浅一些。

4、在新建一个canvas层,做一些飘落樱花的效果。

5、在分叉,画花瓣等地方多使用一些随机数,树形状不能太单一

完整代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>樱花飘落</title>
<meta name="description" content="">
<meta name="keywords" content="">
<style type="text/css">
  canvas{
      position: absolute;
      left: 0;
      top: 0;
  }
</style>
</head>
<body>
  <body bgcolor="#000000">
  <canvas id="treeAndFlower"></canvas>
  <canvas id="animateFlower"></canvas>
  <script type="text/javascript">
    var treeCanvas = document.getElementById("treeAndFlower"),
        tCtx = treeCanvas.getContext('2d'),
        flowerCanvas = document.getElementById("animateFlower"),
        fCtx = flowerCanvas.getContext("2d"),
        cw = window.innerWidth,
        ch = window.innerHeight;
    treeCanvas.width = flowerCanvas.width = cw;
    treeCanvas.height = flowerCanvas.height = ch;
    var flowerList = [],
        rootTop = ch - 150,
        flowerColor = "rgba(255,192,203,.3)", //花色
        flowerColorDeep = "rgba(241,158,194,.5)", //花色深
        treeColor2 = "rgba(255,192,203,.5)", //树枝颜色
        treeColor = "#FFF", //树干颜色
        fallList = [], //飘落樱花列表
        g = 0.01, //重力加速度
        gWind = 0.005, //风力加速度
        limitSpeedY = 1, //Y速度上限
        limitSpeedX = 1; //X速度上限
    fCtx.shadowColor= "#FFF" ;
    fCtx.shadowBlur = 10 ;
    function drawTree(x, y, deg, step) {
      var addDeg = step % 2 === 0 ? 0.1 : -0.1,
          x1 = x + Math.cos(deg + addDeg) * (step + 4) * 0.8,
          y1 = y + Math.sin(deg + addDeg) * (step - 1) * 0.8;
      tCtx.beginPath();
      tCtx.lineWidth = step / 3;
      tCtx.moveTo(x, y);
      tCtx.lineTo(x1, y1);
      tCtx.strokeStyle = step > 5 ? treeColor : treeColor2;
      tCtx.stroke();
      if (step > 20) {
        tCtx.fillStyle = treeColor;
        tCtx.arc(x, y, step / 6, 0, 2 * Math.PI);
        tCtx.fill();
      }
      if (step < 3 || (step < 23 && Math.random() > 0.1)) {
        var color = [flowerColorDeep, flowerColor][Math.round(Math.random() + 0.2)],
            r = 2 + Math.random() * 2;
        tCtx.fillStyle = color;
        tCtx.arc(x1 + Math.random() * 3, y1 + Math.random() * 3, r, 0, Math.PI);
        tCtx.fill();
        flowerList.push({
          x: x,
          y: y,
          sx: Math.random() - 0.5,
          sy: 0,
          color: color,
          r: r,
          deg: deg
        });
      }
      step --;
      if (step > 0) {
        drawTree(x1, y1, deg, step);
        if (step % 3 === 0) {
          drawTree(x1, y1, deg + 0.2 + Math.random() * 0.3, Math.round(step/1.13));
        }
        if (step % 3 === 1) {
          drawTree(x1, y1, deg - 0.2 - Math.random() * 0.3, Math.round(step/1.13));
        }
      }
    }
    function update() {
      if (Math.random() > 0.3) {
        fallList.push(flowerList[Math.floor(Math.random() * flowerList.length)]);
      }
      fCtx.clearRect(0, 0, cw, ch);
      for (var i=0; i<fallList.length; i++) {
        var fall = fallList[i];
        if (fall.sy < limitSpeedY) {
          fall.sy += g;
        }
        fall.sx += gWind;
        fall.x += fall.sx;
        fall.y += fall.sy;
        fall.deg += fall.sx * 0.05;
        if (fall.y > rootTop) {
          fallList.splice(i, 1);
          i --;
          continue;
        }
        fCtx.beginPath();
        fCtx.fillStyle = fall.color;
        fCtx.arc(fall.x, fall.y, fall.r, fall.deg, fall.deg + 1.3 * Math.PI);
        fCtx.fill();
      }
      requestAnimationFrame(update);
    }
    drawTree(cw / 2, rootTop, -Math.PI/2, 30);//执行
    update();
  </script>
</body>
</html>

原文地址:http://www.cnblogs.com/shb190802/p/6606699.html

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章