import * as Helpers from "../helpers"; import jQuery from "jquery"; import { createHTMLElement } from "../helpers"; 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, type = "link") { this.graph = graph; this.parentNode = parentNode; this.infoOverlay = infoOverlay; this.type = type; this.tabContentPages = {}; // Page content - links to other nodes this.tabNavHandles = {}; // Top-level handles of the content pages } /** * 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 ); // Create the collapsible of the entire menu const coll = Helpers.createDiv("button", bottomContainerDiv); coll.className = "neighbor-collapsible-title"; coll.innerText = "Verwandte Inhalte"; coll.style.textAlign = "center"; // Div that displays the information about all the chapters const contentTabs = Helpers.createDiv( "neighbor-content-tabs", bottomContainerDiv ); this.contentTab = contentTabs; contentTabs.style.display = "flex"; coll.addEventListener("click", function () { if (contentTabs.style.display === "flex") { jQuery(contentTabs).slideUp("fast"); } else { jQuery(contentTabs).slideDown({ start: function () { jQuery(this).css({ display: "flex", }); }, }); } }); const colors = this.type === "link" ? this.graph.edgeColors : this.graph.nodeColors; for (const [cls, color] of Object.entries(colors)) { this.createCollapsibleTab(contentTabs, cls, color); } } /** * Creates a new collapsible tab for a node with type name and a given color. * @param {HTMLElement} parent Parent of the new tab. * @param {string} name Name of the node type class * @param {string} color Color of the node type class */ createCollapsibleTab(parent, name, color) { // Creating the collapsible tabs for the different chapters const collTab = Helpers.createDiv("button", parent); collTab.className = "neighbor-collapsible-section"; collTab.innerText = name; collTab.type = name; this.tabNavHandles[name] = collTab; const collTabMarker = Helpers.createDiv( "neighbor-collapsible-marker-div", collTab ); collTabMarker.style.borderColor = color; collTabMarker.style.backgroundColor = color; const openMarkerTabs = Helpers.createDiv( "neighbor-tab-open-status-marker", collTab ); openMarkerTabs.innerText = "+"; collTab.marker = openMarkerTabs; // Content of the different tabs const collTabContent = Helpers.createDiv( "neighbor-content-linksection", parent ); collTabContent.type = name; const list = createHTMLElement("ul", collTabContent); list.style.margin = 0; collTabContent.list = list; this.tabContentPages[name] = collTabContent; collTabContent.marker = openMarkerTabs; collTab.addEventListener("click", function () { if (collTabContent.style.display === "flex") { jQuery(collTabContent).slideUp("fast"); openMarkerTabs.innerText = "+"; } else { jQuery(collTabContent).slideDown({ start: function () { jQuery(this).css({ display: "flex" }); }, }); openMarkerTabs.innerText = "-"; } }); } /** * Clears the images from all tab content pages and makes the object * invisible. */ clearTabContentPages() { for (const page of Object.values(this.tabContentPages)) { jQuery(page.list).empty(); /*if(page.style.display === "flex") { page.style.display = "none"; }*/ } } /** * Creates a new image (with link) for the given target node. * @param target * @returns {HTMLDivElement} */ createReference(target) { const linkDiv = document.createElement("li"); var linkText = document.createTextNode(target.name); linkDiv.className = "neighbor-content-link"; linkDiv.appendChild(linkText); 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); if (this.type === "link") { this.tabContentPages[link.type].list.appendChild(reference); } else { this.tabContentPages[target.type].list.appendChild(reference); } } this.hideContentPages(); } /** * Hides all the categories of a node that are not represented by a link * to another neighbor. */ hideContentPages() { for (const page of Object.values(this.tabContentPages)) { if (!page.list.hasChildNodes()) { this.tabNavHandles[page.type].style.display = "none"; } else { this.tabNavHandles[page.type].style.display = "flex"; if (this.tabContentPages[page.type].style.display === "flex") { this.tabNavHandles[page.type].marker.innerText = "-"; } else { this.tabNavHandles[page.type].marker.innerText = "+"; } } } } /** * Toggle the visibility for a node type * @param {string} type The name of the type that should be toggled */ toggleCategory(type) { const page = this.tabContentPages[type]; if (this.tabNavHandles[page.type].style.display === "flex") { this.tabNavHandles[page.type].style.display = "none"; const collTabContent = this.tabContentPages[page.type]; jQuery(collTabContent).slideUp("fast"); collTabContent.marker.innerText = "+"; } else { if (page.list.hasChildNodes()) { this.tabNavHandles[page.type].style.display = "flex"; if (this.tabContentPages[page.type].style.display === "flex") { this.tabNavHandles[page.type].marker.innerText = "-"; } else { this.tabNavHandles[page.type].marker.innerText = "+"; } } } } }