Jump to content
Search Community

GreenSock last won the day on May 18

GreenSock had the most liked content!

GreenSock

Administrators
  • Posts

    23,183
  • Joined

  • Last visited

  • Days Won

    821

Everything posted by GreenSock

  1. Interesting - the problem boils down to something you can see with one line of code in your example: console.log(document.querySelector("#city").getBBox()); //Safari: {x: -0.8500000238418579, y: 0, width: 319.9736328125, height: 335.6852111816406} //Other browsers: {x: 42.81999969482422, y: 50.01018524169922, width: 276.7608337402344, height: 286.3160705566406} As you can see, that's not related to GSAP at all. Pretty annoying, I know. I think it has to do with the way Safari is handling the transforms in your elements (I noticed you've got a transform applied to almost everything), like it's including those when it calculates the bounding box. Craig's solution with svgOrigin seems like the best, easiest solution here. I don't see a good way for GSAP to somehow work around this Safari issue without having to literally loop through every child and remove its transforms, do the measurement, and then add them back (CPU-intensive, and the code would bloat CSSPlugin). Hopefully Safari will get this fixed soon.
  2. I guess it depends on the plumbing of the canvas stuff you're using. There are a lot of ways you could do it. Fundamentally, it's not ideal to make your animation engine track when it's appropriate to re-render your canvas stuff because you may change things outside of animations too and you don't want to be locked into constantly managing that. Here are a few approaches off the top of my head: Canvas library tracks changes & updates Ideally, your canvas objects (the things you're animating/changing) should internally flag the need for re-renders. For example, if you change the "width" of something, it's gonna need to be redrawn but you don't want to immediately do that because you might have 100 other things that also get changed on that tick and you should only re-render ONCE per requestAnimationFrame (aggregate all your changes) like the browsers do. So perhaps you use getter/setter functions on your elements so that when you set them, they tell their parent canvas "hey, I'm dirty...make sure you redraw me when you have a chance". Like parentCanvas.dirty = true. Then, you TweenLite.ticker.addEventListener("tick", yourRenderFunction) that evaluates "hey, am I dirty? If so, run my redraw routine". That way, you never have to use onUpdates or manually trigger redraws - the system handles it all automatically in an intelligent way. Create a plugin that manages it for you. Alternatively, you could create a simple GSAP plugin that handles all that render stuff for you. The concept is somewhat similar to above, but it's offloading things to a plugin instead of internally managing things in the plumbing of your canvas library. So, for example, a "RenderPlugin": .to(....{x:100, render:yourCanvas}) (Or you could even just add the canvas reference as a static property on the plugin itself to save yourself some typing, and merely call render:1...totally up to you) When that plugin loads, it adds that "tick" listener to GSAP's ticker kinda like: TweenLite.ticker.addEventListener("tick", function() { if (dirty) { yourCanvas.render(); dirty = false; } }); And in the "set" part of the plugin (this is the function that runs on every tick of each tween), all you'd do is: set: function(value) { dirty = true; } That way, anytime any tween sets a value (well, any tween with render:yourCanvas), it'll simply set that simple flag and then only once per tick will it actually call yourCanvas.render(). So 100 tweens could fire and they all set dirty = true and then your tick listener eventually is like "oh, I'm dirty, let me trigger the render now that GSAP is done with everything on this requestAnimationFrame tick." Those are just a few options for you. There are more Does that help at all?
  3. GreenSock

    To heavy animation

    The most expensive stuff I saw in your code was: The className tween (those literally have to iterate through every property, isolate what has changed between states, and record starting/ending values). I generally try to avoid className tweens if you can - it's much cleaner and more performant to specify the values you want changed. The "resize" hander. That can get called many times while the user drags the window bigger/smaller, and you're invalidating() and recreating all your tweens each and every time. If I were you, I'd throttle that so that it waits until the user stops dragging (a certain amount of time has elapsed with no more changes) before firing that. The "width" tweens. "width" is just expensive for the browser due to repaints, layout reflow, etc. Oh, and calling jQuery's "outerWidth()" is pretty expensive too. Typically when you're seeing poor performance, the biggest culprit BY FAR is browser rendering which has absolutely nothing to do with GSAP. In other words, GSAP could change the property values in 1ms, but it might take 100ms for the browser to then calculate all the new pixels and repaint the screen. So I'd focus your energy on minimizing the load on the browser in terms of graphics rendering.
  4. Yep, Craig is right. That's an easier approach, but let me explain why your demo wasn't working the way you wanted... The motion path is all based on the underlying path, thus it has a very particular starting point and ending point. So your objects would jump to that starting point initially, but it sounds like you wanted a different behavior, like to have it figure out where the closest spot on that path was to where your outter-orbit elements happened to be sitting. That's not something the plugin does for you. It's not a trivial thing to do, but there are several techniques you could use. That being said, you probably don't need that because Craig provided a cleaner solution anyway. The data you generated in "motionPath" was all based on offsets from "#outter-orbit-1", and you tried applying that to "#outter-orbit-2" as well. You actually did the right thing creating "motionPath2" but forgot to use that in your tween You forgot to set the xPercent and yPercent on "#outter-orbit-2" to -50 too Let us know if you need anything else.
  5. As for immediateRender:false, it's only true by default in these cases: on a timeline.set() that's at the very beginning of a timeline (startTime:0). If it's anywhere else on the timeline, immediateRender will be false. any from() or fromTo() tweens on a loose (not timeline-based) set() call You should never have to set immediateRender:false on a to() tween. Ever. That's the default (well, unless the duration is 0 for obvious reasons). In practical usage, it should rarely be necessary to set immediateRender:false.
  6. I really don't think we need to bloat the official API further with that type of thing when it'd be relatively easy to just build your own functions around whatever you need to parameterize, like: //parameterize whatever you want...whatever changes often function scene1(d) { var tl = new TimelineLite(); tl.to(".box1", d, {...}) .to(".box2", d, {...}, 0) .fromTo(".box3", d, {...}, {...}, 0); return tl; } //create a master timeline and drop in whatever you want, nesting scene1()... var master = new TimelineLite(); master.to(...) .add(scene1(2), "+=1") That way, you can just tweak the duration (or whatever you find yourself needing to change often) via simple parameters. This approach also makes your code much more modular and easy to shift around. Like if you want to put scene1() later or earlier, it's trivial. Also remember that if you're doing the same tween to a bunch of stuff, you can just pass them all in as the target (array or selector text). And have you seen the function-based values? Those might also come in handy at times. Read more at https://greensock.com/1-19-0/ Does that help at all?
  7. It looks like the problem is that when you introduce bootstrap, it's hiding the elements in a way that causes the browser to incorrectly report their dimensions via the standard getBBox() method that's common to all SVG elements. Here's an example you can drop into your code: console.log(document.getElementById("box").getBBox()); Notice that's returning x:0, y:0, width:0, height:0 which is why everything looks like its origin is in the top left corner. The only solution I know of is to make sure your tweens start when the element is actually in the DOM and not display:none.
  8. Yeah, Craig is right - that's generally what variables are for The problem with building some sort of API functionality like "until labelXYZ" or "until the end of the timeline" is that it'd require constant re-calculation and GSAP is highly optimized for performance. So if, for example, you have 500 tweens in a timeline and then you move one of them, it'd have to loop through EVERY tween and say "is that one affected by this change?", and then if it was, it could affect one that already changed too and it'd get crazy with recursion. Or internally we'd have to set up dependencies/listeners for timing changes and have those ripple out, but that's more kb and processing. The benefit just doesn't seem worth the cost, especially if it's not terribly difficult for users to do now using variables. See what I mean?
  9. Nah, performance-wise it's almost the same. I guess technically it's an extra function call if you nest it, but you'd never notice any real-world difference unless maybe you're nesting things hundreds of levels deep and there are thousands and thousands of simultaneous tweens. Actually, in some cases nesting can actually improve performance. Happy tweening!
  10. I'm so sorry about that! You're absolutely right - it was only an issue on the CustomEase page and for some silly reason I was looking at other pages. My apologies. It should be resolved now. You may need to clear your cache. Better?
  11. For the record, browsers always snap "top" and "left" values to whole pixels anyway, so even if you turn off GSAP's autoRound feature, it won't look any different. For example, if GSAP sets element.style.left = "50.4px" the browser will just make it "50px". As Jonathan suggested, I'd stick with "x". And I do find it very odd that you want the tween to actually stop before it reaches its destination (rather than just tweaking the destination), but you could do it by using an onUpdate that checks how close it is to the final value and just kill() the tween whenever you want. Or tween the tween's progress value to a smaller value, like 0.98. Lots of options.
  12. Good solution, Craig. I like the demo that prints out values. I went about things slightly differently mostly because his array of values aren't equidistant. Like 0, 45, 90, 120... (notice it doesn't always jump by 45). Cheers!
  13. Interesting - I've never heard of someone wanting to use percentages for Draggable. Hm. Since you didn't provide a codepen, I'm not entirely sure I understand your question properly, but have you tried using Draggable.update()? Also beware that transform percentages are always in relation to the element itself, not the window or parent. I'm curious why you wouldn't use normal px-based transforms, especially if you can do something like element.offsetWidth * 0.5 or something. Not saying it's wrong - just curious.
  14. I know PointC is working on an answer (which will no doubt be helpful), but I figured I'd sneak in and offer my perspective.... Here's a forked version that I think does what you're asking: http://codepen.io/GreenSock/pen/JEgwZR?editors=0010 Notice I'm using a function for the liveSnap and running some logic in there that finds the closest value and uses the modulus operator to keep it between 0 and 360. I removed the bounds because that's redundant and actually gets in the way anyway. I also simplified that logic you're running on every drag to figure out the positional index - this way is much faster and easier. Here's the pertinent code: var knob = document.getElementById("knob"); var previousPosition = 0; var position = 0; var currentRotation = 0; var snaps = [0, 45, 90, 120, 150, 180, 210, 240, 270, 315, 360]; //array of rotational snapping points (in degrees) //create the knob Draggable Draggable.create(knob, { type: "rotation", edgeResistance: 0.85, onDrag: onRotateKnob, onThrowUpdate: onRotateKnob, liveSnap: function(value) { position = getClosestIndex((value + 360 * 99999999) % 360, snaps); //adding 360 * 999999999 in order to ensure it's always a positive rotational value return snaps[position]; } }); //when the user drags the knob, we must update the scroll position. We're using the special scrollProxy object of Draggable because it allows us to overscroll (normal browser behavior won't allow it to scroll past the top/bottom). function onRotateKnob() { //do stuff } function getClosestIndex(value, choices) { var i = choices.length; var closest = 0; var absDif = 9999999999; var dif, val; while (--i > -1) { val = choices[i]; dif = Math.abs(val - value); if (dif < absDif) { closest = i; absDif = dif; } } return closest; } Does this help?
  15. I'm so confused - what exactly is the problem? When you're not logged in, that CustomEase download should be locked (as it shows in your screen capture). If you're logged in, you get access to it. Everything looks correct from what I can tell. What file is going from 106kb to 588.75kb? Are you talking about the zip file? Which two are you comparing? The first screen shot doesn't even have a download (it's locked). I really want to help but I'm not quite clear on what the problem is that you're trying to describe.
  16. Yep, Blake is exactly right - just use a generic object with x/y properties and tap into those. As for performance, yeah, if you're just doing a simple render loop with a few calculations manually for thousands of particles, that'll probably always be faster than GSAP (unsurprisingly) even though GSAP is super optimized. But in general animating that way is a pain in the neck workflow-wise (sequencing, easing, etc.) and you lose a ton of the benefits of GSAP (lag smoothing, browsers inconsistency workarounds, random access, etc.). That's not to say it's "bad" to do stuff manually at all - sometimes it's smart (like massive quantities of particles). I'm just saying that a workhorse like GSAP with all of its capabilities can't be expected to compete performance-wise with a simple render loop for thousands of particles BezierPlugin isn't really built to be used apart from the core of GSAP, no. Could it be hacked to work that way? Sure, but it's not really something we support or want to promise future support for (a hack that works today might not work with a future update) so I kinda want to steer clear of offering hacks like that.
  17. If I understood your question correctly, this issue actually has to do with how Safari decides to render circles. You see, the line must start somewhere and pretty much every other browser starts it at the 3 O'Clock position whereas Safari doesn't. Think of it like when you draw a circle with a pen, you'd put your pen down somewhere and draw the circle all the way around, but you could start at the top, left, right, bottom, or anywhere really. I don't think the spec actually dictates anything in particular so it's just kind of an oddity in how Safari works with <circle> elements. One solution would be to convert the <circle> to a <path> so that it's not up to the browser to decide where it should start. You could use a tool like Illustrator to do that conversion or MorphSVGPlugin.convertToPath(). Does that clear things up?
  18. I'm not quite sure what you mean. The code I provided determines the position(s) the first time the timeline renders; it almost sounds like maybe you're calling the functions at the wrong time or something. It'd REALLY help if you created a reduced test case in codepen to demonstrate the issue so we can take a peek and understand better. Doable?
  19. I didn't have much time to look at this, but what jumped out to me was that you're trying to JSON-ify something with this: onUpdate: function() { canvas.renderAll();} But that's not really possible. JSON is basically strings/numbers, but you've got a function that's trying to call a very particular method of a particular object - those reference things in memory that cannot be JSON-ified. You'd probably need to build special logic in to accommodate things like that on both ends (encoding and decoding).
  20. Hm, I can't really think of a way to do that. Draggable would have to discern which behavior you want immediately on touch, but that doesn't seem possible. Sorry. Wish I had an easy solution for you.
  21. If I understand your question properly, you could just have your turnButtonOn() and turnButtonOff() methods return tween/timeline instances so that you can easily sequence things in your customAnimation() method. For example: display = { turnButtonOn: function() { var tl = new TimelineLite(); //...add animations to tl... return tl; }, turnButtonOff: function() { var tl = new TimelineLite(); //...add animations to tl... return tl; }, customAnimation: function() { var tl = new TimelineLite(); tl.add(display.turnButtonOn()) .to(...).to(...) //add custom stuff .add(display.turnButtonOff()); return tl; } } Does that help?
  22. Yep, Craig is exactly right. Basically, TweenLite (the core) can animate any numeric property of any JavaScript object without needing any plugins. But some things require special handling like CSS properties that are put onto the "style" object of the element. And to get the current value, it's not as simple as element.style.property - you've got to getComputedStyle(). That's why plugins exist - to layer functionality on top of the core capabilities. So yeah, by far the most popular plugin on the web would be CSSPlugin (which is included INSIDE of TweenMax too, by the way). If you find yourself needing some other capability (morphing, drawing a line, directional rotation, etc.), that's where the plugins come in. Does that answer your question?
  23. Yeah, I'm very curious about this - are you saying that download overlay pops up automatically and you can't get rid of it by clicking off of it somewhere? Any chance you could provide more details (browser, OS, where to click, etc.)? I definitely want to make sure this is taken care of, but I'm struggling to understand how to reproduce the issue.
  24. I didn't have time to look into that setTimeout() thing, but I can speak to the easing stuff - the string you pass to CustomEase can only contain cubic bezier data ("C", "c", "M", "s", "S" or "L" commands). To accommodate the other commands, it'd almost double the file size of CustomEase, so it didn't seem worthwhile especially since we provide the Ease Visualizer tool that converts anything into the standard format. In other words, you can just run your string through the Ease Visualizer to have it spit back the parsed version that's cleaned up. Keeps file size tight. Does that answer your question?
  25. I feel your pain. And I appreciate your kind words about GSAP. We lived in Flash every day for years and it still has a warm spot in my heart, but I haven't even opened it for months...probably over a year actually. Part of me relishes the challenge of building a GreenSock-ified version of CreateJS and I absolutely see the value of having a GUI to drag stuff around on timelines. Certain animations can really benefit from that. But it's a HUGE undertaking to build from scratch. It's not something we have the resources to tackle at this point. Grant Skinner (the main author of CreateJS) is a very skilled developer and I have lots of respect for him. I think it'd be smart to have Adobe use GSAP as the runtime animation engine for whatever is build in the IDE, but I'm sure that's not a simple undertaking for them to rip out the current guts and swap in GSAP. Then again, maybe it's not that hard. I don't know, but if it's something you wish Adobe would do, I'd encourage you to tell them. Sometimes I get the impression that it's hard for the big software companies to really understand what the market wants when they've got a lot of momentum internally going toward certain feature sets they decided were important. That's not a criticism of Adobe - I'm just saying it's probably hard for them to know unless they hear from a lot of developers. Make your voice heard. We did briefly chat about the GSAP+Adobe combo with them years ago and they've always been very kind but it just didn't fit into their roadmap at that time. Maybe they'll reconsider at some point, and we'd certainly be open to chatting again, but their cooperation would be essential for something like this to get off the ground. We can't just hook into their IDE and make it spit out a GSAP-ified version of all the animations. Even if we figured out a way to do that today (without their help), they could release an update next week that breaks everything we did. That's why it's so critical to have a solid commitment from them and plenty of cooperation. In the mean time, I bet that most of the things you build visually in Flash could be accomplished in GSAP raw in the browser without depending on Flash at all. Yes, it'd take a little time for you to get up to speed on the API and how to build your stuff in HTML/CSS, but most people I've talked to who took the plunge tell me that they now LOVE it and would never want to go back, much like @Vitality said above. Thanks again for taking the time to share your idea/suggestion. I really wish I could snap my fingers and make this happen.
×
×
  • Create New...