スライダー(マルチレンジ)

スライダー(マルチレンジ)

概要

マルチレンジまたはマルチサムスライダーは、ユーザーが最小値と最大値を設定できるように、2つのスライドコントロールがある点を除いて、単純なスライダーと同じ概念に基づいて構築されています。モバイルサポートはマルチレンジスライダーの問題であるため、編集可能なテキストフィールドまたはその他の同様のコントロールでスライダーを補完し、ユーザーが範囲を指定する別の方法を提供するのが賢明です。



スクリーンリーダーをオンにして、この例を実際に体験してください。

属性/オプション 説明
sliderColor この属性/オプションは、メインスライダー/ルーラーの色を指定します。このオプションを指定しない場合は、デフォルトの色が使用されます。
markerColor この属性/オプションはマーカーの色を指定します。このオプションを指定しない場合は、デフォルトの色が使用されます。
getTextValue このオプションは、値をスケールマーカーにとってより意味のある必要なテキストに変換する関数を指定します。このオプションを指定しない場合、値は整数形式で表示されます。
getTextValueDesc このオプションは、値をスクリーンリーダーにとってより意味のある必須のテキスト説明に変換する関数を指定します。このオプションを指定しない場合、値は整数形式で表示されます。
noOfScales このオプションは、スライダーに表示されるマーキング/スケールの数を指定します。デフォルトでは6つのマークが表示されます。
width この属性/オプションは、スライダーウィジェットの幅を指定します。この属性/オプションが指定されていない場合、幅はデフォルト値で設定されます。
ariaDescribedBy この属性/オプションは、スライダーを説明するラベル / 見出し / その他の要素のIDを指定します。この属性/オプションが指定されていない場合、スライダーにはARIAの説明は含まれません。
注意: このオプションは、ナレーターとMicrosoft Edgeブラウザの組み合わせでは機能しません。

オーディオクリップの時間枠

住宅購入の価格帯

月の範囲

HTMLソースコード

<div class="dqu-example">
<table class="data">
    <tr>
        <th width="150px" >属性/オプション</th>
        <th>説明</th>
    </tr>
    <tr>
        <td><code>sliderColor</code></td>
        <td>この属性/オプションは、メインスライダー/ルーラーの色を指定します。このオプションを指定しない場合は、デフォルトの色が使用されます。
        </td>
        </tr>
    <tr>
        <td><code>markerColor</code></td>
        <td>この属性/オプションはマーカーの色を指定します。このオプションを指定しない場合は、デフォルトの色が使用されます。
        </td>
    </tr>
    <tr>
        <td><code>getTextValue</code></td>
        <td>このオプションは、値をスケールマーカーにとってより意味のある必要なテキストに変換する関数を指定します。このオプションを指定しない場合、値は整数形式で表示されます。
        </td>
    </tr>
    <tr>
        <td><code>getTextValueDesc</code></td>
        <td>このオプションは、値をスクリーンリーダーにとってより意味のある必須のテキスト説明に変換する関数を指定します。このオプションを指定しない場合、値は整数形式で表示されます。
        </td>
    </tr>
    <tr>
        <td><code>noOfScales</code></td>
        <td>このオプションは、スライダーに表示されるマーキング/スケールの数を指定します。デフォルトでは6つのマークが表示されます。
        </td>
    </tr>
    <tr>
        <td><code>width</code></td>
        <td>この属性/オプションは、スライダーウィジェットの幅を指定します。この属性/オプションが指定されていない場合、幅はデフォルト値で設定されます。
        </td>
    </tr>    
    <tr>
        <td><code>ariaDescribedBy</code></td>
        <td>この属性/オプションは、スライダーを説明するラベル / 見出し / その他の要素のIDを指定します。この属性/オプションが指定されていない場合、スライダーにはARIAの説明は含まれません。<br/> 注意: このオプションは、ナレーターとMicrosoft Edgeブラウザの組み合わせでは機能しません。
        </td>
    </tr>    
</table>

