function initSliders() { document.querySelectorAll('.double-slider').forEach(setupSlider); } function setupSlider(slider) { const left_input = slider.querySelector('input.left'); const right_input = slider.querySelector('input.right'); const left_thumb = slider.querySelector('.left-thumb'); const right_thumb = slider.querySelector('.right-thumb'); left_thumb.onmousedown = event => { selectLeft(); startDrag(event, left_thumb); } right_thumb.onmousedown = event => { selectRight() startDrag(event, right_thumb); } updateSlider(slider); let x0 = 0; let clientX0 = 0; let input = null; let effective_width = 0; let slider_min_value = 0; let slider_max_value = 0; let slider_range = 0; let thumb_min_value = 0; let thumb_max_value = 0; function selectRight() { input = right_input; thumb_min_value = Math.max(right_input.min, parseInt(left_input.value)); thumb_max_value = right_input.max; } function selectLeft() { input = left_input; thumb_min_value = left_input.min; thumb_max_value = Math.min(left_input.max, parseInt(right_input.value)); } function startDrag(event, thumb) { event = event || window.event; event.preventDefault(); clientX0 = event.clientX; x0 = event.clientX - thumb.getBoundingClientRect().left + slider.getBoundingClientRect().left; effective_width = slider.getBoundingClientRect().width - thumb.getBoundingClientRect().width; slider_min_value = left_input.min; slider_max_value = right_input.max; slider_range = slider_max_value - slider_min_value; document.onmouseup = endDrag; document.onmousemove = drag; } function drag(event) { event = event || window.event; event.preventDefault(); let forceUpdate = false; // calculate mouse position relative to slider let new_thumb_x = event.clientX - x0; new_thumb_x = Math.max(0, Math.min(effective_width, new_thumb_x)); // convert position into value let progress = new_thumb_x / parseFloat(effective_width); let value = Math.round(slider_min_value + (progress * slider_range)); // switch selected thumb if outside thumb value range if (value < parseInt(left_input.value) && input === right_input) { input.value = thumb_min_value; selectLeft(); forceUpdate = true; } else if (value > parseInt(right_input.value) && input === left_input) { input.value = thumb_max_value; selectRight(); forceUpdate = true; } // clamp value value = Math.max(thumb_min_value, Math.min(thumb_max_value, value)); // apply changes if (value !== parseInt(input.value)) { changeValue(input, value); forceUpdate = true; } // update gui if necessary if (forceUpdate) { updateSlider(slider); } } function endDrag() { document.onmouseup = null; document.onmousemove = null; } } function updateSlider(slider) { const left_input = slider.querySelector('input.left'); const right_input = slider.querySelector('input.right'); const slider_min_value = left_input.min; const slider_max_value = right_input.max; const slider_range = slider_max_value - slider_min_value; const left_max_value = left_input.max; const right_min_value = right_input.min; const left_thumb = slider.querySelector('.left-thumb'); const right_thumb = slider.querySelector('.right-thumb'); const bar = slider.querySelector('.bar'); const clampedLeft = Math.max(slider_min_value, Math.min(left_max_value, parseInt(left_input.value))); const clampedRight = Math.max(Math.max(clampedLeft, right_min_value), Math.min(slider_max_value, parseInt(right_input.value))); if (parseInt(left_input.value) !== clampedLeft) { changeValue(left_input, clampedLeft); } if (parseInt(right_input.value) !== clampedRight) { changeValue(right_input, clampedRight); } positionThumbInSlider(left_thumb, left_input.value - slider_min_value, slider_range); positionThumbInSlider(right_thumb, right_input.value - slider_min_value, slider_range); positionBarInSlider(bar, left_input.value - slider_min_value, right_input.value - slider_min_value, slider_range); } function positionThumbInSlider(thumb, position, range) { let progress = position / parseFloat(range); progress = Math.max(0, Math.min(1, progress)); thumb.style.left = 'calc(' + (100 * progress) + '% - ' + (progress) + 'em)'; } function positionBarInSlider(bar, left, right, range) { let leftProgress = left / parseFloat(range); leftProgress = Math.max(0, Math.min(1, leftProgress)); let rightProgress = right / parseFloat(range); rightProgress = Math.max(0, Math.min(1, rightProgress)); bar.style.left = 'calc(' + (100 * leftProgress) + '% - ' + (leftProgress) + 'em)'; bar.style.width = 'calc(' + (100 * (rightProgress - leftProgress)) + '% - ' + (rightProgress - leftProgress) + 'em)'; } function changeValue(input, value) { input.value = value; let evt = document.createEvent('HTMLEvents'); evt.initEvent('change', false, true); input.dispatchEvent(evt); }