@matechat/core
Version:
前端智能化场景解决方案UI库,轻松构建你的AI应用。
143 lines (142 loc) • 5.71 kB
JavaScript
var f = Object.defineProperty;
var u = (d, t, e) => t in d ? f(d, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : d[t] = e;
var m = (d, t, e) => u(d, typeof t != "symbol" ? t + "" : t, e);
class v {
constructor(t = {}) {
m(this, "mermaidInstance", null);
m(this, "isLoading", !1);
m(this, "lastValidResult", "");
m(this, "viewStateMap", /* @__PURE__ */ new WeakMap());
m(this, "containerHeight", 400);
this.config = t;
}
async loadMermaid() {
if (this.mermaidInstance)
return this.mermaidInstance;
if (this.isLoading)
return new Promise((t) => {
const e = () => {
this.mermaidInstance ? t(this.mermaidInstance) : setTimeout(e, 50);
};
e();
});
this.isLoading = !0;
try {
const { default: t } = await import("mermaid");
return t.initialize({
theme: this.config.theme || "default",
startOnLoad: !1,
suppressErrorRendering: !0,
...this.config
}), this.mermaidInstance = t, t;
} catch (t) {
throw console.error("Failed to load mermaid:", t), new Error("Failed to load mermaid library");
} finally {
this.isLoading = !1;
}
}
async renderToContainer(t, e, a = "light") {
const s = await this.renderMermaid(e, a);
t.innerHTML = s;
const i = t.querySelector("svg");
i && (this.initViewState(t, i), this.applyTransform(t, i), i.addEventListener("mousedown", (o) => this.onSvgMouseDown(o, t, i)));
}
initViewState(t, e) {
let a = e.getAttribute("viewBox"), s = 0, i = 0;
if (a) {
const l = a.split(/\s+/);
s = parseFloat(l[2]), i = parseFloat(l[3]);
} else
s = e.width.baseVal.value || e.getBoundingClientRect().width, i = e.height.baseVal.value || e.getBoundingClientRect().height;
const o = t.clientWidth || 0, r = this.containerHeight;
let n = 1;
s && i && o && r && (n = Math.min(o / s, r / i, 1)), this.viewStateMap.set(t, {
scale: n,
offsetX: 0,
offsetY: 0,
dragging: !1,
dragStart: { x: 0, y: 0 },
lastOffset: { x: 0, y: 0 }
});
}
applyTransform(t, e) {
const a = this.viewStateMap.get(t);
a && (e.style.maxWidth = "90%", e.style.maxHeight = "90%", e.style.position = "absolute", e.style.left = "50%", e.style.top = "50%", e.style.transform = `translate(-50%, -50%) translate(${a.offsetX}px, ${a.offsetY}px) scale(${a.scale})`, e.style.transformOrigin = "center center", e.style.cursor = a.dragging ? "grabbing" : "grab");
}
zoomIn(t) {
const e = t.querySelector("svg"), a = this.viewStateMap.get(t);
e && a && (a.scale = Math.min(a.scale + 0.2, 3), this.applyTransform(t, e));
}
zoomOut(t) {
const e = t.querySelector("svg"), a = this.viewStateMap.get(t);
e && a && (a.scale = Math.max(a.scale - 0.2, 0.2), this.applyTransform(t, e));
}
reset(t) {
const e = t.querySelector("svg");
e && (this.initViewState(t, e), this.applyTransform(t, e));
}
async download(t, e = "diagram.png") {
const a = t.querySelector("svg");
if (a)
try {
const s = a.cloneNode(!0), i = new XMLSerializer().serializeToString(s), o = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(i)}`, r = new Image();
await new Promise((g, h) => {
r.onload = () => g(), r.onerror = (c) => h(new Error("Image loading failed")), r.src = o;
});
const n = document.createElement("canvas"), l = n.getContext("2d");
if (!l) throw new Error("Canvas context not available");
n.width = r.width * 2, n.height = r.height * 2, l.fillStyle = "white", l.fillRect(0, 0, n.width, n.height), l.drawImage(r, 0, 0), n.toBlob((g) => {
if (!g) {
console.error("Failed to create blob from canvas");
return;
}
const h = URL.createObjectURL(g), c = document.createElement("a");
c.href = h, c.download = e, document.body.appendChild(c), c.click(), setTimeout(() => {
document.body.removeChild(c), URL.revokeObjectURL(h);
}, 100);
}, "image/png");
} catch (s) {
console.error("Failed to download diagram:", s);
}
}
onSvgMouseDown(t, e, a) {
const s = this.viewStateMap.get(e);
if (!s) return;
s.dragging = !0, s.dragStart = { x: t.clientX, y: t.clientY }, s.lastOffset = { x: s.offsetX, y: s.offsetY };
const i = (r) => this.onSvgMouseMove(r, e, a), o = () => this.onSvgMouseUp(e, a, i, o);
document.addEventListener("mousemove", i), document.addEventListener("mouseup", o), this.applyTransform(e, a);
}
onSvgMouseMove(t, e, a) {
const s = this.viewStateMap.get(e);
!s || !s.dragging || (s.offsetX = s.lastOffset.x + (t.clientX - s.dragStart.x), s.offsetY = s.lastOffset.y + (t.clientY - s.dragStart.y), this.applyTransform(e, a));
}
onSvgMouseUp(t, e, a, s) {
const i = this.viewStateMap.get(t);
i && (i.dragging = !1, document.removeEventListener("mousemove", a), document.removeEventListener("mouseup", s), this.applyTransform(t, e));
}
async renderMermaid(t, e = "light") {
try {
const a = await this.loadMermaid();
this.config.theme !== e && a.initialize({
startOnLoad: !1,
suppressErrorRendering: !0,
theme: e === "dark" ? "dark" : "default",
...this.config
});
const s = `mc_mermaid_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, { svg: i } = await a.render(s, t);
return this.lastValidResult = i, i;
} catch {
return this.lastValidResult;
}
}
// 设置配置
setConfig(t = {}) {
this.config = {
theme: "default",
...t
};
}
}
export {
v as MermaidService
};