Flash Floods

Greensock Tweens in Angular 2

Recommended Posts

Hi,

 

I'm wondering if it is possible to use TeenMax functions inside of an angular controller (or in 2.0, component).

 

Do I dependency inject it somehow?

 

Thanks,

Jim

Share this post


Link to post
Share on other sites

Welcome to the GreenSock forums,

 

Unfortunately I don't have any experience with Angular, but we keep hearing good things about using it with GSAP.

 

Perhaps one of the following resources will be of help:

 

 

http://www.creativebloq.com/javascript/build-animated-angularjs-website-61411891

http://onehungrymind.com/build-super-smooth-rollover-angularjs-greensock-timelinelite/

http://greensock.com/forums/topic/10822-easier-animations-in-angular-13/

  • Like 1

Share this post


Link to post
Share on other sites

You generally don't have to inject stuff that isn't a part of Angular, like GSAP.

 

Using GSAP in Angular2 is still kind of iffy because some things aren't ready like the animation module. I was playing around with some of their demos, and got an animation to work like this.

import {Component, ElementRef} from 'angular2/core';

@Component({
  selector: 'hero',
  template: `<div></div>`
})
export class HeroComponent {

  constructor(private element: ElementRef) {
    TweenLite.to(this.element.nativeElement, 1, { x: 100 });
  }
}

Not sure if I was doing it right because the docs say that you should only access the element like that as a last resort.

https://angular.io/docs/ts/latest/api/core/ElementRef-class.html

 

In Angular 1.x, you usually do your animation in a directive or an animation module. To help migrate to Angular2, components were added to Angular 1.5. To access the element in a component, just inject the $element service in the controller.

class HeroController {
  constructor($element) {
    TweenLite.to($element, 1, { x: 100 });
  }
}

var heroComponent = {
  template: "<div></div>"
  controller: HeroController
};

angular
  .module("app", [])
  .component("hero", heroComponent);

Here's an example of using component. Normally, I would use an animation module to do structural animations like that (adding and removing elements). However, I just wanted to show you how to inject an element into a controller.

 

http://codepen.io/osublake/pen/4ac02b62146b6cbc6a2e236c41effbbf?editors=001

  • Like 3

Share this post


Link to post
Share on other sites

Are there any updates on the subject of improved Angular2 support?  I am most interested in SVGdraw within Angular2 components.

 

If someone figures out if/how a simple SVGdraw (see z-shaped underline) animation can be done in Angular2 I would be very keen to hear.  

 

Till then I fear I am going to have to move on and leave out the animations. 

 

Best regards,

Steve

Share this post


Link to post
Share on other sites

Alright GreenSock fans. Gather around as I'm about to show you how to create a custom SVG component in Angular 2. There have been concerns about whether or not GSAP would be able to play nicely with Angular 2, and I'm going to show you that there is nothing to worry about. But don't expect anything fancy here. I'm only going to go through the basics of setting it up... mainly because that is all I really know how to do.  :unsure:  

 

Lets call our component blob-morpher... because that is what it is going to do. And that brings us to our first problem, the name. You can't use custom tags in SVG like you can with HTML. However, we can use custom attributes, so lets so create an attribute directive and use a <g> element instead. So this is what the SVG syntax would look like for our component.

<svg>
  <g blob-morpher></g>
</svg>


 

The name of the selector needs to be in square brackets as it's going to be an attribute. And for the template, you need to prefix your tags with the svg namespace. Since we are going to be doing morphing, the element type should be a path. This template will become the inner component of the <g> element we put the directive on.

@Component({
  selector: `[blob-morpher]`,
  template: `<svg:path></svg:path>`
})
class BlobMorpher { }


 

We're going to animate the d and fill attributes, so lets link those up with our component, and name them whatever you want. Go ahead and add other fields to our class like a timeline and the path to morph to.

@Component({
  selector: `[blob-morpher]`,
  template: `<svg:path class="blob" [attr.d]="path1" [attr.fill]="fill"></svg:path>`
})
class BlobMorpher { 
  fill  = "#1a1a1a";
  path1 = "M0,0...";
  path2 = "M0,0...";
  timeline = new TimelineMax({ repeat: -1, yoyo: true});
}


 

You can animate most attributes without having a reference to the element. So GSAP will have no problems animating the fill color. However, morphing path data is a little different, and GSAP will throw an error if the type of object being animated is not an element. Lets bring in a reference to the element and animate the path directly. We need to wait for the element to be ready, so lets use our component's onInit lifecycle hook to create our animation instead of doing it in the constructor. Our component is now ready to be used.

