Jump to content

Rodrigo last won the day on March 17 2019

Rodrigo had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Rodrigo

  1. Hi, React yes, but React with typescript is out of my range, since I don't use typescript. I made this sample and it seems to work, at least on stackblitz: https://stackblitz.com/edit/gsap-react-typescript But I see some errors being displayed there, probably because of something I'm not doing correctly typescript-wise. I'll summon @OSUblake, our resident typescript wizard and see if we can get an explanation and a cool, mind-blowing/jaw-dropping example Happy Tweening!!
  2. Hi, Again, the timeline constructors don't work in the same way the single instance constructors, so this is not going to work: var close= new TimelineMax("[.intro", ".foto", ".rules"], 1, { opacity: 0, display: "none", }); If you want to animate all the elements at the same time in a timeline create the timeline and then add the individual instance to it. Remember Timelines are mere containers of single instances, nothing more: var close= new TimelineMax(); close.to("[.intro", ".foto", ".rules"], 1, { opacity: 0, display: "none", }); See that? the .to() method is basically creating a single animation instance inside the timeline instance. If you want to play the close timeline at some point during the execution of the tlOpen timeline, there is no need to actually create a new timeline, you can add a new instance in the tlOpen timeline including all the elements: var tlOpen = new TimelineMax(); tlOpen .to(".one", 0.2, { opacity: 0 display: "none", delay: 1 }) // instead of creating a new timeline add a new instance here .to([".intro", ".foto", ".rules"], 1, { opacity: 0, display: "none", }) .to(".tres", .1, { opacity: 0 display: "none", delay: 3 }); Also remember that display can't be animated so that is not going to animate, instead use autoAlpha. Finally two things. First, please make an effort to go through the documentation, videos and examples in order to better understand how GSAP works. Granted it can be a little challenging at first but if you follow the resources @Carl and @GreenSock (Jack) have made, you'll find yourself mastering GSAP in a short time. Also please try to make a reduced codepen sample in order to see the issue in real-editable code. Second, even though I don't have problems reading spanish (being my native language, of course ) the official language in the forums is english. Of course if you find in a position where you can't explain yourself in english using spanish is understandable, but please do make the effort. Is not for just wanting everyone to speak the same language, is because maybe another user could have a similar issue at some point and having everything in the same language would make it easier for that future user. Happy Tweening!!
  3. Hi, Unfortunately SVG is not my strongest suit, but I managed to make something like that with just HTML markup and is also responsive using Bootstrap: As you can see my approach is to record the size and position of each fret on init. Store the chords data in an object and then when the chord is selected use the frets data to position the dots. Hopefully this helps you get things going. Happy Tweening!!
  4. Rodrigo

    circle rotation

    I'm not sure if I understood correctly but does this comes close to what you want? In the SVG code change the initial position of each circle by changing their cx and cy attributes: <svg class="loader_dots" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" xml:space="preserve"> <circle cx="0" cy="0" r="0" fill="#000" stroke-width="1" class="load_animation_1"></circle> <circle cx="1000" cy="500" r="0" fill="#000" stroke-width="1" class="load_animation_2"></circle> <circle cx="500" cy="1000" r="0" fill="#000" stroke-width="1" class="load_animation_3"></circle> </svg> Then in your GSAP code: tl .to( '.loader_rotate' , 3, { rotation: 360, ease: Power0.easeNone, repeat: -1 }) .staggerTo('.load_dot', .5, {scale: 1, ease: Power0.easeNone}, 0.3) .to('.load_animation_1', .5, { fill:"#fff", scale:1.5, attr: { cx: 500, cy: 500, r: 350 } }) .to('.load_animation_2', .5, { fill:"#fff", scale:1.5, transformOrigin: '200px 200px', attr: { cx: 550, cy: 500, r: 200 } }, "-=0.15") .to('.load_animation_3', .5, { fill:"#fff", scale:1.5, attr: { cx: 500, cy: 400, r: 200 } }, "-=0.15") .to(loader, 0.5, {zIndex:"-10", opacity: 0}) .call(function(){ tl.stop(); }); That seems to do what you're looking for. Happy Tweening!!
  5. Hi and welcome to the GreenSock forums. I'm not entirely sure of what you're trying to do, so I'll cover as many scenarios as possible. First, a timeline constructor accepts an object for specific configurations, not a list of selectors each wrapped in an array: var tl = new TimelineMax({ /*configurations here*/ }); You can read more about them here: https://greensock.com/docs/TimelineLite https://greensock.com/docs/TimelineMax And watch this video from professor @Carl: Second, even though GSAP is capable of tweening any numeric property in an object, which means a GSAP instance can tween the value of a property of another GSAP instance, I believe that is not the particular result you're after with this: TweenMax.from(close, 1, { display: 'none', delay: 0.5 }) It seems that you want to animate a group of elements from display: none, you can pass a single array with all the selectors in it, directly to the GSAP instance: TweenMax.from([".intro", ".photo", ".rules"], 1, { display: none, delay: 0.5 }); Finally display is not an animatable property, what you can do is animate autoAlpha, which is a combination of opacity and visibility that can serve you well. Here is a simple example illustrating how to do it: https://codepen.io/rhernando/pen/YBRYKN Hopefully this clear things a little bit. Happy Tweening!!
  6. Hi and welcome to the GreenScok forums. After reviewing your file, we have some advice to you as it seems you're not very familiar with some key-core concepts about GSAP. First and most important in order to simplify and speed up the support process, we advise users that they create a reduced sample in codepen that illustrates the issue they are having. To learn how to do that please look at this post and video from @Carl Second, among many amazing tools, GSAP has the CSS Plugin, that takes cares of any non-experimental CSS property you want to animate in a DOM element. Having said that, in your file we could spot quite a few of these: var tween = TweenMax.to(sec, 1, {transform: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 421.8, 1010.15, 0, 1)'}); var tween2 = TweenMax.to(sec, 1, {transform: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1004.58, 1011.1, 0, 1)'}); var tween3 = TweenMax.to(sec, 3, {transform: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1008.7, 3100, 0, 1)'}); Now for what I see mostly you're applying a 2D translate in these cases. Well GSAP has you covered, all you need is to pass x and y values to it: var tween = TweenMax.to(sec, 1, {x: 421.8, y: 1010.15}); var tween2 = TweenMax.to(sec, 1, {x: 1004.58, y: 1011.1}); var tween3 = TweenMax.to(sec, 3, {x: 1008.7, y: 3100}); Quite simpler and cleaner, right? If your concern is passing the animation to the GPU, no worries, when animating any type of transform property, GSAP uses a transform matrix for you, so it gets rendered by the GPU on it's own layer. You can read more about the CSS Plugin here: https://greensock.com/docs/Plugins/CSSPlugin The final issue is applying more than one GSAP instance on the same element and the same properties at the same time. When that GSAP overwrite manager will kill any pre-existing tween and apply the new one. In your case it kind of works like this: You create tween, the instance read the start and end values, and then starts to apply the updates to the css styles. A few milliseconds later you create tween2, GSAP sees that the target is already being animated and the properties are the same, it kills the existing tween, records the start and end values and start applying the updates to the css styles. A few milliseconds later you create tween3, same as #2. If you want to concatenate a series of animations during time, my advice is to create a timeline. Here is an extract from the docs, regarding overwrite: overwrite: String (or integer) - Controls how (and if) other tweens of the same target are overwritten. There are several modes to choose from, but "auto" is the default (although you can change the default mode using theTweenLite.defaultOverwrite property): "none" (0) (or false) - no overwriting will occur. "all" (1) (or true) - immediately overwrites all existing tweens of the same target even if they haven't started yet or don't have conflicting properties. "auto" (2) - when the tween renders for the first time, it will analyze tweens of the same target that are currently active/running and only overwrite individual tweening properties that overlap/conflict. Tweens that haven't begun yet are ignored. For example, if another active tween is found that is tweening 3 properties, only 1 of which it shares in common with the new tween, the other 2 properties will be left alone. Only the conflicting property gets overwritten/killed. This is the default mode and typically the most intuitive for developers. "concurrent" (3) - when the tween renders for the first time, it kills only the active (in-progress) tweens of the same target regardless of whether or not they contain conflicting properties. Like a mix of "all" and "auto". Good for situations where you only want one tween controlling the target at a time. "allOnStart" (4) - Identical to "all" but waits to run the overwrite logic until the tween begins (after any delay). Kills tweens of the same target even if they don't contain conflicting properties or haven't started yet. "preexisting" (5) - when the tween renders for the first time, it kills only the tweens of the same target that existed BEFORE this tween was created regardless of their scheduled start times. So, for example, if you create a tween with a delay of 10 and then a tween with a delay of 1 and then a tween with a delay of 2 (all of the same target), the 2nd tween would overwrite the first but not the second even though scheduling might seem to dictate otherwise. "preexisting" only cares about the order in which the instances were actually created. This can be useful when the order in which your code runs plays a critical role. Remember, please do your best to create a reduced case sample so we can take a better look at it and that illustrates what you're trying to achieve. Happy Tweening!!
  7. Rodrigo

    circle rotation

    I'm sorry but I don't think I'm completely following you. What type of scale animation you're looking for, a circle that animates from the edge? I'm not sure I understand what you mean. Could you please set a simple example of what you're trying to do, or explain in an explicit fashion which element you want to animate from what position to another?
  8. Rodrigo

    circle rotation

    Ok so I spotted a few things that really don't add up in your code. To begin you have this: var loader = $(".preloader"), tl = new TimelineMax(loader); tl .to( '.loader_rotate' , 3, { rotation: 360, ease: Power0.easeNone, repeat: -1 }) .to(loader, 0.5, {zIndex:"-10", opacity: 0}) t1.stop(); A timeline constructor accepts a configuration object and while a jQuery selector returns an object, is not really the type of object the constructor is expecting. Then you have chained the to() methods and then you add t1.stop(). First t1 is not defined so I'll assume that it refers to tl. This is exactly a good use for the config object I was talking before, if you want the timeline to stay put until a specific point in your code or perhaps an event, in this case most likely a page transition: var loader = $(".preloader"), tl = new TimelineMax(); tl .to( '.loader_rotate' , 3, { rotation: 360, ease: Power0.easeNone, repeat: -1 }) .to(loader, 0.5, {zIndex:"-10", opacity: 0}); Then you have some jQuery transitions there in the barba configuration. IMO if you're already using GSAP no need for that there. Also you create a different timeline in this part of your code: Barba.Pjax.getTransition = function() { $(".preloader").removeAttr("style"); var loader = $(".preloader"), tl = new TimelineMax(loader); tl.to( '.loader_rotate' , 3, { rotation: 360, ease: Power0.easeNone, repeat: -1 }) .to(loader, 0.5, {zIndex:"-10", opacity: 0}); return FadeTransition; }; Again there are a few issues here, you're removing the style attr in the DOM node you're animating. If you want to remove all the styles applied by GSAP use clear props. Then you're creating a brand new timeline, identical to the one you already created, you should re-use that. Finally if you want to stop the animation after the the fade out part of the code, that is the tween that sets the opacity to 0 you can use a .call() method to stop the animation: var loader = $(".preloader"), tl = new TimelineMax(); // no need for configuration here tl .to( '.loader_rotate' , 3, { rotation: 360, ease: Power0.easeNone, repeat: -1 }) .to(loader, 0.5, {zIndex:"-10", opacity: 0}) .call(function(){ tl.stop(); }); And when you want to start the timeline again just call tl.restart() and that should do it, like that there's no need for two different timelines here. Happy Tweening!!
  9. Hi, Well since your markers are in fact SVG circle elements, those are actually the DOM nodes themselves, so you can animate those directly. In the class constructor add this: constructor() { // your orther code in the constructor here this.markers = []; } In the render function you should do this: <Markers> {data.map((marker, index) => ( <Marker marker={marker}> <circle className="animateMapMarker" cx={0} cy={0} r={8} fill="#FF5722" stroke="#FFF" ref={e => this.markers[index] = e} /> <text y={25} style={{ fontFamily: "Roboto"}} textAnchor="middle"> {marker.place} </text> </Marker> ))} </Markers> And finally in the component did mount method: this.tl = new TimelineMax({ //paused: true, onUpdate: this.updateSlider }) .staggerFrom(this.markers, 5, {autoAlpha: 1, ease: Elastic.easOut, scale: 5, yoyo: true, repeat:1}, next); Also a couple of things to keep in mind. You mention that with hard coded data everything works but with the actual server response there are no animations. It sounds very reasonable because passing hardcoded data as props, makes is immediately available. But when the data comes as a response from the server the component has already mounted and the props update only triggers a re-render of the component. The timeline resides in the component did mount event, that triggers only once in the component's life cycle. Perhaps you should use component did update, compare the list of markers and if they are not equal, pause and then kill the timeline, and finally create it again with the updated array. Just be aware of not passing empty arrays because you'll waste time and resources. GSAP is not going to throw an error, because is not going to care about an empty array, but is a waste of CPU cycles. Finally, for drawing the line between the dots you could use the Draw SVG Plugin for that. To center the globe in the dot when each animation starts, perhaps instead of using the stagger method, you could use a call() instance followed by a from() instance for each dot. That would require to loop through the markers array in the did mount or did update method. Happy Tweening!!
  10. Hi, I need more specific information about this. What exactly are you trying to animate? Then in your code I see this: .staggerFrom("animateMapMarker", 5, {autoAlpha: 1, ease: Elastic.easOut, scale: 5, yoyo: true, repeat:1}, next); Here you're passing a string and not an array, nor a selector that GSAP can work with, if you change that it kind of works: .staggerFrom(".animateMapMarker", 5, {autoAlpha: 1, ease: Elastic.easOut, scale: 5, yoyo: true, repeat:1}, next); Now for the looks of it, you're stumbling upon something you just can't control. You're using a third party component and you need to reach the DOM nodes created by that component. For security reasons that normally is not possible unless the component's creator adds something to the component's API that allows users to set a reference to the DOM nodes. Right now you're using a class selector for that and, while it works, as you mentioned is not the best practice. My advice is this: contact the component's creator to see if there is a way to actually achieve that or fork the component and bake your own solution to reach the DOM nodes. If neither one of those alternatives is viable, then I'd suggest to write some code, perhaps a method in order to check if the selected elements are actually present in the DOM and to update both the selection array and the timeline instance, if the DOM is updated from either the server or a user interaction. Happy Tweening!!
  11. Hi, Chris' magic comes from this two instances: TweenMax.to(this.liquidFollower, 1, { x:'+=0', repeat:-1, modifiers:{ x: (x, target) => { liquidFollowerY += (this.dragger._gsTransform.x - this.liquidFollower._gsTransform.x) * 0.98; liquidFollowerY *= 0.97; return this.follower._gsTransform.x + liquidFollowerY; } } }) TweenMax.to(this.boxFill, 1, { rotation:'+=0', repeat:-1, ease: Linear.easeNone, modifiers:{ rotation:(rotation, target) => { return (rotation+liquidFollowerY*0.35) } } }) Basically He's using the modifiers plugin to track the difference between the x position of the dragger and a liquidFollower, all dummy elements: <circle class="follower" cx="0" cy="0" r="0" fill="green" fill-opacity="1" stroke="#FFFCF9" stroke-width="0"/> <circle class="liquidFollower" cx="0" cy="50" r="0" fill="red" fill-opacity="1" stroke="#FFFCF9" stroke-width="0"/> <circle class="dragger" cx="50" cy="305" r="100" fill="#62B6CB" fill-opacity="0" stroke="#FFFCF9" stroke-width="0"/> If you play with those values (0.98, 0.97 and 0.35) you'll see how they are working in the code. So the bigger the distance between them when the user drags, bigger the motion in the bottle fill. The funny thing is that Chris is using the ThrowProps plugin, so He could have easily plugged the Velocity Tracker to it, but hey is working fantastic anyways, right? Happy Tweening!!
  12. Rodrigo

    circle rotation

    In order to add to Shaun's great advice you could also use a bezier tween to achieve that: But be aware that the bezier solution is not responsive, since you would have to re-calculate every time a screen size change causes a position or dimension change in the element the circle is orbiting around. Shaun's solution is completely responsive though, so keep that in mind. Happy Tweening!!
  13. Rodrigo

    walk animation

    Hi Martin and welcome to the GreenSock forums. It is possible but not the easiest thing to do, not the hardest neither, so don't be discouraged. One of our superstars @Diaco came up with this sweet walking SVG animation: Is worth noticing though that His setup is far more complex than yours, so achieving something similar should come easier in your case. Unfortunately I'm far from being a Morph SVG expert (in fact I've never used that particular plugin in production just some simple tests), so I can't give you any specific directions on the subject, but start simple, first create a tween that flex the leg in one direction, then in the opposite direction and so on. Hopefully Diaco's pen will be enough to get you started. Happy Tweening!!
  14. Hi and welcome to the GreenSock forums. Yeah that's quite weird actually. I'll summon our beloved master @GreenSock so He can take a look at this. Please stand by a bit...
  15. Hi and welcome to the GreenSock forums. Without a live sample and by looking to the code you posted, all I can see is that you are using the onCompleteParams to pass the method you want to be called when the animation is completed. You need to use onComplete and pass the function's name or variable holding an anonymous function: window.onload = function(){ var logo = document.getElementById("logo"); TweenLite.to(logo,1, { left:"440px", ease:Power1.easeOut, onComplete:a1 }); } function a1(){ TweenLite.to(logo, 1, {left:"0px"}); } Try that code and let us know if it works. Also I'd recommend you to check the official documentation to learn the difference between onComplete and onCompleteParams. Follow the next link and scroll down to the part that says: Special properties, eases and callbacks (no plugins required) https://greensock.com/docs/TweenLite Happy Tweening!!
  16. Whoa!! another slider controlled GSAP instance question, using a reactive library?? Deja Vue As Jack points, it would be better to move the GSAP instance to the data callback in order to access it everywhere in the component. Also you can populate it in the mounted method, using $refs. Hopefully this sample comes close to what you need: https://codesandbox.io/s/0yr5oko6pl Feel free to fork it and accommodate it to your scenario. Now I'll go for a drive: Happy Tweening!!
  17. Hi, In general is not recommended to fiddle with the values of a GSAP instance, is better to either create it again with the new values or, in your case, use other alternatives. The best approach I can think of is use a .call() method in the timeline when is completed to call a function that will restart the timeline after a random amount of time: var Box = new TimelineMax({ paused: true }); Box .to($('#square'), 1, {rotation:45}) .call(randomDelay) .play(); function randomDelay() { var newDelay = Math.random() * 3; TweenLite.delayedCall(newDelay, function() { Box.restart(); }); console.log("repeat after: ", newDelay); }; Also I see @mikel here, so He's probably working on a great solution as well, so don't just take my advice and wait for His as well. Happy Tweening!!
  18. Hi, There is a lot to digest from your posts. For what I can understand (or I'm understanding), you want the slider to update the progress of the Timeline instance and the Timeline to update the slider value as well. So, when the app starts, the timeline is moving forward and updating the slider, but when the user interacts with the slider, the timeline should be paused and it should be updated based on the value of the Timeline's progress. Am I getting everything right? If so, does this works as you expect?: https://stackblitz.com/edit/react-rc-slider-gsap?file=index.js
  19. Good to hear that you solved your issue. Just keep in mind that you're using GSAP internal class selector to get your element directly from the DOM and that this code runs only when the component is mounted. If your data is updated after the componentDidMount callback, the animation won't run again and the GSAP instance will have reference to all the elements present in the DOM before the data update. If you want to animate your elements just once, then this approach, although not complying with React's recommended practice, does work. Happy Tweening!!
  20. Hi, I know the pain of things getting a bit convoluted sometimes for something that doesn't seem too complicated, but believe me, as soon as you start working on your own re-usable components, you'll find yourself extending their API to accommodate all the uses you'll give them in your apps. Back on topic the one thing I noticed is this: // here you pass as max bookingData.length <Slider className="slider" style={railStyle} handleStyle={handleStyle} min={0} max={bookingData.length} value={this.state.value} onChange={this.onSliderChange} //onInput={this.handleSliderChange} onAfterChange={this.onAfterChange} /> The max value of the slider will be whatever length bookingData will have (I'll assume an array). Is this value 100 or is it a dynamic value?. Because you're calculating the progress value using 100: onAfterChange = value => { console.log(value); this.tl.progress(value / 100); }; So for example if the length of booking data is 25, at it's maximum point the value returned by the slider will be 25, but since you're dividing by 100, the progress of the GSAP instance will be 0.25, that is one quarter of the animation; see what I mean? So instead of dividing by 100 divide by the length of booking data: onAfterChange = value => { console.log(value); this.tl.progress(value / bookingData.length); }; Give that a try and let us know how it goes. Happy tweening!!
  21. At least I don't see any Draggable instance being created.
  22. Hi and welcome to the GreenSock forums. I'm not at all familiar with ScrollMagic, but there are a few moderators here that know it's API and how it works. Unfortunately your question is far to general and you are not providing any type of sample or code snippet to work with. Please take a look at this post by @Carl in order to create a reduced, editable live sample so we can take a better look at your issues and know how to help you: Happy tweening!!
  23. Hi, In the codepen sample I don't see any Draggable code. Could you please include it in order to get a better grasp of what's happening here? Quick question, have you tried this without using Flex in your styles? I'm not saying that flex is causing this, but the solution could be in finding a workaround involving flex, just a thought. Happy Tweening!!!
  24. Well, based on the error you're reporting and the code you posted the only source for that particular error I can spot is this: {this.data.allMarkdownRemark.edges.map(({ node }) => ( <div key={node.id} ref={div => this.myElement = div}> <StyledLink to={node.fields.slug}> <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} /> <PostTitle> {node.frontmatter.title}{" "} </PostTitle> </StyledLink> <Date> {node.frontmatter.date} </Date> <p>{node.excerpt}</p> </div> ))} Where this is undefined. As far as I can see this is not an error with GSAP but some other part of your implementation. The odd thing here is the fact that this is undefined, when it should be the React instance. I'll guess that you're getting your data asynchronously. In that case after the server response your data should be ready to use. Perhaps use some conditional logic inside the render method: render(){ if ( this.props.data ) { <Wrapper> <Title> Works </Title> <Inner> {this.props.data.allMarkdownRemark.edges.map(({ node }) => ( <div key={node.id} ref={div => this.myElement = div}> <StyledLink to={node.fields.slug}> <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} /> <PostTitle> {node.frontmatter.title}{" "} </PostTitle> </StyledLink> <Date> {node.frontmatter.date} </Date> <p>{node.excerpt}</p> </div> ))} </Inner> </Wrapper> } else { return <Wrapper> <Title> Works </Title> </Wrapper>; } } Finally keep in mind that you're passing the data to the Gallery component as a property, there you can't look for this.data, it has to be this.props.data Happy Tweening!!
  25. Hi and welcome to the GreenSock forums. Sorry to hear about the struggles. I have three things to say/ask about it. Have you checked the documentation regarding the use of GSAP via NPM? Take a look at it: https://greensock.com/docs/NPMUsage Related to the previous point. I don't see any GSAP code in your snippet. What exactly are you trying to do? Have you tried that code in an isolated React project, that doesn't include Gatsby? As far as I know Gatsby shouldn't interfere at all with GSAP in a React project, but just in case. Have you read this? https://greensock.com/react It might help you getting started with using GSAP in a React project. Finally if you can, please set up a reduced sample in either codesandbox or stackblitz showing your issue? Happy Tweening!!