Skip to content

feat: add drag-and-drop functionality for flowchart nodes#7713

Open
BobcGn wants to merge 17 commits into
mermaid-js:developfrom
BobcGn:develop
Open

feat: add drag-and-drop functionality for flowchart nodes#7713
BobcGn wants to merge 17 commits into
mermaid-js:developfrom
BobcGn:develop

Conversation

@BobcGn
Copy link
Copy Markdown

@BobcGn BobcGn commented May 6, 2026

📑 Summary

This PR introduces a new interactive feature: Node Drag-and-Drop for Flowcharts.

Previously, users were limited by the default layout engine's positioning. This feature allows users to manually reposition nodes within the canvas, providing greater flexibility for organizing complex diagrams and enhancing the overall user experience for custom visualizations.

📏 Design Decisions

  • Interactive Layer: Integrated a dragging event listener into the flowchart rendering logic to capture mouse/touch interactions.
  • Layout Compatibility: Implemented the positioning logic to complement existing Dagre layout results, ensuring that manual adjustments don't conflict with the initial auto-layout.
  • Performance: Optimized the coordinate update frequency to ensure smooth dragging performance even in large-scale flowcharts.

📋 Tasks

Make sure you

  • 📖 have read the contribution guidelines
  • 💻 have added necessary unit/e2e tests.(demos/drag-editor-demo.html)
  • 📓 have added documentation. Make sure MERMAID_RELEASE_VERSION is used for all new features.
  • 🦋 If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

BobcGn added 3 commits May 6, 2026 17:36
Add a comprehensive drag-and-drop editor for flowchart diagrams that allows
users to reposition nodes interactively with multi-select, undo/redo, and
position persistence via localStorage.

New modules:
- CoordinateConverter: converts between viewBox and client coordinates
- DragHandler: handles pointer events for single and multi-node dragging
  with shift-click multi-select and real-time edge updates
- EdgeUpdater: updates edge paths when connected nodes are moved
- MermaidDragEditor: main orchestrator tying scanning, drag, undo, and
  storage together
- NodeScanner: discovers and monitors flowchart nodes in SVG DOM
- OverrideStore: persists node position overrides to localStorage with
  version migration, lock support, and merge logic
- UndoManager: undo/redo stack with configurable depth
- types: shared TypeScript interfaces and types
- index: barrel export for the interaction module
- interaction.spec.ts: unit tests for coordinate conversion

Demo:
- demos/drag-editor-demo.html: visual demo with multi-node selection,
  drag, undo/redo UI, and position persistence
- Add data-source and data-target attributes to edge SVG paths in both
  dagre-wrapper and rendering-util edge renderers to enable the drag
  editor's EdgeUpdater to identify connected nodes
- Export MermaidDragEditor class and related types (DragEditorOptions,
  OverrideData) from the public mermaid module entry point
- Add /.trae/ directory to .gitignore
@netlify
Copy link
Copy Markdown

netlify Bot commented May 6, 2026

Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 934d1f0
🔍 Latest deploy log https://app.netlify.com/projects/mermaid-js/deploys/6a03d4ab97b19b000747916c
😎 Deploy Preview https://deploy-preview-7713--mermaid-js.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 6, 2026

⚠️ No Changeset found

Latest commit: 934d1f0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 6, 2026

Open in StackBlitz

@mermaid-js/examples

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/examples@7713

mermaid

npm i https://pkg.pr.new/mermaid-js/mermaid@7713

@mermaid-js/mermaid-flowchart-drag

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/mermaid-flowchart-drag@7713

@mermaid-js/layout-elk

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/layout-elk@7713

@mermaid-js/layout-tidy-tree

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/layout-tidy-tree@7713

@mermaid-js/mermaid-zenuml

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/mermaid-zenuml@7713

@mermaid-js/parser

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/parser@7713

@mermaid-js/tiny

npm i https://pkg.pr.new/mermaid-js/mermaid/@mermaid-js/tiny@7713

commit: 934d1f0

Comment thread demos/drag-editor-demo.html Fixed
@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 0.40816% with 488 lines in your changes missing coverage. Please review.
✅ Project coverage is 3.24%. Comparing base (8e7a0c6) to head (934d1f0).

Files with missing lines Patch % Lines
packages/mermaid-flowchart-drag/src/index.ts 0.28% 348 Missing ⚠️
packages/mermaid-flowchart-drag/src/edge-path.ts 0.75% 131 Missing ⚠️
packages/mermaid/scripts/docs.mts 0.00% 4 Missing ⚠️
packages/mermaid/src/dagre-wrapper/edges.js 0.00% 3 Missing ⚠️
...aid/src/rendering-util/rendering-elements/edges.js 0.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           develop   #7713      +/-   ##
==========================================
- Coverage     3.26%   3.24%   -0.03%     
==========================================
  Files          598     600       +2     
  Lines        60610   61093     +483     
  Branches       914     916       +2     
