Hkc

vuePress-theme-reco Hkc    2025
Hkc Hkc

Choose mode

  • dark
  • auto
  • light
TimeLine
GitHub
author-avatar

Hkc

25

Article

13

Tag

TimeLine
GitHub
  • Vue

  • Websocket

  • JS

  • CSS

  • Canvas

    • 《奇异博士》传送门
  • HTTP

  • GIT

  • SERVER

  • MORE

《奇异博士》传送门

vuePress-theme-reco Hkc    2025

《奇异博士》传送门

Hkc 2020-03-10 canvas
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Cache-Control" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1.0,user-scalable=no"
    />
    <title>奇异博士-传送门</title>
  </head>
  <style>
    html,
    body,
    canvas {
      margin: 0;
      padding: 9;
    }

    html,
    body {
      width: 100%;
      height: 100%;
    }

    body {
      overflow: hidden;
    }

    canvas {
      /* filter: blur(5px); */
    }
  </style>

  <body bgcolor="#000000">
    <canvas id="canvas"></canvas>
  </body>
  <script>
    var canvas = document.getElementById('canvas')
    canvas.style.position = 'absolute'
    canvas.style.top = 0
    var w = window.innerWidth
    var h = window.innerHeight
    canvas.width = w
    canvas.height = h
    ctx = canvas.getContext('2d')
    ctx.lineWidth = 1

    var g = 0.07
    var damping = 0.99
    var MIN_SPEED_X = 0.5

    var center = {
      x: w / 2,
      y: h / 2,
    }
    var list = []
    /**
     * 金黄:#FFD700 rgb(225,215,0)
     * 深红:#8B0000 rgb(139,0,0)
     */
    var MAX_LIMIT_AND_LEN = 41 // init中 limit + len的最大值,脱离圆周运动的最大步长
    var START_COLOR = { r: 255, g: 215, b: 80 }
    var END_COLOR = { r: 139, g: 0, b: 0 }
    var STEP_COLOR = {
      r: (START_COLOR.r - END_COLOR.r) / MAX_LIMIT_AND_LEN,
      g: (START_COLOR.g - END_COLOR.g) / MAX_LIMIT_AND_LEN,
      b: (START_COLOR.b - END_COLOR.b) / MAX_LIMIT_AND_LEN,
    }
    var MAX_RADIUS = 120 // 半径
    var SKYLINE = h / 2 + MAX_RADIUS + 30 // 地平线高度
    var MAX_COUNT = 42
    var STEP_RADIUS = 0.4
    var STEP_COUNT = 0.3
    var count = 1
    var radius = 50

    function init() {
      if (count < MAX_COUNT) count += STEP_COUNT
      if (radius < MAX_RADIUS) radius += STEP_RADIUS
      for (var i = 0; i < count; i++) {
        var deg = Math.random() * Math.PI * 2 // 角度
        var x = center.x + Math.cos(deg) * r // x位置
        var y = center.y + Math.sin(deg) * r // y位置
        var r = radius + Math.random() * 4 // 半径
        var step = 0.045 + Math.random() * 0.04 // 角速度
        var type = 'round' // 圆心运动
        var limit = ~~(Math.random() * 30) + 18 // 脱离圆心运动后运动的步长
        var len = 2 + ~~(Math.random() * 3) // 显示长度
        var color = {
          r: 255,
          g: 200 + ~~(Math.random() * 30),
          b: ~~(Math.random() * START_COLOR.b),
        } // 初始化颜色
        list.push({
          x,
          y,
          r,
          step,
          deg,
          type,
          limit,
          len,
          color,
          trail: [{ x, y }],
        })
      }
    }

    function update() {
      var init_damping = 0.55 + (MAX_RADIUS - radius) * 0.005 // 脱离圆心运动的元素,速度做一次衰减
      list.forEach((item) => {
        var random = Math.random()
        if (item.type === 'round') {
          item.deg += item.step
          if (radius < MAX_RADIUS) item.r += STEP_RADIUS
          item.x = center.x + Math.cos(item.deg) * item.r
          item.y = center.y + Math.sin(item.deg) * item.r
          if (random < 0.1) {
            var speed = item.step * item.r
            item.type = 'parabola'
            item.sx = Math.cos(item.deg + Math.PI / 2) * speed * init_damping
            item.sy = Math.sin(item.deg + Math.PI / 2) * speed * init_damping
            if (item.sy < 0) {
              item.len += 2
            }
          }
        } else {
          item.sx *= damping
          item.sy *= damping
          item.sy += g
          item.x += item.sx
          item.y += item.sy
          if (item.y > SKYLINE) {
            item.sy = -Math.abs(item.sy) // 超过地平线之后,Y方向反弹
            item.sy *= random * 0.5 + 0.5 // 碰撞之后速度衰减
            item.sx *= random * 0.5 + 0.5
          }
          item.limit -= 1
          if (random > 0.5) {
            // 颜色随机衰减
            item.color.r = Math.max(0, ~~(item.color.r - STEP_COLOR.r))
            item.color.g = Math.max(0, ~~(item.color.g - STEP_COLOR.g))
            item.color.b = Math.max(0, ~~(item.color.b - STEP_COLOR.b))
          }
        }
        item.trail.unshift({ x: item.x, y: item.y })
        item.trail = item.trail.slice(
          0,
          Math.max(0, Math.min(item.len, item.len + item.limit))
        )
      })
      list = list.filter((item) => item.trail.length > 0)
    }

    function draw() {
      ctx.clearRect(0, 0, w, h)
      list.forEach((item) => {
        ctx.beginPath()
        item.trail.forEach((trail, index) => {
          if (index === 0) {
            ctx.moveTo(trail.x, trail.y)
          } else {
            ctx.lineTo(trail.x, trail.y)
          }
        })
        ctx.strokeStyle =
          'rgb(' + item.color.r + ',' + item.color.g + ',' + item.color.b + ')'
        ctx.stroke()
      })
    }

    function step() {
      init()
      update()
      draw()
      requestAnimationFrame(step)
    }
    requestAnimationFrame(step)
  </script>
</html>