Skip to content

feat(profiling): structured render profiler + benchmark harness + perf baseline - #7870

Merged
pbrolin47 merged 15 commits into
developfrom
feat/render-profiler
Jun 17, 2026
Merged

pbrolin47 merged 15 commits into
developfrom
feat/render-profiler

Conversation

@knsv-bot

Copy link
Copy Markdown
Collaborator

Summary

Adds a zero-production-cost structured render profiler and a Dev Explorer
benchmark harness so we can see exactly where time goes when rendering large
diagrams — plus performance fixtures and a baseline score to track improvements.
Measurement only: no rendering behavior changes.

This is the foundation for a series of large-diagram perf optimizations; the
follow-up PRs build on it.

Motivation

Optimizing large-diagram rendering responsibly needs reliable, low-overhead
measurement that:

  • breaks a render into phases — parse → prepare → measure → layout → paint → serialize;
  • separates external layout-library time (dagre dagreLayout / elk elk.layout,
    not ours to optimize) from our wrapper code; and
  • attributes hot per-node work (DOM building, getBBox/getBoundingClientRect)
    inside the measure phase.

Zero production cost

Every call site is guarded by injected.profiling, a build-time constant esbuild
replaces with false in normal builds. The guards fold away, all profiler
references drop, and the module tree-shakes out — zero bytes, zero runtime cost.
Two gates:

  1. Build-time (injected.profiling) — present only in dev/profiling builds.
  2. Runtime (profiler.enabled) — off by default even when compiled in; opt in
    with __mermaidProfiler.enable().

What's included

Core profiler (packages/mermaid/src/profiler.ts + spec)

  • Hierarchical phase tree + flat "buckets" for hot ops that run too often to be tree nodes.
  • performance.measure per phase (DevTools Timings), labeled performance.mark
    at each phase start, and a "Mermaid render" custom DevTools track (Chrome 130+).
  • Structured console summary; single profiler shared across bundles (elk inlines
    core) via globalThis.

Phase instrumentation

  • mermaidAPI.ts: parse + serialize spans.
  • common renderer: prepare / measure / layout / paint spans.
  • dagre/index.js: dagre node-measurement attributed to measure; dagreLayout()
    bracketed as layoutCore.
  • elk (mermaid-layout-elk/src/render.ts): elk.layout() bracketed as layoutCore.
  • Per-op measure buckets (getBBox/getBoundingClientRect).

Dev Explorer Profile tab

  • Profile the current diagram or a whole folder; compare layouts side-by-side.
  • Trimmed-mean timing (drop fastest + slowest, warmup skipped), a set score, and
    Copy-as-JSON for cross-session tracking.
  • External-library time read from the direct child of the layout span (dagre
    emits nested subgraph layoutCore spans a depth-first search would misattribute).

Build plumbing — injected.profiling define wired through the esbuild/vite configs.

Perf fixtures + baseline — cypress/platform/dev-diagrams/performance/flowcharts/
(medium/large/huge ×5) + baseline.json.

Drive-by fix — guard generateDashArray against short/degenerate edges (a
RangeError surfaced while profiling huge flowcharts).

How to use

  1. pnpm dev.
  2. /dev → pick a diagram → Profile tab → Run profile (or benchmark the folder).
  3. DevTools: __mermaidProfiler.enable(), enable "Show custom tracks" in the
    Performance panel, record one render → phases appear as labeled bars in the
    "Mermaid render" track with ▶ start markers.

Risk / testing

  • No production behavior change; guards verified to tree-shake out of production bundles.
  • profiler.spec.ts covers the profiler; existing suites unaffected.

🤖 Generated with Claude Code

knsv and others added 9 commits June 15, 2026 13:48
… Explorer compare

Add an opt-in hierarchical render profiler that times the pipeline in four
phases — parse, prep (prepare+measure), layout, paint — plus a serialize tail,
with nestable sub-spans.

- Build-time gated by `injected.profiling` so it tree-shakes out of production
  entirely (zero bytes); runtime `enabled` toggle keeps it a no-op until turned
  on even in dev/profiling builds.
- Emits User Timing measures (DevTools "Timings" track) and a structured console
  summary; exposes a single shared `globalThis.__mermaidProfiler` instance so
  spans from separately-bundled layouts (e.g. layout-elk) aggregate into one tree.
