Labels (CJK + multi-line)
Node and edge labels are rendered through a WebGL2 texture atlas — a shared 2048×2048 OffscreenCanvas whose glyph entries are packed via shelf-packing and uploaded as a single GPU texture. The atlas is what makes label rendering keep up with thousands of nodes.
Simple cases
ASCII, single-line, no fuss:
{ id: 'a', x: 0, y: 0, width: 120, height: 50, label: 'Source' }The label centers horizontally and vertically within the node, picks up the node's style.textColor / fontSize / fontFamily if set, and falls back to system defaults otherwise.
CJK / Hangul / Japanese / Chinese
Fully supported. The atlas write path is verified by a CDP-driven regression gate (packages/core/scripts/atlas-cjk-diag.mjs) on every release — it draws 한국어, 日本語, 中文测试, and mixed strings and asserts the live atlas pixels match an isolated reproduction within tight tolerance.
[
{ id: 'a', x: 0, y: 0, width: 140, height: 50, label: '한국어' },
{ id: 'b', x: 160, y: 0, width: 140, height: 50, label: '日本語' },
{ id: 'c', x: 320, y: 0, width: 140, height: 50, label: '中文测试' },
{ id: 'd', x: 480, y: 0, width: 200, height: 50, label: 'Mixed 한글 test' },
]If you do hit a CJK rendering issue, please open a bug with the exact label string and a screenshot — the regression gate has been tight since 0.4.1 but real-world fonts are wide territory.
Multi-line labels
Use \n in the label string. The atlas wraps each line independently and the editor preserves newlines on round-trip:
{ id: 'multi', x: 0, y: 0, width: 200, height: 100,
label: '여러줄\nテスト\n测试' }Rule of thumb for height: a multi-line label needs
node.height >= lineCount × fontSize × lineHeight + 2 × textPaddingFor the defaults (fontSize 14, lineHeight 1.4, padding ~16), three lines fit comfortably in height: 100. Too-short nodes don't crash — the label overflows the top of the node visually. The examples gallery shows the right sizing rule of thumb.
Editing a label
Double-click a node to open the inline editor. The editor is a <textarea> so multi-line labels round-trip correctly — opening, viewing, and blurring without edits all preserve the original \ns.
Keyboard:
- Enter commits (single-line UX preserved)
- Shift+Enter inserts a newline
- Escape cancels
- Blur (clicking outside) commits
IME composition (Korean / Japanese / Chinese input methods) is handled correctly — finalising a composition with Enter does not prematurely commit the edit.
To disable the inline editor globally:
new FlowChart({ container, labelEditable: false })The nodeDoubleClick event still fires when labelEditable: false, so you can route to your own editor.
Styling labels
Per-node style overrides:
{ id: 'a', x: 0, y: 0, width: 140, height: 50, label: 'Heading',
style: {
textColor: '#1a73e8',
fontSize: 16,
fontFamily: 'Inter, system-ui',
lineHeight: 1.6,
} }Global defaults flow through theme tokens — see Performance for a note on what affects atlas eviction.
Edge labels
Edges get a midpoint label via EdgeData.label. The label renders through the same atlas, on a small white background pill:
{ id: 'e1', source: 'a', target: 'b', label: 'validated' }Edge labels are single-line.
Atlas eviction
When the total label count exceeds what fits in the 2048×2048 atlas, the atlas evicts and rebuilds. From 0.4.1 onward this is invisible — the text-program re-checks the atlas generation after pre-warming and rebuilds every cached quad if eviction fired mid-frame. Older versions (0.4.0 specifically) mis-mapped labels after eviction; upgrade to 0.4.1+.