某时某地,仔细留意花瓣飘来的方向吧,没错,那个地方就叫做爱情公寓

为心爱的人制造一场浪漫,只需一个canvas和一个动画循环。

第一步 定义 画布

首先,chrome浏览器安卓版下载先定义一个背景画布canvas,以及画布绘图能力cxt。

function startSakura() {
    // 定义canvas画布
    var canvas = document.createElement("canvas"), cxt;
    // 初始化canvas画布
    canvas.height = window.innerHeight;
    canvas.width = window.innerWidth;
    canvas.setAttribute(
    "style",
    "position: fixed;left: 0;top: 0;pointer-events: none;"
    );
    canvas.setAttribute("id", "canvas_sakura");
    document.getElementsByTagName("body")[0].appendChild(canvas);
    // 获取canvas画布上下文 提供在画布上绘图的方法和属性
    cxt = canvas.getContext("2d");
    ...
}

第二步 绘制单个 樱花瓣

此处用到cappleanvas的drawImage()方法。这个方法可以在画布上用canvas绘制任何图像,或其他画布内容,或视频的某一帧图像等等,也可以裁剪只画其中一部分。

语法:

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidappearanceth, dHeight)

参数意义:

  • image: image是画布绘制appointment的图像源,绘制到画布上的元素,可以是canvasElement、imageE接口crc错误计数lement、svgElCanvasemen接口类型t、videAPPoElement等一系列具有图像的接口自动化元素。

  • sx:绘制裁剪的图像源的x坐标位置。

  • sy:绘制裁剪的图像变量与函数源的y坐标位置。

  • sWidth: 绘制裁剪的图像源的canvas宽度变量名

  • sHeight: 绘制裁剪的图像的高度。

  • dx: 目标源在canvas画布上绘制的左上角的x坐标。

  • dy: 目标源在canvas画布上绘制的左上角的y坐标。

  • dWidtappearh:目标源在canvas画布上绘制的宽度,会自动根据图像源截取的宽度对比做缩放。

  • dHeight: 目标源在canvas画布上绘制的高度,会自动根据图像源截appear取的高度对比做缩放。

// 定义图像元素
var img = new Image()
img.src = './images/sakura.png'
// 在startSakura方法上加上
// drawImage(image, sx, sy, swidth, sheight, x, y, width, height)
cxt.drawImage(img, 0, 0, 40, 40);
// 图像加载开始画
img.onload = function() {
  startSakura();
};

效果如下:

 用canvas绘制一场浪漫樱花雨

(整张画布在坐标(0,0)处 画了单片花瓣)

第三步 绘制50瓣 樱花瓣

单位以点到面,在画布上花50个花瓣(大小等同,随机x y轴,不旋转)

translate(x,y)方法变量名的命名规则重新映射画布上的 (0, 0) 位置。也就是画布的平移
参数
x:X轴的偏移量
y:Y轴的偏移量

// 单花瓣 类
function Sakura(x, y, s) {
  this.x = x; // x轴坐标
  this.y = y; // y轴随机坐标
  this.s = s; // sakura大小
}
Sakura.prototype.draw = function(cxt) {
  var xc = (40 * this.s) / 4;
  // 画布平移
  cxt.translate(this.x, this.y);
  // drawImage(图像源,图像x坐标,图像y坐标,宽度, 高度)
  cxt.drawImage(img, 0, 0, 40 * this.s, 40 * this.s);
};
// 多花瓣 类
SakuraList = function() {
  this.list = [];
};
SakuraList.prototype.push = function(sakura) {
  this.list.push(sakura);
};
// 多个单瓣 组成 一组花瓣
SakuraList.prototype.draw = function(cxt) {
  for (var i = 0, len = this.list.length; i < len; i++) {
    this.list[i].draw(cxt);
  }
};

绘制成形:

var sakuraList = new SakuraList();
for (var i = 0; i < 50; i++) {
    // x轴随机 y轴随机 大小不变
    sakura = new Sakura(Math.random() * 20, Math.random() * 5, 1);
    sakuraList.push(sakura);
}
sakuraList.draw(cxt); // 绘制

效果图如下:

 用canvas绘制一场浪漫樱花雨

第四步 随机x轴 y轴、随机大小变量之间的关系、随机旋转角度、

随机函数getRandom如下canvas平台

function getRandom(option) {
  var ret, random;
  switch (option) {
    case "x":
      // x轴随机坐标
      ret = Math.random() * window.innerWidth;
      break;
    case "y":
      // y轴随机坐标
      ret = Math.random() * window.innerHeight;
      break;
    case "s":
      // sakura大小
      ret = Math.random();
      break;
    case "r":
      // sakura旋转角度
      ret = Math.random() * 6;
      break;
  }
  return ret;
}

