Jump to content
Search Community

Animating SVG circle strokes from the 12 o'clock position with DrawSVG

PointC test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hey fellow GreenSockers. I was going to post this in the SVG Gotchas thread, but this question is asked a lot around here so I thought maybe a new topic would be the way to go.

 

SVG circles start at 3 o’clock and most people want to animate the stroke from the 12 o’clock position. Conventional wisdom would tell you to simply rotate the circle by -90 degrees and you’re all set, but there are some problems with this approach.

 

Using GSAP to rotate the circle -90 degrees will work perfectly fine in Chrome and FF, but Safari will ignore that set() for some reason. (IE and Edge honor the rotation, but they have another problem.)

 

You can simply add a transform attribute directly to the circle like

<circle cx="500" cy="75" r="60" transform="rotate(-90 500 75)"/>

This will work correctly in Chrome, FF and Safari, but not completely in IE and Edge.

 

If you're animating the stroke with DrawSVG, IE and Edge need the stroke-dasharray set to 0 in the attributes or they will cause problems. If you don’t add that attribute, a regular circle will start at 9 o’clock and the circle that you’ve rotated -90 degrees with GSAP or a transform attribute will start at 6 o’clock. Strangely, if you resize the browser window to the point of the SVG changing size, IE and Edge will correct themselves. 

 

The only bulletproof way I see to draw a circle stroke from the 12 o’clock position with DrawSVG in all browsers is transforming the circle -90 degrees and adding the extra attributes to keep IE and Edge happy.

<circle cx="500" cy="225" r="60" stroke-dashoffset="0" stroke-dasharray="0" transform="rotate(-90 500 225)"/>

It appears that only adding the stroke-dasharray attribute fixes the IE/Edge issues, but I also add a stroke-dashoffset="0" attribute also just to be safe.

 

Check out the demo in all your browsers.

 

Hopefully this helps somebody with this type of animation.

 

Happy tweening.

:)

See the Pen VbPPwY by PointC (@PointC) on CodePen

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

Nice work Craig!

 

The reason that adding the stroke-dasharray attribute fixes the IE/Edge issues. Is due to IE/Edge being really strict and needs the attributes to exist on the element. I have even seen IE/Edge fail to animate with CSS transitions/animations for not even having the stroke attribute present on the element.

 

But that is expected with IE/Edge since they are big poopy pants. :)

  • Like 1
Link to comment
Share on other sites

Thanks for the extra info Jonathan. :)

 

I figured this was IE/Edge being the usual pain in the rear that they always seem to be, but I thought I had tested a circle drawing animation a while back and it worked without that attribute in Edge. Maybe I'm just crazy.  :blink:

 

This one reminded me of the other issue I discovered with DrawSVG and linecaps in IE/Edge, but Jack fixed that one in the plugin. I'm not sure if this one can be fixed or not?

 

Hopefully this info helps others avoid some problems.

:)

Link to comment
Share on other sites

Just an additional follow-up and clarification. Safari ignores the rotation if you do it like this:

<circle id="circ1" stroke="navy" cx="100" cy="75" r="60"  />
TweenMax.set("#circ1", {rotation:-90, transformOrigin:"center center"});

It will work if you use the attribute plugin like this:

<circle id="circ2" stroke="green" cx="300" cy="75" r="60"  />
TweenMax.set("#circ2", {attr: {transform: "rotate(-90 300 75)"}});

I guess that's probably to be expected since it is an attribute, but the unwelcome surprise will come when you expect a regular rotation to work like it does in the other browsers.

 

Happy tweening.

:)

Link to comment
Share on other sites

Great write-up, Craig.

 

Interestingly...

 

Safari doesn't like rotation:-90, but it's fine with rotation:-90.01 so that might be easier. Clearly it's a browser rendering bug that's unrelated to GSAP. So weird.

 

Also, the simplest fix of all is probably just making the <circle> a <path> instead which can be done using MorphSVGPlugin.convertToPath(). If you really don't want to join the club, you could still do that on Codepen (see http://codepen.io/GreenSock/full/OPqpRJ/), have it do the conversion, and copy the path data yourself. Should be pretty quick. 

  • Like 1
