Rodrigo last won the day on March 17

Rodrigo had the most liked content!


  • Content Count

  • Joined

  • Last visited

  • Days Won


Rodrigo last won the day on March 17

Rodrigo had the most liked content!

Community Reputation

2,446 Superhero

About Rodrigo

  • Rank
    Advanced Member

Contact Methods

  • Skype

Profile Information

  • Gender
  • Location
    Santiago - Chile

Recent Profile Visitors

21,810 profile views
  1. In order to get the instance of the <li> element in the DOM you can use refs. If that's not what you're looking for, please be more specific about it. Regarding the second part I'm a bit lost. The first part is that you want to add an extra animation depending on some specific criteria for a specific card. You can use the same to store some data in an array and then return the array of JSX elements. Keep in mind that the callback inside a .map() method has to return some element that is added to an array, but before that you can run any logic you want. Then you can use a for or for each loop to create your animations and check there if the extra instance has to be created using either the original data or a new array you can create in the .map() method. Is also important to remember that the .map() method goes through an array in ascending order, that is starts with the element at index 0. Because of that, the order in which the DOM elements are added to the array that will hold their references created in React, is the same the data for each element in the original array, so you can easily use a forEach and use the index value in the callback to read the original data and avoid adding more attributes to the DOM element. // original data const originalData = []; //in the component constructor constructor (props) { super(props); this.animateCards = this.animateCards.bind(this); = []; } // in the render method render () { <div> { (card, index) => (<li ref={e =>[index] = e}>Element</li>)} </div> } // finally when creating the animations animateCards () {, index) => { // here[index] matches the data in originalData[index] // you can use originalData[index] to deicde if an extra animation is needed }); } Finally if you want to add an extra DOM element depending on the data, you should do that in the inside the render method and not somewhere else. Also base that on the original data and not some attribute passed to the rendered DOM element that results from the .map() method. Please do your best to provide some small and simplified sample code in order to get a better idea of what you're trying to do. Happy Tweening!!
  2. Rodrigo

    getChildren() on Timeline with stagger

    Well as far as I know there is no direct way to get the type from an instance, but it could be something I'm not aware of, Jack could offer a final say in this. What I can think of is the following. Single instances like TweenLite/Max don't have the .add() method while Timeline instances do, so that tells you if you're dealing with a timeline or single tween. A TweenMax instance has the yoyo property so you can check that and finally a TimelineMax has the .getLabelsArray() method, as you already know , so a way to check would be this: var checkInstance = function (instance) { if ( instance.add ) { // instance is a timeline if ( instance.getLabelsArray ) { // instance is TimelineMax } else { // instance is TimelineLite } } else { // instance is TweenLite or TweenMax if (instance.yoyo) { // instance is TweenMax } else { // instance is TweenLite } } }; Happy Tweening!!
  3. Rodrigo

    getChildren() on Timeline with stagger

    Thanks Buddy!!! I learned from the best The one option I can think, by looking at the GSAP code is extend TimelineLite prototype. Since get labels array is quite simple: And TimelineLite has a labels object just like it's Max counterpart: This shouldn't return any problem (running some simple tests doesn't create an issue): TimelineLite.prototype.getLabelsArray = TimelineMax.prototype.getLabelsArray; Unless there is something I'm not totally aware of, in which case our beloved leader and tween-guide spirit @GreenSock could warn us against this. Although this doesn't actually resolves anything as far as the original question, because still there is no way to introduce more than two labels in the main TimelineMax instance that holds the stagger methods. Unless Jack comes up with a new element in the API that allows dynamic labels in stagger methods using a base name for them and switching to TimelineMax. But IMHO it doesn't sound too useful, I'd go with the loop in order to add the animations to a TimelineMax instance.
  4. Rodrigo

    getChildren() on Timeline with stagger

    Hi, Yeah it is by design. A stagger method in a timeline returns a TimelineLite instance with a TweenLite instance for each element in the array passed to it, and since getLabelsArray is a method of the TimelineMax constructor you're getting undefined. Also keep in mind that, besides the parameters of each stagger tween passed in the stagger method, you have no further control over those instances created by these methods. If you want to place a label where each stagger animation starts, you might want to take a longer road and use a loop in order to create each individual tween and place the desired label inside a TimelineMax instance. The current code you posted, only gives you the possibility to add a label when the first stagger tween created by each stagger method starts. Beyond the fact that: console.log( children[i].getLabelsArray ); // -> undefined There is not much I can infer from that code. Perhaps you can provide a few more details in order to get a better grasp of the roadblock you stumbled in your code. Happy Tweening!!
  5. Hi, Well, there are a few ways to tackle this. The ideal react-way should be to keep track of the current card's index position in the array and check that value in order to update the component's state with the card's value, and if the updated state is bigger than 10, run the animation. Unfortunately your code is not structured like that and honestly I don't see the need to refactor everything if the only side effect of an animation update is trigger another animation and not data or DOM updates. With that in mind the solution is to mess around with scope and this, which until this day and after working in JS for so long it can come up as an obscure and difficult topic. Lucky for us GSAP does helps a lot in terms of binding and managing scope. First in the render method add an extra attribute to the DOM element created in the JSX: <li className="dataCard" key={id} ref={e => (this.listItem[id] = e)} data-value={listItem.value}> <p>ID: <span>{}</span></p> <p>Value: <span>{listItem.value}</span></p> </li> As you can see I'm passing the data-value attribute which is the value you want to check. Then in the GSAP part of your code you have to use an onComplete callback inside the configuration of the stagger method, not using the onCompleteAll callback: animateDataCards(){ = new TimelineLite({repeat: -1 }); const duration = 1; const next = 2; .staggerFromTo(this.listItem, duration, {autoAlpha: 0, y:500},{autoAlpha: 1, y:275}, next) .staggerFromTo(this.listItem, duration, {y:275}, {y:125}, next, 2.5) .staggerFromTo(this.listItem, duration, {y:125}, { y:10, onComplete: this.burgerFlip, onCompleteParams: ["{self}"] }, next, 2.5) .staggerFromTo(this.listItem, 1, {y:10},{ autoAlpha: 0, y: -250, ease: Power3.easeInOut },5, this.onCompleteAll) } Now the key here are two GSAP specific concepts. The first concept is the fact that any stagger method returns an array of GSAP instances, so each loop in the array passed to the stagger method, generates a specific TweenLite method in this case. Because of that we can attach a callback on each of those. The second, and I'm sure you already saw it, is the "{self}" string passed as the parameter for that specific callback. That tells GSAP to pass the instance as the first parameter in the callback. Then in the burger flip callback you can run this code: burgerFlip(instance){ const dataValue ="data-value"); if ( dataValue > 10 ){ TweenLite.fromTo(".burger", 3, {x: -250, autoAlpha:0, rotation: 0}, {autoAlpha:1, rotation:720, x:250}) } else { console.log("sorry no burger"); } } Here is the kicker, each GSAP instance has a target property, which is a reference of the DOM node being animated, hence in the code. Since we attached a data-value attribute to the element, we can now check that value and run our conditional logic and see if the burger will animate or not: Happy Tweening!!
  6. Rodrigo

    how avoid the auto-import vscode IntelliSense

    Indeed this is happening since the latest VSCode update and is more likely a VSCode thing and how intellisense (not too intelligent it seems? ) is working. One solution could be to define global variables in your workspace or change the settings. Much like you I've seen this behaviour when working with VSCode, lucky me, in the project I'm working right now I'm using webstorm, so I don't have to deal with this for the next weeks , but still you could start an issue in VSCode repo or look in stack overflow.
  7. I forgot, this example shows how to use GSAP with React Transition Group and a list of elements:
  8. Let me see if I can follow this through. You hide your SVG elements using CSS, then using autoAlpha you set them to be visible. Finally you want them to be hidden if you reverse the timeline or restart it. Is that right? Normally restarting the timeline should be enough, since GSAP records the starting values of the instance's targets. This over-simplified example illustrates that. The restart button restarts the timeline and the reset progress button set's the progress to zero and then plays the timeline: As for the transition between two sets of markers, yeah that's not the easiest task. Before setting the new state there are a couple of considerations. FIrst and most important, is the new set completely different from the previous or it could contain elements from the previous set? If the sets are completely different, then animate out the previous set, when that animation is complete update the state and animate in the new set. If the sets data intersects, then you'll have to filter the existing set, establish the elements that are not present in the new set. Then establish the elements in the new set that are not in the previous set. Animate out the elements in the previous set that are not in the new set, animate in the elements in the new set that are not present in the previous set. Of course in this whole process you need to update the state at the start and figure a way for the elements to be hidden when mounted. Another solution is to use React Transition Group to animate the mounting/unmounting of an element. Here you can see a sample of that: Hopefully this helps in some way. Happy Tweening!!!
  9. Rodrigo

    kill animation, am not understand.

    Hi, Indeed you need to store your GSAP instance somewhere in memory using a variable or constant declaration: const t ="#box", 1, {x: 100}); t.kill(); Or you can use kill tweens of: In order to kill any tweens that target that particular element:"#box", 1, {x: 100}); TweenLite.killTweensOf("#box"); Happy Tweening!!!
  10. Rodrigo

    GSAP Draggable Inside a React Portal - Can't Get To Work

    Allright, this was not a fun morning activity We're meeting once again with this issue: That issue stems from this particular thread in the forums: Now as you can see in this comment by Dan Abramov (from the React team) that this behaviour was change EXCEPT for portals: Adding this makes it work on your case: Draggable.create(this.dragSchedule, { type: "x", edgeResistance: 0.75, lockAxis: true, allowNativeTouchScrolling: false, dragResistance: 0.3, throwProps: true, snap: this.snapX, onClick: this.wasClicked, zIndexBoost: true, autoScroll: 1.5, dragClickables: false, bounds: window }); Why you may ask, because now the portal has the no-op handler associated to the click event so we need to counter that by doing the opposite of the previous behaviour: Still I'll summon our beloved master @GreenSock in order to see if He has something to add to this, but I believe you landed in an edge use case. Anyway, setting the dragClickables to false seems to fix the issue. Happy tweening!!
  11. Rodrigo

    shaking while animation on chrome only - please help me

    I can see some shaking on Chrome in Win7 64. This basically has to do with the fact that your page is using a lot of CPU cycles probably for a lot of calculations. There are two aspects that caught my attention. One, you have this PNG file that is transparent. Transparent PNG files, specially big ones, can be very expensive. Try without it and see how it goes. Two, you are moving this element: <div class="tl-eras-container" style="width: 22500px; transform: translate(27.3895%, 0%) matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);"> <div class="era" style="flex-basis: 2250px;"></div> <div class="era" style="flex-basis: 1750px;"></div> <div class="era" style="flex-basis: 3500px;"></div> <div class="era" style="flex-basis: 15000px;"></div> </div> That's 22500 px width, that's huge. This element is being constantly animated. Also you're animating another 22500px width element at the same time and finally you're animating a 2250px width element. All elements are being animated at the same time and that's causing a lot of calculations and repaints, and that's stressing a lot the CPU. In a smaller screen size performance is better. In terms of performance some layer updates are taking up to 35 milliseconds and the fps are dropping to 16 per second, that's definitely not good. My advice would be to try to move the card elements and not the entire wrappers/containers, especially that big, that could reduce the amount of calculations the CPU has to make. Also see if you can include either canvas or WebGL into the app, in order to improve performance. Finally, regardless of the performance issues, that is one good looking site, very appealing, intuitive, easy and fun to use, nice job!!! Happy Tweening!!
  12. Rodrigo

    Shake animation?

    Hi and welcome to the GreenSock forums. What you can do is kill any previous animation affecting the wiggle target in the button click event and then create a new tween or even more simple, create a GSAP instance outside the click handler scope and restart it on every click: const wiggleTween =, 0.5, { x: 5, ease: "myWiggle", paused: true }); myButton.addEventListener("click", function() { wiggleTween.restart(); }); As you can see in the live sample I'm using the second approach and regardless of how many times you click on the button the animation runs it's regular course, soto speak. Happy Tweening!!
  13. Rodrigo

    update variables in an animation cycles

    Hi and welcome to the GreenSock forums. Is not quite clear what exactly you want to do, but I'm guessing that you want to update the opacity values of some instances after you have created the timeline? If that's the case the recommendation is to create a function that builds the timeline and when you call that function set the values you want: var animation; var myCondition = true; function createTimeline () { animation = new TimelineMax() .to(".O",.5,{opacity: myCondition ? 0 : 1}) .from(".create-r",.5,{y:100, opacity: myCondition ? 0 : 1}); }; Also if you can, please provide a reduced sample illustrating what your issue is. Take a look at the post and video @Carl made for that purpose: Happy Tweening!!
  14. Rodrigo

    render issue tweenTo

    In that case you could try forcing he images elements to a opacity of 0 using the config object available in the .tween methods of TimelineMax. The sweet part of it is that GSAP has a killer overwrite manager that will detect any other lingering GSAP instance that affects the images, kill them and send them to garbage collection. You could try something like this: tl.tweenFromTo(t, "b", { onStart: function() {, 0.1, {opacity: 0}); } }); That will tween the opacity to 0 very quickly on all the images when the timeline playhead starts moving to the "b" label. Happy Tweening!!
  15. Rodrigo

    Did 2.1, immediateRender default behaviour changed?

    Another way is to create the timeline in reversed state: const tl = new TimelineLite().reversed(true);