Issue when zooming in on SVG donut chart in Safari - svg

I'm attempting to create a donut chart using SVG, and am running into a problem when viewing it in Safari. Here's a fiddle that shows the issue; I'll describe it in detail below:
https://jsfiddle.net/nijhazer/phy2ossh/
This fiddle shows a graphic comprised of two circles overlaid atop one another. The problem becomes apparent when a Safari user increases zoom size in her browser:
Relevant HTML from the example:
<div class="donut-chart">
<svg width="200" height="200">
<circle class="backdrop" cx="100" cy="100" r="65" fill="#d5d8d5" stroke="none" stroke-width="0"></circle>
<circle class="progress" cx="100" cy="100" r="75" fill="none" stroke="lightgreen" stroke-width="20" style="stroke-dashoffset: 353.428875px;"></circle>
<circle class="outer-ring" cx="100" cy="100" r="85" fill="none" stroke="#d5d8d5" stroke-width="1"></circle>
</svg>
</div>
Relevant CSS from the example:
body {
background-color: white;
}
.donut-chart {
width: 200px;
height: 200px;
position: relative;
}
svg {
width: 200px;
height: 200px;
}
.progress {
stroke-dasharray: 471.24;
transform: rotate(-90deg);
transform-origin: 50% 50%;
background-color: transparent;
}

I don't know if this helps, but at I can read from the comments that people are blaming the CSS property transform-origin. In this example I moved the styling to attributes on the circle element. I also added pathLength to make it easier to control the progress bar.
body {
background-color: white;
}
.donut-chart {
width: 200px;
height: 200px;
position: relative;
}
svg {
width: 200px;
height: 200px;
}
<div class="donut-chart">
<svg viewBox="0 0 200 200" xmlns="http//www.w3.org/2000/svg">
<circle class="backdrop" cx="100" cy="100" r="65" fill="#d5d8d5"
stroke="none" stroke-width="0" />
<circle class="progress" cx="100" cy="100" r="75" fill="none"
stroke="lightgreen" stroke-width="20" stroke-dasharray="25 100"
transform="rotate(-90 100 100)" pathLength="100" />
<circle class="outer-ring" cx="100" cy="100" r="85" fill="none"
stroke="#d5d8d5" stroke-width="1" />
</svg>
</div>

I can confirm chrwahl's approach is working (at least in MacOS/IOS safari versions (15.4) I've tested - Unfortunately, the support of functions may vary from version to version)
Another workaround could be to add a translateX offset before rotating like so:
.donut-chart {
width: 200px;
height: 200px;
position: relative;
display: block;
}
svg {
width: 200px;
height: 200px;
}
.progress {
stroke-dasharray: 471.24;
background-color: transparent;
transform: translate(0px, 200px) rotate(-90deg);
}
<div class="donut-chart">
<svg width="200" height="200" viewBox="0 0 200 200">
<circle class="backdrop" cx="50%" cy="50%" r="65" fill="#d5d8d5" stroke="none" stroke-width="0"></circle>
<circle class="progress" cx="50%" cy="50%" r="75" fill="none" stroke="lightgreen" stroke-width="20" style="stroke-dashoffset: 353.428875px;"></circle>
<circle class="outer-ring" cx="100" cy="100" r="85" fill="none" stroke="#d5d8d5" stroke-width="1"></circle>
</svg>
</div>
This "hack" won't work combined with transform-origin: 50% 50%

Related

Reusing SVG elements while inserting different text?

I want to display balls with 1,2,3,4 inside. Can I use <use>? or I must duplicate the stone <g>?
#stone text {
fill: grey;
dominant-baseline: middle;
text-anchor: middle;
font-size: 0.33pt;
}
#pane {
background-color: yellow;
width: 100%;
height: 100%;
}
.stone-white {
fill: #F2F4F4;
}
.stone-black {
fill: #273746;
}
<svg id="pane" viewBox="0 0 22 22" preserveAspectRatio="none">
<defs>
<g id="stone">
<circle cx="0" cy="0" r="0.45" />
<text>333</text>
</g>
</defs>
<use href="#stone" class="stone-white" x="1" y="1"/>
<use href="#stone" class="stone-white" x="2" y="2"/>
<use href="#stone" class="stone-black" x="3" y="2"/>
<use href="#stone" class="stone-black" x="2" y="4"/>
</svg>

