PageSourceSearch

https://shop.odakyu-dept.co.jp/search_top/202001_renewal/js/confetti.js

js odakyu-dept.co.jp collected 2026-09-24 20:49:15 UTC 7,860 bytes, 221 lines download raw bytes

1'use strict';
2
3// If set to true, the user must press
4// UP UP DOWN ODWN LEFT RIGHT LEFT RIGHT A B
5// to trigger the confetti with a random color theme.
6// Otherwise the confetti constantly falls.
7var onlyOnKonami = false;
8
9$(function () {
10    // Globals
11    var $window = $(window)
12        , random = Math.random
13        , cos = Math.cos
14        , sin = Math.sin
15        , PI = Math.PI
16        , PI2 = PI * 2
17        , timer = undefined
18        , frame = undefined
19        , confetti = [];
20
21    // Settings
22    var konami = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]
23        , pointer = 0;
24
25    var particles = 150
26        , spread = 250
27        , sizeMin = 3
28        , sizeMax = 12 - sizeMin
29        , eccentricity = 10
30        , deviation = 100
31        , dxThetaMin = -.1
32        , dxThetaMax = -dxThetaMin - dxThetaMin
33        , dyMin = .13
34        , dyMax = .18
35        , dThetaMin = .4
36        , dThetaMax = .7 - dThetaMin;
37
38    var colorThemes = [
39        function () {
40            return 'rgb(255, 236, 139)'; // すべての紙吹雪を設定
41        }
42    ];
43
44    function color(r, g, b) {
45        return 'rgb(' + r + ',' + g + ',' + b + ')';
46    }
47
48    // Cosine interpolation
49    function interpolation(a, b, t) {
50        return (1 - cos(PI * t)) / 2 * (b - a) + a;
51    }
52
53    // Create a 1D Maximal Poisson Disc over [0, 1]
54    var radius = 1 / eccentricity, radius2 = radius + radius;
55    function createPoisson() {
56        // domain is the set of points which are still available to pick from
57        // D = union{ [d_i, d_i+1] | i is even }
58        var domain = [radius, 1 - radius], measure = 1 - radius2, spline = [0, 1];
59        while (measure) {
60            var dart = measure * random(), i, l, interval, a, b, c, d;
61
62            // Find where dart lies
63            for (i = 0, l = domain.length, measure = 0; i < l; i += 2) {
64                a = domain[i], b = domain[i + 1], interval = b - a;
65                if (dart < measure + interval) {
66                    spline.push(dart += a - measure);
67                    break;
68                }
69                measure += interval;
70            }
71            c = dart - radius, d = dart + radius;
72
73            // Update the domain
74            for (i = domain.length - 1; i > 0; i -= 2) {
75                l = i - 1, a = domain[l], b = domain[i];
76                // c---d          c---d  Do nothing
77                //   c-----d  c-----d    Move interior
78                //   c--------------d    Delete interval
79                //         c--d          Split interval
80                //       a------b
81                if (a >= c && a < d)
82                    if (b > d) domain[l] = d; // Move interior (Left case)
83                    else domain.splice(l, 2); // Delete interval
84                else if (a < c && b > c)
85                    if (b <= d) domain[i] = c; // Move interior (Right case)
86                    else domain.splice(i, 0, c, d); // Split interval
87            }
88
89            // Re-measure the domain
90            for (i = 0, l = domain.length, measure = 0; i < l; i += 2)
91                measure += domain[i + 1] - domain[i];
92        }
93
94        return spline.sort();
95    }
96
97    // Create the overarching container
98    var container = document.createElement('div');
99    container.style.position = 'fixed';
100    container.style.top = '0';
101    container.style.left = '0';
102    container.style.width = '100%';
103    container.style.height = '0';
104    container.style.overflow = 'visible';
105    container.style.zIndex = '9999';
106
107    // Confetto constructor
108    function Confetto(theme) {
109        this.frame = 0;
110        this.outer = document.createElement('div');
111        this.inner = document.createElement('div');
112        this.outer.appendChild(this.inner);
113
114        var outerStyle = this.outer.style, innerStyle = this.inner.style;
115        outerStyle.position = 'absolute';
116        outerStyle.width = (sizeMin + sizeMax * random()) + 'px';
117        outerStyle.height = (sizeMin + sizeMax * random()) + 'px';
118        innerStyle.width = '100%';
119        innerStyle.height = '100%';
120        innerStyle.backgroundColor = theme();
121
122        outerStyle.perspective = '50px';
123        outerStyle.transform = 'rotate(' + (360 * random()) + 'deg)';
124        this.axis = 'rotate3D(' +
125            cos(360 * random()) + ',' +
126            cos(360 * random()) + ',0,';
127        this.theta = 360 * random();
128        this.dTheta = dThetaMin + dThetaMax * random();
129        innerStyle.transform = this.axis + this.theta + 'deg)';
130
131        this.x = $window.width() * random();
132        this.y = -deviation;
133        this.dx = sin(dxThetaMin + dxThetaMax * random());
134        this.dy = dyMin + dyMax * random();
135        outerStyle.left = this.x + 'px';
136        outerStyle.top = this.y + 'px';
137
138        // Create the periodic spline
139        this.splineX = createPoisson();
140        this.splineY = [];
141        for (var i = 1, l = this.splineX.length - 1; i < l; ++i)
142            this.splineY[i] = deviation * random();
143        this.splineY[0] = this.splineY[l] = deviation * random();
144
145        this.update = function (height, delta) {
146            this.frame += delta;
147            this.x += this.dx * delta;
148            this.y += this.dy * delta;
149            this.theta += this.dTheta * delta;
150
151            // Compute spline and convert to polar
152            var phi = this.frame % 7777 / 7777, i = 0, j = 1;
153            while (phi >= this.splineX[j]) i = j++;
154            var rho = interpolation(
155                this.splineY[i],
156                this.splineY[j],
157                (phi - this.splineX[i]) / (this.splineX[j] - this.splineX[i])
158            );
159            phi *= PI2;
160
161            outerStyle.left = this.x + rho * cos(phi) + 'px';
162            outerStyle.top = this.y + rho * sin(phi) + 'px';
163            innerStyle.transform = this.axis + this.theta + 'deg)';
164            return this.y > height + deviation;
165        };
166    }
167
168    function poof() {
169        if (!frame) {
170            // Append the container
171            document.body.appendChild(container);
172
173            // Add confetti
174            var theme = colorThemes[onlyOnKonami ? colorThemes.length * random() | 0 : 0]
175                , count = 0;
176            (function addConfetto() {
177                if (onlyOnKonami && ++count > particles)
178                    return timer = undefined;
179
180                var confetto = new Confetto(theme);
181                confetti.push(confetto);
182                container.appendChild(confetto.outer);
183                timer = setTimeout(addConfetto, spread * random());
184            })(0);
185
186            // Start the loop
187            var prev = undefined;
188            requestAnimationFrame(function loop(timestamp) {
189                var delta = prev ? timestamp - prev : 0;
190                prev = timestamp;
191                var height = $window.height();
192
193                for (var i = confetti.length - 1; i >= 0; --i) {
194                    if (confetti[i].update(height, delta)) {
195                        container.removeChild(confetti[i].outer);
196                        confetti.splice(i, 1);
197                    }
198                }
199
200                if (timer || confetti.length)
201                    return frame = requestAnimationFrame(loop);
202
203                // Cleanup
204                document.body.removeChild(container);
205                frame = undefined;
206            });
207        }
208    }
209
210    $window.keydown(function (event) {
211        pointer = konami[pointer] === event.which
212            ? pointer + 1
213            : +(event.which === konami[0]);
214        if (pointer === konami.length) {
215            pointer = 0;
216            poof();
217        }
218    });
219
220    if (!onlyOnKonami) poof();
221});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.