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;