Skip to content

Commit f3ddc8f

Browse files
committed
Merge branch 'service_path_visual' into 'main'
Service path visual See merge request 701/netbox/cesnet_service_path_plugin!42
2 parents 71ab971 + 364a940 commit f3ddc8f

File tree

2 files changed

+72
-62
lines changed

2 files changed

+72
-62
lines changed

cesnet_service_path_plugin/templates/cesnet_service_path_plugin/inc/topology_visualization.html

Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -39,94 +39,104 @@
3939
}
4040
console.log('Topology data :', data);
4141

42-
// Calculate preset positions for deterministic layout
42+
// Calculate preset positions for deterministic layout with adaptive scaling
4343
function calculatePresetPositions(topologyData) {
4444
const positions = {};
4545
const serviceNodes = topologyData.nodes.filter(n => n.data.type === 'service');
4646
const segmentNodes = topologyData.nodes.filter(n => n.data.type === 'segment');
4747
const siteNodes = topologyData.nodes.filter(n => n.data.type === 'site');
4848
const circuitNodes = topologyData.nodes.filter(n => n.data.type === 'circuit');
4949

50-
// Calculate center X for the canvas
51-
const centerX = 500;
50+
// Analyze topology complexity to determine spacing
51+
const maxSitesInSegment = Math.max(...segmentNodes.map(seg =>
52+
siteNodes.filter(s => s.data.parent === seg.data.id).length
53+
), 1);
54+
const maxCircuitsInSegment = Math.max(...segmentNodes.map(seg =>
55+
circuitNodes.filter(c => c.data.parent === seg.data.id).length
56+
), 1);
57+
58+
// Adaptive spacing based on complexity
59+
// For larger topologies, use tighter spacing
60+
let baseNodeSpacing = 180; // Base spacing between nodes
61+
let baseSegmentSpacing = 500; // Base spacing between segments
62+
63+
// Scale down spacing for complex topologies
64+
if (maxSitesInSegment > 3 || maxCircuitsInSegment > 3) {
65+
const complexityFactor = Math.max(maxSitesInSegment, maxCircuitsInSegment);
66+
baseNodeSpacing = Math.max(140, 180 - (complexityFactor - 3) * 15);
67+
baseSegmentSpacing = Math.max(400, 500 - (complexityFactor - 3) * 30);
68+
}
69+
70+
// Calculate total width needed for each segment
71+
const segmentWidths = segmentNodes.map(segment => {
72+
const segmentId = segment.data.id;
73+
const segmentSites = siteNodes.filter(s => s.data.parent === segmentId);
74+
const segmentCircuits = circuitNodes.filter(c => c.data.parent === segmentId);
75+
76+
const maxNodesInRow = Math.max(segmentSites.length, segmentCircuits.length);
77+
return maxNodesInRow > 1 ? (maxNodesInRow - 1) * baseNodeSpacing : 0;
78+
});
79+
80+
// Calculate total layout width and determine segment positions
81+
const totalWidth = segmentWidths.reduce((sum, w) => sum + w, 0) +
82+
(segmentNodes.length - 1) * baseSegmentSpacing;
83+
84+
// Calculate center X for the canvas (use larger value for wide topologies)
85+
const centerX = Math.max(500, totalWidth / 2);
5286

5387
// Service path at top center
5488
if (serviceNodes.length > 0) {
5589
positions[serviceNodes[0].data.id] = { x: centerX, y: 50 };
5690
}
5791

58-
// Segments positioning
59-
let segmentSpacing = 500;
60-
61-
// If only one segment, center it
62-
if (segmentNodes.length === 1) {
63-
positions[segmentNodes[0].data.id] = { x: centerX, y: 220 };
64-
} else {
65-
// Multiple segments - space them out horizontally
66-
const segmentStartX = centerX - (segmentNodes.length - 1) * segmentSpacing / 2;
67-
segmentNodes.forEach((segment, i) => {
68-
positions[segment.data.id] = {
69-
x: segmentStartX + i * segmentSpacing,
70-
y: 220
71-
};
72-
});
73-
}
92+
// Position segments
93+
let currentX = centerX - totalWidth / 2;
7494

75-
// Sites and circuits within segments
7695
segmentNodes.forEach((segment, segmentIndex) => {
7796
const segmentId = segment.data.id;
78-
const segmentX = positions[segmentId].x;
97+
const segmentWidth = segmentWidths[segmentIndex];
98+
const segmentCenterX = currentX + segmentWidth / 2;
99+
100+
positions[segmentId] = { x: segmentCenterX, y: 220 };
79101

80102
// Get sites and circuits for this segment
81103
const segmentSites = siteNodes.filter(s => s.data.parent === segmentId);
82104
const segmentCircuits = circuitNodes.filter(c => c.data.parent === segmentId);
83105

84-
// Adjust spacing based on number of sites and segments
85-
let siteSpacing = 180;
86-
87-
// For single segment layouts, use more compact spacing
88-
if (segmentNodes.length === 1) {
89-
if (segmentSites.length === 2) {
90-
siteSpacing = 220;
91-
} else if (segmentSites.length === 1) {
92-
siteSpacing = 0;
93-
}
106+
// Position sites horizontally within segment
107+
if (segmentSites.length === 1) {
108+
positions[segmentSites[0].data.id] = {
109+
x: segmentCenterX,
110+
y: 360
111+
};
94112
} else {
95-
// Multiple segments
96-
if (segmentSites.length === 2) {
97-
siteSpacing = 250;
98-
} else if (segmentSites.length === 1) {
99-
siteSpacing = 0;
100-
}
113+
const siteStartX = segmentCenterX - (segmentSites.length - 1) * baseNodeSpacing / 2;
114+
segmentSites.forEach((site, i) => {
115+
positions[site.data.id] = {
116+
x: siteStartX + i * baseNodeSpacing,
117+
y: 360
118+
};
119+
});
101120
}
102121

103-
// Position sites horizontally within segment, centered around segmentX
104-
const siteStartX = segmentX - (segmentSites.length - 1) * siteSpacing / 2;
105-
segmentSites.forEach((site, i) => {
106-
positions[site.data.id] = {
107-
x: siteStartX + i * siteSpacing,
108-
y: 360 // Sites above circuits
109-
};
110-
});
111-
112-
// Adjust circuit spacing based on number of circuits
113-
let circuitSpacing = 180;
114-
122+
// Position circuits horizontally within segment
115123
if (segmentCircuits.length === 1) {
116-
// Single circuit - center it
117-
circuitSpacing = 0;
118-
} else if (segmentCircuits.length === 2) {
119-
circuitSpacing = segmentNodes.length === 1 ? 220 : 250;
124+
positions[segmentCircuits[0].data.id] = {
125+
x: segmentCenterX,
126+
y: 460
127+
};
128+
} else {
129+
const circuitStartX = segmentCenterX - (segmentCircuits.length - 1) * baseNodeSpacing / 2;
130+
segmentCircuits.forEach((circuit, i) => {
131+
positions[circuit.data.id] = {
132+
x: circuitStartX + i * baseNodeSpacing,
133+
y: 460
134+
};
135+
});
120136
}
121137

122-
// Position circuits between/below sites, centered around segmentX
123-
const circuitStartX = segmentX - (segmentCircuits.length - 1) * circuitSpacing / 2;
124-
segmentCircuits.forEach((circuit, i) => {
125-
positions[circuit.data.id] = {
126-
x: circuitStartX + i * circuitSpacing,
127-
y: 460 // Circuits below sites
128-
};
129-
});
138+
// Move to next segment position
139+
currentX += segmentWidth + baseSegmentSpacing;
130140
});
131141

132142
return positions;

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "cesnet_service_path_plugin"
7-
version = "5.2.1"
7+
version = "5.2.2"
88
description = "Adds ability to create, edit and view service paths in the network."
99
authors = [
1010
{name = "Jan Krupa", email = "jan.krupa@cesnet.cz"},

0 commit comments

Comments
 (0)