@cardenelabs/cdl 0.112.0 → 0.114.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,77 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.114.0] - 2026-09-30
9
+
10
+ ### Fixed
11
+
12
+ - **左右で段数が違う放射の図が札の横を半分しか使わなかった** (#966)
13
+
14
+ 枝を中心からどれだけ離すかが図で 1 つの値だった。
15
+ 子を持つ枝は子の世代のぶんを内側に空ける必要があるので、その都合が子を持たない枝にも効く。
16
+ 左が入れ子で右が葉 1 枚の図では右の枝も中心から 149 に留まり、
17
+ 右には空ける相手が居ないのにその 171 を誰も使わない。
18
+
19
+ 離す量を **枝ごとに** 出すようにした。
20
+ 子を持つ枝は子を収める位置まで、末端の枝は名前が描画域の端に届く位置まで外へ出る。
21
+
22
+ | 枝 | 直す前 | 直した後 |
23
+ |---|---|---|
24
+ | 子を 1 段持つ枝 | 149 | 149 (変わらない) |
25
+ | 同じ側の末端の枝 | 149 | 296 |
26
+ | 反対側の末端の枝 | 149 | 338 |
27
+
28
+ あわせて末端の上限から「箱ごと描画域に収める」 という条件を外した。
29
+ 末端は枠を持たない (#907) ので、収めるのは名前で箱ではない。
30
+ 箱まで収めると、名前より 41 広い箱の都合で名前が描画域の内側で終わっていた。
31
+
32
+ 名前を描く幅の見積りを、切る側 (`箱に積む` / `幅に収める`) と同じ `textWidth` に揃えた。
33
+ 別の見積りで置き場所を決めていたため、ちょうど収まる位置に置いた名前が描く側で切られていた
34
+ (実測 = `Features` が `Featur…` になった)。
35
+
36
+ 枝の離れは整数に落とす。
37
+ 端数を持ったまま置くと枝の長さが座標の差から出るぶん丸め誤差が乗る
38
+ (実測 = 24 であるべき枝が 23.99999999999997 になった)。
39
+
40
+ 中心の箱を横中央へ寄せる処理 (#913) は、両側が端まで届くようになったため
41
+ この形の図では働かなくなる。 片側にしか枝が無い図では引き続き働く。
42
+
43
+ 見本帳 (`cardene777/dragon`) の 3 図を実際の画面で測ると、札の横を使う割合が
44
+ 85% から 88%、52% から 88%、79% から 87% になった。
45
+
46
+ ## [0.113.0] - 2026-09-30
47
+
48
+ ### Fixed
49
+
50
+ - **放射の枝が札の横を 3 分の 2 しか使わなかった** (#964)
51
+
52
+ 枝を中心からどれだけ離すかが `canvasW * 0.32` という決め打ちの割合だった。
53
+ 枝の名前は枠を持たず、枠があった位置の内側の端から外へ伸びる (#907) ので、
54
+ 名前が短い図ではこの位置の外側に誰も使わない余白が残る。
55
+ 見本帳で測ると、左の名前は 173.2 の余地に対して 90.6 しか使っていなかった。
56
+
57
+ 離す量を **第 1 階層の葉の名前のうち一番広いもの** から出すようにした。
58
+ 名前の右端が描画域の端に一致する位置 (`canvasW / 2 + branchW / 2 - 名前の幅`) を上限にする。
59
+ 名前が短い図では枝が外へ出て、名前が長い図では逆に内側へ寄る。
60
+
61
+ | 図の形 | 直す前 | 直した後 |
62
+ |---|---|---|
63
+ | 左右 2 本ずつ | 237.4 | 305.0 |
64
+ | 名前が長い左右 2 本ずつ | 230.4 | 186.3 |
65
+ | 枝 14 本 | 235.4 | 309.9 |
66
+ | 第 1 階層が全て子を持つ | 175.0 | 175.0 (変わらない) |
67
+
68
+ 第 1 階層に葉が 1 つも無い図では名前では決まらず、入れ子のぶんを空ける従来の上限がそのまま効く。
69
+
70
+ あわせて、札に収める最後の一様縮小が横を **描く端** で測るようにした。
71
+ 末端は枠を持たないので、箱で測ると描いてもいない幅を占めていることになり、
72
+ 何もはみ出していない図まで縮んでいた (枝 1 本の図が 0.83 倍になり、
73
+ 箱の高さが 30.8 から 25.6 に縮んで補足の行が落ちていた)。
74
+
75
+ 見本帳 (`cardene777/dragon`) の 3 図を実際の画面で測ると、札の横を使う割合が
76
+ 66% から 85%、54% から 79% になった。 入れ子を持つ 1 図は 52% のまま変わらない
77
+ (中心の箱を描いた中身の真ん中に置く話で、別 Issue で扱う)。
78
+
8
79
  ## [0.112.0] - 2026-09-30
9
80
 
10
81
  ### Fixed
@@ -4479,7 +4550,9 @@ Initial OSS release.
4479
4550
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
4480
4551
  行き止まりになる。
4481
4552
 
4482
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.112.0...HEAD
4553
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.114.0...HEAD
4554
+ [0.114.0]: https://github.com/cardene777/cdl/compare/v0.113.0...v0.114.0
4555
+ [0.113.0]: https://github.com/cardene777/cdl/compare/v0.112.0...v0.113.0
4483
4556
  [0.112.0]: https://github.com/cardene777/cdl/compare/v0.111.0...v0.112.0
4484
4557
  [0.111.0]: https://github.com/cardene777/cdl/compare/v0.110.0...v0.111.0
4485
4558
  [0.110.0]: https://github.com/cardene777/cdl/compare/v0.109.0...v0.110.0
package/dist/index.cjs CHANGED
@@ -16141,7 +16141,7 @@ function \u63CF\u304F\u6A2A\u306E\u7AEF(n) {
16141
16141
  if (n.isRoot || !n.isLeaf) return [n.x - n.w / 2, n.x + n.w / 2];
16142
16142
  const \u8D77\u70B9 = n.x + (n.side === "right" ? -n.w / 2 : n.w / 2);
16143
16143
  const \u540D\u524D = \u653E\u5C04\u306E\u884C(n)[0];
16144
- const \u5E45 = measureTextWidth(\u540D\u524D.text, { fontSize: \u540D\u524D.fontSize});
16144
+ const \u5E45 = textWidth(\u540D\u524D.text, \u540D\u524D.fontSize);
16145
16145
  return n.side === "right" ? [\u8D77\u70B9, \u8D77\u70B9 + \u5E45] : [\u8D77\u70B9 - \u5E45, \u8D77\u70B9];
16146
16146
  }
16147
16147
  function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
@@ -16214,30 +16214,52 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16214
16214
  if (kids.length === 0) return 1;
16215
16215
  return kids.reduce((sum, k) => sum + leafCountOf(k.id, seen), 0);
16216
16216
  };
16217
- const maxSubDepth = firstLevel.length > 0 ? Math.max(0, ...firstLevel.map((br) => subDepthOf(br.id, /* @__PURE__ */ new Set()))) : 0;
16217
+ const leftBranches = firstLevel.slice(0, leftCount);
16218
+ const rightBranches = firstLevel.slice(leftCount);
16218
16219
  const minLayer1XOffset = rootW / 2 + branchW / 2 + MIND_BOX_GAP;
16219
16220
  const preferredSubDx = subBranchW + 20;
16220
- const reserve = maxSubDepth > 0 ? branchW / 2 + maxSubDepth * preferredSubDx : 0;
16221
- const maxLayer1XOffset = Math.max(minLayer1XOffset, canvasW / 2 - reserve);
16222
- const layer1XOffset = Math.max(minLayer1XOffset, Math.min(canvasW * 0.32, maxLayer1XOffset));
16223
- const room = canvasW / 2 - layer1XOffset;
16224
16221
  const MIN_SUB_W = 56;
16225
16222
  const PREFERRED_GAP = MIND_BOX_GAP;
16226
- const gapRoom = maxSubDepth > 0 ? (room - branchW / 2 - maxSubDepth * MIN_SUB_W) / maxSubDepth : 0;
16227
- const gap = Math.max(8, Math.min(PREFERRED_GAP, gapRoom));
16228
- const effSubW = maxSubDepth > 0 ? Math.max(1, Math.min(subBranchW, (room - branchW / 2 - maxSubDepth * gap) / maxSubDepth)) : subBranchW;
16229
- const step1 = (branchW + effSubW) / 2 + gap;
16230
- const stepN = effSubW + gap;
16231
- const subOffset = (subDepth) => subDepth <= 0 ? 0 : step1 + (subDepth - 1) * stepN;
16232
- const leftBranches = firstLevel.slice(0, leftCount);
16233
- const rightBranches = firstLevel.slice(leftCount);
16223
+ const \u679D\u306E\u540D\u524D\u306E\u5E45 = (title) => {
16224
+ const \u540D\u524D = \u653E\u5C04\u306E\u884C({ title, isRoot: false })[0];
16225
+ return textWidth(\u540D\u524D.text, \u540D\u524D.fontSize);
16226
+ };
16227
+ const \u679D\u306E\u6A2A\u3092\u6C7A\u3081\u308B = (br) => {
16228
+ const maxSubDepth = subDepthOf(br.id, /* @__PURE__ */ new Set());
16229
+ const \u4E0A\u9650 = maxSubDepth > 0 ? canvasW / 2 - (branchW / 2 + maxSubDepth * preferredSubDx) : canvasW / 2 + branchW / 2 - \u679D\u306E\u540D\u524D\u306E\u5E45(br.title);
16230
+ const layer1XOffset = Math.floor(Math.max(minLayer1XOffset, \u4E0A\u9650));
16231
+ const room = canvasW / 2 - layer1XOffset;
16232
+ const gapRoom = maxSubDepth > 0 ? (room - branchW / 2 - maxSubDepth * MIN_SUB_W) / maxSubDepth : 0;
16233
+ const gap = Math.floor(Math.max(8, Math.min(PREFERRED_GAP, gapRoom)));
16234
+ const effSubW = maxSubDepth > 0 ? Math.floor(
16235
+ Math.max(1, Math.min(subBranchW, (room - branchW / 2 - maxSubDepth * gap) / maxSubDepth))
16236
+ ) : subBranchW;
16237
+ const step1 = (branchW + effSubW) / 2 + gap;
16238
+ const stepN = effSubW + gap;
16239
+ return {
16240
+ layer1XOffset,
16241
+ effSubW,
16242
+ subOffset: (subDepth) => subDepth <= 0 ? 0 : step1 + (subDepth - 1) * stepN
16243
+ };
16244
+ };
16245
+ const \u6A2A\u306E\u5272\u4ED8\u8868 = new Map(
16246
+ firstLevel.map((br) => [br.id, \u679D\u306E\u6A2A\u3092\u6C7A\u3081\u308B(br)])
16247
+ );
16248
+ const \u4E00\u756A\u5185\u5074\u306E\u96E2\u308C = Math.min(
16249
+ ...firstLevel.length > 0 ? firstLevel.map((br) => \u6A2A\u306E\u5272\u4ED8\u8868.get(br.id).layer1XOffset) : [minLayer1XOffset]
16250
+ );
16234
16251
  const leavesOfSide = (brs) => Math.max(
16235
16252
  1,
16236
16253
  brs.reduce((sum, br) => sum + leafCountOf(br.id, /* @__PURE__ */ new Set()), 0)
16237
16254
  );
16238
16255
  const sideLaneCount = Math.max(leavesOfSide(leftBranches), leavesOfSide(rightBranches));
16239
16256
  const laneBandH = Math.max(0, canvasH - BRANCH_BOX_H_MAX);
16240
- const rowGap = sideLaneCount > 1 ? Math.min(laneBandH / (sideLaneCount - 1), \u7E26\u306E\u9593\u9694\u306E\u4E0A\u9650(layer1XOffset)) : subBranchH + 14;
16257
+ const rowGap = sideLaneCount > 1 ? Math.min(
16258
+ laneBandH / (sideLaneCount - 1),
16259
+ // 帯は図で 1 つなので、**一番内側の枝** から上限を取る (#966)。
16260
+ // 外へ出た枝に合わせると、内側に残った枝の傾きが 45 度を超える
16261
+ \u7E26\u306E\u9593\u9694\u306E\u4E0A\u9650(\u4E00\u756A\u5185\u5074\u306E\u96E2\u308C)
16262
+ ) : subBranchH + 14;
16241
16263
  const effSubH = Math.min(SUB_BOX_H_MAX, rowGap * 0.7);
16242
16264
  const effBranchH = Math.min(BRANCH_BOX_H_MAX, rowGap * 0.7);
16243
16265
  const \u7AEF\u306E\u4F59\u308A = Math.max(effSubH, effBranchH) / 2;
@@ -16253,11 +16275,11 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16253
16275
  const half = nodeHalfW.get(mindData.rootId) ?? rootW / 2;
16254
16276
  return \u4E2D\u5FC3\u306Ex + (isLeft ? -half : half);
16255
16277
  };
16256
- const placeSubtree = (node, subDepth, isLeft, tone, placed, laneRef) => {
16278
+ const placeSubtree = (node, subDepth, isLeft, tone, placed, laneRef, \u6A2A) => {
16257
16279
  placed.add(node.id);
16258
16280
  const dirX = isLeft ? -1 : 1;
16259
- const x = cx + dirX * (layer1XOffset + subOffset(subDepth));
16260
- const w = subDepth === 0 ? branchW : effSubW;
16281
+ const x = cx + dirX * (\u6A2A.layer1XOffset + \u6A2A.subOffset(subDepth));
16282
+ const w = subDepth === 0 ? branchW : \u6A2A.effSubW;
16261
16283
  const h = subDepth === 0 ? effBranchH : effSubH;
16262
16284
  const myTone = node.tone ?? tone;
16263
16285
  const kids = (childrenOf.get(node.id) ?? []).filter((k) => !placed.has(k.id));
@@ -16273,7 +16295,8 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16273
16295
  isLeft,
16274
16296
  myTone ?? MIND_TONES[i % MIND_TONES.length],
16275
16297
  placed,
16276
- laneRef
16298
+ laneRef,
16299
+ \u6A2A
16277
16300
  )
16278
16301
  );
16279
16302
  y = (ys[0] + ys[ys.length - 1]) / 2;
@@ -16306,7 +16329,7 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16306
16329
  const placed = /* @__PURE__ */ new Set();
16307
16330
  brs.forEach((br, i) => {
16308
16331
  const tone = br.tone ?? MIND_TONES[(toneBase + i) % MIND_TONES.length];
16309
- placeSubtree(br, 0, isLeft, tone, placed, laneRef);
16332
+ placeSubtree(br, 0, isLeft, tone, placed, laneRef, \u6A2A\u306E\u5272\u4ED8\u8868.get(br.id) ?? \u679D\u306E\u6A2A\u3092\u6C7A\u3081\u308B(br));
16310
16333
  });
16311
16334
  };
16312
16335
  placeSide(leftBranches, true, 0);
@@ -16317,7 +16340,8 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16317
16340
  let maxExtentX = rootW / 2;
16318
16341
  let maxExtentY = rootH / 2;
16319
16342
  for (const n of nodes) {
16320
- maxExtentX = Math.max(maxExtentX, Math.abs(n.x - cx) + n.w / 2);
16343
+ const [\u5DE6, \u53F3] = \u63CF\u304F\u6A2A\u306E\u7AEF(n);
16344
+ maxExtentX = Math.max(maxExtentX, Math.abs(\u5DE6 - cx), Math.abs(\u53F3 - cx));
16321
16345
  maxExtentY = Math.max(maxExtentY, Math.abs(n.y - cy) + n.h / 2);
16322
16346
  }
16323
16347
  const scale = Math.min(1, drawableHalfW / maxExtentX, drawableHalfH / maxExtentY);