[{"data":1,"prerenderedAt":690},["ShallowReactive",2],{"msfe-doc:\u002Fen\u002Fextensions\u002Fdiagrams":3},{"id":4,"title":5,"body":6,"description":677,"extension":678,"keywords":679,"locale":683,"meta":684,"navigation":213,"order":197,"path":685,"section":686,"seo":687,"stem":688,"__hash__":689},"docs\u002Fextensions\u002Fdiagrams.en.md","Diagrams and fenced previews",{"type":7,"value":8,"toc":664},"minimark",[9,14,27,31,35,125,138,142,158,256,267,278,282,291,323,399,415,419,442,445,449,460,480,487,491,517,524,528,542,555,559,572,596,599,603,606,642,645,649,660],[10,11,13],"h2",{"id":12},"complete-interactive-example","Complete interactive example",[15,16,17,18,22,23,26],"p",{},"The flowchart uses built-in ",[19,20,21],"code",{},"Mermaid",". The chart below uses the custom ",[19,24,25],{},"echarts"," fence extension supplied on this page. Edit source, change values and move the selection away to update the preview. Read Markdown to verify rendering has not reserialized the fence.",[28,29],"msfe-demo",{"name":30},"charts\u002Feditor",[10,32,34],{"id":33},"built-in-text-diagrams-and-custom-charts","Built-in text diagrams and custom charts",[36,37,38,51],"table",{},[39,40,41],"thead",{},[42,43,44,48],"tr",{},[45,46,47],"th",{},"Scenario",[45,49,50],{},"Approach",[52,53,54,70,88,103,114],"tbody",{},[42,55,56,60],{},[57,58,59],"td",{},"Mermaid flowchart, sequenceDiagram and related diagrams",[57,61,62,63,65,66,69],{},"Install ",[19,64,21],{},"; use a ",[19,67,68],{},"mermaid"," fence",[42,71,72,75],{},[57,73,74],{},"PlantUML sequence, class, use case, component, state, deployment and related diagrams",[57,76,62,77,80,81,84,85],{},[19,78,79],{},"TextDiagrams","; use ",[19,82,83],{},"plantuml"," or ",[19,86,87],{},"puml",[42,89,90,93],{},[57,91,92],{},"Graphviz relationships, clustered architecture and dependency graphs",[57,94,62,95,80,97,84,100],{},[19,96,79],{},[19,98,99],{},"dot",[19,101,102],{},"graphviz",[42,104,105,111],{},[57,106,107,108,110],{},"An application-specific ",[19,109,25],{}," JSON protocol",[57,112,113],{},"Use this codec, block layer and controlled renderer",[42,115,116,122],{},[57,117,118,121],{},[19,119,120],{},"flow",", flowchart.js or another DSL",[57,123,124],{},"Write a fence recognizer and engine adapter; no built-in alias is provided",[15,126,127,128,131,132,134,135,137],{},"The flowchart body starts with ",[19,129,130],{},"flowchart LR",", but its fence language remains ",[19,133,68],{},". Mermaid flowchart and flowchart.js are different DSLs. The built-in extension does not route ",[19,136,120],{}," to another engine.",[10,139,141],{"id":140},"install-and-reuse-existing-behavior","Install and reuse existing behavior",[143,144,149],"pre",{"className":145,"code":146,"language":147,"meta":148,"style":148},"language-sh shiki shiki-themes github-light github-light github-dark","pnpm add '@quirekit\u002Fmsfe-markdown-extras@workspace:*' echarts\n","sh","",[19,150,151],{"__ignoreMap":148},[152,153,156],"span",{"class":154,"line":155},"line",1,[152,157,146],{},[143,159,163],{"className":160,"code":161,"language":162,"meta":148,"style":148},"language-ts shiki shiki-themes github-light github-light github-dark","import { Mermaid } from '@quirekit\u002Fmsfe-markdown-extras'\nimport { VueComponentViewRenderer } from '@quirekit\u002Fmsfe-vue'\nimport PreviewControls from '.\u002Fpreview-controls.vue'\n\nconst diagrams = Mermaid.configure({\n  controls: VueComponentViewRenderer(PreviewControls),\n})\n","ts",[19,164,165,182,195,208,215,238,250],{"__ignoreMap":148},[152,166,167,171,175,178],{"class":154,"line":155},[152,168,170],{"class":169},"sDD9d","import",[152,172,174],{"class":173},"sVPnS"," { Mermaid } ",[152,176,177],{"class":169},"from",[152,179,181],{"class":180},"s-HEn"," '@quirekit\u002Fmsfe-markdown-extras'\n",[152,183,185,187,190,192],{"class":154,"line":184},2,[152,186,170],{"class":169},[152,188,189],{"class":173}," { VueComponentViewRenderer } ",[152,191,177],{"class":169},[152,193,194],{"class":180}," '@quirekit\u002Fmsfe-vue'\n",[152,196,198,200,203,205],{"class":154,"line":197},3,[152,199,170],{"class":169},[152,201,202],{"class":173}," PreviewControls ",[152,204,177],{"class":169},[152,206,207],{"class":180}," '.\u002Fpreview-controls.vue'\n",[152,209,211],{"class":154,"line":210},4,[152,212,214],{"emptyLinePlaceholder":213},true,"\n",[152,216,218,221,225,228,231,235],{"class":154,"line":217},5,[152,219,220],{"class":169},"const",[152,222,224],{"class":223},"sUNQB"," diagrams",[152,226,227],{"class":169}," =",[152,229,230],{"class":173}," Mermaid.",[152,232,234],{"class":233},"sgQzM","configure",[152,236,237],{"class":173},"({\n",[152,239,241,244,247],{"class":154,"line":240},6,[152,242,243],{"class":173},"  controls: ",[152,245,246],{"class":233},"VueComponentViewRenderer",[152,248,249],{"class":173},"(PreviewControls),\n",[152,251,253],{"class":154,"line":252},7,[152,254,255],{"class":173},"})\n",[15,257,258,259,262,263,266],{},"Built-in Mermaid handles closed-fence recognition, asynchronous rendering, source fallback, retry and cleanup. Its public option is currently ",[19,260,261],{},"controls","; it has no arbitrary engine ",[19,264,265],{},"render"," callback. Create an extension for a different rendering pipeline.",[15,268,269,270,277],{},"The built-in renderer uses strict security, disables HTML labels and validates SVG output. It rejects document initialization directives and limits source length and edges. Failures retain readable source. Syntax depends on the installed Mermaid version; see ",[271,272,276],"a",{"href":273,"rel":274},"https:\u002F\u002Fmermaid.js.org\u002Fconfig\u002Fusage.html",[275],"nofollow","official Mermaid usage",".",[10,279,281],{"id":280},"plantuml-and-graphvizdot","PlantUML and Graphviz\u002FDOT",[15,283,284,285,287,288,290],{},"Standalone MSFE hosts install ",[19,286,79],{},"; MD Editor includes it by default. It recognizes different languages from ",[19,289,21],{},", without competing for the same fence:",[143,292,294],{"className":160,"code":293,"language":162,"meta":148,"style":148},"import { Mermaid, TextDiagrams } from '@quirekit\u002Fmsfe-markdown-extras'\n\nconst extensions = [Mermaid, TextDiagrams]\n",[19,295,296,307,311],{"__ignoreMap":148},[152,297,298,300,303,305],{"class":154,"line":155},[152,299,170],{"class":169},[152,301,302],{"class":173}," { Mermaid, TextDiagrams } ",[152,304,177],{"class":169},[152,306,181],{"class":180},[152,308,309],{"class":154,"line":184},[152,310,214],{"emptyLinePlaceholder":213},[152,312,313,315,318,320],{"class":154,"line":197},[152,314,220],{"class":169},[152,316,317],{"class":223}," extensions",[152,319,227],{"class":169},[152,321,322],{"class":173}," [Mermaid, TextDiagrams]\n",[143,324,328],{"className":325,"code":326,"language":327,"meta":148,"style":148},"language-markdown shiki shiki-themes github-light github-light github-dark","```plantuml\n@startuml\nClient -> Service: Request\nService --> Client: Response\n@enduml\n```\n\n```dot\ndigraph G {\n  rankdir=LR;\n  Draft -> Review -> Publish;\n}\n```\n","markdown",[19,329,330,335,340,345,350,355,360,364,370,376,382,388,394],{"__ignoreMap":148},[152,331,332],{"class":154,"line":155},[152,333,334],{},"```plantuml\n",[152,336,337],{"class":154,"line":184},[152,338,339],{},"@startuml\n",[152,341,342],{"class":154,"line":197},[152,343,344],{},"Client -> Service: Request\n",[152,346,347],{"class":154,"line":210},[152,348,349],{},"Service --> Client: Response\n",[152,351,352],{"class":154,"line":217},[152,353,354],{},"@enduml\n",[152,356,357],{"class":154,"line":240},[152,358,359],{},"```\n",[152,361,362],{"class":154,"line":252},[152,363,214],{"emptyLinePlaceholder":213},[152,365,367],{"class":154,"line":366},8,[152,368,369],{},"```dot\n",[152,371,373],{"class":154,"line":372},9,[152,374,375],{},"digraph G {\n",[152,377,379],{"class":154,"line":378},10,[152,380,381],{},"  rankdir=LR;\n",[152,383,385],{"class":154,"line":384},11,[152,386,387],{},"  Draft -> Review -> Publish;\n",[152,389,391],{"class":154,"line":390},12,[152,392,393],{},"}\n",[152,395,397],{"class":154,"line":396},13,[152,398,359],{},[15,400,401,402,406,407,410,411,414],{},"In ",[271,403,405],{"href":404},"\u002Fen\u002Fmd-editor","MD Editor",", Insert → Text diagram opens the shared Classic \u002F Block source workbench. Saving produces standard Markdown fences. Cancellation or rendering failure never commits a draft; existing invalid source remains readable and editable. ",[19,408,409],{},"features.extras.mermaid"," and ",[19,412,413],{},"features.extras.textDiagram"," control Mermaid and PlantUML \u002F DOT separately.",[10,416,418],{"id":417},"standalone-text-diagram-documentation","Standalone text-diagram documentation",[15,420,421,422,427,428,84,433,438,439,277],{},"The shared workbench, 25 bilingual templates, CodeMirror shortcuts, SVG \u002F PNG downloads, standalone Vue integration and asset deployment are maintained in the ",[271,423,426],{"href":424,"rel":425},"http:\u002F\u002F127.0.0.1:3260\u002Fen",[275],"Text Diagram documentation",". Open the ",[271,429,432],{"href":430,"rel":431},"http:\u002F\u002F127.0.0.1:3260\u002Fen\u002Fplayground",[275],"playground",[271,434,437],{"href":435,"rel":436},"http:\u002F\u002F127.0.0.1:3260\u002Fen\u002Freference\u002Fsupport",[275],"support boundaries"," directly. These are fixed-port local preview links; the planned domain is ",[19,440,441],{},"text-diagram.quirekit.com",[15,443,444],{},"This page continues to own MSFE fence integration and custom chart extensions. PlantUML uses the local official JavaScript core; syntax and appearance are not guaranteed to match the full Java distribution. Failures retain source.",[10,446,448],{"id":447},"_1-define-the-data-protocol","1. Define the data protocol",[15,450,451,452,455,456,459],{},"This example accepts ",[19,453,454],{},"{ type: 'bar' | 'line', labels: string[], values: number[] }",". Arrays must have matching lengths of 1–50 and numbers must be finite. Source is limited to 16,000 UTF-16 units. ",[19,457,458],{},"charts\u002Fdata.ts"," rejects unknown fields rather than implying arbitrary ECharts option support.",[143,461,463],{"className":325,"code":462,"language":327,"meta":148,"style":148},"~~~echarts\n{\"type\":\"line\",\"labels\":[\"Jan\",\"Feb\",\"Mar\"],\"values\":[12,20,16]}\n~~~\n",[19,464,465,470,475],{"__ignoreMap":148},[152,466,467],{"class":154,"line":155},[152,468,469],{},"~~~echarts\n",[152,471,472],{"class":154,"line":184},[152,473,474],{},"{\"type\":\"line\",\"labels\":[\"Jan\",\"Feb\",\"Mar\"],\"values\":[12,20,16]}\n",[152,476,477],{"class":154,"line":197},[152,478,479],{},"~~~\n",[15,481,482,483,486],{},"This is a minimal application protocol, not built-in MSFE ECharts support or a complete ",[19,484,485],{},"EChartsOption"," serializer. Extend validation, mapping and tests together. Never evaluate document text as JavaScript. JSON cannot and should not carry formatter functions.",[10,488,490],{"id":489},"_2-recognize-confirmed-closed-fences","2. Recognize confirmed, closed fences",[15,492,493,496,497,500,501,504,505,508,509,512,513,516],{},[19,494,495],{},"charts\u002Fextension.ts"," uses ",[19,498,499],{},"defineSource({ nodes: ['FencedCode'] })",", checks ",[19,502,503],{},"CodeInfo",", two ",[19,506,507],{},"CodeMark"," nodes and allowed parent context, then reads ",[19,510,511],{},"CodeText",". Return ",[19,514,515],{},"null"," for unclosed, unknown or unsupported structures to retain source.",[15,518,519,520,523],{},"The custom ECharts example deliberately replaces only top-level fences. ECharts inside quotes or lists remains source; built-in Mermaid has its own container handling. Supporting nested chart blocks requires list markers, quote prefixes, indentation and hit-testing work, not merely expanding ",[19,521,522],{},"match.from"," to a line start.",[10,525,527],{"id":526},"_3-provide-a-block-projection","3. Provide a block projection",[15,529,530,533,534,537,538,541],{},[19,531,532],{},"addProjectionLayers()"," declares ",[19,535,536],{},"placement: 'block'",", then ",[19,539,540],{},"componentView(chartRenderer, props)"," describes the non-editable preview. Block output is available before viewport layout, avoiding multiline replacement geometry errors.",[15,543,544,545,548,549,551,552,277],{},"Keep renderer identity and keys stable and pass changed props through ",[19,546,547],{},"update()",". A selection entering the source range reveals it. The chart DOM must not become another editor. A projection-only codec may return ",[19,550,515],{}," from ",[19,553,554],{},"patch()",[10,556,558],{"id":557},"_4-own-loading-sizing-and-cleanup","4. Own loading, sizing and cleanup",[15,560,561,564,565,410,568,571],{},[19,562,563],{},"charts\u002Frenderer.ts"," passes runtime ",[19,566,567],{},"scope",[19,569,570],{},"requestMeasure"," to Vue. Source changes cancel the preceding child scope before loading another chart. Unmounts, document replacement and late results require cleanup.",[15,573,574,575,578,579,582,583,586,587,590,591,277],{},"Give the container dimensions before ",[19,576,577],{},"echarts.init()",". Observe its size with ",[19,580,581],{},"ResizeObserver"," and call ",[19,584,585],{},"resize()","; disconnect and ",[19,588,589],{},"dispose()"," during cleanup. This example fixes chart height and requests CodeMirror measurement after status changes, following ",[271,592,595],{"href":593,"rel":594},"https:\u002F\u002Fecharts.apache.org\u002Fhandbook\u002Fen\u002Fconcepts\u002Fchart-size\u002F",[275],"ECharts sizing and disposal guidance",[15,597,598],{},"Failures show an explanation, the exact fence and a retry action. They never discard source. Readonly disables source editing while preserving viewing and retry.",[10,600,602],{"id":601},"_5-adapt-flowchartjs-or-another-engine","5. Adapt flowchart.js or another engine",[15,604,605],{},"Reuse the example structure while replacing these responsibilities:",[607,608,609,616,619,636,639],"ol",{},[610,611,612,613,615],"li",{},"Give the extension and layer unique names and recognize ",[19,614,120],{},", without competing with Mermaid.",[610,617,618],{},"Replace JSON validation with bounded DSL validation.",[610,620,621,622,625,626,629,630,635],{},"Load the engine in a browser lifetime. flowchart.js exposes ",[19,623,624],{},"parse(source)"," followed by ",[19,627,628],{},"drawSVG(...)"," against a sized target; consult its ",[271,631,634],{"href":632,"rel":633},"https:\u002F\u002Fgithub.com\u002Fadrai\u002Fflowchart.js",[275],"official project documentation"," for parameters.",[610,637,638],{},"Wrap engine objects, SVG, listeners and global dependencies in an independent resource lease. Release the old view before updating. Do not assume ECharts cancellation or cleanup behavior applies to another engine.",[610,640,641],{},"Constrain links, HTML, external resources and unsafe SVG. Retain copyable source fallback and verify theme, sizing and selection behavior.",[15,643,644],{},"The interactive example actually runs Mermaid and ECharts. flowchart.js is an adapter path, not an engine bundled or verified by MSFE. Worker-based layout remains possible but still needs cancellation\u002Fversion checks and a controlled DOM output boundary.",[10,646,648],{"id":647},"acceptance-criteria","Acceptance criteria",[15,650,651,652,410,656,277],{},"Compare exact source before and after rendering. Cover valid\u002Finvalid JSON, rapid changes, document replacement while loading, viewport exit, theme changes, narrow containers, readonly, copying, undo and native source reveal. A visible chart alone is insufficient. Continue with ",[271,653,655],{"href":654},"\u002Fen\u002Fextensions\u002Fresources","Resources",[271,657,659],{"href":658},"\u002Fen\u002Fextensions\u002Fprojections","Projection layers",[661,662,663],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDD9d, html code.shiki .sDD9d{--shiki-default:#D73A49;--shiki-light:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVPnS, html code.shiki .sVPnS{--shiki-default:#24292E;--shiki-light:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s-HEn, html code.shiki .s-HEn{--shiki-default:#032F62;--shiki-light:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sUNQB, html code.shiki .sUNQB{--shiki-default:#005CC5;--shiki-light:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sgQzM, html code.shiki .sgQzM{--shiki-default:#6F42C1;--shiki-light:#6F42C1;--shiki-dark:#B392F0}",{"title":148,"searchDepth":184,"depth":184,"links":665},[666,667,668,669,670,671,672,673,674,675,676],{"id":12,"depth":184,"text":13},{"id":33,"depth":184,"text":34},{"id":140,"depth":184,"text":141},{"id":280,"depth":184,"text":281},{"id":417,"depth":184,"text":418},{"id":447,"depth":184,"text":448},{"id":489,"depth":184,"text":490},{"id":526,"depth":184,"text":527},{"id":557,"depth":184,"text":558},{"id":601,"depth":184,"text":602},{"id":647,"depth":184,"text":648},"Build Mermaid and ECharts previews with loading, source fallback and resource cleanup.","md",[21,120,680,25,681,511,682],"flowchart","diagram","async","en",{},"\u002Fen\u002Fextensions\u002Fdiagrams","Extensions",{"title":5,"description":677},"extensions\u002Fdiagrams.en","ip74kZyPR1pi_sMP3Q3ySk-W45Ig6TDzF0G3zcMBw0M",1793046312542]