==========================================
+ Hits          1981    1982       +1     
- Misses       58629   59111     +482     
Flag Coverage Δ
unit 3.24% <0.40%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/mermaid/src/diagrams/sequence/svgDraw.js 0.00% <ø> (ø)
scripts/compare-timings.ts 1.49% <ø> (ø)
scripts/jison/lint.mts 0.00% <ø> (-2.86%) ⬇️
scripts/run-e2e-scoped.ts 4.00% <ø> (ø)
scripts/size.ts 1.35% <ø> (ø)
scripts/tsc-check.ts 0.82% <ø> (ø)
scripts/verify-diagram/verify.mjs 0.00% <ø> (ø)
...aid/src/rendering-util/rendering-elements/edges.js 0.00% <0.00%> (ø)
packages/mermaid/src/dagre-wrapper/edges.js 0.00% <0.00%> (ø)
packages/mermaid/scripts/docs.mts 0.24% <0.00%> (-0.01%) ⬇️
... and 2 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@argos-ci
Copy link
Copy Markdown

argos-ci Bot commented May 6, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - May 13, 2026, 1:47 AM

BobcGn and others added 4 commits May 6, 2026 19:36
- Translate all JSDoc comments from Chinese to English
- Escape `>` to `→` in JSDoc to satisfy tsdoc/syntax rule
- Rename rAFId -> rafId, buildEdgePathD -> buildEdgePathData
- Fix cspell issue: redoable -> operations to redo
- Add dragEditor config option (boolean | DragEditorConfig) to enable drag-and-drop
  node repositioning for flowcharts via mermaid.render()
- Wire auto-activation in mermaidAPI.ts render() — when dragEditor is enabled,
  bindFunctions automatically instantiates MermaidDragEditor on the rendered SVG
- Fix XSS vulnerabilities in drag-editor-demo.html (DOMParser instead of innerHTML)
- Add 47 unit tests covering the interaction module, including 5 auto-activation tests
Copy link
Copy Markdown
Collaborator

@knsv knsv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the substantial effort here, @BobcGn — there's a lot of careful work in this PR (multi-select drag, undo/redo, edge re-routing, persistence, an extensive demo). Before we can move toward merge though, I'd like to surface some concerns about scope and architecture, in addition to the failing CI.

CI / housekeeping

  • unit-test, lint, e2e (1–5), build-docs, Publish preview release, and the Netlify deploy are all failing on the latest commit. These will need to be green.
  • No changeset has been added (changeset-bot flagged this). A user-facing feature like this needs pnpm changeset.
  • Codecov reports ~0.66% patch coverage (1,208 lines uncovered). The new interaction.spec.ts is sizable but only covers types.ts and a thin slice of CoordinateConverter — the core logic in DragHandler, EdgeUpdater, MermaidDragEditor, NodeScanner, OverrideStore, and UndoManager is essentially untested.
  • The PR is opened from the contributor's develop branch into upstream develop. That's not a blocker but tends to cause grief on subsequent PRs — a feature branch is much easier to live with.

Architectural concerns (the bigger items)

  1. Diagram-type-specific branching inside mermaidAPI.render(). The new if (config.dragEditor && (diagramType === 'flowchart-v2' || diagramType === 'flowchart')) block in mermaidAPI.ts couples a flowchart-only interactive feature directly into the shared render pipeline. The diagram-isolation rules in CLAUDE.md / project conventions ask us to avoid exactly this pattern — features that apply to one diagram type shouldn't live in the cross-cutting core API.

  2. bindFunctions is silently wrapped. Today, callers using bindFunctions(el) get DOM-event hookup. After this PR, the same call also constructs a MermaidDragEditor, attaches pointer listeners, and starts writing to localStorage. That's a surprising side effect for downstream consumers (GitHub, GitLab, Docusaurus, Obsidian, etc.) who only opted into "render this SVG."

  3. localStorage in core. Mermaid is rendered server-side by GitHub/GitLab and in many Node toolchains. OverrideStore reaches for localStorage unguarded, which will throw or no-op in those environments, and on the client it silently mutates browser storage by default. Persistence policy should be the host application's choice, not the library's.

  4. Public API expansion. MermaidDragEditor, DragEditorOptions, and OverrideData are now exported from mermaid.ts. Once shipped, those are part of the supported API surface forever. For a non-roadmap experimental feature that's a heavy commitment.

  5. Cross-cutting changes to shared edge code. Both dagre-wrapper/edges.js and rendering-util/rendering-elements/edges.js are modified to emit data-source / data-target attributes purely so the editor can re-route edges. Touching shared rendering code on behalf of a flowchart-only feature is the failure mode CLAUDE.md calls out as the #1 cross-diagram regression risk.

  6. Documentation language. The auto-generated public docs (e.g. docs/config/setup/mermaid/classes/MermaidDragEditor.md) currently ship Chinese-language descriptions ("Mermaid 图表可视化微调主控制器"). The site is English; JSDoc on exported classes should be English so it renders consistently on mermaid.js.org. (The demo itself being in Chinese is fine.)

Suggested direction

The core question is whether this belongs inside packages/mermaid at all. Mermaid's job has always been "text → SVG"; interactive editing has historically lived in separate projects (mermaid-live-editor, mermaid-chart, etc.).

