From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/code/input-knobs.js | 342 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 site/code/input-knobs.js (limited to 'site/code/input-knobs.js') diff --git a/site/code/input-knobs.js b/site/code/input-knobs.js new file mode 100644 index 0000000..65aefb1 --- /dev/null +++ b/site/code/input-knobs.js @@ -0,0 +1,342 @@ +window.addEventListener("load",()=>{ + let op=window.inputKnobsOptions||{}; + op.knobWidth=op.knobWidth||op.knobDiameter||64; + op.knobHeight=op.knobHeight||op.knobDiameter||64; + op.sliderWidth=op.sliderWidth||op.sliderDiameter||128; + op.sliderHeight=op.sliderHeight||op.sliderDiameter||20; + op.switchWidth=op.switchWidth||op.switchDiameter||24; + op.switchHeight=op.switchHeight||op.switchDiameter||24; + op.fgcolor=op.fgcolor||"#f00"; + op.bgcolor=op.bgcolor||"#000"; + op.knobMode=op.knobMode||"linear"; + op.sliderMode=op.sliderMode||"relative"; + let styles=document.createElement("style"); + styles.innerHTML= +`input[type=range].input-knob,input[type=range].input-slider{ + -webkit-appearance:none; + -moz-appearance:none; + border:none; + box-sizing:border-box; + overflow:hidden; + background-repeat:no-repeat; + background-size:100% 100%; + background-position:0px 0%; + background-color:transparent; + touch-action:none; +} +input[type=range].input-knob{ + width:${op.knobWidth}px; height:${op.knobHeight}px; +} +input[type=range].input-slider{ + width:${op.sliderWidth}px; height:${op.sliderHeight}px; +} +input[type=range].input-knob::-webkit-slider-thumb,input[type=range].input-slider::-webkit-slider-thumb{ + -webkit-appearance:none; + opacity:0; +} +input[type=range].input-knob::-moz-range-thumb,input[type=range].input-slider::-moz-range-thumb{ + -moz-appearance:none; + height:0; + border:none; +} +input[type=range].input-knob::-moz-range-track,input[type=range].input-slider::-moz-range-track{ + -moz-appearance:none; + height:0; + border:none; +} +input[type=checkbox].input-switch,input[type=radio].input-switch { + width:${op.switchWidth}px; + height:${op.switchHeight}px; + -webkit-appearance:none; + -moz-appearance:none; + background-size:100% 200%; + background-position:0% 0%; + background-repeat:no-repeat; + border:none; + border-radius:0; + background-color:transparent; +} +input[type=checkbox].input-switch:checked,input[type=radio].input-switch:checked { + background-position:0% 100%; +}`; + document.head.appendChild(styles); + let makeKnobFrames=(fr,fg,bg)=>{ + let r= +` + + +`; + for(let i=1;i`; + return r+""; + } + let makeHSliderFrames=(fr,fg,bg,w,h)=>{ + let r= +` + +`; + for(let i=0;i`; + r+=``; + } + return r+""; + } + let makeVSliderFrames=(fr,fg,bg,w,h)=>{ + let r= +` + +`; + for(let i=0;i`; + r+=``; + } + return r+""; + } + let initSwitches=(el)=>{ + let w,h,d,fg,bg; + if(el.inputKnobs) + return; + el.inputKnobs={}; + el.refresh=()=>{ + let src=el.getAttribute("data-src"); + d=+el.getAttribute("data-diameter"); + let st=document.defaultView.getComputedStyle(el,null); + w=parseFloat(el.getAttribute("data-width")||d||st.width); + h=parseFloat(el.getAttribute("data-height")||d||st.height); + bg=el.getAttribute("data-bgcolor")||op.bgcolor; + fg=el.getAttribute("data-fgcolor")||op.fgcolor; + el.style.width=w+"px"; + el.style.height=h+"px"; + if(src) + el.style.backgroundImage="url("+src+")"; + else { + let minwh=Math.min(w,h); + let svg= +` + + +`; + el.style.backgroundImage="url(data:image/svg+xml;base64,"+btoa(svg)+")"; + } + }; + el.refresh(); + }; + let initKnobs=(el)=>{ + let w,h,d,fg,bg; + if(el.inputKnobs){ + el.redraw(); + return; + } + let ik=el.inputKnobs={}; + el.refresh=()=>{ + d=+el.getAttribute("data-diameter"); + let st=document.defaultView.getComputedStyle(el,null); + w=parseFloat(el.getAttribute("data-width")||d||st.width); + h=parseFloat(el.getAttribute("data-height")||d||st.height); + bg=el.getAttribute("data-bgcolor")||op.bgcolor; + fg=el.getAttribute("data-fgcolor")||op.fgcolor; + ik.sensex=ik.sensey=200; + if(el.className.indexOf("input-knob")>=0) + ik.itype="k"; + else{ + if(w>=h){ + ik.itype="h"; + ik.sensex=w-h; + ik.sensey=Infinity; + el.style.backgroundSize="auto 100%"; + } + else{ + ik.itype="v"; + ik.sensex=Infinity; + ik.sensey=h-w; + el.style.backgroundSize="100% auto"; + } + } + el.style.width=w+"px"; + el.style.height=h+"px"; + ik.frameheight=h; + let src=el.getAttribute("data-src"); + if(src){ + el.style.backgroundImage=`url(${src})`; + let sp=+el.getAttribute("data-sprites"); + if(sp) + ik.sprites=sp; + else + ik.sprites=0; + if(ik.sprites>=1) + el.style.backgroundSize=`100% ${(ik.sprites+1)*100}%`; + else if(ik.itype!="k"){ + el.style.backgroundColor=bg; + el.style.borderRadius=Math.min(w,h)*0.25+"px"; + } + } + else{ + let svg; + switch(ik.itype){ + case "k": svg=makeKnobFrames(101,fg,bg); break; + case "h": svg=makeHSliderFrames(101,fg,bg,w,h); break; + case "v": svg=makeVSliderFrames(101,fg,bg,w,h); break; + } + ik.sprites=100; + el.style.backgroundImage="url(data:image/svg+xml;base64,"+btoa(svg)+")"; + el.style.backgroundSize=`100% ${(ik.sprites+1)*100}%`; + } + ik.valrange={min:+el.min, max:(el.max=="")?100:+el.max, step:(el.step=="")?1:+el.step}; + el.redraw(true); + }; + el.setValue=(v)=>{ + v=(Math.round((v-ik.valrange.min)/ik.valrange.step))*ik.valrange.step+ik.valrange.min; + if(vik.valrange.max) v=ik.valrange.max; + el.value=v; + if(el.value!=ik.oldvalue){ + el.setAttribute("value",el.value); + el.redraw(); + let event=document.createEvent("HTMLEvents"); + event.initEvent("input",false,true); + el.dispatchEvent(event); + ik.oldvalue=el.value; + } + }; + ik.pointerdown=(ev)=>{ + el.focus(); + const evorg = ev; + if(ev.touches) + ev = ev.touches[0]; + let rc=el.getBoundingClientRect(); + let cx=(rc.left+rc.right)*0.5,cy=(rc.top+rc.bottom)*0.5; + let dx=ev.clientX,dy=ev.clientY; + let da=Math.atan2(ev.clientX-cx,cy-ev.clientY); + if(ik.itype=="k"&&op.knobMode=="circularabs"){ + dv=ik.valrange.min+(da/Math.PI*0.75+0.5)*(ik.valrange.max-ik.valrange.min); + el.setValue(dv); + } + if(ik.itype!="k"&&op.sliderMode=="abs"){ + dv=(ik.valrange.min+ik.valrange.max)*0.5+((dx-cx)/ik.sensex-(dy-cy)/ik.sensey)*(ik.valrange.max-ik.valrange.min); + el.setValue(dv); + } + ik.dragfrom={x:ev.clientX,y:ev.clientY,a:Math.atan2(ev.clientX-cx,cy-ev.clientY),v:+el.value}; + document.addEventListener("mousemove",ik.pointermove); + document.addEventListener("mouseup",ik.pointerup); + document.addEventListener("touchmove",ik.pointermove); + document.addEventListener("touchend",ik.pointerup); + document.addEventListener("touchcancel",ik.pointerup); + document.addEventListener("touchstart",ik.preventScroll); + evorg.preventDefault(); + evorg.stopPropagation(); + }; + ik.pointermove=(ev)=>{ + let dv; + let rc=el.getBoundingClientRect(); + let cx=(rc.left+rc.right)*0.5,cy=(rc.top+rc.bottom)*0.5; + if(ev.touches) + ev = ev.touches[0]; + let dx=ev.clientX-ik.dragfrom.x,dy=ev.clientY-ik.dragfrom.y; + let da=Math.atan2(ev.clientX-cx,cy-ev.clientY); + switch(ik.itype){ + case "k": + switch(op.knobMode){ + case "linear": + dv=(dx/ik.sensex-dy/ik.sensey)*(ik.valrange.max-ik.valrange.min); + if(ev.shiftKey) + dv*=0.2; + el.setValue(ik.dragfrom.v+dv); + break; + case "circularabs": + if(!ev.shiftKey){ + dv=ik.valrange.min+(da/Math.PI*0.75+0.5)*(ik.valrange.max-ik.valrange.min); + el.setValue(dv); + break; + } + case "circularrel": + if(da>ik.dragfrom.a+Math.PI) da-=Math.PI*2; + if(da{ + document.removeEventListener("mousemove",ik.pointermove); + document.removeEventListener("touchmove",ik.pointermove); + document.removeEventListener("mouseup",ik.pointerup); + document.removeEventListener("touchend",ik.pointerup); + document.removeEventListener("touchcancel",ik.pointerup); + document.removeEventListener("touchstart",ik.preventScroll); + let event=document.createEvent("HTMLEvents"); + event.initEvent("change",false,true); + el.dispatchEvent(event); + }; + ik.preventScroll=(ev)=>{ + ev.preventDefault(); + }; + ik.keydown=()=>{ + el.redraw(); + }; + ik.wheel=(ev)=>{ + let delta=ev.deltaY>0?-ik.valrange.step:ik.valrange.step; + if(!ev.shiftKey) + delta*=5; + el.setValue(+el.value+delta); + ev.preventDefault(); + ev.stopPropagation(); + }; + el.redraw=(f)=>{ + if(f||ik.valueold!=el.value){ + let v=(el.value-ik.valrange.min)/(ik.valrange.max-ik.valrange.min); + if(ik.sprites>=1) + el.style.backgroundPosition="0px "+(-((v*ik.sprites)|0)*ik.frameheight)+"px"; + else{ + switch(ik.itype){ + case "k": + el.style.transform="rotate("+(270*v-135)+"deg)"; + break; + case "h": + el.style.backgroundPosition=((w-h)*v)+"px 0px"; + break; + case "v": + el.style.backgroundPosition="0px "+(h-w)*(1-v)+"px"; + break; + } + } + ik.valueold=el.value; + } + }; + el.refresh(); + el.redraw(true); + el.addEventListener("keydown",ik.keydown); + el.addEventListener("mousedown",ik.pointerdown); + el.addEventListener("touchstart",ik.pointerdown); + el.addEventListener("wheel",ik.wheel); + } + let refreshque=()=>{ + let elem=document.querySelectorAll("input.input-knob,input.input-slider"); + for(let i=0;i{ + for(let i=0;procque.length>0&&i<8;++i){ + let q=procque.shift(); + q[0](q[1]); + } + if(procque.length<=0) + refreshque(); + },50); +}); -- cgit v1.2.3