UNPKG

@9am/fire-flame

Version:
22 lines (21 loc) 7.7 kB
(function(p,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(p=typeof globalThis<"u"?globalThis:p||self,n(p.FireFlame={}))})(this,function(p){"use strict";var z=Object.defineProperty;var O=(p,n,f)=>n in p?z(p,n,{enumerable:!0,configurable:!0,writable:!0,value:f}):p[n]=f;var o=(p,n,f)=>(O(p,typeof n!="symbol"?n+"":n,f),f);class n{constructor(e){o(this,"x",0);o(this,"y",0);this.set(e)}static add(e,t){return new n({x:e.x+t.x,y:e.y+t.y})}static subtract(e,t){return new n({x:e.x-t.x,y:e.y-t.y})}set(e){if("d"in e){const{d:t,m:i}=e;this.x=Math.cos(t)*i,this.y=Math.sin(t)*i}else this.x=e.x,this.y=e.y;return this}add(e){return this.set({x:this.x+e.x,y:this.y+e.y})}subtract(e){return this.set({x:this.x-e.x,y:this.y-e.y})}multiply(e){return this.set({x:this.x*e,y:this.y*e})}dot(e){return this.x*e.x+this.y*e.y}set m(e){this.set({m:e,d:this.d})}set d(e){this.set({m:this.m,d:e})}get m(){return Math.sqrt(this.dot(this))}get d(){return Math.atan2(this.y,this.x)}}new n({x:0,y:0});class f extends n{constructor({x:t=0,y:i=0,v:r=new n({x:0,y:0}),size:d=1}){super({x:t,y:i});o(this,"v");o(this,"link");o(this,"size");this.v=r,this.size=d,this.link=new n({x:0,y:0})}update(){this.add(this.v)}}class v{constructor(){o(this,"dom");o(this,"ctx");this.dom=v.getTemplate().content.firstElementChild.cloneNode(!0),this.ctx=this.dom.getContext("2d")}static getTemplate(){const e=document.createElement("template");return e.innerHTML='<canvas width="" height=""></canvas>',e}updateSize({w:e,h:t}){this.dom.setAttribute("width",e+""),this.dom.setAttribute("height",t+"")}draw(e,t){const{x:i,y:r,particleNum:d,particleDistance:c,innerColor:l,outerColor:a}=t,h=new Path2D;e.forEach(([u,m])=>{h.quadraticCurveTo(u.x,u.y,m.x,m.y)}),h.closePath(),this.ctx.clearRect(0,0,this.dom.width,this.dom.height);const s=this.ctx.createRadialGradient(i,r,Math.random()*5,i,r,d*c*.5);s.addColorStop(0,l),s.addColorStop(1,a),this.ctx.save(),this.ctx.fillStyle=s,this.ctx.strokeStyle=s,this.ctx.fill(h),this.ctx.filter="blur(4px)",this.ctx.lineWidth=4,this.ctx.stroke(h),this.ctx.restore()}}class M{constructor(){o(this,"dom");o(this,"pathStroke");o(this,"pathFill");o(this,"gradient");o(this,"stopInner");o(this,"stopOuter");this.dom=M.getTemplate().content.firstElementChild.cloneNode(!0),this.pathStroke=this.dom.querySelector(".ff-stroke"),this.pathFill=this.dom.querySelector(".ff-fill"),this.gradient=this.dom.querySelector("#ff-gradient"),this.stopInner=this.dom.querySelector("#stop-inner"),this.stopOuter=this.dom.querySelector("#stop-outer")}static getTemplate(){const e=document.createElement("template");return e.innerHTML=` <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"> <defs> <radialGradient id="ff-gradient" fx="0" gradientTransform=""> <stop id="stop-inner" offset="10%" stop-color="blue" /> <stop id="stop-outer" offset="75%" stop-color="blueviolet" /> </radialGradient> </defs> <g fill="url('#ff-gradient')"> <path class="ff-fill" d="" /> </g> <g stroke="url('#ff-gradient')" stroke-width="4" fill="none" style="filter: blur(4px)" > <path class="ff-stroke" d="" /> </g> </svg> `,e}updateSize({w:e,h:t}){this.dom.setAttribute("width",e+""),this.dom.setAttribute("height",t+"")}draw(e,t){const{innerColor:i,outerColor:r,wind:d}=t;this.stopInner.setAttribute("stop-color",i),this.stopOuter.setAttribute("stop-color",r),console.log(d.d*180/Math.PI),this.gradient.setAttribute("gradientTransform",`rotate(${d.d*180/Math.PI} 0.5 0.5)`);const[c]=e,l=e.map(([h,s])=>`Q ${Math.ceil(h.x)},${Math.ceil(h.y)} ${Math.ceil(s.x)},${Math.ceil(s.y)}`).join(" "),a=`M ${c==null?void 0:c[0].x},${c==null?void 0:c[0].y} ${l} Z`;this.pathStroke.setAttribute("d",a),this.pathFill.setAttribute("d",a)}}const b=Math.PI*2,A=Math.PI*.5,P=(S,e)=>{let t=0,i=1e3/e,r=0;const d=s=>{if(s-t<i){r=requestAnimationFrame(d);return}t=s,S(),r=requestAnimationFrame(d)},c=()=>r!==0,l=s=>{i=1e3/s},a=()=>{cancelAnimationFrame(r),r=0},h=()=>{c()||(t=0,r=requestAnimationFrame(d))};return h(),{start:h,stop:a,setFPS:l,isRunning:c}},x=new n({x:0,y:0}),w=class extends n{constructor(t,i={}){super({x:i.x||0,y:i.y||0});o(this,"painter");o(this,"pIndex",1);o(this,"particles",new Map);o(this,"spawnAnimation");o(this,"renderAnimation");o(this,"spawn",()=>{const{particleNum:t}=this.option,i=new f({x:this.x,y:this.y,v:new n({m:Math.random()*2,d:Math.random()*b})});this.particles.set(this.pIndex,i),this.pIndex>t&&this.particles.delete(this.pIndex-t),this.pIndex++});o(this,"render",()=>{this.updateParticles();const t=this.getPath(),i={...this.option,x:this.x,y:this.y};this.painter.draw(t,i)});o(this,"onMove",t=>{this.set({x:t.offsetX,y:t.offsetY})});this.container=t,this.option=i;const r={...w.getDefaultOption(),...i};this.preparePainter(r.painterType),this.setOption(r)}static getDefaultOption(){return{x:0,y:0,mousemove:!0,w:400,h:400,fps:60,wind:new n({x:0,y:-.8}),friction:.98,particleNum:15,particleDistance:10,particleFPS:10,sizeCurveFn:(t,i)=>t>.7?Math.sqrt(1-t)*50:Math.pow(t-1,2)*-30+30,innerColor:"blue",outerColor:"blueviolet",painterType:"canvas"}}preparePainter(t){var i;this.painter=new w.painterMap[t],(i=this.container)==null||i.appendChild(this.painter.dom)}start(){var t,i;(t=this.spawnAnimation)==null||t.start(),(i=this.renderAnimation)==null||i.start()}stop(){var t,i;(t=this.spawnAnimation)==null||t.stop(),(i=this.renderAnimation)==null||i.stop()}setOption(t){var h,s,u,m;const{mousemove:i,fps:r,w:d,h:c,particleFPS:l,particleNum:a}=this.option;if(this.option={...this.option,...t},(this.option.w!==d||this.option.h!==c)&&this.painter.updateSize({w:this.option.w,h:this.option.h}),this.option.particleNum!==a&&(this.particles.clear(),this.pIndex=1),this.option.mousemove!==i){this.container.addEventListener;const y=this.option.mousemove?(h=this.container)==null?void 0:h.addEventListener:(s=this.container)==null?void 0:s.removeEventListener;y==null||y.call(this.container,"mousemove",this.onMove,!0)}this.option.particleFPS!==l&&((u=this.spawnAnimation)==null||u.stop(),this.spawnAnimation=P(this.spawn,this.option.particleFPS)),this.option.fps!==r&&((m=this.renderAnimation)==null||m.stop(),this.renderAnimation=P(this.render,this.option.fps))}updateParticles(){var a;const{wind:t,friction:i,sizeCurveFn:r,particleNum:d,particleDistance:c}=this.option;let l=0;for(const[h,s]of this.particles){const u=(a=this.particles.get(h+1))!=null?a:s;if(x.set({m:.1,d:b*Math.random()}),s.v.add(n.add(t,x)).multiply(i),s.size=r(l++/(d-1),s.size),s.update(),s.link=n.subtract(s,u),s.link.m>c){const m=s.x,y=s.y;s.link.m=c,s.set({x:u.x+s.link.x,y:u.y+s.link.y}),s.v.add(x.set({x:s.x-m,y:s.y-y}).multiply(.05))}}}getPath(){var d,c;const t=[],i=[],r=new Path2D;for(const[l,a]of this.particles){const h=(d=this.particles.get(l+1))!=null?d:a,s=(c=this.particles.get(l-1))!=null?c:a;if(h===a&&s===a){r.moveTo(a.x,a.y);continue}const u=a.link.d+A,m=h.link.d+A,y=s.link.d+A,T=n.subtract(s,x.set({m:s.size,d:y})),k=n.add(a,x.set({m:a.size,d:u})),C=n.subtract(a,x),I=n.add(h,x.set({m:h.size,d:m})),F=n.add(I,k).multiply(.5),q=n.add(T,C).multiply(.5);t.push([k,F]),i.unshift([C,q])}return[...t,...i]}destroy(){this.stop(),this.particles.clear()}};let g=w;o(g,"painterMap",{canvas:v,svg:M}),p.FireFlame=g,p.Vector=n,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});