UNPKG

dots-animation

Version:

simple module for filling your html container with fancy responsive dots animation

2 lines (1 loc) 8.91 kB
const t={expectedFps:60,number:null,density:5e-5,dprDependentDensity:!0,dprDependentDimensions:!0,minR:1,maxR:6,minSpeedX:-.5,maxSpeedX:.5,minSpeedY:-.5,maxSpeedY:.5,blur:1,fill:!0,colorsFill:["#ffffff","#fff4c1","#faefdb"],opacityFill:null,opacityFillMin:0,opacityFillStep:0,stroke:!1,colorsStroke:["#ffffff"],opacityStroke:1,opacityStrokeMin:0,opacityStrokeStep:0,drawLines:!0,lineColor:"#717892",lineLength:150,lineWidth:2,actionOnClick:!0,actionOnHover:!0,onClickCreate:!1,onClickMove:!0,onHoverMove:!0,onHoverDrawLines:!0,onClickCreateNDots:10,onClickMoveRadius:200,onHoverMoveRadius:50,onHoverLineRadius:150};function i(t,i,s,o){return Math.sqrt((t-s)*(t-s)+(i-o)*(i-o))}function s(t,i){return Math.round(Math.random()*(i-t))+t}function o(t,i){return Math.random()*(i-t)+t}function e(t,i,s=1){t=t.replace("#","");return"rgba("+parseInt(t.substring(0,t.length/3),16)+","+parseInt(t.substring(t.length/3,2*t.length/3),16)+","+parseInt(t.substring(2*t.length/3,3*t.length/3),16)+","+i/s+")"}function n(t,i,s,o,e,n,a){t.lineWidth=n,t.strokeStyle=a,t.beginPath(),t.moveTo(i,s),t.lineTo(o,e),t.stroke()}class a{constructor(t,i,s,o,n,a,h,r,c,l,_,p,d,u,y){this._canvas=t,this._offset=i,this._x=s,this._y=o,this._xSpeed=n,this._ySpeed=a,this._r=h,this._colorSHex=r,this._colorFHex=c,this._opacitySMin=l,this._opacitySMax=_,this._opacitySStep=p,this._opacityFMin=d,this._opacityFMax=u,this._opacityFStep=y,this._opacitySCurrent=_,this._opacityFCurrent=u,this._colorS=null===r?null:e(r,this._opacitySCurrent,100),this._colorF=null===c?null:e(c,this._opacityFCurrent,100)}getProps(){return{x:this._x,y:this._y,r:this._r,xSpeed:this._xSpeed,ySpeed:this._ySpeed,colorS:this._colorS,colorF:this._colorF}}updatePosition(){const t=Math.max(this._offset,this._r),i=-1*t,s=-1*t,o=this._canvas.width+t,e=this._canvas.height+t;this._x<i?this._x=o:this._x>o?this._x=i:this._x+=this._xSpeed,this._y<s?this._y=e:this._y>e?this._y=s:this._y+=this._ySpeed}updateColor(){0!==this._opacitySStep&&null!==this._colorSHex&&(this._opacitySCurrent+=this._opacitySStep,this._opacitySCurrent>this._opacitySMax?(this._opacitySCurrent=this._opacitySMax,this._opacitySStep*=-1):this._opacitySCurrent<this._opacitySMin&&(this._opacitySCurrent=this._opacitySMin,this._opacitySStep*=-1),this._colorS=e(this._colorSHex,this._opacityFCurrent,100)),0!==this._opacityFStep&&null!==this._colorFHex&&(this._opacityFCurrent+=this._opacityFStep,this._opacityFCurrent>this._opacityFMax?(this._opacityFCurrent=this._opacityFMax,this._opacityFStep*=-1):this._opacityFCurrent<this._opacityFMin&&(this._opacityFCurrent=this._opacityFMin,this._opacityFStep*=-1),this._colorF=e(this._colorFHex,this._opacityFCurrent,100))}moveTo(t){this._x=t.x,this._y=t.y}}class h{constructor(t,i){this._pauseState=!1,this._array=[],this._maxNumber=100,this._lastDpr=0,this._canvas=t;const s=this._canvas.getContext("2d");if(null===s)throw new Error("Canvas context is null");this._canvasCtx=s,this._options=i}setPauseState(t){this._pauseState=t}draw(t,i){const s=window.devicePixelRatio;s!==this._lastDpr&&(this._array.length=0),this._lastDpr=s;if(!this.updateDotNumber()&&this._pauseState&&!this.isCanvasEmpty())return;this._canvasCtx.clearRect(0,0,this._canvas.width,this._canvas.height);for(const t of this._array)t.updatePosition(),t.updateColor();const o=this._options.dprDependentDimensions?s:1;this._options.actionOnHover&&(this._options.onHoverDrawLines&&this.drawLinesToCircleCenter(t,this._options.onHoverLineRadius*o,this._options.lineWidth,this._options.lineColor),this._options.onHoverMove&&this.moveDotsOutOfCircle(t,this._options.onHoverMoveRadius*o)),i&&this._options.actionOnClick&&(this._options.onClickMove&&this.moveDotsOutOfCircle(t,this._options.onClickMoveRadius*o),this._options.onClickCreate&&this.dotFactory(this._options.onClickCreateNDots,t)),this._options.drawLines&&this.drawLinesBetweenDots();for(const t of this._array){const i=t.getProps();e=this._canvasCtx,n=i.x,a=i.y,h=i.r,r=i.colorS,c=i.colorF,e.beginPath(),e.arc(n,a,h,0,2*Math.PI,!0),null!==c&&(e.fillStyle=c,e.fill()),null!==r&&(e.strokeStyle=r,e.stroke())}var e,n,a,h,r,c}isCanvasEmpty(){return!this._canvasCtx.getImageData(0,0,this._canvas.width,this._canvas.height).data.some((t=>0!==t))}dotFactory(t,i=null){for(let s=0;s<t;s++){const t=this.createRandomDot(i);this._array.push(t)}this._array.length>this._maxNumber&&this.deleteEldestDots(this._array.length-this._maxNumber)}createRandomDot(t){let i,e;t?(i=t.x,e=t.y):(i=s(0,this._canvas.width),e=s(0,this._canvas.height));const n=this._options.dprDependentDimensions?window.devicePixelRatio:1,h=this._options.drawLines?this._options.lineLength*n:0,r=o(this._options.minSpeedX,this._options.maxSpeedX)*n,c=o(this._options.minSpeedY,this._options.maxSpeedY)*n,l=s(this._options.minR,this._options.maxR)*n;let _=null,p=null;this._options.stroke&&(_=this._options.colorsStroke[Math.floor(Math.random()*this._options.colorsStroke.length)]),this._options.fill&&(p=this._options.colorsFill[Math.floor(Math.random()*this._options.colorsFill.length)]);const d=this._options.opacityStrokeMin,u=this._options.opacityStroke?Math.max(d,this._options.opacityStroke):s(d,100),y=this._options.opacityStrokeStep,m=this._options.opacityFillMin,v=this._options.opacityFill?Math.max(m,this._options.opacityFill):s(m,100),x=this._options.opacityFillStep;return new a(this._canvas,h,i,e,r,c,l,_,p,d,u,y,m,v,x)}deleteEldestDots(t){this._array=this._array.slice(t);for(let i=0;i<t;i++)this._array.shift()}getDotNumber(){const t=this._options.dprDependentDensity?window.devicePixelRatio:1,i=Math.floor(this._canvas.width*this._canvas.height*this._options.density/t);return this._options.number?this._options.number:i}updateDotNumber(){return this._maxNumber=this.getDotNumber(),this._maxNumber<this._array.length?(this.deleteEldestDots(this._array.length-this._maxNumber),!0):this._maxNumber>this._array.length&&(this.dotFactory(this._maxNumber-this._array.length),!0)}getCloseDotPairs(t){const s=this._array,o=[];for(let e=0;e<s.length;e++)for(let n=e;n<s.length;n++){const a=s[e].getProps(),h=s[n].getProps(),r=Math.floor(i(a.x,a.y,h.x,h.y));r<=t&&o.push([a.x,a.y,h.x,h.y,r])}return o}getDotsInsideCircle(t,s){const o=[];for(const e of this._array){const n=e.getProps(),a=i(t.x,t.y,n.x,n.y);a<s&&o.push([e,a])}return o}moveDotsOutOfCircle(t,i){const s=this.getDotsInsideCircle(t,i);for(const o of s){const s=o[0],e=s.getProps(),n=o[1],a=(e.x-t.x)*(i/n)+t.x,h=(e.y-t.y)*(i/n)+t.y;s.moveTo({x:a,y:h})}}drawLinesBetweenDots(){const t=this._options.dprDependentDimensions?window.devicePixelRatio:1,i=this._options.lineLength*t,s=this.getCloseDotPairs(i),o=this._options.lineWidth;for(const t of s){const s=(1-t[4]/i)/2,a=e(this._options.lineColor,s);n(this._canvasCtx,t[0],t[1],t[2],t[3],o,a)}}drawLinesToCircleCenter(t,i,s,o){const a=this.getDotsInsideCircle(t,i);for(const h of a){const a=h[0].getProps(),r=e(o,1-h[1]/i);n(this._canvasCtx,t.x,t.y,a.x,a.y,s,r)}}}class r{constructor(t,i,s,o){this._timer=void 0,this._isMouseClicked=!1,this._parent=t,this._mousePosition={x:0,y:0},this._fps=s.expectedFps,this._canvas=document.createElement("canvas"),this._canvas.id=i,this._canvas.style.display="block",this._canvas.style.width="100%",this._canvas.style.width="100%",this._canvas.style.height="100%",this._canvas.style.filter=`blur(${s.blur}px)`,this.resize(),t.appendChild(this._canvas),window.addEventListener("resize",(()=>{this.resize()})),this._animationControl=r.animationControlFactory(o,this._canvas,s)}static animationControlFactory(t,i,s){return new t(i,s)}resize(){const t=window.devicePixelRatio;this._canvas.width=this._parent.offsetWidth*t,this._canvas.height=this._parent.offsetHeight*t}draw(){this._animationControl.draw(this._mousePosition,this._isMouseClicked),this._isMouseClicked=!1}start(){this._animationControl.setPauseState(!1),void 0===this._timer&&(this._timer=window.setInterval((()=>{window.requestAnimationFrame((()=>{this.draw()}))||window.webkitRequestAnimationFrame((()=>{this.draw()}))}),1e3/this._fps),window.addEventListener("mousemove",this.onMouseMove.bind(this)),window.addEventListener("click",this.onClick.bind(this)))}pause(){this._animationControl.setPauseState(!0)}stop(){clearInterval(this._timer),this._timer=void 0;const t=this._canvas.getContext("2d");window.setTimeout((()=>{null!==t&&t.clearRect(0,0,this._canvas.width,this._canvas.height)}),20)}onClick(){this._isMouseClicked=!0}onMouseMove(t){const i=window.devicePixelRatio,s=this._parent.getBoundingClientRect(),o=s.left+document.documentElement.scrollLeft,e=s.top+document.documentElement.scrollTop,n=(t.clientX-o+window.pageXOffset)*i,a=(t.clientY-e+window.pageYOffset)*i;this._mousePosition.x=n,this._mousePosition.y=a}}class c{static createAnimation(i,s,o=null){const e=Object.assign({},t);o&&Object.assign(e,o);const n=document.querySelector(i);if(null===n)throw new Error("Container is null");return new r(n,s,e,h)}}export{c as DotsAnimationFactory};