Skip to content

Commit

Permalink
Add support for SVG animations (#5)
Browse files Browse the repository at this point in the history
* add initial version of svg animation crossing

* move animation forward for duration of view transition

* remove `svg-anim` kind and move svg animation logic into `anim` kind

* chore: add changeset

---------

Co-authored-by: Martin Trapp <[email protected]>
  • Loading branch information
Trombach and martrapp authored Oct 30, 2024
1 parent d8b18b2 commit d4fd998
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 25 deletions.
11 changes: 11 additions & 0 deletions .changeset/tidy-parents-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@vtbag/element-crossing': patch
---

Extend `anim` expression with support for SVG animations.

To transfer the SVG animation state to the new document use the `/svg` key for the `anim` expression

```html
<svg data-vtbag-x="id:svg anim:/svg">...</svg>
```
81 changes: 56 additions & 25 deletions src/vanilla.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ElementSpec, Spec } from './types';

const DEBUG = false;
const SVG_ANIM_KEY = '/svg';

const crossing = top!.__vtbag?.elementCrossing;
init();
Expand Down Expand Up @@ -147,18 +148,34 @@ function elementSpec(element: HTMLElement) {
});
break;
case 'anim':
const animations = element
.getAnimations()
.filter((a) => a instanceof CSSAnimation && a.animationName === key);
if (animations.length > 1) {
console.error(
'[crossing]',
`retrieval: animation name ${key} is not unique for`,
element
);
}
if (animations.length > 0) {
specs.push({ kind, key, value: '' + (animations[0].currentTime ?? 0) });
if (key === SVG_ANIM_KEY) {
if (!(element instanceof SVGSVGElement)) {
console.error(
'[crossing]',
`retrieval: element is not an SVG element, but "${key}" was used for its key`,
element
);
break;
}

const currentTime = element.getCurrentTime();
if (currentTime > 0) {
specs.push({ kind, key, value: currentTime.toString() });
}
} else {
const animations = element
.getAnimations()
.filter((a) => a instanceof CSSAnimation && a.animationName === key);
if (animations.length > 1) {
console.error(
'[crossing]',
`retrieval: animation name ${key} is not unique for`,
element
);
}
if (animations.length > 0) {
specs.push({ kind, key, value: '' + (animations[0].currentTime ?? 0) });
}
}
break;
case 'elem':
Expand Down Expand Up @@ -218,21 +235,35 @@ function restore(values: ElementSpec[]) {
(element as any)[s.key] = parseFloat(s.value ?? '0');
break;
case 'anim':
const animations = element!
.getAnimations()
.filter((a) => a instanceof CSSAnimation && a.animationName === s.key);
if (animations.length > 1) {
console.warn(
'[crossing]',
`restore: animation name ${s.key} is not unique for`,
element
if (s.key === SVG_ANIM_KEY) {
if (!(element instanceof SVGSVGElement)) {
console.error(
'[crossing]',
`restore: element for key ${s.key} is not an SVG element`,
element
);
break;
}
element.setCurrentTime(
parseFloat(s.value ?? '0') + (new Date().getTime() - elementSpec.timestamp) / 1000
);
} else {
const animations = element!
.getAnimations()
.filter((a) => a instanceof CSSAnimation && a.animationName === s.key);
if (animations.length > 1) {
console.warn(
'[crossing]',
`restore: animation name ${s.key} is not unique for`,
element
);
}
animations.forEach(
(a) =>
(a.currentTime =
~~(s.value ?? '0') + (new Date().getTime() - elementSpec.timestamp))
);
}
animations.forEach(
(a) =>
(a.currentTime =
~~(s.value ?? '0') + (new Date().getTime() - elementSpec.timestamp))
);
break;
case 'elem':
const crossing = top?.__vtbag?.elementCrossing;
Expand Down

0 comments on commit d4fd998

Please sign in to comment.