johnsmith007 commited on
Commit
b455d0c
·
verified ·
1 Parent(s): dc75b23
Files changed (1) hide show
  1. sakura.js +159 -0
sakura.js CHANGED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var Sakura = function Sakura(selector, options) {
2
+ var _this = this;
3
+
4
+ if (typeof selector === 'undefined') {
5
+ throw new Error('No selector present. Define an element.');
6
+ }
7
+
8
+ this.el = document.querySelector(selector); // Defaults for the option object, which gets extended below.
9
+
10
+ var defaults = {
11
+ className: 'sakura',
12
+ // Classname of the petal. This corresponds with the css.
13
+ fallSpeed: 1,
14
+ // Speed factor in which the petal falls.
15
+ maxSize: 14,
16
+ // The maximum size of the petal.
17
+ minSize: 10,
18
+ // The minimum size of the petal.
19
+ delay: 300,
20
+ // Delay between petals.
21
+ gradientColorStart: 'rgba(255, 183, 197, 0.9)',
22
+ // Gradient color start (rgba).
23
+ gradientColorEnd: 'rgba(255, 197, 208, 0.9)',
24
+ // Gradient color end (rgba).
25
+ gradientColorDegree: 120 // Gradient degree angle.
26
+
27
+ }; // Merge defaults with user options.
28
+
29
+ var extend = function extend(originalObj, newObj) {
30
+ Object.keys(originalObj).forEach(function (key) {
31
+ if (newObj && Object.prototype.hasOwnProperty.call(newObj, key)) {
32
+ var origin = originalObj;
33
+ origin[key] = newObj[key];
34
+ }
35
+ });
36
+ return originalObj;
37
+ };
38
+
39
+ this.settings = extend(defaults, options); // Hide horizontal scrollbars on the target element.
40
+
41
+ this.el.style.overflowX = 'hidden'; // Random array element
42
+
43
+ function randomArrayElem(arr) {
44
+ return arr[Math.floor(Math.random() * arr.length)];
45
+ } // Random integer
46
+
47
+
48
+ function randomInt(min, max) {
49
+ return Math.floor(Math.random() * (max - min + 1)) + min;
50
+ } // Check for animation events.
51
+
52
+
53
+ var prefixes = ['webkit', 'moz', 'MS', 'o', ''];
54
+
55
+ function PrefixedEvent(element, type, callback) {
56
+ for (var p = 0; p < prefixes.length; p += 1) {
57
+ var animType = type;
58
+
59
+ if (!prefixes[p]) {
60
+ animType = type.toLowerCase();
61
+ }
62
+
63
+ element.addEventListener(prefixes[p] + animType, callback, false);
64
+ }
65
+ } // Check if the element is in the viewport.
66
+
67
+
68
+ function elementInViewport(el) {
69
+ var rect = el.getBoundingClientRect();
70
+ return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
71
+ }
72
+
73
+ this.createPetal = function () {
74
+ if (_this.el.dataset.sakuraAnimId) {
75
+ setTimeout(function () {
76
+ window.requestAnimationFrame(_this.createPetal);
77
+ }, _this.settings.delay);
78
+ } // Name the animations. These have to match the animations in the CSS file.
79
+
80
+
81
+ var animationNames = {
82
+ blowAnimations: ['blow-soft-left', 'blow-medium-left', 'blow-soft-right', 'blow-medium-right'],
83
+ swayAnimations: ['sway-0', 'sway-1', 'sway-2', 'sway-3', 'sway-4', 'sway-5', 'sway-6', 'sway-7', 'sway-8']
84
+ }; // Get one random animation of each type and randomize fall time of the petals
85
+
86
+ var blowAnimation = randomArrayElem(animationNames.blowAnimations);
87
+ var swayAnimation = randomArrayElem(animationNames.swayAnimations);
88
+
89
+ var fallTime = (document.documentElement.clientHeight * 0.007 + Math.round(Math.random() * 5)) * _this.settings.fallSpeed; // Create animations
90
+
91
+
92
+ var animationsArr = ["fall ".concat(fallTime, "s linear 0s 1"), "".concat(blowAnimation, " ").concat((fallTime > 30 ? fallTime : 30) - 20 + randomInt(0, 20), "s linear 0s infinite"), "".concat(swayAnimation, " ").concat(randomInt(2, 4), "s linear 0s infinite")];
93
+ var animations = animationsArr.join(', '); // Create petal and give it a random size.
94
+
95
+ var petal = document.createElement('div');
96
+ petal.classList.add(_this.settings.className);
97
+ var height = randomInt(_this.settings.minSize, _this.settings.maxSize);
98
+ var width = height - Math.floor(randomInt(0, _this.settings.minSize) / 3);
99
+ petal.style.background = "linear-gradient(".concat(_this.settings.gradientColorDegree, "deg, ").concat(_this.settings.gradientColorStart, ", ").concat(_this.settings.gradientColorEnd, ")");
100
+ petal.style.webkitAnimation = animations;
101
+ petal.style.animation = animations;
102
+ petal.style.borderRadius = "".concat(randomInt(_this.settings.maxSize, _this.settings.maxSize + Math.floor(Math.random() * 10)), "px ").concat(randomInt(1, Math.floor(width / 4)), "px");
103
+ petal.style.height = "".concat(height, "px");
104
+ petal.style.left = "".concat(Math.random() * document.documentElement.clientWidth - 100, "px");
105
+ petal.style.marginTop = "".concat(-(Math.floor(Math.random() * 20) + 15), "px");
106
+ petal.style.width = "".concat(width, "px"); // Remove petals of which the animation ended.
107
+
108
+ PrefixedEvent(petal, 'AnimationEnd', function () {
109
+ if (!elementInViewport(petal)) {
110
+ petal.remove();
111
+ }
112
+ }); // Remove petals that float out of the viewport.
113
+
114
+ PrefixedEvent(petal, 'AnimationIteration', function () {
115
+ if (!elementInViewport(petal)) {
116
+ petal.remove();
117
+ }
118
+ }); // Add the petal to the target element.
119
+
120
+ _this.el.appendChild(petal);
121
+ };
122
+
123
+ this.el.setAttribute('data-sakura-anim-id', window.requestAnimationFrame(this.createPetal));
124
+ };
125
+
126
+ Sakura.prototype.start = function () {
127
+ var animId = this.el.dataset.sakuraAnimId;
128
+
129
+ if (!animId) {
130
+ this.el.setAttribute('data-sakura-anim-id', window.requestAnimationFrame(this.createPetal));
131
+ } else {
132
+ throw new Error('Sakura is already running.');
133
+ }
134
+ };
135
+
136
+ Sakura.prototype.stop = function () {
137
+ var _this2 = this;
138
+
139
+ var graceful = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
140
+ var animId = this.el.dataset.sakuraAnimId;
141
+
142
+ if (animId) {
143
+ window.cancelAnimationFrame(animId);
144
+ this.el.setAttribute('data-sakura-anim-id', '');
145
+ } // Remove all current blossoms at once.
146
+ // You can also set 'graceful' to true to stop new petals from being created.
147
+ // This way the petals won't be removed abruptly.
148
+
149
+
150
+ if (!graceful) {
151
+ setTimeout(function () {
152
+ var petals = document.getElementsByClassName(_this2.settings.className);
153
+
154
+ while (petals.length > 0) {
155
+ petals[0].parentNode.removeChild(petals[0]);
156
+ }
157
+ }, this.settings.delay + 50);
158
+ }
159
+ };