Ben H
Ben H

Reputation: 512

Convert value to percentage using jquery for custom progress bar

I am trying to create a list of progress bars.

The values will be between 15 and 30.

The idea is that 15 is 50% and 30 is 100%. What I'm having trouble with is using jquery to set the width of each element/progress bar to the correct width percentage according to the value provided in the data attribute.

If the value is 15 then the bar width should be 50%. If the vaule is 30 then the bar width should be 100%.

I cannot work out what the calculation would be to make this happen?

I don't have any jQuery to show as i've not had any success so it would just be non-sense i'm afraid.

My HTML is as follows though:

.Progress {
  width: 100%;
  background-color: #ddd;
  height: 30px;
  margin-bottom: 10px;
}

.Bar {
  width: 45%;
  height: 30px;
  background-color: #4CAF50;
  padding-left: 10px;
  padding-right: 10px;
  line-height: 30px;
  color: white;
  display: block;
}

.name {
  float: left;
}

.pct {
  float: right;
}
<div class="Progress">
  <div class="Bar" data-value="15">
    <div class="name">NAME</div>
    <div class="pct">15%</div>
  </div>
</div>

<div class="Progress">
  <div class="Bar" data-value="20">
    <div class="name">NAME</div>
    <div class="pct">20%</div>
  </div>
</div>

<div class="Progress">
  <div class="Bar" data-value="25">
    <div class="name">NAME</div>
    <div class="pct">25%</div>
  </div>
</div>

<div class="Progress">
  <div class="Bar" data-value="30">
    <div class="name">NAME</div>
    <div class="pct">30%</div>
  </div>
</div>

I realised I needed to acheive a slightly different outcome in the end.

My goal was to have a min and max value. If the value was <= the min value the width of the progress bar would be set to 50% and if the value was >= the max value it would be set to 100% and then automatically calculated in between these values.

Using the below 2 functions I was able to acheive this

function range(start, end, step = 1) {
  const len = Math.floor((end - start) / step) + 1
  return Array(len).fill().map((_, idx) => start + (idx * step))
}
function trust15width(value) {
	var lowEnd = 15; // This is the minimum value to be calculated
	var highEnd = 18; // this is the maximum value to be calculated
	
	if(value > highEnd) {
    // if the value is bigger than the maximum value, force the percentage to be 100
		var newWidth = 100;
	} else if(value < lowEnd) {
  // if the value is smaller than the minimum value, force the percentage to be 50
		var newWidth = 50;
	} else {
  
		var result = range(lowEnd, highEnd, 0.1); // Change these variables for the start and end of the range. 
		var increments = result.length;
		var percentageIncrease = 50 / result.length;
		var position = result.indexOf(value)+1; // change this number according to the market share
		var newWidth = 50 + (position * percentageIncrease);
		
	}
	return newWidth;
    }

 console.log(trust15width(14.7));

Upvotes: 0

Views: 6820

Answers (5)

Tushar Walzade
Tushar Walzade

Reputation: 3819

Here's a full proof solution with corresponding mathematics -

  • Shows the percentage on bars
  • Set maximum value dynamically, in your case it's 30
  • Handled two worst cases -
    1. For data-value < 1, shows 0%
    2. For data-value > Max, shows 100%

function findPercentagePer30(x, max) {
    return ((x / max) * 100).toFixed(2).replace(/[.,]00$/, "");
}

$(function() {
    $('.Bar').each(function() {
      var dataVal = $(this).attr("data-value");
      var percentage = findPercentagePer30(dataVal, 30);    // max = 30 here
      if(percentage > 0) {
        percentage = percentage <= 100 ? percentage : 100;
      	$(this).css("width", percentage + '%');
      	$(this).find(".pct:first").text(percentage + '%');
      } else {
      	$(this).css("background-color", 'transparent');
        $(this).find(".pct:first").text('0%');
      }
    });
});
.Progress {
  width: 100%;
  background-color: #ddd;
  height: 30px;
  margin-bottom: 10px;
}

.Bar {
  width: 45%;
  height: 30px;
  background-color: #4CAF50;
  padding-left: 10px;
  padding-right: 10px;
  line-height: 30px;
  color: white;
  display: block;
  box-sizing: border-box;    /* <-- added this */
}

.name {
  float: left;
}

