spritejs/spritejs

View on GitHub
benchmark/shape_fly.spritejs2.html

Summary

Maintainability
Test Coverage
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
  <title>Birds Flying</title>
  <style>
    *{      
      -webkit-touch-callout: auto; /* prevent callout to copy image, etc when tap to hold */      
      -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */      
      -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */       
      -webkit-user-select:none;
    }  
    html,body {
      width: 100%;
      height: 100%;
      padding: 0;
      margin: 0;
      max-width: 500px;
    }
    #paper {
      position: relative;
      overflow: hidden;
      width: 100%;
      padding-top: 100%;
      height: 0px;
    }
  </style>
</head>
<body>
  <div>sprites: <span id="spriteCount">0</span></div>
  <div id="paper"></div>
  
  <!-- <script src="https://s2.ssl.qhres2.com/!87edaa34/animator-0.3.1.min.js"></script> -->
  <script src="/js/spritejs.js"></script>
  
  <script>
  class Animator {
    constructor(duration, update, easing) {
      this.duration = duration
      this.update = update
      this.easing = easing
    }

    animate(startTime) {
      startTime = startTime || 0

      const duration = this.duration,
        update = this.update,
        easing = this.easing,
        self = this

      return new Promise(((resolve, reject) => {
        let qId = 0
        function step(timestamp) {
          startTime = startTime || timestamp
          const p = Math.min(1.0, (timestamp - startTime) / duration)

          update.call(self, easing ? easing(p) : p, p)

          if(p < 1.0) {
            qId = requestAnimationFrame(step)
          } else {
            resolve(startTime + duration)
          }
        }

        self.cancel = function () {
          cancelAnimationFrame(qId)
          update.call(self, 0, 0)
          resolve(startTime + duration)
        }
        qId = requestAnimationFrame(step)
      }))
    }

    ease(easing) {
      return new Animator(this.duration, this.update, easing)
    }
  }

  /* eslint-disable */
  const birdsJsonUrl = 'https://s5.ssl.qhres2.com/static/5f6911b7b91c88da.json'
  const birdsRes = 'https://p.ssl.qhimg.com/d/inn/c886d09f/birds.png'
  const container = document.getElementById('paper');
  ;(async function(){
    const scene = new spritejs.Scene({container, width: 800, height: 800})
    
    const bglayer = scene.layer('bg'),  // 背景层
          // 前景层
          // 不代理事件,提升性能
          fglayer = scene.layer('fg', {
                handleEvent: false,
                bufferSize: 12000,
          })   
    
    const axisZero = [400, 400]
    const circle = new spritejs.Block()
    
    circle.attr({
      anchor: [0.5, 0.5],
      size: [800, 800],
      pos: axisZero,
      bgcolor: '#139',
      opacity: 0.5,
      borderRadius: 400,
    })
    
    bglayer.appendChild(circle)

    let groupCache = null

    function pointAdd(p1, p2 = [0, 0]){
      return [p1[0] + p2[0], p1[1] + p2[1]].map(Math.round)
    }
    
    function pointSub(p1, p2 = [0, 0]){
      return [p1[0] - p2[0], p1[1] - p2[1]].map(Math.round)
    }
    
    function sleep(time){
      return new Promise(resolve => setTimeout(resolve, time))
    }
    
    async function randomAnimate(cloud, i){
      cloud._pos = cloud._pos || [];
      const fromPoint = cloud._pos[i] || [0, 0];
      const randomArc = Math.random() * 2 * Math.PI
      const randomPoint = pointAdd([350 * Math.cos(randomArc), 
                                    350 * Math.sin(randomArc)], [0, 0])
      
      const dist = pointSub(randomPoint, fromPoint)
      const distance = Math.round(Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]))
      const flip = dist[0] < 0 ? -1 : 1
      const duration = 5 * distance + 100

      const anim = new Animator(duration, function(p){
        const pos = pointAdd(fromPoint, [p * dist[0], p * dist[1]])
        const rotate = p * 720
        // sprite.forceUpdate()
        // sprite.attr({
        //   pos,
        //   rotate,
        // })
        // console.log(pos);
        cloud.setTransform(i, null);
        cloud.translate(i, pos);
        cloud.rotate(i, rotate, pos);
        cloud._pos[i] = pos;
      })

      await anim.animate()
      // await sleep(500)
    }
    
    const group = new spritejs.Group()
    group.attr({
      anchor: [0.5, 0.5],
      pos: axisZero,
      size: [60, 60],
      bgcolor: 'blue',
      // bgcolor: 'white',
    })

    const center = new spritejs.Block()
    center.attr({
      anchor: [0.5, 0.5],
      pos: [0, 0],
      size: [20, 20],
      borderRadius: 10,
      bgcolor: 'black',
    })

    const top = center.cloneNode()
    top.attr({
      pos: [0, -20],
    })
    
    const right = center.cloneNode()
    right.attr({
      pos: [20, 0],
    })

    const bottom = center.cloneNode()
    bottom.attr({
      pos: [0, 20]
    })

    const left = center.cloneNode()
    left.attr({
      pos: [-20, 0]
    })

    group.append(center, top, right, bottom, left)
    group.seal()

    const cloud = new spritejs.Cloud(group, 2000);
    
    fglayer.appendChild(cloud)

    window.cloud = cloud

    let _spriteCount = 0
    async function addSprite(idx){
      _spriteCount++
      spriteCount.innerHTML = _spriteCount * 5
      do {
        await randomAnimate(cloud, idx)
      } while(1);
      
      // noprotect
      // do{
      //   await randomAnimate(group)
      // }while(1) 
    }

    requestAnimationFrame(function f() {
      if(_spriteCount < 1000) {
        addSprite(_spriteCount)
        requestAnimationFrame(f)
      }
    })

    window.fglayer = fglayer
  })()
  </script>
</body>
</html>