@9am/fire-flame
Version:
A fire flame library.
284 lines (283 loc) • 9.65 kB
JavaScript
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
};