这50片,每单个随机坐标随机大小随机角度

var sakuraList = new SakuraList();
for (var i = 0; i < 50; i++) {
    var sakura, randomX, randomY, randomS, randomR;
    randomX = getRandom("x");
    randomY = getRandom("y");
    randomR = getRandom("r");
    randomS = getRandom("s");
    sakura = new Sakura(randomX, randomY, randomS, randomR);
    sakuraList.push(sakura);
}
sakuraList.draw(cxt); // 绘制

效果如下:

 用canvas绘制一场浪漫樱花雨

第五步 花瓣动起来

定义一个动画控制函数,告诉浏览器希望执行动接口是什么

window.requestAnimatichrome安卓下载onFrame:

是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是canvas网页版按帧对网页进行重绘。

设置这个API的目的是为了让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

function startSakura() {
  //兼容性 不同浏览器的动画控制函数 告诉浏览器希望执行动画
  var requestAnimationFrame =
    window.requestAnimationFrame || //chrome
    window.mozRequestAnimationFrame || // Firefox
    window.webkitRequestAnimationFrame || // Chrome 兼容不同版本
    window.msRequestAnimationFrame || // IE
    window.oRequestAnimationFrame; // Opera
  // 定义canvas画布
  var canvas = document.createElement("canvas"), cxt;
  ...
   // 第四步花瓣循环
  ...
  // 定义一个stop变量 (循环:清空画布-绘制-重绘)
  stop = requestAnimationFrame(function() {
    cxt.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
    sakuraList.draw(cxt); // 绘制
    stop = requestAnimationFrame(arguments.callee); // 递归重绘
  });
}

到这一步还没完,因为每次sakuraList中的单类还是同样位置,即使用了动画控制函数window.requestAnimationFrame,每一帧还是在原来的位置,这样看起来还是没有在动。那么就变量之间的关系要【更新一下x轴y轴以及每一帧的旋转角度】

function getRandom(option) {
  var ret, random;
  switch (option) {
      ...
      case "fnx":
          // x轴随机函数
          random = -0.5 + Math.random() * 1;
          ret = function(x, y) {
            return x + 0.5 * random - 1.7;
          };
          break;
     case "fny":
      // y轴随机函数
      random = 1.5 + Math.random() * 0.7;
      ret = function(x, y) {
        return y + random;
      };
      break;
    case "fnr":
      // r轴随机函数
      random = Math.random() * 0.03;
      ret = function(r) {
        return r + random;
      };
      break;
  }
}

沿用上一appointment帧的x接口测试 y r,做一些小改动,保证肉眼看到的每一帧连贯性流畅性。

Sakura.prototype.update = function() {
  this.x = this.fn.x(this.x, this.y);
  this.y = this.fn.y(this.y, this.y);
  this.r = this.fn.r(this.r);
  if (
    // 判断是否超出边界
    this.x > window.innerWidth ||
    this.x < 0 ||
    this.y > window.innerHeight ||
    this.y < 0
  ) {
    // 如果超出边界 则重新生成随机坐标
    this.r = getRandom("fnr");
    if (Math.random() > 0.4) {
      // 如果随机值大于0.4 则重新生成x轴随机坐标
      this.x = getRandom("x");
      this.y = 0;
      this.s = getRandom("s");
      this.r = getRandom("r");
    } else {
      // 如果随机值小于0.4 则重新生成y轴随机坐标
      this.x = window.innerWidth;
      this.y = getRandom("y");
      this.s = getRandom("s");
      this.r = getRandom("r");
    }
  }
};
// 清空画布之前 调用一下更新函数
sakuraList.update(); // 更新

其中单花瓣Sakura.prototypeappreciate.draw这个方法加上两句话:
c接口和抽象类的区别xt.save(); // 保存先前的状态
cxt.restore(); /canvas上交/ 恢复之前保存的状态
注:两种方法必须搭配使用,否则没有效果
canvas动画: 先保存的后恢复,后保存的先恢复。


总结

从点到面、从静到动。知识点: canvas相关、window.reapproachquestAnimatioapproachnFrame浏览器动画函数window.requestAnimationFram相关。

代码

花瓣飘来的地方,曾经appstore,最好的朋友在身边,最爱的人在对面。如今,有的人还在追逐梦想,有的人已经背起行囊,奔向远方。这里有太多快乐与忧伤,太多遗憾与不舍。但新的故事,总要启航canvas翻译