- Instrumented at the unified seams: parse/draw/serialize in mermaidAPI and
  prepare/measure/layout/paint in the common layout renderer (dagre/elk/swimlane).
- Dev Explorer gains a "Profile" tab: run the current diagram through selected
  layouts (median of N) and compare per-phase timings side by side.
- Dev server builds a profiling-enabled mermaid core up front so external layout
  bundles that inline mermaid pick up live spans.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A neo-look dashed/dotted edge shorter than its combined marker offsets
(negative middle length) or with a degenerate path (NaN getTotalLength)
produced a negative/NaN count, so `Array(numberOfPairs)` threw
"RangeError: Invalid array length" — surfacing on large diagrams where some
edge hits that case. Clamp the dash-pair count to a non-negative finite integer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…phase

dagre supplies a no-op measureLayout hook and sizes nodes inside its layout
core, so its profiler "measure" phase read 0 while that cost hid inside
"layout" — making it non-comparable to elk. Bracket the DOM node-sizing block
(group setup, insertNode/getBBox, edge labels) with a "measure" span that ends
before dagreLayout(), so the explorer can report measure on its own and layout
as pure algorithm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ming, JSON export

- Profile scope toggle: the current diagram or every .mmd in the folder.
- Per-layout "score" = total render time across the set (lower is better) for
  tracking optimizations, plus per-phase totals and a per-diagram breakdown.
- Warmup pass (absorbs the one-time dynamic layout-loader import) and drop the
  fastest + slowest run per series before averaging.
- Normalize the measure/layout split so dagre and elk are comparable cell-by-cell.
- "Copy JSON" button exports a structured snapshot of the last run.
- Raise maxTextSize/maxEdges via initialize() (both are secure keys a diagram's
  frontmatter can't change) so large diagrams render in the explorer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
15 flowchart fixtures (medium/large/huge) under dev-diagrams/performance plus a
baseline.json captured with the Dev Explorer benchmark (folder scope, 5 iters,
trimmed mean): dagre 11723ms vs elk 16766ms across the set. Tracks render
performance so optimizations can be measured against a fixed baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap the actual external layout call — dagreLayout() and elkjs's elk.layout() —
in a "layoutCore" span, so the layout phase breaks into:
  - lib:  the external algorithm (untouchable)
  - ours: our wrapper around it (graph build/apply, serialization, DOM)
Shown as sub-rows in the Dev Explorer table and carried in the JSON export as
layoutLib/layoutOurs. elk reads the shared profiler off globalThis (it can't
import it from the external package); dagre is gated by injected.profiling.

Caveat: dagre lays out subgraphs recursively inside the measure span, so its
"lib" reflects only the top-level call on diagrams with subgraphs; flat
diagrams are exact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Four fixtures hardcoded `layout: dagre` in frontmatter, which overrode the
benchmark's chosen layout (layout is not a secured config key) — so the elk
column was silently rendering dagre. Drop the directive so each engine is
actually profiled, and refresh baseline.json with valid numbers
(dagre 11855ms vs elk 16406ms across the 15-fixture set).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add labeled performance.mark at each phase start and a "Mermaid render"
custom DevTools track (detail.devtools), and instrument the per-node
measure reads (getBBox / getBoundingClientRect in labelHelper, insertLabel
and updateNodeBounds) into summed profiler buckets so the measure phase's
cost can be attributed. All sites are guarded by `injected.profiling`, so
production builds tree-shake them away.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show the summed getBBox/getBoundingClientRect buckets in the Profile tab and
take the external-library layout time from the direct child of the layout
span (dagre emits nested subgraph layoutCore spans that a depth-first search
would wrongly attribute).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 71b8843
🔍 Latest deploy log https://app.netlify.com/projects/mermaid-js/deploys/6a327aacb1b5b10008771443
😎 Deploy Preview https://deploy-preview-7870--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

changeset-bot Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 71b8843

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mermaid Patch

Not sure what this means? Click here to learn what changesets are.

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

@github-actions github-actions Bot added the Type: Enhancement New feature or request label Jun 17, 2026
knsv and others added 3 commits June 17, 2026 09:01
eslint require-await failed in CI (3 errors) — sync test callbacks were marked
async. profiler.span accepts sync functions, so the async is unnecessary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The machine-generated baseline.json wasn't run through prettier (the pre-commit
lint-staged glob excludes .json), so CI's prettier --check flagged it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	packages/mermaid/src/rendering-util/layout-algorithms/dagre/index.js
@pkg-pr-new

