hi_Matt
hi_Matt

Reputation: 159

Fill a percentage of an SVG and animate the fill

Currently, I am working on a project that is comparing state data with data from another country. One data point is percentage of protected land and I want to fill the a percentage of the state that matches the data point. So for example, if 25% of North Carolina is protected, then I want 25% of the state to fill. Currently, I am trying to use an svg and I want the fill to happen on page load.

Any suggestions or resources on how to do this would be greatly appreciated.

Example I drew up in Illustrator:

NC filled in 33%

Upvotes: 11

Views: 15929

Answers (4)

Jan
Jan

Reputation: 2293

ProgressBar looks promising and easy to use: https://kimmobrunfeldt.github.io/progressbar.js/

Here's a nice Fiddle example: https://jsfiddle.net/kimmobrunfeldt/72tkyn40/

Javascript:

// [email protected] version is used
// Docs: http://progressbarjs.readthedocs.org/en/1.0.0/

var bar = new ProgressBar.Circle(container, {
  color: '#aaa',
  // This has to be the same size as the maximum width to
  // prevent clipping
  strokeWidth: 4,
  trailWidth: 1,
  easing: 'easeInOut',
  duration: 1400,
  text: {
    autoStyleContainer: false
  },
  from: { color: '#aaa', width: 1 },
  to: { color: '#333', width: 4 },
  // Set default step function for all animate calls
  step: function(state, circle) {
    circle.path.setAttribute('stroke', state.color);
    circle.path.setAttribute('stroke-width', state.width);

    var value = Math.round(circle.value() * 100);
    if (value === 0) {
      circle.setText('');
    } else {
      circle.setText(value);
    }

  }
});
bar.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
bar.text.style.fontSize = '2rem';

bar.animate(1.0);  // Number from 0.0 to 1.0

Upvotes: 1

Hao
Hao

Reputation: 1564

This can be done by plain css and html: http://jsfiddle.net/haohcraft/rAPN5/1/

Basically, the trick is

  1. You need a image which has a transparent inner field but non-transparent outer field, like the image in the fiddle. And you need to set z-index:1 in order to place it above the filled <div>.
  2. Set the filled <div> and the img to be position: absolute; width:90px; height:90px; in that case.
  3. Then you can adjust the height of the filled div to show the percentage

Upvotes: 2

Chatyeux
Chatyeux

Reputation: 96

Here are my two cents:

You can have a linear gradient like this:

<linearGradient y2="0%" x2="100%" y1="0%" x1="0%" id="F1g"><stop stop-color="#00FF00" offset="0%" id="F1gst1"/><stop stop-color="#FFFFFF" offset="0%" id="F1gst2"/></linearGradient>

Then take the first stop element:

var firstStop = document.getElementById('F1gst1');

And then assign the percentage you want fill, with the attribute offset:

percentage = '35%'; firstStop.setAttribute('offset',percentage);

And that is the way in javascript. You need a gradient for every state (you can use a group) and maybe you will need to define a path object with a fill inside every state with the same form, so you can apply the linear gradient to that path fill attribute.

If you need an animation, you can set a setInterval, and add an '1%' every x miliseconds to make the effect, and stop every interval when the desired percentage is reached.

I hope this at least have given you a clue.

Regards.

Upvotes: 7

Michael Mullany
Michael Mullany

Reputation: 31808

Well, here's a pretty dumb way in Canvas...(and I'm assuming you mean you want a certain % of interior area filled).

Step 1: Dump a solid image of each state into Canvas

Step 2: Count the number of nonzero pixels

Step 3: Extract the edges using an edge extraction convolution

Step 4: For each line, iterate horizontally within each row within the shape, coloring in pixels until you've reached the x% of the shape you'd like to portray.

It is possible to do this in SVG, but you'd need to hand-tesselate the shape, track all your areas and then hand calculate the ones to fill and it wouldn't do what I think you want - which is to have a state fill up like it's a water container?

An alternative solution is, of course, to 3D print transparent containers in the shape of all 50 states, fill them with colored water to the desired levels. Photograph them, and then manipulate that image via an SVG filter (feImage + feColorMatrix+feComposite) to selectively fill an SVG image. This may be faster than learning tesselation (or Canvas).

Upvotes: 0

Related Questions