-
Notifications
You must be signed in to change notification settings - Fork 0
/
process.js
94 lines (91 loc) · 3.6 KB
/
process.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
gsap.registerPlugin(ScrollTrigger, MotionPathPlugin);
gsap.set("#motionSVG", { scale: 0.85, autoAlpha: 1 });
gsap.set("#bee", {transformOrigin: "50% 50%", scaleX: -1});
let getProp = gsap.getProperty("#motionSVG"),
flippedX = false,
flippedY = false;
gsap.to("#motionSVG", {
scrollTrigger: {
trigger: "#motionPath",
start: "top center",
end: 'bottom center',
scrub: 0.7,
markers: false,
onUpdate: self => {
let rotation = getProp("rotation"),
flipY = Math.abs(rotation) > 90,
flipX = self.direction === 1;
if (flipY !== flippedY || flipX !== flippedX) {
gsap.to("#bee", {scaleY: flipY ? -1 : 1, scaleX: flipX ? -1 : 1, duration: 0.25});
flippedY = flipY;
flippedX = flipX;
}
}
},
duration: 10,
ease: pathEase("#motionPath", {smooth: true}), // <-- MAGIC!
immediateRender: true,
motionPath: {
path: "#motionPath",
align: "#motionPath",
alignOrigin: [0.5, 0.5],
autoRotate: 0
}
});
/*
Helper function that returns an ease that bends time to ensure the target moves on the y axis in a relatively steady fashion in relation to the viewport (assuming the progress of the tween is linked linearly to the scroll position). Requires MotionPathPlugin of course.
You can optionally pass in a config option with any of these properties:
- smooth: if true, the target can drift slightly in order to smooth out the movement. This is especially useful if the path curves backwards at times. It prevents super-fast motions at that point. You can define it as a number (defaults to 7) indicating how much to smooth it.
- precision: number (defaults to 1) controlling the sampling size along the path. The higher the precision, the more accurate but the more processing.
- axis: "y" or "x" ("y" by default)
*/
function pathEase(path, config={}) {
let axis = config.axis || "y",
precision = config.precision || 1,
rawPath = MotionPathPlugin.cacheRawPathMeasurements(MotionPathPlugin.getRawPath(gsap.utils.toArray(path)[0]), Math.round(precision * 12)),
useX = axis === "x",
start = rawPath[0][useX ? 0 : 1],
end = rawPath[rawPath.length - 1][rawPath[rawPath.length-1].length - (useX ? 2 : 1)],
range = end - start,
l = Math.round(precision * 200),
inc = 1 / l,
positions = [0],
a = [],
minIndex = 0,
smooth = [0],
minChange = (1 / l) * 0.6,
smoothRange = config.smooth === true ? 7 : Math.round(config.smooth) || 0,
fullSmoothRange = smoothRange * 2,
getClosest = p => {
while (positions[minIndex] <= p && minIndex++ < l) { }
a.push(a.length && ((p - positions[minIndex-1]) / (positions[minIndex] - positions[minIndex - 1]) * inc + minIndex * inc));
smoothRange && a.length > smoothRange && (a[a.length - 1] - a[a.length - 2] < minChange) && smooth.push(a.length - smoothRange);
},
i = 1;
for (; i < l; i++) {
positions[i] = (MotionPathPlugin.getPositionOnPath(rawPath, i / l)[axis] - start) / range;
}
positions[l] = 1;
for (i = 0; i < l; i++) {
getClosest(i / l);
}
a.push(1); // must end at 1.
if (smoothRange) { // smooth at the necessary indexes where a small difference was sensed. Make it a linear change over the course of the fullSmoothRange
smooth.push(l-fullSmoothRange+1);
smooth.forEach(i => {
let start = a[i],
j = Math.min(i + fullSmoothRange, l),
inc = (a[j] - start) / (j - i),
c = 1;
i++;
for (; i < j; i++) {
a[i] = start + inc * c++;
}
});
}
return p => {
let i = p * l,
s = a[i | 0];
return i ? s + (a[Math.ceil(i)] - s) * (i % 1) : 0;
}
}