timeplayer
Version:
A time player/travel module
286 lines (249 loc) • 9.67 kB
text/typescript
const btnsSVG = {
forward: '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5762" width="16" height="16"><path d="M814.976 222.304c-10.432-5.504-23.168-4.832-32.96 1.824L576 364.288 576 250.592c0-11.872-6.56-22.72-17.024-28.288-10.432-5.504-23.168-4.832-32.96 1.824l-384 261.248C133.248 491.328 128 501.248 128 511.84s5.248 20.512 14.016 26.464l384 261.376c5.408 3.68 11.68 5.568 17.984 5.568 5.12 0 10.272-1.216 14.976-3.712C569.44 796 576 785.088 576 773.248l0-113.792 206.016 140.224c5.408 3.68 11.68 5.568 17.984 5.568 5.12 0 10.272-1.216 14.976-3.712C825.44 796 832 785.088 832 773.248L832 250.592C832 238.72 825.44 227.872 814.976 222.304z" p-id="5763"></path></svg>',
next: '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6081" width="16" height="16"><path d="M817.088 484.96l-512-323.744C295.232 154.976 282.752 154.592 272.576 160.224 262.336 165.856 256 176.608 256 188.256l0 647.328c0 11.648 6.336 22.4 16.576 28.032 4.8 2.656 10.112 3.968 15.424 3.968 5.952 0 11.904-1.664 17.088-4.928l512-323.616C826.368 533.184 832 522.976 832 512 832 501.024 826.368 490.816 817.088 484.96z" p-id="6082"></path></svg>',
pause: '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6307" width="16" height="16"><path d="M352 768c-17.664 0-32-14.304-32-32L320 288c0-17.664 14.336-32 32-32s32 14.336 32 32l0 448C384 753.696 369.664 768 352 768z" p-id="6308"></path><path d="M672 768c-17.696 0-32-14.304-32-32L640 288c0-17.664 14.304-32 32-32s32 14.336 32 32l0 448C704 753.696 689.696 768 672 768z" p-id="6309"></path></svg>'
}
const colors = {
controlBtn: '#000'
}
class Control {
dom: HTMLElement;
speed: number;
controlid: string;
state: number; // 0: stop 1: play
speedMax: number;
speedMin: number;
step: number;
numberFix: number;
value: number;
valueMin: number;
valueMax: number;
allowLoop: boolean;
interval: number;
onChange: Function;
colors: {
[key: string]: string
}
private control: {
forward: HTMLElement;
backward: HTMLElement;
previous: HTMLElement;
play: HTMLElement;
pause: HTMLElement;
next: HTMLElement;
up: HTMLElement;
down: HTMLElement;
speed: HTMLElement;
}
constructor(options: any) {
const {
speed = 1.0, speedMax = 10, speedMin = 0.1, value = 0, valueMax = 10, valueMin = 0, allowLoop = true, step = 0.1,
} = options;
this.colors = Object.assign(colors, options.colors || {});
this.speed = speed;
this.speedMax = speedMax;
this.speedMin = speedMin;
this.value = value;
this.valueMax = valueMax;
this.valueMin = valueMin;
this.allowLoop = allowLoop;
this.step = step;
options.onChange && (this.onChange = options.onChange);
this.speedMin = Math.max(this.speedMin, 0.1);
this.state = 0;
this.numberFix = this.step < 1 ? (this.step.toString().length - 2) : 0;
this.controlid = `control_${+new Date()}`
this.initDom();
this.initEvent();
this.draw();
}
private setCSS() {
const { controlid } = this;
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
.${controlid} {
height: 20px;
line-height: 20px;
font-size: 10px;
text-align: center;
}
.${controlid} span {
cursor: pointer;
border: 1px solid transparent;
display: inline-block;
vertical-align: middle;
line-height: 18px;
height: 18px;
width: 18px;
text-align: center;
box-sizing: border-box;
overflow: hidden;
}
.${controlid} span svg {
float: left;
height: 16px;
width: 16px;
fill: ${this.colors.controlBtn}
}
.${controlid} .space {
width: 1px;
overflow: hidden;
margin: 0 3px;
border-right: 1px solid #eee;
}
.${controlid} .play {
border: 1px solid ${this.colors.controlBtn};
width: 14px;
height: 14px;
border-radius: 100px;
}
.${controlid} .pause {
border: 1px solid transparent;
width: 16px;
height: 16px;
margin: 0 -1px;
}
.${controlid} .previous svg,
.${controlid} .forward svg {
transform: rotate(180deg);
}
.${controlid} .up svg {
transform: rotate(-90deg);
}
.${controlid} .down svg {
transform: rotate(90deg);
}
.${controlid} .play svg {
width: 12px;
height: 12px;
}
.${controlid} .speed {
user-select: none;
width: auto;
color: ${this.colors.controlBtn}
}
`
document.head.appendChild(style);
}
private initDom() {
const controlid = this.controlid;
this.setCSS();
const btns = ['backward', 'previous', 'play', 'pause', 'next', 'forward', 'space', 'up', 'speed', 'down'];
const btnSVGs = ['forward', 'next', 'next', 'pause', 'next', 'forward', '', 'next', '', 'next'];
const controls: any = {};
btns.forEach((item, index) => {
const dom = document.createElement('span');
dom.className = `${item}`;
const key: string = btnSVGs[index];
// @ts-ignore
dom.innerHTML = btnsSVG[key] || '';
controls[item] = dom;
});
const control = document.createElement('div');
control.className = `${controlid}`;
this.control = controls;
for (let [key, dom] of Object.entries(this.control)) {
control.appendChild(dom);
}
this.dom = control;
}
private initEvent() {
const { control, speedMax, speedMin, step } = this;
control.up.addEventListener('click', () => {
this.speed += step;
this.speed = Math.min(speedMax, this.speed);
this.state = 0;
this.draw();
});
control.down.addEventListener('click', () => {
this.speed -= step;
this.speed = Math.max(speedMin, this.speed);
this.state = 0;
this.draw();
});
control.next.addEventListener('click', () => {
this.value += 1;
this.value = Math.min(this.value, this.valueMax);
this.state = 0;
this.draw(true);
});
control.previous.addEventListener('click', () => {
this.value -= 1;
this.state = 0;
this.value = Math.max(this.value, this.valueMin);
this.draw(true);
});
control.backward.addEventListener('click', () => {
this.value = this.valueMin;
this.state = 0;
this.draw(true);
});
control.forward.addEventListener('click', () => {
this.value = this.valueMax;
this.state = 0;
this.draw(true);
});
control.play.addEventListener('click', () => {
this.state = 1;
window.clearInterval(this.interval);
this.interval = window.setInterval(() => {
this.value += 1;
if (this.value > this.valueMax) {
if (this.allowLoop) {
this.value = this.valueMin;
} else {
this.state = 0;
window.clearInterval(this.interval);
}
}
this.draw(true);
}, this.speed * 1000);
});
control.pause.addEventListener('click', () => {
this.state = 0;
window.clearInterval(this.interval);
this.draw();
});
}
private draw(isUpdate = false) {
const { control, state, numberFix, value, valueMin, valueMax, speed, speedMin, speedMax } = this;
control.speed.innerText = speed.toFixed(numberFix);
if (state === 0) {
control.pause.style.display = 'none';
control.play.style.display = 'inline-block';
window.clearInterval(this.interval);
} else {
control.pause.style.display = 'inline-block';
control.play.style.display = 'none';
}
// value check
control.backward.style.opacity = '1';
control.previous.style.opacity = '1';
control.forward.style.opacity = '1';
control.next.style.opacity = '1';
control.down.style.opacity = '1';
control.up.style.opacity = '1';
if (value <= valueMin) {
control.backward.style.opacity = '0.5';
control.previous.style.opacity = '0.5';
} else if (value >= valueMax) {
control.forward.style.opacity = '0.5';
control.next.style.opacity = '0.5';
}
// speed check
if (speed <= speedMin) {
control.down.style.opacity = '0.5';
} else if (speed >= speedMax) {
control.up.style.opacity = '0.5';
}
if (isUpdate) {
this.onChange(this.value);
}
}
public setActive(value: number){
this.value = value;
this.draw();
}
}
export default Control;