<div id="slider-seek-label" ><h2>オーディオクリップの時間枠</h2></div>
<div class="slider-seek" id="media-seek-slider" ></div>

<div id="slider-house-label" ><h2>住宅購入の価格帯</h2></div>
<div class="slider-seek" id="house-price-slider"  ></div>

<div id="slider-month-label" ><h2>月の範囲</h2></div>
<div class="slider-seek" id="month-slider"  ></div>
  
  <!--- This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License https://www.w3.org/copyright/software-license-2023/ -->
</div>

JavaScriptソースコード

class SliderMultirange {
    constructor(domNode, min, max, current, higherRange, options ) {
      this.domNode = domNode;
      this.minValue = min;
      this.maxValue = max;
      this.currentValue = current;
      this.higherRange = higherRange;
      
      
      this.isMoving = false;
  
      if ( typeof options != "object" ) options = {};
      this.sliderColor = "";
      if(typeof options["sliderColor"] === "string")
      {
          this.domNode.style.color = options["sliderColor"];
          this.sliderColor = options["sliderColor"];
      }
      this.markerColor = "";
      if(typeof options["markerColor"] === "string")
          this.markerColor = options["markerColor"];
      this.getTextValue = null;
      if(typeof options["getTextValue"] === "function")
          this.getTextValue = options["getTextValue"];
      this.getTextValueDesc = null;
      if(typeof options["getTextValueDesc"] === "function")
          this.getTextValueDesc = options["getTextValueDesc"];
  
      this.width = 300;
      if( (typeof options["width"] === "string") || (typeof options["width"] === "number") )
          this.width = options["width"];
      this.noOfScales = 5;
      if(typeof options["noOfScales"] === "number")
          this.noOfScales = options["noOfScales"];
      this.ariaDescribedBy = "";
      if(typeof options.ariaDescribedBy === "string")
          this.ariaDescribedBy = options.ariaDescribedBy;
      
      
      
      this.domNode.innerHTML = this.getHTMLSetup();
      this.svgNode = domNode.querySelector('svg');
      this.svgPoint = this.svgNode.createSVGPoint();
  
      this.railNode = domNode.querySelector('.rail');
  // Dimensions of the slider focus ring, thumb and rail
  this.railHeight = parseInt(this.railNode.getAttribute('height'));
      this.railWidth = parseInt(this.railNode.getAttribute('width'));
      this.railY = parseInt(this.railNode.getAttribute('y'));
      this.railX = parseInt(this.railNode.getAttribute('x'));
  
      
      this.railNode.setAttribute('y', this.railY);
      this.railNode.setAttribute('x', this.railX);
      this.railNode.setAttribute('height', this.railHeight);
  
  
      this.sliderNode = domNode.querySelector('[role=slider]');
      this.sliderValueNode = this.sliderNode.querySelector('.value');
      this.sliderFocusNode = this.sliderNode.querySelector('.focus-ring');
      this.sliderThumbNode = this.sliderNode.querySelector('.thumb');
      this.valueLabelNodes = domNode.querySelectorAll('.value-label');
      this.thumbWidth = parseInt(this.sliderThumbNode.getAttribute('width'));
      this.thumbHeight = parseInt(this.sliderThumbNode.getAttribute('height'));
      this.focusHeight = parseInt(this.sliderFocusNode.getAttribute('height'));
      this.focusWidth = parseInt(this.sliderFocusNode.getAttribute('width'));
      this.thumbY = this.railY + this.railHeight / 2 - this.thumbHeight / 2;
      this.sliderThumbNode.setAttribute('y', this.thumbY);
      this.focusY = this.railY + this.railHeight / 2 - this.focusHeight / 2;
      this.sliderFocusNode.setAttribute('y', this.focusY);
  
  
      this.highMarker = domNode.querySelector('#id-higher-marker');
      this.highMarkerValueNode = this.highMarker.querySelector('.value');
      this.highMarkerFocusNode = this.highMarker.querySelector('.focus-ring');
      this.highMarkerThumbNode = this.highMarker.querySelector('.thumb');
      this.highMarker.thumbWidth = parseInt(this.highMarkerThumbNode.getAttribute('width'));
      this.highMarker.thumbHeight = parseInt(this.highMarkerThumbNode.getAttribute('height'));
      this.highMarker.focusHeight = parseInt(this.highMarkerFocusNode.getAttribute('height'));
      this.highMarker.focusWidth = parseInt(this.highMarkerFocusNode.getAttribute('width'));
      this.highMarker.thumbY = this.railY + this.railHeight / 2 - this.highMarker.thumbHeight / 2;
      this.highMarkerThumbNode.setAttribute('y', this.highMarker.thumbY);
      this.highMarker.focusY = this.railY + this.railHeight / 2 - this.highMarker.focusHeight / 2;
      this.highMarkerFocusNode.setAttribute('y', this.highMarker.focusY);
  
  
  
      
      // define possible slider positions
      // bind a pointermove event handler to move pointer
      this.svgNode.addEventListener('pointermove', this.onPointerMove.bind(this));
  
      this.sliderNode.addEventListener('keydown',  this.onSliderKeydown.bind(this)  );
      this.sliderNode.addEventListener('pointerdown',  this.onSliderPointerDown.bind(this));
  
      this.highMarker.addEventListener('keydown',  this.onHighMarkerKeydown.bind(this)  );
      this.highMarker.addEventListener('pointerdown',  this.onSliderPointerDown.bind(this));
  
      
  
      // bind a pointerup event handler to stop tracking pointer movements
      this._boundPointerUp = this.onPointerUp.bind(this);
      document.addEventListener('pointerup', this._boundPointerUp);
  
      this.sliderNode.addEventListener('focus', this.onSliderFocus.bind(this));
      this.sliderNode.addEventListener('blur', this.onSliderBlur.bind(this));
  
      this.highMarker.addEventListener('focus', this.onSliderFocus.bind(this));
      this.highMarker.addEventListener('blur', this.onSliderBlur.bind(this));
  
      let deltaPosition = this.railWidth / (this.valueLabelNodes.length - 1);
  
      let position = this.railX;
  
      this.positions = [];
      this.textValues = [];
  
      let maxTextWidth = this.getWidthFromLabelText();
      let textHeight = this.getHeightFromLabelText();
  
      for (let i = 0; i < this.valueLabelNodes.length; i++) {
        let valueLabelNode = this.valueLabelNodes[i];
  
        let textNode = valueLabelNode.querySelector('text');
  
        let w = maxTextWidth + 2;
        let x = position - w / 2;
        let y = this.thumbY + this.thumbHeight;
  
        x = x + (maxTextWidth - textNode.getBoundingClientRect().width) / 2;
        if( x < 0 ) x =0;
        y = y + textHeight;
  
        textNode.setAttribute('x', x);
        textNode.setAttribute('y', y);
  
        this.textValues.push(valueLabelNode.getAttribute('data-value'));
  
        this.positions.push(position);
        position += deltaPosition;
      }
  
      // temporarily show slider value to allow width calc onload
      this.sliderValueNode.setAttribute('style', 'display: block');
      this.moveSliderTo(this.getValue());
      this.sliderValueNode.removeAttribute('style');
  
      this.highMarkerValueNode.setAttribute('style', 'display: block');
      this.moveHighMarkerTo(this.getHighMarkerValue());
      this.highMarkerValueNode.removeAttribute('style');
  
      
      // Include total time in aria-valuetext when loaded
      this.sliderNode.setAttribute(
        'aria-valuetext',
        ( this.getTextValueDesc? this.getTextValueDesc(this.getValue()): this.getValue() )
      );
    }
  
