@markdy/renderer-dom 0.7.28 → 0.7.29
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/dist/index.js +83 -23
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1748,25 +1748,59 @@ function polylineLength(points) {
|
|
|
1748
1748
|
function segmentLength(a, b) {
|
|
1749
1749
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
1750
1750
|
}
|
|
1751
|
-
function
|
|
1752
|
-
|
|
1751
|
+
function rectsOverlap(a, b) {
|
|
1752
|
+
return a.x1 < b.x2 && a.x2 > b.x1 && a.y1 < b.y2 && a.y2 > b.y1;
|
|
1753
|
+
}
|
|
1754
|
+
function overlapCount(rect, obstacles) {
|
|
1755
|
+
let hits = 0;
|
|
1756
|
+
for (const o of obstacles) if (rectsOverlap(rect, o)) hits++;
|
|
1757
|
+
return hits;
|
|
1758
|
+
}
|
|
1759
|
+
var LABEL_BOX_HEIGHT = 18;
|
|
1760
|
+
function placeFlowLabel(points, textWidth, obstacles, ast) {
|
|
1753
1761
|
let bestIndex = 0;
|
|
1754
1762
|
let bestLength = -1;
|
|
1755
1763
|
for (let i = 0; i < points.length - 1; i++) {
|
|
1756
1764
|
const len = segmentLength(points[i], points[i + 1]);
|
|
1757
1765
|
if (len > bestLength) {
|
|
1758
|
-
bestIndex = i;
|
|
1759
1766
|
bestLength = len;
|
|
1767
|
+
bestIndex = i;
|
|
1760
1768
|
}
|
|
1761
1769
|
}
|
|
1762
|
-
const a = points[bestIndex];
|
|
1763
|
-
const b = points[bestIndex + 1];
|
|
1770
|
+
const a = points[bestIndex] ?? { x: 0, y: 0 };
|
|
1771
|
+
const b = points[bestIndex + 1] ?? a;
|
|
1764
1772
|
const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1773
|
+
const horizontal = Math.abs(a.x - b.x) >= Math.abs(a.y - b.y);
|
|
1774
|
+
const half = textWidth / 2;
|
|
1775
|
+
const halfH = LABEL_BOX_HEIGHT / 2;
|
|
1776
|
+
const pad = 8;
|
|
1777
|
+
const base = horizontal ? 15 : half + 12;
|
|
1778
|
+
const step = horizontal ? LABEL_BOX_HEIGHT + 3 : textWidth + 12;
|
|
1779
|
+
const order = horizontal ? [-1, 1] : [1, -1];
|
|
1780
|
+
const offsets = [];
|
|
1781
|
+
for (let k = 0; k < 7; k++) {
|
|
1782
|
+
for (const sign of order) offsets.push(sign * (base + k * step));
|
|
1768
1783
|
}
|
|
1769
|
-
|
|
1784
|
+
let fallback = null;
|
|
1785
|
+
let fallbackHits = Number.POSITIVE_INFINITY;
|
|
1786
|
+
for (const off of offsets) {
|
|
1787
|
+
let cx = horizontal ? mid.x : mid.x + off;
|
|
1788
|
+
let cy = horizontal ? mid.y + off : mid.y;
|
|
1789
|
+
cx = clamp(cx, pad + half, ast.meta.width - pad - half);
|
|
1790
|
+
cy = clamp(cy, pad + halfH, ast.meta.height - pad - halfH);
|
|
1791
|
+
const rect = { x1: cx - half, y1: cy - halfH, x2: cx + half, y2: cy + halfH };
|
|
1792
|
+
const hits = overlapCount(rect, obstacles);
|
|
1793
|
+
if (hits === 0) return { x: round1(cx), y: round1(cy), rect };
|
|
1794
|
+
if (hits < fallbackHits) {
|
|
1795
|
+
fallbackHits = hits;
|
|
1796
|
+
fallback = { x: round1(cx), y: round1(cy), rect };
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
return fallback ?? {
|
|
1800
|
+
x: round1(mid.x),
|
|
1801
|
+
y: round1(mid.y),
|
|
1802
|
+
rect: { x1: mid.x - half, y1: mid.y - halfH, x2: mid.x + half, y2: mid.y + halfH }
|
|
1803
|
+
};
|
|
1770
1804
|
}
|
|
1771
1805
|
function clamp(n, min, max) {
|
|
1772
1806
|
if (max < min) return n;
|
|
@@ -1863,7 +1897,9 @@ var STROKE_BY_ACTION = {
|
|
|
1863
1897
|
};
|
|
1864
1898
|
var DEFAULT_STROKE = "#38bdf8";
|
|
1865
1899
|
var LABEL_MAX_CHARS = 28;
|
|
1866
|
-
var
|
|
1900
|
+
var LABEL_CHAR_PX = 6.8;
|
|
1901
|
+
var EDGE_REVEAL_MS = 220;
|
|
1902
|
+
var LABEL_RECTS = /* @__PURE__ */ new WeakMap();
|
|
1867
1903
|
function ensureEdgeLayer(scene) {
|
|
1868
1904
|
const existing = scene.querySelector(`svg[${EDGE_LAYER_ATTR}='1']`);
|
|
1869
1905
|
if (existing) return existing;
|
|
@@ -1920,6 +1956,12 @@ function isDashed(ctx) {
|
|
|
1920
1956
|
const style = String(ctx.ev.params.style ?? "");
|
|
1921
1957
|
return style === "dashed" || style === "fire_and_forget" || ctx.ev.action === "response";
|
|
1922
1958
|
}
|
|
1959
|
+
function nodeObstacleRect(state, type, sceneWidth) {
|
|
1960
|
+
const rect = actorRect(state, type);
|
|
1961
|
+
if (type !== "caption") return rect;
|
|
1962
|
+
const halfH = (rect.y2 - rect.y1) / 2 + 4;
|
|
1963
|
+
return { x1: 0, y1: state.y - halfH, x2: sceneWidth, y2: state.y + halfH };
|
|
1964
|
+
}
|
|
1923
1965
|
function buildEdge(ctx, targetName) {
|
|
1924
1966
|
const { ev, state, states, ast, scene, baseOpts, anims } = ctx;
|
|
1925
1967
|
const targetState = states.get(targetName);
|
|
@@ -1931,8 +1973,12 @@ function buildEdge(ctx, targetName) {
|
|
|
1931
1973
|
const stroke = STROKE_BY_ACTION[ev.action] ?? DEFAULT_STROKE;
|
|
1932
1974
|
const svg = ensureEdgeLayer(scene);
|
|
1933
1975
|
ensureEdgeDefs(svg);
|
|
1976
|
+
const startMs = Number(baseOpts.delay ?? 0);
|
|
1977
|
+
const durationMs = Math.max(1, Number(baseOpts.duration ?? 500));
|
|
1978
|
+
const revealMs = Math.min(EDGE_REVEAL_MS, durationMs);
|
|
1934
1979
|
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1935
1980
|
group.setAttribute("data-markdy-flow-edge", "1");
|
|
1981
|
+
group.style.opacity = "0";
|
|
1936
1982
|
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1937
1983
|
path.setAttribute("d", pathD);
|
|
1938
1984
|
path.setAttribute("fill", "none");
|
|
@@ -1956,37 +2002,51 @@ function buildEdge(ctx, targetName) {
|
|
|
1956
2002
|
group.appendChild(marker);
|
|
1957
2003
|
const labelText = String(ev.params.label ?? "");
|
|
1958
2004
|
if (labelText) {
|
|
1959
|
-
const
|
|
2005
|
+
const shown = labelText.length > LABEL_MAX_CHARS ? `${labelText.slice(0, LABEL_MAX_CHARS - 1)}\u2026` : labelText;
|
|
2006
|
+
const textWidth = shown.length * LABEL_CHAR_PX + 12;
|
|
2007
|
+
const placed = LABEL_RECTS.get(svg) ?? (LABEL_RECTS.set(svg, []), LABEL_RECTS.get(svg));
|
|
2008
|
+
const obstacles = [...placed];
|
|
2009
|
+
for (const [name, nodeState] of states.entries()) {
|
|
2010
|
+
const type = ast.actors[name]?.type ?? "box";
|
|
2011
|
+
obstacles.push(inflateRect(nodeObstacleRect(nodeState, type, ast.meta.width), 2));
|
|
2012
|
+
}
|
|
2013
|
+
const spot = placeFlowLabel(points, textWidth, obstacles, ast);
|
|
2014
|
+
placed.push(spot.rect);
|
|
1960
2015
|
const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
1961
|
-
label.setAttribute("x", `${
|
|
1962
|
-
label.setAttribute("y", `${
|
|
2016
|
+
label.setAttribute("x", `${spot.x}`);
|
|
2017
|
+
label.setAttribute("y", `${spot.y}`);
|
|
1963
2018
|
label.setAttribute("text-anchor", "middle");
|
|
2019
|
+
label.setAttribute("dominant-baseline", "middle");
|
|
1964
2020
|
label.setAttribute("font-size", "12");
|
|
1965
2021
|
label.setAttribute("font-weight", "700");
|
|
1966
2022
|
label.setAttribute("paint-order", "stroke");
|
|
1967
|
-
label.setAttribute("stroke", "rgba(2, 6, 23, 0.
|
|
2023
|
+
label.setAttribute("stroke", "rgba(2, 6, 23, 0.9)");
|
|
1968
2024
|
label.setAttribute("stroke-width", "5");
|
|
1969
2025
|
label.setAttribute("stroke-linejoin", "round");
|
|
1970
|
-
label.setAttribute("fill", "#
|
|
1971
|
-
label.setAttribute("filter", "url(#markdy-flow-glow)");
|
|
2026
|
+
label.setAttribute("fill", "#dbe4f0");
|
|
1972
2027
|
label.setAttribute("data-full-label", labelText);
|
|
1973
|
-
label.textContent =
|
|
2028
|
+
label.textContent = shown;
|
|
1974
2029
|
group.appendChild(label);
|
|
1975
2030
|
}
|
|
1976
2031
|
svg.appendChild(group);
|
|
1977
2032
|
anims.push(
|
|
1978
2033
|
path.animate([{ strokeDashoffset: length }, { strokeDashoffset: 0 }], baseOpts),
|
|
2034
|
+
// Travel the dot along the edge, then fade it at arrival so the finished
|
|
2035
|
+
// edge is a clean line + arrowhead rather than a dot resting on the tip.
|
|
1979
2036
|
marker.animate(
|
|
1980
2037
|
[
|
|
1981
|
-
{ offsetDistance: "0%", opacity: 1 },
|
|
1982
|
-
{ offsetDistance: "100%", opacity: 1 }
|
|
2038
|
+
{ offsetDistance: "0%", opacity: 1, offset: 0 },
|
|
2039
|
+
{ offsetDistance: "100%", opacity: 1, offset: 0.82 },
|
|
2040
|
+
{ offsetDistance: "100%", opacity: 0, offset: 1 }
|
|
1983
2041
|
],
|
|
1984
2042
|
baseOpts
|
|
1985
2043
|
),
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2044
|
+
// Reveal the edge at its scheduled time and keep it (persist). `fill: both`
|
|
2045
|
+
// holds opacity 0 during the delay, so nothing appears before its turn.
|
|
2046
|
+
group.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
2047
|
+
delay: startMs,
|
|
2048
|
+
duration: revealMs,
|
|
2049
|
+
fill: "both"
|
|
1990
2050
|
})
|
|
1991
2051
|
);
|
|
1992
2052
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.29",
|
|
4
4
|
"description": "Web Animations API renderer for MarkdyScript scenes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@markdy/core": "0.7.
|
|
46
|
+
"@markdy/core": "0.7.29"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"jsdom": "^29.1.1",
|
|
50
50
|
"tsup": "^8.5.1",
|
|
51
51
|
"typescript": "^5.9.3",
|
|
52
52
|
"vitest": "^4.1.7",
|
|
53
|
-
"@markdy/stdlib-systems": "0.7.
|
|
53
|
+
"@markdy/stdlib-systems": "0.7.29"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsup",
|