YYSuni
cover

Path Motion Methods

I collect several implementations of Path Motion and summarizing my own evaluations of them.

https://path-motion.yysuni.com/

1. CSS

First, the first method is the CSS way.

Using offset-path, and employing animation to make offset-distance go from 0% to 100%.

offset-path: path('M179.43,103.86 ...');
animation: move 3000ms infinite ease-in-out;

2. SVG

The second, SVG

<path
	fill='none'
	stroke='lightgrey'
	d='M179.43,103.86 ...'
/>

<rect width="16" height="16" fill='rgb(75, 85, 99)'>
	<animateMotion
		dur='3s'
		rotate='auto'
		repeatCount='indefinite'
		path='M179.43,103.86 ...'
		calcMode='spline'
		keyTimes='0; 1'
		keySplines='0.5 0 0.5 1'
	/>
</rect>

3. JS

The last is control through JavaScript code.

import { animate } from 'motion'
import { useEffect, useRef } from 'react'
import { getPointAtLength, getTotalLength } from 'svg-path-commander'

const d = 'M179.43,103.86 ... '
const pathLength = getTotalLength(d)

export default function JSMotion() {
	const ref = useRef<HTMLDivElement>(null)

	useEffect(() => {
		if (ref.current) {
			animate(0, 100, {
				repeat: Infinity,
				ease: 'easeInOut',
				onUpdate: latest => {
					const currentLength = (latest / 100) * pathLength
					const { x: currentX, y: currentY } = getPointAtLength(d, currentLength)
					ref.current!.style.left = currentX + 'px'
					ref.current!.style.top = currentY + 'px'

					const { x: nextX, y: nextY } = getPointAtLength(d, currentLength + 1)
					const dx = nextX - currentX
					const dy = nextY - currentY
					const angle = Math.atan2(dy, dx) * (180 / Math.PI) + 90

					ref.current!.style.rotate = angle + 'deg'
				},
				duration: 3
			})
		}
	}, [ref.current])

	return (
		<div className=' relative w-full h-[400px] bg-gray-50 rounded border'>
			<div ref={ref} className='w-4 h-4 bg-gray-600 absolute'></div>
		</div>
	)
}

Experience

CSS is relatively simple and can be directly applied in a normal HTML environment. The SVG approach, however, relies on a stable SVG environment, where the size is scaled according to the SVG dimensions. Fine-tuning the easing effect requires using keySplines, which demands some careful adjustment.

The movement in CSS is similar to a relative offset effect. In contrast, SVG involves setting x and y values within the SVG environment.

For JavaScript, the implementation depends on an animate library, a path utility library (svg-path-commander), and some calculations.

For simple loop animations or single-play animations, CSS is more convenient and efficient. SVG can quickly scale according to the page size.

JavaScript, on the other hand, can orchestrate multiple playback logics and is suitable for complex animations.

TABLE OF CONTENTS