Dependent HTML5 sliders
A various amount of HTML input range fields that are connected to each other, and will automatically correct the others when one is changed.
by Annie Lagang
HTML
<h4>Dependent sliders</h4>
<br>
<input type="range" min="0" max="100" step="1" value="0">
<input type="range" min="0" max="100" step="1" value="0">
<input type="range" min="0" max="100" step="1" value="0">
<input type="range" min="0" max="100" step="1" value="0">
CSS
* { margin: 0; padding: 0; }
body { padding: 10px; }
input[type="range"] {
position: relative;
display: block;
width: 300px;
}
input[type="range"]::after {
content: attr(value);
position: absolute;
left: 305px;
}
JavaScript
var elements = document.querySelectorAll('input');
var length = elements.length;
var sliders = Array.prototype.slice.call(elements); // Copy of `elements` but as a real array
var max = 100;
function change(current) {
"use strict";
set(current);
var input = +current.value;
var delta = max - input;
var sum = 0;
var siblings = [];
// Sum of all siblings
sliders.forEach(function (slider) {
if (current != slider) {
siblings.push(slider); // Register as sibling
sum += +slider.value;
}
});
// Update all the siblings
var partial = 0;
siblings.forEach(function (slider, i) {
var val = +slider.value;
var fraction = 0;
// Calculate fraction
if (sum <= 0) {
fraction = 1 / (length - 1)
} else {
fraction = val / sum;
}
// The last element will correct rounding errors
if (i >= length - 1) {
val = max - partial;
} else {
val = Math.round(delta * fraction);
partial += val;
}
set(slider, val);
});
}
// Set value on a slider
function set(elm, val) {
if (val) {
elm.value = val;
}
// Hack to trigger CSS ::after content to be updated
elm.setAttribute('value', elm.value);
}
// Add event listeners to the DOM elements
for (var i = 0, l = elements.length; i < l; i++) {
elements[i].addEventListener('change', function (e) {
change(this);
}, false);
}