Falko
Falko

Reputation: 1035

Dynamically changing the 'fill' level of an SVG in react

I have an SVG rounded corner container that shows a fill level. I need to change the fill level dynamically. This would be trivial if the container were a rect, but the rounded corners need a path.

enter image description here

here is the path for the black 'filled area'

`M0, 220 L100,220 L100,220 C100,231.045695 91.045695,240 80,240 L20,240 C8.954305,240 1.3527075e-15,231.045695 0,220 L0,120 L0,120 Z`

I need to know which elements of the path to change to fill and empty the tank in a clean way.

Upvotes: 1

Views: 1208

Answers (2)

Józef Podlecki
Józef Podlecki

Reputation: 11283

Even if you find the way to fill the tank you have to take care of top borders.

const { useState, useRef, useEffect } = React;

const App = () => {
  const [value, setValue] = useState(220);
  const handle = useRef(null);
 
  useEffect(() => {
    if(value < 50) {
      clearTimeout(handle.current);
    }
  }, [value]);
 
  useEffect(() => {
  
    let isUnmounted = false;
  
    const loop = () => {
      
      if(isUnmounted) {
        return;
      }
      
      setValue(value => value - 10);
      
      handle.current = setTimeout(loop, 200);
    }
  
    handle.current = setTimeout(loop, 200);
    
    return () => {
      isUnmounted = true;
      clearTimeout(handle.current);
    }
  }, [])

return <div>
  <svg width="400" height="400">
    <path d={`M0, ${value} L100,${value} L100,220 C100,231.045695 91.045695,240 80,240 L20,240 C8.954305,240 1.3527075e-15,231.045695 0,220 L0,120 L0,120 Z`}/>
    <rect fill="none" stroke="black" x="0" y="40" width="100" height="200" rx="15" />
  </svg>
</div>
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
svg, path {
  transition: all .3s ease-in;
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>

Upvotes: 1

enxaneta
enxaneta

Reputation: 33044

You don't need a new shape. You can use a linear gradient:

<svg viewBox="0 0 100 120" width="100">
   <linearGradient id="lg" x1 = "0%" y1 = "0%" x2 = "0%" y2 = "100%">
   <stop offset="0%" stop-color="#fff"></stop>
   <stop offset="50%" stop-color="#fff"></stop>
   <stop offset="50%" stop-color="#f00"></stop>
   <stop offset="100%" stop-color="#f00"></stop>
  </linearGradient>
  <rect x="10" y="10" width="50" height="100" rx="15" ry="15" fill="url(#lg)" stroke="black" />
</svg>

In order to change the fill level dynamically you need to change the value of the second and 3rd stop offset to ${100 - yourvalue}%

Upvotes: 1

Related Questions