Rodrigo last won the day on July 26 2016

Rodrigo had the most liked content!

Rodrigo

Moderators
  • Content count

    1,554
  • Joined

  • Last visited

  • Days Won

    148

Everything posted by Rodrigo

  1. GSAP - React staggerFrom on props.children

    Hi and welcome to the GreenSock forums. The way I normally attack this situation is using React's lifecycle methods, most specific the componentDidMount method. With that you know for sure that all the child have been rendered before making the animation. This is a sample that uses a code similar to that. Unfortunately I don't have any samples around with the specific behavior you need but hopefully you'll get the gist of it: Basically when creating each child (which in this case come as a hardcoded array, but getting the data via props shouldn't be much different) you give it a unique ref attribute to each which then you can use to loop and create the timeline or the stagger instance if you like (to create a stagger instance just reach to the array in the props and that should do it), then create the timeline and finally play it. I'll try to whip something during the afternoon that matches what you need. This is another sample but it uses a different approach, since it uses Transition Group since the elements are mounted and unmounted depending on the user interaction. It doesn't use a timeline or stagger, just a simple delay. This relies in the fact that the code is executed very fast (for larger apps you could consider server side rendering or perhaps another approach, once all the elements are rendered, perhaps pagination to render a small chunk of elements) and that the components are rendered in the sequence they exist in the app's data (again hardcoded in an array). But considering the fact that in a real app React will render all those child components at once so we can rely on that delay to create the stagger effect. Pay no attention to the code that's commented out, that's there in case someone needs to use CSS Transitions. The only catch is that the duration const used in the <Transition> component has to be the same that the one used in the GSAP instance, otherwise the component mount/unmount will be out of sync with the animation. https://codesandbox.io/s/7Lp1Q8WBA Hope this helps. Happy Tweening!!!
  2. React and GSAP

    Hi, Basically the React and React Router (RR) code came from the samples in this issue of the React Transition Group (RTG) repo, so not too much official documentation regarding this: https://github.com/reactjs/react-transition-group/issues/136 RR basically relies on CSS Transitions mainly and that's kind of the official "way to go" in terms of animating route changes. Also you have to keep in mind that the code also has to accommodate for some problems regarding RR, mentioned in this issues: https://github.com/ReactTraining/react-router/issues/5039 https://github.com/ReactTraining/history/issues/470#issuecomment-345422719 The rest comes from the API of RTG. It might seem a bit daunting at first, but the code is not that complicated actually. What part is giving you trouble?
  3. React and GSAP

    @axe-z I haven't played too much with React 16 and GSAP yet but it seems that it hasn't change that much. With that in mind this samples use React 15, Transition group 2.2.0 (latest is 2.2.1) and React Router 4.1.2 (latest 4.2.0) so they should come in handy in order to get you started. Simple component transition using GSAP https://codesandbox.io/s/yvYE9NNW Using React Router to animate the mounting and unmounting of the components: https://codesandbox.io/s/mQy3mMznn Happy Tweening!!
  4. Using TimelineLite with React and Child Components

    Hi, The thing is that the `onComplete` callback is being used to mount/unmount the component from the App and the DOM. He's using React Transition Group, which is heavily inspired from Angular's ng-animate (at least the old version of ng-animate when you had to pass a callback to onComplete in order to keep track of things), and honestly my personal opinion is that for a simple mount/unmount toggle He's over-complicating things, because I don't think is absolutely necessary to use the component's lifecycle methods in the animations, react transition group does that for you, but everyone has it's own ways so if it's working for Him, that's great!!. Here are two samples of using GSAP with React and Transition Group. This is a simple component toggle, the component gets animated and when the out animation is complete it's unmounted, when the in animation starts is mounted: https://codesandbox.io/s/yvYE9NNW As you can see the `<Transition>` element is just a high order component that adds some features to the regular component using the `addEndListener` attribute. This sample is a todo list using the same set up. Never mind the code that's commented out, I keep that in case someone needs to use... [sigh] CSS transitions (sorry for using the forbidden language in the forums :D): https://codesandbox.io/s/7Lp1Q8WBA Hope this helps. Happy Tweening!!!
  5. GSAP and react

    @Carl, @PointC, you guys always know how to put a smile in my face. Is great to feel welcome everytime I pop in the forums. @thomas159, since you want to do a one time stagger the best choice (that I can think of at least) would be to create a timeline in the `componentDidMount` method and add each instance looping through the same array used to add the elements in the DOM. The only caveat is that you need a reusable property in each element of the array for the reference, which in the case of your sample could be the name property of each element. Here's a very simple example: Happy Tweening!!
  6. GSAP and react

    If you're using an array with the data you'll use as a reference, then there's no need to use an anonymous function in the ref attribute, just pass the property of the element being used in the map helper: const data = [ {id:1, name: 'box1'}, {id:2, name:'box2'} ] data.map( (item, index) => className={styles.box} key={`box${index}`} ref={item.name}; ); Then reference the element following the same pattern: tl.to(this.refs.box1, 0.5, { backgroundColor:"#F19939" }); Keep in mind that the GSAP instance must be created inside the component's that has the node element. Here's a simple example made in codepen. Is not a lot of code so it should be easy to follow: Happy tweening!!
  7. GSAP and react

    Hi, Basically the ref attribute in React, points to the node element being created and then added to the DOM. When you use a function in the ref attribute, the parameter passed by react is the DOM node being created. Now the problem with that code when used in a map array helper, is that is adding a reference to that specific node in the react component. So every time the map helper runs the reference to this.name is updated to that last element. Therefore when the array mapping is complete, the reference in the component is only the last element. render(){ return( '<div ref={ (node)=>{console.log(node)} }> </div>' ); } //the console will return the <div></div> tag This is perhaps one of the sore spots of animating mapped collections with react, how can we reference all the elements created in the map helper. The main question here is, what type of animation you're trying to create?. If you want to do a one time stagger, then perhaps you could create an array and use the map callback in order to push each node element and do the tagger. If you want to access each element independently, then you should give a unique name to each one in the ref in order to reach them when necessary. Right now I'd suggest that you post back with the type of animation you need and we can take it from there. Best, Rodrigo.
  8. Accordion with dynamic height according to content inside

    Hi, This is a very simple concept I made some time ago for a wordpress site: The main thing to keep in mind is to kill any existing tween and create new ones after getting the new height of the element after the resize event. Is worth noticing that the animations are reeeeeeaaaally slow in order to test the code responsiveness, but you could use any GSAP instance you want. Also it could use some work in order to avoid looping through all the elements and do it just for the active ones. Is not precisely what you're doing but hopefully will help you get started. Happy tweening!!
  9. Photo Cube Animation

    Hi Anthony, Looks nice!!! Perhaps this could be useful to tween the timescale back to 0 when hovering over the cube and using an onComplete callback to snap the cube to the current face:
  10. Photo Cube Animation

    Hey Anthony, the delayed call was just a sample of using GSAP and modifying other state properties while the animation (delayed call) is working, nothing more. I agree with you that it has no use in your App . I also agree that using the react gsap enhancer shouldn't offer any upside in this particular scenario. As for configuring eslint globals, why don't you declare them in the .eslintrc.json file? { "env": {}, "parserOptions": {}, "globals": { "PIXI": true, "TweenLite": true, "TweenMax": true, "TimelineLite": true, "TimelineMax": true, "Elastic": true, "stripes": true, "axios":true }, "rules": {} } I always use that when working with eslint. Happy Tweening!!
  11. Photo Cube Animation

    Sweet demo Anthony!!! always good to see you coming back with awesome stuff!! For performance I would try to avoid using the elastic easing on all the thumbnails when clicking on the expanded image, I would go with a regular easeOut function, perhaps Power2 and use the elastic on the expanded being scaled down. For using react create app, I can't help you. I've baked my own start packages for working with react, angular, vue, etc. so I never use those tools. Also I've never been a big fan of this bundling madness that has taken over front end development, so even today sometimes I keep GSAP outside the bundled files. This is particularly useful when you end up with a bundled file over 1MB because you can create a pre-loader with GSAP. I'm sure Blake can give you some pointers in this regard. I see you're using timescale to speed up/down the animation using the pointer position. But also I saw this: TweenMax.to(this.timeline, currentFace.progressRemaining / 2, { time: this.timeline.getLabelTime(currentFace.id.toString()), ease: 'Back.easeOut', }); Why don't you create one TweenMax instance to rotate to each side, just like the one you already have, using relative values and a repeat:-1 with linearEaseNone in order to create an endless loop, or you can use the modifiers plugin as well, and based on the pointer position update the timescale between 0 and 1 like that you avoid code like the one above and keep it more simple. You can even put those GSAP instances in your component's state or even a redux store and just reference them. Finally I don't know how the GSAP instances could be messing with the App's state. As a rule of thumb, I try to avoid GSAP updating any property of the app's state that could mean a re-rendering that ultimately will affect the instance. If the GSAP instance will update something in the state, is vital that nothing else does because GSAP won't know about that and will keep going with the stored values, unless you reset and create the instance again. For example if a Tween is changing the X position of an object and is not entirely necessary to store that value in the state then don't, in order to avoid something that could mess that up. In your sample I can't see if the GSAP instance is updating anything from the state, so I'd need for you to tell me that. This is very simple examples of some things I made with react some time ago: In this basically GSAP just animates the DOM element and doesn't even know about the app's state. This is using a delayed call and the Tween updates a specific part of the state that nothing else can update. Finally with the button you can change another state property. Finally this is using the modifiers plugin: Hope that this helps. Best, Rodrigo.
  12. MonkeyPatching Tweens/Timelines for automated testing

    Yep, as I said I'm not convinced that my answer is what the issue is about. just never did a lot of unit test or end-to-end on gsap instances and the end values of the properties they affect, mostly checked that the instance was created by checking some specific properties. Also I haven't done a lot of testing on virtual DOM, mostly browser or Node, so I was attracted to the thread because of that. I've never used a lot of testing on the values because of my blind faith in GSAP, I just create the instances and I know that id something is not working is because I blew it at some point. I posted that answer with the hope that the phrase:"Sometimes the simplest solution is the best solution" could become true in it I'll keep waiting on @UncommonDave's posts to see how it develops. Happy Tweening!!
  13. MonkeyPatching Tweens/Timelines for automated testing

    Hi, Couldn't help to pinch in with a simple suggestion, and perhaps I'm overlooking the real issue in question. If I am please correct me and excuse me for not understanding the conversation. Is the problem that you need to run the tweens in order to check for callbacks and the elements' position?. What I think I understand for your posts is that, your test suite is taking far too long by waiting for a, let's say 5 seconds tween to be completed to check that everything actually happened. If that's the case why don't you use either seek(), or progress(), or time() to advance your GSAP instances to the end and check the values and callbacks. All those methods suppress callbacks by default, but you can pass a second parameter to trigger the callbacks between the current and final positions. You can do that at runtime after defining your instances or even at a specific moment or event of your code: var t = TweenLite.to(e, 1, {x:100, onStart:startCallback, onComplete:completeCallback}); // then move the playhead to the end triggering all the callbacks t.progress(1, false); // using time t.time(t.duration(), false); // using seek t.seek(t.duration(), false); Again, sorry if I'm misunderstanding the problem, if so... sorry. Happy Tweening!!
  14. TimelineMax/attrPlugin not working with React

    Bingo!!!, that's the key to understand it. As always @OSUblake has the nail locked and He hits it in the head!!! @GreenSock, well, this is kind of tricky. First when working with React data is normally passed either as a JSON file or in object notation. So normally elements that share something in common (such as a specific class) are stored in arrays: const els = [ {name: "Jack", ocupation:"Master of GSAP"}, {name: "Carl", ocupation:"Geek Ambassador"}, {name: "Blake", ocupation:"Superstar Moderator and JS wikipedia"}, {name: "Jonathan", ocupation:"Superstar Moderator and Browser-Quirks reference"}, {name: "PointC", ocupation:"Superstar Moderator and SVG Mastermind"} ]; When adding this to the virtual DOM you can use the map array helper: render(){ <div className="staff-wrapper"> {els.map((element, index)=>{ return <div className="staff-card" ref={element.name}></div>; });} </div> } Now when it come to select them all, normally we use querySelectorAll or getElementsByClassName. I'm not very familiar with the specs of this methods, but I can assume that they involve some traversing the DOM tree looking for elements that match the argument. In this case we're setting the ref name for every element by hand, so we have full control over that aspect of our code, so we can loop trough our collection again, matching the ref name using a for or forEach loop, or even using the map method to get a new array: // to create a single animation for each element els.forEach((e,i)=>{ TweenLite.to(e, 1, {rotation:360}); }); // to create a stagger animation const targets = els.map((e,i)=>{ this.refs[e.name]; }); TweenMax.staggerTo(targets, 1, {rotation:360}, 0.1); Here are a couple of samples of a marquee I made for a React app using the modifiers plugin, this is just a simple prototype because I'm bound by some silly NDA for the complete code . This is just React and CSS: And this uses PIXI, just an experiment to see if there was a better performance, since the real thing uses images and text: Well, that's about it, hopefully this helps to make things clear about this and other questions regarding React. Last but not least, @Carl, thanks buddy, is always a pleasure to come back home. Things are going pretty well, still not having a lot of free time but hopefully at some point I'll be back full-time. It certainly feels good when I post an answer or a thread and everyone welcomes me, I feel like Norm in Cheers Happy Tweening!!!
  15. TimelineMax/attrPlugin not working with React

    Hi, I was passing by to se the new features in the forums and ran into this post and I thought I'd offer some tips about using GSAP and React. First the following is a big NO-NO: Never use regular selectors while working with React. This because the component could get an update later and re-render. In this case the id(s) could change or even a DOM node with a specific ID could not be render again, then you get the can't tween a null target error. This goes to master Doyle as well, but we'll forgive his sins because He has given us GSAP . To get a specific element just use this.refs, that points to the node being rendered in the DOM. Second, you added almost 300 lines of SVG code on the component's render method, try to avoid this in order to keep your components small, clean, easy to read/debug/maintain and reusable, which are the cornerstone of component-based development, not only with React, but also with Angular2/4+, Vue, etc. If you can break your svg into smaller component it'll be very easy, remember: "Divide and Conquer" Finally is not necessary to use the bracket notation on JSX. Keep in mind that the component's reference is an object, so you can pass an string to it and React will look for that ref attribute on the code and pass whatever string to the object: render(){ return <div ref="myDiv"></div>; } // Then React does this (this is very simplified of course component.refs["myDiv"] = nodeObject; // So you can access your node this.refs.myDiv; So a real GSAP code could be like this: componentDidMount(){ const target = this.refs.targetGroup; TweenLite.to(target, 1, {}); } render(){ return( <svg xmlns="http://www.w3.org/2000/svg" id="svg2" version="1.1" viewBox="0 -10 573 367" height="367px" width="573px"> <g ref='targetGroup'> // svg code or component here </g> </svg> ); } As for the attribute plugin part, Jack has that already working so no need to go into that. Happy Tweening!!
  16. Detect reverse start event

    Hi, In the case of TweenMax/TimelineMax instances, yoyo does not acts as reverse(), the yoyo feature basically alters the direction of the repeat feature. From the docs: yoyo : Boolean - If true, every other repeat cycle will run in the opposite direction so that the tween appears to go back and forth (forward then backward). This has no affect on the "reversed" property though. So if repeat is 2 and yoyo isfalse, it will look like: start - 1 - 2 - 3 - 1 - 2 - 3 - 1 - 2 - 3 - end. But if yoyo is true, it will look like: start - 1 - 2 - 3 - 3 - 2 - 1 - 1 - 2 - 3 - end. What I can suggest is to detect the direction of the instance or the progress value inside a function and use that on the onRepeat callback: // at startup the direction of an instance is forward // THIS IS NOT RELATED TO THE REVERSED STATUS var forward = true; function cBack(){ forward = !forward; if( !forward) { // the instance is repeating from the end to the start } else { // the instance is repeating from the start to the end } } TweenMax.to(el, 1, {vars, onRepeat:cBack}); Codepen sample: http://codepen.io/rhernando/pen/WRvVqN?editors=0010 Hopefully this makes things a bit more clear. Happy Tweening!!
  17. Run sequence of animations on keypress

    Hi Nate, The issue here could be resolved using TimelineMax, labels and the tweenTo and tweenFromTo methods. http://greensock.com/docs/#/HTML5/Sequencing/TimelineMax/tweenTo/ http://greensock.com/docs/#/HTML5/Sequencing/TimelineMax/tweenFromTo/ Also it could be solved using just labels and the play and reverse methods using the labels as starting points: var tl = new TimelineLite({paused:true}); tl .to(element, 1, {vars}, "label_1") .to(element, 1, {vars}, "label_2") .to(element, 1, {vars}, "label_3") .to(element, 1, {vars}, "label_4"); // then on the click/key events function eventHandler(label, direction){ switch (direction) { case "forward": tl.play(label); // plays the timeline from the specific label break; case "back": tl.reverse(label); // reverses the timeline from the specific label } } // then calling the function eventHandler(forward, "label_2");// plays from label_2 Unfortunately I don't have time to create a working sample of this. Hopefully this is enough to get you started.
  18. getParent method?

    Hi, Since getChildren() returns an array you can do a simple indexOf() in order to check if the instance is in the parent timeline already: var master = new TimelineMax({paused:true}), child1 = new TimelineMax({paused:true}), child2 = new TimelineMax({paused:true}), child3 = new TimelineMax({paused:true}), children; master .add(child1, 1) .add(child2, 2); // get childs children = master.getChildren(); console.log( children.indexOf(child1) );// return 0 console.log( children.indexOf(child2) );// return 1 console.log( children.indexOf(child3) );// return -1 doesn't exists in the array https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
  19. Draggable selection highlight trouble

    Hi Kevin, This is not a GSAP issue, but an HTML thing. Looking in google I found these stack overflow posts: http://stackoverflow.com/questions/9620122/stop-html-text-being-highlighted http://stackoverflow.com/questions/3779534/how-do-i-disable-text-selection-with-css-or-javascript The second one should work with the onDragStart method, you could attach the event handler and then remove it if you want, otherwise you can run a loop through all the elements you don't want highlighted and leave it like this. Although the first option would be the one of my choice, using a IE9 and older conditional to use the JS code: http://caniuse.com/#feat=user-select-none Please let us know how it goes, this will be helpful for other users. Happy Tweening!!
  20. Understanding overwrite:all

    Hi, Nice sample, works really well. Glad that you were able to figure it out. By now you're getting into the GSAP way (since today there's a way for absolutely everything, why not GSAP, right? ) and how things work under the hood. From now on, things will get simpler and easier for you, trust me. Great job and happy tweening!!
  21. adding controller class to control playback example

    No problemo. Again, sorry it took us this long to answer. Happy Tweening!!
  22. adding controller class to control playback example

    Hi, It's working for me when I declare the GSAP instance before the wheelnav. Keep in mind that JS reads the entire code before it's executed, saving variables into memory to access them later. Perhaps the issue comes when clicking on the text element of the pie-nav?. I see that it has no effect whatsoever, perhaps the developers didn't consider event handlers in the text or tspan tags. But clicking on the green part (the path tag) always triggers the function regardless of where you declare the GSAP instances. If you remove the text you'll see that it works: <div id='piemenu' data-wheelnav data-wheelnav-slicepath='DonutSlice' data-wheelnav-marker data-wheelnav-markerpath='PieLineMarker' data-wheelnav-rotateoff data-wheelnav-navangle='270' data-wheelnav-cssmode data-wheelnav-init> <div data-wheelnav-navitemtext=' '></div> <div data-wheelnav-navitemtext=' '></div> <div data-wheelnav-navitemtext=' '></div> </div> Also a good way to avoid such issues is to use an immediately invoked function expression (IIFE), like that you can be completely sure that everything will be read before being executed and avoid any possible conflicts. When working with jQuery I use the following: (function($){$(function(){ var animlogo = $("#animlogo"), tween = TweenLite.to(animlogo, 6, {left:"90%", ease:Linear.easeNone}); // declare wheelnav var piemenu = new wheelnav('piemenu'); piemenu.clockwise = false; piemenu.wheelRadius = piemenu.wheelRadius * 0.83; piemenu.createWheel(); piemenu.navItems[0].navSlice.mouseup(function () { //alert('PLAY'); tween.play(); }); piemenu.navItems[1].navSlice.mouseup(function () { //alert('PAUSE'); tween.pause(); }); piemenu.navItems[2].navSlice.mouseup(function () { //('RESET'); tween.restart(); }); });}(jQuery)); That basically covers everything, avoids conflicts and has the document.ready as well. Give that a try and let us know.
  23. adding controller class to control playback example

    Hi and sorry for the late response There are a few things throwing errors in your codepen sample. First you didn't include the GSAP files and also is this code right here: // navigation UI var piemenu = new wheelnav('piemenu'); piemenu.clockwise = false; piemenu.wheelRadius = piemenu.wheelRadius * 0.83; piemenu.createWheel(); The class wheelnav is not defined or included anywhere, so it throws an error. Also the target id does exists but there's no style definition for it so is basically a div with 0px of width and height, and doesn't have a background color neither. Use this css on the codepen and you should see it: #animlogo { width: 50px; height: 50px; background: blue; position:relative; } Finally comment out or remove the wheelnav code and the codepen should work. Then you can add the controller code from the GreenSock collection's codepen. Let us know if you have more questions. Happy Tweening!!
  24. Passing variable into timeline via play?

    Well if you want to delay the start of the entire timeline and not just a few tweens in it, you could use shiftChildren(), although after you used it you'll have to remove that time if te user clicks on the button to play it immediately. Another option is to create a function and pass a time parameter and use a delayed call to start the timeline: var tl = new TimelineLite(); function startTl(delay){ TweenLite.delayedCall(delay, function(){tl.play();}); } And with the other button just use tl.play()
  25. Passing variable into timeline via play?

    Hi, Without seeing a live sample I would go with shiftChildren(). All you need to know is where the first instance you want to change sits on the timeline, in order to affect the start time of all the instances from that point until the end of the timeline. http://greensock.com/docs/#/HTML5/GSAP/TimelineLite/shiftChildren/ There could be some other ways to do this, such as using a function to create and populate the timeline and passing a value to change the delay of the specific instances. Also is important to know if all your tweens are in straight sequence or if there's some overlaping or staggering between them. As you can see we could keep discussing about different ways to do this, so if you could provide a reduce live sample that is as closest as possible to your real app, it would be great.