Browse Source

Add preview thumbnails

guokeke 8 years ago
parent
commit
dabb7fb699
3 changed files with 117 additions and 21 deletions
  1. 91 19
      src/DPlayer.js
  2. 21 1
      src/DPlayer.scss
  3. 5 1
      src/html.js

+ 91 - 19
src/DPlayer.js

@@ -244,14 +244,18 @@ class DPlayer {
             this.seek(parseFloat(bar.playedBar.style.width) / 100 * this.video.duration);
         });
 
-        this.isTipsShow = false;
-        this.timeTipsHandler = this.timeTipsHandler(
+        this.initVideoPreview();
+        this.isPreViewShow = false;
+        this.isTimeTipsShow = true;
+        this.isMouseHoverPbar = false;
+        this.mouseHandler = this.mouseHandler(
             pbar, pbarTimeTips).bind(this);
-        pbar.addEventListener('mousemove', this.timeTipsHandler);
-        pbar.addEventListener('mouseover', this.timeTipsHandler);
-        pbar.addEventListener('mouseenter', this.timeTipsHandler);
-        pbar.addEventListener('mouseout', this.timeTipsHandler);
-        pbar.addEventListener('mouseleave', this.timeTipsHandler);
+        pbar.addEventListener('mousemove', this.mouseHandler);
+        pbar.addEventListener('mouseover', this.mouseHandler);
+        pbar.addEventListener('mouseenter', this.mouseHandler);
+        pbar.addEventListener('mouseout', this.mouseHandler);
+        pbar.addEventListener('mouseleave', this.mouseHandler);
+
 
         const thumbMove = (event) => {
             const e = event || window.event;
@@ -1076,7 +1080,7 @@ class DPlayer {
         });
     }
 
-    timeTipsHandler (pbar, timeTips) {
+    mouseHandler (pbar, timeTips) {
         // http://stackoverflow.com/questions/1480133/how-can-i-get-an-objects-absolute-position-on-the-page-in-javascript
         const cumulativeOffset = (element) => {
             let top = 0, left = 0;
@@ -1099,30 +1103,98 @@ class DPlayer {
             const { clientX } = e;
             const px = cumulativeOffset(pbar).left;
             const tx = clientX - px;
-            timeTips.innerText = utils.secondToTime(this.video.duration * (tx / pbar.offsetWidth));
+            const time = this.video.duration * (tx / pbar.offsetWidth);
+            timeTips.innerText = utils.secondToTime(time);
             timeTips.style.left = `${(tx - 20)}px`;
+            this.previewWrapper.style.left = `${(tx - 80)}px`;
+
             switch (e.type) {
             case 'mouseenter':
             case 'mouseover':
             case 'mousemove':
-                if (this.isTipsShow) {
-                    return;
-                }
-                timeTips.classList.remove('hidden');
-                this.isTipsShow = true;
+                this.isMouseHoverPbar = true;
+                this.setPreviewSourceAndFrame({ time });
+                this.timeTipsDisplay(true, timeTips);
                 break;
             case 'mouseleave':
             case 'mouseout':
-                if (!this.isTipsShow) {
-                    return;
-                }
-                timeTips.classList.add('hidden');
-                this.isTipsShow = false;
+                this.isMouseHoverPbar = false;
+                this.previewDispaly(false);
+                this.timeTipsDisplay(false, timeTips);
                 break;
             }
         };
     }
 
+    timeTipsDisplay (show, timeTips) {
+        if (show) {
+            if (this.isTimeTipsShow) {
+                return;
+            }
+            timeTips.classList.remove('hidden');
+            this.isTimeTipsShow = true;
+        } else {
+            if (!this.isTimeTipsShow) {
+                return;
+            }
+            timeTips.classList.add('hidden');
+            this.isTimeTipsShow = false;
+        }
+    }
+
+    initVideoPreview () {
+        this.previewVideo = document.createElement("video");
+        this.previewWrapper = this.element.getElementsByClassName('dplayer-bar-preview')[0];
+        this.previewCanvas = this.element.getElementsByClassName('dplayer-bar-preview-canvas')[0];
+        this.previewCanvas.width = this.previewWrapper.offsetWidth;
+        this.previewCanvas.height = this.previewWrapper.offsetHeight;
+        this.previewVideo.preload = 'auto';
+        this.setPreviewSourceAndFrame({
+            url: this.video.src, time: 0
+        });
+        this.bindPreviewEvent();
+    }
+
+    setPreviewSourceAndFrame ({ url, time }) {
+        if (url) {
+            this.previewVideo.src = url;
+        }
+        if (time) {
+            this.previewVideo.currentTime = time;
+        }
+    }
+
+    bindPreviewEvent () {
+        if (!this.previewVideo) {return;}
+        this.previewVideo.addEventListener('seeked', () => {
+            this.generPreviewImage(this.video.currentTime);
+        });
+    }
+
+    generPreviewImage (time) {
+        if (time !== this.video.currentTime) {return;}
+        if (!this.isMouseHoverPbar) {return;}
+        const ctx = this.previewCanvas.getContext('2d');
+        ctx.drawImage(this.previewVideo, 0, 0,
+            this.previewWrapper.offsetWidth,
+            this.previewWrapper.offsetHeight);
+        this.previewDispaly(true);
+    }
+
+
+    previewDispaly (show) {
+        if (show) {
+            if (this.isPreViewShow) {return;}
+            if (!this.isMouseHoverPbar) {return;}
+            this.previewWrapper.classList.remove('hidden');
+            this.isPreViewShow = true;
+        } else {
+            if (!this.isPreViewShow) {return;}
+            this.previewWrapper.classList.add('hidden');
+            this.isPreViewShow = false;
+        }
+    }
+
     notice (text, time = 2000, opacity = 0.8) {
         const noticeEle = this.element.getElementsByClassName('dplayer-notice')[0];
         noticeEle.innerHTML = text;

+ 21 - 1
src/DPlayer.scss

@@ -374,6 +374,25 @@
                 }
             }
 
+            .dplayer-bar-preview {
+                position: absolute;
+                width: 160px;
+                height: 80px;
+                top: -80px;
+                background: #fff;
+
+                &.hidden {
+                    visibility: hidden;
+                }
+            }
+
+            .dplayer-bar-preview-canvas {
+                position: absolute;
+                width: 100%;
+                height: 100%;
+                z-index: 1;
+            }
+
             .dplayer-bar-time {
                 &.hidden {
                     opacity: 0;
@@ -392,6 +411,7 @@
                 transition: opacity .1s ease-in-out;
                 word-wrap: normal;
                 word-break: normal;
+                z-index: 2;
             }
 
             .dplayer-bar {
@@ -1227,4 +1247,4 @@
     0%, 100% {
         transform: translate(0, 0) rotate(0deg);
     }
-}
+}

+ 5 - 1
src/html.js

@@ -158,6 +158,10 @@ const html = {
             </div>
             <div class="dplayer-bar-wrap">
                 <div class="dplayer-bar-time hidden">00:00</div>
+                <div class="dplayer-bar-preview hidden">
+                    <canvas class="dplayer-bar-preview-canvas">
+                    </canvas>
+                </div>
                 <div class="dplayer-bar">
                     <div class="dplayer-loaded" style="width: 0;"></div>
                     <div class="dplayer-played" style="width: 0; background: ${option.theme}">
@@ -246,4 +250,4 @@ const html = {
     })
 };
 
-module.exports = html;
+module.exports = html;