mirror of
https://github.com/hansjone/netx.git
synced 2026-10-10 18:10:45 +08:00
Restore topology fitView with off-screen nodes.
onlyRenderVisibleElements leaves nodes unmeasured; fitView now uses includeHiddenNodes so declared sizes still drive the viewport. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4600629d3a
commit
6e7d84b782
1 changed files with 23 additions and 7 deletions
|
|
@ -107,6 +107,13 @@ function formatUpdatedAt(value?: string | null): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const SNAP_GRID: [number, number] = [16, 16];
|
const SNAP_GRID: [number, number] = [16, 16];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onlyRenderVisibleElements leaves off-screen nodes unmeasured; default fitView
|
||||||
|
* skips those. includeHiddenNodes uses declared width/height so fit still works.
|
||||||
|
*/
|
||||||
|
const FIT_VIEW_OPTS = { padding: 0.2, includeHiddenNodes: true } as const;
|
||||||
|
const FIT_VIEW_OPTS_FS = { padding: 0.15, includeHiddenNodes: true } as const;
|
||||||
const UNDO_MAX = 40;
|
const UNDO_MAX = 40;
|
||||||
const PALETTE_DND = "application/x-netx-topo-palette";
|
const PALETTE_DND = "application/x-netx-topo-palette";
|
||||||
|
|
||||||
|
|
@ -1009,7 +1016,7 @@ export function TopologyPage() {
|
||||||
redoRef.current = [];
|
redoRef.current = [];
|
||||||
clearDirty();
|
clearDirty();
|
||||||
bumpHistory();
|
bumpHistory();
|
||||||
window.setTimeout(() => rfRef.current?.fitView({ padding: 0.2 }), 50);
|
window.setTimeout(() => rfRef.current?.fitView({ ...FIT_VIEW_OPTS }), 50);
|
||||||
}
|
}
|
||||||
historyLockRef.current = false;
|
historyLockRef.current = false;
|
||||||
}, [canvasMode, mapId, graphQuery.data, edgeDefaults, setNodes, setEdges, clearDirty, bumpHistory]);
|
}, [canvasMode, mapId, graphQuery.data, edgeDefaults, setNodes, setEdges, clearDirty, bumpHistory]);
|
||||||
|
|
@ -1096,7 +1103,7 @@ export function TopologyPage() {
|
||||||
const next = layoutGraph(nodes, edges, kind, { onlyIds });
|
const next = layoutGraph(nodes, edges, kind, { onlyIds });
|
||||||
setNodes(next);
|
setNodes(next);
|
||||||
markDirty();
|
markDirty();
|
||||||
window.setTimeout(() => rfRef.current?.fitView({ padding: 0.2 }), 40);
|
window.setTimeout(() => rfRef.current?.fitView({ ...FIT_VIEW_OPTS }), 40);
|
||||||
if (opts?.persist && mapId) {
|
if (opts?.persist && mapId) {
|
||||||
try {
|
try {
|
||||||
const graph = await patchTopologyPositions(mapId, flowToPositions(next));
|
const graph = await patchTopologyPositions(mapId, flowToPositions(next));
|
||||||
|
|
@ -1362,7 +1369,7 @@ export function TopologyPage() {
|
||||||
setEdges(rfEdges);
|
setEdges(rfEdges);
|
||||||
historyLockRef.current = false;
|
historyLockRef.current = false;
|
||||||
if (didAutoLayout) {
|
if (didAutoLayout) {
|
||||||
window.setTimeout(() => rfRef.current?.fitView({ padding: 0.2 }), 50);
|
window.setTimeout(() => rfRef.current?.fitView({ ...FIT_VIEW_OPTS }), 50);
|
||||||
}
|
}
|
||||||
const out: TopologyDiscoverOut = {
|
const out: TopologyDiscoverOut = {
|
||||||
map_id: mapId,
|
map_id: mapId,
|
||||||
|
|
@ -1657,7 +1664,7 @@ export function TopologyPage() {
|
||||||
const active = Boolean(el && document.fullscreenElement === el);
|
const active = Boolean(el && document.fullscreenElement === el);
|
||||||
setFullscreen(active);
|
setFullscreen(active);
|
||||||
if (active) {
|
if (active) {
|
||||||
window.setTimeout(() => rfRef.current?.fitView({ padding: 0.15 }), 80);
|
window.setTimeout(() => rfRef.current?.fitView({ ...FIT_VIEW_OPTS_FS }), 80);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.addEventListener("fullscreenchange", syncFs);
|
document.addEventListener("fullscreenchange", syncFs);
|
||||||
|
|
@ -2043,7 +2050,12 @@ export function TopologyPage() {
|
||||||
setSearchHitIds([nodeId]);
|
setSearchHitIds([nodeId]);
|
||||||
if (searchHitTimerRef.current) window.clearTimeout(searchHitTimerRef.current);
|
if (searchHitTimerRef.current) window.clearTimeout(searchHitTimerRef.current);
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
rfRef.current?.fitView({ nodes: [{ id: nodeId }], padding: 0.45, duration: 280 });
|
rfRef.current?.fitView({
|
||||||
|
nodes: [{ id: nodeId }],
|
||||||
|
padding: 0.45,
|
||||||
|
duration: 280,
|
||||||
|
includeHiddenNodes: true,
|
||||||
|
});
|
||||||
}, 30);
|
}, 30);
|
||||||
searchHitTimerRef.current = window.setTimeout(() => {
|
searchHitTimerRef.current = window.setTimeout(() => {
|
||||||
setSearchHitIds((cur) => (cur.length === 1 && cur[0] === nodeId ? [] : cur));
|
setSearchHitIds((cur) => (cur.length === 1 && cur[0] === nodeId ? [] : cur));
|
||||||
|
|
@ -2721,7 +2733,7 @@ export function TopologyPage() {
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn--sm btn--ghost"
|
className="btn btn--sm btn--ghost"
|
||||||
disabled={nodes.length === 0}
|
disabled={nodes.length === 0}
|
||||||
onClick={() => rfRef.current?.fitView({ padding: 0.2 })}
|
onClick={() => rfRef.current?.fitView({ ...FIT_VIEW_OPTS })}
|
||||||
>
|
>
|
||||||
{t("topology.fit")}
|
{t("topology.fit")}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -3276,7 +3288,7 @@ export function TopologyPage() {
|
||||||
type="button"
|
type="button"
|
||||||
className="topo-fs-toolbar__btn"
|
className="topo-fs-toolbar__btn"
|
||||||
title={t("topology.fit")}
|
title={t("topology.fit")}
|
||||||
onClick={() => rfRef.current?.fitView({ padding: 0.2 })}
|
onClick={() => rfRef.current?.fitView({ ...FIT_VIEW_OPTS })}
|
||||||
>
|
>
|
||||||
{t("topology.fit")}
|
{t("topology.fit")}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -3369,8 +3381,12 @@ export function TopologyPage() {
|
||||||
onMoveStart={closeCtxMenu}
|
onMoveStart={closeCtxMenu}
|
||||||
onInit={(inst) => {
|
onInit={(inst) => {
|
||||||
rfRef.current = inst as ReactFlowInstance<Node<NeNodeData>, Edge>;
|
rfRef.current = inst as ReactFlowInstance<Node<NeNodeData>, Edge>;
|
||||||
|
if (nodesRef.current.length > 0) {
|
||||||
|
window.setTimeout(() => inst.fitView({ ...FIT_VIEW_OPTS }), 0);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
fitView
|
fitView
|
||||||
|
fitViewOptions={{ ...FIT_VIEW_OPTS }}
|
||||||
deleteKeyCode={null}
|
deleteKeyCode={null}
|
||||||
edgesFocusable
|
edgesFocusable
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue