Skip to content
Snippets Groups Projects
Commit 6f500f39 authored by Matthias Konitzny's avatar Matthias Konitzny :fire:
Browse files

Started refactoring the graph.js file into multiple classes.

parent 7352f2cc
No related branches found
No related tags found
No related merge requests found
backgrounds/background_4.jpg

173 KiB

const colorPallette = ['rgb(104, 169, 77)', 'rgb(102, 75, 154)', 'rgb(41, 171, 226)', 'rgb(224, 133, 35)',
'rgb(214, 207, 126)', 'rgb(239, 65, 35)', 'rgb(255, 255, 255)'];
const edgeColors = {};
var graph_element = document.getElementById('3d-graph');
class Graph {
constructor(dataUrl) {
this.graph = null;
this.highlightNodes = new Set();
this.highlightLinks = new Set();
this.hoverNode = null;
this.firstTick = true;
this.infooverlay = null;
this.loadGraph(dataUrl);
}
async loadGraph(dataUrl) {
const gData = await fetch(dataUrl).then(res => res.json())
this.graph = ForceGraph3D({extraRenderers: [new THREE.CSS2DRenderer(), new THREE.CSS3DRenderer()]})
(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.nodeAutoColorBy('group')
.nodeColor(node => this.getNodeColor(node))
.linkWidth(link => this.getLinkWidth(link))
.onNodeClick(node => {
this.focusOnNode(node);
this.infooverlay.updateInfoOverlay(node);
})
.onNodeHover(node => {
this.onNodeHover(node);
this.updateHighlight();
})
.onLinkHover(link => this.onLinkHover(link))
.linkColor(link => this.getLinkColor(link))
.linkOpacity(0.8)
.nodeThreeObjectExtend(false)
.nodeThreeObject(node => this.drawNode(node))
.onEngineTick(() => this.initializeModel())
.width(getWidth())
.height(getHeight());
}
getNodeColor(node) {
return this.highlightNodes.has(node) ? node === hoverNode ? 'rgb(255,0,0,1)' : 'rgba(255,160,0,0.8)' : 'rgba(0,255,255,0.6)';
}
getLinkColor(link) {
if ('type' in link) {
return edgeColors[link.type]
}
return 'rgb(255, 255, 255)'
}
getLinkWidth(link) {
return this.highlightLinks.has(link) ? 2 : 0.8;
}
onNodeHover(node) {
// no state change
if ((!node && !this.highlightNodes.size) || (node && this.hoverNode === node)) return;
this.highlightNodes.clear();
this.highlightLinks.clear();
if (node) {
this.highlightNodes.add(node);
node.neighbors.forEach(neighbor => this.highlightNodes.add(neighbor));
node.links.forEach(link => this.highlightLinks.add(link));
}
this.hoverNode = node || null;
}
onLinkHover(link) {
this.highlightNodes.clear();
this.highlightLinks.clear();
if (link) {
this.highlightLinks.add(link);
this.highlightNodes.add(link.source);
this.highlightNodes.add(link.target);
}
this.updateHighlight();
}
getLinkClasses() {
const linkClasses = [];
this.graph.graphData().links.forEach(link => linkClasses.push(link.type));
return [... new Set(linkClasses)];
}
mapEdgeColors() {
const linkClasses = this.getLinkClasses()
for (let i = 0; i < linkClasses.length; i++) {
edgeColors[linkClasses[i]] = colorPallette[i % colorPallette.length]
}
}
updateLinks() {
const gData = this.graph.graphData()
// cross-link node objects
gData.links.forEach(link => {
const a = link.source;
const b = link.target;
if (!a.neighbors) a.neighbors = [];
if (!b.neighbors) b.neighbors = [];
a.neighbors.push(b);
b.neighbors.push(a);
if (!a.links) a.links = [];
if (!b.links) b.links = [];
a.links.push(link);
b.links.push(link);
});
this.graph.graphData(gData)
}
updateHighlight() {
// trigger update of highlighted objects in scene
this.graph
.nodeColor(this.graph.nodeColor())
.linkWidth(this.graph.linkWidth())
.linkDirectionalParticles(this.graph.linkDirectionalParticles());
}
addBackground() {
const sphereGeometry = new THREE.SphereGeometry(20000, 32, 32);
//const planeGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
const loader = new THREE.TextureLoader();
//const planeMaterial = new THREE.MeshLambertMaterial({color: 0xFF0000, side: THREE.DoubleSide}); //THREE.BackSide
const planeMaterial = new THREE.MeshBasicMaterial({map: loader.load(plugin_path + 'backgrounds/background_4.jpg'), side: THREE.DoubleSide}); //THREE.BackSide
const mesh = new THREE.Mesh(sphereGeometry, planeMaterial);
mesh.position.set(0, 0, 0);
//mesh.rotation.set(0.5 * Math.PI, 0, 0);
this.graph.scene().add(mesh);
}
focusOnNode(node) {
// Aim at node from outside it
const distance = 250;
const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z);
this.graph.cameraPosition(
{ x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }, // new position
node, // lookAt ({ x, y, z })
1000 // ms transition duration
);
}
focusOnNodeId(id) {
const gData = this.graph.graphData();
gData.nodes.forEach(node => {
if (node.id === id) {
this.onNodeClick(node);
}
})
}
resizeGraph() {
this.graph.width(getWidth());
this.graph.height(getHeight());
}
initializeModel() {
if (this.firstTick) {
this.mapEdgeColors();
this.updateLinks();
this.addBackground();
loadComponents();
this.firstTick = false;
}
}
drawNode(node) {
// Draw node as label + image
const nodeDiv = document.createElement('div');
const group = new THREE.Group();
const labelDiv = document.createElement('div')
labelDiv.textContent = node.name;
labelDiv.style.color = node.color;
labelDiv.className = 'node-label';
nodeDiv.appendChild(labelDiv);
const cssobj = new THREE.CSS3DSprite(nodeDiv);
cssobj.scale.set(0.25, 0.25, 0.25);
cssobj.position.set(0, -6, 0);
group.add(cssobj)
// Draw node circle image
const textureLoader = new THREE.TextureLoader();
const imageAlpha = textureLoader.load(plugin_path + 'datasets/images/alpha.png');
let imageTexture = null;
if ('image' in node) {
imageTexture = textureLoader.load(plugin_path + 'datasets/images/' + node.image);
} else {
imageTexture = textureLoader.load(plugin_path + 'datasets/images/default.jpg');
}
const material = new THREE.SpriteMaterial({map: imageTexture, alphaMap: imageAlpha, transparent: true,
alphaTest: 0.2, depthWrite:false, depthTest: false});
const sprite = new THREE.Sprite(material);
sprite.renderOrder = 999; // This may not be optimal. But it allows us to render the sprite on top of everything else.
if ('image' in node) {
sprite.scale.set(20, 20);
} else {
sprite.scale.set(5, 5);
}
group.add(sprite)
return group;
}
}
const dataUrl = plugin_path + 'datasets/aud1.json'
G = new Graph(dataUrl);
linkoverlay = new LinkOverlay(G);
infooverlay = new InfoOverlay();
G.infooverlay = infooverlay;
function loadComponents() {
linkoverlay.create();
infooverlay.create();
add_fullscreen_mode_button();
add_fullscreen_Listener();
window.onresize = G.resizeGraph();
}
function getWidth() {
return document.getElementById('3d-graph').offsetWidth;
}
function getHeight() {
return window.innerHeight - 200
}
function getCanvasDivNode() {
const domNode = document.getElementById('3d-graph');
return domNode.firstChild.firstChild.firstChild;
}
function add_fullscreen_mode_button() {
const sceneNode = document.getElementById('3d-graph');
const overlayNode = document.createElement('button');
overlayNode.className = 'fullscreen_button';
overlayNode.innerText = 'fullscreen';
overlayNode.addEventListener("click", fullscreen_mode);
sceneNode.appendChild(overlayNode);
}
function fullscreen_mode(){
if(getCanvasDivNode().requestFullscreen) {
getCanvasDivNode().requestFullscreen().catch();
}
}
function resize_canvas() {
if(document.fullscreenElement == getCanvasDivNode()) {
G.graph.height(screen.height);
G.graph.width(screen.width);
} else {
G.graph.height(window.innerHeight - 200);
G.graph.width(getWidth());
}
}
function add_fullscreen_Listener() {
getCanvasDivNode().addEventListener("fullscreenchange", resize_canvas);
}
class InfoOverlay {
constructor() {
}
create() {
const sceneNode = getCanvasDivNode();
const overlayNode = document.createElement('div');
overlayNode.id = 'infoOverlay'
overlayNode.className = 'detail-view';
//overlayNode.innerText = 'Hello there!';
sceneNode.insertBefore(overlayNode, sceneNode.childNodes[2]);
const close = document.createElement('div');
close.innerHTML = '<p>&#10006;</p>';
close.id = 'infoOverlayCloseButton';
close.className = 'close-button';
overlayNode.appendChild(close);
const topArea = document.createElement('div');
topArea.className = 'detail-view-top-area';
overlayNode.appendChild(topArea);
const nodeImage = document.createElement('img');
nodeImage.id = 'infoOverlayImage';
nodeImage.src = plugin_path + 'datasets/images/default.jpg';
nodeImage.className = 'detail-view-image';
topArea.appendChild(nodeImage);
const headline = document.createElement('h2');
headline.id = 'infoOverlayHeadline';
headline.innerText = 'Default Text';
headline.className = 'detail-view-headline';
topArea.appendChild(headline);
const textArea = document.createElement('div');
textArea.className = 'detail-view-text-area';
overlayNode.appendChild(textArea);
const description = document.createElement('p');
description.id = 'infoOverlayDescription';
description.innerText = 'Default Text'
description.setAttribute("overflow-y", "scroll");
textArea.appendChild(description);
const link_container = document.createElement('div');
const links = document.createElement('div');
const linkClasses = G.getLinkClasses();
link_container.id = 'link_container';
link_container.className = 'bottom container';
links.className = 'tab';
links.id = 'links';
for(let i = 0; i < linkClasses.length; i++){
const linkType = linkClasses[i];
const tablink = document.createElement('button');
tablink.className = 'tablinks';
tablink.id = linkType + "_id";
tablink.innerHTML = linkType[0] + linkType[1] + linkType[2];
tablink.style = "background-color: " + edgeColors[linkClasses[i]];
tablink.setAttribute("onclick", "openTab(event, " + linkType + "_id)"); //unusual function call
links.appendChild(tablink);
}
link_container.appendChild(links);
for(let i = 0; i < linkClasses.length; i++){
const linkType = linkClasses[i];
const tabcontent = document.createElement('div');
tabcontent.className = "tabcontent";
tabcontent.id = linkType + "_id_content";
tabcontent.style = "background-color: " + edgeColors[linkClasses[i]];
link_container.appendChild(tabcontent);
}
overlayNode.appendChild(link_container);
jQuery('#infoOverlayCloseButton').click(function () {
jQuery('#infoOverlay').slideUp('fast');
});
//sceneNode.appendChild(overlayNode);
}
updateInfoOverlay(node) {
jQuery('#infoOverlayHeadline').text(node.name);
if ('image' in node) {
jQuery('#infoOverlayImage').attr('src', plugin_path + 'datasets/images/' + node.image);
} else {
jQuery('#infoOverlayImage').attr('src', plugin_path + 'datasets/images/default.jpg');
}
if ('description' in node) {
jQuery('#infoOverlayDescription').text(node.description);
} else {
jQuery('#infoOverlayDescription').text('Default Text');
}
this.updateTabs(node);
jQuery('#infoOverlay').slideDown('fast');
}
updateTabs(node){
//tabs of the links to other nodes:
//delete old nodes from tabcontent
const tabcontent = document.getElementsByClassName("tabcontent");
for (let i = 0; i < tabcontent.length; i++) {
while (tabcontent[i].firstChild){
tabcontent[i].removeChild(tabcontent[i].lastChild);
}
}
//add new nodes to tabcontent
for (let i = 0; i < tabcontent.length; i++) { //for every type of link
node.links.forEach(link => { //and for every link
if(link.type + '_id_content' == tabcontent[i].id){ //is checked if the type is equal
const linkButton = document.createElement('div'); //and if so a new element is created
linkButton.className = "link img";
var node2;
if(link.source == node){
node2 = link.target;
}
else if(link.target == node){
node2 = link.source;
}
linkButton.id = "linkButton_" + node2.id;
const nodeID = node2.id;
const linkImage = document.createElement('img');
const linkTitle = document.createElement('div');
if ('image' in node2) {
linkImage.src = plugin_path + 'datasets/images/' + node2.image;
} else if(!('image' in node2) && ('id' in node2)) {
linkImage.src = plugin_path + 'datasets/images/default.jpg';
}
linkTitle.className = "link title";
linkTitle.innerHTML = node2.name;
//linkButton.appendChild(linkTitle);
linkButton.appendChild(linkImage);
linkButton.addEventListener('click', function (){focusOnNodeId(nodeID)});
tabcontent[i].appendChild(linkButton);
}
});
}
}
}
//is used in createInfoOverlay, as an unusual function call to open link-tabs
function openTab (event, tab) {
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(tab.id + "_content").style.display = "flex";
event.currentTarget.className += " active";
}
\ No newline at end of file
class LinkOverlay {
constructor(graph) {
this.graph = graph
}
create() {
const sceneNode = getCanvasDivNode();
const overlayNode = document.createElement('div');
overlayNode.className = 'link-overlay';
//overlayNode.innerText = 'Hello there!';
sceneNode.insertBefore(overlayNode, sceneNode.childNodes[2])
const linkClasses = this.graph.getLinkClasses();
const chars = Math.max.apply(Math, linkClasses.map(function (c) { return c.length; }));
for (let i=0; i<linkClasses.length; i++) {
const relation = document.createElement('div');
relation.className = 'relation';
relation.innerHTML = "<p>" + linkClasses[i] + "</p>";
overlayNode.appendChild(relation);
const colorStrip = document.createElement('div');
colorStrip.className = 'rel-container';
colorStrip.style = "background-color: " + edgeColors[linkClasses[i]] + "; width: " + 10 * chars + "px;";
relation.appendChild(colorStrip);
}
}
}
\ No newline at end of file
const highlightNodes = new Set();
const highlightLinks = new Set();
let hoverNode = null;
let Graph = null;
let firstTick = true;
const colorPallette = ['rgb(104, 169, 77)', 'rgb(102, 75, 154)', 'rgb(41, 171, 226)', 'rgb(224, 133, 35)',
'rgb(214, 207, 126)', 'rgb(239, 65, 35)', 'rgb(255, 255, 255)'];
const edgeColors = {};
var graph_element = document.getElementById('3d-graph');
loadGraph();
async function loadGraph() {
const dataUrl = plugin_path + 'datasets/aud1.json'
const gData = await fetch(dataUrl).then(res => res.json())
Graph = ForceGraph3D({extraRenderers: [new THREE.CSS2DRenderer(), new THREE.CSS3DRenderer()]})
(document.getElementById('3d-graph'))
.graphData(gData)
.nodeLabel('id')
.nodeAutoColorBy('group')
.nodeColor(node => highlightNodes.has(node) ? node === hoverNode ? 'rgb(255,0,0,1)' : 'rgba(255,160,0,0.8)' : 'rgba(0,255,255,0.6)')
.linkWidth(link => highlightLinks.has(link) ? 2 : 0.8)
.onNodeClick(handleNodeClick)
.onNodeHover(nodeHover)
.onLinkHover(linkHover)
.linkColor(linkColor)
.linkOpacity(0.8)
.nodeThreeObjectExtend(false)
.nodeThreeObject(drawNode)
.onEngineTick(loadComponents)
.width(getWidth())
.height(getHeight());
//Graph.renderer().sortObjects = true;
}
function loadComponents() {
if (firstTick) {
mapEdgeColors();
updateLinks();
add_background();
createLinkOverlay();
createInfoOverlay();
add_fullscreen_mode_button();
add_fullscreen_Listener();
window.onresize = resize_graph();
firstTick = false;
}
}
function resize_graph() {
Graph.width(getWidth());
Graph.height(getHeight());
}
function getWidth() {
return document.getElementById('3d-graph').offsetWidth;
}
function getHeight() {
return window.innerHeight - 200
}
function mapEdgeColors() {
const linkClasses = getLinkClasses()
for (let i = 0; i < linkClasses.length; i++) {
edgeColors[linkClasses[i]] = colorPallette[i % colorPallette.length]
}
}
function getLinkClasses() {
const linkClasses = [];
Graph.graphData().links.forEach(link => linkClasses.push(link.type));
return [... new Set(linkClasses)];
}
function getCanvasDivNode() {
const domNode = document.getElementById('3d-graph');
return domNode.firstChild.firstChild.firstChild;
}
function drawNode(node) {
// Draw node as label + image
const nodeDiv = document.createElement('div');
group = new THREE.Group();
const labelDiv = document.createElement('div')
labelDiv.textContent = node.name;
labelDiv.style.color = node.color;
labelDiv.className = 'node-label';
nodeDiv.appendChild(labelDiv);
const cssobj = new THREE.CSS3DSprite(nodeDiv);
cssobj.scale.set(0.25, 0.25, 0.25);
cssobj.position.set(0, -6, 0);
group.add(cssobj)
// Draw node circle image
const textureLoader = new THREE.TextureLoader();
const imageAlpha = textureLoader.load(plugin_path + 'datasets/images/alpha.png');
let imageTexture = null;
if ('image' in node) {
imageTexture = textureLoader.load(plugin_path + 'datasets/images/' + node.image);
} else {
imageTexture = textureLoader.load(plugin_path + 'datasets/images/default.jpg');
}
const material = new THREE.SpriteMaterial({map: imageTexture, alphaMap: imageAlpha, transparent: true,
alphaTest: 0.2, depthWrite:false, depthTest: false});
const sprite = new THREE.Sprite(material);
sprite.renderOrder = 999; // This may not be optimal. But it allows us to render the sprite on top of everything else.
if ('image' in node) {
sprite.scale.set(20, 20);
} else {
sprite.scale.set(5, 5);
}
group.add(sprite)
return group;
}
function createInfoOverlay() {
const sceneNode = getCanvasDivNode();
const overlayNode = document.createElement('div');
overlayNode.id = 'infoOverlay'
overlayNode.className = 'detail-view';
//overlayNode.innerText = 'Hello there!';
sceneNode.insertBefore(overlayNode, sceneNode.childNodes[2]);
const close = document.createElement('div');
close.innerHTML = '<p>&#10006;</p>';
close.id = 'infoOverlayCloseButton';
close.className = 'close-button';
overlayNode.appendChild(close);
const topArea = document.createElement('div');
topArea.className = 'detail-view-top-area';
overlayNode.appendChild(topArea);
const nodeImage = document.createElement('img');
nodeImage.id = 'infoOverlayImage';
nodeImage.src = plugin_path + 'datasets/images/default.jpg';
nodeImage.className = 'detail-view-image';
topArea.appendChild(nodeImage);
const headline = document.createElement('h2');
headline.id = 'infoOverlayHeadline';
headline.innerText = 'Default Text';
headline.className = 'detail-view-headline';
topArea.appendChild(headline);
const textArea = document.createElement('div');
textArea.className = 'detail-view-text-area';
overlayNode.appendChild(textArea);
const description = document.createElement('p');
description.id = 'infoOverlayDescription';
description.innerText = 'Default Text'
description.setAttribute("overflow-y", "scroll");
textArea.appendChild(description);
const link_container = document.createElement('div');
const links = document.createElement('div');
const linkClasses = getLinkClasses();
link_container.id = 'link_container';
link_container.className = 'bottom container';
links.className = 'tab';
links.id = 'links';
for(i = 0; i < linkClasses.length; i++){
const linkType = linkClasses[i];
const tablink = document.createElement('button');
tablink.className = 'tablinks';
tablink.id = linkType + "_id";
tablink.innerHTML = linkType[0] + linkType[1] + linkType[2];
tablink.style = "background-color: " + edgeColors[linkClasses[i]];
tablink.setAttribute("onclick", "openTab(event, " + linkType + "_id)"); //unusual function call
links.appendChild(tablink);
}
link_container.appendChild(links);
for(i = 0; i < linkClasses.length; i++){
const linkType = linkClasses[i];
const tabcontent = document.createElement('div');
tabcontent.className = "tabcontent";
tabcontent.id = linkType + "_id_content";
tabcontent.style = "background-color: " + edgeColors[linkClasses[i]];
link_container.appendChild(tabcontent);
}
overlayNode.appendChild(link_container);
jQuery('#infoOverlayCloseButton').click(function () {
jQuery('#infoOverlay').slideUp('fast');
});
//sceneNode.appendChild(overlayNode);
}
function createLinkOverlay() {
const sceneNode = getCanvasDivNode();
const overlayNode = document.createElement('div');
overlayNode.className = 'link-overlay';
//overlayNode.innerText = 'Hello there!';
sceneNode.insertBefore(overlayNode, sceneNode.childNodes[2])
const linkClasses = getLinkClasses();
const chars = Math.max.apply(Math, linkClasses.map(function (c) { return c.length; }));
for (let i=0; i<linkClasses.length; i++) {
const relation = document.createElement('div');
relation.className = 'relation';
relation.innerHTML = "<p>" + linkClasses[i] + "</p>";
overlayNode.appendChild(relation);
const colorStrip = document.createElement('div');
colorStrip.className = 'rel-container';
colorStrip.style = "background-color: " + edgeColors[linkClasses[i]] + "; width: " + 10 * chars + "px;";
relation.appendChild(colorStrip);
}
}
function add_fullscreen_mode_button() {
const sceneNode = document.getElementById('3d-graph');
const overlayNode = document.createElement('button');
overlayNode.className = 'fullscreen_button';
overlayNode.innerText = 'fullscreen';
overlayNode.addEventListener("click", fullscreen_mode);
sceneNode.appendChild(overlayNode);
}
function fullscreen_mode(){
if(getCanvasDivNode().requestFullscreen) {
getCanvasDivNode().requestFullscreen().catch();
}
}
function resize_canvas() {
if(document.fullscreenElement == getCanvasDivNode()) {
Graph.height(screen.height);
Graph.width(screen.width);
} else {
Graph.height(window.innerHeight - 200);
Graph.width(getWidth());
}
}
function add_fullscreen_Listener() {
getCanvasDivNode().addEventListener("fullscreenchange", resize_canvas);
}
function add_background() {
const sphereGeometry = new THREE.SphereGeometry(20000, 32, 32);
//const planeGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
const loader = new THREE.TextureLoader();
//const planeMaterial = new THREE.MeshLambertMaterial({color: 0xFF0000, side: THREE.DoubleSide}); //THREE.BackSide
const planeMaterial = new THREE.MeshBasicMaterial({map: loader.load(plugin_path + 'backgrounds/background_3.jpg'), side: THREE.DoubleSide}); //THREE.BackSide
const mesh = new THREE.Mesh(sphereGeometry, planeMaterial);
mesh.position.set(0, 0, 0);
//mesh.rotation.set(0.5 * Math.PI, 0, 0);
Graph.scene().add(mesh);
}
function updateLinks() {
const gData = Graph.graphData()
// cross-link node objects
gData.links.forEach(link => {
const a = link.source;
const b = link.target;
if (!a.neighbors) a.neighbors = [];
if (!b.neighbors) b.neighbors = [];
a.neighbors.push(b);
b.neighbors.push(a);
if (!a.links) a.links = [];
if (!b.links) b.links = [];
a.links.push(link);
b.links.push(link);
});
Graph.graphData(gData)
}
function handleNodeClick(node) {
focusOnNode(node);
updateInfoOverlay(node);
}
function updateInfoOverlay(node) {
jQuery('#infoOverlayHeadline').text(node.name);
if ('image' in node) {
jQuery('#infoOverlayImage').attr('src', plugin_path + 'datasets/images/' + node.image);
} else {
jQuery('#infoOverlayImage').attr('src', plugin_path + 'datasets/images/default.jpg');
}
if ('description' in node) {
jQuery('#infoOverlayDescription').text(node.description);
} else {
jQuery('#infoOverlayDescription').text('Default Text');
}
updateTabs(node);
jQuery('#infoOverlay').slideDown('fast');
}
function updateTabs(node){
//tabs of the links to other nodes:
//delete old nodes from tabcontent
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
while (tabcontent[i].firstChild){
tabcontent[i].removeChild(tabcontent[i].lastChild);
}
}
//add new nodes to tabcontent
for (i = 0; i < tabcontent.length; i++) { //for every type of link
node.links.forEach(link => { //and for every link
if(link.type + '_id_content' == tabcontent[i].id){ //is checked if the type is equal
const linkButton = document.createElement('div'); //and if so a new element is created
linkButton.className = "link img";
var node2;
if(link.source == node){
node2 = link.target;
}
else if(link.target == node){
node2 = link.source;
}
linkButton.id = "linkButton_" + node2.id;
const nodeID = node2.id;
const linkImage = document.createElement('img');
const linkTitle = document.createElement('div');
if ('image' in node2) {
linkImage.src = plugin_path + 'datasets/images/' + node2.image;
} else if(!('image' in node2) && ('id' in node2)) {
linkImage.src = plugin_path + 'datasets/images/default.jpg';
}
linkTitle.className = "link title";
linkTitle.innerHTML = node2.name;
//linkButton.appendChild(linkTitle);
linkButton.appendChild(linkImage);
linkButton.addEventListener('click', function (){focusOnNodeId(nodeID)});
tabcontent[i].appendChild(linkButton);
}
});
}
}
function focusOnNodeId(id) {
const gData = Graph.graphData();
gData.nodes.forEach(node => {
if (node.id === id) {
handleNodeClick(node);
}
})
}
function focusOnNode(node) {
// Aim at node from outside it
const distance = 250;
const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z);
Graph.cameraPosition(
{ x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }, // new position
node, // lookAt ({ x, y, z })
1000 // ms transition duration
);
}
function nodeHover(node) {
// no state change
if ((!node && !highlightNodes.size) || (node && hoverNode === node)) return;
highlightNodes.clear();
highlightLinks.clear();
if (node) {
highlightNodes.add(node);
node.neighbors.forEach(neighbor => highlightNodes.add(neighbor));
node.links.forEach(link => highlightLinks.add(link));
}
hoverNode = node || null;
updateHighlight();
}
function linkHover(link) {
highlightNodes.clear();
highlightLinks.clear();
if (link) {
highlightLinks.add(link);
highlightNodes.add(link.source);
highlightNodes.add(link.target);
}
updateHighlight();
}
function linkColor(link) {
if ('type' in link) {
return edgeColors[link.type]
}
return 'rgb(255, 255, 255)'
}
function updateHighlight() {
// trigger update of highlighted objects in scene
Graph
.nodeColor(Graph.nodeColor())
.linkWidth(Graph.linkWidth())
.linkDirectionalParticles(Graph.linkDirectionalParticles());
}
//is used in createInfoOverlay, as an unusual function call to open link-tabs
function openTab (event, tab) {
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(tab.id + "_content").style.display = "flex";
event.currentTarget.className += " active";
}
\ No newline at end of file
...@@ -19,10 +19,16 @@ function ks_add_graph(): string ...@@ -19,10 +19,16 @@ function ks_add_graph(): string
$variables = "<script> $variables = "<script>
var plugin_path = '$plugin_dir'; var plugin_path = '$plugin_dir';
</script>"; </script>";
$script_path = $plugin_dir.'graph.js'; $script_path1 = $plugin_dir.'display'.DIRECTORY_SEPARATOR.'infooverlay.js';
$script = "<script src='$script_path'></script>"; $script_path2 = $plugin_dir.'display'.DIRECTORY_SEPARATOR.'linkoverlay.js';
$script_path3 = $plugin_dir.'display'.DIRECTORY_SEPARATOR.'graph.js';
return $three . $renderer .$renderer2 . $graph . $div . $variables . $script; $script1 = "<script src='$script_path1'></script>";
$script2 = "<script src='$script_path2'></script>";
$script3 = "<script src='$script_path3'></script>";
return $three . $renderer .$renderer2 . $graph . $div . $variables . $script1 . $script2 .$script3;
} }
function ks_add_editor(): string function ks_add_editor(): string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment