Jump to content
Search Community

OSUblake last won the day on September 16 2023

OSUblake had the most liked content!

OSUblake

Moderators
  • Posts

    9,196
  • Joined

  • Last visited

  • Days Won

    708

Everything posted by OSUblake

  1. Now if a component has a bunch children elements that you want to animate, you're going to have to get a reference to them somehow. Most common is probably with the useRef. function MySvg() { const svg = useRef(); const circle1 = useRef(); const circle2 = useRef(); const circle3 = useRef(); const rect1 = useRef(); const rect2 = useRef(); const rect3 = useRef(); useEffect(() => { gsap.to([circle1.current, circle2.current, circle3.current], { x: 100 }); gsap.to([rect1.current, rect2.current, rect3.current], { y: 200 }); }, []); return ( <svg ref={svg}> <circle ref={circle1}></circle> <circle ref={circle2}></circle> <circle ref={circle3}></circle> <rect ref={rect1}></rect> <rect ref={rect2}></rect> <rect ref={rect3}></rect> </svg> ); } If we had an option to pass in the context, we could eliminate all those useRefs except for the parent one, and just use query strings, greatly reducing the amount of code. function MySvg() { const svg = useRef(); useEffect(() => { gsap.to("circle", { context: svg.current, x: 100 }); gsap.to("rect", { context: svg.current, y: 200 }); }, []); return ( <svg ref={svg}> <circ></circle> <circ></circle> <circ></circle> <rect></rect> <rect></rect> <rect></rect> </svg> ); }
  2. Well, let's first go over the biggest problem I see with React users, they don't use refs. They assume the selector string is just going to target that component, but if you use that component more than once, it's not going to animate correctly. This is supposed to animate the first box to 100 with a color of red, the second box to 200 with a color of green, and the third box to 300 with a color of yellow, but it doesn't happen. https://codepen.io/osublake/pen/581c7a732f60e8322b5b543f4691a77b Correct behavior using refs. https://codepen.io/osublake/pen/b8f05fd1700a1ef0c41ef1c41c9ca0fd
  3. How are you using shadow DOM without web components? AFAIK that's the only way.
  4. I don't even know how that could work as a default. How would it get a reference to this.shadowRoot? Where I see this being the most helpful is with component frameworks like React. People wouldn't have to contemplate the best way to stagger elements.
  5. Yeah, that's probably the worst thing you could do. Why don't you convert that demo over to gsap 3, research how to scale a vector, and then I can provide more guidance. For reference, this is the vector that we want to scale. var point = { x: options.centerX + Math.cos(angle) * options.minRadius, y: options.centerY + Math.sin(angle) * options.minRadius };
  6. That's what I'm thinking. So like in React, the user could just pass in the parent element of component. function App() { const container = useRef(null); useEffect(() => { gsap.to(".box", { context: container.current, x: 100 }); }, []); return ( <div className="container" ref={container}> <div className="box"></div> <div className="box"></div> <div className="box"></div> <div className="box"></div> </div> ); }
  7. Yep. The main point is that you can define your animations anywhere. It doesn't have to be inside a method per se. The only bad place might be inside created as you won't be able to access any refs at that point in the lifecycle.
  8. Did you try it? 100% guaranteed it will be reachable. this does not point to the data object. The data properties are copied to this.
  9. He's saying you don't need to put anything related to GSAP on the data object. The data object is for reactive properties. GSAP animations are not reactive, and therefore you are putting additional overhead into your components by adding your animations to the data object. You can set your animations in any method, mounted, or from the vm passed in. It all points to the same instance. // this isn't needed data() { return {}; }, beforeRouteEnter(to, from, next) { next((vm) => { vm.foo(); console.log(vm.bar); // Hello }); }, // Or using mounted mounted() { this.foo(): console.log(this.bar); // Hello }, methods: { foo() { this.bar = "Hello"; } }
  10. Sorry, WordPress n00b here. Isn't there a way to not load the file to begin with?
  11. Your mouse image isn't in the DOM when your gsap code runs. You need to put your animation code inside useEffect functions and use refs instead of query strings. Tutorial using ScrollTrigger, but the concepts are still the same. https://edidiongasikpo.com/using-gsap-scrolltrigger-plugin-in-react
  12. Don't load your animation code on pages that don't use it.
  13. A way to do that more like how Vue handles refs. If a ref attribute appears more than once, it gets added to an array. Ex HTML: <div ref="container"> <div ref="box"></div> <div ref="box"></div> <div ref="box"></div> </div> BaseElement: class BaseElement extends HTMLElement { select(selector) { return this.shadowRoot.querySelectorAll(selector); } createRefs() { const $ = this.$ = {}; for (const node of this.shadowRoot.querySelectorAll("[ref]")) { const id = node.getAttribute("ref"); if (!$[id]) { $[id] = node; } else { if (Array.isArray($[id])) { $[id].push(node); } else { const list = []; list.push($[id], node); $[id] = list; } } } } } Ex JS: class MyComponenet extends BaseElement { connectedCallback() { this.createRefs(); gsap.to(this.$.container, { x: 100 }); gsap.to(this.$.box, { scale: 0.5 }); } }
  14. What do you think the API should look like? @GreenSock I think something like this would also be a nice addition, especially for people who use React, Vue, Angular. That way they wouldn't have to create a bunch of refs. But here is how I've handled that in web components. I extend a "BaseElement" class with some extra methods on it. If you're using a library like LitElement, you could do the same thing. class BaseElement extends HTMLElement { select(selector) { return this.shadowRoot.querySelectorAll(selector); } createIdCache() { this.$ = {}; for (const node of this.shadowRoot.querySelectorAll("[id]")) { this.$[node.id] = node; } } } So you would call createIdCache after the DOM is available, like in a connected callback. That will make any elements with an id available on the $ object. Or you could just use the select method. Ex HTML: <div id="container"> <div class="box"></div> <div class="box"></div> <div class="box"></div> </div> Ex JS: class MyComponenet extends BaseElement { connectedCallback() { this.createIdCache(); gsap.to(this.$.container, { x: 100 }); gsap.to(this.select(".box"), { scale: 0.5 }); } }
  15. Best place to start is by learning PixiJS, and following some of their examples. Once you get it built, animating the filter is super easy. https://pixijs.io/examples/#/filters-basic/displacement-map-flag.js Examples repo: https://github.com/pixijs/examples Docs: http://pixijs.download/release/docs/index.html
  16. Then maybe it's buffering. The canplaythrough event is just an estimate. You might need to download the video. Google how to create a BLOB and use that as a video source. But video is super complicated, and well beyond the scope of this forum. Here's a good place to start learning about all the different properties and events available. https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
  17. You should probably be doing .fromTo() animations. Let's say you animate the opacity .from() 0. If that animation gets invalidated when the opacity value is at 0.5, then the new animation will only animate the opacity to 0.5 instead of 1. .from() will always animate to the whatever the value is at that point in time.
  18. Here's a good example to learn from. https://codepen.io/GreenSock/pen/896549f0a83297debd9111fe9b205a97
  19. You really don't need gsap for that. I would just use some delayedCalls. https://codepen.io/osublake/pen/c0e1bc59e2c7779b291c117906cab8f8
  20. The first option should be faster as it has less function calls and object read/writes. Not saying the are no use cases for the second option, but performance isn't one of them.
  21. I originally made that ripple/wave animation in Pixi, but then I stumbled across a site that showed how SVG filters work basically the same, so it was pretty easy to convert. http://srufaculty.sru.edu/david.dailey/svg/SVGOpen2010/Filters2.htm http://srufaculty.sru.edu/david.dailey/svg/newstuff/Newlist.htm http://srufaculty.sru.edu/david.dailey/svg/texture/texturepage.htm
  22. How come I didn't make the list? I've been making SVG waves since 2015. https://codepen.io/osublake/pen/WQyBJb
  23. What are you trying to figure out? If you want to animate an list of elements, gsap needs an array or a nodelist. gsap.to([element1, element2, element3], { x: 100 }); Push will just keep adding to that list, so you end up with something like this. gsap.to([element1, element2, element3, element1, element2, element3,element1, element2, element3], { x: 100 }); You can ask the author. It's not necessary. Maybe they did it for clarity. ?‍♂️
  24. Yep. Did you look at the examples in the docs? That's pretty much the format they all use. https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.matchMedia() No that's not possible, but like I said earlier, you can put any code you want inside the matchMedia functions.
  25. Sorry, I still don't quite understand what you're asking. You can put whatever code you want into the matchMedia functions. Can you please put what you're trying to achieve into a demo? Media query events don't fire on resize, they fire on media query change events, so trying to debounce them is pointless.
×
×
  • Create New...