在HTML/CSS/JavaScript中渲染NewSticker的最佳方法

发布于 2025-01-29 18:31:29 字数 2554 浏览 0 评论 0原文

我们在HTML页面的底部有一个股票程序,显示出新闻,就像电视上的新闻报名人一样。目前,我们使用requestAnimationFrame为此,我们会体验到它并不总是很好的动画,我想知道是否有人知道这是最佳实践。

首先,我们尝试在Raspberry Pi上运行它,无论尝试什么,它都无法很好地渲染它。

其次,我们在Chrome浏览器的Windows PC中运行它,并且通常运行效果很好,但是如果我们在同一页面上播放高分辨率视频,那么股票的渲染就会变得很懒惰。

我知道它是在争夺资源,但是对股票代码进行动画不应需要很多资源,因此我认为应该有一个解决方案。

这是我们当前的代码。它是打字稿,而不是简单的JavaScript,但是我的问题不是在我当前代码中的详细信息中进行故障排除,而是关于找到我认为与我们现在所做的最佳方法的最佳方法:

  private startTicker() {
    const ticker = document.getElementById(`RssTickerContainer_${this.props.rssTicker?.rssTicker?.url}`);
    if (!ticker || !this.state.items || this.state.items.length === 0) {
      setTimeout(() => {
        if (this.props.rssTicker?.rssTicker?.url) {
          // try to fetch rss content again after 1 second
          this.getRssFeed(this.props.rssTicker?.rssTicker?.url, true);
        }
      }, 1000);
      return;
    }
    console.log("Starting RSS ticker");
    const startPosition = this.state.leftPosition;
    let leftPosition = startPosition;
    let lastFrameCalled = performance.now();
    let fps = 0;
    this.animationFrameID = requestAnimationFrame(() => this.animateTicker(lastFrameCalled, fps, startPosition, leftPosition, ticker));
  }

  private animateTicker(lastFrameCalled: number, fps: number, startPosition: number, leftPosition: number, ticker: HTMLElement) {
    // calculate fps
    const timeSinceLastFrame = (performance.now() - lastFrameCalled) / 1000;
    lastFrameCalled = performance.now();
    fps = 1 / timeSinceLastFrame;
    const containerWidth = ticker.getBoundingClientRect().width;
    if (containerWidth <= 0) {
      // no content, component probably has unmounted
      return;
    }
    if ((leftPosition * -1) > containerWidth) {
      // when leftPosition (inversed, since has negative value) is greater than containerWidth,
      // this means that all elements has passed the screen so we restart the ticker
      console.log("Restarting RSS ticker");
      leftPosition = startPosition;
      ticker.style.left = leftPosition + "px";
      this.getRssFeed(this.props.rssTicker?.rssTicker?.url);
    } else {
      const timeToCross = 25;
      // use fps to set the new position to avoid slow animations on weaker devices
      const step = window.innerWidth / timeToCross / fps;
      leftPosition = leftPosition - step;
      ticker.style.left = leftPosition + "px";
    }
    this.animationFrameID = requestAnimationFrame(() => this.animateTicker(lastFrameCalled, fps, startPosition, leftPosition, ticker));
  }

We have a ticker in the bottom of an HTML page that shows news, just like a news ticker on TV. We currently use requestAnimationFrame for this but we experience that it does not always animate well and I wonder if anyone knows what would be the best practice for this.

Firstly, we tried running it on a Raspberry Pi and it couldn't render it well no matter what we tried.

Secondly, we are running it in a Windows PC in a Chrome browser and generally it works well, but if we play a high resolution video on the same page, then the rendering of the ticker becomes really laggy.

I understand that it's competing for resources but animating a ticker should in principle not require many resources so I think there should be a solution for this.

Here is our current code. It's typescript and not plain javascript, but my question is not so much about troubleshooting details in my current code but more about finding the best approach which I assume is something different than what we are doing now:

  private startTicker() {
    const ticker = document.getElementById(`RssTickerContainer_${this.props.rssTicker?.rssTicker?.url}`);
    if (!ticker || !this.state.items || this.state.items.length === 0) {
      setTimeout(() => {
        if (this.props.rssTicker?.rssTicker?.url) {
          // try to fetch rss content again after 1 second
          this.getRssFeed(this.props.rssTicker?.rssTicker?.url, true);
        }
      }, 1000);
      return;
    }
    console.log("Starting RSS ticker");
    const startPosition = this.state.leftPosition;
    let leftPosition = startPosition;
    let lastFrameCalled = performance.now();
    let fps = 0;
    this.animationFrameID = requestAnimationFrame(() => this.animateTicker(lastFrameCalled, fps, startPosition, leftPosition, ticker));
  }

  private animateTicker(lastFrameCalled: number, fps: number, startPosition: number, leftPosition: number, ticker: HTMLElement) {
    // calculate fps
    const timeSinceLastFrame = (performance.now() - lastFrameCalled) / 1000;
    lastFrameCalled = performance.now();
    fps = 1 / timeSinceLastFrame;
    const containerWidth = ticker.getBoundingClientRect().width;
    if (containerWidth <= 0) {
      // no content, component probably has unmounted
      return;
    }
    if ((leftPosition * -1) > containerWidth) {
      // when leftPosition (inversed, since has negative value) is greater than containerWidth,
      // this means that all elements has passed the screen so we restart the ticker
      console.log("Restarting RSS ticker");
      leftPosition = startPosition;
      ticker.style.left = leftPosition + "px";
      this.getRssFeed(this.props.rssTicker?.rssTicker?.url);
    } else {
      const timeToCross = 25;
      // use fps to set the new position to avoid slow animations on weaker devices
      const step = window.innerWidth / timeToCross / fps;
      leftPosition = leftPosition - step;
      ticker.style.left = leftPosition + "px";
    }
    this.animationFrameID = requestAnimationFrame(() => this.animateTicker(lastFrameCalled, fps, startPosition, leftPosition, ticker));
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文