Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
manchuwook

Animate arc inside svg image

Recommended Posts

Given an SVG image with two circles, #innerCircle and #outerCircle, and other elements I don't care as much about - I want to have an easy way to animate the arc of #outerCicle with maybe easein.  Tried snap.svg but it doesn't animate well (which is a point of contention on SO), wanted to try Raphael but it doesn't handle existing SVGs, looked up svgjs but it is pending svg adoption in the RC milestones.

(function () {
	var ocx = 0,
		ocy = 0,
		oca = 0;

	function describeArc(x, y, radius, startAngle, endAngle) {
		var start = polarToCartesian(x, y, radius, endAngle);
		var end = polarToCartesian(x, y, radius, startAngle);
		var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";

		var d = ["M", start.x, start.y, "A", radius, radius, 0, arcSweep, 0, end.x, end.y, "L", x, y, "Z"].join(" ");

		return d;
	}

	function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
		var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;

		return {
			x: centerX + (radius * Math.cos(angleInRadians)),
			y: centerY + (radius * Math.sin(angleInRadians))
		};
	}

	Polymer('character-hitpoints', {
		maxHealth: 0,
		maxHealthChanged: function () {
			// NotImplemented
		},
		increment: function () {
			// NotImplemented
		},
		ready: function () {
			var character = this.character;

			var h = this.$.hpRing;
			var t = {};

			// load the svg fragment into the element
			Snap.load("hpcircle.svg", function (f) {
				var s = Snap(h);
				s.append(f);

				var n = s.select('#outerRing').node;
				var np = n.pathSegList[2];
				var a = n.pathSegList[1];

				ocx = np.x;
				ocy = np.y;
				oca = a.r1;

				t = s.select('#characterName');
				t.node.textContent = character;
				t.node.x = ocx + 10;
				t.node.y = ocy;
			})
		},
		animRing: function (divRing) {
			var hpRing = Snap(divRing.toElement.shadowRoot.querySelector('#svg2'));
			var max = Math.floor(Math.random() * 359 + 1)

			Snap.animate(0, max, function (val) {
				hpRing.select('#outerRing').attr({
					'd': describeArc(ocx, ocy, oca, 0, max)
				});
			}, 2000, mina.bounce, function (val) {
				console.log('Animate done');
			});
		}
	});
})();

The last bit, animRing, changes the arc, but doesn't actually animate with a bounce, it just flips to the new size.  Any advice is welcome, I've got a dent where I've been banging my head against my desk.

Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

Unfortunately I'm not too deep into SVG in order to help you enough with this issue. I would suggest you two things though.

 

First, take a look at this plugin for Snap, crafted by Anthony starting from the Raphael Plugin, one of our community members:

 

https://github.com/anthonygreco/GSAPSnapPlugin

 

Two, give the Attribute Plugin a go, it could come in handy considering that SVG elements are DOM nodes, which can be easily accessed through JS:

 

http://greensock.com/docs/#/HTML5/Plugins/AttrPlugin/

 

Finally is always a good idea to create a reduced live sample of your code, please check this post in order to find out how:

 

http://greensock.com/forums/topic/9002-read-this-first-how-to-create-a-codepen-demo/

 

Rodrigo.

  • Like 2
Link to comment
Share on other sites

Yeah, like Rodrigo I'm not really familiar with creating SVGs with code which makes it even harder to grasp how that code should work without seeing it running at all.

 

One thing to keep in mind though, is that GSAP can tween any numeric property of any JavaScript object. So even if GSAP doesn't natively tween "the arc of an SVG" you can tween some number and then apply it to your arc-drawing function.

 

For a practical example, GSAP does not animate webkit css filters, but you can tween a value of a proxy object and then apply that value to the filter.

Check out the tween and onUpdate function in this demo to see how it can work: http://codepen.io/anon/pen/psEJa?editors=001

Link to comment
Share on other sites

For brevity, here is what I had figured out - imagine the code above but using this bit changed:

			Snap.animate(359, max, function (val) {
				var ad = describeArc(ocx, ocy, oca, 0, val);
				hpRing.select('#outerRing').attr({
					'd': ad
				});
			}, 1234, mina.bounce, function (val) {
				console.log('Animate done');
			});

This will now shrink the stuff up.  If you notice though, I'm not using the GSAPSnapPlugin to do it.  I'd like to learn how to use GS, but this actually works.  The short of it is there is an attribute to change the arc called 'd' and it contains a string that only portions of it change.  As an example:

M 618.74629,445.21933 A 210.17485,210.17485 0 1 1 536.22656,278.25335 L 408.57144,445.21933 z
M 288.0200999107116 273.0541714183745 A 210.1748504638672 210.1748504638672 0 1 0 408.5714416503906 235.0444793701172 L 408.5714416503906 445.2193298339844 Z 

I am unsure as to how the GSAPSnapPlugin would output this correctly since if I try to do .attr({ 'd' : describeArc(...)}) it gives some silliness about M 0,0 is not a valid property.  The plugin does handle non-long-string attributes awesomely, but this parsed one eludes me.

Edited by manchuwook
Link to comment
Share on other sites

		animRing: function (trg) {
			var hpRing = Snap(trg.toElement.shadowRoot.querySelector('#svg2'));
			var ring = hpRing.select('#outerRing');
			
			var max = Math.floor(Math.random() * 359 + 1)
			var current = {
				radians: 360
			};

			TweenMax.to(current, 2, {
				radians: max,
				onUpdate: resizeRing,
				onUpdateParams: [ring],
				ease: Power1.easeInOut
			});

			function resizeRing(element) {
				var arc = describeArc(ocx, ocy, oca, 0, current.radians);
				element.attr({
					'd': arc
				});
			}
		}

Is what I ended up with, in case people want to use this code in the future.

Link to comment
Share on other sites

Thanks for posting the solution. It is very helpful.

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.
×