PageSourceSearch

https://webdriver.io/js/ribbons.js

js webdriver.io collected 2026-10-01 08:48:27 UTC 14,353 bytes, 410 lines download raw bytes

1/* eslint-disable no-constant-condition, no-prototype-builtins, no-undef */
2/**
3 * Ribbons Class File.
4 * Creates low-poly ribbons background effect inside a target container.
5 * https://gist.github.com/imaegoo/074b5842d9cd8d80ecfa0d3fa4ecd556
6 */
7(function (name, factory) {
8    if (typeof window === 'object') {
9        window[name] = factory()
10    }
11})('Ribbons', function () {
12    var _w = window,
13        _d = document.documentElement
14
15    // random helper
16    var random = function () {
17        if (arguments.length === 1) {
18            // only 1 argument
19            if (Array.isArray(arguments[0])) {
20                // extract index from array
21                var index = Math.round(random(0, arguments[0].length - 1))
22                return arguments[0][index]
23            }
24            return random(0, arguments[0]) // assume numeric
25        } else if (arguments.length === 2) {
26            // two arguments range
27            return Math.random() * (arguments[1] - arguments[0]) + arguments[0]
28        } else if (arguments.length === 4) {
29            //
30
31            var array = [arguments[0], arguments[1], arguments[2], arguments[3]]
32            return array[Math.floor(Math.random() * array.length)]
33            //return console.log(item)
34        }
35        return 0 // default
36    }
37
38    // screen helper
39    var screenInfo = function () {
40        const width = Math.max(0, _w.innerWidth || _d.clientWidth || document.body.clientWidth || 0)
41        const height = Math.max(0, _w.innerHeight || _d.clientHeight || document.body.clientHeight || 0)
42        const scrollx = Math.max(0, _w.pageXOffset || _d.scrollLeft || document.body.scrollLeft || 0) - (_d.clientLeft || 0)
43        const scrolly = Math.max(0, _w.pageYOffset || _d.scrollTop || document.body.scrollTop || 0) - (_d.clientTop || 0)
44
45        return {
46            width: width,
47            height: height,
48            ratio: width / height,
49            centerx: width / 2,
50            centery: height / 2,
51            scrollx: scrollx,
52            scrolly: scrolly
53        }
54    }
55
56    // point object
57    var Point = function (x, y) {
58        this.x = 0
59        this.y = 0
60        this.set(x, y)
61    }
62    Point.prototype = {
63        constructor: Point,
64
65        set: function (x, y) {
66            this.x = x || 0
67            this.y = y || 0
68        },
69        copy: function (point) {
70            this.x = point.x || 0
71            this.y = point.y || 0
72            return this
73        },
74        multiply: function (x, y) {
75            this.x *= x || 1
76            this.y *= y || 1
77            return this
78        },
79        divide: function (x, y) {
80            this.x /= x || 1
81            this.y /= y || 1
82            return this
83        },
84        add: function (x, y) {
85            this.x += x || 0
86            this.y += y || 0
87            return this
88        },
89        subtract: function (x, y) {
90            this.x -= x || 0
91            this.y -= y || 0
92            return this
93        },
94        clampX: function (min, max) {
95            this.x = Math.max(min, Math.min(this.x, max))
96            return this
97        },
98        clampY: function (min, max) {
99            this.y = Math.max(min, Math.min(this.y, max))
100            return this
101        },
102        flipX: function () {
103            this.x *= -1
104            return this
105        },
106        flipY: function () {
107            this.y *= -1
108            return this
109        }
110    }
111
112    // class constructor
113    var Factory = function (options) {
114        this._canvas = null
115        this._context = null
116        this._sto = null
117        this._width = 0
118        this._height = 0
119        this._scroll = 0
120        this._ribbons = []
121        this._options = {
122            // ribbon color HSL saturation amount
123            colorSaturation: '80%',
124            // ribbon color HSL brightness amount
125            colorBrightness: '60%',
126            // ribbon color opacity amount
127            colorAlpha: 0.65,
128            // how fast to cycle through colors in the HSL color space
129            colorCycleSpeed: 6,
130            // where to start from on the Y axis on each side (top|min, middle|center, bottom|max, random)
131            verticalPosition: 'center',
132            // how fast to get to the other side of the screen
133            horizontalSpeed: 150,
134            // how many ribbons to keep on screen at any given time
135            ribbonCount: 3,
136            // add stroke along with ribbon fill colors
137            strokeSize: 0,
138            // move ribbons vertically by a factor on page scroll
139            parallaxAmount: -0.5,
140            // add animation effect to each ribbon section over time
141            animateSections: true,
142            // element to attach the effect to
143            element: document.body
144        }
145        this._onDraw = this._onDraw.bind(this)
146        this._onResize = this._onResize.bind(this)
147        this._onScroll = this._onScroll.bind(this)
148        this.setOptions(options)
149        this.init()
150    }
151
152    // class prototype
153    Factory.prototype = {
154        constructor: Factory,
155
156        // Set and merge local options
157        setOptions: function (options) {
158            if (typeof options === 'object') {
159                for (var key in options) {
160                    if (options.hasOwnProperty(key)) {
161                        this._options[key] = options[key]
162                    }
163                }
164            }
165        },
166
167        // Initialize the ribbons effect
168        init: function () {
169            try {
170                this._canvas = document.createElement('canvas')
171                this._canvas.style['display'] = 'block'
172                this._canvas.style['position'] = 'absolute'
173                this._canvas.style['margin'] = '0'
174                this._canvas.style['padding'] = '0'
175                this._canvas.style['border'] = '0'
176                this._canvas.style['outline'] = '0'
177                this._canvas.style['left'] = '0'
178                this._canvas.style['top'] = '0'
179                this._canvas.style['width'] = '100%'
180                this._canvas.style['height'] = '100%'
181                this._canvas.style['z-index'] = '-1'
182                this._onResize()
183
184                this._context = this._canvas.getContext('2d')
185                this._context.clearRect(0, 0, this._width, this._height)
186                this._context.globalAlpha = this._options.colorAlpha
187
188                window.addEventListener('resize', this._onResize)
189                window.addEventListener('scroll', this._onScroll)
190                this._options.element.appendChild(this._canvas)
191            } catch (e) {
192                console.warn('Canvas Context Error: ' + e.toString())
193                return
194            }
195            this._onDraw()
196        },
197
198        // Create a new random ribbon and to the list
199        addRibbon: function () {
200            // movement data
201            var dir = Math.round(random(1, 9)) > 5 ? 'right' : 'left',
202                stop = 1000,
203                hide = 200,
204                min = 0 - hide,
205                max = this._width + hide,
206                movex = 0,
207                movey = 0,
208                startx = dir === 'right' ? min : max,
209                starty = Math.round(random(0, this._height))
210
211            // asjust starty based on options
212            if (/^(top|min)$/i.test(this._options.verticalPosition)) {
213                starty = 0 + hide
214            } else if (/^(middle|center)$/i.test(this._options.verticalPosition)) {
215                starty = this._height / 2
216            } else if (/^(bottom|max)$/i.test(this._options.verticalPosition)) {
217                starty = this._height - hide
218            }
219
220            // ribbon sections data
221            var ribbon = [],
222                point1 = new Point(startx, starty),
223                point2 = new Point(startx, starty),
224                point3 = null,
225                color = Math.round(random(35, 35, 40, 40)),
226                delay = 0
227
228            // buils ribbon sections
229            while (true) {
230                if (stop <= 0) break
231                stop--
232
233                movex = Math.round(
234                    (Math.random() * 1 - 0.2) * this._options.horizontalSpeed
235                )
236                movey = Math.round((Math.random() * 1 - 0.5) * (this._height * 0.25))
237
238                point3 = new Point()
239                point3.copy(point2)
240
241                if (dir === 'right') {
242                    point3.add(movex, movey)
243                    if (point2.x >= max) break
244                } else if (dir === 'left') {
245                    point3.subtract(movex, movey)
246                    if (point2.x <= min) break
247                }
248                // point3.clampY( 0, this._height );
249                //console.log(Math.round(random(1, 5)))
250                ribbon.push({
251                    // single ribbon section
252                    point1: new Point(point1.x, point1.y),
253                    point2: new Point(point2.x, point2.y),
254                    point3: point3,
255                    color: color,
256                    delay: delay,
257                    dir: dir,
258                    alpha: 0,
259                    phase: 0
260                })
261
262                point1.copy(point2)
263                point2.copy(point3)
264
265                delay += 4
266                //color += 1
267                //console.log('colorCycleSpeed', color)
268            }
269            this._ribbons.push(ribbon)
270        },
271
272        // Draw single section
273        _drawRibbonSection: function (section) {
274            if (section) {
275                if (section.phase >= 1 && section.alpha <= 0) {
276                    return true // done
277                }
278                if (section.delay <= 0) {
279                    section.phase += 0.02
280                    section.alpha = Math.sin(section.phase) * 1
281                    section.alpha = section.alpha <= 0 ? 0 : section.alpha
282                    section.alpha = section.alpha >= 1 ? 1 : section.alpha
283
284                    if (this._options.animateSections) {
285                        var mod = Math.sin(1 + section.phase * Math.PI / 2) * 0.1
286
287                        if (section.dir === 'right') {
288                            section.point1.add(mod, 0)
289                            section.point2.add(mod, 0)
290                            section.point3.add(mod, 0)
291                        } else {
292                            section.point1.subtract(mod, 0)
293                            section.point2.subtract(mod, 0)
294                            section.point3.subtract(mod, 0)
295                        }
296                        section.point1.add(0, mod)
297                        section.point2.add(0, mod)
298                        section.point3.add(0, mod)
299                    }
300                } else {
301                    section.delay -= 0.5
302                }
303                //console.log('section.color', section.color)
304                var s = this._options.colorSaturation,
305                    l = this._options.colorBrightness,
306                    c =
307                        'hsla(' +
308                        section.color +
309                        ', ' +
310                        s +
311                        ', ' +
312                        l +
313                        ', ' +
314                        section.alpha +
315                        ' )'
316
317                this._context.save()
318
319                if (this._options.parallaxAmount !== 0) {
320                    this._context.translate(
321                        0,
322                        this._scroll * this._options.parallaxAmount
323                    )
324                }
325                this._context.beginPath()
326                this._context.moveTo(section.point1.x, section.point1.y)
327                this._context.lineTo(section.point2.x, section.point2.y)
328                this._context.lineTo(section.point3.x, section.point3.y)
329                this._context.fillStyle = c
330                this._context.fill()
331
332                if (this._options.strokeSize > 0) {
333                    this._context.lineWidth = this._options.strokeSize
334                    this._context.strokeStyle = c
335                    this._context.lineCap = 'round'
336                    this._context.stroke()
337                }
338                this._context.restore()
339            }
340            return false // not done yet
341        },
342
343        // Draw ribbons
344        _onDraw: function () {
345            // cleanup on ribbons list to rtemoved finished ribbons
346            for (var i = 0, t = this._ribbons.length; i < t; ++i) {
347                if (!this._ribbons[i]) {
348                    this._ribbons.splice(i, 1)
349                }
350            }
351
352            // draw new ribbons
353            this._context.clearRect(0, 0, this._width, this._height)
354
355            for (
356                var a = 0;
357                a < this._ribbons.length;
358                ++a // single ribbon
359            ) {
360                var ribbon = this._ribbons[a],
361                    numSections = ribbon.length,
362                    numDone = 0
363
364                for (
365                    var b = 0;
366                    b < numSections;
367                    ++b // ribbon section
368                ) {
369                    if (this._drawRibbonSection(ribbon[b])) {
370                        numDone++ // section done
371                    }
372                }
373                if (numDone >= numSections) {
374                    // ribbon done
375                    this._ribbons[a] = null
376                }
377            }
378            // maintain optional number of ribbons on canvas
379            if (this._ribbons.length < this._options.ribbonCount) {
380                this.addRibbon()
381            }
382            requestAnimationFrame(this._onDraw)
383        },
384
385        // Update container size info
386        _onResize: function (e) {
387            var screen = screenInfo(e)
388            this._width = screen.width
389            this._height = screen.height
390
391            if (this._canvas) {
392                this._canvas.width = this._width
393                this._canvas.height = this._height
394
395                if (this._context) {
396                    this._context.globalAlpha = this._options.colorAlpha
397                }
398            }
399        },
400
401        // Update container size info
402        _onScroll: function (e) {
403            var screen = screenInfo(e)
404            this._scroll = screen.scrolly
405        }
406    }
407
408    // export
409    return Factory
410})

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.