mermaid-to-excalidraw

repository·master·Indexed 21 days ago

https://github.com/excalidraw/mermaid-to-excalidraw

A utility for converting Mermaid diagram definitions into Excalidraw elements and files. It provides the `parseMermaidToExcalidraw` API to render Mermaid diagrams within the Excalidraw whiteboard environment, supporting customizable rendering via `MermaidConfig` and `ExcalidrawConfig`. The library includes functions for creating element skeletons from SVG elements, such as arrows, text, containers, and lines.

Tokens
3.8K
Snippets
17
Records
19
Agent score
73%

What's inside @excalidraw/mermaid-to-excalidraw

  1. Understand Vertex and SubGraph data structures

    master

    The parser uses internal representations for diagram components like vertices (nodes) and subgraphs. While these are used during the conversion process, they define the properties available for nodes and containers:

    Vertex

    Represents a single node in the graph.

    • id: Unique identifier.
    • type: One of VERTEX_TYPE (e.g., ROUND, CIRCLE, DIAMOND).
    • text: The label text.
    • x, y, width, height: Positional and dimensional data.
    • containerStyle: Styling for the node shape (fill, stroke, etc.).
    • labelStyle: Styling for the text (color).

    SubGraph

    Represents a grouping of nodes.

    • nodeIds: Array of Vertex IDs contained within this subgraph.
    • text: The subgraph label.
    • containerStyle: Styling for the subgraph boundary.
    export interface Vertex {
      id: string;
      type: VERTEX_TYPE;
      labelType: string;
      text: string;
      x: number;
      y: number;
      width: number;
      height: number;
      link?: string;
      containerStyle: ContainerStyle;
      labelStyle: LabelStyle;
    }
    
    export interface SubGraph {
      id: string;
      nodeIds: string[];
      text: string;
      labelType: string;
      x: number;
      y: number;
      width: number;
      height: number;
      containerStyle: ContainerStyle;
      labelStyle: LabelStyle;
    }
  2. Configure Mermaid parsing with MermaidConfig

    master

    You can pass a MermaidConfig object to parseMermaidToExcalidraw to customize the rendering. The following configuration parameters are currently supported:

    KeyTypeDefaultDescription
    startOnLoadbooleanfalseWhether to start the diagram automatically when the page loads.
    flowchart.curve"linear" | "basis""linear"The flowchart curve style.
    themeVariables.fontSizestring{ fontSize: "20px" }Theme variables for font size.
    maxEdgesnumber500Maximum number of edges to be rendered.
    maxTextSizenumber50000Maximum number of characters to be rendered.
    interface MermaidConfig {
      /**
       * Whether to start the diagram automatically when the page loads.
       * @default false
       */
      startOnLoad?: boolean;
      /**
       * The flowchart curve style.
       * @default "linear"
       */
      flowchart?: {
        curve?: "linear" | "basis";
      };
      /**
       * Theme variables
       * @default { fontSize: "20px" }
       */
      themeVariables?: {
        fontSize?: string;
      };
      /**
       * Maximum number of edges to be rendered.
       * @default 500
       */
      maxEdges?: number;
      /**
       * Maximum number of characters to be rendered.
       * @default 50000
       */
      maxTextSize?: number;
    }
  3. Use parseMermaidToExcalidraw to convert diagrams

    master

    The primary API for converting Mermaid diagrams to Excalidraw elements is parseMermaidToExcalidraw. It accepts a Mermaid diagram definition string and an optional configuration object.

    Returns a Promise that resolves to an object containing elements and files which can be rendered on Excalidraw. If the parsing fails, it throws an error that should be caught to display the message to users.

    import { parseMermaidToExcalidraw } from "@excalidraw/mermaid-to-excalidraw";
    
    try {
      const { elements, files } = await parseMermaidToExcalidraw(
        diagramDefinition,
        {
          themeVariables: {
            fontSize: "25px",
          },
        }
      );
      // Render elements and files on Excalidraw
    } catch (e) {
      // Parse error, displaying error message to users
    }
  4. Configure Playwright for visual testing

    master

    The project uses Playwright for visual regression testing. The configuration is defined in playwright.config.ts and targets tests located in the ./visual-tests directory.

    Key configuration settings include:

    • testDir: Set to ./visual-tests.
    • fullyParallel: Enabled (true) to run tests in parallel.
    • forbidOnly: Prevents running tests with .only in CI environments.
    • retries: Set to 0.
    • reporter: Uses the html reporter.
    • webServer: Automatically starts the local development server using npx vite --config visual-tests/vite.config.ts at http://localhost:3419 before running tests. It is configured to reuseExistingServer: true.
    • projects: Currently configured to run tests on chromium using the Desktop Chrome device profile.
    • expect.toHaveScreenshot: Visual comparison is configured with a maxDiffPixels threshold of 2.
    import { defineConfig, devices } from "@playwright/test";
    
    export default defineConfig({
      testDir: "./visual-tests",
      fullyParallel: true,
      forbidOnly: !!process.env.CI,
      retries: 0,
      reporter: "html",
      use: {
        baseURL: "http://localhost:3419",
        trace: "on-first-retry",
      },
      projects: [
        {
          name: "chromium",
          use: { ...devices["Desktop Chrome"] },
        },
      ],
      webServer: {
        command: "npx vite --config visual-tests/vite.config.ts",
        url: "http://localhost:3419",
        reuseExistingServer: true,
      },
      expect: {
        toHaveScreenshot: {
          maxDiffPixels: 2,
        },
      },
    });
  5. Create an arrow skeleton with createArrowSkeletion

    master

    Manually construct an Arrow skeleton by providing coordinates and optional configuration. This is useful when you have the start and end points of an arrow but not an SVG element.

    const arrow = createArrowSkeletion(10, 10, 100, 100, {
      id: 'my-arrow-id',
      label: { text: 'Hello' },
      strokeColor: '#ff0000',
      strokeStyle: 'dashed',
      startArrowhead: 'cardinality_one',
      endArrowhead: 'cardinality_many'
    });
  6. Create an arrow skeleton from an SVG element with createArrowSkeletonFromSVG

    master

    Convert an existing SVGLineElement or SVGPathElement into an Arrow skeleton. This function handles coordinate extraction from line tags or path command parsing for path tags, and automatically calculates points for curved paths.

    // Assuming arrowNode is an SVGLineElement or SVGPathElement
    const arrow = createArrowSkeletonFromSVG(arrowNode, {
      label: 'Arrow Label',
      strokeStyle: 'solid',
      startArrowhead: 'cardinality_one',
      endArrowhead: 'cardinality_many'
    });
  7. Parse Mermaid definitions with parseMermaidToExcalidraw()

    master

    The parseMermaidToExcalidraw function converts a Mermaid diagram definition string into Excalidraw elements. It is an asynchronous function that accepts the Mermaid definition and an optional MermaidConfig object. It returns a promise that resolves to an array of Excalidraw elements.

    import { parseMermaidToExcalidraw } from '@excalidraw/mermaid-to-excalidraw';
    
    const mermaidDefinition = `graph TD;\nA-->B;`;
    const excalidrawElements = await parseMermaidToExcalidraw(mermaidDefinition, {
      themeVariables: { fontSize: '20px' }
    });
  8. Create a text skeleton from an SVG element with createTextSkeletonFromSVG

    master

    Extract a Text skeleton from an SVGTextElement. It uses the element's bounding box (getBBox) to determine width and height, and getComputedStyle to resolve font size and color.

    // Assuming textNode is an SVGTextElement
    const text = createTextSkeletonFromSVG(textNode, 'Extracted Text', {
      id: 'svg-text-id',
      groupId: 'group-1'
    });
  9. Create a container skeleton from an SVG element with createContainerSkeletonFromSVG

    master

    Convert an SVGSVGElement or SVGRectElement into a Container skeleton (type rectangle or ellipse). It extracts dimensions from the bounding box and applies specific styling based on the subtype:

    • highlight: Uses the SVG fill attribute as bgColor.
    • note: Sets strokeStyle to dashed automatically.
    // Assuming node is an SVGRectElement
    const container = createContainerSkeletonFromSVG(node, 'rectangle', {
      id: 'rect-1',
      subtype: 'highlight',
      label: { text: 'Container Label' }
    });