diff --git a/content/patterns/slider-multithumb/examples/css/slider-multithumb.css b/content/patterns/slider-multithumb/examples/css/slider-multithumb.css index deb555ba4b..5c384f6feb 100644 --- a/content/patterns/slider-multithumb/examples/css/slider-multithumb.css +++ b/content/patterns/slider-multithumb/examples/css/slider-multithumb.css @@ -29,6 +29,7 @@ .slider-multithumb .slider-group .range { fill: currentcolor; opacity: 0.4; + pointer-events: none; } .slider-multithumb .slider-group .thumb { diff --git a/content/patterns/slider-multithumb/examples/js/slider-multithumb.js b/content/patterns/slider-multithumb/examples/js/slider-multithumb.js index fcb2ae6288..dbbb735380 100644 --- a/content/patterns/slider-multithumb/examples/js/slider-multithumb.js +++ b/content/patterns/slider-multithumb/examples/js/slider-multithumb.js @@ -8,6 +8,7 @@ */ 'use strict'; + class SliderMultithumb { constructor(domNode) { this.isMoving = false; @@ -21,6 +22,9 @@ class SliderMultithumb { this.railNode = domNode.querySelector('.rail rect'); this.rangeNode = domNode.querySelector('.range rect'); + this.minSliderPosition = 0; + this.maxSliderPosition = 0; + this.minSliderNode = domNode.querySelector('[role=slider].minimum'); this.maxSliderNode = domNode.querySelector('[role=slider].maximum'); @@ -36,7 +40,7 @@ class SliderMultithumb { // Dimensions of the slider focus ring, thumb and rail this.svgWidth = 360; - this.svgHeight = 80; + this.svgHeight = 100; this.valueTop = 24; this.valueHeight = this.minSliderValueNode.getBoundingClientRect().height; @@ -122,6 +126,8 @@ class SliderMultithumb { this.maxSliderNode.addEventListener('focus', this.onSliderFocus.bind(this)); this.maxSliderNode.addEventListener('blur', this.onSliderBlur.bind(this)); + this.railNode.addEventListener('click', this.onRailClick.bind(this)); + this.moveSliderTo(this.minSliderNode, this.getValue(this.minSliderNode)); this.moveSliderTo(this.maxSliderNode, this.getValue(this.maxSliderNode)); } @@ -149,30 +155,29 @@ class SliderMultithumb { } isInRange(sliderNode, value) { - let valueMin = this.getValueMin(sliderNode); - let valueMax = this.getValueMax(sliderNode); + const valueMin = this.getValueMin(sliderNode); + const valueMax = this.getValueMax(sliderNode); return value <= valueMax && value >= valueMin; } isOutOfRange(value) { - let valueMin = this.getValueMin(this.minSliderNode); - let valueMax = this.getValueMax(this.maxSliderNode); + const valueMin = this.getValueMin(this.minSliderNode); + const valueMax = this.getValueMax(this.maxSliderNode); return value > valueMax || value < valueMin; } getXFromThumb(node) { - var points = node.getAttribute('points').split(','); + const points = node.getAttribute('points').split(','); return parseInt(points[0]); } moveSliderTo(sliderNode, value) { - var valueMax, - valueMin, - pos, - x, - points = '', - width, - dollarValue; + let valueMax; + let valueMin; + let pos; + let points = ''; + let x; + let width; if (this.isMinSlider(sliderNode)) { valueMin = this.getValueMin(this.minSliderNode); @@ -185,7 +190,7 @@ class SliderMultithumb { value = Math.min(Math.max(value, valueMin), valueMax); sliderNode.setAttribute('aria-valuenow', value); - dollarValue = '$' + value; + const dollarValue = `$${value}`; pos = this.railX; pos += Math.round( @@ -194,6 +199,8 @@ class SliderMultithumb { ); if (this.isMinSlider(sliderNode)) { + this.minSliderPosition = pos; + // update ARIA attributes this.minSliderValueNode.textContent = dollarValue; this.maxSliderNode.setAttribute('aria-valuemin', value); @@ -209,7 +216,7 @@ class SliderMultithumb { // Position value width = this.minSliderValueNode.getBoundingClientRect().width; - pos = pos + (this.thumbWidth - width) / 2; + pos += (this.thumbWidth - width) / 2; if (pos + width > this.maxSliderLeft - 2) { pos = this.maxSliderLeft - width - 2; } @@ -217,6 +224,8 @@ class SliderMultithumb { this.minSliderRight = pos; } else { // update label and ARIA attributes + this.maxSliderPosition = pos; + this.maxSliderValueNode.textContent = dollarValue; this.minSliderNode.setAttribute('aria-valuemax', value); @@ -229,7 +238,10 @@ class SliderMultithumb { points += ` ${pos + this.thumb2Width},${this.thumbBottom}`; this.maxSliderThumbNode.setAttribute('points', points); - width = this.maxSliderValueNode.getBoundingClientRect().width; + width = Math.max( + 0, + this.maxSliderValueNode.getBoundingClientRect().width + ); pos = pos + this.thumbWidth + (this.thumbWidth - width) / 2; if (pos - width < this.minSliderRight + 2) { pos = this.minSliderRight + width + 2; @@ -249,11 +261,11 @@ class SliderMultithumb { } onSliderKeydown(event) { - var flag = false; - var sliderNode = event.currentTarget; - var value = this.getValue(sliderNode); - var valueMin = this.getValueMin(sliderNode); - var valueMax = this.getValueMax(sliderNode); + let flag = false; + const sliderNode = event.currentTarget; + const value = this.getValue(sliderNode); + const valueMin = this.getValueMin(sliderNode); + const valueMax = this.getValueMax(sliderNode); switch (event.key) { case 'ArrowLeft': @@ -326,14 +338,14 @@ class SliderMultithumb { this.movingSliderNode && this.domNode.contains(event.target) ) { - var x = this.getSVGPoint(event).x - this.railX; + let x = this.getSVGPoint(event).x - this.railX; if (this.isMinSliderMoving) { x = Math.max(0, x - this.thumbWidth / 3); } else { x = Math.max(0, x - (5 * this.thumbWidth) / 3); } x = Math.min(x, this.railWidth - this.thumbWidth); - var value = Math.round( + const value = Math.round( (x * this.sliderDiffValue) / (this.railWidth - this.thumbWidth) ); this.moveSliderTo(this.movingSliderNode, value); @@ -347,11 +359,34 @@ class SliderMultithumb { this.isMoving = false; this.movingSliderNode = false; } + + // handle click event on the rail + onRailClick(event) { + const x = this.getSVGPoint(event).x - this.railX; + const diffMin = x - this.minSliderPosition - (3 * this.thumbWidth) / 2; + const diffMax = this.maxSliderPosition - x; + const sliderNode = + (x < this.minSliderPosition || diffMin < diffMax) && + x < this.maxSliderPosition + ? this.minSliderNode + : this.maxSliderNode; + + let p = Math.max(0, x - this.thumbWidth); + p = Math.min(p, this.railWidth - this.thumbWidth); + const value = Math.round( + (p * this.sliderDiffValue) / (this.railWidth - this.thumbWidth) + ); + + this.moveSliderTo(sliderNode, value); + + event.preventDefault(); + event.stopPropagation(); + } } // Initialize Multithumb Slider widgets on the page -window.addEventListener('load', function () { - var slidersMultithumb = document.querySelectorAll('.slider-multithumb'); +window.addEventListener('load', () => { + const slidersMultithumb = document.querySelectorAll('.slider-multithumb'); for (let i = 0; i < slidersMultithumb.length; i++) { new SliderMultithumb(slidersMultithumb[i]);