theolavaux Posted October 30, 2020 Share Posted October 30, 2020 Hello everyone, I'm getting started with the MorphSVG plugin and I want to create animation with two shapes that start changing shape at the same time and then halfway through the images height, they take back their original shape. I run into 2 major problems : First, my animation is not smooth, it abruptly changes shapes at the center of the image. The current behaviour that I have is that both shapes change shape until halfway in the animation, then one of my shapes abruptly goes back to its original shape at the center of the image. Then nothing happens on the last 50% of the size. Here is my code (Vue.js): mounted() { // Initalize GSAP Plugins if (process.client) { gsap.registerPlugin(ScrollTrigger, MorphSVGPlugin, GSDevTools) } // Intialize GSAP Devtools GSDevTools.create() // Create a Timeline const tl = gsap.timeline() // Use MorphSVG/scrollTrigger to animate SVG shapes tl.to( '#shape1', { scrollTrigger: { trigger: '#shape1', toggleActions: 'restart complete reverse reset', scrub: true, start: 'top 80%', end: 'center center', }, morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', duration: 1, }, 0 ) tl.to( '#shape2', { scrollTrigger: { trigger: '#shape2', toggleActions: 'restart complete reverse reset', scrub: true, start: 'top 80%', end: 'center center', }, morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', duration: 1, }, 0 ) tl.to( '#shape1', { scrollTrigger: { trigger: '#shape1', toggleActions: 'restart complete reverse reset', scrub: true, start: 'center center', end: 'bottom 20%', }, morphSVG: '#shape1', duration: 1, }, 1 ) tl.to( '#shape2', { scrollTrigger: { trigger: '#shape2', toggleActions: 'restart complete reverse reset', scrub: true, start: 'center center', end: 'bottom 20%', }, morphSVG: '#shape2', duration: 1, }, 1 ) } And my SVG <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none" viewBox="0 0 1280 1768.468" > <defs> <linearGradient id="linear-gradient" x1="1.023" y1="0.042" x2="0.144" y2="0.551" gradientUnits="objectBoundingBox" > <stop offset="0" stop-color="#dcedf0" /> <stop offset="1" stop-color="#bed4de" /> </linearGradient> <linearGradient id="linear-gradient-2" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox" > <stop offset="0" stop-color="#0a5088" /> <stop offset="1" stop-color="#1d7d86" /> </linearGradient> </defs> <g id="Group_491" data-name="Group 491" transform="translate(-1111 -1014.509)" > <path id="shape1" data-name="Shape 1" d="M444.239,541.067s46.093-49.294,165.931-72.65,264.607,29.95,320.529,24.858,85.356-35.216,107.544-63.625,15.243-63.424,60.188-144.222S1189.87,82.243,1346.321,14.515s377.918,0,377.918,0v1101.1S1620.05,971.641,1456.611,990.641C1382.083,999.3,1313.9,1031.767,1213.6,1135.3s-200.227,206.892-248.241,221.973-153.854,1.34-290.624,91.849-230.494,303.756-230.494,303.756Z" transform="translate(666.761 1030.095)" fill="url(#linear-gradient)" /> <path id="shape2" data-name="Shape 2" d="M444.239,704.163S460.753,594.087,600.6,527.483s284.2-31.2,309-30.8,73.125,3.938,117.858-48.514,61.484-122.372,79.192-154.028,80.3-198.455,236.75-227.023,380.842,104.037,380.842,104.037V942.466s-131.615-54.079-266.08,0-206.273,113.756-271.779,216.316S1051.336,1406.422,909.6,1367.02c-349.507-106.371-465.358,136.532-465.358,136.532Z" transform="translate(666.761 1030.095)" fill="url(#linear-gradient-2)" /> </g> </svg> Link to comment Share on other sites More sharing options...
ZachSaucier Posted October 30, 2020 Share Posted October 30, 2020 Hey theolavaux and welcome to the GreenSock forums. Thanks for supporting GreenSock with a Club GreenSock membership! You're making one of the most common ScrollTrigger mistakes: putting ScrollTriggers on tweens inside of timelines. Doing so doesn't make much sense. I think what you're trying to do instead is to create a single timeline with a single ScrollTrigger attached to it. Then add your morphs to that timeline. Link to comment Share on other sites More sharing options...
theolavaux Posted October 30, 2020 Author Share Posted October 30, 2020 Changed my Javascript to this, and its indeed working much much better, thanks a lot ! My animation timing problems are solved, I'm now left with the question of the changing width. Considering that I only give a path to change shape to, what could be the reason that my image changes width ? mounted() { // Initalize GSAP Plugins if (process.client) { gsap.registerPlugin(ScrollTrigger, MorphSVGPlugin, GSDevTools) } // Intialize GSAP Devtools GSDevTools.create() // Create a Timeline const tl = gsap.timeline({ // yes, we can add it to an entire timeline! scrollTrigger: { trigger: '#shape1', start: 'top 80%', end: 'bottom 20%', scrub: true, toggleActions: 'restart complete reverse reset', }, }) // Use MorphSVG/scrollTrigger to animate SVG shapes tl.to( '#shape1', { morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', duration: 1, }, 0 ) tl.to( '#shape2', { morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', duration: 1, }, 0 ) tl.to( '#shape1', { morphSVG: '#shape1', duration: 1, }, 1 ) tl.to( '#shape2', { morphSVG: '#shape2', duration: 1, }, 1 ) } Link to comment Share on other sites More sharing options...
ZachSaucier Posted October 30, 2020 Share Posted October 30, 2020 Can you please make a minimal demo? Link to comment Share on other sites More sharing options...
theolavaux Posted October 30, 2020 Author Share Posted October 30, 2020 (edited) See the Pen VwjXQzj by theolavaux (@theolavaux) on CodePen The only difference with my actual code is that in the Codepen I use svg { width: 100%; height: auto; } instead of both at 100%. I would like the image to always take up 100% of width because I use it like a background image. Edited October 30, 2020 by theolavaux Added some text to better reproduce my use case Link to comment Share on other sites More sharing options...
ZachSaucier Posted October 30, 2020 Share Posted October 30, 2020 The width of your SVG isn't changing at all. Your paths just don't take up the full SVG. I think it would help if you removed all the transforms from your SVG elements in the HTML section. It's best to use GSAP for any transforms that you want to have on elements that you're animating. 2 Link to comment Share on other sites More sharing options...
theolavaux Posted October 30, 2020 Author Share Posted October 30, 2020 (edited) I'll try that out ! Another question that came to my mind is : how can I have fine-control with a ScrollTrigger on the Timeline to allow the first part of the animation to last 50% of it (from 'top 80%' to 'center center'.), and the second part the other 50% (from 'center center' to 'bottom 20%') ? EDIT: Just replaced my transforms by these and it's working perfectly ! // Initial translations gsap.to('#shape1', { x: 666.761, y: 1030.095, }) gsap.to('#shape2', { x: 666.761, y: 1030.095, }) // Timeline translations tl.to( '#shape1', { morphSVG: '#shape1', x: 666.761, y: 1030.095, }, 1 ) tl.to( '#shape2', { morphSVG: '#shape2', x: 666.761, y: 1030.095, }, 1 ) Edited October 30, 2020 by theolavaux Added transforms in JS Link to comment Share on other sites More sharing options...
ZachSaucier Posted October 30, 2020 Share Posted October 30, 2020 32 minutes ago, theolavaux said: how can I have fine-control with a ScrollTrigger on the Timeline to allow the first part of the animation to last 50% of it (from 'top 80%' to 'center center'.), and the second part the other 50% (from 'center center' to 'bottom 20%') ? See How does duration work with scrub: true? in the ScrollTrigger docs. Link to comment Share on other sites More sharing options...
mikel Posted October 30, 2020 Share Posted October 30, 2020 Hey @theolavaux, If you want to animate the beginning and the end individually, maybe use separate shapes / parts. Here is an example with a very simple structure: See the Pen 5cbe8fb4a94c4f2e048c67739f354fe9?editors=1010 by mikeK (@mikeK) on CodePen Happy morphing ... Mikel 3 Link to comment Share on other sites More sharing options...
theolavaux Posted October 30, 2020 Author Share Posted October 30, 2020 That's what I was looking for @mikel! Thanks for help as well. I refactored my code to look like the following and it now fits my use case more. I probably still have something off in this code : my first timeline works fine, but for the second timeline, nothing seems to happen on the first 80% of the timeline and then the image actually morphs only in the last 20% or so of the scroller. That's what I found out using markers: true. I set "center center" as the end of timeline one and beginning of timeline two so that the morph doesn't stop and remains fluid. mounted() { // Initalize GSAP Plugins if (process.client) { gsap.registerPlugin(ScrollTrigger, MorphSVGPlugin, GSDevTools) } // Intialize GSAP Devtools GSDevTools.create() // Initial translations gsap.to('.path', { x: 666.761, y: 1030.095, }) // Create a Timeline const timeline1 = gsap.timeline({ scrollTrigger: { trigger: '#shape1', start: 'top 60%', end: 'center center', scrub: true, markers: true, }, }) const timeline2 = gsap.timeline({ scrollTrigger: { trigger: '#shape1', start: 'center center', end: 'bottom 40%', scrub: true, markers: true, }, }) // Use MorphSVG/scrollTrigger to animate SVG shapes timeline1.to( '#shape1', { morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', }, 0 ) timeline1.to( '#shape2', { morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', }, 0 ) timeline2.to( '#shape1', { morphSVG: '#shape1', x: 666.761, y: 1030.095, }, 1 ) timeline2.to( '#shape2', { morphSVG: '#shape2', x: 666.761, y: 1030.095, }, 1 ) } Link to comment Share on other sites More sharing options...
mikel Posted October 31, 2020 Share Posted October 31, 2020 Hey @theolavaux, For this concept, I have divided only one shape into an TOP and a BOTTOM part (= separate shapes = separate paths) - see the newly named paths. It doesn't work without this preparation. Do you see the difference? 1 Link to comment Share on other sites More sharing options...
mikel Posted October 31, 2020 Share Posted October 31, 2020 Hey @theolavaux, And another concept - SVG prep and coding See the Pen 942eb37a6652890b60145b61d62e5a9f by mikeK (@mikeK) on CodePen Happy morphing ... Mikel 1 Link to comment Share on other sites More sharing options...
theolavaux Posted October 31, 2020 Author Share Posted October 31, 2020 Hi @mikel, thank you for these examples, but I'm a bit confused about why I would need to split my SVGs into two parts. The first timeline in my example is working as expected and I don't understand why the second part isn't, even though it follows the same principle. My explanation was certainly not clear, but in the effect I want to create, the shape that I morph to (and back) is never fixed during the scroll, I would like to make sure that the svg never stops morphing along the whole length of the scroll, progressively from A to B in the first 50% and from B to A in the remaining 50%. What I have now is first morph -> nothing happens for a good portion of scroll -> second morph happens very late. Link to comment Share on other sites More sharing options...
Solution mikel Posted October 31, 2020 Solution Share Posted October 31, 2020 Hey @theolavaux, Then maybe like this ... See the Pen 2278160e0d7d0b46162ec02c4a5b7db5?editors=0010 by mikeK (@mikeK) on CodePen 2 1 Link to comment Share on other sites More sharing options...
theolavaux Posted October 31, 2020 Author Share Posted October 31, 2020 That's exactly the effect I was looking for, I'm trying it out ! I try to understand why you used 0.1 and -=0.9 in your animation timing, why not use the same method for both shapes ? And why 0.1 and 0.9 ? I have one final question, when I run my code with dev server, sometimes, I need to refresh the page several times for my ScrollTriggers to be placed correctly. I thought there might be a mistake while loading GSAP or so. I just tried out to run it it production mode and my trigger is again placed somewhere else. What could be causing this behaviour ? EDIT: Working as expected even with the SVG in one part. Thank you very much @mikel and @ZachSaucier! I'll showcase the effect on my website when the production version will be released! mounted() { // Initalize GSAP Plugins if (process.client) { gsap.registerPlugin(ScrollTrigger, MorphSVGPlugin, GSDevTools) } // Intialize GSAP Devtools GSDevTools.create() // Initial translations gsap.to('.path', { x: 666.761, y: 1030.095, }) // Create a Timeline gsap .timeline({ scrollTrigger: { trigger: '#shape1', start: 'top 20%', end: 'bottom 80%', scrub: true, markers: true, }, defaults: { duration: 1, ease: 'none' }, }) .to( '#shape1', { morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', }, 0.1 ) .to( '#shape2', { morphSVG: 'm2.00006,1l1279.99988,0l0,1767.99976l-1279.99988,0l0,-1767.99976z', }, 0 ) .to('#shape1', { morphSVG: '#shape1', x: 666.761, y: 1030.095 }) .to( '#shape2', { morphSVG: '#shape2', x: 666.761, y: 1030.095 }, '-=0.9' ) } Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now