import * as Helpers from "../helpers"; import jQuery from "jquery"; import * as Config from "../../config"; export { NodeNeighborOverlay }; /** * Displays an overlay showing the neighbors of a node divided by the link type * that connects them. */ class NodeNeighborOverlay { constructor(graph, parentNode, infoOverlay) { this.graph = graph; this.parentNode = parentNode; this.infoOverlay = infoOverlay; this.activeTabNav = null; // The currently selected tab handle this.activeTabContent = null; // The currently selected tab content this.tabContentPages = {}; } /** * Creates the visible elements of the overlay. * Must be called after the graph has been initialized. */ create() { const bottomContainerDiv = Helpers.createDiv( "bottom-container", this.parentNode ); const bottomContainerNavDiv = Helpers.createDiv( "bottom-container-nav", bottomContainerDiv ); const bottomContainerLinkDiv = Helpers.createDiv( "bottom-container-links", bottomContainerDiv ); for (const [cls, color] of Object.entries(this.graph.edgeColors)) { const navTab = Helpers.createDiv( "bottom-container-nav-tab", bottomContainerNavDiv ); navTab.innerText = cls.slice(0, 3); navTab.style.backgroundColor = color; navTab.edgeType = cls; // Attach the edge type to the DOM object to retrieve it during click events jQuery(navTab).click((event) => this.openTab(event)); const tabContent = Helpers.createDiv( "bottom-container-tab-content", bottomContainerLinkDiv ); tabContent.style.backgroundColor = color; this.tabContentPages[cls] = tabContent; } this.initializeActive(bottomContainerNavDiv, bottomContainerLinkDiv); } /** * Initializes the activeTabNav and activeTabContent variables to a random edge type. * @param {Element} bottomContainerNavDiv * @param {Element} bottomContainerLinkDiv */ initializeActive(bottomContainerNavDiv, bottomContainerLinkDiv) { this.activeTabNav = bottomContainerNavDiv.firstChild; this.activeTabContent = bottomContainerLinkDiv.firstChild; this.activeTabContent.classList.add("active-tab-content"); this.activeTabNav.classList.add("active-tab-nav"); this.activeTabNav.innerText = this.activeTabNav.edgeType; } /** * Click event handler for the tab headers of the bottom menu. * @param event */ openTab(event) { const navTab = event.target; const cls = navTab.edgeType; this.activeTabNav.classList.remove("active-tab-nav"); this.activeTabNav.innerText = this.activeTabNav.innerText.slice(0, 3); navTab.classList.add("active-tab-nav"); navTab.innerText = cls; this.activeTabContent.classList.remove("active-tab-content"); this.tabContentPages[cls].classList.add("active-tab-content"); this.activeTabNav = navTab; this.activeTabContent = this.tabContentPages[cls]; } /** * Clears the images from all tab content pages. */ clearTabContentPages() { for (const page of Object.values(this.tabContentPages)) { jQuery(page).empty(); } } /** * Creates a new image (with link) for the given target node. * @param target * @returns {HTMLDivElement} */ createReference(target) { const linkDiv = document.createElement("div"); linkDiv.className = "link-img"; if ("image" in target) { const linkImage = document.createElement("img"); linkImage.src = Config.PLUGIN_PATH + "datasets/images/" + target.image; linkDiv.appendChild(linkImage); } jQuery(linkDiv).on("click", () => { this.graph.focusOnNode(target); this.infoOverlay.updateInfoOverlay(target); }); return linkDiv; } /** * Updates all tabs to have content matching the given node. * @param node */ updateTabs(node) { this.clearTabContentPages(); for (const link of node.links) { const target = link.source == node ? link.target : link.source; const reference = this.createReference(target); this.tabContentPages[link.type].appendChild(reference); } } }