my SVG (donnut chart) doesn't display correctly on IOS

Issue

Context : I want to display a donut chart using one SVG composed of two circles :

Final result

  • Both circles are dynamically filled with a css variable (as a percent).

Everythings works fine on PC and Android (chrome).

When viewing with an iPhone, the green circle is fully filled hiding the grey circle.

Below is the result as seen with IOS phone (tried Safari and Chrome) :

enter image description here

Here is a snippet, took 45% for green and 75% for grey

Code :

:root {
  --val: 0;
}

svg {
  transform: rotate(135deg);
}

.percent {
  stroke-dasharray: 100;
  stroke-dashoffset: calc(100 - var(--val));
}

.white {
  transform: rotate(135deg)
}

.forty-five{
  --val: 45;
}

.complete {
   --val: 75;
 }
<div class="svg-container">
  <svg width="250" height="250" viewBox="0 0 140 140">
  <circle class="percent complete" cx="70" cy="70" r="52" fill="none" stroke="#e6e6e6" strokeWidth="18" pathLength="100" />
  <circle class="percent" cx="70" cy="70" r="52" fill="none" stroke="#333" strokeWidth="18" pathLength="100" />
  <circle class="percent forty-five" cx="70" cy="70" r="52" fill="none" stroke="#6AA617" strokeWidth="18" pathLength="100" />
  </svg>
</div>

Any suggestion or any other way to obtain this result ?

EDIT : I just found out that there is the same problem when using Firefox on pC

Solution

As @A Haworth already pointed out:
css calc support for svg properties is still rather spotty (might work in Chrome but not in Firefox – might also depend on the actual svg element and certain properties.
Probably fixed and negligible in the near future … unless ie returns).

But you don’t really need it anyway.

Since your horseshoe gauge should render only 270° of a 360° circle, you could instead tweak the pathLength property:

The ideal pathLength would be 133.333
360/270*100
(i.e. the 270° part of the circle will result in a computed circumference of 100 svg units)

Now you can use css-variable to display percentage based values:

:root {
  --val: 100;
  --dashGap: 133.333;
  --offset: 0;
}

svg {
  transform: rotate(135deg);
}

.percent {
  stroke-dashoffset: var(--offset);
  stroke-dasharray: var(--val) var(--dashGap)
}
<div class="svg-container">
  <svg width="250" height="250" viewBox="0 0 140 140">
    <defs>
          <circle id="circle" cx="70" cy="70" r="52" fill="none" pathLength="133.333" stroke-width="18" />
    </defs>
   <!-- bg circle -->
    <use class="percent complete" href="#circle" stroke="#e6e6e6" />
   <!-- percentage circles -->
    <use class="percent" href="#circle" stroke="green" style="--val:50"/>
    <use class="percent" href="#circle" stroke="pink" style="--val:25; --offset:-50" />
  </svg>
</div>

If you need to render values progressively like 50% + 25% (so a total of 75%) you can use a stroke-dahoffset variable.
Each new segment needs to have a negative offset according the previous segments’s percentage.

Answered By – herrstrietzel

Answer Checked By – David Marino (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.