Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript svg circular gradiant

Tags:

javascript

svg

I have a problem to solve. I want to draw a circle svg with gradient fonts based on a score. The score varies from 0 to 100. If the score is 60% for example, I have to draw 60% of the circle knowing that the gradient changes every 20%. I would like to do something like the following image but with gradients:

enter image description here

I saw the example below which could be useful to me, but I don't understand how the coordinates of the M in path are calculated:

<svg width="300" height="300">
    <linearGradient id="linearColors1" x1="0" y1="0" x2="1" y2="1">
       <stop offset="0%" stop-color="#01E400"></stop>
       <stop offset="100%" stop-color="#FEFF01"></stop>
    </linearGradient>
    <linearGradient id="linearColors2" x1="0.5" y1="0" x2="0.5" y2="1">
       <stop offset="0%" stop-color="#FEFF01"></stop>
       <stop offset="100%" stop-color="#FF7E00"></stop>
    </linearGradient>
    <linearGradient id="linearColors3" x1="1" y1="0" x2="0" y2="1">
       <stop offset="0%" stop-color="#FF7E00"></stop>
       <stop offset="100%" stop-color="#FB0300"></stop>
    </linearGradient>
    <linearGradient id="linearColors4" x1="1" y1="1" x2="0" y2="0">
       <stop offset="0%" stop-color="#FB0300"></stop>
       <stop offset="100%" stop-color="#9B004A"></stop>
    </linearGradient>
    <linearGradient id="linearColors5" x1="0.5" y1="1" x2="0.5" y2="0">
       <stop offset="0%" stop-color="#9B004A"></stop>
       <stop offset="100%" stop-color="#7D0022"></stop>
    </linearGradient>
    <linearGradient id="linearColors6" x1="0" y1="1" x2="1" y2="0">
       <stop offset="0%" stop-color="#7D0022"></stop>
       <stop offset="100%" stop-color="#01E400"></stop>
    </linearGradient>
    <path d="M150 10 a120 120 0 0 1 103.9230 60"
        fill="none" stroke="url(#linearColors1)" stroke-width="5" />
  <path d="M253.9230 70 a120 120 0 0 1 0 120"
        fill="none" stroke="url(#linearColors2)" stroke-width="5" />
  <path d="M253.9230 190 a120 120 0 0 1 -103.9230 60"
        fill="none" stroke="url(#linearColors3)" stroke-width="5" />
  <path d="M150 250 a120 120 0 0 1 -103.9230 -60"
        fill="none" stroke="url(#linearColors4)" stroke-width="5" />
  <path d="M46.077 190 a120 120 0 0 1 0 -120"
        fill="none" stroke="url(#linearColors5)" stroke-width="5" />
  <path d="M46.077 70 a120 120 0 0 1 103.9230 -60"
        fill="none" stroke="url(#linearColors6)" stroke-width="5" />
</svg>

Can you help me solve this problem or explain to me the calculation logic of the M in the example above?

Thanks very much !

like image 930
Soilih Ben Soilih Avatar asked Feb 20 '26 09:02

Soilih Ben Soilih


1 Answers

Instead of using the path element I use a circle and the stroke-dasharray attribute. I create a circle "slice" (1/5 if a circle) and then use <use> for reusing the slice. The value is controlled by a mask (and the stroke-dasharray of a circle).

Each gradient is used on the different use elements. You can see that they are all the same. Basically it fits the initial circle slice. After being applied each circle slice is rotated.

Here is an example of the circle element with the stroke-dasharray and the gradient. I added the gradient to the fill so that you can see what it looks like:

<svg width="250" viewBox="0 0 100 100">
  <defs>
    <linearGradient id="lg1" gradientTransform="rotate(36) translate(.2 0)">
       <stop offset="25%" stop-color="DodgerBlue"/>
       <stop offset="75%" stop-color="Green"/>
    </linearGradient>
  </defs>
  <g transform="translate(50 50)">
    <circle id="c1" r="45" stroke-width="10" fill="url(#lg1)"
      stroke="url(#lg1)" stroke-dasharray="0 74 21 20" pathLength="100" />
  </g>
</svg>

And this is the end result:

document.forms.form01.range.addEventListener('change', e => {
  document.getElementById('c2').setAttribute('stroke-dasharray', `${e.target.value} 200`);
  document.getElementById('t1').textContent = `${e.target.value}%`;
});
<form name="form01">
<input type="range" name="range" min="0" max="100" value="71"/>
</form>
<svg width="250" viewBox="0 0 100 100">
  <defs>
    <linearGradient id="temp1" gradientTransform="rotate(36) translate(.2 0)"/>
    <linearGradient id="lg1" href="#temp1">
       <stop offset="25%" stop-color="DodgerBlue"/>
       <stop offset="75%" stop-color="Green"/>
    </linearGradient>
    <linearGradient id="lg2" href="#temp1">
       <stop offset="25%" stop-color="Green"/>
       <stop offset="75%" stop-color="Yellow"/>
    </linearGradient>
    <linearGradient id="lg3" href="#temp1">
       <stop offset="25%" stop-color="Yellow"/>
       <stop offset="75%" stop-color="Orange"/>
    </linearGradient>
    <linearGradient id="lg4" href="#temp1">
       <stop offset="25%" stop-color="Orange"/>
       <stop offset="75%" stop-color="DarkOrchid"/>
    </linearGradient>
    <linearGradient id="lg5" href="#temp1">
       <stop offset="25%" stop-color="DarkOrchid"/>
       <stop offset="75%" stop-color="Red"/>
    </linearGradient>
    <circle id="c1" r="45" stroke-width="10" fill="none"
      stroke-dasharray="0 74 21 20" pathLength="100" />
    <mask id="m1">
      <circle id="c2" r="45" stroke-width="10" fill="none" stroke="white"
        stroke-dasharray="71 100" pathLength="104" transform="rotate(-83)"
        stroke-linecap="round" />
    </mask>
  </defs>
  <g transform="translate(50 50)" mask="url(#m1)">
    <use href="#c1" stroke="url(#lg1)"/>
    <use href="#c1" stroke="url(#lg2)" transform="rotate(72)"/>
    <use href="#c1" stroke="url(#lg3)" transform="rotate(144)"/>
    <use href="#c1" stroke="url(#lg4)" transform="rotate(216)"/>
    <use href="#c1" stroke="url(#lg5)" transform="rotate(288)"/>
  </g>
  <text id="t1" x="50" y="50" font-family="sans-serif" text-anchor="middle"
    dominant-baseline="middle">71%</text>
</svg>
like image 52
chrwahl Avatar answered Feb 22 '26 23:02

chrwahl