.pct {
  float: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="Progress">
  <div class="Bar" data-value="15"><div class="name">NAME</div><div class="pct">15%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="20"><div class="name">NAME</div><div class="pct">20%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="25"><div class="name">NAME</div><div class="pct">25%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="30"><div class="name">NAME</div><div class="pct">30%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="0"><div class="name">WORST CASE (data-value &lt; 1)</div><div class="pct">0%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="35"><div class="name">WORST CASE (data-value &gt; Max)</div><div class="pct">35%</div></div>
</div>

  • Note: Remember to add box-sizing: border-box; to your .Bar, so that all bars will look uniform.

Upvotes: 1

jogoe
jogoe

Reputation: 324

this is the jQuery code you need :D

edit: oh no seems like i was to slow :(

edit2: alright, now dynamic and right numbers

$( document ).ready(function() {
    var max = 0;
    $('.Bar').each(function(i, obj) {
      if ($(this).data("value") > max){
        max = $(this).data("value");
      }
    });
    
    $('.Bar').each(function(i, obj) {
      $(this).css("width", (100/max)*$(this).data("value")+"%");
      $(this).find(".pct").html(Math.round((100/max)*$(this).data("value"))+"%");
    });
});
.Progress {
  width: 100%;
  background-color: #ddd;
  height:30px;
  margin-bottom:10px;
}

.Bar {
  width: 45%;
  height: 30px;
  background-color: #4CAF50;
  padding-left:10px;
  padding-right:10px;
  line-height: 30px;
  color: white;
  display:block;
}
.name {
float:left;
}
.pct {
float:right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="Progress">
  <div class="Bar" data-value="15"><div class="name">NAME</div><div class="pct">15%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="20"><div class="name">NAME</div><div class="pct">20%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="25"><div class="name">NAME</div><div class="pct">25%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="30"><div class="name">NAME</div><div class="pct">30%</div></div>
</div>

Upvotes: 1

Seba99
Seba99

Reputation: 1319

Using JQuery .each() on your Bar and setting the CSS width attribute by getting the data-value and doing some simple Math percentages would do the trick

$( ".Bar" ).each(function() {
  let percent = $(this).attr('data-value');
  percent = percent * 100 / 30;
  
  //For too high values :
  if(percent > 100){
    percent = 100;
  }
  
  //$(this).css('width', percent+'%' );
  
  //With animation as asked :
    $(this).animate({width: percent+'%' }, 2000);
});
.Progress {
  width: 100%;
  background-color: #ddd;
  height:30px;
  margin-bottom:10px;
}

.Bar {
  width: 45%;
  height: 30px;
  background-color: #4CAF50;
  padding-left:10px;
  padding-right:10px;
  line-height: 30px;
  color: white;
  display:block;
}
.name {
float:left;
}
.pct {
float:right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="Progress">
  <div class="Bar" data-value="15"><div class="name">NAME</div><div class="pct">15%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="20"><div class="name">NAME</div><div class="pct">20%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="25"><div class="name">NAME</div><div class="pct">25%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="30"><div class="name">NAME</div><div class="pct">30%</div></div>
</div>

Upvotes: 2

Maheer Ali
Maheer Ali

Reputation: 36594

You need to divide 30 by the value of .Bar and then multiply it with 100 also. Set box-sizing:border-box

/*$('.Progress').each(function(){
  let value = $(this).find('.Bar').css('width', '30')
  console.log(value);
  let parentWidth = getComputedStyle(this).width;
  
})*/
let total = 30;
$('.Bar').each(function(){
  let value = (parseInt($(this).data().value)/total) * 100;
  $(this).css('width',value + '%')
})
.Progress {
  width: 100%;
  background-color: #ddd;
  height:30px;
  margin-bottom:10px;
}

.Bar {
  box-sizing:border-box;
  height: 30px;
  background-color: #4CAF50;
  padding-left:10px;
  padding-right:10px;
  line-height: 30px;
  color: white;
  display:block;
}
.name {
float:left;
}
.pct {
float:right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="Progress">
  <div class="Bar" data-value="15"><div class="name">NAME</div><div class="pct">15%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="20"><div class="name">NAME</div><div class="pct">20%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="25"><div class="name">NAME</div><div class="pct">25%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="30"><div class="name">NAME</div><div class="pct">30%</div></div>
</div>

Upvotes: 1

doğukan
doğukan

Reputation: 27531

I set the widths according to data-value

let bar = document.querySelectorAll(".Bar");

let biggest_value = 0;

bar.forEach(function(par){
  
  if(Number(par.getAttribute("data-value")) > biggest_value){
    biggest_value = Number(par.getAttribute("data-value"));
  }
});

let rate = 100 / biggest_value;

bar.forEach(function(par){
  par.style.width = (par.getAttribute("data-value")*rate) + "%";
});
* {
  box-sizing:border-box;
}

.Progress {
  width: 100%;
  background-color: #ddd;
  height:30px;
  margin-bottom:10px;
}

.Bar {
  width: 45%;
  height: 30px;
  background-color: #4CAF50;
  padding-left:10px;
  padding-right:10px;
  line-height: 30px;
  color: white;
  display:block;
}
.name {
float:left;
}
.pct {
float:right;
}
<div class="Progress">
  <div class="Bar" data-value="15"><div class="name">NAME</div><div class="pct">15%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="20"><div class="name">NAME</div><div class="pct">20%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="25"><div class="name">NAME</div><div class="pct">25%</div></div>
</div>

<div class="Progress">
  <div class="Bar" data-value="30"><div class="name">NAME</div><div class="pct">30%</div></div>
</div>

Upvotes: 1

Related Questions