From 71cfa133a634b7feede05dfa3490241625171a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Tue, 28 Oct 2025 09:53:37 +0800 Subject: [PATCH] =?UTF-8?q?mermaid=20=E6=94=B9=E4=B8=BA=E6=B5=81=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/style.css | 4 ++- js/core/app-shell.js | 68 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/css/style.css b/css/style.css index fc89fbd..bc8f3d1 100644 --- a/css/style.css +++ b/css/style.css @@ -458,4 +458,6 @@ iconify-icon { height: 100%; object-fit: contain; max-width: 100% !important; -} \ No newline at end of file +} + +#dmermaidSvg{ height: 0px;} \ No newline at end of file diff --git a/js/core/app-shell.js b/js/core/app-shell.js index 429827f..b74282c 100644 --- a/js/core/app-shell.js +++ b/js/core/app-shell.js @@ -1169,7 +1169,12 @@ streamState.mermaid = { started: false, artifactId: null, - beforeText: '' + beforeText: '', + renderedCode: null, + pendingCode: null, + renderLoopPromise: null, + codeStartIndex: null, + completed: false }; } const ctx = streamState.mermaid; @@ -1180,10 +1185,69 @@ ctx.started = true; ctx.artifactId = ctx.artifactId || Utils.generateId('mermaid'); ctx.beforeText = fullContent.substring(0, match.index); + ctx.codeStartIndex = match.index + match[0].length; this.updateMermaidPlaceholder(streamState.container, manifest, ctx); this.showViewerStreaming(manifest); } } + if (!ctx.started) { + return; + } + if (typeof ctx.codeStartIndex !== 'number' || ctx.codeStartIndex < 0) { + return; + } + let codeSection = fullContent.substring(ctx.codeStartIndex); + const closingFenceIndex = codeSection.indexOf('```'); + if (closingFenceIndex !== -1) { + ctx.completed = true; + codeSection = codeSection.substring(0, closingFenceIndex); + } + const code = codeSection.trim(); + if (!code || code === ctx.renderedCode) { + return; + } + this.scheduleMermaidStreamRender(manifest, streamState, code); + } + + scheduleMermaidStreamRender(manifest, streamState, code) { + if (!streamState || !streamState.mermaid) return; + const ctx = streamState.mermaid; + ctx.pendingCode = code; + if (ctx.renderLoopPromise) { + return; + } + const renderLoop = async () => { + while (ctx.pendingCode && ctx.pendingCode !== ctx.renderedCode) { + const nextCode = ctx.pendingCode; + ctx.pendingCode = null; + try { + await this.ensureMermaidReady(); + window.mermaid.parse(nextCode); + const renderId = `mermaidSvg`; + const { svg } = await window.mermaid.render(renderId, nextCode); + ctx.renderedCode = nextCode; + ctx.svgContent = svg; + streamState.mermaid.svgContent = svg; + streamState.mermaid.code = nextCode; + this.destroyMermaidPanZoom(); + this.renderSvgMarkup(svg, manifest.id, { + applyTransform: false, + wrapperClasses: ['svg-content-wrapper--mermaid'] + }); + } catch (error) { + ctx.lastError = error; + console.warn('Mermaid 流式渲染失败,等待更多内容补全:', error); + break; + } + } + }; + ctx.renderLoopPromise = renderLoop() + .catch((error) => { + console.warn('Mermaid 流式渲染循环异常:', error); + }) + .finally(() => { + ctx.renderLoopPromise = null; + }); } updateMermaidPlaceholder(container, manifest, ctx) { @@ -1262,7 +1326,7 @@ return artifact.svgContent; } await this.ensureMermaidReady(); - const renderId = `mermaid-${artifact.id || Utils.generateId('mermaid')}-${Date.now()}`; + //const renderId = `mermaid-${artifact.id || Utils.generateId('mermaid')}-${Date.now()}`; const code = artifact.code || artifact.content || ''; if (!code.trim()) { throw new Error('缺少 Mermaid 代码,无法渲染');