pjw
pjw

Reputation: 2335

Multiple progress bar circles on single row

I am using this example to create a circle progress bar: https://codepen.io/shellbryson/pen/KzaKLe

However, I would like to have multiple elements together on a row. I have tried this for two elements by adding two separate divs and two separate css IDs (both with display: inline-block;).

This successfully creates two progress bars together, but the first stays at 0%. In this case, the first should go to 90% and the second to 95% (as defined with var end in the js).

enter image description here

var wrapper = document.getElementById('progress1');
    	var start = 0;
    	var end = 90;
    
    	var colours = {
    	  fill: '#' + wrapper.dataset.fillColour,
    	  track: '#' + wrapper.dataset.trackColour,
    	  text: '#' + wrapper.dataset.textColour,
    	  stroke: '#' + wrapper.dataset.strokeColour,
    	}
    
    	var radius = 100;
    	var border = wrapper.dataset.trackWidth;
    	var strokeSpacing = wrapper.dataset.strokeSpacing;
    	var endAngle = Math.PI * 2;
    	var formatText = d3.format('.0%');
    	var boxSize = radius * 2;
    	var count = end;
    	var progress = start;
    	var step = end < start ? -0.01 : 0.01;
    
    	//Define the circle
    	var circle = d3.arc()
    	  .startAngle(0)
    	  .innerRadius(radius)
    	  .outerRadius(radius - border);
    
    	//setup SVG wrapper
    	var svg = d3.select(wrapper)
    	  .append('svg')
    	  .attr('width', boxSize)
    	  .attr('height', boxSize);
    
    	// ADD Group container
    	var g = svg.append('g')
    	  .attr('transform', 'translate(' + boxSize / 2 + ',' + boxSize / 2 + ')');
    
    	//Setup track
    	var track = g.append('g').attr('class', 'radial-progress');
    	track.append('path')
    	  .attr('class', 'radial-progress__background')
    	  .attr('fill', colours.track)
    	  .attr('stroke', colours.stroke)
    	  .attr('stroke-width', strokeSpacing + 'px')
    	  .attr('d', circle.endAngle(endAngle));
    
    	//Add colour fill
    	var value = track.append('path')
    	  .attr('class', 'radial-progress__value')
    	  .attr('fill', colours.fill)
    	  .attr('stroke', colours.stroke)
    	  .attr('stroke-width', strokeSpacing + 'px');
    
    	//Add text value
    	var numberText = track.append('text')
    	  .attr('class', 'radial-progress__text')
    	  .attr('fill', colours.text)
    	  .attr('font-size', '30px')
    	  .attr('text-anchor', 'middle')
    	  .attr('dy', '.5rem');
    
    	function update(progress) {
    	  //update position of endAngle
    	  value.attr('d', circle.endAngle(endAngle * progress));
    	  //update text value
    	  numberText.text(formatText(progress));
    	} 
    
    	(function iterate() {
    	  //call update to begin animation
    	  update(progress);
    	  if (count > 0) {
    	    //reduce count till it reaches 0
    	    count--;
    	    //increase progress
    	    progress += step;
    	    //Control the speed of the fill
    	    setTimeout(iterate, 10);
    	  }
    	})();
    
    var wrapper = document.getElementById('progress2');
    	var start = 0;
    	var end = 95;
    
    	var colours = {
    	  fill: '#' + wrapper.dataset.fillColour,
    	  track: '#' + wrapper.dataset.trackColour,
    	  text: '#' + wrapper.dataset.textColour,
    	  stroke: '#' + wrapper.dataset.strokeColour,
    	}
    
    	var radius = 100;
    	var border = wrapper.dataset.trackWidth;
    	var strokeSpacing = wrapper.dataset.strokeSpacing;
    	var endAngle = Math.PI * 2;
    	var formatText = d3.format('.0%');
    	var boxSize = radius * 2;
    	var count = end;
    	var progress = start;
    	var step = end < start ? -0.01 : 0.01;
    
    	//Define the circle
    	var circle = d3.arc()
    	  .startAngle(0)
    	  .innerRadius(radius)
    	  .outerRadius(radius - border);
    
    	//setup SVG wrapper
    	var svg = d3.select(wrapper)
    	  .append('svg')
    	  .attr('width', boxSize)
    	  .attr('height', boxSize);
    
    	// ADD Group container
    	var g = svg.append('g')
    	  .attr('transform', 'translate(' + boxSize / 2 + ',' + boxSize / 2 + ')');
    
    	//Setup track
    	var track = g.append('g').attr('class', 'radial-progress');
    	track.append('path')
    	  .attr('class', 'radial-progress__background')
    	  .attr('fill', colours.track)
    	  .attr('stroke', colours.stroke)
    	  .attr('stroke-width', strokeSpacing + 'px')
    	  .attr('d', circle.endAngle(endAngle));
    
    	//Add colour fill
    	var value = track.append('path')
    	  .attr('class', 'radial-progress__value')
    	  .attr('fill', colours.fill)
    	  .attr('stroke', colours.stroke)
    	  .attr('stroke-width', strokeSpacing + 'px');
    
    	//Add text value
    	var numberText = track.append('text')
    	  .attr('class', 'radial-progress__text')
    	  .attr('fill', colours.text)
    	  .attr('font-size', '30px')
    	  .attr('text-anchor', 'middle')
    	  .attr('dy', '.5rem');
    
    	function update(progress) {
    	  //update position of endAngle
    	  value.attr('d', circle.endAngle(endAngle * progress));
    	  //update text value
    	  numberText.text(formatText(progress));
    	} 
    
    	(function iterate() {
    	  //call update to begin animation
    	  update(progress);
    	  if (count > 0) {
    	    //reduce count till it reaches 0
    	    count--;
    	    //increase progress
    	    progress += step;
    	    //Control the speed of the fill
    	    setTimeout(iterate, 10);
    	  }
    	})();
	#progress1 {
	  	display: inline-block;
	  	padding: 20px;
	}

	#progress2 {
		display: inline-block;
	  	padding: 20px;
	}

	.radial-progress { 
	  &__text {
	    font-family: Arial, sans-serif;
	    font-size: 2rem;
	    font-weight: bold;
	  }  
	}
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="progress1"
        data-track-width="15" 
        data-track-colour="555555" 
        data-fill-colour="228B22" 
        data-text-colour="383838" 
        data-stroke-colour="FFFFFF" 
        data-stroke-spacing="1"> 
    </div>
    
    <div id="progress2" 
    	data-track-width="15" 
        data-track-colour="555555" 
        data-fill-colour="228B22" 
        data-text-colour="383838" 
        data-stroke-colour="FFFFFF" 
        data-stroke-spacing="1"> 
    </div>

