-
Notifications
You must be signed in to change notification settings - Fork 0
/
component_snow.js
125 lines (106 loc) · 3.1 KB
/
component_snow.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
class Snow extends HTMLElement {
static random(min, max) {
return min + Math.floor(Math.random() * (max - min) + 1);
}
static attrs = {
count: "count", // default: 100
mode: "mode",
};
generateCss(mode, count) {
let css = [];
css.push(`
:host([mode="element"]) {
display: block;
position: relative;
overflow: hidden;
}
:host([mode="page"]) {
position: fixed;
top: 0;
left: 0;
right: 0;
}
:host([mode="page"]),
:host([mode="element"]) > * {
pointer-events: none;
}
:host([mode="element"]) ::slotted(*) {
pointer-events: all;
}
* {
position: absolute;
width: var(--snow-fall-size, 10px);
height: var(--snow-fall-size, 10px);
background: var(--snow-fall-color, rgba(255,255,255,.5));
border-radius: 50%;
}
`);
// using vw units (max 100)
let dimensions = { width: 100, height: 100 };
let units = { x: "vw", y: "vh" };
if (mode === "element") {
dimensions = {
width: this.firstElementChild.clientWidth,
height: this.firstElementChild.clientHeight,
};
units = { x: "px", y: "px" };
}
// Thank you @alphardex: https://codepen.io/alphardex/pen/dyPorwJ
for (let j = 1; j <= count; j++) {
let x = (Snow.random(1, 100) * dimensions.width) / 100; // vw
let offset = (Snow.random(-10, 10) * dimensions.width) / 100; // vw
let yoyo = Math.round(Snow.random(30, 100)); // % time
let yStart = (yoyo * dimensions.height) / 100; // vh
let yEnd = dimensions.height; // vh
let scale = Snow.random(1, 10000) * 0.0001;
let duration = Snow.random(10, 30);
let delay = Snow.random(0, 30) * -1;
css.push(`
:nth-child(${j}) {
opacity: ${Snow.random(0, 1000) * 0.001};
transform: translate(${x}${units.x}, -10px) scale(${scale});
animation: fall-${j} ${duration}s ${delay}s linear infinite;
}
@keyframes fall-${j} {
${yoyo}% {
transform: translate(${x + offset}${units.x}, ${yStart}${
units.y
}) scale(${scale});
}
to {
transform: translate(${x + offset / 2}${units.x}, ${yEnd}${
units.y
}) scale(${scale});
}
}`);
}
return css.join("\n");
}
connectedCallback() {
// https://caniuse.com/mdn-api_cssstylesheet_replacesync
if (this.shadowRoot || !("replaceSync" in CSSStyleSheet.prototype)) {
return;
}
let count = parseInt(this.getAttribute(Snow.attrs.count)) || 100;
let mode;
if (this.hasAttribute(Snow.attrs.mode)) {
mode = this.getAttribute(Snow.attrs.mode);
} else {
mode = this.firstElementChild ? "element" : "page";
this.setAttribute(Snow.attrs.mode, mode);
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(this.generateCss(mode, count));
let shadowroot = this.attachShadow({ mode: "open" });
shadowroot.adoptedStyleSheets = [sheet];
let d = document.createElement("div");
for (let j = 0, k = count; j < k; j++) {
shadowroot.appendChild(d.cloneNode());
}
shadowroot.appendChild(document.createElement("slot"));
addEventListener("resize", (event) => {
sheet.replaceSync(this.generateCss(mode, count));
});
}
}
customElements.define("snow-fall", Snow);