前语

最近总是梦见一些小时候的故事,印象最深刻的便是夏天坐在屋顶上,看着满天的繁星,一颗,两颗,三颗…情不自禁地开端了数星星的进程。不经意间,一颗流星划过夜间,尽管仅仅转瞬即逝,但它似乎比夜空中的其它繁星更吸引着我。听白叟说,看见流星的时候许愿,希望是可以实现的,此时早已把数星星抛之脑后,开端期待着下一颗流星的呈现。可是那天晚上,流星再也没有呈现,这也成了自己小时候的一个惋惜。

今日,我决议用canvas为大家带来一场流星雨视觉盛宴。

我用canvas带你看一场流星雨

假如这篇文章有帮助到你,❤️重视+点赞❤️鼓舞一下作者,文章公众号首发,重视 前端南玖 第一时间获取最新文章~

需求剖析

首先咱们需要的元素有:夜空、满天繁星、流星雨。

满天繁星: 这个其实便是画上一个个点,然后不断的经过色彩交替,营造出一种星星闪耀的意境。

流星雨: 流星处于他自己的运动轨道之中,当时的方位最亮,轮廓最清晰,而之前划过的当地离当时方位轨道间隔越远就越昏暗越含糊,其实它便是一个突变的进程,恰巧canvas有办法可以创立一个沿参数坐标指定的直线的突变。然后让它从右上向左下移动,这样就能营造一种流星雨的作用,一同实现动画的循环。

OK,需求剖析结束,准备动手开干~

我用canvas带你看一场流星雨

实现进程

1.制作满天繁星

//创立一个星星目标
class Star {
  constructor() {
    this.x = windowWidth * Math.random(); //横坐标
    this.y = 5000 * Math.random(); //纵坐标
    this.text = "."; //文本
    this.color = "white"; //色彩
  }
  //初始化
  init() {
    this.getColor();
  }
  //制作
  draw() {
    context.fillStyle = this.color;
    context.fillText(this.text, this.x, this.y);
  }
}
//画星星
for (let i = 0; i < starCount; i++) {
  let star = new Star();
  star.init();
  star.draw();
  arr.push(star);
}

来看下此时的作用:

我用canvas带你看一场流星雨

夜空中的满天繁星现在是有了,可是缺乏一点意境,咱们得想办法让这些繁星都闪耀起来。

2.满天繁星闪起来

//创立一个星星目标
class Star {
  constructor() {
    this.x = windowWidth * Math.random(); //横坐标
    this.y = 5000 * Math.random(); //纵坐标
    this.text = "."; //文本
    this.color = "white"; //色彩
  }
	// 获取随机色彩
  getColor() {
    let _r = Math.random();
    if (_r < 0.5) {
      this.color = "#333";
    } else {
      this.color = "white";
    }
  }
  //初始化
  init() {
    this.getColor();
  }
  //制作
  draw() {
    context.fillStyle = this.color;
    context.fillText(this.text, this.x, this.y);
  }
}
//画星星
for (let i = 0; i < starCount; i++) {
  let star = new Star();
  star.init();
  star.draw();
  arr.push(star);
}
//繁星闪起来
let t1
function playStars() {
  for (let n = 0; n < starCount; n++) {
    arr[n].getColor();
    arr[n].draw();
  }
  t1 = requestAnimationFrame(playStars);
}

繁星闪耀的元素就在于这个getColor办法,经过不断地切换星星的色彩,来到达星星闪耀的作用。

再来看看这时的作用:

我用canvas带你看一场流星雨

此时的自己就可以开端数星星了,一颗,两颗,三颗…

3.制作流星

简略点了解,流星其实便是一条突变的线段,当时的方位最亮,轮廓最清晰,而之前划过的当地离当时方位轨道间隔越远就越昏暗越含糊。

这儿的关键API是createLinearGradient,用于创立一个沿参数坐标指定的直线的突变。

我用canvas带你看一场流星雨

语法:

CanvasGradient ctx.createLinearGradient(x0, y0, x1, y1);

  • x0:起点的 x 轴坐标。
  • y0:起点的 y 轴坐标。
  • x1:结尾的 x 轴坐标。
  • y1:结尾的 y 轴坐标。

使用createLinearGradient() 办法初始化一个线性突变。在这个线性突变中添加三种色彩,到达一种突变的作用来模拟出流星划过夜空的状态。

/**制作流星**/
  draw() {
    //制作一个流星的函数
    context.save();
    context.beginPath();
    context.lineWidth = 1; //宽度
    context.globalAlpha = this.alpha; //设置透明度
    //创立横向突变色彩,起点坐标至结尾坐标
    let line = context.createLinearGradient(
      this.x,
      this.y,
      this.x + this.width,
      this.y - this.height
    );
    //分段设置色彩
    line.addColorStop(0, "white");
    line.addColorStop(0.3, this.color1);
    line.addColorStop(0.6, this.color2);
    context.strokeStyle = line;
    //起点
    context.moveTo(this.x, this.y);
    //结尾
    context.lineTo(this.x + this.width, this.y - this.height);
    context.closePath();
    context.stroke();
    context.restore();
  }

现在咱们来看一看当年的那个流星:

我用canvas带你看一场流星雨

4.流星划过夜空

流星有了,现在咱们得想办法让它动起来。这儿其实便是经过不断地核算方位来到达流星动起来的作用。

move() {
    //清空流星像素
    let x = this.x + this.width - this.offset_x;
    let y = this.y - this.height;
    context.clearRect(x - 3, y - 3, this.offset_x + 5, this.offset_y + 5);
    //重新核算方位,往左下移动
    this.countPos();
    //透明度增加
    this.alpha -= 0.002;
    //重绘
    this.draw();
  }

我用canvas带你看一场流星雨

现在,咱们就可以看到当年的那颗流星了,是不是很激动。稍安勿躁,为了弥补当年的惋惜,这儿决议来一场从未实在见过的流星雨。

5.流星雨

写到这儿,实现流星雨其实就很简略了,咱们只需要再多生成一些流星,为它们各自分配不同的坐标即可。

let t2
// 创立流星雨目标
class MeteorRain {
  constructor() {
    this.x = -1;
    this.y = -1;
    this.length = -1; //长度
    this.angle = 30; //倾斜角度
    this.width = -1; //宽度
    this.height = -1; //高度
    this.speed = 1; //速度
    this.offset_x = -1; //横轴移动偏移量
    this.offset_y = -1; //纵轴移动偏移量
    this.alpha = 1; //透明度
    this.color1 = ""; //流星的色彩
    this.color2 = ""; //流星的色彩
  }
  init() {
    //初始化
    this.getPos();
    this.alpha = 1; //透明度
    this.getRandomColor();
    //最小长度,最大长度
    let x = Math.random() * 80 + 150;
    this.length = Math.ceil(x);
    x = Math.random() + 0.5;
    this.speed = Math.ceil(x); //流星的速度
    let cos = Math.cos((this.angle * 3.14) / 180);
    let sin = Math.sin((this.angle * 3.14) / 180);
    this.width = this.length * cos;
    this.height = this.length * sin;
    this.offset_x = this.speed * cos;
    this.offset_y = this.speed * sin;
  }
  /**获取随机色彩函数**/
  getRandomColor() {
    let a = Math.ceil(255 - 240 * Math.random());
    //中段色彩
    this.color1 = "rgba(" + a + "," + a + "," + a + ",1)";
    //结束色彩
    this.color2 = "black";
  }
  /**重新核算流星坐标的函数**/
  countPos() {
    //
    //往左下移动,x减少,y增加
    this.x = this.x - this.offset_x;
    this.y = this.y + this.offset_y;
  }
  /**获取随机坐标的函数**/
  getPos() {
    //
    //横坐标
    this.x = Math.random() * window.innerWidth; //窗口高度
    //纵坐标
    this.y = Math.random() * window.innerHeight; //窗口宽度
  }
  /**制作流星**/
  draw() {
    //制作一个流星的函数
    context.save();
    context.beginPath();
    context.lineWidth = 1; //宽度
    context.globalAlpha = this.alpha; //设置透明度
    //创立横向突变色彩,起点坐标至结尾坐标
    let line = context.createLinearGradient(
      this.x,
      this.y,
      this.x + this.width,
      this.y - this.height
    );
    //分段设置色彩
    line.addColorStop(0, "white");
    line.addColorStop(0.3, this.color1);
    line.addColorStop(0.6, this.color2);
    context.strokeStyle = line;
    //起点
    context.moveTo(this.x, this.y);
    //结尾
    context.lineTo(this.x + this.width, this.y - this.height);
    context.closePath();
    context.stroke();
    context.restore();
  }
  move() {
    //清空流星像素
    let x = this.x + this.width - this.offset_x;
    let y = this.y - this.height;
    context.clearRect(x - 3, y - 3, this.offset_x + 5, this.offset_y + 5);
    //重新核算方位,往左下移动
    this.countPos();
    //透明度增加
    this.alpha -= 0.002;
    //重绘
    this.draw();
  }
}
//制作流星
function playRains() {
  for (let n = 0; n < rainCount; n++) {
    // console.log(rains, "--");
    let rain = rains[n];
    rain.move(); //移动
    if (rain.y > window.innerHeight) {
      //超出界限后重来
      context.clearRect(rain.x, rain.y - rain.height, rain.width, rain.height);
      rains[n] = new MeteorRain();
      rains[n].init();
    }
  }
  t2 = requestAnimationFrame(playRains);
}

我用canvas带你看一场流星雨

6.merge视觉盛宴

流星极时间短的星星是也,它不像恒星和行星那般耀眼,却用时间短的生命,划破夜空,用瞬间洒脱的弧线留住美丽的光芒。昙花和流星瞬间之美令我无法忘记,大自然神奇的造物者给了咱们许多的美,不论瞬间的还是永久的,咱们都要用真心去欣赏去品味。

经过兼并前面五个步骤,咱们就能够一睹这流星霎时间的交织,而后瞬间就穿透为永久,仅仅一刻用生命变幻的美。

我用canvas带你看一场流星雨

最后

今日的视觉盛宴就到这儿了,想要检查源码的同学公众号回复流星雨

原文首发地址点这儿,欢迎大家重视公众号 「前端南玖」,假如你想进前端交流群一同学习,请点这儿

我是南玖,咱们下期见!!!