Skip to content

Commit 3e68d09

Browse files
committed
[APM] Service map - fixes layout issues for maps with no rum services (#62887)
* Closes #62878 in Service Maps by improving the selection algorithm for root nodes * Fixes some latent centering issues when navigating in the service map. * Removes unused imports * Added layoutstopDelayTimeout to cleanup step
1 parent abec49d commit 3e68d09

1 file changed

Lines changed: 28 additions & 13 deletions

File tree

  • x-pack/legacy/plugins/apm/public/components/app/ServiceMap

x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import React, {
1414
useState
1515
} from 'react';
1616
import { debounce } from 'lodash';
17-
import { isRumAgentName } from '../../../../../../../plugins/apm/common/agent_name';
18-
import { AGENT_NAME } from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames';
1917
import {
2018
animationOptions,
2119
cytoscapeOptions,
@@ -96,10 +94,15 @@ function getLayoutOptions(
9694
}
9795

9896
function selectRoots(cy: cytoscape.Core): string[] {
99-
const nodes = cy.nodes();
100-
const roots = nodes.roots();
101-
const rumNodes = nodes.filter(node => isRumAgentName(node.data(AGENT_NAME)));
102-
return rumNodes.union(roots).map(node => node.id());
97+
const bfs = cy.elements().bfs({
98+
roots: cy.elements().leaves()
99+
});
100+
const furthestNodeFromLeaves = bfs.path.last();
101+
return cy
102+
.elements()
103+
.roots()
104+
.union(furthestNodeFromLeaves)
105+
.map(el => el.id());
103106
}
104107

105108
export function Cytoscape({
@@ -168,15 +171,26 @@ export function Cytoscape({
168171
layout.run();
169172
}
170173
};
174+
let layoutstopDelayTimeout: NodeJS.Timeout;
171175
const layoutstopHandler: cytoscape.EventHandler = event => {
172-
event.cy.animate({
173-
...animationOptions,
174-
center: {
175-
eles: serviceName
176-
? event.cy.getElementById(serviceName)
177-
: event.cy.collection()
176+
// This 0ms timer is necessary to prevent a race condition
177+
// between the layout finishing rendering and viewport centering
178+
layoutstopDelayTimeout = setTimeout(() => {
179+
if (serviceName) {
180+
event.cy.animate({
181+
...animationOptions,
182+
fit: {
183+
eles: event.cy.elements(),
184+
padding: nodeHeight
185+
},
186+
center: {
187+
eles: event.cy.getElementById(serviceName)
188+
}
189+
});
190+
} else {
191+
event.cy.fit(undefined, nodeHeight);
178192
}
179-
});
193+
}, 0);
180194
};
181195
// debounce hover tracking so it doesn't spam telemetry with redundant events
182196
const trackNodeEdgeHover = debounce(
@@ -231,6 +245,7 @@ export function Cytoscape({
231245
cy.removeListener('select', 'node', selectHandler);
232246
cy.removeListener('unselect', 'node', unselectHandler);
233247
}
248+
clearTimeout(layoutstopDelayTimeout);
234249
};
235250
}, [cy, height, serviceName, trackApmEvent, width]);
236251

0 commit comments

Comments
 (0)