pkg-pr-new Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@mermaid-js/examples

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

mermaid

npm i https://pkg.pr.new/mermaid@7870

@mermaid-js/layout-elk

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

@mermaid-js/layout-tidy-tree

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

@mermaid-js/mermaid-zenuml

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

@mermaid-js/parser

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

@mermaid-js/tiny

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

commit: 71b8843

@codecov

codecov Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0.27174% with 734 lines in your changes missing coverage. Please review.
✅ Project coverage is 2.91%. Comparing base (94a8f3f) to head (71b8843).

Files with missing lines Patch % Lines
.esbuild/dev-explorer/diagram-viewer.ts 0.00% 419 Missing ⚠️
packages/mermaid/src/profiler.ts 0.51% 195 Missing ⚠️
packages/mermaid/src/mermaidAPI.ts 0.00% 36 Missing ⚠️
...c/rendering-util/rendering-elements/shapes/util.ts 0.00% 21 Missing ⚠️
...c/rendering-util/layout-algorithms/common/index.ts 0.00% 16 Missing ⚠️
.esbuild/server.ts 0.00% 12 Missing ⚠️
packages/mermaid-layout-elk/src/render.ts 0.00% 10 Missing ⚠️
...rc/rendering-util/layout-algorithms/dagre/index.js 12.50% 7 Missing ⚠️
...aid/src/rendering-util/rendering-elements/edges.js 0.00% 7 Missing ⚠️
packages/mermaid/src/rendering-util/createText.ts 0.00% 5 Missing ⚠️
... and 3 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           develop   #7870      +/-   ##
==========================================
- Coverage     2.94%   2.91%   -0.03%     
==========================================
  Files          655     656       +1     
  Lines        69752   70406     +654     
  Branches       978     979       +1     
