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.