Verly Range Slider
Idea
The main idea was to make some verlet simulated ropes and connect them to the rang slider's thumb and let them sway
Core Technologies
- Javascript
- Canvas
While I was building my physics engineVerly.js I was thinking of making something that would showcase the engine's potential to do some exciting stuff, so I created this just as an experiment.
- so far VerlyRangeSlider got over18K Views onCodepen
- got mentioned inCodepenSpark #136
- showcased injustforfun.io
- and40 stars on Github
How It Works?
It works by using Verly.js'sverly.createRope(x, y, segments, gap, pin)
function which takes arguments -x
andy
for location of the rope,segments
which determines the dots count in the rope (more dots, more fluid rope),gap
which specifies the distance between each dot (more gap, longer rope), and lastlypin
which just pins the defined point.
I created a
verly instance
for every input slider present on the screen.
let DOMSlider= document.getElementById(id);let canvas= document.createElement('canvas');let ctx= canvas.getContext('2d');// canvas width is equal to the slider's widthlet width= DOMSlider.scrollWidth;let height= width/2;canvas.width= width;canvas.height= height;canvas.style.pointerEvents='none';// offsetting the position so its lines upcanvas.style.transform='translate(0, -15px)';DOMSlider.parentElement.appendChild(canvas);// -- then initialized verly// new Verly(iteration, canvas, ctx)let verly=newVerly(50, canvas, ctx);// added some gravityconst gravity=newVector(0,0.3);
after that, I created the rope with
// width / 20 to adjust the segments depending on the screen sizelet rope= verly.createRope(0,0, width/20,17,0);let lastIndex= rope.points.length-1;rope.setGravity(gravity);// i pinned the last dot of the roperope.pin(lastIndex);
Getting the slider's position and applying it to the rope
now the actual part where I fix the last dot's position with the slider's thumb.To do this,We will take the slider'svalue
and normalize it, so it's between 0 and 1 then multiply the value with the width to get the slider's thumb position.
(yeah i did not bother to use shadowDOM because of browser compatibility and vendor issues)
functionsetRopePosition(){// get the normalized value of the sliderlet ratio=(DOMSlider.value- DOMSlider.min)/(DOMSlider.max- DOMSlider.min);// then just apply it to the last dot of the rope rope.points[rope.points.length-1].pos.x=(ratio* width);}// and use event listenerDOMSlider.addEventListener('input', setRopePosition);
Okay, this works!But I noticed something weird behavior with this.
The problem was, for some reason (probably floating point precision) the slider's position was offsetting a bit while moving towards the edge, so I had to think some ways to prevent this. then I ended up with this solution (yeah crazy but works)
functionsetRopePosition(){let ratio=(DOMSlider.value- DOMSlider.min)/(DOMSlider.max- DOMSlider.min);// floating point correctionif(ratio<0.5) ratio+=0.01;if(ratio<0.3) ratio+=0.01;if(ratio>0.6) ratio-=0.01;if(ratio>0.8) ratio-=0.02; rope.points[rope.points.length-1].pos.x=(ratio* width);}
nice!
now we can render the scene and update the physics.
functionanimate(){ ctx.clearRect(0,0, width, height); verly.update();// rendering the rope rope.renderSticks();requestAnimationFrame(animate);}animate();
and we are done!
hopefully, you enjoyed playing with this project, I know because I did.you can give the project a star on GitHub if you liked it, have a beautiful day (or night)