I have tried re-naming variables in the js to be unique for each element (i.e. wrapper1 and wrapper2 or end1 and end2), but I cannot seem to get the first element to pay attention to the 90% end setting.

Upvotes: 2

Views: 1375

Answers (1)

exside
exside

Reputation: 3884

Why so much code duplication? You could simply generalize the JS into a function and then use it on any amount of progress circles, just add another data attribute for the progress, e.g data-progress:

var renderProgress = function(el) {
  var start = 0;
  var end = el.dataset.progress;
  
  var colours = {
    fill: '#' + el.dataset.fillColour,
    track: '#' + el.dataset.trackColour,
    text: '#' + el.dataset.textColour,
    stroke: '#' + el.dataset.strokeColour,
  }
  
  var radius = 100;
  var border = el.dataset.trackWidth;
  var strokeSpacing = el.dataset.strokeSpacing;
  var endAngle = Math.PI * 2;
  var formatText = d3.format('.0%');
  var boxSize = radius * 2;
  var count = end;
  var progress = start;
  var step = end < start ? -0.01 : 0.01;
  
  //Define the circle
  var circle = d3.arc()
    .startAngle(0)
    .innerRadius(radius)
    .outerRadius(radius - border);
  
  //setup SVG wrapper
  var svg = d3.select(el)
    .append('svg')
    .attr('width', boxSize)
    .attr('height', boxSize);
  
  // ADD Group container
  var g = svg.append('g')
    .attr('transform', 'translate(' + boxSize / 2 + ',' + boxSize / 2 + ')');
  
  //Setup track
  var track = g.append('g').attr('class', 'radial-progress');
  track.append('path')
    .attr('class', 'radial-progress__background')
    .attr('fill', colours.track)
    .attr('stroke', colours.stroke)
    .attr('stroke-width', strokeSpacing + 'px')
    .attr('d', circle.endAngle(endAngle));
  
  //Add colour fill
  var value = track.append('path')
    .attr('class', 'radial-progress__value')
    .attr('fill', colours.fill)
    .attr('stroke', colours.stroke)
    .attr('stroke-width', strokeSpacing + 'px');
  
  //Add text value
  var numberText = track.append('text')
    .attr('class', 'radial-progress__text')
    .attr('fill', colours.text)
    .attr('font-size', '30px')
    .attr('text-anchor', 'middle')
    .attr('dy', '.5rem');
  
  function update(progress) {
    //update position of endAngle
    value.attr('d', circle.endAngle(endAngle * progress));
    //update text value
    numberText.text(formatText(progress));
  };
  
  function iterate() {
    //call update to begin animation
    update(progress);
    
    if (count > 0) {
      //reduce count till it reaches 0
      count--;
      //increase progress
      progress += step;
      //Control the speed of the fill
      setTimeout(iterate, 10);
    }
  };
  
  iterate();
}

Array.prototype.slice.call(document.querySelectorAll('.progress')).forEach(el => {
  renderProgress(el);
});
  .progress {
      display: inline-block;
      padding: 20px;
  }

  .radial-progress { 
    &__text {
      font-family: Arial, sans-serif;
      font-size: 2rem;
      font-weight: bold;
    }  
  }
<script src="https://d3js.org/d3.v5.min.js"></script>
<div
  data-progress="90"
  data-track-width="15" 
  data-track-colour="555555" 
  data-fill-colour="228B22" 
  data-text-colour="383838" 
  data-stroke-colour="FFFFFF" 
  data-stroke-spacing="1"
  class="progress"> 
</div>

<div
  data-progress="95"
  data-track-width="15" 
  data-track-colour="555555" 
  data-fill-colour="228B22" 
  data-text-colour="383838" 
  data-stroke-colour="FFFFFF" 
  data-stroke-spacing="1"
  class="progress"> 
</div>

Upvotes: 4

Related Questions