diff --git a/static/app.js b/static/app.js index faef2dc..f485c5c 100644 --- a/static/app.js +++ b/static/app.js @@ -323,6 +323,32 @@ function dagSize() { return dagLayout(tasks, idMap); } +function dagFitView() { + // 画布适配视口:缩放并居中,让全部节点可见 + const s = dagState; + const box = $('#dag-box'); + const {width, height} = dagSize(); + if (!box || !s) return; + const bw = box.clientWidth, bh = box.clientHeight; + const scale = Math.max(0.25, Math.min(1, (bw - 60) / width, (bh - 60) / height)); + s.scale = scale; + s.tx = (bw - width * scale) / 2; + s.ty = (bh - height * scale) / 2; + dagApplyView(); + saveDagState(); +} + +function dagZoomTo(scale) { + // 一键回到指定比例(100% = 原始视图) + const s = dagState; + if (!s) return; + s.scale = scale; + s.tx = 0; + s.ty = 0; + dagApplyView(); + saveDagState(); +} + function saveDagState() { if (!dagState) return; try { @@ -340,6 +366,8 @@ function dagApplyView() { if (!svg) return; svg.style.transform = `translate(${s.tx}px, ${s.ty}px) scale(${s.scale})`; svg.style.transformOrigin = '0 0'; + const pct = $('#dag-zoom-pct'); + if (pct) pct.textContent = Math.round(s.scale * 100) + '%'; } function drawDag() { @@ -364,6 +392,10 @@ function drawDag() {
+
🔍 100% + + +
🗑️ 删除区0
@@ -627,9 +659,23 @@ function renderDag() { ty: savedView?.ty || 0, drag: null, moved: false, }; - const box = $('#tab-body'); - box.innerHTML = ''; + const body2 = $('#tab-body'); + body2.innerHTML = ''; drawDag(); + // 节点是否在视口内?不在则自动适配(防止节点被平移到视口外无法操作) + const box = $('#dag-box'); + const bb = box ? box.getBoundingClientRect() : null; + let anyVisible = false; + if (bb) { + tasks.forEach(t => { + const p = dagState.pos[t.id]; + if (!p) return; + const vx = bb.left + dagState.tx + p.x * dagState.scale; + const vy = bb.top + dagState.ty + p.y * dagState.scale; + if (vx < bb.right && vx > bb.left && vy < bb.bottom && vy > bb.top) anyVisible = true; + }); + } + if (!anyVisible || !savedView) dagFitView(); } async function runWorkflow() { diff --git a/static/style.css b/static/style.css index 080f581..be5961e 100644 --- a/static/style.css +++ b/static/style.css @@ -143,6 +143,10 @@ tr:hover td{background:var(--panel2)} .dag-trash{position:absolute;left:14px;bottom:14px;background:rgba(255,107,107,.1);border:1.5px dashed var(--danger);color:var(--danger);border-radius:10px;padding:8px 14px;font-size:12px;cursor:pointer;z-index:5;display:flex;align-items:center;gap:6px;backdrop-filter:blur(2px)} .dag-trash:hover,.dag-trash.hover{background:rgba(255,107,107,.25);border-style:solid} .dag-trash .cnt{background:var(--danger);color:#fff;border-radius:8px;padding:0 6px;font-size:11px} +.dag-zoom{position:absolute;right:14px;top:14px;background:rgba(23,30,46,.88);border:1px solid var(--border);border-radius:8px;padding:4px 10px;font-size:12px;color:var(--muted);display:flex;align-items:center;gap:6px;z-index:6} +.dag-zoom b{color:var(--text);font-weight:600;min-width:42px;text-align:center} +.dag-zoom button{background:var(--panel2);border:1px solid var(--border);color:var(--text);border-radius:5px;padding:2px 8px;font-size:11px;cursor:pointer} +.dag-zoom button:hover{border-color:var(--accent);color:var(--accent)} .alert-row{border-left:3px solid var(--border);padding:12px 14px;margin-bottom:8px;background:var(--panel2);border-radius:0 10px 10px 0;cursor:pointer} .alert-row.unread{border-left-color:var(--warn)} .alert-row.critical{border-left-color:var(--danger)}