sketchmark 1.3.4 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -377,11 +377,13 @@ For `path`, write `value` in local coordinates near `0,0`. The renderer normaliz
377
377
  | `label` | string | Display text (required) | `label="Hello World"` |
378
378
  | `width` | number | Override auto-width (px) | `width=140` |
379
379
  | `height` | number | Override auto-height (px) | `height=55` |
380
- | `x` | number | Authored X position when parent/root uses `layout=absolute` | `x=80` |
381
- | `y` | number | Authored Y position when parent/root uses `layout=absolute` | `y=40` |
382
- | `theme` | string | Named theme preset | `theme=primary` |
383
- | `fill` | CSS color | Background fill color | `fill="#e8f4ff"` |
384
- | `stroke` | CSS color | Border/outline color | `stroke="#0044cc"` |
380
+ | `x` | number | Authored X position when parent/root uses `layout=absolute` | `x=80` |
381
+ | `y` | number | Authored Y position when parent/root uses `layout=absolute` | `y=40` |
382
+ | `label-dx` | number | Horizontal label nudge for overlap fixes and fine positioning | `label-dx=12` |
383
+ | `label-dy` | number | Vertical label nudge for overlap fixes and fine positioning | `label-dy=-6` |
384
+ | `theme` | string | Named theme preset | `theme=primary` |
385
+ | `fill` | CSS color | Background fill color | `fill="#e8f4ff"` |
386
+ | `stroke` | CSS color | Border/outline color | `stroke="#0044cc"` |
385
387
  | `stroke-width` | number | Border thickness | `stroke-width=2` |
386
388
  | `color` | CSS color | Text color | `color="#003399"` |
387
389
  | `opacity` | 0–1 | Element opacity | `opacity=0.5` |
@@ -440,12 +442,14 @@ a --> b label="HTTPS" stroke="#cc0000" stroke-width=2 color="#aa0000" font-size=
440
442
 
441
443
  ### Edge Style Properties
442
444
 
443
- | Property | Description |
444
- |----------|-------------|
445
- | `label` | Text label floating on the edge |
446
- | `stroke` | Line color |
447
- | `stroke-width` | Line thickness |
448
- | `color` | Label text color |
445
+ | Property | Description |
446
+ |----------|-------------|
447
+ | `label` | Text label floating on the edge |
448
+ | `label-dx` | Horizontal edge-label nudge to avoid crowded midpoints or crossings |
449
+ | `label-dy` | Vertical edge-label nudge to avoid crowded midpoints or crossings |
450
+ | `stroke` | Line color |
451
+ | `stroke-width` | Line thickness |
452
+ | `color` | Label text color |
449
453
  | `font-size` | Label font size |
450
454
  | `font` | Label font family |
451
455
  | `letter-spacing` | Label letter spacing |
@@ -483,12 +487,14 @@ group <id> [label="..."] [layout=row|column|grid|absolute] [gap=N] [padding=N]
483
487
 
484
488
  ### Group Properties
485
489
 
486
- | Property | Type | Description |
487
- |----------|------|-------------|
488
- | `label` | string | Group title (shown at top) |
489
- | `layout` | row / column / grid / absolute | Child arrangement direction |
490
- | `gap` | number | Space between children (px) |
491
- | `padding` | number | Inner padding (px) |
490
+ | Property | Type | Description |
491
+ |----------|------|-------------|
492
+ | `label` | string | Group title (shown at top) |
493
+ | `label-dx` | number | Horizontal group-title nudge for overlap fixes |
494
+ | `label-dy` | number | Vertical group-title nudge for overlap fixes |
495
+ | `layout` | row / column / grid / absolute | Child arrangement direction |
496
+ | `gap` | number | Space between children (px) |
497
+ | `padding` | number | Inner padding (px) |
492
498
  | `columns` | number | Column count (for `layout=grid`) |
493
499
  | `align` | start/center/end | Cross-axis alignment (align-items) |
494
500
  | `justify` | start/center/end/space-between/space-around | Main-axis alignment |
