magic-snowflakes
Version:
Falling snowflakes
2 lines • 8.49 kB
JavaScript
/*! Snowflakes | © 2025 Denis Seleznev | MIT License | https://github.com/hcodes/snowflakes/ */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Snowflakes=t()}(this,function(){"use strict";function e(){return{color:"#5ECDEF",container:document.body,count:50,speed:1,stop:!1,rotation:!0,minOpacity:.6,maxOpacity:1,minSize:10,maxSize:25,types:6,width:void 0,height:void 0,wind:!0,zIndex:9999,autoResize:!0}}function t(e,t){Object.keys(t).forEach(function(n){e.style[n]=t[n]})}function n(e){t(e,{display:"block"})}function i(e){t(e,{display:"none"})}function o(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function a(e){return"string"==typeof e&&""!==e}function s(e){for(var t,n=[],i=1;i<arguments.length;i++)n[i-1]=arguments[i];var o=n.filter(a);o.length&&(t=e.classList).add.apply(t,o)}function r(e){for(var t,n=[],i=1;i<arguments.length;i++)n[i-1]=arguments[i];var o=n.filter(a);o.length&&(t=e.classList).remove.apply(t,o)}function h(e,t){return e+Math.floor(Math.random()*(t-e))}function d(e,t,n,i,o){return i+(o-i)*(e-t)/(n-t)}function l(e,t,n){return Math.floor(d(e,0,20,t,n))}var c=function(){function e(e){var o=this;this.size=0,this.sizeInner=0,this.handleAnimationEnd=function(e){var a,s=o.elem;s&&(e.target===s&&(t(s,{left:o.getLeft()}),i(a=s),a.offsetHeight,n(a)))};var a=this.elem=document.createElement("div"),r=this.elemInner=document.createElement("div");this.update(e),s(a,"snowflake"),s(r,"snowflake__inner",e.types?"snowflake__inner_type_"+h(0,e.types):"",e.wind?"snowflake__inner_wind":"",e.rotation?"snowflake__inner_rotation"+(Math.random()>.5?"":"_reverse"):""),a.appendChild(r),a.onanimationend=this.handleAnimationEnd}return e.prototype.getLeft=function(){return 99*Math.random()+"%"},e.prototype.update=function(e){if(this.elem&&this.elemInner){var n=e.minSize===e.maxSize;this.sizeInner=n?0:h(0,20),this.size=l(this.sizeInner,e.minSize,e.maxSize);var i=this.getAnimationProps(e),o={animationName:"snowflake_gid_".concat(e.gid,"_y"),animationDelay:i.animationDelay,animationDuration:i.animationDuration,left:this.getLeft(),top:-Math.sqrt(2)*this.size+"px",width:this.size+"px",height:this.size+"px"};n||(o.opacity=String(d(this.size,e.minSize,e.maxSize,e.minOpacity,e.maxOpacity))),t(this.elem,o);var a="snowflake_gid_".concat(e.gid,"_x_").concat(this.sizeInner);t(this.elemInner,{animationName:a,animationDelay:4*Math.random()+"s"})}},e.prototype.resize=function(e){if(this.elem){var n=this.getAnimationProps(e);t(this.elem,{animationDuration:n.animationDuration})}},e.prototype.appendTo=function(e){this.elem&&e.appendChild(this.elem)},e.prototype.destroy=function(){this.elem&&(this.elem.onanimationend=null,delete this.elem,delete this.elemInner)},e.prototype.getAnimationProps=function(e){var t=e.containerHeight/50/e.speed,n=t/3;return{animationDelay:Math.random()*t+"s",animationDuration:String(d(this.size,e.minSize,e.maxSize,t,n)+"s")}},e}();return function(){function a(e){var t=this;this.destroyed=!1,this.flakes=[],this.handleResize=function(){t.params.autoResize&&t.resize()},this.handleOrientationChange=function(){t.resize()},this.params=this.setParams(e),a.gid++,this.gid=a.gid,this.container=this.appendContainer(),this.params.stop&&this.stop(),this.appendStyles(),this.appendFlakes(),this.containerSize={width:this.width(),height:this.height()},window.addEventListener("resize",this.handleResize,!1),screen.orientation&&screen.orientation.addEventListener&&screen.orientation.addEventListener("change",this.handleOrientationChange)}return a.hasSupport=function(){return Boolean("onanimationend"in document)},Object.defineProperty(a,"defaultParams",{get:function(){return e()},enumerable:!1,configurable:!0}),a.prototype.start=function(){r(this.container,"snowflakes_paused")},a.prototype.stop=function(){s(this.container,"snowflakes_paused")},a.prototype.show=function(){r(this.container,"snowflakes_hidden")},a.prototype.hide=function(){s(this.container,"snowflakes_hidden")},a.prototype.resize=function(){var e=this.width(),t=this.height();if(t!==this.containerSize.height){this.containerSize.width=e,this.containerSize.height=t;var o=this.getFlakeParams();this.flakes.forEach(function(e){return e.resize(o)}),this.isBody()||(i(this.container),this.updateAnimationStyle(),n(this.container))}},a.prototype.destroy=function(){this.destroyed||(this.destroyed=!0,a.instanceCounter&&a.instanceCounter--,this.removeStyles(),o(this.container),this.flakes.forEach(function(e){return e.destroy()}),this.flakes=[],window.removeEventListener("resize",this.handleResize,!1),screen.orientation&&screen.orientation.removeEventListener&&screen.orientation.removeEventListener("change",this.handleOrientationChange,!1))},a.prototype.isBody=function(){return this.params.container===document.body},a.prototype.appendContainer=function(){var e=document.createElement("div");return s(e,"snowflakes","snowflakes_gid_".concat(this.gid),this.isBody()?"snowflakes_body":""),t(e,{zIndex:String(this.params.zIndex)}),this.params.container.appendChild(e),e},a.prototype.appendStyles=function(){a.instanceCounter||(this.mainStyleNode=this.injectStyle('.snowflake{animation:snowflake_unknown 10s linear;pointer-events:none;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;will-change:transform}.snowflake__inner,.snowflake__inner:before{bottom:0;left:0;position:absolute;right:0;top:0}.snowflake__inner:before{background-size:100% 100%;content:""}.snowflake__inner_wind{animation:snowflake_unknown 2s ease-in-out infinite alternate}.snowflake__inner_rotation:before{animation:snowflake_rotation 10s linear infinite}.snowflake__inner_rotation_reverse:before{animation:snowflake_rotation_reverse 10s linear infinite}@keyframes snowflake_rotation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes snowflake_rotation_reverse{0%{transform:rotate(0deg)}to{transform:rotate(-1turn)}}.snowflakes{pointer-events:none}.snowflakes_paused .snowflake,.snowflakes_paused .snowflake__inner,.snowflakes_paused .snowflake__inner:before{animation-play-state:paused}.snowflakes_hidden{visibility:hidden}.snowflakes_body{height:1px;left:0;position:fixed;top:0;width:100%}')),a.instanceCounter++,this.imagesStyleNode=this.injectStyle("".replace(/:color:/g,encodeURIComponent(this.params.color))),this.animationStyleNode=this.injectStyle(this.getAnimationStyle())},a.prototype.injectStyle=function(e,t){return function(e,t){return t||(t=document.createElement("style"),document.head.appendChild(t)),t.textContent=e,t}(e.replace(/_gid_value/g,"_gid_".concat(this.gid)),t)},a.prototype.getFlakeParams=function(){var e=this.height(),t=this.params;return{containerHeight:e,gid:this.gid,count:t.count,speed:t.speed,rotation:t.rotation,minOpacity:t.minOpacity,maxOpacity:t.maxOpacity,minSize:t.minSize,maxSize:t.maxSize,types:t.types,wind:t.wind}},a.prototype.appendFlakes=function(){var e=this,t=this.getFlakeParams();this.flakes=[];for(var n=0;n<this.params.count;n++)this.flakes.push(new c(t));this.flakes.sort(function(e,t){return e.size-t.size}).forEach(function(t){t.appendTo(e.container)})},a.prototype.setParams=function(t){var n=t||{},i={},o=e();return Object.keys(o).forEach(function(e){i[e]=void 0===n[e]?o[e]:n[e]}),i},a.prototype.getAnimationStyle=function(){for(var e=Math.ceil(this.params.maxSize*Math.sqrt(2)),t=this.isBody()?"calc(100vh + ".concat(e,"px)"):"".concat(this.height()+e,"px"),n=this.gid,i=["@keyframes snowflake_gid_".concat(n,"_y{from{transform:translateY(").concat("0px",")}to{transform:translateY(").concat(t,")}}")],o=0;o<=20;o++){var a=l(o,this.params.minSize,this.params.maxSize)+"px";i.push("@keyframes snowflake_gid_".concat(n,"_x_").concat(o,"{from{transform:translateX(0px)}to{transform:translateX(").concat(a,")}}"))}return i.join("\n")},a.prototype.updateAnimationStyle=function(){this.injectStyle(this.getAnimationStyle(),this.animationStyleNode)},a.prototype.removeStyles=function(){a.instanceCounter||(o(this.mainStyleNode),delete this.mainStyleNode),o(this.imagesStyleNode),delete this.imagesStyleNode,o(this.animationStyleNode),delete this.animationStyleNode},a.prototype.width=function(){return this.params.width||(this.isBody()?window.innerWidth:this.params.container.offsetWidth)},a.prototype.height=function(){return this.params.height||(this.isBody()?window.innerHeight:this.params.container.offsetHeight+this.params.maxSize)},a.gid=0,a.instanceCounter=0,a}()});