How To Build A Range Slider With Three Pointers And Four Values

SidramaraddySidramaraddy
6 min read

Sliders are common user interface components that allow users to select a value from a range. By adding multiple pointers to a single slider, we can provide more flexibility in selecting multiple values. Our goal is to implement a slider with three draggable pointers, each representing a specific value within the slider’s range.

We know how to make a slider of range with two pointers only by using normal HTML tags like

<input type="range" id="points" name="points" min="0" max="10">

Result of the above code :

<input type="range" class="min" min="0" max="1000" value="300" step="10">
<input type="range" class="max" min="0" max="1000" value="700" step="10">

Result of the above code :

But how to make a single slider with three pointers and four values, don’t worry here you can see the solution using normal HTML, CSS, and Javascript

Before we begin, make sure you have a basic understanding of HTML, CSS, and JavaScript. Also, ensure you have a code editor like Visual Studio Code or Sublime Text to write and test your code.

Step 1: Setting up the HTML structure


  <div class="slider-container">
    <div class="slider-track"></div>
    <div class="slider-pointer" data-value="50" style="left: 50%;"></div>
    <div class="slider-pointer" data-value="90" style="left: 90%;"></div>
    <div class="slider-pointer" data-value="100" style="left: 100%;"></div>
  </div>
  <div class="result-container">
    <div>Value 1: <span id="value1">50</span></div>
    <div>Value 2: <span id="value2">40</span></div>
    <div>Value 3: <span id="value3">10</span></div>
    <div>Value 4: <span id="value4">0</span></div>
  </div>

Step 2: Styling the slider with CSS

.slider-container {
  position: relative;
  width: 100%;
  height: 20px;
  background-color: #ddd;
}

.slider-track {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #333;
}

.slider-pointer {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #0066cc;
  cursor: pointer;
}

.result-container {
  margin-top: 20px;
  font-size: 16px;
}

Step 3: Implementing the JavaScript logic

const sliderContainer = document.querySelector(".slider-container");
const sliders = document.querySelectorAll(".slider-pointer");
const value1 = document.getElementById("value1");
const value2 = document.getElementById("value2");
const value3 = document.getElementById("value3");
const value4 = document.getElementById("value4");

function updateValues() {
  const values = Array.from(sliders).map((slider) => Number(slider.dataset.value));
  value1.textContent = values[0];
  value2.textContent = values[1] - values[0];
  value3.textContent = values[2] - values[1];
  value4.textContent = 100 - (values[2] - values[1] + values[1] - values[0] + values[0]);


}

sliders.forEach((slider) => {
  slider.addEventListener("mousedown", (e) => {
    const target = e.target;
    const sliderWidth = target.parentNode.offsetWidth;
    let prevX = e.clientX;

    function onMouseMove(e) {
      const deltaX = e.clientX - prevX;
      const newPosition = Math.min(Math.max(target.offsetLeft + deltaX, 0), sliderWidth);
      prevX = e.clientX;

      target.style.left = newPosition + "px";
      target.dataset.value = Math.round((newPosition / sliderWidth) * 100);
      updateValues();
    }

    function onMouseUp() {
      document.removeEventListener("mousemove", onMouseMove);
      document.removeEventListener("mouseup", onMouseUp);
    }

    document.addEventListener("mousemove", onMouseMove);
    document.addEventListener("mouseup", onMouseUp);
  });
});

// Update the values initially
updateValues();

Results :

But how to implement the same code on Angular or React framework?

Implement code using the Angular framework.

Step 1: app.component.html code looks

<div class="slider-container">
    <div class="slider-track" ></div>

    <div
      class="slider-pointer"
      *ngFor="let slider of sliders; let i = index"
      [style.left]="slider.position"
      [attr.data-value]="slider.value"
      (mousedown)="onDragStart($event, i)"
    ></div>
  </div>
  <div class="result-container">
    <div class="easy-slider ">
      <div>Easy</div>
      <div>{{value1}}%</div>   
    </div>
    <div class="medium-slider ">
      <div>Medium</div>
      <div>{{value2}}%</div>   
    </div><div class="hard-slider ">
      <div>Hard</div>
      <div>{{value3}}%</div>   
    </div>
    <div class="hardest-slider ">
      <div>Hardest</div>
      <div>{{value4}}%</div>   
    </div>

  </div>

Step 2: app.component.css code looks

.slider-container {
  position: relative;
  width: 30%;
  height: 20px;
  background-color: #ddd;
  margin-left:200px;
  margin-top:50px;
}

.slider-track {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #333;
}

.slider-pointer {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #0066cc;
  cursor: pointer;
}

.result-container {
  margin-top: 20px;
  font-size: 16px;
  margin-left:400px;
}
.slider-container {
  position: relative;
  width: 30%;
  height: 20px;
  background-color: #ddd;
  margin-left:200px;
  margin-top:50px;
}

.slider-track {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #333;
}

.slider-pointer {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #0066cc;
  cursor: pointer;
}

.result-container {
  margin-top: 20px;
  font-size: 16px;
  margin-left:400px;
}

Step 3: app.component.ts code looks

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit{
  value1=50;
  value2=40;
  value3=10;
  value4=0; 
  sliders = [
    { value: 50, position: '46%' },
    { value: 90, position: '86%' },
    { value: 100, position: '96%' }
  ];



  constructor() {
    this.onDragStart = this.onDragStart.bind(this);

  }

  ngOnInit(): void {}

  slidersAll = [
    { position: '0%', value: this.value1 },
    { position: '25%', value: this.value2 },
    { position: '50%', value: this.value3 },
    { position: '75%', value: this.value4 },
  ];



  getWidthForSegment(value: number): string {
    const total = this.value1 + this.value2 + this.value3 + this.value4;
    const widthPercentage = (value / total) * 100;
    return `${widthPercentage}%`;
  }



  onDragStart =(event:any, index: number) => {
    const target = event.target;
    const sliderWidth = target.parentNode.offsetWidth;
    let prevX = event.clientX;

    const onMouseMove = (event:any) => {
      const deltaX = event.clientX - prevX;
      const newPosition = Math.min(Math.max(target.offsetLeft + deltaX, 0), sliderWidth);
      prevX = event.clientX;

      target.style.left = newPosition + 'px';
      target.dataset.value = Math.round((newPosition / sliderWidth) * 100);
      this.sliders[index].value = target.dataset.value;
      this.sliders[index].position = target.style.left;
      this.updateValues();
    }

    const onMouseUp = () => {
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    }

    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  }


  updateValues() {
    const values = this.sliders.map((slider) => Number(slider.value));
    this.value1 = values[0];
    this.value2 = values[1] - values[0];
    this.value3 = values[2] - values[1];
    this.value4 = 100 - (values[2] - values[1] + values[1] - values[0] + values[0]);

  }

}

Implement code using React framework:

Step 1: Create a new React component named “Slider”

import React, { useState } from 'react';
import './Slider.css';

const Slider = () => {
  const [pointer1Value, setPointer1Value] = useState(50);
  const [pointer2Value, setPointer2Value] = useState(90);
  const [pointer3Value, setPointer3Value] = useState(100);

  const [pointer1Position, setPointer1Position] = useState(pointer1Value);
  const [pointer2Position, setPointer2Position] = useState(pointer2Value);
  const [pointer3Position, setPointer3Position] = useState(pointer3Value);

  const updateValues = () => {
    const value2 = pointer2Value - pointer1Value;
    const value3 = pointer3Value - pointer2Value;
    const value4 = 100 - (value2 + value3);
    return { value2, value3, value4 };
  };

  const { value2, value3, value4 } = updateValues();

  const onMouseDown = (event, pointerIndex) => {
    const sliderWidth = event.target.parentNode.offsetWidth;
    let prevX = event.clientX;

    const onMouseMove = (e) => {
      const deltaX = e.clientX - prevX;
      const newPosition = Math.min(Math.max(event.target.offsetLeft + deltaX, 0), sliderWidth);
      prevX = e.clientX;

      if (pointerIndex === 1) {
        setPointer1Position(newPosition);
        setPointer1Value(Math.round((newPosition / sliderWidth) * 100));
      } else if (pointerIndex === 2) {
        setPointer2Position(newPosition);
        setPointer2Value(Math.round((newPosition / sliderWidth) * 100));
      } else if (pointerIndex === 3) {
        setPointer3Position(newPosition);
        setPointer3Value(Math.round((newPosition / sliderWidth) * 100));
      }
    };

    const onMouseUp = () => {
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    };

    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  };

  return (
    <>
      <div className="slider-container">
        <div className="slider-track"></div>
        <div
          className="slider-pointer"
          style={{ left: `${pointer1Position}px` }}
          data-value={pointer1Value}
          onMouseDown={(e) => onMouseDown(e, 1)}
        ></div>
        <div
          className="slider-pointer"
          style={{ left: `${pointer2Position}px` }}
          data-value={pointer2Value}
          onMouseDown={(e) => onMouseDown(e, 2)}
        ></div>
        <div
          className="slider-pointer"
          style={{ left: `${pointer3Position}px` }}
          data-value={pointer3Value}
          onMouseDown={(e) => onMouseDown(e, 3)}
        ></div>
      </div>
      <div className="result-container">
        <div>Value 1: <span id="value1">{pointer1Value}</span></div>
        <div>Value 2: <span id="value2">{value2}</span></div>
        <div>Value 3: <span id="value3">{value3}</span></div>
        <div>Value 4: <span id="value4">{value4}</span></div>
      </div>
    </>
  );
};

export default Slider;

Step 2: Create a CSS file named “Slider.css” and add the following styles

.slider-container {
  position: relative;
  width: 30%;
  height: 20px;
  background-color: #ddd;
  margin-left: 200px;
  margin-top: 50px;
}

.slider-track {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #333;
}

.slider-pointer {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #0066cc;
  cursor: pointer;
}

.result-container {
  margin-top: 20px;
  font-size: 16px;
  margin-left: 400px;
}

As you move each pointer, you will notice that the values are updated accordingly. The third pointer’s position determines the range between the first and third pointers, which is displayed as a blue track.

Congratulations! You’ve successfully created a single slider with three-pointers and four values using HTML, CSS, JavaScript, React, and Angular. This custom slider can be incorporated into various web projects to provide users with a more versatile and interactive way of selecting multiple values within a range. Feel free to enhance the design and functionality further based on your project requirements. Happy coding!

#singleslider #threepointer

10
Subscribe to my newsletter

Read articles from Sidramaraddy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sidramaraddy
Sidramaraddy