Thibault Saunier d3ad6136ef dots-viewer: Refactor JavaScript into modular architecture
Split monolithic embedded JavaScript in overlay.html into dedicated modules:
- tooltip.js: Custom tooltip functionality with interactive copy/paste mode
- pipeline-navigation.js: Clickable pipeline-dot references for navigation
- text-ellipsizer.js: Text ellipsizing with tooltip integration
- svg-overlay-manager.js: Main coordinator orchestrating all functionality

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9547>
2025-08-19 15:34:44 +00:00

174 lines
5.5 KiB
JavaScript

/**
* SVG Overlay Manager
*
* Main coordinator for all SVG overlay functionality including tooltips,
* text ellipsizing, pipeline navigation, and drag-to-pan interaction.
*/
class SvgOverlayManager {
constructor() {
this.tooltipManager = null;
this.pipelineNavigationManager = null;
this.textEllipsizerManager = null;
this.gv = null;
}
/**
* Initializes all managers and sets up the SVG overlay functionality
*/
init() {
// Initialize managers
this.tooltipManager = new TooltipManager();
this.pipelineNavigationManager = new PipelineNavigationManager(this.tooltipManager);
this.textEllipsizerManager = new TextEllipsizerManager(this.tooltipManager, this.pipelineNavigationManager);
// Set up GraphViz SVG functionality
this.setupGraphvizSvg();
}
/**
* Sets up GraphViz SVG functionality and event handlers
*/
setupGraphvizSvg() {
$("#graph").graphviz({
url: this.getSvgUrl(),
ready: () => {
this.onSvgReady();
}
});
}
/**
* Called when SVG is loaded and ready
*/
onSvgReady() {
this.gv = $("#graph").data('graphviz.svg');
const $svg = $("#graph svg");
// Set up node click functionality for highlighting
this.setupNodeHighlighting();
// Set up smart drag-to-pan behavior that doesn't interfere with text selection
this.setupSmartDragBehavior();
// Set up keyboard shortcuts
this.setupKeyboardShortcuts();
// Set up save SVG functionality
this.setupSaveSvg();
// Process SVG content
this.processSvgContent($svg);
}
/**
* Processes SVG content with all managers
* @param {jQuery} $svg - jQuery object containing the SVG element
*/
processSvgContent($svg) {
// Set up pipeline-dot navigation
this.pipelineNavigationManager.setupPipelineDotNavigation($svg);
// Process text ellipsizing (this must come after pipeline navigation setup)
this.textEllipsizerManager.ellipsizeLongText($svg);
}
/**
* Sets up node click functionality for highlighting connected nodes
*/
setupNodeHighlighting() {
this.gv.nodes().on('click', function () {
const gv = $("#graph").data('graphviz.svg');
let $set = $();
$set.push(this);
$set = $set.add(gv.linkedFrom(this, true));
$set = $set.add(gv.linkedTo(this, true));
gv.highlight($set, true);
gv.bringToFront($set);
});
}
/**
* Sets up smart drag behavior that allows text selection while preserving pan functionality
*/
setupSmartDragBehavior() {
const graphDiv = document.getElementById('graph');
// Intercept mousedown events to prevent dragscroll on text elements
graphDiv.addEventListener('mousedown', (e) => {
if (e.target.tagName === 'text' || e.target.tagName === 'tspan') {
if (e.target.textContent &&
e.target.textContent.startsWith("pipeline-dot=") &&
e.target.textContent.includes(".dot")) {
return; // Let pipeline dot click handler take precedence
}
e.stopPropagation(); // Stop dragscroll for regular text
return true;
}
}, true);
}
/**
* Sets up keyboard shortcuts for the SVG viewer
*/
setupKeyboardShortcuts() {
$(document).on('keyup', (evt) => {
if (evt.key == "Escape") {
this.gv.highlight();
} else if (evt.key == "w") {
this.gv.scaleInView((this.gv.zoom.percentage + 100));
} else if (evt.key == "s") {
this.gv.scaleInView((this.gv.zoom.percentage - 100) || 100);
}
});
}
/**
* Sets up SVG save functionality
*/
setupSaveSvg() {
$("#save-svg").on('click', () => {
const svgElement = $("#graph svg")[0];
const svgData = new XMLSerializer().serializeToString(svgElement);
const blob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
const url = URL.createObjectURL(blob);
const title = document.getElementById("title").textContent.trim();
const downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.download = title + ".svg";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
URL.revokeObjectURL(url);
});
}
/**
* Gets the SVG URL from query parameters
* @returns {string} SVG URL
*/
getSvgUrl() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('svg');
}
/**
* Gets the title from query parameters and sets it in the document
*/
setTitle() {
const urlParams = new URLSearchParams(window.location.search);
const title = urlParams.get('title');
if (title) {
document.getElementById("title").textContent = title;
document.title = "Dots viewer: " + title;
}
}
}
// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
module.exports = SvgOverlayManager;
} else {
window.SvgOverlayManager = SvgOverlayManager;
}