Bästa sättet att visa en nyhetsrulle i HTML/CSS/JavaScript
Vi har en ticker längst ner på en HTML-sida som visar nyheter, precis som en nyhetsticker på TV. Vi använder för närvarande requestAnimationFrame för detta men vi upplever att det inte alltid animeras bra och jag undrar om någon vet vad som skulle vara bästa praxis för detta.
Först försökte vi köra det på en Raspberry Pi och det kunde inte rendera det bra oavsett vad vi försökte.
För det andra kör vi det på en Windows-PC i en Chrome-webbläsare och generellt fungerar det bra, men om vi spelar en högupplöst video på samma sida blir rendering av tickern verkligen seg.
Jag förstår att det konkurrerar om resurser, men att animera en ticker borde i princip inte kräva många resurser, så jag tror att det borde finnas en lösning för detta.
Här är vår nuvarande kod. Det är TypeScript och inte vanlig JavaScript, men min fråga handlar inte så mycket om att felsöka detaljer i min nuvarande kod utan mer om att hitta det bästa tillvägagångssättet, vilket jag antar är något annat än vad vi gör nu:
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));
}