    getHTMLSetup()
    {
      var margin = 80;
      var width = parseInt(this.width);
      var noOfScales = this.noOfScales;
      var increment = (this.maxValue - this.minValue)/noOfScales;
      var ariaDescribedByText = '';
      if(this.ariaDescribedBy.trim() != "" )
          ariaDescribedByText = 'aria-describedby="'+this.ariaDescribedBy+'" ';
  
     var html = `<svg role="none" class="slider-group" width="`+( width+margin)+`" height="120">
      <rect class="rail" x="25" y="50" width="`+ ( width) +`" height="8" rx="5" aria-hidden="true"></rect>
      <g  role="slider" tabindex="0" aria-valuemin="`+this.minValue+`" 
      aria-valuenow="`+this.currentValue+`" aria-valuetext="" aria-valuemax="`+this.maxValue+`"  aria-label="set lower range"  `+ariaDescribedByText+` >
      <text class="value" x="0" y="15"></text>
      <rect class="focus-ring" x="0" y="0" width="28" height="60" rx="12"></rect>
      <rect class="thumb" x="0" y="0" width="14" height="48" rx="5"></rect>
      </g>`;
      
      html += `<g id="id-higher-marker" role="slider" tabindex="0" aria-valuemin="`+this.minValue+`" 
      aria-valuenow="`+this.higherRange+`" aria-valuetext="" aria-valuemax="`+this.maxValue+`" aria-label="set higher range" `+ariaDescribedByText+` >
      <text class="value" x="0" y="15"></text>
      <rect class="focus-ring" x="0" y="0" width="28" height="60" rx="12"></rect>
      <rect class="thumb" x="0" y="0" width="14" height="48" rx="5"></rect>
      </g>`;
      
      for(var i = this.minValue; i <= this.maxValue; i= i + increment)
      {
          var textVal = i;
          if(this.getTextValue) textVal = this.getTextValue(i);
          html += '<g class="value-label" data-value="'+ i +'"><text x="0" y="0">'+ textVal +'</text> </g>';
      }        
      return html;          
    }
  
