function Control(el, { value = 0, min = 0, max = 100, minAngle = 0, maxAngle = 360, wheelSpeed = 0.1, step = 1 } = {}) { const img = document.createElement('img') img.src = '1@3x.png' img.style.width = '100%' img.style.height = 'auto' el.append(img) let forceChange = new Event('change') this.currentValue = document.createElement('input') this.currentValue.type = 'number' this.currentValue.value = value const ratio = (maxAngle - minAngle) / (max - min) const getAngle = () => (value - min) * ratio + minAngle this.getValue = () => { return value } this.setValue = newValue => { if (newValue > max) { newValue = max } if (newValue < min) { newValue = min } value = newValue this.currentValue.value = value this.currentValue.dispatchEvent(forceChange) img.style.transform = `rotate(${getAngle()}deg)` } img.onmousewheel = e => { const { deltaY } = e const newValue = value + deltaY * wheelSpeed this.setValue(newValue) e.preventDefault() } img.onclick = e => { const { layerX } = e const { width } = img layerX > width / 2? this.setValue(value + step) : this.setValue(value - step) } const toDeg = rad => ((rad * 180) / Math.PI + 360 + 90) % 360 let prevMouseAngle = null img.onmousedown = e => { const y = e.layerY - img.height / 2 const x = e.layerX - img.width / 2 prevMouseAngle = toDeg(Math.atan2(y, x)) e.preventDefault() } img.onmousemove = e => { if (prevMouseAngle === null) return const y = e.layerY - img.height / 2 const x = e.layerX - img.width / 2 let currentAngle = toDeg(Math.atan2(y, x)) let moveAngleDiff = (currentAngle - prevMouseAngle) this.setValue(value + moveAngleDiff / ratio) prevMouseAngle = currentAngle } img.onmouseout = img.onmouseup = () => { prevMouseAngle = null } this.setValue(value) } let track = document.getElementById('track') let audioSpin = document.getElementById('audio-spin') const volumeControl = new Control(audioSpin, { value: 50, min: 0, max: 100, minAngle: 0, maxAngle: 360 }) track.volume = volumeControl.getValue() / 100 volumeControl.currentValue.onchange = () => track.volume = volumeControl.getValue() / 100 // RGB const Red = new Control(red, {min: 0, max: 255}) const Green = new Control(green, {value: 200, min: 0, max: 255}) const Blue = new Control(blue, {value: 125, min: 0, max: 255}) let setRGB = (element) => { element.style.backgroundColor = `rgb(${Red.getValue()||0}, ${Green.getValue()||0}, ${Blue.getValue()||0})` } setRGB(document.getElementById('color-window')) Red.currentValue.onchange = () => setRGB(document.getElementById('color-window')) Green.currentValue.onchange = () => setRGB(document.getElementById('color-window')) Blue.currentValue.onchange = () => setRGB(document.getElementById('color-window'))