time/DualRangeComponent.mjs
const html = `
<input id="fromSlider" type="range"/>
<input id="toSlider" type="range"/>
<div id="fromSlider-value"></div>
<div id="toSlider-value"></div>
`
const sliderWidth = 4 * 16
const css = `
:host {
display: flex;
flex-direction: column;
position: relative;
color: grey;
}
#fromSlider-value, #toSlider-value {
user-select: none;
position: absolute;
z-index: 1;
}
.sliders_control {
position: relative;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
pointer-events: all;
width: ${sliderWidth}px;
height: 2em;
padding: 0.25em 0.5em;
background-color: #fff;
border-radius: 0.5em;
box-shadow: 0 0 0 1px #C6C6C6;
cursor: pointer;
content: "1234";
}
input[type=range]::-moz-range-thumb {
-webkit-appearance: none;
pointer-events: all;
width: ${sliderWidth}em;
height: 2em;
padding: 0.25em 0.5em;
background-color: #fff;
border-radius: 0.5em;
box-shadow: 0 0 0 1px #C6C6C6;
cursor: pointer;
content: "1234";
}
input[type=range]::-webkit-slider-thumb:hover {
background: #f7f7f7;
}
input[type=range]::-webkit-slider-thumb:active {
box-shadow: inset 0 0 3px #387bbe, 0 0 9px #387bbe;
-webkit-box-shadow: inset 0 0 3px #387bbe, 0 0 9px #387bbe;
}
input[type="range"] {
-webkit-appearance: none;
appearance: none;
height: 2px;
width: 100%;
position: absolute;
background-color: #C6C6C6;
pointer-events: none;
}
#fromSlider {
height: 0;
z-index: 1;
}
`
const template = document.createElement("template")
template.innerHTML = `<style>${css}</style>${html}`
export class DualRangeComponent extends HTMLElement {
sliderColor = "#C6C6C6"
rangeColor = "#25daa5"
fromSlider
fromSliderValue
toSlider
toSliderValue
constructor () {
super()
this.shadow = this.attachShadow({ mode: "open" })
this.shadow.appendChild(template.content.cloneNode(true))
}
connectedCallback () {
this.fromSlider = this.shadow.querySelector("#fromSlider")
this.fromSliderValue = this.shadow.querySelector("#fromSlider-value")
this.toSlider = this.shadow.querySelector("#toSlider")
this.toSliderValue = this.shadow.querySelector("#toSlider-value")
this.fillSlider(this.fromSlider, this.toSlider, this.toSlider)
this.setToggleAccessible(this.toSlider)
this.fromSlider.oninput = () => this.controlFromSlider()
this.toSlider.oninput = () => this.controlToSlider()
this.controlFromSlider()
}
setMin (value) {
this.fromSlider.min = this.fromSlider.min = this.toSlider.min = value
this.fromSlider.setAttribute("value", value)
this.fillSlider(this.fromSlider, this.toSlider, this.toSlider)
}
setMax (value) {
this.fromSlider.max = this.fromSlider.max = this.toSlider.max = value
this.toSlider.setAttribute("value", value)
this.fillSlider(this.fromSlider, this.toSlider, this.toSlider)
}
setPos (el, slider, value) {
const scale = slider.max - slider.min
const deltaValue = value - slider.min
// console.log("deltaValue", deltaValue)
const pos = deltaValue * 100 / scale
// console.log("pos", pos)
el.style.left = `calc(${pos}% + ${(sliderWidth / 2) - pos * 0.65}px)`
}
controlFromSlider () {
const [from, to] = this.getParsed(this.fromSlider, this.toSlider)
this.fillSlider(this.fromSlider, this.toSlider, this.toSlider)
this.fromSlider.value = from > to ? to : from
this.fromSliderValue.textContent = from
this.setPos(this.fromSliderValue, this.fromSlider, this.fromSlider.value)
}
controlToSlider () {
const [from, to] = this.getParsed(this.fromSlider, this.toSlider)
this.fillSlider(this.fromSlider, this.toSlider, this.toSlider)
this.setToggleAccessible(this.toSlider)
this.toSlider.value = from <= to ? to : from
this.toSliderValue.textContent = to
this.setPos(this.toSliderValue, this.toSlider, this.toSlider.value)
}
getParsed (currentFrom, currentTo) {
const from = parseInt(currentFrom.value, 10)
const to = parseInt(currentTo.value, 10)
return [from, to]
}
fillSlider (from, to, controlSlider) {
const rangeDistance = to.max - to.min
const fromPosition = from.value - to.min
const toPosition = to.value - to.min
controlSlider.style.background = `linear-gradient(
to right,
${this.sliderColor} 0%,
${this.sliderColor} ${(fromPosition) / (rangeDistance) * 100}%,
${this.rangeColor} ${((fromPosition) / (rangeDistance)) * 100}%,
${this.rangeColor} ${(toPosition) / (rangeDistance) * 100}%,
${this.sliderColor} ${(toPosition) / (rangeDistance) * 100}%,
${this.sliderColor} 100%)`
}
setToggleAccessible (currentTarget) {
const toSlider = this.shadow.querySelector("#toSlider")
toSlider.style.zIndex = Number(currentTarget.value) <= 0 ? 2 : 0
}
}
const name = "rr0-dual-range"
if (!customElements.get(name)) {
customElements.define(name, DualRangeComponent)
}