@strategicprojects/rpic 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +121 -11
- package/package.json +1 -1
- package/pkg/rpic_wasm_bg.wasm +0 -0
- package/pkg/rpic_wasm_math_bg.wasm +0 -0
package/index.js
CHANGED
|
@@ -63,7 +63,9 @@ function ensure() {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
* Compile pic source into `{ svg, animations, diagnostics, warnings, objects }`
|
|
66
|
+
* Compile pic source into `{ svg, animations, diagnostics, warnings, objects }`
|
|
67
|
+
* (throws on a pic error). A top-level `scroll: true` is present when the source
|
|
68
|
+
* used `animate scroll` — a hint to scrub the timeline on scroll (see `animate`).
|
|
67
69
|
* @param {string} src
|
|
68
70
|
* @param {{circuits?: boolean, texlabels?: boolean}} [opts]
|
|
69
71
|
*/
|
|
@@ -93,8 +95,8 @@ export function renderSvg(src, opts) {
|
|
|
93
95
|
* Build a GSAP timeline from a drawing's animation manifest and play it on the
|
|
94
96
|
* SVG inside `root`. Browser-only (needs the DOM and a GSAP instance).
|
|
95
97
|
* @param {Element} root container holding the injected SVG
|
|
96
|
-
* @param {Array<{id:string,effect:string,start:number,duration:number}>} animations
|
|
97
|
-
* @param {*} gsap the GSAP instance
|
|
98
|
+
* @param {Array<{id:string,effect:string,start:number,duration:number,repeat?:number,yoyo?:boolean,ease?:string,path?:string,color?:string,out?:boolean,from?:string,morph?:string}>} animations
|
|
99
|
+
* @param {*} gsap the GSAP instance (register MotionPathPlugin for `move`, MorphSVGPlugin for `morph`)
|
|
98
100
|
* @returns the GSAP timeline
|
|
99
101
|
*/
|
|
100
102
|
export function animate(root, animations, gsap) {
|
|
@@ -106,25 +108,131 @@ export function animate(root, animations, gsap) {
|
|
|
106
108
|
if (!el) continue;
|
|
107
109
|
switch (a.effect) {
|
|
108
110
|
case 'fade':
|
|
109
|
-
tl
|
|
111
|
+
enterExit(tl, el, withOverrides({ opacity: 0, duration: a.duration, ease: 'power1.out' }, a), a);
|
|
110
112
|
break;
|
|
111
113
|
case 'pop':
|
|
112
|
-
|
|
114
|
+
enterExit(
|
|
115
|
+
tl,
|
|
113
116
|
el,
|
|
114
|
-
{ scale: 0, transformOrigin: '50% 50%', duration: a.duration, ease: 'back.out(1.7)' },
|
|
115
|
-
a
|
|
117
|
+
withOverrides({ scale: 0, transformOrigin: '50% 50%', duration: a.duration, ease: 'back.out(1.7)' }, a),
|
|
118
|
+
a
|
|
116
119
|
);
|
|
117
120
|
break;
|
|
121
|
+
case 'slide':
|
|
122
|
+
slideIn(tl, el, a);
|
|
123
|
+
break;
|
|
118
124
|
case 'draw':
|
|
119
125
|
drawOn(el, a, tl);
|
|
120
126
|
break;
|
|
127
|
+
case 'move':
|
|
128
|
+
moveAlong(root, el, a, tl);
|
|
129
|
+
break;
|
|
130
|
+
case 'morph':
|
|
131
|
+
morphInto(root, el, a, tl);
|
|
132
|
+
break;
|
|
133
|
+
case 'highlight':
|
|
134
|
+
highlightWith(el, a, tl);
|
|
135
|
+
break;
|
|
121
136
|
default:
|
|
122
|
-
tl
|
|
137
|
+
enterExit(tl, el, withOverrides({ opacity: 0, duration: a.duration }, a), a);
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
140
|
return tl;
|
|
126
141
|
}
|
|
127
142
|
|
|
143
|
+
// Entrances tween FROM the hidden `vars` to the natural state; `out` reverses
|
|
144
|
+
// it into an exit (TO the hidden state). Shared by fade/pop/slide.
|
|
145
|
+
function enterExit(tl, el, vars, a) {
|
|
146
|
+
return a.out ? tl.to(el, vars, a.start) : tl.from(el, vars, a.start);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// The `slide` effect: enter (or, with `out`, leave) by translating from a
|
|
150
|
+
// compass direction, offset by the element's own extent so it clears its slot.
|
|
151
|
+
function slideIn(tl, el, a) {
|
|
152
|
+
let bb = { width: 0, height: 0 };
|
|
153
|
+
try {
|
|
154
|
+
bb = el.getBBox();
|
|
155
|
+
} catch {
|
|
156
|
+
/* not yet laid out */
|
|
157
|
+
}
|
|
158
|
+
const off = {
|
|
159
|
+
left: { x: -(bb.width * 1.5 || 40) },
|
|
160
|
+
right: { x: bb.width * 1.5 || 40 },
|
|
161
|
+
up: { y: -(bb.height * 1.5 || 40) },
|
|
162
|
+
down: { y: bb.height * 1.5 || 40 },
|
|
163
|
+
}[a.from || 'left'];
|
|
164
|
+
enterExit(tl, el, withOverrides({ ...off, opacity: 0, duration: a.duration, ease: 'power2.out' }, a), a);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Fold the optional GSAP overrides (repeat/yoyo/ease) into a tween's vars.
|
|
168
|
+
// `ease` replaces the effect's default easing; repeat/yoyo loop the tween.
|
|
169
|
+
function withOverrides(vars, a) {
|
|
170
|
+
if (a.repeat) vars.repeat = a.repeat;
|
|
171
|
+
if (a.yoyo) vars.yoyo = true;
|
|
172
|
+
if (a.ease) vars.ease = a.ease;
|
|
173
|
+
return vars;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// The `highlight` effect: emphasise `el`. With a target colour, tween the
|
|
177
|
+
// stroke of its geometry to that colour; without one, a colour-free scale
|
|
178
|
+
// pulse. It's a one-directional `.to()` — pair with `repeat 1 yoyo` for a
|
|
179
|
+
// flash-and-return, or `repeat -1 yoyo` for a continuous pulse.
|
|
180
|
+
function highlightWith(el, a, tl) {
|
|
181
|
+
if (a.color) {
|
|
182
|
+
const shapes = el.querySelectorAll('path, polyline, line, rect, circle, ellipse, polygon');
|
|
183
|
+
tl.to(shapes, withOverrides({ stroke: a.color, duration: a.duration, ease: 'power1.inOut' }, a), a.start);
|
|
184
|
+
} else {
|
|
185
|
+
tl.to(
|
|
186
|
+
el,
|
|
187
|
+
withOverrides({ scale: 1.12, transformOrigin: '50% 50%', duration: a.duration, ease: 'power1.inOut' }, a),
|
|
188
|
+
a.start
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// The `morph` effect: tween `el`'s outline into the shape of the object
|
|
194
|
+
// `a.morph` references, via GSAP's MorphSVGPlugin. The consumer must have
|
|
195
|
+
// registered it (`gsap.registerPlugin(MorphSVGPlugin)`); without it GSAP
|
|
196
|
+
// no-ops the morphSVG and the shape stays put.
|
|
197
|
+
function morphInto(root, el, a, tl) {
|
|
198
|
+
if (!a.morph) return;
|
|
199
|
+
const tsel =
|
|
200
|
+
typeof CSS !== 'undefined' && CSS.escape ? '#' + CSS.escape(a.morph) : `[id="${a.morph}"]`;
|
|
201
|
+
const target = root.querySelector(tsel);
|
|
202
|
+
const sel = 'path, polyline, line, rect, circle, ellipse, polygon';
|
|
203
|
+
const src = el.querySelector(sel);
|
|
204
|
+
const dst = target && target.querySelector(sel);
|
|
205
|
+
if (!src || !dst) return;
|
|
206
|
+
tl.to(src, withOverrides({ morphSVG: dst, duration: a.duration, ease: 'power1.inOut' }, a), a.start);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// The `move` effect: travel `el` along the geometry of the object `a.path`
|
|
210
|
+
// references, via GSAP's MotionPathPlugin. The consumer must have registered
|
|
211
|
+
// it (`gsap.registerPlugin(MotionPathPlugin)`); without it GSAP no-ops the
|
|
212
|
+
// motionPath and the object simply stays put.
|
|
213
|
+
function moveAlong(root, el, a, tl) {
|
|
214
|
+
if (!a.path) return;
|
|
215
|
+
const psel =
|
|
216
|
+
typeof CSS !== 'undefined' && CSS.escape ? '#' + CSS.escape(a.path) : `[id="${a.path}"]`;
|
|
217
|
+
const group = root.querySelector(psel);
|
|
218
|
+
const pathEl = group && group.querySelector('path, polyline, line, polygon');
|
|
219
|
+
if (!pathEl) return;
|
|
220
|
+
// `align` maps the path into the traveller's coordinate space; a `move`
|
|
221
|
+
// tween is a `.to()` (current position → along the path), not a `.from()`.
|
|
222
|
+
tl.to(
|
|
223
|
+
el,
|
|
224
|
+
withOverrides(
|
|
225
|
+
{
|
|
226
|
+
motionPath: { path: pathEl, align: pathEl, alignOrigin: [0.5, 0.5], autoRotate: false },
|
|
227
|
+
duration: a.duration,
|
|
228
|
+
ease: 'none',
|
|
229
|
+
},
|
|
230
|
+
a
|
|
231
|
+
),
|
|
232
|
+
a.start
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
128
236
|
function drawOn(group, a, tl) {
|
|
129
237
|
const els = group.querySelectorAll('path, polyline, line, rect, circle, ellipse, polygon');
|
|
130
238
|
els.forEach((el) => {
|
|
@@ -146,14 +254,16 @@ function drawOn(group, a, tl) {
|
|
|
146
254
|
len = 0;
|
|
147
255
|
}
|
|
148
256
|
if (len > 0) {
|
|
257
|
+
// `out` reverses the trace: the stroke retracts (dashoffset 0 → len).
|
|
258
|
+
const [begin, end] = a.out ? [0, len] : [len, 0];
|
|
149
259
|
tl.fromTo(
|
|
150
260
|
el,
|
|
151
|
-
{ strokeDasharray: len, strokeDashoffset:
|
|
152
|
-
{ strokeDashoffset:
|
|
261
|
+
{ strokeDasharray: len, strokeDashoffset: begin },
|
|
262
|
+
withOverrides({ strokeDashoffset: end, duration: a.duration, ease: 'none' }, a),
|
|
153
263
|
a.start
|
|
154
264
|
);
|
|
155
265
|
} else {
|
|
156
|
-
tl
|
|
266
|
+
enterExit(tl, el, withOverrides({ opacity: 0, duration: a.duration }, a), a);
|
|
157
267
|
}
|
|
158
268
|
});
|
|
159
269
|
const texts = group.querySelectorAll('text');
|
package/package.json
CHANGED
package/pkg/rpic_wasm_bg.wasm
CHANGED
|
Binary file
|
|
Binary file
|