@Component({
  selector: `[blob-morpher]`,
  template: `<svg:path class="blob" [attr.d]="path1" [attr.fill]="fill"></svg:path>`
})
class BlobMorpher { 
  fill  = "#1a1a1a";
  path1 = "M0,0...";
  path2 = "M0,0...";
  timeline = new TimelineMax({ repeat: -1, yoyo: true});

  constructor(private elementRef: ElementRef) { }

  ngOnInit() {   

    var path = this.elementRef.nativeElement.firstChild;

    this.timeline
      .to(path, 2, { morphSVG: this.path2, x: 120 }, 0)
      .to(this, 2, { fill: "orange" }, 0);
  }
}

RESULT

  • Like 7

Share this post


Link to post
Share on other sites

Thanks for the thorough write-up, Blake.

Share this post


Link to post
Share on other sites

Blake,  This is really great stuff you have shared. I have learned very much from your example.  I cannot say how long it will take me to figure out everything that you have done to get this to work but you have inspired me to try again, now knowing that it can be done.  

 

Please understand that I know only a very little more about Angular2 than I know about GreenSock, which all who have seen my posts can see is precious little.  

 

As a somewhat comical example of how with even as little knowledge as I have, I managed to blow up my CodePen account.  this was done while trying to integrate your example with my z-style underline.  It seems the css was corrupted (or something else I cannot imagine), I took a screen capture of what the results were.  I share this in hopes of helping anyone else who may experience a problem like this. My advise to them is 'remain calm and wait about an hour and things will gradually return to normal' (beyond that I have no clue what happened).  

 

I have captured many of my learnings from your post and will try to highlight them when(if) I am ever able to get this example working.  I will not be attempting this in CodePen again as this environment adds several challenges when working with this framework (or at least so it appears to me). 

 

I added svgDraw to your file, and attempted to replace a single path <svg> in the template and attached the CodePen below (not working but at least displaying correctly now).

 

http://codepen.io/Bolmanator/pen/qZPMjo

 

For some reason the pen.js file (whatever that is) is still looking for the BlobMorpher (is not compiling the TS correctly?).  I see there are errors in the TS compile, in CodePen, but these are present in your working file as well.

 

When time allows I will take attempt this using WebStorm I hope this will at least remove some of the variables from this problem.  

 

Again, many thanks and I will keep you posted as to my progress (likely not for  a few weeks as family commitments are consuming my weekends),

Steve

CodePen_CSS_Meltdown.pdf

  • Like 1

Share this post


Link to post
Share on other sites

Glad you found it useful!
 
I wish I could provide more assistance with Angular 2, but I haven't had a chance to learn it yet. But from what I can tell, it's going to be much easier to use than Angular 1. The only problem is that everything is completely different so you have re-learn everything from the ground up. The only thing that is the same between the two versions is the name, Angular   :blink:
 
CodePen has been doing some upgrades today, so your CSS didn't break it... although that would be kind crazy if did! So I would be cautious about trusting any errors you might see on CodePen in the next 24 hours or so.
 
Your comment about using const instead of import just has to deal with the way CodePen works. CodePen doesn't have a file system, so you can't use import or definitions, so that's just a work around. And the Angular files I'm using on CodePen are the umd versions, which are little bit different than the normal files, and aren't split up into modules.
 
CodePen also doesn't do type checking, so that's why I didn't include any types if you were wondering. If you are trying to create my demo locally, with type checking and all, the code should look more like this.

import { Component, ElementRef, OnInit } from "angular2/core";
import { bootstrap } from "angular2/platform/browser";
import "gsap";

@Component({
  selector: `[blob-morpher]`,
  template: `<svg:path class="blob" [attr.d]="path1" [attr.fill]="fill"></svg:path>`
})
class BlobMorpher implements OnInit { 
  fill:  string = "#1a1a1a";
  path1: string = "M0,0...";
  path2: string = "M0,0...";
  timeline: TimelineMax = new TimelineMax({ repeat: -1, yoyo: true});

  constructor(private elementRef: ElementRef) { }

  ngOnInit() {   

    var path = this.elementRef.nativeElement.firstChild;

    this.timeline
      .to(path, 2, { morphSVG: this.path2, x: 120 }, 0)
      .to(this, 2, { fill: "orange" }, 0);
  }
}

@Component({
  selector: "my-app",
  directives: [BlobMorpher],
  template: `<svg><g blob-morpher></g></svg>`
})
class AppComponent { }