    getWidthFromLabelText() {
      let width = 0;
      for (let i = 0; i < this.valueLabelNodes.length; i++) {
        let textNode = this.valueLabelNodes[i].querySelector('text');
        if (textNode) {
          width = Math.max(width, textNode.getBoundingClientRect().width);
        }
      }
      return width;
    }
  
    getHeightFromLabelText() {
      let height = 0;
      let textNode = this.valueLabelNodes[0].querySelector('text');
      if (textNode) {
        height = textNode.getBoundingClientRect().height;
      }
      return height;
    }
  
    // Get point in global SVG space
    getSVGPoint(event) {
      this.svgPoint.x = event.clientX;
      this.svgPoint.y = event.clientY;
      return this.svgPoint.matrixTransform(this.svgNode.getScreenCTM().inverse());
    }
  
    getValue() {
      return parseInt(this.sliderNode.getAttribute('aria-valuenow'));
    }
    getValueMin() {
      return parseInt(this.sliderNode.getAttribute('aria-valuemin'));
    }
  
    getValueMax() {
      return parseInt(this.sliderNode.getAttribute('aria-valuemax'));
    }
  
    getHighMarkerValue() {
      return parseInt(this.highMarker.getAttribute('aria-valuenow'));
    }
    getHighMarkerMin() {
      return parseInt(this.highMarker.getAttribute('aria-valuemin'));
    }
  
    getHighMarkerMax() {
      return parseInt(this.highMarker.getAttribute('aria-valuemax'));
    }
  
    
  
    isInRange(value) {
      let valueMin = this.getValueMin();
      let valueMax = this.getValueMax();
      return value <= valueMax && value >= valueMin;
    }
  
    
  