Link to comment
Share on other sites

I think you're absolutely right Jack - making it a path is the easiest thing to do. :)

 

Figuring out a solid go-to answer on this was one of the reasons I wrote this post. This question seems to pop up frequently and I want to give the best advice when it does. Converting to a path seems to be the best, but we have a fallback with the extra attributes in IE and Edge and -90.01 rotation for Safari.

 

Regarding the convert to path, I'm seeing some strange behavior in Edge and wondering if you or anyone else can confirm it? I've made a new little demo that converts a circle to path rotates it -90 degrees, then draws the stroke. It works perfectly in all browsers except Edge. I'm seeing a solid circle with no stroke or animation. Looking at the inspector I see the values animating, but nothing is rendering. It looks like the attribute names for stroke, fill, and stroke-width have been changed to uppercase. I'm not sure if that's what's causing it not to render properly, but it looked odd. I'm not even sure if attribute names are case-sensitive? 

 

Anyway, here it is:

See the Pen BRWNxN by PointC (@PointC) on CodePen

 

This works fine in IE11 for me. I'm only seeing this in Edge.

Link to comment
Share on other sites

Good catch, Craig - Edge is acting super weird but I think I got a workaround in place now...

 

It had to do with the MorphSVGPlugin.convertToPath() and the attributes that were copied from the <circle> to the <path> being uppercase. 

 

Apparently if you loop through the attributes and set them exactly as the browser provides them in the list (using the nodeName), Edge reports those in uppercase but chokes when set that way. Go figure! What's even more strange is that if I force them to lowercase when setting, it displays correctly (visually) but if you inspect the DOM you'll see that Edge still shows them as uppercase! Doesn't get much stranger than that.

 

I patched MorphSVGPlugin to work around the Edge bug. Seems to be working well now. The codepen-specific file is updated as well as the club member downloads. 

  • Like 1
Link to comment
Share on other sites

Crazy Microsoft indeed

 

Here was another one:

 

Edge's DOMParser.parseFromString converts known SVG attributes to all upper-case

 

https://connect.microsoft.com/IE/feedback/details/2057021/edges-domparser-parsefromstring-converts-known-svg-attributes-to-all-upper-case

 

The DOMParser parses valid svg documents into a DOM that has attributes that are all upper-case for the known SVG attributes. However creating elements like this (e.g. through recursive DOM copying) the attributes aren't recognized anymore and rendering fails

 

Gotta love or actually hate Microsoft :)

  • Like 2
Link to comment
Share on other sites

I'm kind of surprised nobody has run into this issue before. This bug has been in Edge for as long as I have been using it, so for at least a couple of years. 

 

And there are several things you should know about the bug. First, it only affects presentation attributes, which are attributes that can be used as CSS properties. The attribute name does not start out in uppercase. It will only get converted to uppercase if the first time the attribute is accessed is by using an index, i.e. looping through the attributes nodes or viewing the element in the dev tools. 

 

Look at the following demo. The first time Rect 1 is accessed is through the getAttributeNode method, so its name will not be converted to uppercase. However, the first time Rect 2 is accessed is through an index value, so its name will be converted to uppercase.

var rects = document.querySelectorAll("rect");

// RECT 1
rects[0].getAttributeNode("fill").name; // => fill
rects[0].attributes[0].name; // => fill

// RECT 2
rects[1].attributes[0].name; // => FILL
rects[1].getAttributeNode("fill").name; // => FILL

See the Pen 73cda5416b011dd2963bceb74da2bd13?editors=1010 by osublake (@osublake) on CodePen

 

Another important thing to note is that even if an attribute name gets converted to uppercase, the mapping with the original lowercase name does not change, so you would still use the lowercase name to get and set the attribute.

 

You can enter this into the console to see how it plays out. And notice the how the outerHTML value does not show the attribute in uppercase.

 

SrSdUXF.png

 

So the big thing to take away from all this is that it only affects presentation attributes, but does not change their usage. The uppercase name only causes problems when you need the correct casing, as is the case with the MorphSVGPlugin when it needs to copy attributes between different elements.

 