@@ -60,6 +60,8 @@ export interface ASTNode {
60
60
  id: string;
61
61
  shape: NodeShape;
62
62
  label: string;
63
+ labelDx?: number;
64
+ labelDy?: number;
63
65
  groupId?: string;
64
66
  imageUrl?: string;
65
67
  iconName?: string;
@@ -83,6 +85,8 @@ export interface ASTEdge {
83
85
  to: string;
84
86
  connector: EdgeConnector;
85
87
  label?: string;
88
+ labelDx?: number;
89
+ labelDy?: number;
86
90
  fromAnchor?: EdgeAnchor;
87
91
  toAnchor?: EdgeAnchor;
88
92
  dashed?: boolean;
@@ -94,6 +98,8 @@ export interface ASTGroup {
94
98
  kind: 'group';
95
99
  id: string;
96
100
  label: string;
101
+ labelDx?: number;
102
+ labelDy?: number;
97
103
  children: GroupChildRef[];
98
104
  layout?: LayoutType;
99
105
  columns?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ast/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ast/types.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -9,6 +9,7 @@ export declare const NODE: {
9
9
  readonly minW: 90;
10
10
  readonly maxW: 300;
11
11
  readonly defaultH: 52;
12
+ readonly mediaLabelH: 20;
12
13
  readonly fontPxPerChar: 8.6;
13
14
  readonly basePad: 26;
14
15
  };
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,MAAM;;;;;;CAMT,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;;CAMP,CAAC;AAGX,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMT,CAAC;AAGX,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;;;CAOP,CAAC;AAGX,eAAO,MAAM,UAAU;;;;;;;CAOb,CAAC;AAGX,eAAO,MAAM,KAAK;;;;CAIR,CAAC;AAGX,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;;0BAMS,SAAS,MAAM,EAAE;CACjC,CAAC;AAGX,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;CAKX,CAAC;AAGX,eAAO,MAAM,KAAK;;;;CAIR,CAAC;AAGX,eAAO,MAAM,KAAK;;;;;;;;;CASR,CAAC;AAGX,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCZ,CAAC;AAGX,eAAO,MAAM,MAAM;;;;;;;CAOT,CAAC;AAGX,eAAO,MAAM,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,MAAM;;;;;;CAMT,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;;;CAOP,CAAC;AAGX,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMT,CAAC;AAGX,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;;;CAOP,CAAC;AAGX,eAAO,MAAM,UAAU;;;;;;;CAOb,CAAC;AAGX,eAAO,MAAM,KAAK;;;;CAIR,CAAC;AAGX,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;;0BAMS,SAAS,MAAM,EAAE;CACjC,CAAC;AAGX,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;CAKX,CAAC;AAGX,eAAO,MAAM,KAAK;;;;CAIR,CAAC;AAGX,eAAO,MAAM,KAAK;;;;;;;;;CASR,CAAC;AAGX,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCZ,CAAC;AAGX,eAAO,MAAM,MAAM;;;;;;;CAOT,CAAC;AAGX,eAAO,MAAM,MAAM,+BAA+B,CAAC"}
package/dist/index.cjs CHANGED
@@ -600,6 +600,12 @@ function parse(src, options = {}) {
600
600
  id,
601
601
  shape,
602
602
  label: props.label || "",
603
+ ...(props["label-dx"] !== undefined
604
+ ? { labelDx: parseFloat(props["label-dx"]) }
605
+ : {}),
606
+ ...(props["label-dy"] !== undefined
607
+ ? { labelDy: parseFloat(props["label-dy"]) }
608
+ : {}),
603
609
  ...(props.width ? { width: parseFloat(props.width) } : {}),
604
610
  ...(props.height ? { height: parseFloat(props.height) } : {}),
605
611
  ...(props.x ? { x: parseFloat(props.x) } : {}),
@@ -640,6 +646,12 @@ function parse(src, options = {}) {
640
646
  id,
641
647
  shape: "note",
642
648
  label: (props.label ?? "").replace(/\\n/g, "\n"),
649
+ ...(props["label-dx"] !== undefined
650
+ ? { labelDx: parseFloat(props["label-dx"]) }
651
+ : {}),
652
+ ...(props["label-dy"] !== undefined
653
+ ? { labelDy: parseFloat(props["label-dy"]) }
654
+ : {}),
643
655
  theme: props.theme,
644
656
  ...(meta ? { meta } : {}),
645
657
  style: propsToStyle(props),
@@ -688,6 +700,8 @@ function parse(src, options = {}) {
688
700
  kind: "group",
689
701
  id,
690
702
  label: props.label ?? "",
703
+ labelDx: props["label-dx"] !== undefined ? parseFloat(props["label-dx"]) : undefined,
704
+ labelDy: props["label-dy"] !== undefined ? parseFloat(props["label-dy"]) : undefined,
691
705
  children: [],
692
706
  layout: props.layout,
693
707
  columns: props.columns !== undefined ? parseInt(props.columns, 10) : undefined,
@@ -732,6 +746,8 @@ function parse(src, options = {}) {
732
746
  to: toTok.value,
733
747
  connector: connector,
734
748
  label: props.label,
749
+ labelDx: props["label-dx"] !== undefined ? parseFloat(props["label-dx"]) : undefined,
750
+ labelDy: props["label-dy"] !== undefined ? parseFloat(props["label-dy"]) : undefined,
735
751
  fromAnchor: props["anchor-from"],
736
752
  toAnchor: props["anchor-to"],
737
753
  dashed,
@@ -1233,6 +1249,7 @@ const LAYOUT = {
1233
1249
  const NODE = {
1234
1250
  minW: 90, // minimum auto-sized node width (px)
1235
1251
  maxW: 300, // maximum auto-sized node width (px)
1252
+ mediaLabelH: 20, // reserved bottom strip for icon/image/line labels (px)
1236
1253
  basePad: 26, // base padding added to label width (px)
1237
1254
  };
1238
1255
  // ── Shape-specific sizing ──────────────────────────────────
@@ -3556,6 +3573,8 @@ function buildSceneGraph(ast) {
3556
3573
  id: n.id,
3557
3574
  shape: n.shape,
3558
3575
  label: n.label,
3576
+ labelDx: n.labelDx,
3577
+ labelDy: n.labelDy,
3559
3578
  style: { ...ast.styles[n.id], ...themeStyle, ...n.style },
3560
3579
  groupId: nodeParentById.get(n.id),
3561
3580
  width: n.width,
@@ -3581,6 +3600,8 @@ function buildSceneGraph(ast) {
3581
3600
  return {
3582
3601
  id: g.id,
3583
3602
  label: g.label,
3603
+ labelDx: g.labelDx,
3604
+ labelDy: g.labelDy,
3584
3605
  parentId: groupParentById.get(g.id),
3585
3606
  children: g.children,
3586
3607
  layout: (g.layout ?? "column"),
@@ -3658,6 +3679,8 @@ function buildSceneGraph(ast) {
3658
3679
  to: e.to,
3659
3680
  connector: e.connector,
3660
3681
  label: e.label,
3682
+ labelDx: e.labelDx,
3683
+ labelDy: e.labelDy,
3661
3684
  fromAnchor: e.fromAnchor,
3662
3685
  toAnchor: e.toAnchor,
3663
3686
  dashed: e.dashed ?? false,
@@ -3999,10 +4022,25 @@ const textShape = {
3999
4022
  },
4000
4023
  };
4001
4024
 
4025
+ const MEDIA_LABEL_SHAPES = new Set(["icon", "image", "line"]);
4026
+ function usesBottomLabelStrip(shape) {
4027
+ return MEDIA_LABEL_SHAPES.has(shape);
4028
+ }
4029
+ function getBottomLabelStripHeight(node) {
4030
+ return usesBottomLabelStrip(node.shape) && node.label ? NODE.mediaLabelH : 0;
4031
+ }
4032
+ function getBottomLabelContentHeight(node) {
4033
+ return node.h - getBottomLabelStripHeight(node);
4034
+ }
4035
+ function getBottomLabelCenterY(node) {
4036
+ const stripH = getBottomLabelStripHeight(node);
4037
+ return stripH > 0 ? node.y + node.h - stripH / 2 : node.y + node.h / 2;
4038
+ }
4039
+
4002
4040
  const iconShape = {
4003
4041
  size(n, labelW) {
4004
4042
  const iconBase = 48;
4005
- const labelH = n.label ? 20 : 0;
4043
+ const labelH = getBottomLabelStripHeight(n);
4006
4044
  n.w = n.w || Math.max(iconBase, n.label ? labelW : 0);
4007
4045
  n.h = n.h || (iconBase + labelH);
4008
4046
  },
@@ -4015,8 +4053,7 @@ const iconShape = {
4015
4053
  const iconColor = s.color
4016
4054
  ? encodeURIComponent(String(s.color))
4017
4055
  : encodeURIComponent(String(palette.nodeStroke));
4018
- const labelSpace = n.label ? 20 : 0;
4019
- const iconAreaH = n.h - labelSpace;
4056
+ const iconAreaH = getBottomLabelContentHeight(n);
4020
4057
  const iconSize = Math.min(n.w, iconAreaH) - 4;
4021
4058
  const iconUrl = `https://api.iconify.design/${prefix}/${name}.svg?color=${iconColor}&width=${iconSize}&height=${iconSize}`;
4022
4059
  const img = document.createElementNS(SVG_NS, "image");
@@ -4060,8 +4097,7 @@ const iconShape = {
4060
4097
  const iconColor = s.color
4061
4098
  ? encodeURIComponent(String(s.color))
4062
4099
  : encodeURIComponent(String(palette.nodeStroke));
4063
- const iconLabelSpace = n.label ? 20 : 0;
4064
- const iconAreaH = n.h - iconLabelSpace;
4100
+ const iconAreaH = getBottomLabelContentHeight(n);
4065
4101
  const iconSize = Math.min(n.w, iconAreaH) - 4;
4066
4102
  const iconUrl = `https://api.iconify.design/${prefix}/${name}.svg?color=${iconColor}&width=${iconSize}&height=${iconSize}`;
4067
4103
  const img = new Image();
@@ -4104,21 +4140,21 @@ const imageShape = {
4104
4140
  const w = n.w || Math.max(MIN_W, Math.min(MAX_W, labelW));
4105
4141
  n.w = w;
4106
4142
  if (!n.h) {
4143
+ const labelH = getBottomLabelStripHeight(n);
4107
4144
  if (labelW > w) {
4108
4145
  const fontSize = Number(n.style?.fontSize ?? 14);
4109
4146
  const lines = Math.ceil(labelW / (w - 16));
4110
- n.h = Math.max(52, lines * fontSize * 1.5 + 20);
4147
+ n.h = Math.max(52, lines * fontSize * 1.5 + labelH);
4111
4148
  }
4112
4149
  else {
4113
- n.h = 52;
4150
+ n.h = 52 + labelH;
4114
4151
  }
4115
4152
  }
4116
4153
  },
4117
4154
  renderSVG(rc, n, _palette, opts) {
4118
4155
  const s = n.style ?? {};
4119
4156
  if (n.imageUrl) {
4120
- const imgLabelSpace = n.label ? 20 : 0;
4121
- const imgAreaH = n.h - imgLabelSpace;
4157
+ const imgAreaH = getBottomLabelContentHeight(n);
4122
4158
  const img = document.createElementNS(SVG_NS, "image");
4123
4159
  img.setAttribute("href", n.imageUrl);
4124
4160
  img.setAttribute("x", String(n.x + 1));
@@ -4150,8 +4186,7 @@ const imageShape = {
4150
4186
  renderCanvas(rc, ctx, n, _palette, opts) {
4151
4187
  const s = n.style ?? {};
4152
4188
  if (n.imageUrl) {
4153
- const imgLblSpace = n.label ? 20 : 0;
4154
- const imgAreaH = n.h - imgLblSpace;
4189
+ const imgAreaH = getBottomLabelContentHeight(n);
4155
4190
  const img = new Image();
4156
4191
  img.crossOrigin = "anonymous";
4157
4192
  img.onload = () => {
@@ -4328,17 +4363,17 @@ const noteShape = {
4328
4363
 
4329
4364
  const lineShape = {
4330
4365
  size(n, labelW) {
4331
- const labelH = n.label ? 20 : 0;
4366
+ const labelH = getBottomLabelStripHeight(n);
4332
4367
  n.w = n.width ?? Math.max(MIN_W, labelW + 20);
4333
4368
  n.h = n.height ?? (6 + labelH);
4334
4369
  },
4335
4370
  renderSVG(rc, n, _palette, opts) {
4336
- const labelH = n.label ? 20 : 0;
4371
+ const labelH = getBottomLabelStripHeight(n);
4337
4372
  const lineY = n.y + (n.h - labelH) / 2;
4338
4373
  return [rc.line(n.x, lineY, n.x + n.w, lineY, opts)];
4339
4374
  },
4340
4375
  renderCanvas(rc, _ctx, n, _palette, opts) {
4341
- const labelH = n.label ? 20 : 0;
4376
+ const labelH = getBottomLabelStripHeight(n);
4342
4377
  const lineY = n.y + (n.h - labelH) / 2;
4343
4378
  rc.line(n.x, lineY, n.x + n.w, lineY, opts);
4344
4379
  },
@@ -5584,18 +5619,18 @@ function renderRoughChartSVG(rc, c, palette, isDark) {
5584
5619
  stroke: bgStroke, strokeWidth: Number(s.strokeWidth ?? 1.2),
5585
5620
  ...(s.strokeDash ? { strokeLineDash: s.strokeDash } : {}),
5586
5621
  }));
5622
+ const { px, py, pw, ph, titleH, cx, cy } = chartLayout(c);
5587
5623
  // Title
5588
5624
  if (c.label) {
5589
- cg.appendChild(mkT(c.label, c.x + c.w / 2, c.y + 14, cFontSize, cFontWeight, lc, 'middle', cFont));
5625
+ cg.appendChild(mkT(c.label, c.x + c.w / 2, c.y + titleH / 2 + 2, cFontSize, cFontWeight, lc, 'middle', cFont));
5590
5626
  }
5591
- const { px, py, pw, ph, cx, cy } = chartLayout(c);
5592
5627
  // ── Pie / Donut ──────────────────────────────────────────
5593
5628
  if (c.chartType === 'pie' || c.chartType === 'donut') {
5594
5629
  const { segments, total } = parsePie(c.data);
5595
- const r = Math.min(c.w * 0.38, (c.h - (c.label ? 24 : 8)) * 0.44);
5630
+ const r = Math.min(c.w * 0.38, (c.h - titleH) * 0.44);
5596
5631
  const ir = c.chartType === 'donut' ? r * 0.48 : 0;
5597
5632
  const legendX = c.x + 8;
5598
- const legendY = c.y + (c.label ? 28 : 12);
5633
+ const legendY = c.y + titleH + 4;
5599
5634
  let angle = -Math.PI / 2;
5600
5635
  for (const seg of segments) {
5601
5636
  const sweep = (seg.value / total) * Math.PI * 2;
@@ -5633,7 +5668,7 @@ function renderRoughChartSVG(rc, c, palette, isDark) {
5633
5668
  strokeWidth: 1.2,
5634
5669
  }));
5635
5670
  });
5636
- legend(cg, pts.map(p => p.label), CHART_COLORS, c.x + 8, c.y + (c.label ? 28 : 12), lc, cFont);
5671
+ legend(cg, pts.map(p => p.label), CHART_COLORS, c.x + 8, c.y + titleH + 4, lc, cFont);
5637
5672
  return cg;
5638
5673
  }
5639
5674
  // ── Bar / Line / Area ─────────────────────────────────────
@@ -8379,9 +8414,10 @@ function renderToSVG(sg, container, options = {}) {
8379
8414
  }));
8380
8415
  // ── Group label typography ──────────────────────────
8381
8416
  const gTypo = resolveTypography(gs, { fontSize: GROUP_LABEL.fontSize, fontWeight: GROUP_LABEL.fontWeight, textAlign: "left", padding: GROUP_LABEL.padding }, diagramFont, palette.groupLabel);
8382
- const gTextX = computeTextX(gTypo, g.x, g.w);
8417
+ const gTextX = computeTextX(gTypo, g.x, g.w) + (g.labelDx ?? 0);
8418
+ const gTextY = g.y + gTypo.padding + (g.labelDy ?? 0);
8383
8419
  if (g.label) {
8384
- gg.appendChild(mkText(g.label, gTextX, g.y + gTypo.padding, gTypo.fontSize, gTypo.fontWeight, gTypo.textColor, gTypo.textAnchor, gTypo.font, gTypo.letterSpacing));
8420
+ gg.appendChild(mkText(g.label, gTextX, gTextY, gTypo.fontSize, gTypo.fontWeight, gTypo.textColor, gTypo.textAnchor, gTypo.font, gTypo.letterSpacing));
8385
8421
  }
8386
8422
  GL.appendChild(gg);
8387
8423
  }
@@ -8433,8 +8469,8 @@ function renderToSVG(sg, container, options = {}) {
8433
8469
  eg.appendChild(startHead);
8434
8470
  }
8435
8471
  if (e.label) {
8436
- const mx = (x1 + x2) / 2 - ny * EDGE.labelOffset;
8437
- const my = (y1 + y2) / 2 + nx * EDGE.labelOffset;
8472
+ const mx = (x1 + x2) / 2 - ny * EDGE.labelOffset + (e.labelDx ?? 0);
8473
+ const my = (y1 + y2) / 2 + nx * EDGE.labelOffset + (e.labelDy ?? 0);
8438
8474
  const tw = Math.max(e.label.length * 7 + 12, 36);
8439
8475
  const bg = se("rect");
8440
8476
  bg.setAttribute("x", String(mx - tw / 2));
@@ -8502,7 +8538,7 @@ function renderToSVG(sg, container, options = {}) {
8502
8538
  // ── Node / text typography ─────────────────────────
8503
8539
  const isText = n.shape === "text";
8504
8540
  const isNote = n.shape === "note";
8505
- const isMediaShape = n.shape === "icon" || n.shape === "image" || n.shape === "line";
8541
+ const usesBottomStrip = usesBottomLabelStrip(n.shape);
8506
8542
  const typo = resolveTypography(n.style, {
8507
8543
  fontSize: isText ? 13 : isNote ? 12 : 14,
8508
8544
  fontWeight: isText || isNote ? 400 : 500,
@@ -8520,20 +8556,22 @@ function renderToSVG(sg, container, options = {}) {
8520
8556
  : n.x + typo.padding)
8521
8557
  : computeTextX(typo, n.x, n.w);
8522
8558
  const fontStr = buildFontStr(typo.fontSize, typo.fontWeight, typo.font);
8523
- const shouldWrap = !isMediaShape && !n.label.includes('\n');
8559
+ const shouldWrap = !usesBottomStrip && !n.label.includes('\n');
8524
8560
  const innerW = shapeInnerTextWidth(n.shape, n.w, typo.padding);
8525
8561
  const lines = shouldWrap
8526
8562
  ? wrapText(n.label, innerW, typo.fontSize, fontStr)
8527
8563
  : n.label.split('\n');
8528
- const textCY = isMediaShape
8529
- ? n.y + n.h - 10
8564
+ const textCY = usesBottomStrip
8565
+ ? getBottomLabelCenterY(n)
8530
8566
  : isNote
8531
8567
  ? computeTextCY(typo, n.y, n.h, lines.length, FOLD + typo.padding)
8532
8568
  : computeTextCY(typo, n.y, n.h, lines.length);
8569
+ const labelX = textX + (n.labelDx ?? 0);
8570
+ const labelY = textCY + (n.labelDy ?? 0);
8533
8571
  if (n.label) {
8534
8572
  ng.appendChild(lines.length > 1
8535
- ? mkMultilineText(lines, textX, textCY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAnchor, typo.lineHeight, typo.font, typo.letterSpacing)
8536
- : mkText(n.label, textX, textCY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAnchor, typo.font, typo.letterSpacing));
8573
+ ? mkMultilineText(lines, labelX, labelY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAnchor, typo.lineHeight, typo.font, typo.letterSpacing)
8574
+ : mkText(n.label, labelX, labelY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAnchor, typo.font, typo.letterSpacing));
8537
8575
  }
8538
8576
  if (options.interactive) {
8539
8577
  ng.style.cursor = "pointer";
@@ -8847,6 +8885,7 @@ function drawRoughChartCanvas(rc, ctx, c, pal, R) {
8847
8885
  strokeWidth: Number(s.strokeWidth ?? 1.2),
8848
8886
  ...(s.strokeDash ? { strokeLineDash: s.strokeDash } : {}),
8849
8887
  });
8888
+ const { px, py, pw, ph, titleH, cx, cy } = chartLayout(c);
8850
8889
  // Title
8851
8890
  if (c.label) {
8852
8891
  ctx.save();
@@ -8854,17 +8893,16 @@ function drawRoughChartCanvas(rc, ctx, c, pal, R) {
8854
8893
  ctx.fillStyle = lc;
8855
8894
  ctx.textAlign = 'center';
8856
8895
  ctx.textBaseline = 'middle';
8857
- ctx.fillText(c.label, c.x + c.w / 2, c.y + 14);
8896
+ ctx.fillText(c.label, c.x + c.w / 2, c.y + titleH / 2 + 2);
8858
8897
  ctx.restore();
8859
8898
  }
8860
- const { px, py, pw, ph, cx, cy } = chartLayout(c);
8861
8899
  // ── Pie / Donut ──────────────────────────────────────────
8862
8900
  if (c.chartType === 'pie' || c.chartType === 'donut') {
8863
8901
  const { segments, total } = parsePie(c.data);
8864
- const r = Math.min(c.w * 0.38, (c.h - (c.label ? 24 : 8)) * 0.44);
8902
+ const r = Math.min(c.w * 0.38, (c.h - titleH) * 0.44);
8865
8903
  const ir = c.chartType === 'donut' ? r * 0.48 : 0;
8866
8904
  const legendX = c.x + 8;
8867
- const legendY = c.y + (c.label ? 28 : 12);
8905
+ const legendY = c.y + titleH + 4;
8868
8906
  let angle = -Math.PI / 2;
8869
8907
  segments.forEach((seg, i) => {
8870
8908
  const sweep = (seg.value / total) * Math.PI * 2;
@@ -8892,7 +8930,7 @@ function drawRoughChartCanvas(rc, ctx, c, pal, R) {
8892
8930
  strokeWidth: 1.2,
8893
8931
  });
8894
8932
  });
8895
- drawLegend(ctx, pts.map(p => p.label), CHART_COLORS, c.x + 8, c.y + (c.label ? 28 : 12), lc, cFont);
8933
+ drawLegend(ctx, pts.map(p => p.label), CHART_COLORS, c.x + 8, c.y + titleH + 4, lc, cFont);
8896
8934
  ctx.globalAlpha = 1;
8897
8935
  return;
8898
8936
  }
@@ -9127,8 +9165,9 @@ function renderToCanvas(sg, canvas, options = {}) {
9127
9165
  });
9128
9166
  if (g.label) {
9129
9167
  const gTypo = resolveTypography(gs, { fontSize: GROUP_LABEL.fontSize, fontWeight: GROUP_LABEL.fontWeight, textAlign: "left", padding: GROUP_LABEL.padding }, diagramFont, palette.groupLabel);
9130
- const gTextX = computeTextX(gTypo, g.x, g.w);
9131
- drawText(ctx, g.label, gTextX, g.y + gTypo.padding + 2, gTypo.fontSize, gTypo.fontWeight, gTypo.textColor, gTypo.textAlign, gTypo.font, gTypo.letterSpacing);
9168
+ const gTextX = computeTextX(gTypo, g.x, g.w) + (g.labelDx ?? 0);
9169
+ const gTextY = g.y + gTypo.padding + 2 + (g.labelDy ?? 0);
9170
+ drawText(ctx, g.label, gTextX, gTextY, gTypo.fontSize, gTypo.fontWeight, gTypo.textColor, gTypo.textAlign, gTypo.font, gTypo.letterSpacing);
9132
9171
  }
9133
9172
  if (gs.opacity != null)
9134
9173
  ctx.globalAlpha = 1;
@@ -9166,8 +9205,8 @@ function renderToCanvas(sg, canvas, options = {}) {
9166
9205
  if (arrowAt === 'start' || arrowAt === 'both')
9167
9206
  drawArrowHead(rc, x1, y1, Math.atan2(y1 - y2, x1 - x2), ecol, hashStr$3(e.from + 'back'));
9168
9207
  if (e.label) {
9169
- const mx = (x1 + x2) / 2 - ny * EDGE.labelOffset;
9170
- const my = (y1 + y2) / 2 + nx * EDGE.labelOffset;
9208
+ const mx = (x1 + x2) / 2 - ny * EDGE.labelOffset + (e.labelDx ?? 0);
9209
+ const my = (y1 + y2) / 2 + nx * EDGE.labelOffset + (e.labelDy ?? 0);
9171
9210
  // ── Edge label: font, font-size, letter-spacing ──
9172
9211
  // always center-anchored (single line)
9173
9212
  const eFontSize = Number(e.style?.fontSize ?? EDGE.labelFontSize);
@@ -9207,7 +9246,7 @@ function renderToCanvas(sg, canvas, options = {}) {
9207
9246
  // ── Node / text typography ─────────────────────────
9208
9247
  const isText = n.shape === 'text';
9209
9248
  const isNote = n.shape === 'note';
9210
- const isMediaShape = n.shape === 'icon' || n.shape === 'image' || n.shape === 'line';
9249
+ const usesBottomStrip = usesBottomLabelStrip(n.shape);
9211
9250
  const typo = resolveTypography(n.style, {
9212
9251
  fontSize: isText ? 13 : isNote ? 12 : 14,
9213
9252
  fontWeight: isText || isNote ? 400 : 500,
@@ -9225,23 +9264,25 @@ function renderToCanvas(sg, canvas, options = {}) {
9225
9264
  : n.x + typo.padding)
9226
9265
  : computeTextX(typo, n.x, n.w);
9227
9266
  const fontStr = buildFontStr(typo.fontSize, typo.fontWeight, typo.font);
9228
- const shouldWrap = !isMediaShape && !n.label.includes('\n');
9267
+ const shouldWrap = !usesBottomStrip && !n.label.includes('\n');
9229
9268
  const innerW = shapeInnerTextWidth(n.shape, n.w, typo.padding);
9230
9269
  const rawLines = n.label.split('\n');
9231
9270
  const lines = shouldWrap && rawLines.length === 1
9232
9271
  ? wrapText(n.label, innerW, typo.fontSize, fontStr)
9233
9272
  : rawLines;
9234
- const textCY = isMediaShape
9235
- ? n.y + n.h - 10
9273
+ const textCY = usesBottomStrip
9274
+ ? getBottomLabelCenterY(n)
9236
9275
  : isNote
9237
9276
  ? computeTextCY(typo, n.y, n.h, lines.length, FOLD + typo.padding)
9238
9277
  : computeTextCY(typo, n.y, n.h, lines.length);
9278
+ const labelX = textX + (n.labelDx ?? 0);
9279
+ const labelY = textCY + (n.labelDy ?? 0);
9239
9280
  if (n.label) {
9240
9281
  if (lines.length > 1) {
9241
- drawMultilineText(ctx, lines, textX, textCY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAlign, typo.lineHeight, typo.font, typo.letterSpacing);
9282
+ drawMultilineText(ctx, lines, labelX, labelY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAlign, typo.lineHeight, typo.font, typo.letterSpacing);
9242
9283
  }
9243
9284
  else {
9244
- drawText(ctx, lines[0] ?? '', textX, textCY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAlign, typo.font, typo.letterSpacing);
9285
+ drawText(ctx, lines[0] ?? '', labelX, labelY, typo.fontSize, typo.fontWeight, typo.textColor, typo.textAlign, typo.font, typo.letterSpacing);
9245
9286
  }
9246
9287
  }
9247
9288
  if (hasTx)
@@ -9579,7 +9620,7 @@ function buildNodeGuidePath(el) {
9579
9620
  [x + 1, y + h - 1],
9580
9621
  ]);
9581
9622
  case "line": {
9582
- const labelH = el.querySelector("text") ? 20 : 0;
9623
+ const labelH = el.querySelector("text") ? NODE.mediaLabelH : 0;
9583
9624
  const lineY = y + (h - labelH) / 2;
9584
9625
  return `M ${x} ${lineY} L ${x + w} ${lineY}`;
9585
9626
  }