    moveSliderTo(value) {
      let valueMax, valueMin, pos, width;
  
      valueMin = this.getValueMin();
      valueMax = this.getValueMax();
  
      value = Math.min(Math.max(value, valueMin), valueMax);
      if(value >= this.getHighMarkerValue())
          return;
        
      this.sliderNode.setAttribute('aria-valuenow', value);
  
      this.sliderValueNode.textContent = ( this.getTextValue? this.getTextValue(value): value );
  
      width = this.sliderValueNode.getBoundingClientRect().width;
      
      this.sliderNode.setAttribute(
        'aria-valuetext',
        ( this.getTextValueDesc? this.getTextValueDesc(this.getValue()): this.getValue() )
      );
  
      pos =
        this.railX +
        Math.round(((value - valueMin) * this.railWidth) / (valueMax - valueMin));
    
      // move the SVG focus ring and thumb elements
      this.sliderFocusNode.setAttribute('x', pos - this.focusWidth / 2);
      this.sliderThumbNode.setAttribute('x', pos - this.thumbWidth / 2);
      this.sliderValueNode.setAttribute('x', ( (pos - width) > 0 ? (pos - width)  : 0 ));
    }
  
    moveHighMarkerTo(value) {
      let valueMax, valueMin, pos, width;
  
      valueMin = this.getHighMarkerMin();
      valueMax = this.getHighMarkerMax();
  
      value = Math.min(Math.max(value, valueMin), valueMax);
      if(value <= this.getValue())
          return;
      
  
      this.highMarker.setAttribute('aria-valuenow', value);
  
      this.highMarkerValueNode.textContent = ( this.getTextValue? this.getTextValue(value): value );
  
      width = this.highMarkerValueNode.getBoundingClientRect().width;
  
      this.highMarker.setAttribute(
        'aria-valuetext',
        ( this.getTextValueDesc? this.getTextValueDesc(this.getHighMarkerValue()): this.getHighMarkerValue() )
      );
  
      pos =
        this.railX +
        Math.round(((value - valueMin) * this.railWidth) / (valueMax - valueMin));
  
      // move the SVG focus ring and thumb elements
      this.highMarkerFocusNode.setAttribute('x', pos - this.highMarker.focusWidth / 2);
      this.highMarkerThumbNode.setAttribute('x', pos - this.highMarker.thumbWidth / 2);
      this.highMarkerValueNode.setAttribute('x', pos - width / 2);
    }
  
  
    onSliderKeydown(event) {
      var flag = false;
      var value = this.getValue();
      var valueMin = this.getValueMin();
      var valueMax = this.getValueMax();
  
      switch (event.key) {
        case 'ArrowLeft':
        case 'ArrowDown':
          this.moveSliderTo(value - 1);
          flag = true;
          break;
  
        case 'ArrowRight':
        case 'ArrowUp':
          this.moveSliderTo(value + 1);
          flag = true;
          break;
  
        case 'PageDown':
          this.moveSliderTo(value - 15);
          flag = true;
          break;
  
        case 'PageUp':
          this.moveSliderTo(value + 15);
          flag = true;
          break;
  
        case 'Home':
          this.moveSliderTo(valueMin);
          flag = true;
          break;
  
        case 'End':
          this.moveSliderTo(valueMax);
          flag = true;
          break;
  
        default:
          break;
      }
  
      if (flag) {
        event.preventDefault();
        event.stopPropagation();
      }
    }
    onHighMarkerKeydown(event) {
      var flag = false;
      var value = this.getHighMarkerValue();
      var valueMin = this.getHighMarkerMin();
      var valueMax = this.getHighMarkerMax();
  
      switch (event.key) {
        case 'ArrowLeft':
        case 'ArrowDown':
          this.moveHighMarkerTo(value - 1);
          flag = true;
          break;
  
        case 'ArrowRight':
        case 'ArrowUp':
          this.moveHighMarkerTo(value + 1);
          flag = true;
          break;
  
        case 'PageDown':
          this.moveHighMarkerTo(value - 15);
          flag = true;
          break;
  
        case 'PageUp':
          this.moveHighMarkerTo(value + 15);
          flag = true;
          break;
  
        case 'Home':
          this.moveHighMarkerTo(valueMin);
          flag = true;
          break;
  
        case 'End':
          this.moveHighMarkerTo(valueMax);
          flag = true;
          break;
  
        default:
          break;
      }
  
      if (flag) {
        event.preventDefault();
        event.stopPropagation();
      }
    }
    
  
    onSliderFocus() {
      if(this.markerColor != "")
      {
          
         if( document.activeElement == this.sliderNode)
         {
              var valEl = this.sliderNode.querySelector(".value");
              var thumbEl = this.sliderNode.querySelector(".thumb");
              var ringEl = this.sliderNode.querySelector(".focus-ring");
              if (valEl) valEl.style.color = this.markerColor;
              if (thumbEl) thumbEl.style.color = this.markerColor;
              if (ringEl) ringEl.style.color = this.markerColor;
         }
         if( document.activeElement == this.highMarker)
         {
              var valEl = this.highMarker.querySelector(".value");
              var thumbEl = this.highMarker.querySelector(".thumb");
              var ringEl = this.highMarker.querySelector(".focus-ring");
              if (valEl) valEl.style.color = this.markerColor;
              if (thumbEl) thumbEl.style.color = this.markerColor;
              if (ringEl) ringEl.style.color = this.markerColor;
         }
      }
    }
  
