@cardenelabs/cdl 0.113.0 → 0.115.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,74 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.115.0] - 2026-09-30
9
+
10
+ ### Fixed
11
+
12
+ - **木の兄弟どうしが遠くへ離れ、離れた 2 本の列に見えた** (#968)
13
+
14
+ 葉は `canvasW / 葉の数` で等分した区画の中央に置かれていた。
15
+ 区画は箱より広いので、葉が少ない図では兄弟が区画の幅だけ離れる。
16
+ 見本帳の `配布物の構成` は葉が 2 枚で、箱の縁の間が 196 空いていた。
17
+ 同じ図の段と段の隙間は 95 なので、横だけが縦の 2 倍になる。
18
+
19
+ 横の隙間を **段と段の隙間に揃えた**。
20
+ 木は根から下へ辿る図なので、間隔が 1 つの調子で揃っていないと系統が読めない。
21
+
22
+ | 図の形 | 横の隙間 (直す前 → 後) | 縦の隙間 |
23
+ |---|---|---|
24
+ | 葉 2 枚 | 196 → 95 | 95 |
25
+ | 葉 3 枚 | 84 → 84 (変わらない) | 95 |
26
+
27
+ **今より広げない**。 葉が多い図では区画の方が狭いので、そちらが効いて位置は動かない。
28
+ 頭打ちを外すと間隔が区画の 3 倍になり、最後の一様縮小が効いて箱まで小さくなる
29
+ (実測 = 葉 10 枚の図で箱の幅が 57.1 から 19.5 に縮んだ)。
30
+
31
+ 箱の幅を出す処理を置き場所より先に回した。
32
+ 端の葉がどれだけ幅を取るかは、名前と段から決まるので位置より先に出せる。
33
+
34
+ 見本帳 (`cardene777/dragon`) の `配布物の構成` は、札に対する中身の割合が
35
+ 横 66% から 52% に **下がる**。 兄弟が近づいたぶん中身が小さくなるためで、
36
+ 図が札の中で浮くのは札の大きさの話として別に扱う。
37
+
38
+ ## [0.114.0] - 2026-09-30
39
+
40
+ ### Fixed
41
+
42
+ - **左右で段数が違う放射の図が札の横を半分しか使わなかった** (#966)
43
+
44
+ 枝を中心からどれだけ離すかが図で 1 つの値だった。
45
+ 子を持つ枝は子の世代のぶんを内側に空ける必要があるので、その都合が子を持たない枝にも効く。
46
+ 左が入れ子で右が葉 1 枚の図では右の枝も中心から 149 に留まり、
47
+ 右には空ける相手が居ないのにその 171 を誰も使わない。
48
+
49
+ 離す量を **枝ごとに** 出すようにした。
50
+ 子を持つ枝は子を収める位置まで、末端の枝は名前が描画域の端に届く位置まで外へ出る。
51
+
52
+ | 枝 | 直す前 | 直した後 |
53
+ |---|---|---|
54
+ | 子を 1 段持つ枝 | 149 | 149 (変わらない) |
55
+ | 同じ側の末端の枝 | 149 | 296 |
56
+ | 反対側の末端の枝 | 149 | 338 |
57
+
58
+ あわせて末端の上限から「箱ごと描画域に収める」 という条件を外した。
59
+ 末端は枠を持たない (#907) ので、収めるのは名前で箱ではない。
60
+ 箱まで収めると、名前より 41 広い箱の都合で名前が描画域の内側で終わっていた。
61
+
62
+ 名前を描く幅の見積りを、切る側 (`箱に積む` / `幅に収める`) と同じ `textWidth` に揃えた。
63
+ 別の見積りで置き場所を決めていたため、ちょうど収まる位置に置いた名前が描く側で切られていた
64
+ (実測 = `Features` が `Featur…` になった)。
65
+
66
+ 枝の離れは整数に落とす。
67
+ 端数を持ったまま置くと枝の長さが座標の差から出るぶん丸め誤差が乗る
68
+ (実測 = 24 であるべき枝が 23.99999999999997 になった)。
69
+
70
+ 中心の箱を横中央へ寄せる処理 (#913) は、両側が端まで届くようになったため
71
+ この形の図では働かなくなる。 片側にしか枝が無い図では引き続き働く。
72
+
73
+ 見本帳 (`cardene777/dragon`) の 3 図を実際の画面で測ると、札の横を使う割合が
74
+ 85% から 88%、52% から 88%、79% から 87% になった。
75
+
8
76
  ## [0.113.0] - 2026-09-30
9
77
 
10
78
  ### Fixed
@@ -4512,7 +4580,9 @@ Initial OSS release.
4512
4580
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
4513
4581
  行き止まりになる。
4514
4582
 
4515
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.113.0...HEAD
4583
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.115.0...HEAD
4584
+ [0.115.0]: https://github.com/cardene777/cdl/compare/v0.114.0...v0.115.0
4585
+ [0.114.0]: https://github.com/cardene777/cdl/compare/v0.113.0...v0.114.0
4516
4586
  [0.113.0]: https://github.com/cardene777/cdl/compare/v0.112.0...v0.113.0
4517
4587
  [0.112.0]: https://github.com/cardene777/cdl/compare/v0.111.0...v0.112.0
4518
4588
  [0.111.0]: https://github.com/cardene777/cdl/compare/v0.110.0...v0.111.0
package/dist/index.cjs CHANGED
@@ -15931,6 +15931,28 @@ function computeTreeLayout(treeNodes, canvasW, canvasH) {
15931
15931
  const \u8981\u308B = measureTextWidth(\u540D\u524D.text, { fontSize: \u540D\u524D.fontSize}) + (nodeW - \u4F7F\u3048\u308B\u5E45(nodeW));
15932
15932
  return Math.min(Math.max(\u8981\u308B, nodeW), slotW * 0.92);
15933
15933
  };
15934
+ const \u8449\u306E\u4E26\u3073 = [];
15935
+ const \u6BB5\u306E\u8868 = /* @__PURE__ */ new Map();
15936
+ const \u5E45\u306E\u8868 = /* @__PURE__ */ new Map();
15937
+ {
15938
+ const \u898B\u305F = /* @__PURE__ */ new Set();
15939
+ const \u4E0B\u898B = (n, depth) => {
15940
+ \u898B\u305F.add(n.id);
15941
+ \u6BB5\u306E\u8868.set(n.id, depth);
15942
+ \u5E45\u306E\u8868.set(n.id, \u7BB1\u306E\u5E45(n, depth));
15943
+ const kids = (childrenOf.get(n.id) ?? []).filter((k) => !\u898B\u305F.has(k.id));
15944
+ if (kids.length === 0) {
15945
+ \u8449\u306E\u4E26\u3073.push(n.id);
15946
+ return;
15947
+ }
15948
+ for (const k of kids) \u4E0B\u898B(k, depth + 1);
15949
+ };
15950
+ for (const r of roots) if (!\u898B\u305F.has(r.id)) \u4E0B\u898B(r, 0);
15951
+ }
15952
+ const \u8449\u306E\u6570 = Math.max(\u8449\u306E\u4E26\u3073.length, 1);
15953
+ const \u6BB5\u306E\u9699\u9593 = depthGap - nodeH;
15954
+ const \u8449\u306E\u9593\u9694 = Math.min(slotW, nodeW + \u6BB5\u306E\u9699\u9593);
15955
+ const \u8449\u306Ex = (i) => canvasW / 2 - (\u8449\u306E\u6570 - 1) * \u8449\u306E\u9593\u9694 / 2 + i * \u8449\u306E\u9593\u9694;
15934
15956
  const posOf = /* @__PURE__ */ new Map();
15935
15957
  const nodes = [];
15936
15958
  const placed = /* @__PURE__ */ new Set();
@@ -15940,7 +15962,7 @@ function computeTreeLayout(treeNodes, canvasW, canvasH) {
15940
15962
  const kids = (childrenOf.get(n.id) ?? []).filter((k) => !placed.has(k.id));
15941
15963
  let x;
15942
15964
  if (kids.length === 0) {
15943
- x = leafCursor * slotW + slotW / 2;
15965
+ x = \u8449\u306Ex(leafCursor);
15944
15966
  leafCursor += 1;
15945
15967
  } else {
15946
15968
  const xs = kids.map((k) => place(k, depth + 1));
@@ -15954,7 +15976,7 @@ function computeTreeLayout(treeNodes, canvasW, canvasH) {
15954
15976
  ...n.subtitle !== void 0 ? { subtitle: n.subtitle } : {},
15955
15977
  x,
15956
15978
  y,
15957
- w: \u7BB1\u306E\u5E45(n, depth),
15979
+ w: \u5E45\u306E\u8868.get(n.id) ?? \u7BB1\u306E\u5E45(n, depth),
15958
15980
  h: nodeH,
15959
15981
  depth,
15960
15982
  ...n.unresolved ? { unresolved: true } : {}
@@ -16141,7 +16163,7 @@ function \u63CF\u304F\u6A2A\u306E\u7AEF(n) {
16141
16163
  if (n.isRoot || !n.isLeaf) return [n.x - n.w / 2, n.x + n.w / 2];
16142
16164
  const \u8D77\u70B9 = n.x + (n.side === "right" ? -n.w / 2 : n.w / 2);
16143
16165
  const \u540D\u524D = \u653E\u5C04\u306E\u884C(n)[0];
16144
- const \u5E45 = measureTextWidth(\u540D\u524D.text, { fontSize: \u540D\u524D.fontSize});
16166
+ const \u5E45 = textWidth(\u540D\u524D.text, \u540D\u524D.fontSize);
16145
16167
  return n.side === "right" ? [\u8D77\u70B9, \u8D77\u70B9 + \u5E45] : [\u8D77\u70B9 - \u5E45, \u8D77\u70B9];
16146
16168
  }
16147
16169
  function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
@@ -16214,38 +16236,52 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16214
16236
  if (kids.length === 0) return 1;
16215
16237
  return kids.reduce((sum, k) => sum + leafCountOf(k.id, seen), 0);
16216
16238
  };
16217
- const maxSubDepth = firstLevel.length > 0 ? Math.max(0, ...firstLevel.map((br) => subDepthOf(br.id, /* @__PURE__ */ new Set()))) : 0;
16239
+ const leftBranches = firstLevel.slice(0, leftCount);
16240
+ const rightBranches = firstLevel.slice(leftCount);
16218
16241
  const minLayer1XOffset = rootW / 2 + branchW / 2 + MIND_BOX_GAP;
16219
16242
  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 \u8449\u306E\u540D\u524D\u306E\u6700\u5927\u5E45 = Math.max(
16223
- 0,
16224
- ...firstLevel.filter((br) => (childrenOf.get(br.id) ?? []).length === 0).map((br) => {
16225
- const \u540D\u524D = \u653E\u5C04\u306E\u884C({ title: br.title, isRoot: false })[0];
16226
- return measureTextWidth(\u540D\u524D.text, { fontSize: \u540D\u524D.fontSize});
16227
- })
16228
- );
16229
- const \u540D\u524D\u3067\u6C7A\u307E\u308B\u4E0A\u9650 = canvasW / 2 + branchW / 2 - \u8449\u306E\u540D\u524D\u306E\u6700\u5927\u5E45;
16230
- const layer1XOffset = Math.max(minLayer1XOffset, Math.min(\u540D\u524D\u3067\u6C7A\u307E\u308B\u4E0A\u9650, maxLayer1XOffset));
16231
- const room = canvasW / 2 - layer1XOffset;
16232
16243
  const MIN_SUB_W = 56;
16233
16244
  const PREFERRED_GAP = MIND_BOX_GAP;
16234
- const gapRoom = maxSubDepth > 0 ? (room - branchW / 2 - maxSubDepth * MIN_SUB_W) / maxSubDepth : 0;
16235
- const gap = Math.max(8, Math.min(PREFERRED_GAP, gapRoom));
16236
- const effSubW = maxSubDepth > 0 ? Math.max(1, Math.min(subBranchW, (room - branchW / 2 - maxSubDepth * gap) / maxSubDepth)) : subBranchW;
16237
- const step1 = (branchW + effSubW) / 2 + gap;
16238
- const stepN = effSubW + gap;
16239
- const subOffset = (subDepth) => subDepth <= 0 ? 0 : step1 + (subDepth - 1) * stepN;
16240
- const leftBranches = firstLevel.slice(0, leftCount);
16241
- const rightBranches = firstLevel.slice(leftCount);
16245
+ const \u679D\u306E\u540D\u524D\u306E\u5E45 = (title) => {
16246
+ const \u540D\u524D = \u653E\u5C04\u306E\u884C({ title, isRoot: false })[0];
16247
+ return textWidth(\u540D\u524D.text, \u540D\u524D.fontSize);
16248
+ };
16249
+ const \u679D\u306E\u6A2A\u3092\u6C7A\u3081\u308B = (br) => {
16250
+ const maxSubDepth = subDepthOf(br.id, /* @__PURE__ */ new Set());
16251
+ const \u4E0A\u9650 = maxSubDepth > 0 ? canvasW / 2 - (branchW / 2 + maxSubDepth * preferredSubDx) : canvasW / 2 + branchW / 2 - \u679D\u306E\u540D\u524D\u306E\u5E45(br.title);
16252
+ const layer1XOffset = Math.floor(Math.max(minLayer1XOffset, \u4E0A\u9650));
16253
+ const room = canvasW / 2 - layer1XOffset;
16254
+ const gapRoom = maxSubDepth > 0 ? (room - branchW / 2 - maxSubDepth * MIN_SUB_W) / maxSubDepth : 0;
16255
+ const gap = Math.floor(Math.max(8, Math.min(PREFERRED_GAP, gapRoom)));
16256
+ const effSubW = maxSubDepth > 0 ? Math.floor(
16257
+ Math.max(1, Math.min(subBranchW, (room - branchW / 2 - maxSubDepth * gap) / maxSubDepth))
16258
+ ) : subBranchW;
16259
+ const step1 = (branchW + effSubW) / 2 + gap;
16260
+ const stepN = effSubW + gap;
16261
+ return {
16262
+ layer1XOffset,
16263
+ effSubW,
16264
+ subOffset: (subDepth) => subDepth <= 0 ? 0 : step1 + (subDepth - 1) * stepN
16265
+ };
16266
+ };
16267
+ const \u6A2A\u306E\u5272\u4ED8\u8868 = new Map(
16268
+ firstLevel.map((br) => [br.id, \u679D\u306E\u6A2A\u3092\u6C7A\u3081\u308B(br)])
16269
+ );
16270
+ const \u4E00\u756A\u5185\u5074\u306E\u96E2\u308C = Math.min(
16271
+ ...firstLevel.length > 0 ? firstLevel.map((br) => \u6A2A\u306E\u5272\u4ED8\u8868.get(br.id).layer1XOffset) : [minLayer1XOffset]
16272
+ );
16242
16273
  const leavesOfSide = (brs) => Math.max(
16243
16274
  1,
16244
16275
  brs.reduce((sum, br) => sum + leafCountOf(br.id, /* @__PURE__ */ new Set()), 0)
16245
16276
  );
16246
16277
  const sideLaneCount = Math.max(leavesOfSide(leftBranches), leavesOfSide(rightBranches));
16247
16278
  const laneBandH = Math.max(0, canvasH - BRANCH_BOX_H_MAX);
16248
- const rowGap = sideLaneCount > 1 ? Math.min(laneBandH / (sideLaneCount - 1), \u7E26\u306E\u9593\u9694\u306E\u4E0A\u9650(layer1XOffset)) : subBranchH + 14;
16279
+ const rowGap = sideLaneCount > 1 ? Math.min(
16280
+ laneBandH / (sideLaneCount - 1),
16281
+ // 帯は図で 1 つなので、**一番内側の枝** から上限を取る (#966)。
16282
+ // 外へ出た枝に合わせると、内側に残った枝の傾きが 45 度を超える
16283
+ \u7E26\u306E\u9593\u9694\u306E\u4E0A\u9650(\u4E00\u756A\u5185\u5074\u306E\u96E2\u308C)
16284
+ ) : subBranchH + 14;
16249
16285
  const effSubH = Math.min(SUB_BOX_H_MAX, rowGap * 0.7);
16250
16286
  const effBranchH = Math.min(BRANCH_BOX_H_MAX, rowGap * 0.7);
16251
16287
  const \u7AEF\u306E\u4F59\u308A = Math.max(effSubH, effBranchH) / 2;
@@ -16261,11 +16297,11 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16261
16297
  const half = nodeHalfW.get(mindData.rootId) ?? rootW / 2;
16262
16298
  return \u4E2D\u5FC3\u306Ex + (isLeft ? -half : half);
16263
16299
  };
16264
- const placeSubtree = (node, subDepth, isLeft, tone, placed, laneRef) => {
16300
+ const placeSubtree = (node, subDepth, isLeft, tone, placed, laneRef, \u6A2A) => {
16265
16301
  placed.add(node.id);
16266
16302
  const dirX = isLeft ? -1 : 1;
16267
- const x = cx + dirX * (layer1XOffset + subOffset(subDepth));
16268
- const w = subDepth === 0 ? branchW : effSubW;
16303
+ const x = cx + dirX * (\u6A2A.layer1XOffset + \u6A2A.subOffset(subDepth));
16304
+ const w = subDepth === 0 ? branchW : \u6A2A.effSubW;
16269
16305
  const h = subDepth === 0 ? effBranchH : effSubH;
16270
16306
  const myTone = node.tone ?? tone;
16271
16307
  const kids = (childrenOf.get(node.id) ?? []).filter((k) => !placed.has(k.id));
@@ -16281,7 +16317,8 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16281
16317
  isLeft,
16282
16318
  myTone ?? MIND_TONES[i % MIND_TONES.length],
16283
16319
  placed,
16284
- laneRef
16320
+ laneRef,
16321
+ \u6A2A
16285
16322
  )
16286
16323
  );
16287
16324
  y = (ys[0] + ys[ys.length - 1]) / 2;
@@ -16314,7 +16351,7 @@ function computeMindMapLayout(mindData, cx, cy, canvasW, canvasH) {
16314
16351
  const placed = /* @__PURE__ */ new Set();
16315
16352
  brs.forEach((br, i) => {
16316
16353
  const tone = br.tone ?? MIND_TONES[(toneBase + i) % MIND_TONES.length];
16317
- placeSubtree(br, 0, isLeft, tone, placed, laneRef);
16354
+ placeSubtree(br, 0, isLeft, tone, placed, laneRef, \u6A2A\u306E\u5272\u4ED8\u8868.get(br.id) ?? \u679D\u306E\u6A2A\u3092\u6C7A\u3081\u308B(br));
16318
16355
  });
16319
16356
  };
16320
16357
  placeSide(leftBranches, true, 0);