为什么这个像素化动画很快乐

时间:2019-06-04 21:09:08

标签: javascript css animation html5-canvas pixelate

我有以下多步像素化动画。它会从低像素到高像素进行非常缓慢的动画处理,以向您显示它在某些步骤之间震荡,就像图像在渲染之间略微移动一样。我不知道为什么会这样,或者如何使它看起来好像图像停留在一个地方。

var c = document.createElement('canvas')
c.style.display = 'flex'
c.style.width = '100vw'
c.style.height = '100vh'
c.style['image-rendering'] = 'pixelated'
document.body.appendChild(c)

var x = c.getContext('2d')

x.webkitImageSmoothingEnabled = false
x.mozImageSmoothingEnabled = false
x.msImageSmoothingEnabled = false
x.imageSmoothingEnabled = false

var src = c.getAttribute('data-draw')
var small = `https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/M101_hires_STScI-PRC2006-10a.jpg/307px-M101_hires_STScI-PRC2006-10a.jpg`
var large = `https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/M101_hires_STScI-PRC2006-10a.jpg/1280px-M101_hires_STScI-PRC2006-10a.jpg`

// c.width = c.clientWidth
// c.height = c.clientHeight

var stack = []
var start = false
var place = 0

function queue(image, ratio, width, height) {
  stack.push({ image, ratio, width, height })

  if (start) return
  start = true

  setTimeout(proceed, 0)
}

function proceed() {
  let point = stack.shift()
  let w
  let h

  if (point.ratio) {
    w = c.width = c.clientWidth * point.ratio
    h = c.height = c.clientHeight * point.ratio
  } else {
    w = point.width
    h = point.height
  }

  if (!stack.length) {
    x.webkitImageSmoothingEnabled = true
    x.mozImageSmoothingEnabled = true
    x.msImageSmoothingEnabled = true
    x.imageSmoothingEnabled = true
    c.classList.remove('px')
  }

  drawImageProp(x, point.image, 0, 0, w, h)

  if (stack.length) {
    setTimeout(proceed, 1000)
  }
}

var s = new Image()
s.onload = function(){
  queue(s, 0.01)
  queue(s, 0.03)

  var i = new Image()
  i.onload = function(){
    queue(i, 0.03)
    queue(i, 0.11)
    queue(i, 1)
  }
  i.src = large
}
s.src = small

function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
  if (arguments.length === 2) {
      x = y = 0;
      w = ctx.canvas.width;
      h = ctx.canvas.height;
  }

  // default offset is center
  offsetX = typeof offsetX === "number" ? offsetX : 0.5;
  offsetY = typeof offsetY === "number" ? offsetY : 0.5;

  // keep bounds [0.0, 1.0]
  if (offsetX < 0) offsetX = 0;
  if (offsetY < 0) offsetY = 0;
  if (offsetX > 1) offsetX = 1;
  if (offsetY > 1) offsetY = 1;

  var iw = img.width,
      ih = img.height,
      r = Math.min(w / iw, h / ih),
      nw = iw * r,   // new prop. width
      nh = ih * r,   // new prop. height
      cx, cy, cw, ch, ar = 1;

  // decide which gap to fill
  if (nw < w) ar = w / nw;
  if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh;  // updated
  nw *= ar;
  nh *= ar;

  // calc source rectangle
  cw = iw / (nw / w);
  ch = ih / (nh / h);

  cx = (iw - cw) * offsetX;
  cy = (ih - ch) * offsetY;

  // make sure source rectangle is valid
  if (cx < 0) cx = 0;
  if (cy < 0) cy = 0;
  if (cw > iw) cw = iw;
  if (ch > ih) ch = ih;

  // fill image in dest. rectangle
  ctx.drawImage(img, cx, cy, cw, ch,  x, y, w, h);
}

即使在最后两个步骤之间,它也会稍微移动。想知道出了什么问题以及如何解决。

仅供参考,有两张图片,一幅小图像和一张大图像,都是同一幅画。它首先以低分辨率加载小图像,然后加载大图像。在加载较大的动画时,它使用较小的图像执行动画步骤,以启动动画。然后,大图完成后,它会拾取小图停止的位置,并使用大图执行更多的动画步骤。

0 个答案:

没有答案