Jump to content
Search Community

MorphSVG in ReactJS

Figo test
Moderator Tag

Recommended Posts

Hi, I just became Club Greensock Member today! 👊

 

I've been searching all day for a MorphSVG tutorial in ReactJS, but haven't had much luck so far. I'm trying to morph one simple svg to another.

I've only been working in ReactJS for a couple of months now but comfortable with htmls,css,sass,js and some gsap.

 

Anyway I'm pretty sure the problem is GSAP is not recognising my svgs as I'm probably not calling the svgs correctly in my useEffect. My code looks something like this:

import gsap from 'gsap';
import { MorphSVGPlugin } from "gsap/MorphSVGPlugin";

import Shape1 from '../src/styles/components/assets/shape1.svg';
import Shape2 from '../src/styles/components/assets/shape2.svg';

gsap.registerPlugin(MorphSVGPlugin);
MorphSVGPlugin.convertToPath("circle, rect, ellipse, line, polygon, polyline");

useEffect(()=> {
  gsap.to(Shape1.current, {morphSVG: Shape2.current, duration:2});
})

Should I setup refs ( e.g. const Shape1 = useRef(null) )? 
Can anyone point me in the right direction, apologies for being a React noob
 

Link to comment
Share on other sites

I'm unfamiliar with MorphSVGPlugin, but it'd maybe help if you showed what the Shape1 and Shape2 look like - when I import SVGs like that, there typically isn't a "current" to access - "current" is typically a property on refs. This link might be helpful.

 

You'll also have a higher likelihood of receiving substantive help if you provide a codesandbox link with a demo example of your use-case. 

  • Like 3
Link to comment
Share on other sites

Hi @Figo

 

Good advice right here.

2 hours ago, granularclouds said:

You'll also have a higher likelihood of receiving substantive help if you provide a codesandbox link with a demo example of your use-case. 

 

You should be able to use the demo version of the plugin on CodeSandbox. Just use script tags instead of importing.

https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js
https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin3.min.js

 

It's hard to tell from the code what these imports actually are, elements, SVG document, string, etc. The plugin is designed to work with SVG path elements, element selectors for path elements, and path data strings.

 

import Shape1 from '../src/styles/components/assets/shape1.svg';
import Shape2 from '../src/styles/components/assets/shape2.svg';

 

 

 

  • Like 3
Link to comment
Share on other sites

On top of the already great advice by Blake and granularclouds, this is not going to work:

import gsap from 'gsap';
import { MorphSVGPlugin } from "gsap/MorphSVGPlugin";

import Shape1 from '../src/styles/components/assets/shape1.svg';
import Shape2 from '../src/styles/components/assets/shape2.svg';

gsap.registerPlugin(MorphSVGPlugin);
MorphSVGPlugin.convertToPath("circle, rect, ellipse, line, polygon, polyline");

useEffect(()=> {
  gsap.to(Shape1.current, {morphSVG: Shape2.current, duration:2});
})

Shape1 and Shape2 are definitions at the top of the file's scope, that come from importing a specific file, they are not React refs so neither has a current property, so that particular GSAP instance is not going to produce any results.

 

What you should do is take a path in your JSX, create a ref in it and use that in your useEffect hook:

const myShape = useRef();

useEffect(() => {
  gsap.to(myShape.current, { morphSVG: Shape1, duration: 2 });
}, []);

return (
  <svg>
    <path ref={myShape} d="..." />
  </svg>
)

Finally always use a dependencies array in your useEffect hook in order to prevent it from being triggered every time the state or props of that component are updated.

 

Happy Tweening!!!

  • Like 3
Link to comment
Share on other sites

Thanks for the swift replies, I definitely think I'm not referencing my svg assets correctly which I want to morph. I would also just like to mention that my project has other gsap animantions (e.g. tl.from/to) which works perfectly so I'm not a complete noob.

 

I've created a code sandbox:

https://codesandbox.io/s/relaxed-shadow-93y4e?fontsize=14&hidenavigation=1&theme=dark

 

Blake I've never used a cdn in React JS, so I hope the script tags are correct.

 

Link to comment
Share on other sites

Hi,

 

No need for this actually:

const script = document.createElement("script");

script.src = "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js";
script.async = true;

document.body.appendChild(script);

const script2 = document.createElement("script2");

script.src =
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin3.min.js";
script.async = true;

document.body.appendChild(script2);

Also you're replacing the src attribute of the first constant and the second script tag has no src attribute.

 

Just install GSAP in the dependencies section and add the URL to the test Plugin file in the external resources section:

0w8g6HH.jpg

 

Then you should be able to find the MorphSVG plugin in the window object, so you can use gsap.registerPlugin(), something like this:

import { gsap } from "gsap";

gsap.registerPlugin(window.MorphSVGPlugin);

Happy Tweening!!!

  • Like 4
Link to comment
Share on other sites

Cool I've created the codesandbox earlier so fingers crossed for a response. Or if anyone has a link to a morphSVG done in a React JS in a codesandbox or tutorial or  video it would be super appreciated.

Link to comment
Share on other sites

1 hour ago, Figo said:

Or if anyone has a link to a morphSVG done in a React JS in a codesandbox

Sorry I don't have one, but just follow the same approach for a regular MorphSVG sample and store the path you want to morph using a useRef hook.

 

Finally you don't need to import the whole SVG file, all you need is the d attribute of the element you want, the rest is not really necessary.

 

Something like this:

import React, { useRef, useEffect } from "react";
import { gsap } from "gsap";

gsap.registerPlugin(window.MorphSVGPlugin);

const finalPath = "..."; // The path you want to morph to

const App = () => {
  const targetPath = useRef();
  
  useEffect(() => {
    gsap.to(targetPath.current, {
      duration: 2, repeat: -1, yoyo: true,
      morphSVG: finalPath
    });
  }, []);
  
  return (
    <div>
      <svg>
        <path ref={targetPath} d="..." />
      </svg>
    </div>
  );
};

Happy Tweening!!!

  • Like 4
Link to comment
Share on other sites

Thanks @Rodrigo, I really appreciate your response so much man. Can my svgs have multiple paths, e.g. d= "...." d="..."?

 

I read somewhere on the forums that @OSUblake  mentions that you need to convert svgs to path, so mine has multiple "d=" per svg when I convert them.

 

I left the original svgs in the codesandbox under assets, but did covert them.

https://codesandbox.io/s/relaxed-shadow-93y4e?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js
 

Link to comment
Share on other sites

I think Rodrigo meant assigning the finished SVG to the finalPath variable. In React you can assign JSX to variables - just make sure the brackets close off and it's valid JSX. If you need help converting SVG to valid JSX -> https://svg2jsx.com/

 

I don't think that tool is entirely necessary, but I also don't think your SVG is valid - just copy and paste the <SVG>...</SVG> from your asset files into your code. Google "inline SVG React" if you need some help on that front.

 

  • Like 1
Link to comment
Share on other sites

Nope a path can't have more than one d attribute.

 

Honestly is quite unclear to me what you're trying to do, beyond the fact that you want to morph some SVG paths, this because you haven't been able to provide a working sample. I encourage you to get your feet wet with SVG first, since you have some glaring issues with it and how it works. For example the fact that you added several d attributes to a single path, the fact that your svg tag doesn't have a viewbox and your paths are not visible right now. Also the path you're trying to morph right now is inside a <defs> tag.

 

Also you didn't included the link Blake provided for the test file of the MorphSVG Plugin.

 

This code in the morphAnimation.js file seems to do something, but I'm not sure if that's what you're after:

import React, { useRef, useEffect } from "react";
import { gsap } from "gsap";
gsap.registerPlugin(window.MorphSVGPlugin);
const finalPath = "M2883.73851,14.7479675 C2944.77177,14.7479675 2994.26316,64.3124718 2994.26316,125.427935 L2994.26316,1688.57207 C2994.26316,1749.70102 2944.76552,1799.25203 2883.70168,1799.25203 C2879.54668,1799.25203 2876.24772,1802.55348 2876.24772,1806.62602 C2876.24772,1810.69856 2879.54668,1814 2883.61614,1814 C2952.90552,1814 3009,1757.84503 3009,1688.57207 L3009,125.427935 C3009,56.1697756 2952.91308,0 2883.73851,0 L2736.36842,0 C2732.29895,0 2729,3.30144497 2729,7.37398374 C2729,11.4465225 2732.29895,14.7479675 2736.36842,14.7479675 L2883.73851,14.7479675Z"; // The path you want to morph to

const MorphAnimation = () => {
  const targetPath = useRef();

  useEffect(() => {
    gsap.to(targetPath.current, {
      duration: 2,
      repeat: -1,
      yoyo: true,
      morphSVG: finalPath
    });
  }, []);

  return (
    <div>
      <svg width="100%" viewBox="0 0 3500 2500">
        <path
          ref={targetPath}
          d="M1206,151 C1206,891 1206,1631 1206,2371 1206,2451.63357 1140.63357,2517 1060,2517 757,2517 454,2517 151,2517 70.36643,2517 5,2451.63357 5,2371 5,1631 5,891 5,151 5,70.36643 70.36643,5 151,5 454,5 757,5 1060,5 1140.63357,5 1206,70.36643 1206,151z"
        />
      </svg>
    </div>
  );
};

export default MorphAnimation;

Try playing with the MorphSVG Plugin in a regular codepen first, before jumping to a React app. You can use this starter pen from the GreenSock collection:

See the Pen RxBOrb by GreenSock (@GreenSock) on CodePen

 

Happy Tweening!!!

  • Like 2
Link to comment
Share on other sites

2 hours ago, Figo said:

Can my svgs have multiple paths, e.g. d= "...." d="..."?

 

No. Only 1 d="..." per <path> element. You can only morph 1 path data string, the d="..." into another path data string. 

 

I think you might need to go into your SVG editor and merge all the shapes into a compound path. That should create a single <path> element.

 

  • Like 3
Link to comment
Share on other sites

Thanks for all the great feedback, you guys are rockstars.

I did however include a working sample but maybe it's only accessible to myself? Here is the working sample => https://codesandbox.io/s/relaxed-shadow-93y4e?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js

I'm trying morph the phone.svg to the macbook.svg, that's all.


However thank you so much for the feedback, I'm sure with all the advice provided, I'll be able to get it right from here.

Have a great day everybody!

Link to comment
Share on other sites

I also realised that Sketch App is not great for exporting svgs as it creates multiple paths (which I use for my designs). Apologies as this has been throwing me off a bit. A fix for this is to use Adobe Illustrator which apparently has an compound path option. Thought I would leave this in the topic if anyone in the future experiences the same :)

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...