Newer
Older
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.
*/

Matthias Konitzny
committed
constructor(graph, parentNode, infoOverlay, type = "link") {
this.graph = graph;
this.parentNode = parentNode;
this.infoOverlay = infoOverlay;

Matthias Konitzny
committed
this.type = type;
this.activeTabNav = null; // The currently selected tab handle
this.activeTabContent = null; // The currently selected tab content

Matthias Konitzny
committed
this.tabNavHandles = {};
/**
* 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
);

Matthias Konitzny
committed
const colors =
this.type === "link"
? this.graph.edgeColors
: this.graph.nodeColors;
for (const [cls, color] of Object.entries(colors)) {
const navTab = Helpers.createDiv(
"bottom-container-nav-tab",
bottomContainerNavDiv
);
navTab.innerText = cls.slice(0, 3);
navTab.style.backgroundColor = color;

Matthias Konitzny
committed
navTab.type = cls; // Attach the edge type to the DOM object to retrieve it during click events
jQuery(navTab).click((event) => this.openTabFromEvent(event));
this.tabNavHandles[cls] = navTab;
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");

Matthias Konitzny
committed
this.activeTabNav.innerText = this.activeTabNav.type;
}
/**
* Click event handler for the tab headers of the bottom menu.
* @param event
*/

Matthias Konitzny
committed
openTabFromEvent(event) {

Matthias Konitzny
committed
const cls = navTab.type;
this.openTab(cls);
}

Matthias Konitzny
committed
openTab(cls) {
this.activeTabNav.classList.remove("active-tab-nav");
this.activeTabNav.innerText = this.activeTabNav.innerText.slice(0, 3);

Matthias Konitzny
committed
this.tabNavHandles[cls].classList.add("active-tab-nav");
this.tabNavHandles[cls].innerText = cls;
this.activeTabContent.classList.remove("active-tab-content");
this.tabContentPages[cls].classList.add("active-tab-content");

Matthias Konitzny
committed
this.activeTabNav = this.tabNavHandles[cls];
this.activeTabContent = this.tabContentPages[cls];
}

Matthias Konitzny
committed
toggleTabVisibility(cls) {
this.tabNavHandles[cls].classList.toggle("bottom-container-nav-tab");
this.tabNavHandles[cls].classList.toggle("hidden-tab");
const tcc = this.tabContentPages[cls].classList;
tcc.toggle("bottom-container-tab-content");
tcc.toggle("hidden-tab");

Matthias Konitzny
committed
// If the tab gets hidden and is the active tab, search for an alternative nav tab to become the new active tab.
if (tcc.contains("hidden-tab")) {
if (tcc.contains("active-tab-nav")) {

Matthias Konitzny
committed
for (const tab of Object.values(this.tabNavHandles)) {
if (!tab.classList.contains("hidden-tab")) {
this.openTab(tab.type);
break;
}
}
}
} else {
// If all tabs are hidden, the new tab should become the active tab.
if (this.activeTabNav.classList.contains("hidden-tab")) {
this.openTab(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);

Matthias Konitzny
committed
if (this.type === "link") {
this.tabContentPages[link.type].appendChild(reference);
} else {
this.tabContentPages[target.type].appendChild(reference);
}