const btnsSVG = {
forward: '',
next: '',
pause: ''
}
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;