如何缩放+滚动JavaScript而不会闪烁

时间:2016-03-04 16:05:46

标签: javascript html css

我有一个带有缩放功能的Web应用程序,可以缩放一些绝对定位的DIV并保持当前的滚动位置。缩放是动画的,问题是在动画期间,明显的滚动位置似乎上下闪烁。换句话说,当动画播放时,这些框看起来像是在几个像素上下跳跃。如果可能的话,我希望它更顺畅。

问题可以在这里看到:http://codepen.io/excelkobayashi/pen/EKVmrK。向下滚动到底部并使用+/-按钮。你滚动的距离越远,闪烁就越严重。在实际应用中,闪烁更加明显,可能是因为DOM更复杂。

特别要注意上边缘和文字:

http://i.imgur.com/fbkx1nJ.gifv

以下是滚动的相关代码:

    var oldZoom = zoom;
    zoom += step;

    render();

    scrollPos = ((zoom / oldZoom) * scrollPos) || 0;
    $("#container").scrollTop(scrollPos);

一些注意事项:

  • 从requestAnimationFrame循环调用整个块以设置缩放级别更改的动画
  • step是当前缩放和目标缩放之间差异的一小部分,以创建缓出效果。
  • 渲染是调整大小和放大的功能。在可滚动区域内移动DIV

var zoom = 1;
var targetZoom = 1;
var lastTick = null;
var scrollPos = 0;

function render() {
  $(".main").height(1000 * zoom).each(function() {
    var pos = 10 * zoom;
    var height = 30 * zoom;
    $(this).find(".stuff").each(function() {
      $(this).css("top", pos + "px");
      $(this).css("height", height + "px");
      pos += 50 * zoom;
    });
  })

}

function animate() {
  var diff = targetZoom - zoom;
  if (!diff) {
    lastTick = null;
    return;
  }

  var tick = new Date().getTime();
  if (lastTick) {
    var minDiff = 0.01;
    var timeDiff = tick - lastTick;
    var step = diff * timeDiff / 100;

    if (diff > 0 && step <= minDiff)
      step = Math.min(minDiff, diff);
    else if (diff < 0 && step >= -minDiff)
      step = Math.max(-minDiff, diff);

    var oldZoom = zoom;
    zoom += step;

    render();

    scrollPos = ((zoom / oldZoom) * scrollPos) || 0;
    $("#container").scrollTop(scrollPos);
  }

  lastTick = tick;
  requestAnimationFrame(animate);
}

function startAnimation() {
  if (lastTick)
    return;
  animate();
}

$("#zoomIn").click(function() {
  targetZoom += 0.2;
  startAnimation();
})

$("#zoomOut").click(function() {
  targetZoom -= 0.2;
  startAnimation();
})

$("#container").scroll(function() {
  var scrollTop = $(this).scrollTop();
  var diff = scrollPos - scrollTop;
  if (isNaN(diff) || diff < 0 || diff >= 1)
    scrollPos = scrollTop;
})

render();
div {
  border: 1px solid black;
  box-sizing: border-box;
}

#container {
  margin: 10px;
  width: 1200px;
  height: 400px;
  overflow: auto;
  display: flex;
  flex-direction: row;
}

.main {
  width: 200px;
  overflow: hidden;
  position: relative;
  /* Slow rendering (simulate complex content) */
  box-shadow: 5px 5px 10px #888;
  background-image: linear-gradient(to right, #fdd, #ddf);
}

.stuff {
  position: absolute;
  left: 10px;
  right: 10px;
  overflow: hidden;
  /* Slow rendering (simulate complex content) */
  box-shadow: 5px 5px 10px #888;
  background-image: linear-gradient(white, #aaa);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="zoomOut">-</button>
<button id="zoomIn">+</button>
<div id="container">
  <div class="main">
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
  </div>
  <div class="main">
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
  </div>
  <div class="main">
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
  </div>
  <div class="main">
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
  </div>
  <div class="main">
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
  </div>
  <div class="main">
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
    <div class="stuff">Stuff</div>
  </div>
</div>

关于我已经研究过的事情的一些注释:

  • 浏览器舍入scrollTop值。
    • 这应该考虑因为我有一个单独的变量存储预期的位置,但这种舍入仍然是罪魁祸首。
    • 在调用scrollTop之前添加一个圆形/楼层似乎没有效果。
  • 不能使用CSS变换,因为我不希望这会影响内部DIV的内容;放大应显示更多内容。
  • 交换调用render和scrollTop的顺序不会改变任何内容。
  • 设置scrollTop会导致重绘,但调用渲染不应该尽我所能。
  • Google地图等服务通过缩放上一张图片,然后将其隐藏并显示其后面的下一张图片来处理此问题。在这种情况下,这似乎不是一个选项,因为这不是基于图像的。

1 个答案:

答案 0 :(得分:0)

It flickers because you set the scrollTop value of the container with a certain step. If you want to gradually change the scrollTop, you might want to look at jQuery's .animate() function (http://api.jquery.com/animate/).