内置mindmap改为markmap渲染

This commit is contained in:
Tron 2025-11-24 22:56:36 +08:00
parent c58e626823
commit a9b58641ea
4 changed files with 109 additions and 45 deletions

View file

@ -14,7 +14,11 @@ export const mindmapRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
if (mindmapElements.length === 0) {
return;
}
addScript(`${cdn}/js/echarts/echarts.min.js?v=0.0.0`, "protyleEchartsScript").then(() => {
// load d3 first, then markmap-lib, then markmap-view (in order)
addScript(`${cdn}/js/markmap/d3.min.js`, "protyleD3Script")
.then(() => addScript(`${cdn}/js/markmap/markmap-lib.min.js`, "protyleMarkmapLibScript"))
.then(() => addScript(`${cdn}/js/markmap/markmap-view.min.js`, "protyleMarkmapScript"))
.then(() => {
const wysiswgElement = hasClosestByClassName(element, "protyle-wysiwyg", true);
let width: number = undefined;
if (wysiswgElement && wysiswgElement.clientWidth > 0 && mindmapElements[0].firstElementChild.clientWidth === 0 && wysiswgElement.firstElementChild) {
@ -33,56 +37,101 @@ export const mindmapRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
return;
}
try {
// create or reuse container for markmap
if (!renderElement.lastElementChild || renderElement.childElementCount === 1) {
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span><div style="height:${e.style.height || "420px"}" contenteditable="false"></div>`;
} else {
renderElement.lastElementChild.classList.remove("ft__error");
}
window.echarts.init(renderElement.lastElementChild, window.siyuan.config.appearance.mode === 1 ? "dark" : undefined, {
width,
}).setOption({
series: [
{
data: [JSON.parse(Lute.EChartsMindmapStr(Lute.UnEscapeHTMLStr(e.getAttribute("data-content"))))],
initialTreeDepth: -1,
itemStyle: {
borderWidth: 0,
color: "#4285f4",
},
label: {
backgroundColor: "#f6f8fa",
borderColor: "#d1d5da",
borderRadius: 6,
borderWidth: 0.5,
color: "#586069",
lineHeight: 20,
offset: [-5, 0],
padding: [0, 5],
position: "insideRight",
},
lineStyle: {
color: "#d1d5da",
width: 1,
},
roam: true,
symbol: (value: number, params: { data?: { children?: string } }) => {
if (params?.data?.children) {
return "circle";
} else {
return "path://";
}
},
type: "tree",
},
],
tooltip: {
trigger: "item",
triggerOn: "mousemove",
},
backgroundColor: "transparent",
});
// Convert stored content to markdown using Lute (prefer existing instance), then transform/render with markmap
const raw = Lute.UnEscapeHTMLStr(e.getAttribute("data-content"));
let md: string = raw;
// prefer protyle's lute instance if available
if ((window as any).protyle && (window as any).protyle.lute && typeof (window as any).protyle.lute.BlockDOM2Md === "function") {
md = (window as any).protyle.lute.BlockDOM2Md(raw);
} else if (typeof Lute === "function" && typeof Lute.New === "function") {
try {
const luteInst = Lute.New();
if (luteInst && typeof luteInst.BlockDOM2Md === "function") {
md = luteInst.BlockDOM2Md(raw);
} else if (luteInst && typeof luteInst.BlockDOM2HTML === "function") {
md = luteInst.BlockDOM2HTML(raw);
}
} catch (e) {
// fallback to raw
md = raw;
}
}
// Try to obtain markmap entry from loaded bundles (single unified reference)
const mm: any = (window as any).markmap;
// Prefer the new markmap Transformer API when available
let data: any = null;
let rootData: any = null;
try {
if (mm && typeof mm.Transformer === "function") {
const transformer = new mm.Transformer();
const tx = transformer.transform(md);
// tx contains { root, features }
rootData = tx && tx.root;
// load assets required by used features
const assetsGetter = typeof transformer.getUsedAssets === "function" ? "getUsedAssets" : (typeof transformer.getAssets === "function" ? "getAssets" : null);
if (assetsGetter) {
const assets = (transformer as any)[assetsGetter](tx.features);
const styles = assets && assets.styles;
const scripts = assets && assets.scripts;
if (styles && typeof mm.loadCSS === "function") {
try { mm.loadCSS(styles); } catch (err) { /* ignore */ }
}
if (scripts && typeof mm.loadJS === "function") {
try { mm.loadJS(scripts, { getMarkmap: () => (window as any).markmap }); } catch (err) { /* ignore */ }
}
}
} else if (mm && typeof mm.transform === "function") {
data = mm.transform(md);
} else if ((window as any).markmap && typeof (window as any).markmap.transform === "function") {
data = (window as any).markmap.transform(md);
}
} catch (e) {
// fallback, leave data/rootData null and let downstream handle it
data = null;
rootData = null;
}
// container for svg
const container = renderElement.lastElementChild as HTMLElement;
// clear existing content and append an svg for markmap
container.innerHTML = "";
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
// use width if calculated earlier
if (typeof width === "number" && width > 0) {
svg.setAttribute("width", String(width));
} else {
svg.setAttribute("width", "100%");
}
svg.setAttribute("height", "100%");
container.appendChild(svg);
// prefer Markmap.create if available
const MarkmapCtor = (mm && (mm.Markmap || mm.default || mm)) || (window as any).Markmap;
if (MarkmapCtor && typeof MarkmapCtor.create === "function") {
if (rootData) {
// When Transformer was used we have a `root` structure
MarkmapCtor.create(svg, null, rootData);
} else {
if (!data && typeof MarkmapCtor.transform === "function") {
try { data = MarkmapCtor.transform(md); } catch (err) { data = null; }
}
MarkmapCtor.create(svg, data || { root: { children: [] } }, { embedCSS: true });
}
} else {
throw new Error("Markmap not available");
}
} catch (error) {
window.echarts.dispose(renderElement.lastElementChild);
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span><div class="ft__error" style="height:${e.style.height || "420px"}" contenteditable="false">Mindmap render error: <br>${error}</div>`;
}
e.setAttribute("data-render", "true");

2
app/stage/protyle/js/d3/d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long