function Control( el, { value = 0, step = 1, max = 100, min = 0, maxAngle = 360, minAngle = 0 } = {} ) { const img = document.createElement("img"); img.src = "1@3x.png"; img.width = "250"; el.append(img); const ratio = (maxAngle - minAngle) / (max - min); const value2Deg = () => ratio * (value - min) + minAngle; const changeValue = (delta, fireEvent = false) => { let newValue = value + delta; if (newValue >= max) newValue = max; if (newValue <= min) newValue = min; value = newValue; if (fireEvent && this.onChange && typeof this.onChange === "function") { this.onChange(value); } img.style.transform = `rotate(${value2Deg()}deg)`; }; const { top, left } = img.getBoundingClientRect(); changeValue(0); console.log(img.width, top, left); img.onclick = (e) => { changeValue(e.clientX - left > img.width / 2 ? step : -step, true); }; img.onmousewheel = (e) => { changeValue((e.deltaY * step) / 25, true); e.preventDefault(); }; let startDragAngle; const calcAngle = ({ layerX, layerY }) => { const deltaX = layerX - img.width / 2; const deltaY = layerY - img.height / 2; return (Math.atan2(deltaY, deltaX) / Math.PI) * 180; }; img.onmousedown = (e) => { startDragAngle = calcAngle(e); e.preventDefault(); }; img.onmousemove = (e) => { if (startDragAngle !== undefined) { const currentAngle = calcAngle(e); let deltaAngle = currentAngle - startDragAngle; // дальше идет коррекция перехода через +-180 градусов // но из-за функции onclick осталось иногда подергивание // при выкручивании в крайние положения // onclick пришлось отключить if (Math.abs(deltaAngle) >= 180) { deltaAngle += deltaAngle < 0 ? 360 : -360; } else { deltaAngle += deltaAngle < 0 ? -360 : 360; } deltaAngle = deltaAngle % 360; changeValue(deltaAngle / ratio, true); startDragAngle = currentAngle; e.preventDefault(); } }; img.onmouseup = img.onmouseout = (e) => { if (startDragAngle) { startDragAngle = undefined; e.preventDefault(); } }; this.setValue = (v) => changeValue(v - value); this.changeValue = changeValue; this.getValue = () => value; } const volumeControl = new Control(container1, { value: 50, max: 1, step: 0.01 }); let volumeMp3 = document.getElementById("audio"); // volumeControl.onChange = (value) => console.log("VOLUME", value); volumeControl.onChange = (value) => volumeMp3.volume = value; const redControl = new Control(color1, { maxAngle: 90, minAngle: -90, min: 0, max: 255, value: 0, }); const greenControl = new Control(color2, { maxAngle: 90, minAngle: -90, min: 0, max: 255, value: 0, }); const blueControl = new Control(color3, { maxAngle: 90, minAngle: -90, min: 0, max: 255, value: 0, }); redControl.onChange = (x) => RGB.style.background = `rgb(${x}, ${greenControl.getValue()}, ${blueControl.getValue()})`; greenControl.onChange = (x) => RGB.style.background = `rgb(${redControl.getValue()}, ${x}, ${blueControl.getValue()})`; blueControl.onChange = (x) => RGB.style.background = `rgb(${redControl.getValue()}, ${greenControl.getValue()}, ${x})`; // value = 0, // step = 1, // max = 100, // min = 0, // maxAngle = 360, // minAngle = 0