Jump to content
Search Community

SVG animation freeze

bparticle 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

I am integrating a piece of code that was discussed in this forum post:

The code works in itself but while interacting with it, the reverse animation does not show and I noticed in the code inspector that the animated points of the SVG are somehow frozen at 0,0,0,0,0,0. The numbers also shake a little bit as if there is conflicting animation commands freezing it in a certain state. I attached a gif to illustrate this. How can I debug this effectively? No other errors are being shown in the console. 

gsap-problem.gif

Link to comment
Share on other sites

@Sahil I managed to reproduce the behavior in a CodePen, so maybe this will help you or someone else pinpointing my problem. This code is used in a CMS for animating the opening of modal windows. There are multiple modal calls on the same page, everywhere in the website, and the behavior needs to be consistent and reliable. Right now it works pretty well, but only the opening of the window is executed, the closing window is skipped and "freezes" the svg animation like I mentioned and like you can see in the CodePen.

 

I have moved the timeline into a dedicated function in order to be called by the different modal actions (in this case I have modified it to receive the appropriate message from the button click). When the function receives the 'playTl' message it will play the timeline, when it receives a different message it should play it in reverse.But the reverse never works.

 

See the Pen oEaXNW by bparticle (@bparticle) on CodePen

 

Link to comment
Share on other sites

Here is how you can apply that effect to multiple elements. I didn't go through your code because you were mixing jQuery animate and their hide/show etc animations with GSAP which over complicates things. This demo will give you idea how to approach it.

 

Play and reverse is simple and you don't have to mess with classes.

  1. First create a paused timeline.
  2. Now first you have to check if timeline is reversed by using ternary operator.
  3. If Timeline is reversed then it will play timeline forward but our timeline is not played yet.
  4. So you can set timelines's reversed property to true and timeline will play on first click and reverse on second click.

Does that help?

 

See the Pen BYqVRG?editors=0010 by Sahil89 (@Sahil89) on CodePen

 

  • Like 4
Link to comment
Share on other sites

Thanks, @Sahil. I will try this approach and report back if it worked out for me.

 

Since you mention mixing jQuery animation and gsap: is that a very bad idea? I'm doing it, because jQuery is added to the CMS by default, and it's second nature for me to use it, but in this case I have the full gsap suit loaded as well. Better to stick to gsap only? What are the disadvantages of mixing the methods?

Link to comment
Share on other sites

@bparticleIt's not bad, it complicates things. And trust me, if you stick with GSAP then you will never  feel the need to use jQuery animations. I was like you but I have simply forgotten jQuery, life is easier with less jQuery. :D But it is personal choice, if you prefer you can continue using jQuery animations with GSAP.

 

And wait, @OSUblake is responding so he will have some better approach.

 

BTW you are using svg element as modal then can't you reuse same element throughout the page? Just give it position and dimension of whatever element you are animating?

  • Like 2
Link to comment
Share on other sites

 

 

17 hours ago, bparticle said:

I have moved the timeline into a dedicated function in order to be called by the different modal actions (in this case I have modified it to receive the appropriate message from the button click). When the function receives the 'playTl' message it will play the timeline, when it receives a different message it should play it in reverse.But the reverse never works.

 

 

That is creating some serious issues. You're not saving a reference to anything, so you're creating new event listeners and animations that run independently of each other every time you call that function. What goes on inside a function does not stop when the animation is done. These will continue to run unless you explicitly remove them.

 

TweenLite.ticker.addEventListener("tick", drawPoly);

window.addEventListener("resize", function() {
  TweenMax.set(svg, {
    width: target.clientWidth,
    height: target.clientHeight
  });

  rect = svg[0].getBoundingClientRect();
});

 

You should read up on how closures work.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

 

And objects too.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects

 

When you try to close the modal, you're creating a timeline and then immediately calling reverse on it. That won't do anything because the start of an animation is also the end of animation when reversed. You would need to do something like setting the progress of the animation to 1, and then call reverse. So what's happening is the onReverseComplete callback gets called immediately, removing your modal.

 

 

 

 

How to animate points on a polyline/polygon

You can't change an attribute. Setting an attribute initializes that property. So every time you set the points attribute, you're creating a brand new set of points. That's slow, and requires extra work. Here's how you can access and work with those points. When you change/animate a point, it will automatically update the element!

 

var svg = document.querySelector("#svg");
var polygon = document.querySelector("#polygon");

// Create and add points to the polygon
var point1 = polygon.points.appendItem(svg.createSVGPoint());
var point2 = polygon.points.appendItem(svg.createSVGPoint());
var point3 = polygon.points.appendItem(svg.createSVGPoint());

// Now animate it. That's it!
var tl = new TimelineMax()
  .to(point1, 1, { x: 50, y: 10 }, 0)
  .to(point2, 1, { x: 90, y: 90 }, 0)
  .to(point3, 1, { x: 10, y: 90 }, 0)

 

 

 

How to make paths, polylines and polygons responsive

@Sahil was on the right track. This will make the SVG fill it's bounds, and will allow you to use values between 0 and 100.

 

<svg id="svg" width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
  <polygon id="polygon" />
</svg>

 

 

 

 

 

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

 

 

  • Like 4
Link to comment
Share on other sites

@OSUblake but that won't work for rectangular shapes right? It works. I was going to do something similar with 100x100 viewbox and looked for if viewbox can be stretched etc but didn't find anything so decided to not use viewbox.

 

I didn't know polygon points can be animated like that. Thanks. Any similar trick for paths to avoid setAttribute?

 

BTW have you decided to start answering in blog format? :D It does look great and more impactful.

  • Like 1
