Leaderboard


Popular Content

Showing most liked content since 08/21/2017 in all areas

  1. 7 points
    In that case, more people will be willing to help you if you provide your code. Just post new question and attach codepen with your current code so we can help you out or guide in right direction.
  2. 7 points
    Hi @alan0buchanan It really depends on where you look. On this forum, and places like CodePen, you're not gong to find a lot of people using ES6. Look around a place like HTML5 Game Devs, and it's a completely different story. I think most people start using ES6 because of some library/framework they are using. If a person is using React, there's a good chance they are also using ES6 because it's used in all the examples. But I've noticed that a lot of people still live in a jQuery world. The only code they are exposed to is what they see in jQuery's documentation and 10 year old answers on Stackoverflow. So I would have to say that the reason you don't see a lot of ES6 is just plain ignorance. A lot of people have never heard of it, or are misinformed. You'd be surprised by how many times people have asked me how to convert Babel into JavaScript. If you want to see more ES6 examples, people need to be informed, so help spread the word. What is ES6? It's the 6th version of JavaScript, and is also known as ECMAScript 2015. ES5 was the previous version, and came out in 2009. Why should I use it? Because it's JavaScript. There's a lot of new features that can help you write code that is cleaner, smaller, and more concise e.g. arrow functions, string templates, destructuring assignment, computed property names, classes. What is Babel? It's a tool to convert modern JavaScript (ES6) into code that can be used in older browsers. What about performance? There are some new features that haven't been optimized by browsers yet or need a polyfill. This will of course change over time, but if something is too slow, don't use that feature. Most of the features are syntactic sugar, so there should be no difference in performance.
  3. 6 points
    I guess my question would be "why?". GSAP is great at manipulating element properties over time and managing those timelines. The pen above illustrates something a bit outside of that scope. While I'm sure something could be whipped up with GSAP ... why when the solution in the pen handles it perfectly?
  4. 6 points
    Hi @spartan89 I think this should work for you. If you'd like the quote to stay up longer, you can change the pause variable. If you don't want the next quote to overlap at all, you can set the overlap to 0. Hopefully that helps. Happy tweening.
  5. 6 points
    So weird. I made a demo earlier that is nearly identical to that, but I didn't get around to posting it in time. It's just a modified version of something I made for another question.
  6. 6 points
    Hi Patryk Is this what you needed? I used a from() tween at the beginning of the timeline to start the opacity at 0 and then fade out at the end. The position parameter is hard coded based on your 8 second tween, but you could certainly add labels for flexibility. I also reduced it down quite a bit by targeting the '#leaves groups' for the tween. That way you don't need all those separate timelines since the animation is the same for each leaf group. You could certainly use a stagger, cycle or a function based value for some randomness too. You had two values for yPercent (-450 and 50) in your tweens and I wasn't sure which was correct so I just left in the value of 50. Hopefully this helps. Happy tweening.
  7. 6 points
    Hi @Ali Farooq I think you have a slight rotation on that gear so the tween shows that little adjustment on each repeat since you're animating from exactly 360. Please try animating from a relative 360 like this: TweenMax.from(mainGear, 4, {rotation:"+=360", transformOrigin:"50% 50%", ease:Linear.easeNone,repeat:-1}); Hopefully that helps. Happy tweening.
  8. 6 points
    Hi @Robert Wildling The CSSRulePlugin is not loaded with TweenMax. The following is loaded with TweenMax: TweenLite TweenMax TimelineLite TimelineMax CSSPlugin AttrPlugin RoundPropsPlugin DirectionalRotationPlugin BezierPlugin EasePack You can load that plugin separately here: <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/plugins/CSSRulePlugin.min.js"></script> I don't think you can stagger that since it's affecting the CSS rule itself, but I'm no expert with that particular plugin so I'm sure someone will correct me if I'm wrong. I usually avoid pseudo elements except in rare cases of a little style. For elements I want to animate, I always loop through and append them as needed so they're actual DOM elements. Hopefully that helps. Happy tweening.
  9. 6 points
    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!!
  10. 5 points
    Hi Gabvrel, Welcome the GreenSock forums and Club GreenSock! Sorry to hear you are having trouble with files that are loaded in our CodePen demos. Not sure why they are being blocked. Below is the source to findShapeIndex. Save it to your own file and try loading it locally /* For use with GreenSock's MorphSVGPlugin - helps find the best-looking shapeIndex value. USAGE: findShapeIndex("#yourTarget", "#otherShape", {duration:3, ease:Linear.easeNone, size:10}); You can pass in either the other shape's selector text, or the full path data, like: findShapeIndex("#yourTarget", "M506.066,200L400,306.066L293.934,200L400,93.934L506.066,200z", {duration:3, ease:Linear.easeNone, size:10}); Tap the up/down arrows (or left/right or "u"/"d") to change the shapeIndex. Requires: TweenLite 1.18.0 (or later), MorphSVGPlugin LAST UPDATED: 2015-10-21 Copyright 2015, GreenSock Inc. @author: Jack Doyle, jack@greensock.com */ function findShapeIndex(target, endShape, vars) { vars = vars || {}; var _doc = document, TweenLite = (window.GreenSockGlobals || window).TweenLite, _get = function(e) { return _doc.querySelectorAll(e); }, _createSVG = function(type, attributes) { var element = _doc.createElementNS("http://www.w3.org/2000/svg", type), reg = /([a-z])([A-Z])/g, p; for (p in attributes) { element.setAttributeNS(null, p.replace(reg, "$1-$2").toLowerCase(), attributes[p]); } return element; }, _numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, _parseShape = function(shape, forcePath) { var e, type; if (typeof(shape) !== "string" || (shape.match(_numbersExp) || []).length < 3) { e = TweenLite.selector(shape); if (e && e[0]) { e = e[0]; type = e.nodeName.toUpperCase(); if (forcePath && type !== "PATH") { //if we were passed an element (or selector text for an element) that isn't a path, convert it. e = MorphSVGPlugin.convertToPath(e, false)[0]; type = "PATH"; } shape = e.getAttribute(type === "PATH" ? "d" : "points") || ""; } else { console.log("WARNING: invalid morph to: " + shape); shape = false; } } return shape; }, startDot, endDot, incrementButton, decrementButton, _setup = function() { var e = _doc.createElement("div"), label = _doc.createElement("div"), body = _get("body")[0]; incrementButton = _doc.createElement("div"); decrementButton = _doc.createElement("div"); label.setAttribute("id", "shapeIndexLabel"); startDot = _createSVG("circle", {cx:0, cy:0, r:(vars.startStrokeWidth || 3) + 3, fill:vars.startStroke || "red"}); endDot = _createSVG("circle", {cx:0, cy:0, r:(vars.endStrokeWidth || 3) + 3, fill:vars.endStroke || "yellow"}); TweenLite.set(e, {padding:"0px", position:"absolute", bottom:0, fontSize:"20px", textAlign:"center", backgroundColor: "black", color:"#91e600", border:"1px solid #999", left:"50%", xPercent:-50, yPercent:-50, userSelect:"none", fontFamily:"sans-serif"}); TweenLite.set(label, {display:"inline-block", minWidth:"210px", marginRight:"10px", textAlign:"center", marginLeft:"10px"}); TweenLite.set([incrementButton, decrementButton], {display:"inline-block", padding:"0 15px", color:"#ccc", height:"50px", lineHeight:"48px", cursor:"pointer"}); TweenLite.set(decrementButton, {borderRight:"1px solid #999"}); TweenLite.set(incrementButton, {borderLeft:"1px solid #999"}); decrementButton.innerHTML = " - "; incrementButton.innerHTML = " + "; e.appendChild(decrementButton); e.appendChild(label); e.appendChild(incrementButton); if (body) { body.appendChild(e); } return label; }, label = _get("#shapeIndexLabel")[0] || _setup(), index = 0, _yoyo = function() { shapeTween.reversed(!shapeTween.reversed()).resume(); dotTween.reversed(!dotTween.reversed()).resume(); }, shapeTween, dotTween, startBezier, endBezier, dotProxy = {x:0, y:0}, _getFirstCoordinates = function(start, end, shapeIndex) { startBezier = MorphSVGPlugin.pathDataToRawBezier(start); endBezier = MorphSVGPlugin.pathDataToRawBezier(end); MorphSVGPlugin.equalizeSegmentQuantity(startBezier, endBezier, shapeIndex); return [startBezier[0][0], startBezier[0][1], endBezier[0][0], endBezier[0][1]]; }, _startTween = function() { var coordinates = _getFirstCoordinates(target.getAttribute("d"), _parseShape(endShape, true), index); dotProxy.x = coordinates[0]; dotProxy.y = coordinates[1]; startDot.setAttribute("cx", dotProxy.x); startDot.setAttribute("cy", dotProxy.y); endDot.setAttribute("cx", coordinates[2]); endDot.setAttribute("cy", coordinates[3]); shapeTween = TweenLite.to(target, vars.duration || 3, {delay:0.5, morphSVG:{shape:endShape, shapeIndex:index}, ease:vars.ease || "Linear.easeNone", onComplete:_yoyo, onReverseComplete:_yoyo}); dotTween = TweenLite.to(dotProxy, vars.duration || 3, {delay:0.5, x:coordinates[2], y:coordinates[3], ease:vars.ease || "Linear.easeNone", onUpdate:function() { startDot.setAttribute("cx", dotProxy.x); startDot.setAttribute("cy", dotProxy.y); }}); }, _refresh = function() { label.innerHTML = "shapeIndex: " + index + (index === autoIndex ? " (auto)" : ""); shapeTween.seek(0).kill(); dotTween.seek(0).kill(); _startTween(); TweenLite.fromTo(label.parentNode, 0.4, {backgroundColor:"#777"}, {backgroundColor:"black", ease:Linear.easeNone}); }, _increment = function() { index = (index + 1) % (maxIndex + 1); _refresh(); }, _decrement = function() { index = (index - 1) % (maxIndex + 1); _refresh(); }, autoIndex, maxIndex, endTarget; if (typeof(target) === "string") { target = TweenLite.selector(target)[0]; } if (!target) { console.log("ERROR: target not found for findShapeIndex(). Please use a valid target."); return; } else if (target.nodeName && target.nodeName.toUpperCase() !== "PATH") { console.log("ERROR: target of findShapeIndex() must be a path."); return; } else if (target.push && target[0] && target[0].nodeName) { target = target[0]; } if (target.parentNode) { target.parentNode.appendChild(endDot); target.parentNode.appendChild(startDot); } if (typeof(endShape) !== "string" || (endShape.match(_numbersExp) || []).length < 3) { endTarget = TweenLite.selector(endShape); if (endTarget && endTarget[0]) { endTarget = endTarget[0]; TweenLite.set(endTarget, {display:"block", strokeWidth:vars.endStrokeWidth || 3, stroke:vars.endStroke || "yellow", fill:vars.endFill || "none", visibility:"visible", opacity:vars.endOpacity || 0.7}); } } TweenLite.set(target, {display:"block", strokeWidth:vars.startStrokeWidth || 3, stroke:vars.startStroke || "red", fill:vars.startFill || "none", visibility:"visible", opacity:vars.startOpacity || 0.7}); startBezier = MorphSVGPlugin.pathDataToRawBezier(target.getAttribute("d")); endBezier = MorphSVGPlugin.pathDataToRawBezier(_parseShape(endShape, true)); autoIndex = index = Math.round(MorphSVGPlugin.equalizeSegmentQuantity(startBezier, endBezier, "auto")[0]); //also handles subdividing! maxIndex = (startBezier[0].length / 6) | 0; TweenLite.killTweensOf([target, endShape], false, {morphSVG:true}); //kill other tweens so they don't interfere with our yoyo-ing one. _startTween(); label.innerHTML = "shapeIndex: " + index + (index === autoIndex ? " (auto)" : ""); window.addEventListener("keydown", function(event) { var key = event.keyCode; if (key === 38 || key === 39 || key === 85) { //right or up arrows (increment) _increment(); } else if (key === 37 || key === 40 || key === 68) { //left or down arrows (decrement) _decrement(); } }); incrementButton.addEventListener("click", _increment); decrementButton.addEventListener("click", _decrement); }
  11. 5 points
    Hello guys - I've finally finished an app I've been working on for some time, as while it doesn't showcase GSAP (which I've used in just about everything else I've ever done!) - I'd love to offer free pro accounts for any developers over here who might want to use it. I have about 33,000 Open Source & Creative Commons graphics, inside of an easy to use SVG editor that can output PNGS or SVGs, and will soon also have app icon exports for IOS and Android, as well as export for the Spine animation platform. We have a few thousand pieces of game art as well - including over 400 of the best Glitch pieces, as well as the Kenney.nl collection, and others. We are at https://kwippe.com The basic app is free but a pro subscription will get you access to importing your own stuff, as well as cloud syncing (coming soon) - and lots of other cool stuff on our roadmap. Sorry if this isn't the right place for this message - but wanted to throw it out there and see if anybody is interested! We are still definitely a beta product, but the app has a lot of promise as we are offering a variations designer that makes it pretty painless to throw together some quick graphics. Just shoot me an email - stace at kwippe.com - and I'll upgrade your account on Kwippe. @OSUblake @Carl @GreenSock
  12. 5 points
    Hello @timdt and welcome to the GreenSock Forum! Do you mean something like this? Animating a background image of just clouds And this one is animating background of clouds and grass.. 2 background images at once. Happy Tweening
  13. 5 points
    Hi @aderon14 I think that's fine, but I'm no expert. For that, I would highly recommend following Sarah Drasner. She does a bunch of workshops and presentations on GSAP and Vue/Nuxt. GitHub - a bunch of good stuff in here https://github.com/sdras?tab=repositories CodePen https://codepen.io/sdras/pens/public/ Twitter https://twitter.com/sarah_edo Slides http://slides.com/sdrasner
  14. 5 points
    Awesome answer, @PointC! Above and beyond as usual. Just for kicks, here's a slightly different version that shows how you can use a single delayedCall() instance and simply restart() it in the makeItMorph() method. And it uses slightly different logic for the incrementing/decrementing...
  15. 5 points
    Yep - both those things are possible. 1. Moving to a new x/y position: You could animate the path to a new x/y position on each morph. Those coordinates could be pulled out of an array and used in the morphing tween. Or you can have your target paths at different positions. Remember that you will not only be morphing to a new path shape, but also a new path position if the new one is someplace else. Here's a pen I made for another forum question, but shows that morphs will move to the new path position: You can see in one version the target paths are at the corners and they are all stacked on top of each other in the other version. 2. Autoplay the morphs: I think the easiest way to modify my first demo for an automatic play would be to modify the button click function so it's accessible via a delayedCall tween too. The delayed call will run the function every 5 seconds (it's a variable so change it to your liking) unless a button is clicked and interrupts it. Once the morph tween plays via a button click, it will once again call the function that starts the delay autoplay cycle again. Hopefully that makes sense and helps a bit. Happy tweening.
  16. 5 points
    Hi @Bernt Welcome to the forum. Here's a pen I made as an answer to another forum question that should help you get started: This is the original thread which has a similar question to yours: Hopefully that helps. Happy tweening and welcome aboard.
  17. 5 points
    Children don't tell their parents what to do... at least well behaved children don't. Think about elements. A child element cannot change the position of its parent, and it cannot stop its parent's position from changing. So you would need to do to do something like this. Not pretty, but when you see repetition, that usually means you can use a loop to simplify things. var master = new TimelineLite() .add(fadeIn(".d1")) .addPause() .add(fadeOut(".d1")) .add(fadeIn(".d2")) .addPause() .add(fadeOut(".d2")) .add(fadeIn(".d3")) .addPause() .add(fadeOut(".d3")) function fadeIn(el) { return new TimelineLite().from(el, 0.5, {xPercent:-50, autoAlpha:0}) } function fadeOut(el) { return new TimelineLite().to(el, 0.5, {xPercent:50, autoAlpha:0}, "+=0.2") }
  18. 5 points
    Hi @Bernt! Welcome to the forums! When you say you're new to coding in general, how much do you know? Can you add the buttons and have them trigger calls? To point you in the direction without writing the actual code, here's what you need to do: Create a timeline that loops (TimelineMax will do the trick super easily) Use a TimelineMax's .to() method for each of the shapes, each with a unique label attached to it (Check the position parameter in the docs). Add your buttons to call one of a variety of methods/techniques to jump to the desired label depending on the desired effect .seek() .play() .tweenTo() .progress() with .time(), .totalTime() and .getLableTime() I'm sure there are other ways as well, people here are pretty good at coming up with ideas how to achieve things. Happy tweening!
  19. 5 points
    Hi sebHeweit, Welcome to the forums. You're right, that comment could be a little mis-leading. jQuery is NOT required to select a target via a class. If jQuery is available it will be used, but its not necessary. As stated earlier in the docs, TweenLite will use document.querySelectorAll() where available which these days is every browser. I updated the TweenLite docs to simply say //tween the element with ID of "myID" TweenLite.to("#myID", 2, {backgroundColor:"#ff0000", width:"50%", top:"100px", ease:Power2.easeInOut}); //tween every element with the class "myClass" like this: TweenLite.to(".myClass", 2, {boxShadow:"0px 0px 20px red", color:"#FC0"});
  20. 5 points
    You can just use jQuery for selection, GSAP works with it without any issues.
  21. 5 points
    I'm on my way out the door, but here's a really quick example. By hovering over the green box while red animates, it will change the toggle variable and won't change the background color. Hopefully that helps a little bit. Happy tweening.
  22. 5 points
    Hi and welcome to the GreenSock forums, Thanks for the demo. I'm not able to dissect all 300+ lines of it but there are some performance red flags mainly regarding how you are creating a bunch of set()s repeatedly in new timelines for every update. Whenever a tween is created and run GSAP needs to ask the browser to find that element in the DOM and also read the existing values of the properties you are animating. A tween needs to record start and end values so that it can efficiently be played and reversed multiple times without needing to search the DOM again. Doing a set() is the same as a to() or from() tween except that the duration is 0 seconds. A set() still needs to search the DOM for the target and also READ and WRITE the starting and ending values immediately. A tween created via set() is a very odd bird in that since it has no duration it runs immediately and completes as soon as it starts but it also needs to remember start and end values so that it can be placed in a timeline and reversed. Also consider that the purpose of a timeline is for sequencing. On each update you are creating a new timeline with 4 .set() calls that all fire at the same time. A TimelineLite object inherently has a bunch of features for the advanced scheduling of tweens. If you need 4 set()s to run at once it would be more efficient to just use 4 TweenMax.set()s. Creating a timeline really doesn't suck up a lot of resources but in this usage it seems wasteful or unnecessary. My point is that it would be better to use vanilla JS to if you only need to instantly change a bunch of css style values. There is no need for any sequencing (TimelineLite) or any need to create a bunch of tweens (created by set()) that require all the reading and writing. In normal, 1-off, instances sets are perfectly fine to use, but if you are re-creating a bunch of them and trying to keep up with 60fps it could be an issue. I would recommend you study the demo below from @OSUblake When the app loads it creates 1 timeline for each dot that scales and changes the color of each dot (bullet). Based on the horizontal scroll position he determines which animations need to move their progress forwards or backwards. As you scroll horizontally you will see very fluid animation of the dots. It is much easier on the browser to tell multiple animations to update then to repeatedly do all that searching, reading and writing caused by the set()s.
  23. 5 points
    Hi @Kenjee What you're seeing there is the easing. You're using a Power4 ease in/out. If you want the animation to have the same duration as 100% of the scroll, you'd want to use Linear.easeNone. Hopefully that helps. Happy tweening and scrolling.
  24. 5 points
    That's expected. The value needs to be mod like ((-179 - 180) % 360) + 360. Play around with SVG arc paths, and you'll see why. Just wanted to point out the DirectionalRotationPlugin is part of the CSSPlugin, so you don't have use it directly. And you don't have to convert to degrees... although I'm wondering if your x and y values are reversed? TweenMax.to(foo, 1, { rotation: Math.atan2(dy, dx) + "rad_short" });
  25. 5 points
    Hi @JarethB You may want to take a look at the docs for the DirectionalRotationPlugin here: https://greensock.com/docs/Plugins/DirectionalRotationPlugin Happy tweening.
  26. 5 points
    Hi @Ali Farooq I pretty sure the problem is just your SVG markup. It's in serious need of some cleanup. There's a lot of redundant stuff in it, like all these nested groups. <g class="g46142"> <g id="g46130"> <g id="g46128"> <g id="g46108"> <g id="path46106"> <use id="use4673" fill="#39B54A" transform="matrix(-0.0282279 0 -0 -0.0282279 -1766.86 -1902.92)" xlink:href="#path24_fill"/> </g> </g> <g id="g46116"> <g id="path46114"> <use id="use4677" fill="#CDFF8A" transform="matrix(-0.0282279 0 -0 -0.0282279 -1787.63 -1923.47)" xlink:href="#path25_fill"/> </g> </g> <g id="g46122"> <g id="path46120"> <use id="use4681" fill="#39B54A" transform="matrix(-0.0282279 0 -0 -0.0282279 -1890.12 -2038.52)" xlink:href="#path26_fill"/> </g> </g> <g id="g46126"> <g id="path46124"> <use id="use4685" fill="#39B54A" transform="matrix(-0.0282279 0 -0 -0.0282279 -1824.12 -1958.51)" xlink:href="#path27_fill"/> </g> </g> </g> </g> </g> That could be reduced down to something like this. <g class="dollar"> <path d="..." /> <path d="..." /> <path d="..." /> <path d="..." /> </g> It's also a good idea to get rid any transforms in your markup. What SVG editor are you using? Some editors like Inkscape and Affinity Designer have an option to flatten the transforms for you. If not, you can usually ungroup your elements to get rid of the transforms. I used Illustrator to ungroup your SVG elements, and it dramatically cleaned up your code. From over 1000 lines of code, down to 150. It also got rid of all the <use> elements and flattened the transforms on a normal path element. I also removed the initial rotation on the eyes and dollars as that was throwing some of the centering off a tad. Everything is working as expected in all browsers.
  27. 5 points
    This is selecting everything in your document that matches. That's why all your slides have played. var workTitle = $(".title"); var workContent = $("p"); It's better to create your animations ahead of time for something like this. Using jQuery's .map() method is an easy way to create an array-like list of objects (timelines). When a slide loads, use the index to play that animation. When a slide leaves, use the next slide index to pause the animation in its starting state so it will play all the way from the beginning when loaded.
  28. 5 points
    This was actually a pretty clever transition and it took me a little while to figure out what was happening. The solution came only after I recorded a video to study the transition in slow motion. (you can change the speed of this youtube video) I initially thought they were doing very clever masking but it turns out they are only rotating very large, solid-colored rectangles. The animation is always: - a rectangle animates to cover up an image on one side - then another rectangle animates out to reveal an image and that process just repeats over and over again. The tricky part is that for each transition you have re-sort the stacking order of the rectangles that are animating and the images that are being revealed and covered. I did a VERY ROUGH mockup just because I saw it as a bit of a challenge. The code is horrendous and in real life you would want to make it more dynamic and flexible. I provide this to show just that the effect can be achieved just by rotating some divs around. I don't expect you or anyone to understand all the code as ... again ... it was done in haste as an experiment as a proof of concept. It would take me quite some time to do it right. RIght now it is quite slow to help you see what is happening.
  29. 5 points
    I set those demos up to handle different sizes because I knew that was going to be your next question. But forget all that for now. I see that is just going to lead us down another rabbit hole. Just do EXACTLY what @PointC is telling you to do, and it will work. I would highly recommend to read up on SVG before trying to do anymore animating. Here's a good place to start. Please go through every item. http://tutorials.jenkov.com/svg/index.html You can use CSS with SVG, but most of the properties are different than HTML. Notice there is no left or top anywhere. https://www.w3.org/TR/SVG/styling.html#SVGStylingProperties
  30. 5 points
    Wow! GSAP now has a time travel feature? Is there anything this platform can't do? I suppose we now have to be careful about accidentally creating a paradox while animating. Clever solution @Carl.
  31. 5 points
    Hi @iwas@thestartofitall.com Welcome to the forum. There are some strange paths in your SVG. They all have a class of 'a_severity' and look like coordinates for line elements. Here's one: <path class="a_severity" x1="613" y1="408" x2="590" y2="399"/> Once I removed those from the SVG, it seemed to work correctly in IE11. I'm really not sure why the other browsers didn't get cranky about it? Maybe the other browsers just ignored those for some reason, but removing those odd paths did fix it for me in IE. IE is more of a fussy pants with everything related to SVGs. Hopefully that helps. Happy tweening.
  32. 5 points
    Hi @SalvoDee Welcome to the forum. Instead of using tweens with delays, you should take a look at using a timeline for that animation. If you're using delays and you move one tween or change its duration, the whole sequence is going to break. Timelines make that type of work super easy. https://greensock.com/timelinemax You can play them in sequence, overlap them or make them wait a bit to start. You do this by using the position parameter. More info: https://greensock.com/position-parameter You can use the jQuery selector for your target, but if you want to save some typing, you can just write it like this too: TweenLite.to('#mission .grid-item', 1.2, {width:"100%", opacity: 1,ease:Expo.easeIn}); To get started, these are great resources if you haven't seen them yet: https://greensock.com/jump-start-js https://greensock.com/get-started-js Hopefully that helps. Happy tweening.
  33. 5 points
    If you want different eases for each direction of the animation I think the best solution is what you had initially: create unique tweens for each direction. When an animation is reversed GSAP honors the ease that you set for that animation. If playing forward your animation starts fast and ends slow, in reverse it will start slow and end fast. What you are suggesting is that one animation would have 2 eases: one for playing forward and one for playing in reverse. We recently added this for TweenMax tweens that repeat and have yoyo set to true. See video here: https://greensock.com/1-20-0 and demo. However, in your case since your animation is driven by user interaction which i don't think it is going to work well in your case. yoyoEase is great for animations that run on their own (repeating TweenMax tweens) as the engine knows exactly when to swap in the new ease – at the exact end of an iteration. In your example the user can click many times WHILE an animation is playing and if you swap eases at that point, the animation will jump and look bad.
  34. 5 points
    Hello @alan0buchanan and Welcome to the GreenSock Forum! You can create a new timeline in a paused state. Then just simply play() on focus and reverse() on blur. See the below example : Happy Tweening!
  35. 5 points
    Hi @SLSCoder Don't confuse left and top with x and y. Two completely different concepts. My advice, don't use left and top if it can be done using x and y. Positioning is much easier when you set top and left to 0, and use GSAP to set and animate x and y. You should also read up on how xPercent and yPercent work in this blog post. And motion paths are not tied to SVGs. All the pathDataToBezier methods does is it converts path data into an array of points, which can be used with the BezierPlugin. That's where the real magic happens. Learn that, and you'll be golden. There's some good stuff in here. There are no hard coded values, so it's pretty flexible. It requires more code, but makes it easier to test out different things. And a variation of that using the BezierPlugin's thru type instead of path data.
  36. 5 points
    Hi and welcome to the GreenSock forums, Thanks for the demos. Nice animation. Every animation has a progress() which is a value between 0 and 1. When the animation is half-way, or 50% complete tl.progress() will return 0.5. So if you know your page is 80% loaded, you can set the progress to 0.8 like: tl.progress(0.8); The demo below has a few buttons that allow you to set the progress() to different amounts. While your page loads you could repeatedly update the progress() very quickly You'll notice that the animation just jumps to each progress() value when you press each button. If you are updating the progress() very quickly you will get a smoother animation but it won't be that great. TimelineMax has a tweenTo() method that allows you to smoothly animate to any time or label in a timeline. The demo below converts the progress() to a time by multiplying by the duration of the timeline. So if your timeline is 10 seconds long and you want to tween to the time that is at the 10% mark you would do 0.1 * 10 = 5 seconds var duration = tl.duration(); $("#p10").click(function(){ tl.tweenTo(0.1 * duration) }); So now each time you press a button you will smoothly tween to the new percentage (represented by time) So you may want to check how much of the page is loaded every second and tweenTo the proper time based on that percentage for a smoother result than just setting the progress() Note: you had an infinitely repeating animation of the sun rays rotating. This gives your timeline an infinite duration and makes dealing with progress() very cumbersome so I had to make it not repeat. I'm not sure how many rotations you want the user to have to see while the page loads but it will need to be a finite amount.
  37. 5 points
    A lot of the stuff you can tween can be found on the style object for your rectangle. For x and y, you can tween the position object. TweenMax.to(rectangle.position, 1, { x: "+=200", y: "+=400" }); To change the transform origin, you set the pivot property. It's in local coordinates, so you can do this to rotate it around the top left corner. rectangle.pivot = rectangle.parentToLocal(rectangle.bounds.topLeft)
  38. 5 points
    Hi @sgtpenguin Welcome to the forum. 3D transforms are not supported by SVG. You can get away with it in some browsers. Your CSS rotation works in Chrome and Firefox, but not in Edge. The best approach right now is transforming the entire SVG element. Hopefully that helps. Happy tweening.
  39. 5 points
    I think the language barrier is causing some confusion. I'm having a lot of difficulty following this. I suspect though that PointC is correct in pointing out the position parameter of "-=04" .to(".icon-cursor-1", 0.75, {width: 66, height: 66, rotation: 0, borderWidth: 6, ease: Power4.easeOut}) .to(".icon-cursor-1", 0.25, {borderWidth: 2}, "=-0.4"); // this tween starts while the previous tween is still animating borderWidth! When the second tween starts, 0.4 seconds BEFORE the previous tween ends the engine is in a situation where 2 tweens are trying to change the borderWidth at the same time. Instead of wasting CPU by having 2 tweens fighting for control the engine allows the second tween to overwrite the part of the first tween that animates borderWidth. When you reverse or play the timeline again... the borderWidth part of the first tween is killed by the overwrite. The best solution is: do not schedule 2 tweens at the same time to control the same properties of the same object. You can achieve this by removing the position parameter of "-=0.4" on the second tween .to(".icon-cursor-1", 0.75, {width: 66, height: 66, rotation: 0, borderWidth: 6, ease: Power4.easeOut}) .to(".icon-cursor-1", 0.25, {borderWidth: 2}]); Another solution is to put overwrite:"none" on the second tween. .to(".icon-cursor-1", 0.75, {width: 66, height: 66, rotation: 0, borderWidth: 6, ease: Power4.easeOut}) .to(".icon-cursor-1", 0.25, {borderWidth: 2, overwrite:"none"}, "=-0.4");
  40. 5 points
    What is it @Jonathan always says? "If you build it, they will break it."
  41. 5 points
    Interesting. Yes, I see what you mean. I never even anticipated that someone would start with a <br>. I just updated the special version of SplitText that's on codepen: https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/SplitText.min.js - does that work better for you? Once you confirm, I can add it to the "official" members-only zip download (the one that's not limited to Codepen). Thanks for letting us know about this.
  42. 5 points
    As you probably know, we place a HUGE priority on performance in GSAP, and callbacks are extremely fast. Event listeners (which is what you're describing here) take longer because you have to manage an array of them, loop through that array whenever they need to be triggered, offer ways to remove listeners, etc., etc. There's just more overhead and it's pretty simple to achieve what you're asking for with vanilla JS: .eventCallback("onComplete", function() { func1(); func2(); func3(); }); Or you could easily create your own wrapper around the callback system that'll let you add as many listeners as you want: function addListener(animation, type, func, params, scope) { var listeners = animation._listeners = animation._listeners || []; listeners.push({type:type, func:func, params:params, scope:scope}); if (!animation._listeners[type]) { animation._listeners[type] = function() { var i = listeners.length, listener; while (--i > -1) { listener = listeners[i]; if (listener.type === type) { listener.func.apply(listener.scope || animation, listener.params); } } }; animation.eventCallback(type, animation._listeners[type]); } } (untested) That way, you can just call addListener(yourAnimation, "onComplete", yourFunc); And of course you could create a removeListener() function that loops through the listeners and removes the appropriate one(s). Hopefully this gives you a nudge in the right direction
  43. 5 points
    Yeah, that's unrelated to GSAP - Safari just doesn't render things correctly (Safari bug). Apparently clip-path isn't "officially" supported by Safari, at least according to the info I saw on the web. But the weird rendering behavior got me thinking - maybe if you could force the browser to re-render on each tick/update, it'd work. Sure enough, that seems to help. So in your example, you could do something like: var img = document.querySelector(".svg-image"); function redrawClipPath() { // <- call this in an onUpdate img.style.clipPath = "none"; img.offsetWidth; //force a style recalculation img.style.clipPath = "url(#svgPath)"; }; Does that help at all? You might want to add some conditional logic so that it only runs in Safari (strictly for performance reasons). Hopefully this gives you a nudge in the right direction.
  44. 5 points
    Thanks for the demo. Not 100% sure how it all works, but took a stab at this: press the runwave button to toggle the paused state of master
  45. 5 points
    Thanks for the updated demo. I think I understand what you're trying to do. You have a set of elements that you want to stagger and repeat, but on the first pass, element[0] should not be a part of the stagger, correct? On iteration 1 element[0] is going to do its own animation, but every repeat thereafter it should be a part of the stagger array? If that's the case, there would be a number of ways to make this happen. For simplicity I just made a couple new demos with some divs so we can clearly see what's going on. In this first option I have made two arrays. One with all the boxes and one with all the boxes except .box1 using jQuery's .not() selector. You'll see the result is box1 animating its y position on the first tween and boxes 2-5 rotate. After that, all 5 boxes rotate. Another option would be to create the target array and then splice out the first element. You'd then play your first iteration of the animation and onComplete call a function that recreates the array and staggers all the elements in a new stagger tween. It's the same result, but just a different approach. Personally, I'd go with the 1st option as it's a bit simpler. The bottom line is you need an element to be part of an array for one stagger animation, but not part of it for another so I think you'll need to create a couple arrays as targets or modify one between animations. Others may have additional ideas better than mine. Hopefully that helps. Happy tweening.
  46. 4 points
    That's great Blake. It's always an education seeing you and Jack post a demo for the same question. I see many similarities, but differences too. It helps me learn and hopefully get better. Right now I have a high degree of confidence that I can make almost anything work with JS. It may not be the best way, but it will work so I feel good about that part. Now I want to get better at writing more efficient, shorter and flexible code. Small demos like this help. One of these days I need to take your advice and write a little game for practice. Maybe when each day contains an extra 20-30 hours I can get to all the things I'd like to learn. Thanks again for all the schooling around here.
  47. 4 points
    Thanks for the demo. The short answer is no, there isn't an easy (practical) way to just remove the delay from a tween in a timeline when it is reversed. Yes, you could find the tween in the timeline, remove its delay and then shift the following tweens around, but then when you want to move forward again you would have to add the delay back in and move the tweens that follow. It can get messy. Once you say "i want this animation to something different in reverse" you step beyond what reverse is supposed to do. You need a different animation. My suggestion is to have separate functions for your open and close animations. When you call those functions you create the necessary timelines. This allows you to have much more flexibility Something like:
  48. 4 points
    Ah, okay, I see what you're talking about. Yes, minimumMovement was designed for regular x/y drags (total pixel movement), not rotational dragging. However, I think it's a good idea to add that capability, so I'll do so in the upcoming release which you can preview at https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/Draggable-latest-beta.js (uncompressed). That'll interpret minimumMovement as degrees when used with type:"rotation". That should make it very simple for you. In the mean time, if you want a solution with the current version, here's an example of using onPress and onDrag to limit dragging until a threshold of 45 degrees is reached: Does that help?
  49. 4 points
    There's nothing wrong with the SVG coordinate system. It's consistent, and works pretty much the same as every 2d graphics library ever made. Everything is based on a transformation matrix. That's the key. Unfortunately, I cannot recommend a single resource to help you out with that because I've never seen one, so good luck with that. There are ways to get and work with those transformation matrices in the browser, but again, good luck finding any documentation on it. Here's a really simple example that converts the mouse position into the coordinate space of the SVG. Try resizing it and using different values values for the preserveAspectRatio attribute. There are ways to figure everything out.
  50. 4 points
    this might do the trick: Most of this came from the guts of demos and posts from Blake. watch the videos here: