diff --git a/awx/ui/src/screens/TopologyView/Header.js b/awx/ui/src/screens/TopologyView/Header.js
index e1b8f6648d..4929c8ceb1 100644
--- a/awx/ui/src/screens/TopologyView/Header.js
+++ b/awx/ui/src/screens/TopologyView/Header.js
@@ -25,6 +25,7 @@ const Header = ({
zoomIn,
zoomOut,
resetZoom,
+ zoomFit,
}) => {
const { light } = PageSectionVariants;
return (
@@ -74,6 +75,7 @@ const Header = ({
aria-label={t`Fit to screen`}
variant="plain"
icon={}
+ onClick={zoomFit}
>
diff --git a/awx/ui/src/screens/TopologyView/MeshGraph.js b/awx/ui/src/screens/TopologyView/MeshGraph.js
index ab808f2a50..a94c805340 100644
--- a/awx/ui/src/screens/TopologyView/MeshGraph.js
+++ b/awx/ui/src/screens/TopologyView/MeshGraph.js
@@ -52,7 +52,7 @@ function MeshGraph({ showLegend, zoom }) {
}
return generateLinks(nodes, getRandomInt(1, n - 1));
};
- const data = generateNodes(getRandomInt(5, 30));
+ const data = generateNodes(getRandomInt(250, 250));
const draw = () => {
const margin = 15;
const defaultRadius = 16;
diff --git a/awx/ui/src/screens/TopologyView/TopologyView.js b/awx/ui/src/screens/TopologyView/TopologyView.js
index bad237100b..21c52537ba 100644
--- a/awx/ui/src/screens/TopologyView/TopologyView.js
+++ b/awx/ui/src/screens/TopologyView/TopologyView.js
@@ -38,13 +38,40 @@ function TopologyView() {
};
const resetZoom = () => {
const margin = 15;
+ const height = 600;
const width = parseInt(d3.select(`#chart`).style('width'), 10) - margin;
- d3.select('.mesh-svg').transition().duration(750).call(
- zoom.transform,
- d3.zoomIdentity,
- d3.zoomTransform(d3.select('.mesh-svg').node()).invert([width / 2, 600 / 2])
- );
- }
+ d3.select('.mesh-svg')
+ .transition()
+ .duration(750)
+ .call(
+ zoom.transform,
+ d3.zoomIdentity,
+ d3
+ .zoomTransform(d3.select('.mesh-svg').node())
+ .invert([width / 2, height / 2])
+ );
+ };
+
+ const zoomFit = () => {
+ const bounds = d3.select('.mesh').node().getBBox();
+ const parent = d3.select('.mesh').node().parentElement;
+ const fullWidth = parent.clientWidth;
+ const fullHeight = parent.clientHeight;
+ const { width, height } = bounds;
+ const midX = bounds.x + width / 2;
+ const midY = bounds.y + height / 2;
+ if (width === 0 || height === 0) return; // nothing to fit
+ const scale = 0.8 / Math.max(width / fullWidth, height / fullHeight);
+ const translate = [
+ fullWidth / 2 - scale * midX,
+ fullHeight / 2 - scale * midY,
+ ];
+ const [x, y] = translate;
+ d3.select('.mesh-svg')
+ .transition()
+ .duration(750)
+ .call(zoom.transform, d3.zoomIdentity.translate(x, y).scale(scale));
+ };
return (
<>
@@ -54,6 +81,7 @@ function TopologyView() {
toggleState={showLegend}
zoomIn={zoomIn}
zoomOut={zoomOut}
+ zoomFit={zoomFit}
resetZoom={resetZoom}
/>