241 lines
6.5 KiB
JavaScript
241 lines
6.5 KiB
JavaScript
/**
|
|
* Mindmap Interaction Enhancement
|
|
* Verbessert die Interaktion mit der Mindmap und steuert die Seitenleisten-Anzeige
|
|
*/
|
|
|
|
// Globale Variablen
|
|
let cy;
|
|
let selectedNode = null;
|
|
let isLegendVisible = true;
|
|
|
|
// Initialisierung der Mindmap
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Cytoscape-Container initialisieren
|
|
cy = cytoscape({
|
|
container: document.getElementById('cy'),
|
|
style: [
|
|
{
|
|
selector: 'node',
|
|
style: {
|
|
'background-color': '#60a5fa',
|
|
'label': 'data(label)',
|
|
'text-valign': 'center',
|
|
'text-halign': 'center',
|
|
'text-wrap': 'wrap',
|
|
'text-max-width': '100px',
|
|
'font-size': '12px',
|
|
'color': '#fff',
|
|
'text-outline-color': '#000',
|
|
'text-outline-width': '2px',
|
|
'width': '40px',
|
|
'height': '40px',
|
|
'border-width': '2px',
|
|
'border-color': '#fff',
|
|
'border-opacity': '0.5',
|
|
'padding': '10px',
|
|
'text-events': 'yes'
|
|
}
|
|
},
|
|
{
|
|
selector: 'edge',
|
|
style: {
|
|
'width': '2px',
|
|
'line-color': 'rgba(255, 255, 255, 0.3)',
|
|
'target-arrow-color': 'rgba(255, 255, 255, 0.3)',
|
|
'target-arrow-shape': 'triangle',
|
|
'curve-style': 'bezier',
|
|
'label': 'data(label)',
|
|
'font-size': '10px',
|
|
'color': '#fff',
|
|
'text-outline-color': '#000',
|
|
'text-outline-width': '2px',
|
|
'text-rotation': 'autorotate'
|
|
}
|
|
},
|
|
{
|
|
selector: ':selected',
|
|
style: {
|
|
'background-color': '#8b5cf6',
|
|
'line-color': '#8b5cf6',
|
|
'target-arrow-color': '#8b5cf6',
|
|
'source-arrow-color': '#8b5cf6',
|
|
'text-outline-color': '#000',
|
|
'text-outline-width': '2px',
|
|
'border-width': '3px',
|
|
'border-color': '#fff',
|
|
'border-opacity': '1'
|
|
}
|
|
},
|
|
{
|
|
selector: '.highlighted',
|
|
style: {
|
|
'background-color': '#10b981',
|
|
'line-color': '#10b981',
|
|
'target-arrow-color': '#10b981',
|
|
'source-arrow-color': '#10b981',
|
|
'transition-property': 'background-color, line-color, target-arrow-color',
|
|
'transition-duration': '0.3s'
|
|
}
|
|
}
|
|
],
|
|
layout: {
|
|
name: 'cose',
|
|
idealEdgeLength: 100,
|
|
nodeOverlap: 20,
|
|
refresh: 20,
|
|
fit: true,
|
|
padding: 30,
|
|
randomize: false,
|
|
componentSpacing: 100,
|
|
nodeRepulsion: 400000,
|
|
edgeElasticity: 100,
|
|
nestingFactor: 5,
|
|
gravity: 80,
|
|
numIter: 1000,
|
|
initialTemp: 200,
|
|
coolingFactor: 0.95,
|
|
minTemp: 1.0
|
|
}
|
|
});
|
|
|
|
// Event-Listener für Knoten
|
|
cy.on('tap', 'node', function(evt) {
|
|
const node = evt.target;
|
|
updateNodeInfo(node);
|
|
highlightConnectedNodes(node);
|
|
});
|
|
|
|
// Event-Listener für Hintergrund-Klick
|
|
cy.on('tap', function(evt) {
|
|
if (evt.target === cy) {
|
|
resetHighlighting();
|
|
hideNodeInfo();
|
|
}
|
|
});
|
|
|
|
// Zoom-Kontrollen
|
|
document.getElementById('zoom-in').addEventListener('click', function() {
|
|
cy.zoom({
|
|
level: cy.zoom() * 1.2,
|
|
renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }
|
|
});
|
|
});
|
|
|
|
document.getElementById('zoom-out').addEventListener('click', function() {
|
|
cy.zoom({
|
|
level: cy.zoom() / 1.2,
|
|
renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }
|
|
});
|
|
});
|
|
|
|
document.getElementById('reset-view').addEventListener('click', function() {
|
|
cy.fit();
|
|
});
|
|
|
|
// Legende ein-/ausblenden
|
|
document.getElementById('toggle-legend').addEventListener('click', function() {
|
|
const legend = document.querySelector('.category-legend');
|
|
isLegendVisible = !isLegendVisible;
|
|
legend.style.display = isLegendVisible ? 'flex' : 'none';
|
|
});
|
|
|
|
// Tastatursteuerung
|
|
document.addEventListener('keydown', function(evt) {
|
|
switch(evt.key) {
|
|
case '+':
|
|
cy.zoom({
|
|
level: cy.zoom() * 1.2,
|
|
renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }
|
|
});
|
|
break;
|
|
case '-':
|
|
cy.zoom({
|
|
level: cy.zoom() / 1.2,
|
|
renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }
|
|
});
|
|
break;
|
|
case 'Escape':
|
|
resetHighlighting();
|
|
hideNodeInfo();
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
|
|
// Knoteninformationen aktualisieren
|
|
function updateNodeInfo(node) {
|
|
const infoPanel = document.getElementById('node-info');
|
|
const infoContent = infoPanel.querySelector('.info-content');
|
|
|
|
// Knotendaten abrufen
|
|
const nodeData = node.data();
|
|
|
|
// Info-Panel aktualisieren
|
|
infoContent.innerHTML = `
|
|
<h4 class="text-lg font-semibold mb-2">${nodeData.label}</h4>
|
|
<p class="mb-3">${nodeData.description || 'Keine Beschreibung verfügbar.'}</p>
|
|
<div class="mt-4">
|
|
<h5 class="text-sm font-semibold mb-2">Verknüpfte Konzepte:</h5>
|
|
<ul class="space-y-1">
|
|
${getConnectedNodesList(node)}
|
|
</ul>
|
|
</div>
|
|
`;
|
|
|
|
// Panel anzeigen
|
|
infoPanel.classList.add('visible');
|
|
}
|
|
|
|
// Verbundene Knoten hervorheben
|
|
function highlightConnectedNodes(node) {
|
|
// Vorherige Hervorhebungen zurücksetzen
|
|
resetHighlighting();
|
|
|
|
// Ausgewählten Knoten hervorheben
|
|
node.addClass('highlighted');
|
|
|
|
// Verbundene Knoten und Kanten hervorheben
|
|
const connectedElements = node.neighborhood();
|
|
connectedElements.addClass('highlighted');
|
|
}
|
|
|
|
// Hervorhebungen zurücksetzen
|
|
function resetHighlighting() {
|
|
cy.elements().removeClass('highlighted');
|
|
}
|
|
|
|
// Info-Panel ausblenden
|
|
function hideNodeInfo() {
|
|
const infoPanel = document.getElementById('node-info');
|
|
infoPanel.classList.remove('visible');
|
|
}
|
|
|
|
// Liste der verbundenen Knoten generieren
|
|
function getConnectedNodesList(node) {
|
|
const connectedNodes = node.neighborhood('node');
|
|
if (connectedNodes.length === 0) {
|
|
return '<li class="text-gray-400">Keine direkten Verbindungen</li>';
|
|
}
|
|
|
|
return connectedNodes.map(connectedNode => {
|
|
const data = connectedNode.data();
|
|
return `
|
|
<li class="flex items-center space-x-2">
|
|
<span class="w-2 h-2 rounded-full" style="background-color: ${getNodeColor(data.category)}"></span>
|
|
<span>${data.label}</span>
|
|
</li>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// Farbe basierend auf Kategorie
|
|
function getNodeColor(category) {
|
|
const colors = {
|
|
'Philosophie': '#60a5fa',
|
|
'Wissenschaft': '#8b5cf6',
|
|
'Technologie': '#10b981',
|
|
'Künste': '#f59e0b',
|
|
'Psychologie': '#ef4444'
|
|
};
|
|
return colors[category] || '#60a5fa';
|
|
}
|