A much smaller, less invasive shape would be:

  • Publish this as an external package (e.g. @mermaid-js/drag-editor) that consumes the SVG returned by mermaid.render() and attaches its own behavior.
  • Keep the only upstream change minimal: optionally adding data-source/data-target to edges (already useful for other consumers), behind no diagram-specific branch.
  • Skip the global localStorage and bindFunctions wrapping entirely — let the host app decide when/where to instantiate the editor.

That model gives you full freedom on the editor's shape, avoids the API-surface and SSR concerns, and is much easier to iterate on outside the core release cadence.

If you'd like to pursue that, I'd suggest opening an issue/discussion first so the maintainers can confirm appetite and the approach before more work goes in. Happy to help sketch what the minimal upstream change would look like if that helps.

@BobcGn
Copy link
Copy Markdown
Author

BobcGn commented May 7, 2026

Thank you for the detailed and constructive feedback! I completely understand and agree with your architectural concerns. Mermaid's core philosophy of "text → SVG" should absolutely be preserved, and I realize now that integrating heavy interactive editing, localStorage, and DOM event wrapping directly into the core API is too invasive.
Based on your suggestions, I would like to pivot my approach to fully decouple this feature from the core rendering pipeline:
1. Extract the Editor Logic: I will remove the interactive editor logic (MermaidDragEditor, localStorage handling, event binding, etc.) from this PR and the core mermaid package entirely.
2. Minimal Upstream Change: If you are open to it, I would like to scale this PR down to only add the data-source and data-target attributes to the edges (without any diagram-specific branching). This minimal, non-breaking change would provide the necessary hooks for any external editor to re-route edges properly.
3. New Implementation Plan (External/Live Editor): My new plan is to implement the drag-and-drop functionality as a completely external tool/plugin. Specifically, I'm thinking about proposing this for the Mermaid Live Editor: adding a "Customize Layout" button in the toolbar. Clicking this would take the user to a dedicated interface/page specifically for dragging nodes, editing layouts, and saving the state, which completely isolates the editing behavior from the core library.
Does this "minimal-upstream-change" approach (only keeping the generic data-* attributes here) sound good to you? If so, I will clean up this PR, fix all the CI/Lint/Coverage issues, add the changeset, and then open a separate Discussion in the mermaid-live-editor repository for the interactive UI part.
Thanks again for guiding me in the right direction!

BobcGn added 4 commits May 7, 2026 14:50
BREAKING CHANGE: Remove entire interaction module (MermaidDragEditor,
DragHandler, UndoManager, OverrideStore, NodeScanner, CoordinateConverter,
EdgeUpdater, types, tests) along with the dragEditor config option and
auto-activation wiring in mermaidAPI.ts. Also remove the drag-editor-demo.

Only the data-source and data-target attributes on SVG edge path elements
are preserved — these are generic, diagram-agnostic attributes that enable
future external editor integrations to map edges to their connected nodes.
Replaces the removed drag-editor-demo with a focused demo that
highlights the data-source / data-target attributes on SVG edge
paths. Layout puts the flowchart editor in the main central area
with a sidebar showing edge data mapping tables, summary stats,
and raw SVG attribute inspection.
Create packages/mermaid-flowchart-drag/ as a self-contained drag-and-drop
plugin for rendered flowchart SVGs. Works purely on SVG DOM — no runtime
dependency on mermaid internals. Includes smooth bezier edge recalculation,
label repositioning, undo/redo stack, and enable/disable/destroy lifecycle.

Zero intrusion into main mermaid source code. Only new files added.
Comment thread packages/mermaid-flowchart-drag/demos/basic.html Fixed
BobcGn and others added 3 commits May 7, 2026 19:35
Scope type-checked ESLint configs to .ts files only,
fix docs.mts readFileSync path for vitest CWD-independence,
and add missing cspell term 'lerp'.
Update pnpm-lock.yaml to match mermaid-flowchart-drag
package.json dependencies, and replace innerHTML with
safe DOM API in demo error handler.
@BobcGn
Copy link
Copy Markdown
Author

BobcGn commented May 7, 2026

Hi @knsv ,

I've checked the pending argos visual regression results. It flagged 11 changes (mostly in architecture and quadrant diagrams).

After inspecting the diffs closely, I can confirm there are no structural layout breaks. The flags are catching sub-pixel shifts/anti-aliasing differences (the text and icons have slight visual ghosts in the diff). This appears to be a minor rendering recalculation triggered by adding the new data-source and data-target attributes to the shared edge DOM elements.

Since I followed the advice to keep this change generic (without diagram-specific branching) and the visual baseline remains structurally intact, could a maintainer please review and approve the Argos build when possible? Thanks!

@ashishjain0512
Copy link
Copy Markdown
Collaborator

@BobcGn Reviewed and approved the argos test

@BobcGn
Copy link
Copy Markdown
Author

BobcGn commented May 10, 2026

@ashishjain0512 After you manually approved it through Argos last time, today when I was updating the branch, Argos encountered the same problem as last time. Could you approve it again?

@knsv
Copy link
Copy Markdown
Collaborator

knsv commented May 11, 2026

It has been done. We are in the process of fixing these flaky tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants