{"componentChunkName":"component---src-templates-case-study-js","path":"/case-studies/verly-range-slider","result":{"data":{"markdownRemark":{"id":"304bf971-9851-57fd-8983-ac61e4a95ee1","html":"<p>While I was building my physics engine <a href=\"http://anuraghazra.github.io/Verly.js\">Verly.js</a> 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. </p>\n<ul>\n<li>so far VerlyRangeSlider got over <strong>18K Views</strong> on <a href=\"https://codepen.io/anuraghazra/pen/agKJEd\">Codepen</a></li>\n<li>got mentioned in <strong><a href=\"https://codepen.io/spark/136\">CodepenSpark #136</a></strong></li>\n<li>showcased in <strong><a href=\"https://justforfun.io/post/verly-range-slider\">justforfun.io</a></strong></li>\n<li>and <strong>40 stars</strong> on Github</li>\n</ul>\n<h2 id=\"How-It-Works\"><a href=\"#How-It-Works\" aria-label=\"How It Works permalink\" class=\"gatsby-remark-autolink\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How It Works?</h2>\n<p>It works by using Verly.js's <code class=\"language-text\">verly.createRope(x, y, segments, gap, pin)</code> function which takes arguments - <code class=\"language-text\">x</code> and <code class=\"language-text\">y</code> for location of the rope, <code class=\"language-text\">segments</code> which determines the dots count in the rope (more dots, more fluid rope), <code class=\"language-text\">gap</code> which specifies the distance between each dot (more gap, longer rope), and lastly <code class=\"language-text\">pin</code> which just pins the defined point.</p>\n<blockquote>\n<p>I created a <code class=\"language-text\">verly instance</code> for every input slider present on the screen. </p>\n</blockquote>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">let</span> DOMSlider <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">let</span> canvas <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'canvas'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">let</span> ctx <span class=\"token operator\">=</span> canvas<span class=\"token punctuation\">.</span><span class=\"token function\">getContext</span><span class=\"token punctuation\">(</span><span class=\"token string\">'2d'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// canvas width is equal to the slider's width </span>\n<span class=\"token keyword\">let</span> width <span class=\"token operator\">=</span> DOMSlider<span class=\"token punctuation\">.</span>scrollWidth<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">let</span> height <span class=\"token operator\">=</span> width <span class=\"token operator\">/</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\ncanvas<span class=\"token punctuation\">.</span>width <span class=\"token operator\">=</span> width<span class=\"token punctuation\">;</span>\ncanvas<span class=\"token punctuation\">.</span>height <span class=\"token operator\">=</span> height<span class=\"token punctuation\">;</span>\ncanvas<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span>pointerEvents <span class=\"token operator\">=</span> <span class=\"token string\">'none'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// offsetting the position so its lines up</span>\ncanvas<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span>transform <span class=\"token operator\">=</span> <span class=\"token string\">'translate(0, -15px)'</span><span class=\"token punctuation\">;</span>\nDOMSlider<span class=\"token punctuation\">.</span>parentElement<span class=\"token punctuation\">.</span><span class=\"token function\">appendChild</span><span class=\"token punctuation\">(</span>canvas<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// -- then initialized verly</span>\n<span class=\"token comment\">// new Verly(iteration, canvas, ctx)</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">let</span> verly <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Verly</span><span class=\"token punctuation\">(</span><span class=\"token number\">50</span><span class=\"token punctuation\">,</span> canvas<span class=\"token punctuation\">,</span> ctx<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"token comment\">// added some gravity</span>\n<span class=\"token keyword\">const</span> gravity <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Vector</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.3</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>after that, I created the rope with</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token comment\">// width / 20 to adjust the segments depending on the screen size</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">let</span> rope <span class=\"token operator\">=</span> verly<span class=\"token punctuation\">.</span><span class=\"token function\">createRope</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> width <span class=\"token operator\">/</span> <span class=\"token number\">20</span><span class=\"token punctuation\">,</span> <span class=\"token number\">17</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"token keyword\">let</span> lastIndex <span class=\"token operator\">=</span> rope<span class=\"token punctuation\">.</span>points<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n\nrope<span class=\"token punctuation\">.</span><span class=\"token function\">setGravity</span><span class=\"token punctuation\">(</span>gravity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">// i pinned the last dot of the rope</span>\nrope<span class=\"token punctuation\">.</span><span class=\"token function\">pin</span><span class=\"token punctuation\">(</span>lastIndex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<h4 id=\"Getting-the-sliders-position-and-applying-it-to-the-rope\"><a href=\"#Getting-the-sliders-position-and-applying-it-to-the-rope\" aria-label=\"Getting the sliders position and applying it to the rope permalink\" class=\"gatsby-remark-autolink\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Getting the slider's position and applying it to the rope</h4>\n<p>now the actual part where I fix the last dot's position with the slider's thumb.\nTo do this,\nWe will take the slider's <code class=\"language-text\">value</code> and normalize it, so it's between 0 and 1 then multiply the value with the width to get the slider's thumb position. </p>\n<p>(yeah i did not bother to use shadowDOM because of browser compatibility and vendor issues) </p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token function\">setRopePosition</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// get the normalized value of the slider</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">let</span> ratio <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>DOMSlider<span class=\"token punctuation\">.</span>value <span class=\"token operator\">-</span> DOMSlider<span class=\"token punctuation\">.</span>min<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>DOMSlider<span class=\"token punctuation\">.</span>max <span class=\"token operator\">-</span> DOMSlider<span class=\"token punctuation\">.</span>min<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>  <span class=\"token comment\">// then just apply it to the last dot of the rope</span>\n  rope<span class=\"token punctuation\">.</span>points<span class=\"token punctuation\">[</span>rope<span class=\"token punctuation\">.</span>points<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>pos<span class=\"token punctuation\">.</span>x <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>ratio <span class=\"token operator\">*</span> width<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// and use event listener</span>\nDOMSlider<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'input'</span><span class=\"token punctuation\">,</span> setRopePosition<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Okay, this works!\nBut I noticed something weird behavior with this.</p>\n<p>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)</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token function\">setRopePosition</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> ratio <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>DOMSlider<span class=\"token punctuation\">.</span>value <span class=\"token operator\">-</span> DOMSlider<span class=\"token punctuation\">.</span>min<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>DOMSlider<span class=\"token punctuation\">.</span>max <span class=\"token operator\">-</span> DOMSlider<span class=\"token punctuation\">.</span>min<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token comment\">// floating point correction</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>ratio <span class=\"token operator\">&lt;</span> <span class=\"token number\">0.5</span><span class=\"token punctuation\">)</span> ratio <span class=\"token operator\">+=</span> <span class=\"token number\">0.01</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>ratio <span class=\"token operator\">&lt;</span> <span class=\"token number\">0.3</span><span class=\"token punctuation\">)</span> ratio <span class=\"token operator\">+=</span> <span class=\"token number\">0.01</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>ratio <span class=\"token operator\">></span> <span class=\"token number\">0.6</span><span class=\"token punctuation\">)</span> ratio <span class=\"token operator\">-=</span> <span class=\"token number\">0.01</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>ratio <span class=\"token operator\">></span> <span class=\"token number\">0.8</span><span class=\"token punctuation\">)</span> ratio <span class=\"token operator\">-=</span> <span class=\"token number\">0.02</span><span class=\"token punctuation\">;</span></span>\n  rope<span class=\"token punctuation\">.</span>points<span class=\"token punctuation\">[</span>rope<span class=\"token punctuation\">.</span>points<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>pos<span class=\"token punctuation\">.</span>x <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>ratio <span class=\"token operator\">*</span> width<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>nice!</p>\n<p>now we can render the scene and update the physics.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token function\">animate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  ctx<span class=\"token punctuation\">.</span><span class=\"token function\">clearRect</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> width<span class=\"token punctuation\">,</span> height<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  verly<span class=\"token punctuation\">.</span><span class=\"token function\">update</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token comment\">// rendering the rope</span>\n  rope<span class=\"token punctuation\">.</span><span class=\"token function\">renderSticks</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">requestAnimationFrame</span><span class=\"token punctuation\">(</span>animate<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">animate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>and we are done!</p>\n<blockquote>\n<p>hopefully, you enjoyed playing with this project, I know because I did.\nyou can give the project a star on GitHub if you liked it, have a beautiful day (or night)</p>\n</blockquote>","fields":{"slug":"/case-studies/verly-range-slider"},"frontmatter":{"demo":"//anuraghazra.github.io/VerlyRangeSlider","iframe":"//codepen.io/anuraghazra/embed/agKJEd/?default-tab=result&theme-id=light","src":"//github.com/anuraghazra/VerlyRangeSlider","title":"Verly Range Slider","info":{"idea":"The main idea was to make some verlet simulated ropes and connect them to the rang slider's thumb and let them sway","links":[["On Codepen","https://codepen.io/anuraghazra/pen/agKJEd"],["Verly.js - Physics engine that it uses","https://github.com/anuraghazra/Verly.js"],["Article at DataGenetic | Verlet Simulation","https://datagenetics.com/blog/july22018/index.html"]],"tech":["Javascript","Canvas"]}}}},"pageContext":{"slug":"/case-studies/verly-range-slider"}},"staticQueryHashes":["1033876704"]}