==========================================
+ Hits          2053    2055       +2     
- Misses       67699   68351     +652     
Flag Coverage Δ
unit 2.91% <0.27%> (-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/type.d.ts 100.00% <ø> (ø)
.vite/build.ts 0.87% <0.00%> (-0.01%) ⬇️
.esbuild/build.ts 0.00% <0.00%> (ø)
.esbuild/util.ts 0.00% <0.00%> (ø)
packages/mermaid/src/rendering-util/createText.ts 0.00% <0.00%> (ø)
...rc/rendering-util/layout-algorithms/dagre/index.js 0.14% <12.50%> (+0.14%) ⬆️
...aid/src/rendering-util/rendering-elements/edges.js 0.00% <0.00%> (ø)
packages/mermaid-layout-elk/src/render.ts 0.00% <0.00%> (ø)
.esbuild/server.ts 0.00% <0.00%> (ø)
...c/rendering-util/layout-algorithms/common/index.ts 0.41% <0.00%> (-0.03%) ⬇️
... and 4 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

argos-ci Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

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

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Jun 17, 2026, 10:59 AM

knsv and others added 2 commits June 17, 2026 09:47
… don't throw

esbuild's `define` replaces `injected.profiling` etc. only in bundled builds. The
docs generator runs source through tsx without that define, so profiler.ts's
module-level `injected.profiling` threw `ReferenceError: injected is not defined`,
failing build-docs. Seed a production-equivalent default on globalThis before the
read; bundled builds replace the reads with literals and never touch it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@knsv
knsv marked this pull request as ready for review June 17, 2026 08:09
@pbrolin47

Copy link
Copy Markdown
Collaborator

Hi @knsv-bot
Thanks for this PR. Some things to address:

[sisyphos-bot]


What's Working Well

🎉 The dual-gate pattern is the right architecture. Build-time constant (injected.profiling) eliminates the code from production bundles entirely. The runtime toggle
(profiler.enabled) means even in dev you pay nothing until you opt in. Elegant design with correct use of /* @PURE */ on the fallback new Profiler() to ensure tree-shaking.

🎉 profiler.span() correctly prevents span leaks on exceptions — the try/finally ensures end() is called regardless of whether the wrapped callback throws. The same guarantee
holds for tickSync and tick. This is exactly right for instrumentation code that must never break a render.

🎉 profiler.stop() defensively drains the entire stack (while (this.stack.length > 0) { this.end(); }), so a thrown exception that skips stop() won't corrupt the profiler state
for the next render.

🎉 The ELK cross-bundle solution is well-conceived. The @mermaid-js/layout-elk package can't import profiler.ts from the mermaid package, so it reaches the shared instance via
globalThis.__mermaidProfiler. The optional-chaining access (profiler?.begin('layoutCore')) means it's a complete no-op in production builds where the global is never set.

🎉 The generateDashArray bug fix is clean and well-commented. Array(n) with negative n throws a RangeError; clamping to Math.max(0, rawPairs) with a NaN guard is the correct
fix. The comment explains the two failure scenarios (short edge, degenerate path).

🎉 injected global fallback seed in profiler.ts correctly handles tsx/ts-node environments where esbuild's define replacements haven't run. Well-documented.


Issues

🟡 [important] — Missing changeset for the generateDashArray bug fix

packages/mermaid/src/rendering-util/rendering-elements/edges.js has a production fix: Array(numberOfPairs) was throwing RangeError: Invalid array length on short or degenerate
edges in large flowcharts. This is a user-visible crash fix that needs a patch changeset. The profiling infrastructure itself doesn't need one (zero production impact), but this
fix does.


🟡 [important] — tickSync, tick, and buckets have no test coverage

packages/mermaid/src/profiler.spec.ts

tickSync and tick (added in a later commit) are the methods actually called in the shared rendering code (createText.ts instrumented three getBBox/getBoundingClientRect call
sites; shapes/util.ts instrumented four more). The buckets field on ProfileRecord — the output of all that instrumentation — is also untested. It would be easy to silently break
the accumulation logic or miss a this.buckets = {} reset between renders.

Suggested additions to profiler.spec.ts:
it('tickSync accumulates time into buckets', () => {
profiler.enable();
profiler.start('render');
const result = profiler.tickSync('getBBox', () => 42);
profiler.stop();
expect(result).toBe(42);
expect(profiler.records[0].buckets['getBBox']).toBeGreaterThanOrEqual(0);
});

it('buckets reset between renders', () => {
profiler.enable();
profiler.start('render');
profiler.tickSync('getBBox', () => {});
profiler.stop();
profiler.start('render');
profiler.stop();
expect(profiler.records[1].buckets['getBBox']).toBeUndefined();
});


🟢 [nit] — profiler.begin('serialize') is manually paired in mermaidAPI.ts

packages/mermaid/src/mermaidAPI.ts

The serialize phase uses an explicit begin/end pair rather than span(). If anything between them throws (unlikely, but attachFunctions() mutates DOM state), the span leaks open.
profiler.stop() would recover on the next render, but the record for the failing render would show duration: -1 for serialize. Using span() here would be consistent with the
other phase instrumentation and eliminate this case.


🟢 [nit] — && profiler.tickSync optional check in call sites could use a comment

packages/mermaid/src/rendering-util/createText.ts and shapes/util.ts

The pattern:
injected.profiling && profiler.tickSync
? profiler.tickSync('getBBox', () => ...)
: getBBox()
The && profiler.tickSync check guards against the __mermaidProfiler global coming from an older bundle that predates tickSync. The intent isn't obvious at first glance — a
one-line comment would clarify it.


Security

The profiler is entirely dev-only. In production (injected.profiling = false), every if (injected.profiling) block folds away and profiler.ts tree-shakes out entirely. No
user-controlled data flows into phase names — they're all hardcoded string literals ('parse', 'draw', 'measure', etc.). performance.mark/performance.measure names are constants.
console.log in printSummary outputs only phase names and numeric timing values, never diagram content. span() uses try/finally and rethrows — the DOMPurify sanitization at the
SVG output boundary is not affected. No XSS issues identified.


- Add a patch changeset for the generateDashArray RangeError fix (a
  user-visible edge-rendering crash on short/degenerate paths).
- Cover tickSync/tick, bucket accumulation, and the per-render bucket
  reset in profiler.spec.ts (previously untested).
- Run the serialize phase inside a guarded profiler.span() instead of a
  manual begin/end pair, so a throw can't leak the span or record
  duration:-1; the `injected.profiling` ternary keeps it tree-shaken and
  zero-cost in production (consistent with parse/draw/measure).
- Document the `&& profiler.tickSync` cross-version guard at the
  createText.ts / shapes/util.ts call sites.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@knsv-bot

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough review @pbrolin47 — all four addressed in 71b8843:

🟡 Missing changeset for the generateDashArray fix — added .changeset/fix-edge-dasharray-rangeerror.md (mermaid: patch). The profiling infra still ships no changeset (zero production impact, as you noted); the changeset covers only the user-visible RangeError crash fix in edges.js.

🟡 tickSync/tick/buckets untested — added six tests to profiler.spec.ts covering: tickSync return value + bucket accumulation, repeated calls summing into one bucket, rethrow-still-records, the async tick path, the buckets reset between renders (your exact concern), and the disabled no-op passthrough for both.

🟢 serialize manually paired begin/end — converted to profiler.span('serialize', …). The body is extracted into a serializeSvg() closure and called via the same injected.profiling ? profiler.span(...) : serializeSvg() ternary used for parse/draw/measure, so it's now leak-safe (span's try/finally, no more duration: -1 on a throw) while the profiler branch still tree-shakes away in production.

