1

我有以下多步像素化动画。它从低像素到高像素的动画非常缓慢,以向您显示它在某些步骤之间颠簸,就好像图像在渲染之间略微移动一样。我无法弄清楚为什么会发生这种情况或如何使它看起来好像图像停留在一个地方。

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);
}

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

仅供参考,有两个图像,一个小的和一个大的,都是一样的。它首先以低分辨率加载小图像,然后加载大图像。在加载大图像时,它会使用小图像执行一些动画步骤来启动动画。然后,一旦大的图像完成,它会从小图像停止的地方开始,并使用大图像执行更多的动画步骤。

4

0 回答 0