Newer
Older
import * as Helpers from "../helpers";
import { createHTMLElement } from "../helpers";
/**
* 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.contentTab = null;
this.tabContentPages = {}; // Page content - links to other nodes
this.tabNavHandles = {}; // Top-level handles of the content pages
this.tabPageVisibility = {}; // Visibility of each content page
/**
* Creates the visible elements of the overlay.
* Must be called after the graph has been initialized.
*/
create() {
const bottomContainerDiv = Helpers.createDiv(
bottomContainerDiv.classList.add("fancy-scrollbar");
const coll = Helpers.createDiv("button", bottomContainerDiv);
coll.className = "neighbor-collapsible-title";
// Div that displays the information about all the chapters
const contentTab = Helpers.createDiv(
//contentTab.classList.add("neighbor-collapsible-wrapper");
this.contentTab = contentTab;
coll.addEventListener("click", () => {
if (contentTab.style.height === "0px") {
contentTab.style.height = "auto";
contentTab.style.height = "0px";

Matthias Konitzny
committed
const colors =
this.type === "link"
? this.graph.edgeColors
: this.graph.nodeColors;
for (const [cls, color] of Object.entries(colors)) {
this.createCollapsibleTab(contentTab, cls, color);

Matthias Konitzny
committed
}
}
* Creates a new collapsible tab and content area for a specific node.
* @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;
this.tabPageVisibility[name] = false;
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.classList.add("neighbor-collapsible-wrapper");
collTabContent.type = name;
const list = createHTMLElement("ul", collTabContent);
collTabContent.list = list;
this.tabContentPages[name] = collTabContent;
collTab.addEventListener("click", () => {
this.toggleSectionVisibility(name);
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* Toggles the visibility of a specific section
* @param {string} name Id of the section
*/
toggleSectionVisibility(name) {
if (this.tabPageVisibility[name]) {
this.collapseSection(name);
} else {
this.expandSection(name);
}
}
/**
* Collapses the content area of a specific section
* @param {string} name Id of the section
*/
collapseSection(name) {
this.tabPageVisibility[name] = false;
const section = this.tabContentPages[name];
section.style.height = "0px";
section.marker.innerText = "+";
}
/**
* Expands the content area of a specific section
* @param {string} name Id of the section
*/
expandSection(name) {
this.tabPageVisibility[name] = true;
const section = this.tabContentPages[name];
section.style.height = `${section.scrollHeight}px`;
section.marker.innerText = "-";
}
* Clears the images from all tab content pages and makes the object
* invisible.
for (const page of Object.values(this.tabContentPages)) {
page.list.replaceChildren();
* Creates a new list element for the given target node.
const linkDiv = document.createElement("li");
const linkText = document.createTextNode(target.name);
linkDiv.className = "neighbor-content-link";
linkDiv.addEventListener("click", () => {
this.graph.focusOnNode(target);
this.infoOverlay.updateInfoOverlay(target);
});
return linkDiv;
}
/**
* Updates all tabs to have content matching the given node.
* @param node
*/
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].list.appendChild(reference);

Matthias Konitzny
committed
} else {
this.tabContentPages[target.type].list.appendChild(reference);

Matthias Konitzny
committed
}
this.updatePageVisibility();
* Updates the content page visibility on node change.
* Hides all empty content pages.
updatePageVisibility() {
for (const page of Object.values(this.tabContentPages)) {
this.tabNavHandles[page.type].style.display = "none";
page.style.display = "none";
} else {
this.tabNavHandles[page.type].style.display = "flex";
page.style.display = "flex";
if (this.tabPageVisibility[page.type]) {
page.style.height = `${page.list.scrollHeight}px`;
* Toggle the visibility for a category
* @param {string} type The name of the category that should be toggled
const page = this.tabContentPages[type];
const handle = this.tabNavHandles[type];
if (handle.style.display === "flex") {
page.style.display = "none";
handle.style.display = "none";
} else if (page.list.hasChildNodes()) {
page.style.display = "flex";
handle.style.display = "flex";