@cardenelabs/dragon 0.35.1 → 0.36.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/README.md +41 -3
- package/dist/cli.cjs +597 -375
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +597 -375
- package/dist/cli.js.map +1 -1
- package/dist/export.cjs +104 -37
- package/dist/export.cjs.map +1 -1
- package/dist/export.d.cts +1 -1
- package/dist/export.d.ts +1 -1
- package/dist/export.js +104 -37
- package/dist/export.js.map +1 -1
- package/dist/index.cjs +833 -526
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -15
- package/dist/index.d.ts +21 -15
- package/dist/index.js +833 -526
- package/dist/index.js.map +1 -1
- package/dist/player.global.js +2 -2
- package/dist/{schema-BBWfniwH.d.cts → schema-9VLameDG.d.cts} +15 -3
- package/dist/{schema-BBWfniwH.d.ts → schema-9VLameDG.d.ts} +15 -3
- package/package.json +3 -2
- package/src/cli.ts +13 -14
- package/src/figure-text.ts +1 -1
- package/src/index.ts +4 -4
- package/src/look/values.ts +16 -4
- package/src/messages.ts +158 -80
- package/src/parser.ts +402 -245
- package/src/player.ts +80 -9
- package/src/printer.ts +90 -60
- package/src/render/parts.ts +28 -8
- package/src/render/svg.ts +128 -33
- package/src/schema.ts +1 -1
- package/src/tokenize.ts +11 -8
- package/src/view.ts +5 -2
- package/src/words.ts +39 -65
package/dist/export.d.cts
CHANGED
package/dist/export.d.ts
CHANGED
package/dist/export.js
CHANGED
|
@@ -284,8 +284,16 @@ var LOOK = {
|
|
|
284
284
|
stroke: { hair: 1, edge: 1.7, edgeOn: 2.25, arrow: 1.5, flow: 1.3, halo: 7, on: 1.75, glyph: 2, lifeline: 1.2, envelope: 1.5, badgeRing: 1.5 },
|
|
285
285
|
shadow: { near: 0.8, far: 4, nearY: 1, farY: 3 },
|
|
286
286
|
mini: { w: 168, pad: 8, title: 14, inset: 12, radius: 10 },
|
|
287
|
-
/**
|
|
288
|
-
|
|
287
|
+
/**
|
|
288
|
+
* 寄って追う見せ方の窓の高さの、幅に対する割合と下限。
|
|
289
|
+
* `fitMinH` は見える高さに収める時 (#3047) の窓の高さの下限で、これより低い枠では収めずに枠の中で送る。
|
|
290
|
+
* `narrow` は縦長の全体図を出す枠の幅の下限で、これより狭い枠 (携帯の幅) では全体図を出さずに窓へ幅を渡す (#3055)。
|
|
291
|
+
* `badgeRoom` は番号の丸が窓から外れる段で窓を寄せ直す時に、丸の周りに空ける幅 (#3046)。
|
|
292
|
+
* `headRoom` は時系列図の図の頭の箱の下端から、窓に線を見せ始める所までの幅 (#3118)。
|
|
293
|
+
* `head` は時系列図の窓の上端に貼る頭の列の頭の箱で、アイコンを外した名前と下の字の 2 段 (#3120)。
|
|
294
|
+
* `pad` は頭の列の上下の余白、`h` は箱の高さ、`nameY` と `subY` は箱の上端から名前と下の字の基準線まで
|
|
295
|
+
*/
|
|
296
|
+
follow: { aspect: 0.75, minH: 320, fitMinH: 160, ease: 0.6, narrow: 440, badgeRoom: 8, headRoom: 10, head: { pad: 8, h: 40, nameY: 17, subY: 31 } },
|
|
289
297
|
/** 色を混ぜる割合 (%) */
|
|
290
298
|
mix: { icon: 14, regionIcon: 16, regionIconEdge: 34, cap: 12, capEdge: 42, badgePast: 14, badgePastEdge: 70, mini: 62, miniBand: 16, miniBandEdge: 36, view: 6 },
|
|
291
299
|
/** 字の並びの基準線を、置きたい高さの真ん中からどれだけ下げるか */
|
|
@@ -3048,20 +3056,31 @@ function band(region) {
|
|
|
3048
3056
|
const mark = region.icon && ICONS[region.icon] ? `<rect class="dg-bi" x="${r1(x)}" y="${r1(y)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(region.icon, x + icon / 2, y + icon / 2, iconScale)}` : "";
|
|
3049
3057
|
return `<g style="${cs(region.color)}"><rect class="dg-band" x="${r1(region.x + 0.5)}" y="${r1(region.y + 0.5)}" width="${r1(region.w - 1)}" height="${r1(region.h - 1)}" rx="${radius}"/>${mark}${lines}${note}</g>`;
|
|
3050
3058
|
}
|
|
3051
|
-
function
|
|
3052
|
-
const { m, sh } = ctx;
|
|
3053
|
-
const { radius, icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
|
|
3059
|
+
function subLines(box, m, changes, y) {
|
|
3054
3060
|
const seq = [[0, box.sub ?? "", "dg-ss"], ...changes];
|
|
3055
|
-
|
|
3061
|
+
return seq.map(([t, text2, cls], k) => {
|
|
3056
3062
|
const next = seq[k + 1]?.[0];
|
|
3057
3063
|
const anim = k === 0 ? next === void 0 ? "" : m.until(next - MOTION.untilFade) : next === void 0 ? m.rise(t) : m.rise(t, next - MOTION.untilFade);
|
|
3058
3064
|
if (text2 === "") return "";
|
|
3059
|
-
return `<g${anim ? ` class="dg-a" style="${anim}"` : ""}><text class="${cls}" x="${r1(box.cx)}" y="${r1(
|
|
3065
|
+
return `<g${anim ? ` class="dg-a" style="${anim}"` : ""}><text class="${cls}" x="${r1(box.cx)}" y="${r1(y)}" text-anchor="middle">${esc(text2)}</text></g>`;
|
|
3060
3066
|
}).join("");
|
|
3067
|
+
}
|
|
3068
|
+
function cardFrame(box, ctx, act, y, h) {
|
|
3069
|
+
const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(y)}" width="${r1(box.w)}" height="${h}" rx="${LOOK.box.radius}"${extra}/>`;
|
|
3070
|
+
return `${act ? `<g class="dg-a" style="${act}">${rect("dg-halo")}</g>` : ""}${rect("dg-st", ` ${ctx.sh}`)}${act ? `<g class="dg-a" style="${act}">${rect("dg-on")}</g>` : ""}`;
|
|
3071
|
+
}
|
|
3072
|
+
function card(box, ctx, on, changes) {
|
|
3073
|
+
const { icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
|
|
3074
|
+
const subs = subLines(box, ctx.m, changes, box.cy + subY);
|
|
3061
3075
|
const act = on.length > 0 ? activeKf(ctx, on) : void 0;
|
|
3062
|
-
const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(box.y)}" width="${r1(box.w)}" height="${box.h}" rx="${radius}"${extra}/>`;
|
|
3063
3076
|
const mark = box.icon && ICONS[box.icon] ? `<rect class="dg-ic" x="${r1(box.cx - icon / 2)}" y="${r1(box.cy + iconY - icon / 2)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(box.icon, box.cx, box.cy + iconY, iconScale)}` : "";
|
|
3064
|
-
return `<g style="${cs(box.color)}">${
|
|
3077
|
+
return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, box.y, box.h)}${mark}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(box.cy + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
|
|
3078
|
+
}
|
|
3079
|
+
function headCard(box, ctx, on, changes) {
|
|
3080
|
+
const { pad: pad2, h, nameY, subY } = LOOK.follow.head;
|
|
3081
|
+
const subs = subLines(box, ctx.m, changes, pad2 + subY);
|
|
3082
|
+
const act = on.length > 0 ? activeKf(ctx, on) : void 0;
|
|
3083
|
+
return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, pad2, h)}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(pad2 + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
|
|
3065
3084
|
}
|
|
3066
3085
|
function lifeline(x, y1, y2) {
|
|
3067
3086
|
return `<line class="dg-ll" x1="${r1(x)}" y1="${r1(y1)}" x2="${r1(x)}" y2="${r1(y2)}"/>`;
|
|
@@ -3354,6 +3373,7 @@ var PART_CSS = [
|
|
|
3354
3373
|
`.dg-tg text{${font(TYPE.tag)};fill:var(--on-c)}`,
|
|
3355
3374
|
".dg-vp-bg{fill:var(--bg)}",
|
|
3356
3375
|
".dg-vp-frame{fill:none;stroke:var(--hair)}",
|
|
3376
|
+
".dg-hd-bg{fill:var(--bg)}",
|
|
3357
3377
|
".dg-mm-bg{fill:var(--surf);stroke:var(--hair)}",
|
|
3358
3378
|
`.dg-mm-t{${font(TYPE.miniTitle)};fill:var(--mute)}`,
|
|
3359
3379
|
".dg-mm-world{fill:var(--sunk);stroke:var(--hair)}",
|
|
@@ -3467,13 +3487,34 @@ function drawSvg(diagram, layout, timeline, palette, theme, follow) {
|
|
|
3467
3487
|
const content = Object.values(L).map((parts) => parts.join("")).join("");
|
|
3468
3488
|
const { near, far, nearY, farY } = LOOK.shadow;
|
|
3469
3489
|
const shadow = `<filter id="dg-sh-${id}" x="-20%" y="-30%" width="140%" height="180%"><feDropShadow dx="0" dy="${nearY}" stdDeviation="${near}" style="flood-color:var(--sh);flood-opacity:var(--shA)"/><feDropShadow dx="0" dy="${farY}" stdDeviation="${far}" style="flood-color:var(--sh);flood-opacity:var(--shB)"/></filter>`;
|
|
3470
|
-
const
|
|
3490
|
+
const heads = follow && layout.kind === "sequence" ? layout.boxes.map((box) => headCard(box, ctx, on.get(box.id) ?? [], subs.get(box.id) ?? [])).join("") : "";
|
|
3491
|
+
const view = follow ? followView(layout, timeline, diagram, m, id, content, follow, heads) : { body: `<rect class="dg-bg" width="${layout.width}" height="${layout.height}" rx="${LOOK.region.radius}"/>${content}`, w: layout.width, h: layout.height };
|
|
3471
3492
|
const css = `.dg-${id}{${FONT_VARS};--T:${timeline.total}s;${paletteVars(palette, theme)}}${PART_CSS}${m.frames.join("")}`;
|
|
3472
3493
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="dg dg-${id}" viewBox="0 0 ${Math.ceil(view.w)} ${Math.ceil(view.h)}" width="${Math.ceil(view.w)}" height="${Math.ceil(view.h)}" role="img" aria-label="${esc(diagram.title)}" data-dragon="figure" data-view="${follow ? "follow" : "fixed"}"><style>${css}</style><defs>${shadow}</defs>${view.body}</svg>`;
|
|
3473
3494
|
}
|
|
3495
|
+
function union(rects) {
|
|
3496
|
+
const x = Math.min(...rects.map((r) => r.x));
|
|
3497
|
+
const y = Math.min(...rects.map((r) => r.y));
|
|
3498
|
+
return { x, y, w: Math.max(...rects.map((r) => r.x + r.w)) - x, h: Math.max(...rects.map((r) => r.y + r.h)) - y };
|
|
3499
|
+
}
|
|
3474
3500
|
function focusOf(layout, diagram, step) {
|
|
3501
|
+
const rects = focusParts(layout, diagram, step);
|
|
3502
|
+
return rects.length === 0 ? void 0 : union(rects);
|
|
3503
|
+
}
|
|
3504
|
+
function badgeFocus(badge2, parts, vw, vh) {
|
|
3505
|
+
const room = LOOK.badge.r + LOOK.follow.badgeRoom;
|
|
3506
|
+
const { x: bx, y: by } = badge2;
|
|
3507
|
+
const away = (p) => Math.hypot(Math.max(0, p.x - bx, bx - p.x - p.w), Math.max(0, p.y - by, by - p.y - p.h));
|
|
3508
|
+
let held = { x: bx - room, y: by - room, w: room * 2, h: room * 2 };
|
|
3509
|
+
for (const p of [...parts].sort((a, b) => away(a) - away(b))) {
|
|
3510
|
+
const next = union([held, p]);
|
|
3511
|
+
if (next.w <= vw && next.h <= vh) held = next;
|
|
3512
|
+
}
|
|
3513
|
+
return held;
|
|
3514
|
+
}
|
|
3515
|
+
function focusParts(layout, diagram, step) {
|
|
3475
3516
|
const rects = [];
|
|
3476
|
-
for (const e of layout.edges.filter((
|
|
3517
|
+
for (const e of layout.edges.filter((x) => x.step === step)) {
|
|
3477
3518
|
const xs = e.points.map((p) => p[0]);
|
|
3478
3519
|
const ys = e.points.map((p) => p[1]);
|
|
3479
3520
|
rects.push({ x: Math.min(...xs), y: Math.min(...ys), w: Math.max(...xs) - Math.min(...xs), h: Math.max(...ys) - Math.min(...ys) });
|
|
@@ -3486,24 +3527,44 @@ function focusOf(layout, diagram, step) {
|
|
|
3486
3527
|
if (box && (layout.kind === "architecture" || event.type === "swap")) rects.push(box);
|
|
3487
3528
|
}
|
|
3488
3529
|
}
|
|
3489
|
-
|
|
3490
|
-
const x = Math.min(...rects.map((r) => r.x));
|
|
3491
|
-
const y = Math.min(...rects.map((r) => r.y));
|
|
3492
|
-
return { x, y, w: Math.max(...rects.map((r) => r.x + r.w)) - x, h: Math.max(...rects.map((r) => r.y + r.h)) - y };
|
|
3530
|
+
return rects;
|
|
3493
3531
|
}
|
|
3494
|
-
function followView(layout, timeline, diagram, m, id, content, follow) {
|
|
3532
|
+
function followView(layout, timeline, diagram, m, id, content, follow, heads) {
|
|
3495
3533
|
const F = LOOK.follow;
|
|
3496
3534
|
const M = LOOK.mini;
|
|
3497
|
-
const
|
|
3498
|
-
const
|
|
3535
|
+
const frameWidth = Math.max(1, follow.width);
|
|
3536
|
+
const full = Math.min(layout.width, frameWidth);
|
|
3537
|
+
const title = FIGURE_TEXT[follow.lang].overview;
|
|
3538
|
+
const sized = (vh2) => {
|
|
3539
|
+
const mw2 = Math.min(M.w, full * 0.4, vh2 * 0.4 / layout.height * layout.width);
|
|
3540
|
+
const k2 = mw2 / layout.width;
|
|
3541
|
+
const mh2 = layout.height * k2;
|
|
3542
|
+
const bw2 = Math.max(mw2, Math.ceil(textWidth(title, TYPE.miniTitle)));
|
|
3543
|
+
return { vh: vh2, mw: mw2, k: k2, mh: mh2, bw: bw2, bgW: bw2 + M.pad * 2, bgH: mh2 + M.pad * 2 + M.title, beside: mh2 > mw2 };
|
|
3544
|
+
};
|
|
3545
|
+
const natural = sized(Math.min(layout.height, Math.max(F.minH, full * F.aspect)));
|
|
3546
|
+
const bare = natural.beside && frameWidth < F.narrow;
|
|
3547
|
+
const room = follow.height === void 0 ? Number.POSITIVE_INFINITY : natural.beside ? follow.height : follow.height - natural.bgH - M.inset;
|
|
3548
|
+
const { vh, mw, k, mh, bw, bgW, bgH, beside } = room < natural.vh ? sized(Math.max(F.fitMinH, room)) : { ...natural, vh: Number.isFinite(room) ? Math.min(layout.height, room) : natural.vh };
|
|
3549
|
+
const vw = beside && !bare ? Math.min(layout.width, frameWidth - bgW - M.inset) : full;
|
|
3499
3550
|
const clampX = (x) => Math.min(layout.width - vw / 2, Math.max(vw / 2, x));
|
|
3500
|
-
const
|
|
3551
|
+
const top = heads === "" ? 0 : Math.max(...layout.boxes.map((b) => b.y + b.h)) + F.headRoom;
|
|
3552
|
+
const strip2 = heads === "" ? 0 : F.head.pad * 2 + F.head.h;
|
|
3553
|
+
const below = vh - strip2;
|
|
3554
|
+
const clampY = (y) => Math.min(layout.height - below / 2, Math.max(top + below / 2, y));
|
|
3555
|
+
const r = LOOK.badge.r;
|
|
3501
3556
|
let prev = [layout.width / 2, layout.height / 2];
|
|
3502
|
-
const
|
|
3557
|
+
const middles = timeline.steps.map((_, s) => {
|
|
3503
3558
|
const f = focusOf(layout, diagram, s);
|
|
3504
3559
|
prev = f ? [f.x + f.w / 2, f.y + f.h / 2] : prev;
|
|
3560
|
+
const at2 = [clampX(prev[0]), clampY(prev[1])];
|
|
3561
|
+
const b = layout.badges.find((x) => x.step === s);
|
|
3562
|
+
if (!b || Math.abs(b.x - at2[0]) <= vw / 2 - r && Math.abs(b.y - at2[1]) <= below / 2 - r) return at2;
|
|
3563
|
+
const near = badgeFocus(b, focusParts(layout, diagram, s), vw, below);
|
|
3564
|
+
prev = [near.x + near.w / 2, near.y + near.h / 2];
|
|
3505
3565
|
return [clampX(prev[0]), clampY(prev[1])];
|
|
3506
3566
|
});
|
|
3567
|
+
const centers = middles.map(([x, y]) => [x, y - strip2 / 2]);
|
|
3507
3568
|
const c0 = centers[0];
|
|
3508
3569
|
const cam = [
|
|
3509
3570
|
[0, c0[0], c0[1]],
|
|
@@ -3518,22 +3579,26 @@ function followView(layout, timeline, diagram, m, id, content, follow) {
|
|
|
3518
3579
|
const cl = centers[centers.length - 1];
|
|
3519
3580
|
cam.push([timeline.last, cl[0], cl[1], 1, EASE.inOut], [timeline.total, c0[0], c0[1]]);
|
|
3520
3581
|
const camKf = m.move(cam.map(([t, cx, cy, s, e]) => [t, vw / 2 - cx, vh / 2 - cy, s, e]));
|
|
3521
|
-
const
|
|
3522
|
-
const
|
|
3523
|
-
const
|
|
3524
|
-
const title = FIGURE_TEXT[follow.lang].overview;
|
|
3525
|
-
const bw = Math.max(mw, Math.ceil(textWidth(title, TYPE.miniTitle)));
|
|
3526
|
-
const bx = vw - bw - M.inset - M.pad;
|
|
3582
|
+
const bgX = beside ? vw + M.inset : vw - bgW - M.inset;
|
|
3583
|
+
const bgY = beside ? 0 : vh + M.inset;
|
|
3584
|
+
const bx = bgX + M.pad;
|
|
3527
3585
|
const mx = bx + (bw - mw) / 2;
|
|
3528
|
-
const my =
|
|
3529
|
-
const
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3586
|
+
const my = bgY + M.pad + M.title;
|
|
3587
|
+
const overview = () => {
|
|
3588
|
+
const shapes = [
|
|
3589
|
+
...layout.regions.map((r3) => `<rect class="dg-mm-band" style="${cs(r3.color)}" x="${mx + r3.x * k}" y="${my + r3.y * k}" width="${r3.w * k}" height="${r3.h * k}" rx="3"/>`),
|
|
3590
|
+
...layout.boxes.map((b) => `<rect class="dg-mm-card" style="${cs(b.color)}" x="${mx + b.x * k}" y="${my + b.y * k}" width="${b.w * k}" height="${b.h * k}" rx="1.5"/>`)
|
|
3591
|
+
].join("");
|
|
3592
|
+
const vp = m.move(cam.map(([t, cx, cy, , e]) => [t, mx + (cx - vw / 2) * k, my + (cy - vh / 2) * k, 1, e]));
|
|
3593
|
+
return {
|
|
3594
|
+
clip: `<clipPath id="dg-mm-${id}"><rect x="${mx}" y="${my}" width="${mw}" height="${mh}" rx="4"/></clipPath>`,
|
|
3595
|
+
body: `<rect class="dg-mm-bg" x="${bgX}" y="${bgY}" width="${bgW}" height="${bgH}" rx="${M.radius}"/><text class="dg-mm-t" x="${bx}" y="${my - M.pad + 2}">${title}</text><g clip-path="url(#dg-mm-${id})"><rect class="dg-mm-world" x="${mx}" y="${my}" width="${mw}" height="${mh}"/>${shapes}<rect class="dg-mm-vp dg-a"${strip2 === 0 ? "" : ` y="${strip2 * k}"`} width="${vw * k}" height="${(vh - strip2) * k}" rx="2" style="${vp}"/></g>`
|
|
3596
|
+
};
|
|
3597
|
+
};
|
|
3598
|
+
const mini = bare ? { clip: "", body: "" } : overview();
|
|
3599
|
+
const head = strip2 === 0 ? "" : `<g class="dg-hd"><rect class="dg-hd-bg" width="${vw}" height="${strip2}"/><line class="dg-sep" x1="0" y1="${strip2}" x2="${vw}" y2="${strip2}"/><g class="dg-a" style="${m.move(cam.map(([t, cx, , s, e]) => [t, vw / 2 - cx, 0, s, e]))}">${heads}</g></g>`;
|
|
3600
|
+
const body = `<defs><clipPath id="dg-vp-${id}"><rect width="${vw}" height="${vh}" rx="${LOOK.region.radius}"/></clipPath>${mini.clip}</defs><g clip-path="url(#dg-vp-${id})"><rect class="dg-vp-bg" width="${vw}" height="${vh}"/><g class="dg-a" style="${camKf}">${content}</g>${head}</g><rect class="dg-vp-frame" x="0.5" y="0.5" width="${vw - 1}" height="${vh - 1}" rx="${LOOK.region.radius}"/>${mini.body}`;
|
|
3601
|
+
return { body, w: beside && !bare ? vw + M.inset + bgW : full, h: beside ? vh : bgY + bgH };
|
|
3537
3602
|
}
|
|
3538
3603
|
function renderDiagram(input, options = {}) {
|
|
3539
3604
|
const lang = options.lang ?? "ja";
|
|
@@ -3557,8 +3622,10 @@ function renderDiagram(input, options = {}) {
|
|
|
3557
3622
|
}
|
|
3558
3623
|
|
|
3559
3624
|
// src/view.ts
|
|
3560
|
-
function chooseView(rendered, frameWidth) {
|
|
3561
|
-
const
|
|
3625
|
+
function chooseView(rendered, frameWidth, frameHeight) {
|
|
3626
|
+
const byWidth = Math.max(0, frameWidth) / rendered.layout.width;
|
|
3627
|
+
const scale = byWidth ;
|
|
3628
|
+
const textPx = scale * TYPE.boxName.size;
|
|
3562
3629
|
if (rendered.view) return { mode: rendered.view, textPx };
|
|
3563
3630
|
return { mode: textPx >= READABLE_PX ? "fixed" : "follow", textPx };
|
|
3564
3631
|
}
|