progressbar.js with image on the inside and text on the stroke

Viewed 192

I want to reproduce the progress bar in the image below

but I am having trouble with the center image and the text on the side. I am using progressbar.js and this is where I am at right now:

// progressbar.js@1.0.0 version is used
// Docs: http://progressbarjs.readthedocs.org/en/1.0.0/

var bar = new ProgressBar.Circle(container, {
  strokeWidth: 20,
  easing: 'easeInOut',
  duration: 1400,
  color: 'url(#gradient)',
  trailColor: '#eee',
  trailWidth: 1,
  svgStyle: null
});
let linearGradient = `
  <defs>
    <linearGradient id="gradient" x1="100%" y1="0%" x2="0%" y2="0%" gradientUnits="userSpaceOnUse">
      <stop offset="20%" stop-color="mediumaquamarine"/>
      <stop offset="50%" stop-color="turquoise"/>
    </linearGradient>
  </defs>
`
let percentage_text = "<span>100%</span>";

bar.svg.insertAdjacentHTML('afterBegin', linearGradient);

bar.svg.insertAdjacentHTML('beforeend', percentage_text);
bar.animate(1.0);  // Number from 0.0 to 1.0
#container {
  margin: 20px;
  width: 200px;
  height: 200px;
}
span{
  position: absolute;
  z-index: 9;
  width: 90px;
  height: 90px;
  color: black;
}
<script src="https://rawgit.com/kimmobrunfeldt/progressbar.js/1.0.0/dist/progressbar.js"></script>
<div id="container"></div>

I have tried inserting the percentage as a span but it doesn't show, for the image I think I can add another div on top of this one with the image in the center but it wouldn't be perfectly centered and might overlap the progress bar.

Any help would go a long way, and if there is another better library to imitate the image it would be perfect. thanks in advance.

1 Answers

I hope this helps you. Clean the code as you want!

  1. Add an id for second path in svg for percentage:
let path = document.querySelector('svg path:last-child').setAttribute("id", "MyPath");
  1. Add the step key to your bar:
step: (state, bar) => {
  var value = Math.round(bar.value() * 100);
  update(value)
}
  1. Add an update method to handle the percentage on the path:
function update(val) {
  if (!bar) return;
  if (document.getElementById('text-tp'))
    document.getElementById('text-tp').outerHTML = "";
  bar.svg.insertAdjacentHTML('beforeend',
    `<text id="text-tp"> <textPath id="tp" href="#MyPath">${val}%</textPath> </text>`);

  let tp = document.getElementById('tp');
  if (val > 7)
    tp.setAttributeNS(null, "startOffset", val - 7 + "%");
  else tp.setAttributeNS(null, "startOffset", val + "%");
}
  1. Add clipPath to your defs part
<clipPath id="circleView">
  <circle cx="50" cy="50" r="30" fill="none" />
</clipPath>
  1. Add image to your svg:
bar.svg.insertAdjacentHTML('beforeend',
  ` <image 
      width="250" 
      height="150"   xlink:href="https://www.amrita.edu/sites/default/files/news-images/new/news-events/images/l-nov/grass.jpg" 
      clip-path="url(#circleView)"
    />`);

Full code is:

var bar = new ProgressBar.Circle(container, {
  strokeWidth: 20,
  easing: 'easeInOut',
  duration: 4400,
  color: 'url(#gradient)',
  trailColor: '#eee',
  trailWidth: 1,
  svgStyle: null,
  step: (state, bar) => {
    var value = Math.round(bar.value() * 100);
    update(value)
  }
});

let linearGradient = `
  <defs>
    <linearGradient id="gradient" x1="100%" y1="0%" x2="0%" y2="0%" gradientUnits="userSpaceOnUse">
      <stop offset="20%" stop-color="mediumaquamarine"/>
      <stop offset="50%" stop-color="turquoise"/>
    </linearGradient>
    <clipPath id="circleView">
            <circle cx="50" cy="50" r="30" fill="none" />
        </clipPath>
  </defs>
`

bar.svg.insertAdjacentHTML('afterBegin', linearGradient);

let path = document.querySelector('svg path:last-child').setAttribute("id", "MyPath");

bar.svg.insertAdjacentHTML('beforeend',
    ` <image 
      width="250" 
      height="150"   xlink:href="https://www.amrita.edu/sites/default/files/news-images/new/news-events/images/l-nov/grass.jpg" 
      clip-path="url(#circleView)"
    />`);

function update(val) {
  if (!bar) return;
  if (document.getElementById('text-tp'))
    document.getElementById('text-tp').outerHTML = "";
  bar.svg.insertAdjacentHTML('beforeend',
    `<text id="text-tp"> <textPath id="tp" href="#MyPath">${val}%</textPath> </text>`);

  let tp = document.getElementById('tp');
  if (val > 7)
    tp.setAttributeNS(null, "startOffset", val - 7 + "%");
  else tp.setAttributeNS(null, "startOffset", val + "%");
}

bar.animate(1.0); // Number from 0.0 to 1.0
#container {
  margin: 20px;
  width: 200px;
  height: 200px;
}

span {
  position: absolute;
  z-index: 9;
  width: 90px;
  height: 90px;
  color: black;
}

#text-tp {
  position: absolute;
  font-size: 8px;
}
<script src="https://rawgit.com/kimmobrunfeldt/progressbar.js/1.0.0/dist/progressbar.js"></script>
<div id="container"></div>

Related