UNPKG

@9am/fire-flame

Version:
284 lines (283 loc) 9.65 kB
var T = Object.defineProperty; var z = (m, e, t) => e in m ? T(m, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : m[e] = t; var n = (m, e, t) => (z(m, typeof e != "symbol" ? e + "" : e, t), t); class c { constructor(e) { n(this, "x", 0); n(this, "y", 0); this.set(e); } static add(e, t) { return new c({ x: e.x + t.x, y: e.y + t.y }); } static subtract(e, t) { return new c({ 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 c({ x: 0, y: 0 }); class F extends c { constructor({ x: t = 0, y: i = 0, v: o = new c({ x: 0, y: 0 }), size: p = 1 }) { super({ x: t, y: i }); n(this, "v"); n(this, "link"); n(this, "size"); this.v = o, this.size = p, this.link = new c({ x: 0, y: 0 }); } update() { this.add(this.v); } } class v { constructor() { n(this, "dom"); n(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: o, particleNum: p, particleDistance: h, innerColor: d, outerColor: r } = t, a = new Path2D(); e.forEach(([l, u]) => { a.quadraticCurveTo(l.x, l.y, u.x, u.y); }), a.closePath(), this.ctx.clearRect(0, 0, this.dom.width, this.dom.height); const s = this.ctx.createRadialGradient( i, o, Math.random() * 5, i, o, p * h * 0.5 ); s.addColorStop(0, d), s.addColorStop(1, r), this.ctx.save(), this.ctx.fillStyle = s, this.ctx.strokeStyle = s, this.ctx.fill(a), this.ctx.filter = "blur(4px)", this.ctx.lineWidth = 4, this.ctx.stroke(a), this.ctx.restore(); } } class A { constructor() { n(this, "dom"); n(this, "pathStroke"); n(this, "pathFill"); n(this, "gradient"); n(this, "stopInner"); n(this, "stopOuter"); this.dom = A.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: o, wind: p } = t; this.stopInner.setAttribute("stop-color", i), this.stopOuter.setAttribute("stop-color", o), console.log(p.d * 180 / Math.PI), this.gradient.setAttribute( "gradientTransform", `rotate(${p.d * 180 / Math.PI} 0.5 0.5)` ); const [h] = e, d = e.map( ([a, s]) => `Q ${Math.ceil(a.x)},${Math.ceil(a.y)} ${Math.ceil(s.x)},${Math.ceil(s.y)}` ).join(" "), r = `M ${h == null ? void 0 : h[0].x},${h == null ? void 0 : h[0].y} ${d} Z`; this.pathStroke.setAttribute("d", r), this.pathFill.setAttribute("d", r); } } const b = Math.PI * 2, g = Math.PI * 0.5, S = (m, e) => { let t = 0, i = 1e3 / e, o = 0; const p = (s) => { if (s - t < i) { o = requestAnimationFrame(p); return; } t = s, m(), o = requestAnimationFrame(p); }, h = () => o !== 0, d = (s) => { i = 1e3 / s; }, r = () => { cancelAnimationFrame(o), o = 0; }, a = () => { h() || (t = 0, o = requestAnimationFrame(p)); }; return a(), { start: a, stop: r, setFPS: d, isRunning: h }; }, f = new c({ x: 0, y: 0 }), y = class extends c { constructor(t, i = {}) { super({ x: i.x || 0, y: i.y || 0 }); n(this, "painter"); n(this, "pIndex", 1); n(this, "particles", /* @__PURE__ */ new Map()); n(this, "spawnAnimation"); n(this, "renderAnimation"); n(this, "spawn", () => { const { particleNum: t } = this.option, i = new F({ x: this.x, y: this.y, v: new c({ 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++; }); n(this, "render", () => { this.updateParticles(); const t = this.getPath(), i = { ...this.option, x: this.x, y: this.y }; this.painter.draw(t, i); }); n(this, "onMove", (t) => { this.set({ x: t.offsetX, y: t.offsetY }); }); this.container = t, this.option = i; const o = { ...y.getDefaultOption(), ...i }; this.preparePainter(o.painterType), this.setOption(o); } static getDefaultOption() { return { x: 0, y: 0, mousemove: !0, w: 400, h: 400, fps: 60, wind: new c({ x: 0, y: -0.8 }), friction: 0.98, particleNum: 15, particleDistance: 10, particleFPS: 10, sizeCurveFn: (t, i) => t > 0.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 y.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 a, s, l, u; const { mousemove: i, fps: o, w: p, h, particleFPS: d, particleNum: r } = this.option; if (this.option = { ...this.option, ...t }, (this.option.w !== p || this.option.h !== h) && this.painter.updateSize({ w: this.option.w, h: this.option.h }), this.option.particleNum !== r && (this.particles.clear(), this.pIndex = 1), this.option.mousemove !== i) { this.container.addEventListener; const x = this.option.mousemove ? (a = this.container) == null ? void 0 : a.addEventListener : (s = this.container) == null ? void 0 : s.removeEventListener; x == null || x.call(this.container, "mousemove", this.onMove, !0); } this.option.particleFPS !== d && ((l = this.spawnAnimation) == null || l.stop(), this.spawnAnimation = S(this.spawn, this.option.particleFPS)), this.option.fps !== o && ((u = this.renderAnimation) == null || u.stop(), this.renderAnimation = S(this.render, this.option.fps)); } updateParticles() { var r; const { wind: t, friction: i, sizeCurveFn: o, particleNum: p, particleDistance: h } = this.option; let d = 0; for (const [a, s] of this.particles) { const l = (r = this.particles.get(a + 1)) != null ? r : s; if (f.set({ m: 0.1, d: b * Math.random() }), s.v.add(c.add(t, f)).multiply(i), s.size = o(d++ / (p - 1), s.size), s.update(), s.link = c.subtract(s, l), s.link.m > h) { const u = s.x, x = s.y; s.link.m = h, s.set({ x: l.x + s.link.x, y: l.y + s.link.y }), s.v.add(f.set({ x: s.x - u, y: s.y - x }).multiply(0.05)); } } } getPath() { var p, h; const t = [], i = [], o = new Path2D(); for (const [d, r] of this.particles) { const a = (p = this.particles.get(d + 1)) != null ? p : r, s = (h = this.particles.get(d - 1)) != null ? h : r; if (a === r && s === r) { o.moveTo(r.x, r.y); continue; } const l = r.link.d + g, u = a.link.d + g, x = s.link.d + g, k = c.subtract(s, f.set({ m: s.size, d: x })), M = c.add(r, f.set({ m: r.size, d: l })), P = c.subtract(r, f), C = c.add(a, f.set({ m: a.size, d: u })), I = c.add(C, M).multiply(0.5), q = c.add(k, P).multiply(0.5); t.push([M, I]), i.unshift([P, q]); } return [...t, ...i]; } destroy() { this.stop(), this.particles.clear(); } }; let w = y; n(w, "painterMap", { canvas: v, svg: A }); export { w as FireFlame, c as Vector };