Skip to content

Commit 522f538

Browse files
v1.0.0
1 parent fb8120e commit 522f538

File tree

3 files changed

+399
-0
lines changed

3 files changed

+399
-0
lines changed

download-button/index.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!DOCTYPE html>
2+
<html lang="en" >
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>CodePen - Download Button Animation</title>
6+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
7+
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:400,500,700&amp;display=swap'><link rel="stylesheet" href="./style.css">
8+
9+
</head>
10+
<body>
11+
<!-- partial:index.partial.html -->
12+
<div class="container">
13+
14+
<a href="" class="button">
15+
<ul>
16+
<li>&#68;ownload</li>
17+
<li>&#68;ownloading</li>
18+
<li>Open File</li>
19+
</ul>
20+
<div>
21+
<svg viewBox="0 0 24 24"></svg>
22+
</div>
23+
</a>
24+
</div>
25+
26+
<!-- dribbble -->
27+
<a class="dribbble" href="https://dribbble.com/shots/7299868-Download-Buttons" target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a>
28+
<!-- partial -->
29+
<script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js'></script><script src="./script.js"></script>
30+
31+
</body>
32+
</html>

download-button/script.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
document.querySelectorAll('.button').forEach(button => {
2+
3+
let duration = 3000,
4+
svg = button.querySelector('svg'),
5+
svgPath = new Proxy({
6+
y: null,
7+
smoothing: null
8+
}, {
9+
set(target, key, value) {
10+
target[key] = value;
11+
if(target.y !== null && target.smoothing !== null) {
12+
svg.innerHTML = getPath(target.y, target.smoothing, null);
13+
}
14+
return true;
15+
},
16+
get(target, key) {
17+
return target[key];
18+
}
19+
});
20+
21+
button.style.setProperty('--duration', duration);
22+
23+
svgPath.y = 20;
24+
svgPath.smoothing = 0;
25+
26+
button.addEventListener('click', e => {
27+
28+
e.preventDefault();
29+
30+
if(!button.classList.contains('loading')) {
31+
32+
button.classList.add('loading');
33+
34+
gsap.to(svgPath, {
35+
smoothing: .3,
36+
duration: duration * .065 / 1000
37+
});
38+
39+
gsap.to(svgPath, {
40+
y: 12,
41+
duration: duration * .265 / 1000,
42+
delay: duration * .065 / 1000,
43+
ease: Elastic.easeOut.config(1.12, .4)
44+
});
45+
46+
setTimeout(() => {
47+
svg.innerHTML = getPath(0, 0, [
48+
[3, 14],
49+
[8, 19],
50+
[21, 6]
51+
]);
52+
}, duration / 2);
53+
54+
}
55+
56+
});
57+
58+
});
59+
60+
function getPoint(point, i, a, smoothing) {
61+
let cp = (current, previous, next, reverse) => {
62+
let p = previous || current,
63+
n = next || current,
64+
o = {
65+
length: Math.sqrt(Math.pow(n[0] - p[0], 2) + Math.pow(n[1] - p[1], 2)),
66+
angle: Math.atan2(n[1] - p[1], n[0] - p[0])
67+
},
68+
angle = o.angle + (reverse ? Math.PI : 0),
69+
length = o.length * smoothing;
70+
return [current[0] + Math.cos(angle) * length, current[1] + Math.sin(angle) * length];
71+
},
72+
cps = cp(a[i - 1], a[i - 2], point, false),
73+
cpe = cp(point, a[i - 1], a[i + 1], true);
74+
return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;
75+
}
76+
77+
function getPath(update, smoothing, pointsNew) {
78+
let points = pointsNew ? pointsNew : [
79+
[4, 12],
80+
[12, update],
81+
[20, 12]
82+
],
83+
d = points.reduce((acc, point, i, a) => i === 0 ? `M ${point[0]},${point[1]}` : `${acc} ${getPoint(point, i, a, smoothing)}`, '');
84+
return `<path d="${d}" />`;
85+
}

0 commit comments

Comments
 (0)