I noticed that the current fix seems to set all the attribute names to lowercase, which will work fine presentation attributes as they are all lowercase. However, this will break camel cased attribute names, and SVG has a lot of camel cased attribute names. It will also break any uppercase names that aren't presentation attributes. There's no telling what attributes the user may have put on the element. Custom attributes are used extensively in frameworks like Angular, Vue, and React, and are rarely prefixed with "data-".

 

So it might be better to just limit the check to Edge. And instead of looping through every possible presentation attribute, you might be able to just grab all the attributes from the outerHTML value. The uppercase names do not seem show up on it.

 

 

.

  • Like 1
Link to comment
Share on other sites

Hey Blake. I'm seeing your orange circle start at 3 o'clock in Safari. All other browsers have it starting at 12 o'clock.

 

I see. I've never looked into this whole 3 o'clock issue before, but that is quite telling. The same thing used to happen in Firefox.

 

Now take a look at this demo in all the different browsers....

See the Pen ed2f14b6fe1cc612e18b67aea9c68281?editors=0010 by osublake (@osublake) on CodePen

 

Can you tell what's going on? The strokes glitching in the middle have nothing to do SVG. It's a canvas issue. What do I mean? There is no SVG renderer. The way SVGs are implemented in the browser is based on canvas, so that's the source of most rendering issues.

 

However, the actual rendering isn't done on the HTML canvas. That's done on the browser's canvas, like everything else. I don't know what Edge and Safari use, but Chrome and Firefox both use Skia. It's just a more advanced canvas, but the api is very similar.

 

.

  • Like 2
Link to comment
Share on other sites

Back to the original topic, drawing circles from 12 o'clock. Using the MorphSVGPlugin to convert the circle to a path works, but that requires setting a transform, and doesn't work well with an ellipse. A better approach would be to have the path start where you want it. 

 

Here's a function to do that calculation for you. For a circle, just pass in the same radius for the rx and ry parameters.

function getArcPath(cx, cy, rx, ry, startAngle) {
  
  var theta = startAngle * Math.PI / 180;
      
  var dx = rx * Math.cos(theta);   
  var dy = ry * Math.sin(theta);
  
  return [
    "M", cx + dx, cy + dy,
    "a", rx, ry, "0 1 1", 2 * -dx, 2 * -dy,
    "a", rx, ry, "0 1 1", 2 *  dx, 2 *  dy, "z"
  ].join(" ");
}

Here's a demo of its usage. Pretty easy to make an ellipse start at some arbitrary angle.

See the Pen VbWKMj by osublake (@osublake) on CodePen

 

That function could be expanded to do other stuff, like making a pie chart. Here's a demo showing how that could be done.

See the Pen OmgMNm by osublake (@osublake) on CodePen

.

  • Like 4
Link to comment
Share on other sites

Excellent information Blake. :)

 

Yeah - I've experienced that weird rendering glitch in the middle a few times. In fact, I've made a couple of pie charts into doughnut charts just so I wouldn't have to deal with it. I was never sure why, but Chrome doesn't display that problem while all the other browsers do.

 

Your demos will be quite helpful in future projects. Thank you.

 

I started this topic because I've seen several people try to draw a circle starting at 12 o'clock, but we've found new browser bugs, updated the MorphSVG plugin, got new demos from Blake and learned more about canvas. You just never know where a topic may lead around here. I do love the GreenSock neighborhood.

:)

Link to comment
Share on other sites

  • 4 weeks later...

@OSUblake I was exploring a workaround that takes into consideration the potential problems you noticed with the lowercase attribute names, but it seems like even if I get the "outerHTML" of an element that contains camelCased attributes, they're always converted to be lowercase by the browser. Are you seeing the same thing? I'm wondering if the current solution is actually much more durable than anticipated. Do you still think we need to accommodate various cases? 

Link to comment
Share on other sites

Hmmm... maybe. I'm seeing other browsers convert camel case names to lowercase too. 

 

I'm having a hard time finding a valid, camel cased attribute to test out to see if it would actually affect it. List of list of attributes on MDN.

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute

 

If we can't manually break it, then that's probably a good sign about its effectiveness.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...