🟢 && profiler.tickSync guard needs a comment — documented the cross-version-bundle rationale at the call sites in createText.ts and shapes/util.ts.

@pbrolin47

Copy link
Copy Markdown
Collaborator

@knsv-bot , thanks for addressing the issue

[sisyphos-bot]


PR #7870 — Follow-up Review (commit 14/14: "address PR review feedback")

All items from the previous review are resolved:


✅ Missing changeset — resolved

.changeset/fix-edge-dasharray-rangeerror.md added with patch bump for mermaid. The description correctly explains both failure scenarios (short edge → negative count, degenerate
path → NaN count). Exactly what was needed.


✅ tickSync/tick/buckets untested — resolved

profiler.spec.ts adds 6 new tests that cover every case that was missing:

  • Return value passthrough for both tickSync and tick
  • Bucket accumulation across repeated calls
  • Exception rethrow while still recording elapsed time
  • Per-render bucket reset
  • No-op passthrough when disabled

The test for multiple tickSync calls summing into a single bucket (sort().toEqual([...])) is particularly thorough.


✅ profiler.begin('serialize') manual pair — resolved, and improved

The serialize phase is now extracted into a serializeSvg() closure and run via profiler.span('serialize', serializeSvg). This is cleaner than a simple begin/end swap — DOMPurify
and attachFunctions() now live inside the closure where they belong, and the span's try/finally guarantees safety. Consistent with the parse/draw pattern.


✅ && profiler.tickSync guard comment — resolved

Both createText.ts and shapes/util.ts now have clear comments explaining the cross-version guard. The shapes/util.ts comment also explicitly notes "Same pattern applies to the
other guarded reads below," which saves readers from puzzling over each occurrence independently.


Verdict: APPROVE — 🔴 0 / 🟡 0 / 🟢 0 / 🎉 4

@pbrolin47
pbrolin47 added this pull request to the merge queue Jun 17, 2026
Merged via the queue into develop with commit a2d9686 Jun 17, 2026
28 checks passed
@pbrolin47
pbrolin47 deleted the feat/render-profiler branch June 17, 2026 12:29
@github-actions github-actions Bot mentioned this pull request Aug 18, 2026
ark-65 added a commit to zhongmiao-org/mermaid-markdown-bridge that referenced this pull request Aug 21, 2026
Upstream release: https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4011.17.0

Release notes:
### Minor Changes

