• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

TypeScript + Vue 实现某个canvas科幻背景 -- 1

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

    在TypeScript + Vue项目中实现一个酷炫的Canvas运动背景,实现代码如下:

<template>
  <div id="main">
    <div id="bg-main">
      <canvas id="bg"></canvas>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

let tick = 0,
    options = {
      len: 20,
      count: 50,
      baseTime: 10,
      addedTime: 10,
      dieChance: .01,
      spawnChance: .5,
      sparkChance: .1,
      sparkDist: 10,
      sparkSize: 2,
      color: `hsl(tone, 100%, light%)`,
      baseLight: 50,
      addedLight: 10,
      shadowToTimePropMult: 6,
      baseLightInputMultiplier: .01,
      addedLightInputMultiplier: .02,
      ox: 0,
      oy: 0,
      repaintAlpha: .04,
      toneChange: .1
    },
    lines = new Array(),
    dieX: number = 0,
    dieY: number = 0,
    clientHeight: number = 0,
    clientWidth: number = 0,
    baseRadius = Math.PI * 2 / 6

@Component
export default class Main extends Vue {
  name = "ContentMain"

  mounted(){
    const bg = document.getElementById('bg') as HTMLCanvasElement,
          bgMain = document.getElementById('bg-main') as HTMLDivElement
    let ctx = bg.getContext('2d') as CanvasRenderingContext2D
    clientWidth = bg.width = bgMain.clientWidth
    clientHeight = bg.height = bgMain.clientHeight
    options.ox = clientWidth / 2
    options.oy = clientHeight / 2
    dieX = clientWidth / 2 / options.len
    dieY = clientHeight / 2 / options.len
    ctx.fillStyle = 'black'
    ctx.fillRect(0, 0, clientWidth, clientHeight)

    function loop(){
      // setTimeout(()=>requestAnimationFrame(loop),  50)
      requestAnimationFrame(loop)
      ++tick;
      ctx.globalCompositeOperation = "source-over"
      ctx.shadowBlur = 0
      ctx.fillStyle = "rgba(0, 0, 0, alp)".replace('alp', options.repaintAlpha.toString())
      ctx.fillRect(0, 0, clientWidth, clientHeight)
      ctx.globalCompositeOperation = "lighter"
      if(lines.length < options.count && Math.random()<options.spawnChance)
        lines.push(new Line(ctx))
      lines.map(line=>line.step())
    }

    window.addEventListener('resize', (e:Event)=>{
      clientWidth = bg.width = bgMain.clientWidth
      clientHeight = bg.height = bgMain.clientHeight
      ctx.fillStyle = 'black'
      ctx.fillRect(0, 0, clientWidth, clientHeight)
      options.ox = clientWidth / 2
      options.oy = clientHeight / 2
      dieX = clientWidth / 2 / options.len
      dieY = clientHeight / 2 / options.len
    })

    loop()
  }
}

interface Option {
  readonly len: number;
  readonly count: number;
  readonly baseTime: number;
  readonly addedTime: number;
  readonly dieChance: number;
  readonly spawnChance: number;
  readonly sparkChance: number;
  readonly sparkDist: number;
  readonly sparkSize: number;
  readonly color: string;
  readonly baseLight: number;
  readonly addedLight: number;
  readonly shadowToTimePropMult: number;
  readonly baseLightInputMultiplier: number;
  readonly addedLightInputMultiplier: number;
  ox: number;
  oy: number;
  readonly repaintAlpha: number;
  readonly toneChange: number;
}
class Line {
  private x = 0;
  private y = 0;
  private addedX = 0;
  private addedY = 0;
  private radius = 0;
  private lightInputMultiplier = 0;
  private color = "";
  private cumulativeTime = 0;
  private time = 0;
  private targetTime = 0;
  private ctx: CanvasRenderingContext2D

  constructor(ctx: CanvasRenderingContext2D) {
    this.ctx = ctx
    this.reset()
  }

  reset(): void {
    this.x = 0;
    this.y = 0;
    this.addedX = 0;
    this.addedY = 0;
    this.radius = 0;
    this.lightInputMultiplier =
      options.baseLightInputMultiplier +
      options.addedLightInputMultiplier * Math.random();
    this.color = options.color.replace(
      "tone",
      (options.toneChange * tick).toString()
    );
    this.cumulativeTime = 0;
    this.beginPhase();
  }

  beginPhase(): void {
    this.x += this.addedX;
    this.y += this.addedY;
    this.time = 0;
    this.targetTime =  (options.baseTime + options.addedTime * Math.random()) | 0;
    this.radius += baseRadius * (Math.random() < 0.5 ? 1 : -1);
    this.addedX = Math.cos(this.radius);
    this.addedY = Math.sin(this.radius);

    if ( Math.random() < options.dieChance ||
        this.x > dieX || this.x < -dieX ||
        dieY > dieY || this.y < -dieY )
      this.reset()
  }

  step() {
    ++this.time
    ++this.cumulativeTime
    if (this.time >= this.targetTime) this.beginPhase();
    let prop = this.time / this.targetTime,
        wave = Math.sin(prop * Math.PI / 2),
        x = this.addedX * wave,
        y = this.addedY * wave;
    this.ctx.shadowBlur = prop * options.shadowToTimePropMult;
    this.ctx.fillStyle = this.ctx.shadowColor = this.color.replace(
      "light",
      (options.baseLight +
        options.addedLight *
          Math.sin(this.cumulativeTime * this.lightInputMultiplier)).toString()
    );
    this.ctx.fillRect(
    options.ox + (this.x + x) * options.len,
    options.oy + (this.y + y) * options.len,
    2, 2);
    if (Math.random() < options.sparkChance)
      this.ctx.fillRect(
        options.ox +
          (this.x + x) * options.len +
          Math.random() * options.sparkDist * (Math.random() < 0.5 ? 1 : -1) - options.sparkSize / 2,
        options.oy +
          (this.y + y) * options.len +
          Math.random() * options.sparkDist * (Math.random() < 0.5 ? 1 : -1) - options.sparkSize / 2,
        options.sparkSize,
        options.sparkSize
      );
  }
}
</script>

<style lang="scss">
#main {
  position: relative;
  top: 5vh;
  left: 0;
  margin: 0;
  width: 100%;
  height: 80%;
  margin-top: 0;
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;

  #bg-main {
    margin: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    z-index: 0;
  }
}
</style>
代码仅供参考学习


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap