【问题标题】:How to zoom + scroll in JavaScript without flickering如何在 JavaScript 中缩放 + 滚动而不闪烁
【发布时间】:2016-03-04 16:05:45
【问题描述】:

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

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

特别注意顶部边缘和文字:

这里是滚动的相关代码:

    var oldZoom = zoom;
    zoom += step;

    render();

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

一些注意事项:

  • 从 requestAnimationFrame 循环调用整个块以动画化缩放级别的变化
  • 步长是当前缩放和目标缩放之间差异的一小部分,用于创建缓出效果。
  • render 是在可滚动区域内调整和移动 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 会导致重绘,但据我所知调用 render 不应该。
  • Google Maps 等服务通过缩放前一个图像、然后隐藏它并在其后面显示下一个加载的图像来处理此问题。在这种情况下,这似乎不是一个选项,因为这不是基于图像的。

【问题讨论】:

    标签: javascript html css


    【解决方案1】:

    它闪烁是因为您通过某个步骤设置了容器的scrollTop 值。如果你想逐渐改变scrollTop,你可能想看看jQuery的.animate()函数(http://api.jquery.com/animate/)。

    【讨论】:

    • 我会假设 animate 也只是像我一样设置 scrollTop,我不明白为什么它应该有任何不同。
    • 您一次性设置新的(最终)y 值,.animate() 分步更改它,从而使其更平滑
    • 我设置它的方式已经将它设置为小增量,并且使用 requestAnimationFrame 进行设置,因此它应该是任何可能使用的最小增量。
    猜你喜欢
    • 2012-09-26
    • 2023-03-25
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    相关资源
    最近更新 更多