css rotate introduces outline when using SVG clip-path or mask

Is there a way to stop this outline in firefox?
#blob { background: red; width: 500px; height: 500px; clip-path: url(#myClip); transform: rotate(20deg);}
<div id="blob"></div>
<svg>
<defs>
<path d="M320.403196,424.677624 C426.787532,365.585154 447.310044,306.188587 433.45394,197.28033 C419.597836,88.3720737 316.997962,53.8862578 227.347416,40.9086547 C144.650118,28.9375873 104.472702,88.6407456 69.862267,131.812053 C15.52584,199.588564 48.3439099,300.905451 80.8563197,361.757908 C110.80391,417.809872 214.018859,483.770094 320.403196,424.677624 Z" id="path-1"></path>
<clipPath id="myClip"><use href="#path-1"></use></clipPath>
</defs>
</svg>
This renders correctly in other browsers, just need some work around for this firefox bug
same outline appears using either clip-path or mask
As a workaround you could rotate the clipPath instead:
#blob {
background: red;
width: 500px;
height: 500px;
clip-path: url(#myClip);
}
<div id="blob"></div>
<svg viewBox="0 0 397 409">
<defs>
<path d="M320.403196,424.677624 C426.787532,365.585154 447.310044,306.188587 433.45394,197.28033 C419.597836,88.3720737 316.997962,53.8862578 227.347416,40.9086547 C144.650118,28.9375873 104.472702,88.6407456 69.862267,131.812053 C15.52584,199.588564 48.3439099,300.905451 80.8563197,361.757908 C110.80391,417.809872 214.018859,483.770094 320.403196,424.677624 Z" id="path-1" />
<clipPath id="myClip" transform="rotate(20)" transform-origin="center">
<use href="#path-1"></use>
</clipPath>
</defs>
</svg>

IE11 defaults SVG to 100% width - how to refactor this code?

I am not aware of alternatives to adding width: 1em to the SVG in order to fix the IE11 issue (please see comment in the code). Play with the code in the codepen. Appreciate any help! Thanks :)
https://codepen.io/ambrwlsn90/pen/zjZYpb
<div class="box">
<span class="handle--draggable">
<svg class="handle--icon" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 10 32">
<circle cx="2" cy="2" r="2" />
<circle cx="8" cy="2" r="2" />
<circle cx="2" cy="9" r="2" />
<circle cx="8" cy="9" r="2" />
<circle cx="2" cy="16" r="2" />
<circle cx="8" cy="16" r="2" />
<circle cx="2" cy="23" r="2" />
<circle cx="8" cy="23" r="2" />
<circle cx="2" cy="30" r="2" />
<circle cx="8" cy="30" r="2" />
</svg>
</span>
</div>
.box {
position: relative;
width: 400px;
height: 100px;
border: 3px solid black;
background-color: white;
top: 50px;
left: 100px;
padding: 15px;
line-height: 1.5em;
}
.handle--draggable {
position: absolute;
cursor: move;
left: -26px;
top: -3.5px;
}
/**
* 1. Magic number added to fix visual bug in IE: 11
*/
.handle--icon {
fill: black;
background-color: grey;
padding: 3.5px;
height: 37px;
width: 1em; /* 1. */
position: relative;
&:hover {
left: -5px;
border-right: 5px solid grey;
}
}
The SVG tag needs some basic attributes in order to be rendered as expected. If you read the W3C documentation according the outermost svg tag you will find the answer:
For embedded ‘svg’ elements, the width of the rectangular region into which the ‘svg’ element is placed.
A negative value is an error (see Error processing). A value of zero disables rendering of the element.
If the attribute is not specified, the effect is as if a value of '100%' were specified.
So you will need to specify the width and height attributes of the SVG tag, or it will be rendered at 100% width.
The opening svg tag should look like this:
<svg class="handle--icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 32" width=“10” height=“32”>
Then the SVG will look the same crossbrowser.
Having the width and height attributes defined on your svg element you can discard the ugly Internet Explorer 11 hack.

