uo-tashtagol.kemobl.ru
324 строки · 13.3 Кб
1(function () {2let lastTime = 0;3let vendors = ['webkit', 'moz'];4for (let x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {5window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];6window.cancelAnimationFrame =7window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];8}9
10if (!window.requestAnimationFrame)11window.requestAnimationFrame = function (callback, element) {12let currTime = new Date().getTime();13let timeToCall = Math.max(0, 16 - (currTime - lastTime));14let id = window.setTimeout(function () { callback(currTime + timeToCall); },15timeToCall);16lastTime = currTime + timeToCall;17return id;18};19
20if (!window.cancelAnimationFrame)21window.cancelAnimationFrame = function (id) {22clearTimeout(id);23};24}());25
26(function () {27let Snowfall = function (element, opts) {28let defaults = {29flakeCount: 35,30flakeColor: '#ffffff',31flakeIndex: 999999,32minSize: 1,33maxSize: 2,34minSpeed: 1,35maxSpeed: 5,36round: false,37shadow: false,38collection: false,39collectionHeight: 40,40deviceorientation: false41},42options = { ...defaults, ...opts },43random = function random(min, max) {44return Math.round(min + Math.random() * (max - min));45};46
47if (!element.data) {48element.data = {}49}50element.data.snowfall = this;51let canvasCollection = []52
53function Flake(_x, _y, _size, _speed, _id) {54this.id = _id;55this.x = _x;56this.y = _y;57this.size = _size;58this.speed = _speed;59this.step = 0;60this.stepSize = random(1, 10) / 100;61
62if (options.collection) {63this.target = canvasCollection[random(0, canvasCollection.length - 1)];64}65
66let flakeMarkup = null;67
68if (options.image) {69flakeMarkup = document.createElement("img");70flakeMarkup.src = options.image;71} else {72flakeMarkup = document.createElement("div");73flakeMarkup.style.background = options.flakeColor;74}75let attrs = { 'class': 'snowfall-flakes', 'id': 'flake-' + this.id }76let style = { 'width': `${this.size}px`, 'height': `${this.size}px`, 'position': 'absolute', 'top': this.y, 'left': this.x, 'fontSize': 0, 'zIndex': options.flakeIndex }77for (const key in attrs) flakeMarkup.setAttribute(key, attrs[key]);78for (const key in style) flakeMarkup.style[key] = style[key];79
80if (element.tagName === document.tagName) element = document.body;81element.append(flakeMarkup);82
83this.element = document.getElementById('flake-' + this.id);84
85// Update function, used to update the snow flakes, and checks current snowflake against bounds86this.update = function () {87this.y += this.speed;88
89if (this.y > (elHeight) - (this.size + 6)) {90this.reset();91}92
93this.element.style.top = this.y + 'px';94this.element.style.left = this.x + 'px';95
96this.step += this.stepSize;97
98if (doRatio === false) {99this.x += Math.cos(this.step);100} else {101this.x += (doRatio + Math.cos(this.step));102}103
104// Pileup check105if (options.collection) {106let canvas = this.target.element,107parentBounds = canvas.data.parent.getBoundingClientRect();108canvas.style.width = parentBounds.width + 'px';109canvas.style.left = parentBounds.left + 'px';110if (this.x > this.target.x && this.x < this.target.width + this.target.x && this.y > this.target.y && this.y < this.target.height + this.target.y) {111let ctx = canvas.getContext("2d"),112curX = this.x - this.target.x,113curY = this.y - this.target.y,114colData = this.target.colData;115if (colData[parseInt(curX)][parseInt(curY + this.speed + this.size)] !== undefined || curY + this.speed + this.size > this.target.height) {116if (curY + this.speed + this.size > this.target.height) {117while (curY + this.speed + this.size > this.target.height && this.speed > 0) {118this.speed *= .5;119}120
121ctx.fillStyle = "#fff";122
123if (colData[parseInt(curX)][parseInt(curY + this.speed + this.size)] == undefined) {124colData[parseInt(curX)][parseInt(curY + this.speed + this.size)] = 1;125ctx.fillRect(curX, (curY) + this.speed + this.size, this.size, this.size);126} else {127colData[parseInt(curX)][parseInt(curY + this.speed)] = 1;128ctx.fillRect(curX, curY + this.speed, this.size, this.size);129}130this.reset();131} else {132// flow to the sides133this.speed = 1;134this.stepSize = 0;135
136if (parseInt(curX) + 1 < this.target.width && colData[parseInt(curX) + 1][parseInt(curY) + 1] == undefined) {137// go left138this.x++;139} else if (parseInt(curX) - 1 > 0 && colData[parseInt(curX) - 1][parseInt(curY) + 1] == undefined) {140// go right141this.x--;142} else {143//stop144ctx.fillRect(curX, curY, this.size, this.size);145colData[parseInt(curX)][parseInt(curY)] = 1;146this.reset();147}148}149}150}151}152
153if (this.x > (elWidth) - widthOffset || this.x < widthOffset) {154this.reset();155}156}157
158// Resets the snowflake once it reaches one of the bounds set159this.reset = function () {160this.y = 0;161this.x = random(widthOffset, elWidth - widthOffset);162this.stepSize = random(1, 10) / 100;163this.size = random((options.minSize * 100), (options.maxSize * 100)) / 100;164this.speed = random(options.minSpeed, options.maxSpeed);165}166}167
168// local vars169let flakes = [],170flakeId = 0,171i = 0,172elHeight = element.clientHeight,173elWidth = element.clientWidth,174widthOffset = 0,175snowTimeout = 0;176
177// Collection Piece ******************************178if (options.collection !== false) {179let testElem = document.createElement('canvas');180if (!!(testElem.getContext && testElem.getContext('2d'))) {181let elements = document.querySelectorAll(options.collection),182collectionHeight = options.collectionHeight;183
184for (let i = 0; i < elements.length; i++) {185let bounds = elements[i].getBoundingClientRect(),186canvas = document.createElement('canvas'),187collisionData = [],188ctx = canvas.getContext('2d');189canvas.data = {}190
191if (bounds.top - collectionHeight > 0) {192document.body.appendChild(canvas);193canvas.style.position = 'absolute';194canvas.height = collectionHeight;195canvas.width = bounds.width;196canvas.style.left = bounds.left + 'px';197canvas.style.top = bounds.top - collectionHeight + 'px';198canvas.data.parent = elements[i];199
200for (let w = 0; w < bounds.width; w++) {201collisionData[w] = [];202}203
204if (options.image) {205const img = new Image();206img.src = options.image;207img.onload = function () {208const pattern = ctx.createPattern(img, 'repeat');209ctx.fillStyle = pattern;210}211} else {212ctx.fillStyle = "#fff";213}214
215canvasCollection.push({ element: canvas, x: bounds.left, y: bounds.top - collectionHeight, width: bounds.width, height: collectionHeight, colData: collisionData });216}217}218} else {219// Canvas element isnt supported220options.collection = false;221}222}223// ************************************************224
225// This will reduce the horizontal scroll bar from displaying, when the effect is applied to the whole page226if (element.tagName === document.tagName) {227widthOffset = 25;228}229
230// Bind the window resize event so we can get the innerHeight again231window.addEventListener("resize", function () {232elHeight = element.clientHeight;233elWidth = element.offsetWidth;234console.log(elHeight);235});236
237// initialize the flakes238for (i = 0; i < options.flakeCount; i += 1) {239flakeId = flakes.length;240flakes.push(new Flake(random(widthOffset, elWidth - widthOffset), random(0, elHeight), random((options.minSize * 100), (options.maxSize * 100)) / 100, random(options.minSpeed, options.maxSpeed), flakeId));241}242
243// This adds the style to make the snowflakes round via border radius property244if (options.round) {245let style = { '-moz-border-radius': options.maxSize, '-webkit-border-radius': options.maxSize, 'border-radius': options.maxSize }246document.querySelectorAll('.snowfall-flakes').forEach(elem => {247for (const key in style) {248elem.setAttribute(key, attributes[key]);249}250});251}252
253// This adds shadows just below the snowflake so they pop a bit on lighter colored web pages254if (options.shadow) {255let style = { '-moz-box-shadow': '1px 1px 1px #555', '-webkit-box-shadow': '1px 1px 1px #555', 'box-shadow': '1px 1px 1px #555' }256document.querySelectorAll('.snowfall-flakes').forEach(elem => {257for (const key in style) {258elem.setAttribute(key, attributes[key]);259}260});261}262
263// On newer Macbooks Snowflakes will fall based on deviceorientation264let doRatio = false;265if (options.deviceorientation) {266window.addEventListener('deviceorientation', function (event) {267doRatio = event.originalEvent.gamma * 0.1;268});269}270
271// this controls flow of the updating snow272function snow() {273for (let i = 0; i < flakes.length; i += 1) {274flakes[i].update();275}276
277snowTimeout = requestAnimationFrame(function () { snow() });278}279
280snow();281
282// clears the snowflakes283this.clear = function (element) {284element.querySelectorAll('.snowfall-flakes').forEach(elem => elem.remove());285flakes = [];286cancelAnimationFrame(snowTimeout);287}288};289
290// Initialize the options and the plugin291// NodeList.prototype.snowfall = function (options) {292// for (let i = 0; i < this.length; i++) {293// const element = this[i];294// if (typeof options === "object" || options === undefined) {295// new Snowfall(element, options);296// } else if (typeof options === "string") {297// if (element.data.snowfall) {298// element.data.snowfall.clear(element);299// }300// }301// }302// }303
304// Node.prototype.snowfall = function (options) {305// this.snowfall(options);306// return this;307// }308Node.prototype.snowfall = function (options) {309options = options || {}310
311if (typeof options === 'string' && this.data?.snowfall) {312this.data.snowfall.clear(this);313return this;314}315
316new Snowfall(this, options)317
318return this;319}320
321NodeList.prototype.snowfall = function (options) {322this.forEach(el => el.snowfall(options));323}324})();