-   [#7842](mermaid-js/mermaid#7842) [`3670b4e`](mermaid-js/mermaid@3670b4e) Thanks [@filipsajdak](https://github.com/filipsajdak)! - feat(c4): render C4 elements through the unified shape system, using the new person shape

-   [#7812](mermaid-js/mermaid#7812) [`cdfc0ea`](mermaid-js/mermaid@cdfc0ea) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(class): route `classDiagram` to the unified (v2) renderer by default

    Set `class: { defaultRenderer: 'dagre-d3' }` in the config to restore the legacy renderer.

-   [#7785](mermaid-js/mermaid#7785) [`c45cde9`](mermaid-js/mermaid@c45cde9) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(flowchart): add collapsible flowchart subgraphs via `subgraphId@{ view: collapsed }`

-   [#7828](mermaid-js/mermaid#7828) [`8eb3afc`](mermaid-js/mermaid@8eb3afc) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(elk): add `elk.keepEntryNodeOnTop` config option to keep a recursive flow's entry node on top

-   [#7803](mermaid-js/mermaid#7803) [`74e44eb`](mermaid-js/mermaid@74e44eb) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(elk): add `elk.nodePlacementAlignment` config option

-   [#7792](mermaid-js/mermaid#7792) [`ea55b31`](mermaid-js/mermaid@ea55b31) Thanks [@RodrigojndSantos](https://github.com/RodrigojndSantos)! - feat(er): add subgraph support to ER diagrams.

-   [#7970](mermaid-js/mermaid#7970) [`a2c0fb6`](mermaid-js/mermaid@a2c0fb6) Thanks [@filipsajdak](https://github.com/filipsajdak)! - feat(flowchart): add `folder`, `bucket`, `console` (terminal window) and `browser` shapes

-   [#7842](mermaid-js/mermaid#7842) [`ae3e115`](mermaid-js/mermaid@ae3e115) Thanks [@filipsajdak](https://github.com/filipsajdak)! - feat(flowchart): add `person` shape (circular head above a rounded body), usable in flowcharts via `A@{ shape: person }`

-   [#7724](mermaid-js/mermaid#7724) [`0fd7a9f`](mermaid-js/mermaid@0fd7a9f) Thanks [@xdumaine](https://github.com/xdumaine)! - feat(xyChart): add legends for named line and bar series

### Patch Changes

-   [#7847](mermaid-js/mermaid#7847) [`215fe89`](mermaid-js/mermaid@215fe89) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): named attributes such as `$tags`, `$link` and `$sprite` are no longer clobbered to undefined when they arrive in an earlier positional slot of Person/System/Container/Component/Boundary/Rel statements.

-   [#7871](mermaid-js/mermaid#7871) [`8d874c4`](mermaid-js/mermaid@8d874c4) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(flowchart): stop dagre layout from spamming `warn`-level logs on every node/edge/cluster

-   [#8071](mermaid-js/mermaid#8071) [`b3d1f63`](mermaid-js/mermaid@b3d1f63) Thanks [@pbrolin47](https://github.com/pbrolin47)! - fix(block): sibling blocks overlapping in block diagrams when one has a label wider than 200px

-   [#7870](mermaid-js/mermaid#7870) [`71b8843`](mermaid-js/mermaid@71b8843) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: a `RangeError: Invalid array length` crash when rendering certain edges.

-   [#7924](mermaid-js/mermaid#7924) [`9cbef5d`](mermaid-js/mermaid@9cbef5d) Thanks [@nightt5879](https://github.com/nightt5879)! - fix(treeView): icons disappearing after strict security sanitization.

-   [#7850](mermaid-js/mermaid#7850) [`a34cbf0`](mermaid-js/mermaid@a34cbf0) Thanks [@aloisklink](https://github.com/aloisklink)! - fix(block): allow classdefs to update text color

-   [#7937](mermaid-js/mermaid#7937) [`f9cbe1e`](mermaid-js/mermaid@f9cbe1e) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(dagre): let a diagram's own nodeSpacing/rankSpacing take effect in the unified dagre layout

-   [#8005](mermaid-js/mermaid#8005) [`90eeece`](mermaid-js/mermaid@90eeece) Thanks [@pbrolin47](https://github.com/pbrolin47)! - fix(flowchart): reverts the behavior change from #7672 (fix/4648-directions), since arrows between subgraphs are broken

-   [#7951](mermaid-js/mermaid#7951) [`afa2f80`](mermaid-js/mermaid@afa2f80) Thanks [@aloisklink](https://github.com/aloisklink)! - perf: use `fastdom` to batch DOM measurements (up to 25% speedup)

-   Updated dependencies \[[`e848423`](mermaid-js/mermaid@e848423)]:
    -   @mermaid-js/parser@1.2.1

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants