Home > Software engineering >  how to get a pointer pointing at centre of slider thumb? CSS and Jquery
how to get a pointer pointing at centre of slider thumb? CSS and Jquery

Time:04-12

I have a feature to show the price range and the most repeated price (Mode). What i did is i used the range input type and deactivated it (so it can't be moved by user as it's only for illustration).

Below is my HTML, CSS and JS which i guess will explain better my issue

<div >
    <div >
        <span  style="left: ${pinPostion}%;">${mostCommonMaxPrice}</span>
    </div>
    <div >
        <div >${lowestMinPrice}</div>
        <input type="range" min="${lowestMinPrice}" max="${highestMaxPrice}" value="${mostCommonMaxPrice}" disabled>
        <div >${highestMaxPrice}</div>
    </div>
</div>
.range{
  height: 40px;
  width: 130px;
  background: #fff;
  border-radius: 10px;
  padding: 0 32.5px 0 22.5px;
}
.field{
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
}
.field .value{
  position: absolute;
  font-size: 12px;
  color: #4638D2;
  font-weight: 600;
}
.field .value.left{
  left: -15px;
}
.field .value.right{
  right: -21.5px;
}
.range input{
  -webkit-appearance: none;
  width: 100%;
  height: 3px;
  background: #ddd;
  border-radius: 5px;
  outline: none;
  border: none;
  z-index: 2222;
}
.range input::-webkit-slider-thumb{
  -webkit-appearance: none;
  width: 10px;
  height: 10px;
  background: #4638D2 !important;
  border-radius: 50%;
  background: #4638D2;
  border: 1px solid #4638D2;
}
 
.range input::-moz-range-progress{
  background: #4638D2;
}
.sliderValue{
  position: relative;
  width: 100%;
  align-items: center;
}
.sliderValue span{
  font-size: 8px;
  position: absolute;
  height: 22.5px;
  width: 22.5px;
  /*transform: translateX(-70%) scale(0);*/
  font-weight: 600;
  top: -15px;
  line-height: 27.5px;
  z-index: 2;
  color: #fff;
  text-align: center;
}
.sliderValue span.show{
  transform: translateX(-70%) scale(1.3);
}
.sliderValue span:after{
  position: absolute;
  content: '';
  height: 100%;
  width: 100%;
  background: #4638D2;
  border: 3px solid #fff;
  z-index: -1;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  border-bottom-left-radius: 50%;
  box-shadow: 0px 0px 8px rgba(0,0,0,0.1);
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
}
const pinPostion = (((mostCommonMaxPrice - lowestMinPrice)/(highestMaxPrice - lowestMinPrice)) * 100)   lowestMinPrice;

Price range sliders

enter image description here

As you see in the picture am not able to get the bubble that shows the mode number to point at the slider thumb position, it is only showing well when it's 100 but if it's more or less then it goes off position, I tried to calculate the percentage and pass it as a variable but it's still coming off, am not sure if my CSS is wrong or is it the equation am using or am I doing all this altogether wrong and there is an easier way to do it. I really appreciate your help. And would be grateful if you up the question, please :)

CodePudding user response:

I found some code example here, it uses similar to yours approach with manual position calculation for Value Bubble, try it:

const allRanges = document.querySelectorAll(".range-wrap");
allRanges.forEach(wrap => {
  const range = wrap.querySelector(".range");
  const bubble = wrap.querySelector(".bubble");

  range.addEventListener("input", () => {
    setBubble(range, bubble);
  });
  setBubble(range, bubble);
});

function setBubble(range, bubble) {
  const val = range.value;
  const min = range.min ? range.min : 0;
  const max = range.max ? range.max : 100;
  const newVal = Number(((val - min) * 100) / (max - min));
  bubble.innerHTML = val;

  // Sorta magic numbers based on size of the native UI thumb
  bubble.style.left = `calc(${newVal}%   (${8 - newVal * 0.15}px))`;
}
.range-wrap {
  position: relative;
  margin: 0 auto 3rem;
}
.range {
  width: 100%;
}
.bubble {
  background: red;
  color: white;
  padding: 4px 12px;
  position: absolute;
  border-radius: 4px;
  left: 50%;
  transform: translateX(-50%);
}
.bubble::after {
  content: "";
  position: absolute;
  width: 2px;
  height: 2px;
  background: red;
  top: -1px;
  left: 50%;
}

body {
  margin: 2rem;
}
<div >
  <input type="range" >
  <output ></output>
</div>

<div >
  <input type="range"  min="20" max="940">
  <output ></output>
</div>

<div  style="width: 75%;">
  <input type="range"  min="50" max="60" step="2">
  <output ></output>
</div>

<div  style="width: 55%;">
  <input type="range"  min="-20" max="20">
  <output ></output>
</div>

I found it here enter image description here

If I further take the transform off, this is how it looks

enter image description here

Even I port the number to your example, the pinpoint is off a little bit.

.range {
  height: 40px;
  width: 130px;
  background: #fff;
  border-radius: 10px;
  padding: 0 32.5px 0 22.5px;
}

.field {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
}

.field .value {
  position: absolute;
  font-size: 12px;
  color: #4638D2;
  font-weight: 600;
}

.field .value.left {
  left: -15px;
}

.field .value.right {
  right: -21.5px;
}

.range input {
  -webkit-appearance: none;
  width: 100%;
  height: 3px;
  background: #ddd;
  border-radius: 5px;
  outline: none;
  border: none;
  z-index: 2222;
}

.range input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 10px;
  height: 10px;
  background: #4638D2 !important;
  border-radius: 50%;
  background: #4638D2;
  border: 1px solid #4638D2;
}

.range input::-moz-range-progress {
  background: #4638D2;
}

.sliderValue {
  position: relative;
  width: 100%;
  align-items: center;
}

.sliderValue span {
  font-size: 8px;
  position: absolute;
  height: 22.5px;
  width: 22.5px;
  /*transform: translateX(-70%) scale(0);*/
  font-weight: 600;
  top: -15px;
  line-height: 27.5px;
  z-index: 2;
  color: #fff;
  text-align: center;
}

.sliderValue span.show {
  transform: translateX(-70%) scale(1.3);
}

.sliderValue span:after {
  position: absolute;
  content: '';
  height: 100%;
  width: 100%;
  background: #4638D2;
  border: 3px solid #fff;
  z-index: -1;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  border-bottom-left-radius: 50%;
  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.1);
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
}
<div >
  <div >
    <span  style="left: 50%;">50</span>
  </div>
  <div >
    <div >0</div>
    <input type="range" min="0" max="100" value="50" disabled>
    <div >100</div>
  </div>
</div>

  • Related