    onSliderBlur() {
      this.sliderNode.setAttribute(
        'aria-valuetext',
        ( this.getTextValueDesc? this.getTextValueDesc(this.getValue()): this.getValue() )
      );
      if(this.markerColor != "")
      {
          
          var valEl = this.sliderNode.querySelector(".value");
          var thumbEl = this.sliderNode.querySelector(".thumb");
          var ringEl = this.sliderNode.querySelector(".focus-ring");
          if (valEl) valEl.style.color = "";
          if (thumbEl) thumbEl.style.color = "";
          if (ringEl) ringEl.style.color = "";
      
          var valEl2 = this.highMarker.querySelector(".value");
          var thumbEl2 = this.highMarker.querySelector(".thumb");
          var ringEl2 = this.highMarker.querySelector(".focus-ring");
          if (valEl2) valEl2.style.color = "";
          if (thumbEl2) thumbEl2.style.color = "";
          if (ringEl2) ringEl2.style.color = "";
         
      }
      
    }
  
    onRailClick(event) {
      var x = this.getSVGPoint(event).x;
      var min = this.getValueMin();
      var max = this.getValueMax();
      var diffX = x - this.railX;
      var value = Math.round((diffX * (max - min)) / this.railWidth);
      this.moveSliderTo(value);
  
      event.preventDefault();
      event.stopPropagation();
      // Set focus to the clicked handle
      this.sliderNode.focus();
    }
  
    onSliderPointerDown(event) {
      this.isMoving = true;
      this.movingSlider = event.target;
      event.preventDefault();
      event.stopPropagation();
      // Set focus to the clicked handle
      if(event.target == this.sliderThumbNode )
          this.sliderNode.focus();
      if(event.target == this.highMarkerThumbNode )
          this.highMarker.focus();
  
    }
  
    onPointerMove(event) {
      if (this.isMoving) {
        var x = this.getSVGPoint(event).x;
        var min = this.getValueMin();
        var max = this.getValueMax();
        if(event.target == this.highMarkerThumbNode )
        {
              min = this.getHighMarkerMin();
              max = this.getHighMarkerMax();
        }
        var diffX = x - this.railX;
        var value = Math.round((diffX * (max - min)) / this.railWidth);
        if(this.movingSlider == this.sliderThumbNode )
          this.moveSliderTo(min + value);
        if(this.movingSlider == this.highMarkerThumbNode )
          this.moveHighMarkerTo(min + value);
  
        event.preventDefault();
        event.stopPropagation();
      }
    }
    onMarkerMove(event) {
      if (this.isMoving) {
        var x = this.getSVGPoint(event).x;
        var min = this.getHighMarkerMin();
        var max = this.getHighMarkerMax();
        var diffX = x - this.railX;
        var value = Math.round((diffX * (max - min)) / this.railWidth);
        this.moveHighMarkerTo(min+value);
        event.preventDefault();
        event.stopPropagation();
      }
    }
  
    onPointerUp() {
      this.isMoving = false;
      this.movingSlider = null;
    }