bootstrap(AppComponent);

 

 
If you haven't already done so, I would do the Tour of Heros tutorial. I ran the demo, and it looks like they show how do everything you would need to get your input box z-animations working with events. Here's what you end up building in the tutorial.
 
http://plnkr.co/edit/e2Anc17jZ3Wp2EepCANK?p=preview

  • Like 1

Share this post


Link to post
Share on other sites

I noticed a couple of issues with your code...

 

The starting y-coordinates for you paths are really high, 575. Adding the viewbox you had from your previous demo brought your paths back into the view.

<svg viewBox="0.5 560.5 360 16">
  <g z-style-underline></g>
</svg>
 

In your template, you were trying to bind to a color attribute. There isn't one. You probably meant to put stroke there.

// Incorrect
<svg:path class="z-underline" [attr.d]="path1" [attr.color]="color"></svg:path>

// Correct
<svg:path class="z-underline" [attr.d]="path1" [attr.stroke]="color"></svg:path>
 

I also wouldn't use GSAP's selector engine for a reusable component as you have little control over what is being selected. That is why I used the elementRef.nativeElement, which would be <g> element the directive is on. From there you can use the element.querySelector or element.querySelectorAll methods to target the correct element(s).

// Try to avoid selecting line1 like this. 
// This would select all elements with the line1 class, which may not be what you want 
this.timeline.fromTo(".line1", 0.2, { drawSVG: "0% 0%" }, { drawSVG: "100% 0%" });
// This will select only the line1 element associated with the component
let group = this.elementRef.nativeElement; // This is the <g> element
let line1 = group.querySelector(".line1");

this.timeline.fromTo(line1, 0.2, { drawSVG: "0% 0%" }, { drawSVG: "100% 0%" });
 

I moved a couple properties to a CSS class to simplify some of the stuff, but this should give you a good start.

http://codepen.io/osublake/pen/RaLqKZ/?editors=0010

  • Like 2

Share this post


Link to post
Share on other sites

Blake,  

 

Many thanks for your work on the above subject.  I wish I were actually able to contribute more than just questions, but I just cannot adapt to the CodePen environment. I completely agree with your comments on Angular 2 it is a complete redo and would have been better, renamed to limit the confusion.  If you are interested in learning more I strongly recommend the book by Ari Lerner https://www.ng-book.com/2/ it is really excellent and the associated community https://gitter.im/ng-book/ng-book is helpful as well (of course nothing like my friends at GreenSock).  

 

I am now sure it is possible, and probably easy, to animate Angular2 components using GreenSock (including drawSVG).  However it will need to be done by someone more expert than I.  I keep getting hung-up by the most mundane problems, like importing drawSVG using WebStorm.  This is not a GreenSock problem, it is mostly my problem and secondly a problem with the maturity of Angular2 and every tool that has to interface with it.  

 

FYI,  I have tried the  http://greensock.com/forums/topic/13445-using-gsap-with-angular2/  and had no luck with that solution.  

 

My hat is off to you, for getting this conversation as far as you have.  I am just not able to take it from the CodePen (js) and translate it to the TypeScript and SystemJS + Webstorm that I am working in.

 

 

 

 

 
 

Share this post


Link to post
Share on other sites

I agree with you on CodePen. I'll try to convert my examples over to plunker later on and see if I can get DrawSVG working with SystemJS.

 

I haven't used Webstorm in awhile, so I can't offer much help with that. I think getting SystemJS to work is the hardest part. I would avoid trying to load GSAP/DrawSVG with it for the time being. Just put them inside good old script tags at the top of your document and see if that helps.

  • Like 1

Share this post


Link to post
Share on other sites

Here's a plunker version of it.

http://plnkr.co/edit/oZm5CRFPkFNnSpUW6gMY?p=preview

 

I didn't bother trying to import GSAP through SystemJS since GSAP sets itself up as a global anyways. I know running SystemJS locally uses a different configuration, but this might help point you in the right direction.

  • Like 2

Share this post


Link to post
Share on other sites

Blake,  I think I am very nearly there.  I did however simplify things a bit (I think).  I really like what you did in your Plunker, but when I set it up, it complied perfect but nothing worked.  So then I went back to my old CodePen version and pasted the HTML and JS just into an element and pulled that element into a Angular2 Component template, that works except that when I import drawSVG via good old fashioned <script> into my HTML the app is taken to Greensock.  I take this as a sign that I am very close, but cannot quite seal the deal.  

 

What is the best practice for importing drawSVGPlugin when working from an IDE?

 

Thanks, 

Steve

Share this post


Link to post
Share on other sites

Hi Steve,

 

As you've already noticed, it's taking you to the GreenSock home page because you are using a version of the plugin that will only work on certain domains like CodePen and Plunker. I've attached another version of the plunk. Just copy your DrawSVGPlugin.js file into the "lib" folder. There should already be a TweenMax file inside of it.

 

As for the best way to import a members only plugin... that's a good question. You can never go wrong with the tried and true way. Just copy the files into your project. Of course that may not always be ideal, especially if you are part of a team.

 

One nice thing about using jspm/SystemJS is that it can import packages from anywhere, npm, bower, git, local, etc. So you can create a private package and import it that way. Just update it whenever a new version of GSAP is available. Where to host it will depend on your situation. NPM and GitHub are the most popular places, but they aren't free. I use Visual Studio Team Services because it has a lot more features and is free for the first 5 users. To connect to it using a JetBrains product like WebStorm, you would need to install the IntelliJ plugin.

plunk.zip

Share this post


Link to post
Share on other sites

Blake,  

 

In the spirit of full disclosure, I must share that the reason I was being sent to the GreenSock home page was because I had inadvertently included a 'src=' that was (as you predicted) was still pointing to "a version of the plugin that would only work on certain domains like..." so not surprisingly the (correctly referenced) local <script src="vendor/... was simply being contradicted by the reference to the remote src,  So lesson learned, keep all <script src=... statments in the head so as not to entertain duplicates (then reshuffle them for distribution).  

 

My apologies, as much as I would like to share my work so far; it is so completely unimpressive that I would like to ask that if anyone is following this (and I have seen no indication that anyone actually is) to message me if they would like to see my progress on the Angular2 input form that uses the z-style-underline as a focus line with sketchy input.  

 

Summary:  I am happy to report that as evidenced in the work provided by Blake in fact GreenSock is happy to play with Angular2 thanks to Blake's fine efforts we have a very elegant pattern to follow in doing this.  The only one bit wisdom I may have been able to contribute to this is the addition of declare var TimelineMax: any; to the top of the "app/org_header_input.ts".  This may not be for every specific environment but it made my particular stack much happier.  

 

 

import { Component, ElementRef, OnInit } from 'angular2/core';

declare var TimelineMax: any;

@Component({
selector: `[z-underline]`,
 

So let me describe where I am going with this mundane little component.  

 

User will be completing a document information for an "engineering calculation worksheet"  

Project      :  My Project                            Title:  Some Really Hard Calc

Client        :  Some Client                Document:  123-456-789-AB

Reference:  Usually PO Number       Revision:  IFC1  Rev. Date: 04/11/2016

Author      :  Someone Smarter         Checker:  SRB   Chk. Date: 04/10/2016

 

The above fields will reside in an Angular2 "ControlGroup" thanks to Angular2 FormBuilder.

Each field above will be an Observable and this will allow the group to be have their visibility "subdued" when the ControGroup has focus, the specific field that ACTUALLY has focus will shift slightly up and increase in size ~5% and in general make clear that "hey I have focus".  On Blur the field would adopt the condition of it's siblings, on selected the z-style-underline will draw beneath the input field with a length equal to the limiting width of the field.  On loss of focus the line will fade out as shown in the animations. 

 

Again my apologies for the hand-waving and promises.  While this has been a time consuming activity the results are satisfying (again many thanks to Blake) and I look forward producing a novel (albeit retro) user experience, based on paper and pencil.  I will be using what I learn in may ways as I build out my application, so it is defiantly time well spent.

 

Steve

  • Like 2

Share this post


Link to post
Share on other sites

I forgot to bring up the part about the GreenSock definitions. You can declare missing stuff like you did or use the definitions from DefinitelyTyped.

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/greensock/greensock.d.ts

 

They're not 100% up-to-date, but should work for most cases. I've been promising a better version for the longest time now, but haven't been able to work on it yet as I've fallen way behind on my current work. One of these days!

 

Not recommended, but another option would be to just turn error checking off. You can do that in the typescriptOptions or by linking to a tsconfig.json file and setting noEmitOnError to false. Yeah, it's a confusing name! There might be a better way to do that, but that's the only option I'm familiar with to bypass errors.

<script>
  System.config({
    transpiler: 'typescript', 
    typescriptOptions: { emitDecoratorMetadata: true, noEmitOnError: false }, 
    packages: {'app': {defaultExtension: 'ts'}} 
  });
  System.import('app/main')
    .then(null, console.error.bind(console));
</script>

Here's a list of the compiler options you can set.

http://www.typescriptlang.org/docs/handbook/compiler-options.html

  • Like 1

Share this post


Link to post
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.