SVG backgrounds are getting cut off in IE11 when zooming

We are trying to display SVG backgrounds in internet explorer. Our images are always getting cut off when a zoom other than 100% is used. This can be reproduced using the following code:
with this svg
<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="48" stroke="black" stroke-width="3" fill="red" />
</svg>
div {
width: 14px;
height: 14px;
background-size: 14px 14px;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml;charset=utf-8,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' height='100' width='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='48' stroke='black' stroke-width='3' fill='red'%3E%3C/circle%3E%3C/svg%3E");
}
<div></div>
The result looks like this:
In all other browsers it renders fine. Has anyone else ever experienced this bug? Is there a workaround?
I have found one workaround which requires very little work:
Make the SVG image 2X size of the actual content (this would make the circle look like this:
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200">
<circle cx="50" cy="50" r="48" stroke="black" stroke-width="3" fill="red" />
</svg>
Then use the :after pseudo element to create an inside element with 2x the desired size. So the html would be
<div class="circle"></div>
And the css would be
.circle {
width: 14px;
height: 14px;
position:relative;
}
.circle:after {
position: absolute;
top: 0;
left: 0;
content: ' ';
width: 28px;
height: 28px;
background-size: 28px 28px;
background-repeat: no-repeat;
background-image: url('circle.svg');
}
The extra space in the :after pseoudoelement gives IE spare canvas to draw on, but both the visible icon and the space occupied by the original container remain the same.

SVG moves out of position when screen size changes or doesn't scale

I've created an SVG and put the width as a percentage because I want it to resize to fit different screen widths, but when I resize the screen, the svg moves up and down and doesn't move left/right to stay in the centre. If I use pixels instead of percentages, it doesn't resize with the screen.
Preview didn't work on here so here's the codepen link
.
HTML
<svg height="100%" width="100%" id="main">
<circle class="graph line line-1" cx="50%" cy="50%" r="25%" stroke-width="5%" stroke="#f1c40f" fill="none" />
<circle class="graph line line-2" cx="50%" cy="50%" r="20%" stroke-width="5%" stroke="#e67e22" fill="none" />
<circle class="graph line line-3" cx="50%" cy="50%" r="15%" stroke-width="5%" stroke="#00c0df" fill="none" />
</svg>
CSS
#main {
padding: 100px 0;
margin-top: 100px;
height: 200px;
background-color: pink;
}
.graph {
transform: rotate(270deg);
}
.graph.line {
transform-origin: center;
stroke-dasharray: 160%;
animation: graph 1.5s ease-in-out infinite alternate;
}
#keyframes graph {
from {
stroke-dashoffset: 160%;
}
to {
stroke-dashoffset: 90%;
}
}
That's what viewBox is for. With a viewBox, you establish a local coordinate system, which scales with your image. In your svg you simply use your local coordinates, and the image scales to any size...
#main {
position:absolute;
top:0px;left:0px;
right:0px;bottom:0px;
background:pink
}
.graph {
transform: rotate(270deg);
}
.graph.line {
transform-origin: center;
stroke-dasharray: 160%;
animation: graph 1.5s ease-in-out infinite alternate;
}
#keyframes graph {
from {
stroke-dashoffset: 160%;
}
to {
stroke-dashoffset: 90%;
}
}
<svg viewBox="0 0 100 100" id="main">
<circle class="graph line line-1" cx="50" cy="50" r="25" stroke-width="5" stroke="#f1c40f" fill="none" />
<circle class="graph line line-2" cx="50" cy="50" r="20" stroke-width="5" stroke="#e67e22" fill="none" />
<circle class="graph line line-3" cx="50" cy="50" r="15" stroke-width="5" stroke="#00c0df" fill="none" />
</svg>

Resources