    destroy() {
      document.removeEventListener('pointerup', this._boundPointerUp);
    }
  }
  
  var widgets = {};
  window.addEventListener('load', function () {
    createMediaseekWidget();
    createHousePriceWidget();
    createMonthWidget();
  });
  
  window.addEventListener('resize', function () {
    createMediaseekWidget();
    createHousePriceWidget();
    createMonthWidget();
  });
  
  
  
  
  function createMediaseekWidget()
  {
      let slider = document.querySelector('#media-seek-slider');
      var maxWidth = getMaxWidth();
      var options = {};
      options.sliderColor = "#990c0c";
      options.markerColor = "#225f5f";
      options["getTextValue"] = getMinutesSeconds;
      options["getTextValueDesc"] = getMinutesSecondsText;
      options.noOfScales = 5;
      options.width = ( maxWidth > 600 ? "400": "270" );
      options.ariaDescribedBy = "slider-seek-label";
      widgets["mediaSeek"] = new SliderMultirange(slider,0,300,90,180, options);
  }
  function createHousePriceWidget()
  {
      let slider = document.querySelector('#house-price-slider');
      var maxWidth = getMaxWidth();
      var options = {};
      options.sliderColor = "#333b88";
      options.noOfScales = 5;
      if( maxWidth < 1200 ) options.noOfScales = 4;
      options.width = ( maxWidth > 800 ? maxWidth * .6: maxWidth * .72);
      var formatNumber = function(num){
          if (maxWidth > 1200 ) 
          return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(num);
          return ("$ "+(num/1000)+"K");
      };
      options["getTextValue"] = formatNumber;
      options["getTextValueDesc"] = formatNumber;
      
      var lowRangeVal = 200000;
      var highRangeVal = 600000;
      if(typeof widgets["housePrice"] == "object")
      {
          lowRangeVal = widgets["housePrice"].getValue();
          highRangeVal = widgets["housePrice"].getHighMarkerValue();
      }
      options.ariaDescribedBy = "slider-house-label";
      widgets["housePrice"] = new SliderMultirange(slider,0,1000000,lowRangeVal,highRangeVal, options);
  }
  function getMaxWidth()
  {
      var maxWidth = screen.width;
      if( maxWidth > window.innerWidth ) maxWidth = window.innerWidth;
      return maxWidth;
  }
  function createMonthWidget()
  {
      let slider = document.querySelector('#month-slider');
      var maxWidth = getMaxWidth();
      var formatNumber = function(num){  
          const date = new Date(2020, num, 10);  // 2009-11-10
          const month = date.toLocaleString('ja', { month: 'short' });
          return month;
      };
      var options = {};
      options["getTextValue"] = formatNumber;
      options["getTextValueDesc"] = formatNumber;
      options.noOfScales = 11;
      if( maxWidth < 1000 ) options.noOfScales = 4;
      options.width = ( maxWidth > 800 ? maxWidth * .6: maxWidth * .72);
      options.ariaDescribedBy = "slider-month-label";
      var lowRangeVal = 1;
      var highRangeVal = 8;
      if(typeof widgets["monthRange"] == "object")
      {
          lowRangeVal = widgets["monthRange"].getValue();
          highRangeVal = widgets["monthRange"].getHighMarkerValue();
      }
      widgets["monthRange"] = new SliderMultirange(slider,0,11,lowRangeVal, highRangeVal, options);
  }
  
  function getMinutesSecondsText(value)
  {
      var minutes =  Math.floor( value / 60);
      var seconds =  ( value % 60);
      var valueText = "";
      if(minutes == 1 ) valueText += minutes + " minute ";
      if(minutes > 1 ) valueText += minutes + " minutes ";
      if(seconds == 1 ) valueText += seconds + " second ";
      if(seconds > 1 ) valueText += seconds + " seconds ";
      return valueText;
  }
  
  function getMinutesSeconds(value)
  {
      var minutes =  Math.floor( value / 60);
      var seconds =  ( value % 60);
      if( seconds < 10 ) seconds = "0"+seconds;
      return minutes +":"+ seconds;
  }
  
  
  function htmlSliderChanged(event)
  {
      var slider = event.target;
      var minutes =  Math.floor( slider.value / 60);
      var seconds =  ( slider.value % 60);
      var valueText = getMinutesSecondsText(slider.value);
      if( seconds < 10 ) seconds = "0"+seconds;
      document.getElementById("current-value").textContent = minutes +":"+ seconds;
      document.getElementById("seek-input").setAttribute("aria-valuetext", valueText);
  }
  

