Parcourir la source

Switch to using web animations api for track progress

Thomas Dy il y a 4 ans
Parent
commit
8e33619860
2 fichiers modifiés avec 36 ajouts et 38 suppressions
  1. 0 11
      dist/style.css
  2. 36 27
      src/display.ts

+ 0 - 11
dist/style.css

@@ -60,17 +60,6 @@
   position: absolute;
   height: 0.3125em;
   background-color: var(--base-color);
-  animation-timing-function: linear;
-  animation-play-state: paused;
-}
-
-@keyframes progress {
-  from {
-    width: 0%;
-  }
-  to {
-    width: 100%;
-  }
 }
 
 /* }}} */

+ 36 - 27
src/display.ts

@@ -160,47 +160,56 @@ namespace display {
   export class TrackProgressController {
     totalBar: HTMLElement;
     intervalBar: HTMLElement;
-    listener: ((event: AnimationEvent) => void) | null;
+    listener: ((event: AnimationPlaybackEvent) => void) | null;
 
-    constructor(private element: HTMLElement, lines: level.Line[]) {
+    constructor(private element: HTMLElement, private lines: level.Line[]) {
       this.totalBar = util.getElement(element, '.total .shade');
       this.intervalBar = util.getElement(element, '.interval .shade');
       this.listener = null;
+    }
 
-      let totalDuration = lines[lines.length - 1].end;
-      this.totalBar.style.animationName = 'progress';
-      this.totalBar.style.animationDuration = totalDuration + 's';
+    start(start: number = 0): void {
+      this.clearAnimations();
+      const end = this.lines[this.lines.length - 1].end!;
+      const progress = start / end;
+      this.totalBar.animate({ width: [`${progress * 100}%`, '100%'] }, {
+        duration: (end - start) * 1000
+      });
 
-      let names = lines.map(line => 'progress').join(',');
-      let delays = lines.map(line => line.start + 's').join(',');
-      let durations = lines.map(line => (line.end! - line.start!) + 's').join(',');
-      this.intervalBar.style.animationName = names;
-      this.intervalBar.style.animationDelay = delays;
-      this.intervalBar.style.animationDuration = durations;
+      for (const line of this.lines) {
+        if (line.end! <= start) {
+          continue;
+        }
+        const segmentStart = Math.max(line.start!, start);
+        const segmentLength = line.end! - segmentStart;
+        const fullSegmentLength = line.end! - line.start!;
+        const progress = 1 - segmentLength / fullSegmentLength;
+        const animation = this.intervalBar.animate({ width: [`${progress * 100}%`, '100%'] }, {
+          delay: (segmentStart - start) * 1000,
+          duration: segmentLength * 1000,
+        });
+        if (this.listener) {
+          animation.addEventListener('finish', this.listener);
+        }
+      }
     }
 
-    start(): void {
-      this.intervalBar.style.width = '100%';
-      this.totalBar.style.width = '100%';
-
-      this.intervalBar.style.animationPlayState = 'running';
-      this.totalBar.style.animationPlayState = 'running';
+    pause(): void {
+      this.totalBar.getAnimations().forEach(anim => anim.pause());
+      this.intervalBar.getAnimations().forEach(anim => anim.pause());
     }
 
-    setListener(func: (event: AnimationEvent) => void): void {
-      if (this.listener) {
-        this.intervalBar.removeEventListener('animationend', func);
-      }
-      this.intervalBar.addEventListener('animationend', func);
+    setListener(func: (event: AnimationPlaybackEvent) => void): void {
       this.listener = func;
     }
 
     destroy(): void {
-      if (this.listener) {
-        this.intervalBar.removeEventListener('animationend', this.listener);
-      }
-      this.intervalBar.style.animationName = '';
-      this.totalBar.style.animationName = '';
+      this.clearAnimations();
+    }
+
+    private clearAnimations() {
+      this.totalBar.getAnimations().forEach(anim => anim.cancel());
+      this.intervalBar.getAnimations().forEach(anim => anim.cancel());
     }
   }