Link to comment
Share on other sites

@OSUblake Thank you for the elaborate and enlightening answer! Seems like this is going to be a rewrite :D All for the better.

 

About moving the timeline to a function, you wrote the following:

 

29 minutes ago, OSUblake said:

That is creating some serious issues. You're not saving a reference to anything, so you're creating new event listeners and animations that run independently of each other every time you call that function. What goes on inside a function does not stop when the animation is done. These will continue to run unless you explicitly remove them.

 

I was afraid for that actually, but I didn't know the details about it, nor how to go about it differently. Could you tell me how exactly it is different in the CodePen you have shared? (Please excuse me if it's obvious)

 

I will try this out tonight in any case, and report back. Thanks again!!

  • Like 2
Link to comment
Share on other sites

1 hour ago, Sahil said:

@OSUblake but that won't work for rectangular shapes right? It works. I was going to do something similar with 100x100 viewbox and looked for if viewbox can be stretched etc but didn't find anything so decided to not use viewbox.

 

Yep. The trick is setting preserveAspectRatio="none" on the SVG.

 

1 hour ago, Sahil said:

I didn't know polygon points can be animated like that. Thanks. Any similar trick for paths to avoid setAttribute?

 

If the points are already set on the attribute, you can still use them.

 

for (var i = 0; i < polygon.points.numberOfItems; i++) {
  var point = polygon.points.getItem(i);
  
  TweenMax.to(point, 1, {
    x: Math.random() * 100,
    y: Math.random() * 100
  });
}

 

 

It depends on the element and attribute, but you can usually access values like this. Just console.dir(element) an element, and explore some of the properties.

 

var circle = document.querySelector("circle");
circle.cx.baseVal.value = 100;
circle.cy.baseVal.value = 200;
circle.r.baseVal.value = 50;

var svg = document.querySelector("svg");
var viewBox = svg.viewBox.baseVal;
viewBox.x = 100;
viewBox.y = 200;
viewBox.width = 1000;
viewBox.height = 500;

 

 

I use the viewBox object to drive all the dragging and zooming in this demo.

 

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

 

 

1 hour ago, Sahil said:

BTW have you decided to start answering in blog format? :D It does look great and more impactful.

 

Thanks. I've done that in other posts, so it's not totally new, but I'm going to start doing it more.

  • Like 4
Link to comment
Share on other sites

1 hour ago, bparticle said:

I was afraid for that actually, but I didn't know the details about it, nor how to go about it differently. Could you tell me how exactly it is different in the CodePen you have shared? (Please excuse me if it's obvious)

 

 

I'm using the same timeline. Here's a reduced look at my code. I'm returning an object with some properties and methods on it.

 

var modal = createModal();

function createModal() {

  var animation = new TimelineMax()
  
  var modal = {
    animation: animation,
    open: open,
    close: close
  };
  
  function open() {
    animation.play();
  }
  
  function close() {
    animation.reverse();
  }
  
  return modal;
}

 

 

So I can control the timeline from outside the createModal function.

 

// calls the open function on the modal object, which calls animation.play()
modal.open() 

// the same goes for close, but it calls animation.reverse()
modal.close()

 

  • Like 3
Link to comment
Share on other sites

I have one more question: when closing the modal in the CMS, I need to actually keep the created window in existence on the page, because the Ajax call won't work twice on the same object for performance reasons (if the content is loaded once, no need to do that again the second time). Is there a quick method to remove the points from the polygon, so they can be recreated next time the same modal is opened? Right now the second time around, these points are all mangled up.

Link to comment
Share on other sites

@bparticle Aren't you using exact code as Blake? It only reverses animation when you close the modal, I can't imagine how polygon gets mangled up. Maybe you need to check if modal exists then play animation otherwise create modal. You can remove points by writing poly.setAttribute('points', '');

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

  • 2 weeks later...
On 2/26/2018 at 3:56 PM, OSUblake said:

 

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

 

 

 

I'm back again working with this code :) The CodePen above is showing a beautiful modal folding open using SVG point animations. I'm integrating this code in a situation where multiple modal windows need to open and close individually, without being erased from the DOM like is happening in this code. If I understand it correctly, what's happening here is the markup for the modal is kept in memory in the modal object, and therefore the window can be reopened like it does. If there are multiple modal objects however, they will be overwritten in memory and will not be able to be reopened. Could someone take a stab at editing this code with two or three instances of these modals, or point me in the right direction on how to edit this? The part that concerns me is body.removeChild(container). It seems to be a vital part of the code, but it comlicates things when multiple objects need to be opened and closed.

Link to comment
Share on other sites

@bparticle Blake has provided you really great and robust demo which will work in all scenarios with zero to minor changes, it all comes down to how you will implement it in your project. And when CMS gets involved it just gets broader. Like, what if you have different elements from different parents that open modal on click? What if then you want some modal to auto-open? Then what if there is already another modal open? etc scenarios. You can take different approaches with most basic approach of creating two modal objects that will respond to two different click events and will present text from two different sections. More flexible implementation will be where you pass different parameters for color, section etc and just use single modal object that will be used throughout the site. Then third way I can think of will be by using data attributes that will be used to create/track all modals throughout the page.

 

Following is very basic demo of two modals, that you can implement if have few modal objects on your site. Anything beyond that just becomes general programming and CMS related question which is way too broad and beyond this forum. Somebody else might take interest to help you if they find the topic interesting but chances are slim.

 

See the Pen KoVMMr?editors=0010 by Sahil89 (@Sahil89) on CodePen

 

  • Like 4
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...