CSSソースコード

/*
  Slider (Multirange) — Restyled
  Deque University ARIA Component

  This component has been adapted from an example provided by the W3C,
  in accordance with the W3C Software and Document License
  https://www.w3.org/copyright/software-license-2023/
*/

:root {
  --dqu-interactive: #2e5f7a;
  --dqu-interactive-light: rgba(46, 95, 122, 0.08);
  --dqu-bg-primary: #fcfaf8;
  --dqu-bg-secondary: #f6f3ed;
  --dqu-border-secondary: #8c827d;
  --dqu-text-primary: #21201e;
  --dqu-font-family: "Noto Sans", sans-serif;
}

.slider-seek .label {
  font-weight: 600;
  font-size: 125%;
  font-family: var(--dqu-font-family);
}

.slider-seek svg {
  forced-color-adjust: auto;
}

.slider-seek text {
  font-weight: 600;
  fill: var(--dqu-text-primary);
  font-family: var(--dqu-font-family);
}

.slider-seek {
  margin-top: 1em;
  padding: 6px;
  color: var(--dqu-text-primary);
}

.slider-slider .value {
  position: relative;
  top: 20px;
  height: 1.5em;
  font-size: 80%;
}

.slider-seek .temp-value {
  padding-left: 24px;
  font-size: 200%;
  font-family: var(--dqu-font-family);
}

.slider-seek .rail {
  stroke: var(--dqu-border-secondary);
  stroke-width: 2px;
  fill: var(--dqu-bg-secondary);
  fill-opacity: 0.5;
}

.slider-seek .thumb {
  stroke-width: 0;
  fill: var(--dqu-interactive);
}

.slider-seek .focus-ring {
  stroke: currentcolor;
  stroke-opacity: 0;
  fill-opacity: 0;
  stroke-width: 3px;
  display: none;
}

.slider-seek .slider-group {
  touch-action: pan-y;
}

.slider-seek .slider-group .value {
  display: none;
}

/* Focus and hover styling */
.slider-seek.focus [role="slider"],
.slider-seek [role="slider"] {
  color: var(--dqu-interactive);
}

.slider-seek [role="slider"]:focus {
  outline: none !important;
}

.slider-seek [role="slider"]:focus .focus-ring {
  display: block;
  stroke-opacity: 1;
}

.slider-seek [role="slider"]:focus .value {
  display: block;
}

/* Native HTML range input */
input[type="range"].deque-slider-widget {
  accent-color: var(--dqu-interactive);
  cursor: pointer;
}

input[type="range"].deque-slider-widget:focus-visible {
  outline: 3px solid var(--dqu-interactive) !important;
  outline-offset: 4px;
}

/* Data table */
table.data {
  border-collapse: collapse;
  font-family: var(--dqu-font-family);
  font-size: 0.9375rem;
}

table.data th,
table.data td {
  border: 1px solid var(--dqu-border-secondary);
  padding: 10px 12px;
  text-align: left;
  color: var(--dqu-text-primary);
}

table.data th {
  background: var(--dqu-bg-secondary);
  font-weight: 600;
}

.dqu-example h2, .dqu-example h3 {
  font-family: var(--dqu-font-family);
  color: var(--dqu-text-primary);
}

.dqu-example label {
  font-family: var(--dqu-font-family);
  color: var(--dqu-text-primary);
}

フルページのコピーと貼り付けの例