<div class="range_container js-range-slider js-filter" data-range-slider-id="slider1" data-type="range-slider" data-title="Air flow range">
<div class="switchers js-switchers">
<div class="switchers__title">Airflow range</div>
<div class="switchers__list">
<label for="radio-1" class="switchers__label">
<input id="radio-1" value="radio-1" type="radio" name="radio" class="switchers__input" checked data-type="radio" data-max-beyond="110" data-step-increments="[10,20,50,100,200,500,1000]" data-steps="[0,70,250,500,2000,5000,15000,50000]">
<span>m/h</span>
</label>
<label for="radio-2" class="switchers__label">
<input id="radio-2" value="radio-2" type="radio" name="radio" class="switchers__input" data-type="radio" data-step-increments="[0.002,0.005,0.015,0.03,0.05,0.1,0.25]" data-steps="[0,0.02,0.07,0.14,0.56,1.39,4.17,13.89]">
<span>m/s</span>
</label>
<label for="radio-3" class="switchers__label">
<input id="radio-3" value="radio-3" type="radio" name="radio" class="switchers__input" data-type="radio" data-max-beyond="140" data-step-increments="[5,10,10,50,50,100,200]" data-steps="[0,20,70,150,550,1400,4100,13900]">
<span>l/s</span>
</label>
</div>
</div>
<div class="sliders_control">
<input class="input" type="range" />
</div>
<div class="form_control">
<div class="form_control_container">
<output class="form_control_container__time__input input-label"></output>
</div>
</div>
</div>
<div class="range_container js-range-slider js-filter" {{{ getattributes attr }}}>
{{> @switchers this }}
<div class="sliders_control">
<input class="input" type="range"/>
</div>
<div class="form_control">
<div class="form_control_container">
<output class="form_control_container__time__input input-label"></output>
</div>
</div>
</div>
{
"attr": {
"data-range-slider-id": "slider1",
"data-type": "range-slider",
"data-title": "Air flow range"
},
"radios": [
{
"name": "radio",
"disabled": false,
"checked": true,
"label": "m/h",
"value": "radio-1",
"type": "radio",
"attr": {
"data-type": "radio",
"data-max-beyond": "110",
"data-step-increments": "[10,20,50,100,200,500,1000]",
"data-steps": "[0,70,250,500,2000,5000,15000,50000]"
}
},
{
"name": "radio",
"disabled": false,
"checked": false,
"label": "m/s",
"value": "radio-2",
"type": "radio",
"attr": {
"data-type": "radio",
"data-step-increments": "[0.002,0.005,0.015,0.03,0.05,0.1,0.25]",
"data-steps": "[0,0.02,0.07,0.14,0.56,1.39,4.17,13.89]"
}
},
{
"name": "radio",
"disabled": false,
"checked": false,
"label": "l/s",
"value": "radio-3",
"type": "radio",
"attr": {
"data-type": "radio",
"data-max-beyond": "140",
"data-step-increments": "[5,10,10,50,50,100,200]",
"data-steps": "[0,20,70,150,550,1400,4100,13900]"
}
}
]
}
import { lerpExt } from '../../functions/lerp';
class RangeSlider {
constructor(el) {
this.step = 0.001;
this.wrapper = el;
this.input = el.querySelector('.input');
this.inputLabel = el.querySelector('.input-label');
this.formControl = el.querySelector('.form_control');
this.reset();
this.input.addEventListener('change', this.handleInputChange.bind(this));
this.input.addEventListener('input', this.handleInputChange.bind(this));
el.addEventListener('reset', this.reset.bind(this));
};
set isDirty(value) {
this.input.setAttribute('isDirty', value);
}
get isDirty() {
return this.input.getAttribute('isDirty') === 'true';
}
reset (e) {
this.input.min = 0;
this.input.max = 1;
this.input.step = this.step;
this.input.value = 1;
this.isDirty = false;
this.render(this.input, '#D1D2D2', '#277D32');
this.renderLabels(this.input);
}
handleInputChange(event) {
this.isDirty = true;
this.render(this.input, '#D1D2D2', '#277D32');
this.renderLabels(this.input);
}
render(input, sliderColor, rangeColor) {
const rangeDistance = input.max - input.min;
const rangePosition = input.value;
input.style.background = `linear-gradient(
to right,
${rangeColor} 0%,
${rangeColor} calc(${(rangePosition) / (rangeDistance) * 100}%),
${sliderColor} calc(${(rangePosition) / (rangeDistance) * 100}%),
${sliderColor} 100%)`;
}
renderLabels(input, precision = 3) {
let stepIncrements;
let steps;
try {
stepIncrements = JSON.parse(this.wrapper.dataset.stepIncrements);
steps = JSON.parse(this.wrapper.dataset.steps);
} catch (e) {
console.error('invalid JSON');
}
if (!stepIncrements || !steps) {
return;
}
// The most left value on range(units)
const minValue = steps[0];
// The most right value on range(units)
const maxValue = steps[steps.length - 1];
// Interval width for single step(0-1)
const stepInterval = 1 / stepIncrements.length;
const stepIndex = Math.floor(input.value / stepInterval); // Index of handle interval
const startValue = steps[stepIndex]; // Start value of handle interval(units)
const endValue = steps[stepIndex + 1] || steps[stepIndex]; // End value of handle interval(units)
// Handle multiplication value(units)
const stepIncrement = stepIncrements[stepIndex] || stepIncrements[stepIncrements.length - 1];
let multValue = lerpExt(startValue, endValue, (input.value - stepIndex * stepInterval) / stepInterval, stepIncrement, precision);
multValue = Math.min(multValue, maxValue);
input.dataset.realValue = multValue;
this.dispatchChange(minValue, maxValue, multValue);
this.inputLabel.textContent = multValue === maxValue ? `${multValue}+` : multValue;
const accordionContent = this.inputLabel.closest('.accordion__content');
if (accordionContent) {
accordionContent.style.display = 'block';
}
const labelContainer = this.inputLabel.parentNode;
const labelHalfWidth = labelContainer.offsetWidth / 2;
const formControlWidth = this.formControl.offsetWidth;
const labelOffset = Math.min(Math.max(this.input.value * formControlWidth, labelHalfWidth), formControlWidth - labelHalfWidth);
labelContainer.style.left = `${labelOffset}px`;
if (accordionContent) {
accordionContent.style.display = '';
}
}
dispatchChange(min, max, input) {
if (this.isDirty) {
this.wrapper.dispatchEvent(new CustomEvent('change', { detail:{
min, max, input, isDirty: this.isDirty
} }));
}
}
}
export default RangeSlider;
import RangeSlider from './RangeSlider';
const els = document.querySelectorAll('.js-range-slider');
for (let el of els) {
new RangeSlider(el);
}
.range_container {
display: flex;
flex-direction: column;
margin: 8px 0px;
}
.sliders_control {
position: relative;
min-height: 7px;
}
.form_control {
position: relative;
display: flex;
justify-content: space-between;
font-size: 14px;
line-height: 20px;
color: #635a5a;
height: 36px;
}
.form_control_container {
position: absolute;
top: 0;
transform: translateX(-50%);
padding: 8px;
background: $color-green-pale;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
pointer-events: all;
width: 12px;
height: 12px;
background-color: $color-green-dark;
border-radius: 50%;
cursor: grab;
z-index: 2;
position: relative;
border: none;
&:focus {
outline: none;
}
}
input[type=range]::-moz-range-thumb {
-webkit-appearance: none;
pointer-events: all;
width: 12px;
height: 12px;
background-color: $color-green-dark;
border-radius: 50%;
cursor: grab;
z-index: 2;
position: relative;
border: none;
&:focus {
outline: none;
}
}
input[type=range]::-webkit-slider-thumb:hover {
border: 2px solid $color-green-dark;
background: $color-green-pale;
cursor: grab;
width: 14px;
height: 14px;
}
input[type=range]::-moz-range-thumb:hover {
border: 2px solid $color-green-dark;
background: $color-green-pale;
cursor: grab;
width: 8px;
height: 8px;
}
input[type=range]::-webkit-slider-thumb:active {
cursor: grabbing;
border: 3px solid $color-green-dark;
}
input[type=range]::-moz-range-thumb:active {
cursor: grabbing;
border: 3px solid $color-green-dark;
width: 8px;
height: 8px;
}
input[type="range"] {
-webkit-appearance: none;
appearance: none;
height: 2px;
width: 100%;
position: absolute;
background-color: $color-green-dark;
pointer-events: none;
&:focus {
outline: 0;
}
}
input[type="range"]:focus-visible::-webkit-slider-thumb {
outline: 2px solid #000;
background: $color-green-pale;
}
input[type="range"]:focus-visible::-moz-range-thumb {
outline: 2px solid $color-black;
background: $color-green-pale;
}
No notes defined.