Slowly fill SVG image with color (like progress ba

2019-02-16 02:05发布

问题:

I'd like to fill a svg image with colour instead of a progress bar. I will be using this for an animated infographic.

Fill the image below slowly with green colour to show it's 30% "full".<br>
<img src="https://cdn.mediacru.sh/P-WOGKdNDiGT.svg" width="700px">

Fiddle here: http://jsfiddle.net/47ayquwq/4/

回答1:

You can do this by animating a mask or a filter, and using the fakeSMIL library to polyfill for IE. Below is the filter version.

<svg width="800px" height="400px">
  <defs>
    <filter id="green-fill" x="0%" y="0%">
      <feFlood flood-color="green"/>
      <feOffset dy="210">
        <animate attributeName="dy" from="300" to="210" dur="2s"/>
        </feOffset>
      <feComposite operator="in" in2="SourceGraphic"/>
      <feComposite operator="over" in2="SourceGraphic"/>
      </filter>
    </defs>
  
     <image filter="url(#green-fill)" xlink:href="https://cdn.mediacru.sh/P-WOGKdNDiGT.svg" height="400" width="700" />
  
  </svg>



回答2:

You can achieve this effect by implementing a rectangular progress bar and then masking it with the SVG. See below. However this is not a general solution. It won't work on IE because IE doesn't support CSS Masks.

You could also use the same approach as below, but instead of using CSS Masks, you could use an SVG <mask> or <clipPath> element. There are plenty of other questions on here about how to use those elements. This approach will also work on IE9+.

.progress {
    position: relative;
    background-color: green;
    -webkit-mask: url(https://cdn.mediacru.sh/P-WOGKdNDiGT.svg) top left / cover;
}

/* IMG is just here for the size */
.progress IMG {
    visibility: hidden;
}

/* We expose the green by moving the LHS of the "background" grey */
.progress-bg {
    background-color: gray;
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    -webkit-animation-duration: 1s;
    -webkit-animation-name: to30percent;
    -webkit-animation-fill-mode: forwards;
    animation-duration: 1s;
    animation-name: to30percent;
    animation-fill-mode: forwards;
}

@-webkit-keyframes to30percent {
  from { left: 0%; }
  to { left: 30%; }
}

@keyframes to30percent {
  from { left: 0%; }
  to { left: 30%; }
}
<div class="progress">
    <img src="https://cdn.mediacru.sh/P-WOGKdNDiGT.svg" width="700px"/>
    <div class="progress-bg"></div>
</div>

Here we have a div with a green background. And on top we have a grey div that represents the "background" of the progress bar. We are doing it this way round so we can set the "left" property of the grey div to the same value as our progress percentage.

Finally the whole thing is masked with our SVG.



回答3:

If your svg is actually just some text or a simple shape, you could also just animate inside the svg (e.g as a gradient). For IE you'd need to either add the fakeSMIL library or animate with js.

Example:

svg {
    height: 500px;
    width: 100%;
}
text {
    font: 220px Arial;
    font-weight: bold;
    fill: url(#gradient);
}
<svg>
    <defs>
        <linearGradient id="gradient" x1="0" y1="0" x2="0" y2="1">
            <stop stop-color="#aaa" offset="0" />
            <stop stop-color="#aaa" offset="1">
                <animate dur="2s" by="-0.5" attributeName="offset" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.4, 0, 0.2, 1" />
            </stop>
            <stop stop-color="green" offset="1">
                <animate dur="2s" by="-0.5" attributeName="offset" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.4, 0, 0.2, 1" />
            </stop>
            <stop stop-color="green" offset="1" />
        </linearGradient>
    </defs>
    <text y="1em">HELLO</text>
</svg>