@cardenelabs/cdl 0.78.0 → 0.79.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 +30 -1
- package/dist/index.cjs +134 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -37
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +134 -37
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +134 -37
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/layout/collisions.ts +185 -41
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ CDL (Chainome Diagram Language) の主要変更履歴。
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.79.0] - 2026-09-27
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **円弧を含む線の外接矩形が図の左上まで伸びるのを直した** (#872 / #895)
|
|
13
|
+
|
|
14
|
+
道筋を読む所が **命令ごとの引数の数を見ていなかった**。 文字を全部消して数を 2 つずつ
|
|
15
|
+
組にしていたため、円弧 (`A`) の引数 7 個 = 奇数で組にする位置が 1 つずれ、その後ろの点が
|
|
16
|
+
全部ずれる。 道筋のどこにも無い `(11,11)` と `(0,0)` が点として入っていた。
|
|
17
|
+
|
|
18
|
+
| 何を | 値 |
|
|
19
|
+
|---|---|
|
|
20
|
+
| 道筋の実際の範囲 | x 105..507 / y 278..628 |
|
|
21
|
+
| 直す前の読み方が出す範囲 | x 0..691 / y 0..472 |
|
|
22
|
+
|
|
23
|
+
画面で 358px 離れている名札と線が「重なっている」 と知らされる。 逆向きにも効いており、
|
|
24
|
+
矩形が実際より大きいぶん近接の押し出しが誤った方向に働いていた。
|
|
25
|
+
|
|
26
|
+
**壊れていたのは 3 箇所**。 同じ読み方が散っており、道筋を組み直す所は円弧の `A` を命令と
|
|
27
|
+
して認識できず、前の命令の引数に混ざって `NaN` を書き出していた (円弧を持つ経路を
|
|
28
|
+
近接の解消で動かすと道筋そのものが壊れる)。
|
|
29
|
+
|
|
30
|
+
命令ごとの引数の数を 1 箇所に持ち、3 つの関数がそれを使う形にした。
|
|
31
|
+
|
|
32
|
+
外接矩形は円弧の膨らみを足す。 円弧は終点しか座標を持たないが実際の線は弦から膨らむので
|
|
33
|
+
(経路が経路を跨ぐ飛び越しは半径 11 の半円)、終点だけで矩形を作ると本当の重なりを
|
|
34
|
+
見落とす側に倒れる。
|
|
35
|
+
|
|
8
36
|
## [0.78.0] - 2026-09-26
|
|
9
37
|
|
|
10
38
|
### Fixed
|
|
@@ -3228,7 +3256,8 @@ Initial OSS release.
|
|
|
3228
3256
|
使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
|
|
3229
3257
|
行き止まりになる。
|
|
3230
3258
|
|
|
3231
|
-
[Unreleased]: https://github.com/cardene777/cdl/compare/v0.
|
|
3259
|
+
[Unreleased]: https://github.com/cardene777/cdl/compare/v0.79.0...HEAD
|
|
3260
|
+
[0.79.0]: https://github.com/cardene777/cdl/compare/v0.78.0...v0.79.0
|
|
3232
3261
|
[0.78.0]: https://github.com/cardene777/cdl/compare/v0.77.0...v0.78.0
|
|
3233
3262
|
[0.77.0]: https://github.com/cardene777/cdl/compare/v0.76.0...v0.77.0
|
|
3234
3263
|
[0.76.0]: https://github.com/cardene777/cdl/compare/v0.75.0...v0.76.0
|
package/dist/index.cjs
CHANGED
|
@@ -12798,72 +12798,169 @@ function collectBBoxes(lanes, nodes, edges) {
|
|
|
12798
12798
|
});
|
|
12799
12799
|
}
|
|
12800
12800
|
for (const e of edges) {
|
|
12801
|
-
const
|
|
12802
|
-
if (
|
|
12803
|
-
const xs = points.map((p) => p.x);
|
|
12804
|
-
const ys = points.map((p) => p.y);
|
|
12805
|
-
const minX = Math.min(...xs);
|
|
12806
|
-
const maxX = Math.max(...xs);
|
|
12807
|
-
const minY = Math.min(...ys);
|
|
12808
|
-
const maxY = Math.max(...ys);
|
|
12801
|
+
const box = pathBBox(e.d);
|
|
12802
|
+
if (!box) continue;
|
|
12809
12803
|
out.push({
|
|
12810
12804
|
kind: "edge-path",
|
|
12811
12805
|
id: e.id,
|
|
12812
|
-
x: minX - 2,
|
|
12813
|
-
y: minY - 2,
|
|
12814
|
-
w: maxX - minX + 4,
|
|
12815
|
-
h: maxY - minY + 4
|
|
12806
|
+
x: box.minX - 2,
|
|
12807
|
+
y: box.minY - 2,
|
|
12808
|
+
w: box.maxX - box.minX + 4,
|
|
12809
|
+
h: box.maxY - box.minY + 4
|
|
12816
12810
|
});
|
|
12817
12811
|
}
|
|
12818
12812
|
return out;
|
|
12819
12813
|
}
|
|
12814
|
+
var PATH_ARITY = {
|
|
12815
|
+
M: 2,
|
|
12816
|
+
L: 2,
|
|
12817
|
+
H: 1,
|
|
12818
|
+
V: 1,
|
|
12819
|
+
C: 6,
|
|
12820
|
+
S: 4,
|
|
12821
|
+
Q: 4,
|
|
12822
|
+
T: 2,
|
|
12823
|
+
A: 7,
|
|
12824
|
+
Z: 0
|
|
12825
|
+
};
|
|
12826
|
+
function isRelative(cmd) {
|
|
12827
|
+
return cmd >= "a" && cmd <= "z";
|
|
12828
|
+
}
|
|
12829
|
+
function coordSlots(cmd) {
|
|
12830
|
+
switch (cmd.toUpperCase()) {
|
|
12831
|
+
case "M":
|
|
12832
|
+
case "L":
|
|
12833
|
+
case "T":
|
|
12834
|
+
return [[0, 1]];
|
|
12835
|
+
case "H":
|
|
12836
|
+
return [[0, -1]];
|
|
12837
|
+
case "V":
|
|
12838
|
+
return [[-1, 0]];
|
|
12839
|
+
case "Q":
|
|
12840
|
+
case "S":
|
|
12841
|
+
return [[0, 1], [2, 3]];
|
|
12842
|
+
case "C":
|
|
12843
|
+
return [[0, 1], [2, 3], [4, 5]];
|
|
12844
|
+
case "A":
|
|
12845
|
+
return [[5, 6]];
|
|
12846
|
+
default:
|
|
12847
|
+
return [];
|
|
12848
|
+
}
|
|
12849
|
+
}
|
|
12850
|
+
function parsePathCommands(d) {
|
|
12851
|
+
const out = [];
|
|
12852
|
+
const commandRegex = /([MmLlHhVvCcSsQqTtAaZz])([^MmLlHhVvCcSsQqTtAaZz]*)/g;
|
|
12853
|
+
let m;
|
|
12854
|
+
while ((m = commandRegex.exec(d)) !== null) {
|
|
12855
|
+
const cmd = m[1];
|
|
12856
|
+
const arity = PATH_ARITY[cmd.toUpperCase()] ?? 0;
|
|
12857
|
+
if (arity === 0) {
|
|
12858
|
+
out.push({ cmd, args: [] });
|
|
12859
|
+
continue;
|
|
12860
|
+
}
|
|
12861
|
+
const nums = (m[2] ?? "").trim().split(/[\s,]+/).filter(Boolean).map(parseFloat);
|
|
12862
|
+
for (let i = 0; i + arity <= nums.length; i += arity) {
|
|
12863
|
+
const args = nums.slice(i, i + arity);
|
|
12864
|
+
if (!args.every(Number.isFinite)) break;
|
|
12865
|
+
const \u7E70\u308A\u8FD4\u3057 = i > 0;
|
|
12866
|
+
const c = \u7E70\u308A\u8FD4\u3057 && cmd === "M" ? "L" : \u7E70\u308A\u8FD4\u3057 && cmd === "m" ? "l" : cmd;
|
|
12867
|
+
out.push({ cmd: c, args });
|
|
12868
|
+
}
|
|
12869
|
+
}
|
|
12870
|
+
return out;
|
|
12871
|
+
}
|
|
12820
12872
|
function extractPathPoints(d) {
|
|
12821
12873
|
const out = [];
|
|
12822
|
-
|
|
12823
|
-
|
|
12824
|
-
|
|
12825
|
-
const
|
|
12826
|
-
|
|
12874
|
+
let cur = { x: 0, y: 0 };
|
|
12875
|
+
let started = false;
|
|
12876
|
+
for (const { cmd, args } of parsePathCommands(d)) {
|
|
12877
|
+
const \u76F8\u5BFE = started && isRelative(cmd);
|
|
12878
|
+
const \u57FA\u70B9 = cur;
|
|
12879
|
+
for (const [xi, yi] of coordSlots(cmd)) {
|
|
12880
|
+
const x = xi >= 0 ? \u76F8\u5BFE ? \u57FA\u70B9.x + args[xi] : args[xi] : \u57FA\u70B9.x;
|
|
12881
|
+
const y = yi >= 0 ? \u76F8\u5BFE ? \u57FA\u70B9.y + args[yi] : args[yi] : \u57FA\u70B9.y;
|
|
12827
12882
|
out.push({ x, y });
|
|
12883
|
+
cur = { x, y };
|
|
12828
12884
|
}
|
|
12885
|
+
started = true;
|
|
12829
12886
|
}
|
|
12830
12887
|
return out;
|
|
12831
12888
|
}
|
|
12889
|
+
function pathBBox(d) {
|
|
12890
|
+
let minX = Infinity;
|
|
12891
|
+
let minY = Infinity;
|
|
12892
|
+
let maxX = -Infinity;
|
|
12893
|
+
let maxY = -Infinity;
|
|
12894
|
+
let \u70B9\u3042\u308A = false;
|
|
12895
|
+
const \u53D6\u308B = (x, y) => {
|
|
12896
|
+
minX = Math.min(minX, x);
|
|
12897
|
+
minY = Math.min(minY, y);
|
|
12898
|
+
maxX = Math.max(maxX, x);
|
|
12899
|
+
maxY = Math.max(maxY, y);
|
|
12900
|
+
\u70B9\u3042\u308A = true;
|
|
12901
|
+
};
|
|
12902
|
+
let cur = { x: 0, y: 0 };
|
|
12903
|
+
let started = false;
|
|
12904
|
+
for (const { cmd, args } of parsePathCommands(d)) {
|
|
12905
|
+
const \u76F8\u5BFE = started && isRelative(cmd);
|
|
12906
|
+
const \u57FA\u70B9 = cur;
|
|
12907
|
+
for (const [xi, yi] of coordSlots(cmd)) {
|
|
12908
|
+
const x = xi >= 0 ? \u76F8\u5BFE ? \u57FA\u70B9.x + args[xi] : args[xi] : \u57FA\u70B9.x;
|
|
12909
|
+
const y = yi >= 0 ? \u76F8\u5BFE ? \u57FA\u70B9.y + args[yi] : args[yi] : \u57FA\u70B9.y;
|
|
12910
|
+
\u53D6\u308B(x, y);
|
|
12911
|
+
cur = { x, y };
|
|
12912
|
+
}
|
|
12913
|
+
if (cmd.toUpperCase() === "A") {
|
|
12914
|
+
const r = Math.max(Math.abs(args[0]), Math.abs(args[1]));
|
|
12915
|
+
const \u5F26 = Math.hypot(cur.x - \u57FA\u70B9.x, cur.y - \u57FA\u70B9.y);
|
|
12916
|
+
const \u534A\u5F26 = Math.min(\u5F26 / 2, r);
|
|
12917
|
+
const \u4F59 = Math.sqrt(Math.max(0, r * r - \u534A\u5F26 * \u534A\u5F26));
|
|
12918
|
+
const \u81A8\u3089\u307F = args[3] !== 0 ? r + \u4F59 : r - \u4F59;
|
|
12919
|
+
\u53D6\u308B(Math.min(\u57FA\u70B9.x, cur.x) - \u81A8\u3089\u307F, Math.min(\u57FA\u70B9.y, cur.y) - \u81A8\u3089\u307F);
|
|
12920
|
+
\u53D6\u308B(Math.max(\u57FA\u70B9.x, cur.x) + \u81A8\u3089\u307F, Math.max(\u57FA\u70B9.y, cur.y) + \u81A8\u3089\u307F);
|
|
12921
|
+
}
|
|
12922
|
+
started = true;
|
|
12923
|
+
}
|
|
12924
|
+
return \u70B9\u3042\u308A ? { minX, minY, maxX, maxY } : null;
|
|
12925
|
+
}
|
|
12832
12926
|
function rebuildPathD(d, map) {
|
|
12833
|
-
const commandRegex = /([MLCQZmlcqz])([^MLCQZmlcqz]*)/g;
|
|
12834
12927
|
let out = "";
|
|
12835
12928
|
let idx = 0;
|
|
12836
|
-
let
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
const
|
|
12840
|
-
if (
|
|
12929
|
+
let cur = { x: 0, y: 0 };
|
|
12930
|
+
let started = false;
|
|
12931
|
+
for (const { cmd, args } of parsePathCommands(d)) {
|
|
12932
|
+
const slots = coordSlots(cmd);
|
|
12933
|
+
if (slots.length === 0) {
|
|
12841
12934
|
out += cmd + " ";
|
|
12935
|
+
started = true;
|
|
12842
12936
|
continue;
|
|
12843
12937
|
}
|
|
12844
|
-
const
|
|
12845
|
-
const
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12938
|
+
const \u76F8\u5BFE = started && isRelative(cmd);
|
|
12939
|
+
const \u57FA\u70B9 = cur;
|
|
12940
|
+
const \u6B21\u306E\u5F15\u6570 = args.slice();
|
|
12941
|
+
for (const [xi, yi] of slots) {
|
|
12942
|
+
const x = xi >= 0 ? \u76F8\u5BFE ? \u57FA\u70B9.x + args[xi] : args[xi] : \u57FA\u70B9.x;
|
|
12943
|
+
const y = yi >= 0 ? \u76F8\u5BFE ? \u57FA\u70B9.y + args[yi] : args[yi] : \u57FA\u70B9.y;
|
|
12944
|
+
const [nx, ny] = map(x, y, idx);
|
|
12945
|
+
if (!\u76F8\u5BFE) {
|
|
12946
|
+
if (xi >= 0) \u6B21\u306E\u5F15\u6570[xi] = nx;
|
|
12947
|
+
if (yi >= 0) \u6B21\u306E\u5F15\u6570[yi] = ny;
|
|
12948
|
+
}
|
|
12849
12949
|
idx += 1;
|
|
12950
|
+
cur = { x, y };
|
|
12850
12951
|
}
|
|
12851
|
-
out += cmd + " " +
|
|
12952
|
+
out += cmd + " " + \u6B21\u306E\u5F15\u6570.join(" ") + " ";
|
|
12953
|
+
started = true;
|
|
12852
12954
|
}
|
|
12853
12955
|
return out.trim();
|
|
12854
12956
|
}
|
|
12855
12957
|
function cornerBoundaryIndices(d) {
|
|
12856
|
-
const commandRegex = /([MLCQZmlcqz])([^MLCQZmlcqz]*)/g;
|
|
12857
12958
|
let idx = 0;
|
|
12858
12959
|
let firstCornerEnd = -1;
|
|
12859
12960
|
let lastCornerStart = -1;
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12863
|
-
const argsStr = (m[2] ?? "").trim();
|
|
12864
|
-
if (argsStr === "" || cmd === "Z" || cmd === "z") continue;
|
|
12865
|
-
const pairs = argsStr.split(/[\s,]+/).filter(Boolean).length >> 1;
|
|
12866
|
-
if ((cmd === "Q" || cmd === "q") && pairs >= 2) {
|
|
12961
|
+
for (const { cmd } of parsePathCommands(d)) {
|
|
12962
|
+
const pairs = coordSlots(cmd).length;
|
|
12963
|
+
if (cmd.toUpperCase() === "Q" && pairs >= 2) {
|
|
12867
12964
|
if (firstCornerEnd < 0) firstCornerEnd = idx + 1;
|
|
12868
12965
|
lastCornerStart = idx;
|
|
12869
12966
|
}
|