Skip to content

feat(2d): add Path component #700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jul 1, 2023
Merged

Conversation

levirs565
Copy link
Contributor

@levirs565 levirs565 commented May 20, 2023

This will add Path component to render and animate SVG path.

This is part of add Latex component pull request.

Path component will inherit Curve component. This component can morph between two SVG path.

Why Morphing Path is Necessary for Latex Tweening

When we render Latex, some character can render into different SVG path depending on its situtation.

For example: ( and ) character.

You can see these two math.

$$
\left( 1 \right)
$$

$$ \left( 1 \right) $$

$$
\left( {1 \over 2} \right)
$$

$$ \left( {1 \over 2} \right) $$

We can see that ( and ) in these two math look have two size. Path of ( character in two math are actually different. When tweening latex between these math, we must morph path of ( character.

@levirs565 levirs565 requested a review from aarthificial as a code owner May 20, 2023 04:17
@nick-bors
Copy link

Lets gooo!! one step closer to latex animation

Copy link
Contributor

@aarthificial aarthificial left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some problems with the tweening algorithm:

Subpaths disappear when tweening:

project.mp4
Code
import {makeScene2D} from '@motion-canvas/2d/lib/scenes';
import {Path} from '@motion-canvas/2d/lib/components';
import {createRef} from '@motion-canvas/core/lib/utils';
import {waitFor} from '@motion-canvas/core/lib';

export default makeScene2D(function* (view) {
  const path = createRef<Path>();
  view.add(
    <Path
      ref={path}
      lineWidth={8}
      stroke={'white'}
      data="M -200,0 h 100 M 100,0 h 100"
    />,
  );

  yield* waitFor(0.5);
  yield* path().data('M -200,100 h 100 M 100,0 h 100', 1);
  yield* waitFor(0.5);
});

The path gets closed during the transition

close.mp4
Code
import {makeScene2D} from '@motion-canvas/2d/lib/scenes';
import {Path} from '@motion-canvas/2d/lib/components';
import {createRef} from '@motion-canvas/core/lib/utils';
import {waitFor} from '@motion-canvas/core/lib';

export default makeScene2D(function* (view) {
  const path = createRef<Path>();
  view.add(
    <Path
      ref={path}
      lineWidth={8}
      stroke={'white'}
      data="M -200,-200 h 400 v 400"
    />,
  );

  yield* waitFor(0.5);
  yield* path().data('M -200,-200 v 400 h 400', 1);
  yield* waitFor(0.5);
});

Tweening to an empty path throws an error.

Code
import {makeScene2D} from '@motion-canvas/2d/lib/scenes';
import {Path} from '@motion-canvas/2d/lib/components';
import {createRef} from '@motion-canvas/core/lib/utils';
import {waitFor} from '@motion-canvas/core/lib';

export default makeScene2D(function* (view) {
  const path = createRef<Path>();
  view.add(
    <Path
      ref={path}
      lineWidth={8}
      stroke={'white'}
      data="M -200,-200 h 400 v 400"
    />,
  );

  yield* waitFor(0.5);
  yield* path().data('M 0,0', 1);
  yield* waitFor(0.5);
});

levirs565 and others added 3 commits May 27, 2023 10:11
Co-authored-by: Jacob <64662184+aarthificial@users.noreply.github.com>
Added function:
- static function `angleBetween` to calculate angle between two vector.
- `cross` to calc length of cross product of current vector and other.
@levirs565 levirs565 force-pushed the path branch 2 times, most recently from 217dc14 to 931a4d9 Compare May 27, 2023 03:20
levirs565 and others added 4 commits May 28, 2023 11:42
Use getBBox to calculate arc extreme point

Co-authored-by: Jacob <64662184+aarthificial@users.noreply.github.com>
Add points property to Segment and implement in all Segment subclass
Co-authored-by: Jacob <64662184+aarthificial@users.noreply.github.com>
levirs565 added 2 commits May 28, 2023 11:54
Path balancing mechanism
If a path lacks subpaths, a new subpath is added  to it. A new subpath
consists of 1 LineSegment that first point and end point is first point
of subpath in another path that have same index.
This also prevent filled area gone when morphing
between closed and unclosed path.
levirs565 added 4 commits May 28, 2023 21:22
This is more simple and performant approach than before.
This happened especially when arc segment is first segment.
When close path contain arc then it will parsed as 2 open path.
@levirs565
Copy link
Contributor Author

I have fixed all issue.

Kute.js svgMorph actually cannot tween unclosed path well. Its also caanot tween between closed and unclosed path. It only can tween unclosed single line into closed shape. I create my own implementation to do that. I implement 2 method in 2 commit.

  • First method is to immitate how kute.js morph single line into circle. When createCurveProfileLerp encounter twening between closed and unclosed path, it will force close unclosed path. However, this will make filled area gone. To prevent this, we must add extra polygon. This method is on feat(2d): morph between closed and unclosed path
  • Second method is simpler than first. It will not force close unclosed path which means filled area not gone. When interpolatin from unclosed to closed path, first all point is interpolated like unclosed path. When first point and last point is equal then path closed automatically. This will make different interpolation than first method but with simpler and performant code. This method is on feat(2d): simple closed and unclosed path morphing.

In my opionion, we must use second method. Although the interpolation is different from KUTE.js, the code is much simpler and performant.

@levirs565 levirs565 requested a review from aarthificial June 7, 2023 14:24
Copy link
Contributor

@aarthificial aarthificial left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is generally good for merging but the documentation requires some updates.
Since #712, fiddles (```tsx editor) are required to correctly import all modules they use.

@levirs565 levirs565 requested a review from aarthificial June 28, 2023 11:42
@levirs565
Copy link
Contributor Author

I have fixed documentation error.

@aarthificial aarthificial merged commit 2128b6b into motion-canvas:main Jul 1, 2023
@aarthificial
Copy link
Contributor

Awesome! Thanks for the PR and apologies for the delays.

@ksassnowski
Copy link
Contributor

Thanks a ton @levirs565! Whenever you're ready, please go ahead and open the next PR. We really appreciate your work on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants