excalidraw

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Excalidraw Diagram Generation

Excalidraw 图表生成

Generate professional hand-drawn style diagrams in Excalidraw JSON format.
生成专业手绘风格的Excalidraw JSON格式图表。

Critical Rules

核心规则

  1. Arrow Binding (MUST follow): Arrows must bind to components bidirectionally:
    • Arrow needs
      startBinding
      and
      endBinding
      pointing to component IDs
    • Rectangle needs
      boundElements
      array listing bound arrow IDs
    • Without both, arrows won't snap to components
  2. Text requires width/height: Text elements must have
    width
    and
    height
    fields, otherwise they won't render
  3. Arrow labels: Place below arrow (y + 30) or above (y - 30), never overlapping components
  4. Background region sizing (MUST follow): Background regions (subgraphs/phases) must fully cover all contained elements:
    • Calculate bounding box: find min/max x/y of ALL elements in the region
    • Add padding: 40px on all sides
    • Formula:
      width = (maxX + maxWidth) - minX + 80
      ,
      height = (maxY + maxHeight) - minY + 80
    • Verify: every child element's bottom-right corner must be inside the region
  5. No overlaps (MUST follow): Arrows must not cross unrelated components; labels must not overlap components. See "Layout Optimization" section for strategies.
  6. Container binding (MUST follow): When connecting to grouped/nested structures, arrows must bind to the outer container (background region), NOT to internal elements:
    • If a phase/subgraph contains multiple internal steps, arrows from outside should connect to the container box
    • Internal element connections stay internal; external connections go to the container
    • Example:
      dag → main-bg
      (container), NOT
      dag → read-main
      (internal element)
    • This keeps the diagram semantically correct and visually clean
  7. Sibling layout (MUST follow): Elements at the same hierarchy level must be placed horizontally (same row), NOT vertically:
    • Siblings represent parallel/alternative paths (e.g., TCP and HTTP handlers)
    • Vertical stacking implies sequential execution, which is semantically wrong for siblings
    • Use fork arrows from parent to horizontally-aligned children
  8. Nested structure clarity (MUST follow): When a container has internal elements, ensure clear hierarchy and no overlaps:
    • Internal elements must have proper vertical spacing with arrows showing call sequence
    • Text labels must fit entirely within their rectangles (calculate:
      rect.height >= text.height + 20
      )
    • Reference annotations (file paths, line numbers) go OUTSIDE the box (below or to the right)
    • Sub-containers within a parent should be visually distinct (different opacity or color shade)
  9. Arrow path space reservation (MUST follow): When arrows connect nested containers, ensure sufficient space for arrow routing:
    • Problem: If containers are too close, arrows may pass through target containers instead of connecting to their edges
    • Solution: Proactively enlarge parent containers to leave 40-60px gap between child containers and the next target
    • When multiple sub-containers need to merge arrows to a shared target below, calculate:
      target.y >= max(child.y + child.height) + 60
    • If arrow crossing occurs after generation, increase container heights rather than using complex bypass paths
  1. 箭头绑定(必须遵守):箭头必须与组件双向绑定:
    • 箭头需包含
      startBinding
      endBinding
      字段,指向对应组件ID
    • 矩形组件需包含
      boundElements
      数组,列出绑定的箭头ID
    • 缺少任意一项,箭头都无法吸附到组件上
  2. 文本元素需指定宽高:文本元素必须包含
    width
    height
    字段,否则无法渲染
  3. 箭头标签位置:箭头标签需放置在箭头下方(y坐标+30)或上方(y坐标-30),禁止与组件重叠
  4. 背景区域尺寸(必须遵守):背景区域(子图/阶段)必须完全覆盖其包含的所有元素:
    • 计算边界框:找出区域内所有元素的最小/最大x/y坐标
    • 添加内边距:四边各留40px
    • 计算公式:
      width = (maxX + maxWidth) - minX + 80
      height = (maxY + maxHeight) - minY + 80
    • 验证:确保每个子元素的右下角都在区域内部
  5. 禁止重叠(必须遵守):箭头不得穿过无关组件;标签不得与组件重叠。可参考「布局优化」章节的解决策略。
  6. 容器绑定(必须遵守):连接分组/嵌套结构时,箭头必须绑定到外部容器(背景区域),而非内部元素:
    • 如果某个阶段/子图包含多个内部步骤,外部箭头应连接到容器框
    • 内部元素的连接保持在容器内部;外部连接仅指向容器
    • 示例:
      dag → main-bg
      (容器),而非
      dag → read-main
      (内部元素)
    • 这样可保证图表语义正确且视觉整洁
  7. 同级元素布局(必须遵守):同一层级的元素必须水平排列(同一行),不得垂直堆叠:
    • 同级元素代表并行/可选路径(如TCP和HTTP处理器)
    • 垂直堆叠会暗示顺序执行,这对同级元素来说语义错误
    • 使用分叉箭头从父元素指向水平排列的子元素
  8. 嵌套结构清晰度(必须遵守):当容器包含内部元素时,需确保层级清晰且无重叠:
    • 内部元素间需保留适当垂直间距,并用箭头表示调用顺序
    • 文本标签必须完全适配其所在矩形(计算公式:
      rect.height >= text.height + 20
    • 参考注释(文件路径、行号)需放在框外(下方或右侧)
    • 父容器内的子容器需视觉区分(不同透明度或色调)
  9. 箭头路径空间预留(必须遵守):当箭头连接嵌套容器时,需为箭头路由预留足够空间:
    • 问题:如果容器间距过近,箭头可能穿过目标容器而非连接到其边缘
    • 解决方案:主动放大父容器,在子容器与下一个目标之间留出40-60px间隙
    • 当多个子容器需要将箭头合并到下方共享目标时,计算公式:
      target.y >= max(child.y + child.height) + 60
    • 如果生成后仍出现箭头交叉,优先增加容器高度,而非使用复杂的绕行路径

Mandatory Workflow (MUST follow before writing JSON)

强制工作流(编写JSON前必须遵守)

Step 1: Arrow Path Analysis Before placing any component, list ALL arrows and their source→target pairs:
Arrow 1: A → B (horizontal)
Arrow 2: B → C (horizontal)
Arrow 3: C → A (return arrow - DANGER: will cross B if horizontal layout)
Step 2: Identify Crossing Risks For each arrow, check: "Does a straight line from source to target pass through any other component?"
  • If YES → mark as "needs layout adjustment" or "needs bypass path"
  • Common patterns that cause crossings:
    • Return arrows in horizontal layouts (e.g., C → A when B is between them)
    • Bidirectional flows between non-adjacent components
    • Hub-and-spoke patterns with central component
Step 3: Choose Layout Strategy Based on crossing risks, select appropriate layout:
  • No crossings: Use simple horizontal/vertical layout
  • 1-2 crossings: Use bypass paths (multi-point arrows)
  • 3+ crossings or complex flows: Restructure to 2D layout (grid, triangle, diamond)
Step 4: Verify Before Finalizing After generating JSON, mentally trace each arrow path and confirm:
  • No arrow passes through any component it doesn't connect to
  • No label overlaps any component
  • All background regions fully contain their elements
步骤1:箭头路径分析 在放置任何组件前,列出所有箭头及其源→目标对:
Arrow 1: A → B (horizontal)
Arrow 2: B → C (horizontal)
Arrow 3: C → A (return arrow - DANGER: will cross B if horizontal layout)
步骤2:识别交叉风险 对每个箭头,检查:「从源到目标的直线是否会穿过其他组件?」
  • 如果是 → 标记为「需要调整布局」或「需要绕行路径」
  • 常见的交叉风险场景:
    • 水平布局中的返回箭头(如B在A和C之间时,C→A的箭头)
    • 非相邻组件间的双向流
    • 中心组件的星型连接模式
步骤3:选择布局策略 根据交叉风险,选择合适的布局:
  • 无交叉:使用简单的水平/垂直布局
  • 1-2处交叉:使用绕行路径(多点箭头)
  • 3处及以上交叉或复杂流:重构为2D布局(网格、三角形、菱形)
步骤4:最终验证 生成JSON后,逐一追踪每个箭头路径并确认:
  • 箭头未穿过任何非关联组件
  • 标签未与任何组件重叠
  • 所有背景区域完全包含其内部元素

Core Elements

核心元素

Base Template

基础模板

json
{
  "type": "excalidraw",
  "version": 2,
  "source": "https://excalidraw.com",
  "elements": [],
  "appState": { "viewBackgroundColor": "#ffffff" },
  "files": {}
}
json
{
  "type": "excalidraw",
  "version": 2,
  "source": "https://excalidraw.com",
  "elements": [],
  "appState": { "viewBackgroundColor": "#ffffff" },
  "files": {}
}

Element Templates

元素模板

Rectangle (Component Box)
json
{
  "id": "unique-id",
  "type": "rectangle",
  "x": 100, "y": 100,
  "width": 140, "height": 60,
  "strokeColor": "#1e1e1e",
  "backgroundColor": "#a5d8ff",
  "roundness": { "type": 3 },
  "boundElements": [{"id": "arrow-id", "type": "arrow"}]
}
Text (width/height required, fontFamily: 4 required)
json
{
  "id": "unique-id",
  "type": "text",
  "x": 120, "y": 120,
  "width": 80, "height": 24,
  "text": "Label",
  "fontSize": 16,
  "fontFamily": 4,
  "textAlign": "center"
}
Text centering formula (to center text inside a rectangle):
  • text.x = rect.x + (rect.width - text.width) / 2
  • text.y = rect.y + (rect.height - text.height) / 2
Arrow
json
{
  "id": "unique-id",
  "type": "arrow",
  "x": 240, "y": 130,
  "points": [[0, 0], [100, 0]],
  "startBinding": { "elementId": "source-id", "focus": 0, "gap": 5 },
  "endBinding": { "elementId": "target-id", "focus": 0, "gap": 5 },
  "endArrowhead": "arrow"
}
Arrow coordinate system:
  • x
    ,
    y
    : absolute position of arrow start point
  • points
    : relative offsets from (x, y). First point is always [0, 0]
  • Example:
    x: 100, y: 200, points: [[0,0], [50, 0], [50, 100]]
    draws L-shaped arrow starting at (100, 200)
Background Region - Use rectangle with
"opacity": 30
矩形(组件框)
json
{
  "id": "unique-id",
  "type": "rectangle",
  "x": 100, "y": 100,
  "width": 140, "height": 60,
  "strokeColor": "#1e1e1e",
  "backgroundColor": "#a5d8ff",
  "roundness": { "type": 3 },
  "boundElements": [{"id": "arrow-id", "type": "arrow"}]
}
文本(必须指定宽高,必须使用fontFamily: 4)
json
{
  "id": "unique-id",
  "type": "text",
  "x": 120, "y": 120,
  "width": 80, "height": 24,
  "text": "Label",
  "fontSize": 16,
  "fontFamily": 4,
  "textAlign": "center"
}
文本居中公式(使文本在矩形内居中):
  • text.x = rect.x + (rect.width - text.width) / 2
  • text.y = rect.y + (rect.height - text.height) / 2
箭头
json
{
  "id": "unique-id",
  "type": "arrow",
  "x": 240, "y": 130,
  "points": [[0, 0], [100, 0]],
  "startBinding": { "elementId": "source-id", "focus": 0, "gap": 5 },
  "endBinding": { "elementId": "target-id", "focus": 0, "gap": 5 },
  "endArrowhead": "arrow"
}
箭头坐标系:
  • x
    ,
    y
    : 箭头起点的绝对位置
  • points
    : 相对于(x, y)的偏移量。第一个点始终为[0, 0]
  • 示例:
    x: 100, y: 200, points: [[0,0], [50, 0], [50, 100]]
    绘制从(100, 200)开始的L形箭头
背景区域 - 使用设置了
"opacity": 30
的矩形

Default Values (can be omitted)

可省略的默认值

json
"fillStyle": "solid", "strokeWidth": 2, "roughness": 1,
"opacity": 100, "angle": 0, "seed": 1, "version": 1
json
"fillStyle": "solid", "strokeWidth": 2, "roughness": 1,
"opacity": 100, "angle": 0, "seed": 1, "version": 1

Color System

配色系统

PurposeBackgroundStroke
Primary / Phase 1
#a5d8ff
#1971c2
Secondary / Phase 2
#b2f2bb
#2f9e44
Accent / Shared
#fff3bf
#e67700
Storage / State
#d0bfff
#7048e8
用途背景色描边色
主要/阶段1
#a5d8ff
#1971c2
次要/阶段2
#b2f2bb
#2f9e44
强调/共享
#fff3bf
#e67700
存储/状态
#d0bfff
#7048e8

Layout Rules

布局规则

  • Align coordinates to multiples of 20
  • Component spacing: 100-150px
  • Standard component size:
    140×60
  • Background regions:
    opacity: 30
  • Render order: earlier elements in array appear behind
  • 坐标对齐到20的倍数
  • 组件间距:100-150px
  • 标准组件尺寸:
    140×60
  • 背景区域:
    opacity: 30
  • 渲染顺序:数组中靠前的元素显示在底层

Common Diagram Patterns

常见图表模式

Sequence Diagram Layout

序列图布局

For sequence diagrams (multiple participants with message flows):
  • Place participants horizontally at top (y = 100)
  • Each phase/stage gets its own vertical section below
  • Use background regions to separate phases
  • Vertical lifelines are implicit (not drawn as elements)
  • Messages flow left-to-right or right-to-left between participants
Layout strategy:
Phase 1 (y: 80-300):   [A] -----> [B] -----> [C]
                            msg1       msg2
                       [A] <----- [B]
                            response

Phase 2 (y: 320-500):  [A'] ----> [B'] ----> [C']
                       (duplicate participants at new y)
Key insight: For multi-phase sequence diagrams, duplicate participant boxes in each phase rather than drawing long vertical lifelines. This avoids arrow crossing issues.
对于包含多个参与者和消息流的序列图:
  • 参与者水平排列在顶部(y = 100)
  • 每个阶段/步骤在下方拥有独立的垂直区域
  • 使用背景区域分隔不同阶段
  • 垂直生命线为隐式(不绘制为元素)
  • 消息在参与者之间左右流动
布局策略:
Phase 1 (y: 80-300):   [A] -----> [B] -----> [C]
                            msg1       msg2
                       [A] <----- [B]
                            response

Phase 2 (y: 320-500):  [A'] ----> [B'] ----> [C']
                       (在新y坐标处复制参与者)
关键技巧:对于多阶段序列图,在每个阶段复制参与者框,而非绘制长垂直生命线。这可避免箭头交叉问题。

Layout Optimization (Avoiding Overlaps)

布局优化(避免重叠)

Prevent Arrow Overlap

防止箭头重叠

When multiple arrows connect to the same component:
  • Use
    focus
    parameter to offset arrow positions on component edge
  • focus: -0.5
    = upper half,
    focus: 0.5
    = lower half,
    focus: 0
    = center
  • Example: two horizontal arrows can use
    focus: -0.5
    and
    focus: 0.5
    to separate vertically
当多个箭头连接到同一组件时:
  • 使用
    focus
    参数偏移箭头在组件边缘的位置
  • focus: -0.5
    = 上半部分,
    focus: 0.5
    = 下半部分,
    focus: 0
    = 中心
  • 示例:两个水平箭头可分别使用
    focus: -0.5
    focus: 0.5
    实现垂直分隔

Prevent Arrows Crossing Components

防止箭头穿过组件

When arrows would cross unrelated components, restructure the layout:
3 components with return arrow (A→B→C, C→A):
  • Triangle layout: A at top, B bottom-left, C bottom-right
  • All arrows flow along triangle edges, no crossings
4 components with return arrow (A→B→C→D, D→A):
  • Diamond layout: A at top, B left, C bottom, D right
  • Or 2×2 grid with diagonal return arrow
  • Or use bypass path for return arrow (route above/below the row)
4+ components in sequence with return arrows:
  • Split into rows: forward flow on top row, return flow on bottom row
  • Or use vertical bypass: return arrows route above/below all components
    json
    "points": [[0, 0], [0, -80], [-400, -80], [-400, 0]]
Hub-and-spoke (central component connects to many):
  • Place hub in center, spokes radially around it
  • Avoid placing spokes in a line with hub in middle
Default assumption: If there's a return arrow, horizontal layout will likely fail—plan for bypass or 2D layout upfront.
当箭头会穿过无关组件时,重构布局:
带返回箭头的3个组件(A→B→C,C→A)
  • 三角形布局:A在顶部,B在左下,C在右下
  • 所有箭头沿三角形边缘流动,无交叉
带返回箭头的4个组件(A→B→C→D,D→A)
  • 菱形布局:A在顶部,B在左侧,C在底部,D在右侧
  • 或2×2网格布局,搭配对角线返回箭头
  • 或为返回箭头使用绕行路径(在所有组件上方/下方路由)
    json
    "points": [[0, 0], [0, -80], [-400, -80], [-400, 0]]
4个以上组件的序列带返回箭头
  • 拆分为两行:正向流在上行,返回流在下行
  • 或使用垂直绕行:返回箭头在所有组件上方/下方路由
星型连接(中心组件连接多个其他组件)
  • 将中心组件放在中间,其他组件呈放射状环绕
  • 避免将组件排成直线,中心组件在中间
默认假设:如果存在返回箭头,水平布局很可能失效——提前规划绕行路径或2D布局。

Complete Example

完整示例

Flow with Return Arrow (using bypass path) A → B → C, then C → A (return arrow routes above to avoid crossing B)
Arrow analysis:
  • Arrow 1: A → B (horizontal) ✓
  • Arrow 2: B → C (horizontal) ✓
  • Arrow 3: C → A (return) ⚠️ Would cross B → use bypass path above
json
{
  "type": "excalidraw",
  "version": 2,
  "source": "https://excalidraw.com",
  "elements": [
    {"id": "a", "type": "rectangle", "x": 100, "y": 150, "width": 140, "height": 60, "backgroundColor": "#a5d8ff", "strokeColor": "#1971c2", "roundness": {"type": 3}, "boundElements": [{"id": "arr1", "type": "arrow"}, {"id": "arr3", "type": "arrow"}]},
    {"id": "a-label", "type": "text", "x": 155, "y": 168, "width": 30, "height": 24, "text": "A", "fontSize": 16, "fontFamily": 4, "textAlign": "center"},
    {"id": "b", "type": "rectangle", "x": 340, "y": 150, "width": 140, "height": 60, "backgroundColor": "#b2f2bb", "strokeColor": "#2f9e44", "roundness": {"type": 3}, "boundElements": [{"id": "arr1", "type": "arrow"}, {"id": "arr2", "type": "arrow"}]},
    {"id": "b-label", "type": "text", "x": 395, "y": 168, "width": 30, "height": 24, "text": "B", "fontSize": 16, "fontFamily": 4, "textAlign": "center"},
    {"id": "c", "type": "rectangle", "x": 580, "y": 150, "width": 140, "height": 60, "backgroundColor": "#d0bfff", "strokeColor": "#7048e8", "roundness": {"type": 3}, "boundElements": [{"id": "arr2", "type": "arrow"}, {"id": "arr3", "type": "arrow"}]},
    {"id": "c-label", "type": "text", "x": 635, "y": 168, "width": 30, "height": 24, "text": "C", "fontSize": 16, "fontFamily": 4, "textAlign": "center"},
    {"id": "arr1", "type": "arrow", "x": 245, "y": 180, "points": [[0, 0], [90, 0]], "endArrowhead": "arrow", "startBinding": {"elementId": "a", "focus": 0, "gap": 5}, "endBinding": {"elementId": "b", "focus": 0, "gap": 5}},
    {"id": "arr2", "type": "arrow", "x": 485, "y": 180, "points": [[0, 0], [90, 0]], "endArrowhead": "arrow", "startBinding": {"elementId": "b", "focus": 0, "gap": 5}, "endBinding": {"elementId": "c", "focus": 0, "gap": 5}},
    {"id": "arr3", "type": "arrow", "x": 650, "y": 145, "points": [[0, 0], [0, -60], [-480, -60], [-480, 0]], "endArrowhead": "arrow", "strokeStyle": "dashed", "startBinding": {"elementId": "c", "focus": 0, "gap": 5}, "endBinding": {"elementId": "a", "focus": 0, "gap": 5}},
    {"id": "arr3-label", "type": "text", "x": 380, "y": 60, "width": 60, "height": 20, "text": "return", "fontSize": 12, "fontFamily": 4, "textAlign": "center"}
  ],
  "appState": {"viewBackgroundColor": "#ffffff"},
  "files": {}
}
带返回箭头的流程(使用绕行路径) A → B → C,然后C → A(返回箭头从上方绕行以避开B)
箭头分析:
  • 箭头1:A → B(水平) ✓
  • 箭头2:B → C(水平) ✓
  • 箭头3:C → A(返回) ⚠️ 会穿过B → 使用上方绕行路径
json
{
  "type": "excalidraw",
  "version": 2,
  "source": "https://excalidraw.com",
  "elements": [
    {"id": "a", "type": "rectangle", "x": 100, "y": 150, "width": 140, "height": 60, "backgroundColor": "#a5d8ff", "strokeColor": "#1971c2", "roundness": {"type": 3}, "boundElements": [{"id": "arr1", "type": "arrow"}, {"id": "arr3", "type": "arrow"}]},
    {"id": "a-label", "type": "text", "x": 155, "y": 168, "width": 30, "height": 24, "text": "A", "fontSize": 16, "fontFamily": 4, "textAlign": "center"},
    {"id": "b", "type": "rectangle", "x": 340, "y": 150, "width": 140, "height": 60, "backgroundColor": "#b2f2bb", "strokeColor": "#2f9e44", "roundness": {"type": 3}, "boundElements": [{"id": "arr1", "type": "arrow"}, {"id": "arr2", "type": "arrow"}]},
    {"id": "b-label", "type": "text", "x": 395, "y": 168, "width": 30, "height": 24, "text": "B", "fontSize": 16, "fontFamily": 4, "textAlign": "center"},
    {"id": "c", "type": "rectangle", "x": 580, "y": 150, "width": 140, "height": 60, "backgroundColor": "#d0bfff", "strokeColor": "#7048e8", "roundness": {"type": 3}, "boundElements": [{"id": "arr2", "type": "arrow"}, {"id": "arr3", "type": "arrow"}]},
    {"id": "c-label", "type": "text", "x": 635, "y": 168, "width": 30, "height": 24, "text": "C", "fontSize": 16, "fontFamily": 4, "textAlign": "center"},
    {"id": "arr1", "type": "arrow", "x": 245, "y": 180, "points": [[0, 0], [90, 0]], "endArrowhead": "arrow", "startBinding": {"elementId": "a", "focus": 0, "gap": 5}, "endBinding": {"elementId": "b", "focus": 0, "gap": 5}},
    {"id": "arr2", "type": "arrow", "x": 485, "y": 180, "points": [[0, 0], [90, 0]], "endArrowhead": "arrow", "startBinding": {"elementId": "b", "focus": 0, "gap": 5}, "endBinding": {"elementId": "c", "focus": 0, "gap": 5}},
    {"id": "arr3", "type": "arrow", "x": 650, "y": 145, "points": [[0, 0], [0, -60], [-480, -60], [-480, 0]], "endArrowhead": "arrow", "strokeStyle": "dashed", "startBinding": {"elementId": "c", "focus": 0, "gap": 5}, "endBinding": {"elementId": "a", "focus": 0, "gap": 5}},
    {"id": "arr3-label", "type": "text", "x": 380, "y": 60, "width": 60, "height": 20, "text": "return", "fontSize": 12, "fontFamily": 4, "textAlign": "center"}
  ],
  "appState": {"viewBackgroundColor": "#ffffff"},
  "files": {}
}

Output

输出

  • Filename:
    {descriptive-name}.excalidraw.json
  • Location: project root or
    docs/
    folder
  • Tell user: drag into https://excalidraw.com or open with VS Code Excalidraw extension
  • 文件名:
    {descriptive-name}.excalidraw.json
  • 位置:项目根目录或
    docs/
    文件夹
  • 告知用户:可拖拽到https://excalidraw.com 或使用VS Code Excalidraw扩展打开

Notes

注意事项

  • IDs must be unique across the file
  • fontFamily
    : 1=Virgil, 2=Helvetica, 3=Cascadia, 4=Comic Shanns (MUST use for hand-drawn style)
  • strokeWidth
    usage in software diagrams:
    • 1
      (thin): background regions, container borders, secondary connections
    • 2
      (normal/default): primary components, main flow arrows
    • 4
      (bold): emphasis, critical paths, highlighted elements
  • Dashed arrows: add
    "strokeStyle": "dashed"
  • 整个文件中的ID必须唯一
  • fontFamily
    :1=Virgil,2=Helvetica,3=Cascadia,4=Comic Shanns(手绘风格必须使用此选项)
  • 软件图中
    strokeWidth
    的使用:
    • 1
      (细):背景区域、容器边框、次要连接
    • 2
      (正常/默认):主要组件、主流程箭头
    • 4
      (粗):强调、关键路径、高亮元素
  • 虚线箭头:添加
    "strokeStyle": "dashed"