mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-23 13:51:20 -08:00
修改包管理
This commit is contained in:
1 parent
c5c673ae79
commit
0aa018db6d
99 files changed
+70
-70
No files matched your search
@@ -0,0 +1,25 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Danmu {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, danmu } = art;
|
||||
this.$danmu = append($control, icons.danmu);
|
||||
tooltip(this.$danmu, i18n.get('Hide danmu'));
|
||||
proxy($control, 'click', () => {
|
||||
if (danmu.isOpen) {
|
||||
danmu.hide();
|
||||
setStyle(this.$danmu, 'opacity', '1');
|
||||
tooltip(this.$danmu, i18n.get('Show danmu'));
|
||||
} else {
|
||||
danmu.show();
|
||||
setStyle(this.$danmu, 'opacity', '0.8');
|
||||
tooltip(this.$danmu, i18n.get('Hide danmu'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Fullscreen {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, player } = art;
|
||||
this.$fullscreen = append($control, icons.fullscreen);
|
||||
tooltip(this.$fullscreen, i18n.get('Fullscreen'));
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
player.fullscreenToggle();
|
||||
});
|
||||
|
||||
art.on('fullscreen:enabled', () => {
|
||||
setStyle(this.$fullscreen, 'opacity', '0.8');
|
||||
tooltip(this.$fullscreen, i18n.get('Exit fullscreen'));
|
||||
});
|
||||
|
||||
art.on('fullscreen:exit', () => {
|
||||
setStyle(this.$fullscreen, 'opacity', '1');
|
||||
tooltip(this.$fullscreen, i18n.get('Fullscreen'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class FullscreenWeb {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, player } = art;
|
||||
this.$fullscreenWeb = append($control, icons.fullscreenWeb);
|
||||
tooltip(this.$fullscreenWeb, i18n.get('Web fullscreen'));
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
player.fullscreenWebToggle();
|
||||
});
|
||||
|
||||
art.on('fullscreenWeb:enabled', () => {
|
||||
setStyle(this.$fullscreenWeb, 'opacity', '0.8');
|
||||
tooltip(this.$fullscreenWeb, i18n.get('Exit web fullscreen'));
|
||||
});
|
||||
|
||||
art.on('fullscreenWeb:exit', () => {
|
||||
setStyle(this.$fullscreenWeb, 'opacity', '1');
|
||||
tooltip(this.$fullscreenWeb, i18n.get('Web fullscreen'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import { insertByIndex } from '../utils';
|
||||
import Fullscreen from './fullscreen';
|
||||
import FullscreenWeb from './fullscreenWeb';
|
||||
import Pip from './pip';
|
||||
import PlayAndPause from './playAndPause';
|
||||
import Progress from './progress';
|
||||
import Subtitle from './subtitle';
|
||||
import Time from './time';
|
||||
import Volume from './volume';
|
||||
import Setting from './setting';
|
||||
import Thumbnails from './thumbnails';
|
||||
import Screenshot from './screenshot';
|
||||
import Quality from './quality';
|
||||
|
||||
let id = 0;
|
||||
export default class Controls {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.art.on('firstCanplay', () => {
|
||||
this.init();
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
this.add(new Progress({
|
||||
name: 'progress',
|
||||
disable: false,
|
||||
position: 'top',
|
||||
index: 10
|
||||
}));
|
||||
|
||||
this.add(new Thumbnails({
|
||||
name: 'thumbnails',
|
||||
disable: !this.art.option.thumbnails.url,
|
||||
position: 'top',
|
||||
index: 20
|
||||
}));
|
||||
|
||||
this.add(new PlayAndPause({
|
||||
name: 'playAndPause',
|
||||
disable: false,
|
||||
position: 'left',
|
||||
index: 10
|
||||
}));
|
||||
|
||||
this.add(new Volume({
|
||||
name: 'volume',
|
||||
disable: false,
|
||||
position: 'left',
|
||||
index: 20
|
||||
}));
|
||||
|
||||
this.add(new Time({
|
||||
name: 'time',
|
||||
disable: false,
|
||||
position: 'left',
|
||||
index: 30
|
||||
}));
|
||||
|
||||
this.add(new Quality({
|
||||
name: 'quality',
|
||||
disable: this.art.option.quality.length === 0,
|
||||
position: 'right',
|
||||
index: 10
|
||||
}));
|
||||
|
||||
this.add(new Screenshot({
|
||||
name: 'screenshot',
|
||||
disable: !this.art.option.screenshot,
|
||||
position: 'right',
|
||||
index: 20
|
||||
}));
|
||||
|
||||
this.add(new Subtitle({
|
||||
name: 'subtitle',
|
||||
disable: !this.art.option.subtitle.url,
|
||||
position: 'right',
|
||||
index: 30
|
||||
}));
|
||||
|
||||
this.add(new Setting({
|
||||
name: 'setting',
|
||||
disable: !this.art.option.setting,
|
||||
position: 'right',
|
||||
index: 40
|
||||
}));
|
||||
|
||||
this.add(new Pip({
|
||||
name: 'pip',
|
||||
disable: !this.art.option.pip,
|
||||
position: 'right',
|
||||
index: 50
|
||||
}));
|
||||
|
||||
this.add(new FullscreenWeb({
|
||||
name: 'fullscreenWeb',
|
||||
disable: !this.art.option.fullscreenWeb,
|
||||
position: 'right',
|
||||
index: 60
|
||||
}));
|
||||
|
||||
this.add(new Fullscreen({
|
||||
name: 'fullscreen',
|
||||
disable: !this.art.option.fullscreen,
|
||||
position: 'right',
|
||||
index: 70
|
||||
}));
|
||||
|
||||
this.art.option.controls.forEach(item => {
|
||||
this.add(item);
|
||||
});
|
||||
}
|
||||
|
||||
add(control) {
|
||||
const { option } = control;
|
||||
if (option && !option.disable) {
|
||||
id++;
|
||||
const name = option.name || control.constructor.name.toLowerCase() || `control${id}`;
|
||||
const $control = document.createElement('div');
|
||||
$control.setAttribute('class', `art-control art-control-${name}`);
|
||||
this.mount(option.position, $control, option.index || id);
|
||||
control.apply && control.apply(this.art, $control);
|
||||
this[name] = control;
|
||||
}
|
||||
}
|
||||
|
||||
mount(position, $control, index) {
|
||||
const { $progress, $controlsLeft, $controlsRight } = this.art.refs;
|
||||
switch (position) {
|
||||
case 'top':
|
||||
insertByIndex($progress, $control, index);
|
||||
break;
|
||||
case 'left':
|
||||
insertByIndex($controlsLeft, $control, index);
|
||||
break;
|
||||
case 'right':
|
||||
insertByIndex($controlsRight, $control, index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
show() {
|
||||
const { $player } = this.art.refs;
|
||||
$player.classList.add('artplayer-controls-show');
|
||||
}
|
||||
|
||||
hide() {
|
||||
const { $player } = this.art.refs;
|
||||
$player.classList.remove('artplayer-controls-show');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { append, tooltip } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Pip {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, player } = art;
|
||||
this.$pip = append($control, icons.pip);
|
||||
tooltip(this.$pip, i18n.get('Mini player'));
|
||||
proxy($control, 'click', () => {
|
||||
player.pipEnabled();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class PlayAndPause {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, player, i18n } = art;
|
||||
this.$play = append($control, icons.play);
|
||||
this.$pause = append($control, icons.pause);
|
||||
tooltip(this.$play, i18n.get('Play'));
|
||||
tooltip(this.$pause, i18n.get('Pause'));
|
||||
setStyle(this.$pause, 'display', 'none');
|
||||
|
||||
proxy(this.$play, 'click', () => {
|
||||
player.play();
|
||||
});
|
||||
|
||||
proxy(this.$pause, 'click', () => {
|
||||
player.pause();
|
||||
});
|
||||
|
||||
art.on('video:playing', () => {
|
||||
setStyle(this.$play, 'display', 'none');
|
||||
setStyle(this.$pause, 'display', 'block');
|
||||
});
|
||||
|
||||
art.on('video:pause', () => {
|
||||
setStyle(this.$play, 'display', 'block');
|
||||
setStyle(this.$pause, 'display', 'none');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import { append, clamp, secondToTime, setStyle } from '../utils';
|
||||
|
||||
export default class Progress {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
this.isDroging = false;
|
||||
this.getLoaded = this.getLoaded.bind(this);
|
||||
this.getPlayed = this.getPlayed.bind(this);
|
||||
this.set = this.set.bind(this);
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
this.art = art;
|
||||
this.$control = $control;
|
||||
const { option: { highlight, theme }, events: { proxy }, refs: { $video }, player } = art;
|
||||
|
||||
append(
|
||||
$control,
|
||||
`
|
||||
<div class="art-control-progress-inner">
|
||||
<div class="art-progress-loaded"></div>
|
||||
<div class="art-progress-played" style="background: ${theme}"></div>
|
||||
<div class="art-progress-highlight"></div>
|
||||
<div class="art-progress-indicator" style="background: ${theme}"></div>
|
||||
<div class="art-progress-tip art-tip"></div>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
|
||||
this.$loaded = $control.querySelector('.art-progress-loaded');
|
||||
this.$played = $control.querySelector('.art-progress-played');
|
||||
this.$highlight = $control.querySelector('.art-progress-highlight');
|
||||
this.$indicator = $control.querySelector('.art-progress-indicator');
|
||||
this.$tip = $control.querySelector('.art-progress-tip');
|
||||
|
||||
this.set('loaded', this.getLoaded());
|
||||
highlight.forEach(item => {
|
||||
const left = Number(item.time) / $video.duration;
|
||||
append(this.$highlight, `<span data-text="${item.text}" data-time="${item.time}" style="left: ${left * 100}%"></span>`);
|
||||
});
|
||||
|
||||
this.art.on('video:progress', () => {
|
||||
this.set('loaded', this.getLoaded());
|
||||
});
|
||||
|
||||
this.art.on('video:timeupdate', () => {
|
||||
this.set('played', this.getPlayed());
|
||||
});
|
||||
|
||||
this.art.on('video:ended', () => {
|
||||
this.set('played', 1);
|
||||
});
|
||||
|
||||
proxy($control, 'mousemove', event => {
|
||||
setStyle(this.$tip, 'display', 'block');
|
||||
if (event.composedPath().indexOf(this.$highlight) > -1) {
|
||||
this.showHighlight(event);
|
||||
} else {
|
||||
this.showTime(event);
|
||||
}
|
||||
});
|
||||
|
||||
proxy($control, 'mouseout', () => {
|
||||
setStyle(this.$tip, 'display', 'none');
|
||||
});
|
||||
|
||||
proxy($control, 'click', event => {
|
||||
if (event.target !== this.$indicator) {
|
||||
const { second, percentage } = this.getPosFromEvent(event);
|
||||
this.set('played', percentage);
|
||||
player.seek(second);
|
||||
}
|
||||
});
|
||||
|
||||
proxy(this.$indicator, 'mousedown', () => {
|
||||
this.isDroging = true;
|
||||
});
|
||||
|
||||
proxy(document, 'mousemove', event => {
|
||||
if (this.isDroging) {
|
||||
const { second, percentage } = this.getPosFromEvent(event);
|
||||
this.$indicator.classList.add('show-indicator');
|
||||
this.set('played', percentage);
|
||||
player.seek(second);
|
||||
}
|
||||
});
|
||||
|
||||
proxy(document, 'mouseup', () => {
|
||||
if (this.isDroging) {
|
||||
this.isDroging = false;
|
||||
this.$indicator.classList.remove('show-indicator');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showHighlight(event) {
|
||||
const { $video } = this.art.refs;
|
||||
const { text, time } = event.target.dataset;
|
||||
this.$tip.innerHTML = text;
|
||||
const left =
|
||||
Number(time) / $video.duration * this.$control.clientWidth +
|
||||
event.target.clientWidth / 2 -
|
||||
this.$tip.clientWidth / 2;
|
||||
setStyle(this.$tip, 'left', `${left}px`);
|
||||
}
|
||||
|
||||
showTime(event) {
|
||||
const { width, time } = this.getPosFromEvent(event);
|
||||
const tipWidth = this.$tip.clientWidth;
|
||||
this.$tip.innerHTML = time;
|
||||
if (width <= tipWidth / 2) {
|
||||
setStyle(this.$tip, 'left', 0);
|
||||
} else if (width > this.$control.clientWidth - tipWidth / 2) {
|
||||
setStyle(this.$tip, 'left', `${this.$control.clientWidth - tipWidth}px`);
|
||||
} else {
|
||||
setStyle(this.$tip, 'left', `${width - tipWidth / 2}px`);
|
||||
}
|
||||
}
|
||||
|
||||
getPlayed() {
|
||||
const { $video } = this.art.refs;
|
||||
return $video.currentTime / $video.duration;
|
||||
}
|
||||
|
||||
getLoaded() {
|
||||
const { $video } = this.art.refs;
|
||||
return $video.buffered.length
|
||||
? $video.buffered.end($video.buffered.length - 1) / $video.duration
|
||||
: 0;
|
||||
}
|
||||
|
||||
getPosFromEvent(event) {
|
||||
const { $video, $progress } = this.art.refs;
|
||||
const { left } = $progress.getBoundingClientRect();
|
||||
const width = clamp(event.x - left, 0, $progress.clientWidth);
|
||||
const second = width / $progress.clientWidth * $video.duration;
|
||||
const time = secondToTime(second);
|
||||
const percentage = clamp(width / $progress.clientWidth, 0, 1);
|
||||
return { second, time, width, percentage };
|
||||
}
|
||||
|
||||
set(type, percentage) {
|
||||
setStyle(this[`$${type}`], 'width', `${percentage * 100}%`);
|
||||
if (type === 'played') {
|
||||
setStyle(this.$indicator, 'left', `calc(${percentage * 100}% - 6.5px)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { append } from '../utils';
|
||||
|
||||
export default class Quality {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
this.playIndex = -1;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { option, events: { proxy, hover }, player } = art;
|
||||
const defaultQuality = option.quality.find(item => item.default) || option.quality[0];
|
||||
this.playIndex = option.quality.indexOf(defaultQuality);
|
||||
const $qualityName = append($control, `<div class="art-quality-name">${defaultQuality.name}</div>`);
|
||||
const qualityList = option.quality.map((item, index) => `<div class="art-quality-item" data-index="${index}">${item.name}</div>`).join('');
|
||||
const $qualitys = append($control, `<div class="art-qualitys">${qualityList}</div>`);
|
||||
|
||||
hover($control, () => {
|
||||
$control.classList.add('hover');
|
||||
}, () => {
|
||||
$control.classList.remove('hover');
|
||||
});
|
||||
|
||||
proxy($qualitys, 'click', event => {
|
||||
const index = Number(event.target.dataset.index);
|
||||
const { url, name } = option.quality[index];
|
||||
if (url && name && this.playIndex !== index) {
|
||||
player.switch(url, name);
|
||||
$qualityName.innerHTML = name;
|
||||
this.playIndex = index;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { append, tooltip } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Screenshot {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, player } = art;
|
||||
this.$screenshot = append($control, icons.screenshot);
|
||||
tooltip(this.$screenshot, i18n.get('Screenshot'));
|
||||
proxy(this.$screenshot, 'click', () => {
|
||||
player.screenshot();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Setting {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, setting } = art;
|
||||
this.$setting = append($control, icons.setting);
|
||||
tooltip(this.$setting, i18n.get('Show setting'));
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
setting.toggle();
|
||||
});
|
||||
|
||||
art.on('setting:show', () => {
|
||||
setStyle(this.$setting, 'opacity', '0.8');
|
||||
tooltip(this.$setting, i18n.get('Hide setting'));
|
||||
});
|
||||
|
||||
art.on('setting:hide', () => {
|
||||
setStyle(this.$setting, 'opacity', '1');
|
||||
tooltip(this.$setting, i18n.get('Show setting'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Subtitle {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
const { events: { proxy }, i18n, subtitle } = art;
|
||||
this.$subtitle = append($control, icons.subtitle);
|
||||
tooltip(this.$subtitle, i18n.get('Hide subtitle'));
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
subtitle.toggle();
|
||||
});
|
||||
|
||||
art.on('subtitle:show', () => {
|
||||
setStyle(this.$subtitle, 'opacity', '0.8');
|
||||
tooltip(this.$subtitle, i18n.get('Hide subtitle'));
|
||||
});
|
||||
|
||||
art.on('subtitle:hide', () => {
|
||||
setStyle(this.$subtitle, 'opacity', '1');
|
||||
tooltip(this.$subtitle, i18n.get('Show subtitle'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { errorHandle, setStyle } from '../utils';
|
||||
|
||||
export default class Thumbnails {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
this.loading = false;
|
||||
this.isLoad = false;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
this.art = art;
|
||||
errorHandle(art.controls.progress, '\'thumbnails\' control dependent on \'progress\' control');
|
||||
const { refs: { $progress }, events: { proxy } } = art;
|
||||
this.$control = $control;
|
||||
|
||||
proxy($progress, 'mousemove', event => {
|
||||
if (!this.loading) {
|
||||
this.loading = true;
|
||||
this.load(this.art.option.thumbnails.url).then(() => {
|
||||
this.isLoad = true;
|
||||
});
|
||||
}
|
||||
|
||||
if (this.isLoad) {
|
||||
setStyle($control, 'display', 'block');
|
||||
this.showThumbnails(event);
|
||||
}
|
||||
});
|
||||
|
||||
proxy($progress, 'mouseout', () => {
|
||||
setStyle($control, 'display', 'none');
|
||||
});
|
||||
}
|
||||
|
||||
load(url) {
|
||||
const { proxy } = this.art.events;
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.src = url;
|
||||
|
||||
if (image.complete) {
|
||||
return resolve(image);
|
||||
}
|
||||
|
||||
proxy(image, 'load', () => resolve(image));
|
||||
proxy(image, 'error', () => reject(image));
|
||||
});
|
||||
}
|
||||
|
||||
showThumbnails(event) {
|
||||
const { refs: { $progress }, controls } = this.art;
|
||||
const { width: posWidth } = controls.progress.getPosFromEvent(event);
|
||||
const { url, height, width, number, column } = this.art.option.thumbnails;
|
||||
const perWidth = $progress.clientWidth / number;
|
||||
const perIndex = Math.ceil(posWidth / perWidth);
|
||||
let yIndex = Math.ceil(perIndex / column);
|
||||
let xIndex = perIndex % column || column;
|
||||
|
||||
setStyle(this.$control, 'backgroundImage', `url(${url})`);
|
||||
setStyle(this.$control, 'height', `${height}px`);
|
||||
setStyle(this.$control, 'width', `${width}px`);
|
||||
setStyle(this.$control, 'backgroundPosition', `-${--xIndex * width}px -${--yIndex * height}px`);
|
||||
|
||||
if (posWidth <= width / 2) {
|
||||
setStyle(this.$control, 'left', 0);
|
||||
} else if (posWidth > $progress.clientWidth - width / 2) {
|
||||
setStyle(this.$control, 'left', `${$progress.clientWidth - width}px`);
|
||||
} else {
|
||||
setStyle(this.$control, 'left', `${posWidth - width / 2}px`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { secondToTime } from '../utils';
|
||||
|
||||
export default class Time {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
$control.innerHTML = '00:00 / 00:00';
|
||||
|
||||
function setTime() {
|
||||
$control.innerHTML = `${secondToTime(art.player.currentTime())} / ${secondToTime(art.player.duration())}`;
|
||||
}
|
||||
|
||||
art.on('video:canplay', () => {
|
||||
setTime();
|
||||
});
|
||||
|
||||
art.on('video:timeupdate', () => {
|
||||
setTime();
|
||||
});
|
||||
|
||||
art.on('video:seeking', () => {
|
||||
setTime();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { append, getStorage, clamp, tooltip, setStyle } from '../utils';
|
||||
import icons from '../icons';
|
||||
|
||||
export default class Volume {
|
||||
constructor(option) {
|
||||
this.option = option;
|
||||
this.isDroging = false;
|
||||
}
|
||||
|
||||
apply(art, $control) {
|
||||
this.art = art;
|
||||
this.$control = $control;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const { events: { proxy }, player, i18n } = this.art;
|
||||
this.$volume = append(this.$control, icons.volume);
|
||||
this.$volumeClose = append(this.$control, icons.volumeClose);
|
||||
this.$volumePanel = append(this.$control, '<div class="art-volume-panel"></div>');
|
||||
this.$volumeHandle = append(this.$volumePanel, '<div class="art-volume-slider-handle"></div>');
|
||||
tooltip(this.$volume, i18n.get('Mute'));
|
||||
setStyle(this.$volumeClose, 'display', 'none');
|
||||
|
||||
const volume = getStorage('volume');
|
||||
this.setVolumeHandle(volume);
|
||||
player.volume(volume);
|
||||
|
||||
proxy(this.$volume, 'click', () => {
|
||||
setStyle(this.$volume, 'display', 'none');
|
||||
setStyle(this.$volumeClose, 'display', 'block');
|
||||
player.volume(0);
|
||||
});
|
||||
|
||||
proxy(this.$volumeClose, 'click', () => {
|
||||
setStyle(this.$volume, 'display', 'block');
|
||||
setStyle(this.$volumeClose, 'display', 'none');
|
||||
player.volume(getStorage('volume'));
|
||||
});
|
||||
|
||||
proxy(this.$control, 'mouseenter', () => {
|
||||
this.$volumePanel.classList.add('art-volume-panel-hover');
|
||||
|
||||
// TODO
|
||||
setTimeout(() => {
|
||||
this.setVolumeHandle(player.volume());
|
||||
}, 200);
|
||||
});
|
||||
|
||||
proxy(this.$control, 'mouseleave', () => {
|
||||
this.$volumePanel.classList.remove('art-volume-panel-hover');
|
||||
});
|
||||
|
||||
proxy(this.$volumePanel, 'click', event => {
|
||||
this.volumeChangeFromEvent(event);
|
||||
});
|
||||
|
||||
proxy(this.$volumeHandle, 'mousedown', () => {
|
||||
this.isDroging = true;
|
||||
});
|
||||
|
||||
proxy(this.$volumeHandle, 'mousemove', event => {
|
||||
if (this.isDroging) {
|
||||
this.volumeChangeFromEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
proxy(document, 'mouseup', () => {
|
||||
if (this.isDroging) {
|
||||
this.isDroging = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.art.on('video:volumechange', () => {
|
||||
const percentage = player.volume();
|
||||
this.setVolumeHandle(percentage);
|
||||
if (percentage === 0) {
|
||||
setStyle(this.$volume, 'display', 'none');
|
||||
setStyle(this.$volumeClose, 'display', 'block');
|
||||
} else {
|
||||
setStyle(this.$volume, 'display', 'block');
|
||||
setStyle(this.$volumeClose, 'display', 'none');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
volumeChangeFromEvent(event) {
|
||||
const { player } = this.art;
|
||||
const { left: panelLeft, width: panelWidth } = this.$volumePanel.getBoundingClientRect();
|
||||
const { width: handleWidth } = this.$volumeHandle.getBoundingClientRect();
|
||||
const percentage = clamp(event.x - panelLeft - handleWidth / 2, 0, panelWidth - handleWidth / 2) / (panelWidth - handleWidth);
|
||||
player.volume(percentage);
|
||||
}
|
||||
|
||||
setVolumeHandle(percentage = 0.7) {
|
||||
const { width: panelWidth } = this.$volumePanel.getBoundingClientRect();
|
||||
const { width: handleWidth } = this.$volumeHandle.getBoundingClientRect();
|
||||
const width = handleWidth / 2 + (panelWidth - handleWidth) * percentage - handleWidth / 2;
|
||||
setStyle(this.$volumeHandle, 'left', `${width}px`);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user