diff --git a/static/js/mindmap_controls.js b/static/js/mindmap_controls.js
deleted file mode 100644
index bf3271a..0000000
--- a/static/js/mindmap_controls.js
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * Systades Mindmap Steuerung
- * Implementierung der Funktionalitäten für die Mindmap-Kontrollbuttons
- */
-
-document.addEventListener('DOMContentLoaded', function() {
- console.log('Mindmap-Steuerung wird initialisiert...');
-
- // Vergrößern-Funktion (Kontrollpanel)
- const zoomInBtn = document.querySelector('#zoomIn');
- if (zoomInBtn) {
- console.log('Zoom-In Button gefunden');
- zoomInBtn.addEventListener('click', function() {
- vergrößern();
- });
- }
-
- // Verkleinern-Funktion (Kontrollpanel)
- const zoomOutBtn = document.querySelector('#zoomOut');
- if (zoomOutBtn) {
- console.log('Zoom-Out Button gefunden');
- zoomOutBtn.addEventListener('click', function() {
- verkleinern();
- });
- }
-
- // Zurücksetzen-Funktion (Kontrollpanel)
- const resetViewBtn = document.querySelector('#resetView');
- if (resetViewBtn) {
- console.log('Reset-View Button gefunden');
- resetViewBtn.addEventListener('click', function() {
- zurücksetzen();
- });
- }
-
- // Legende-Funktion (Kontrollpanel)
- const toggleLegendBtn = document.querySelector('#toggleLegend');
- if (toggleLegendBtn) {
- console.log('Toggle-Legend Button gefunden');
- toggleLegendBtn.addEventListener('click', function() {
- legendeUmschalten();
- });
- }
-
- // Seitliche Buttons
- const vergrößernBtn = document.querySelector('#vergrößernBtn');
- if (vergrößernBtn) {
- console.log('Vergrößern Button (Seitenleiste) gefunden');
- vergrößernBtn.addEventListener('click', function() {
- vergrößern();
- animateButtonClick(this);
- });
- } else {
- console.warn('Vergrößern Button nicht gefunden');
- }
-
- const verkleinernBtn = document.querySelector('#verkleinernBtn');
- if (verkleinernBtn) {
- console.log('Verkleinern Button (Seitenleiste) gefunden');
- verkleinernBtn.addEventListener('click', function() {
- verkleinern();
- animateButtonClick(this);
- });
- } else {
- console.warn('Verkleinern Button nicht gefunden');
- }
-
- const zurücksetzenBtn = document.querySelector('#zurücksetzenBtn');
- if (zurücksetzenBtn) {
- console.log('Zurücksetzen Button (Seitenleiste) gefunden');
- zurücksetzenBtn.addEventListener('click', function() {
- zurücksetzen();
- animateButtonClick(this);
- });
- } else {
- console.warn('Zurücksetzen Button nicht gefunden');
- }
-});
-
-/**
- * Vergrößert die aktuelle Mindmap-Ansicht
- */
-function vergrößern() {
- console.log('Vergrößern-Funktion aufgerufen');
- if (window.cy) {
- const aktuellerZoom = window.cy.zoom();
- window.cy.zoom({
- level: aktuellerZoom * 1.2,
- renderedPosition: { x: window.innerWidth / 2, y: window.innerHeight / 2 }
- });
- console.log('Vergrößerung: Neuer Zoom-Level:', window.cy.zoom());
- } else {
- console.error('Cytoscape-Instanz nicht verfügbar');
- }
-}
-
-/**
- * Verkleinert die aktuelle Mindmap-Ansicht
- */
-function verkleinern() {
- console.log('Verkleinern-Funktion aufgerufen');
- if (window.cy) {
- const aktuellerZoom = window.cy.zoom();
- window.cy.zoom({
- level: aktuellerZoom * 0.8,
- renderedPosition: { x: window.innerWidth / 2, y: window.innerHeight / 2 }
- });
- console.log('Verkleinerung: Neuer Zoom-Level:', window.cy.zoom());
- } else {
- console.error('Cytoscape-Instanz nicht verfügbar');
- }
-}
-
-/**
- * Setzt die Mindmap-Ansicht zurück, sodass alle Elemente sichtbar sind
- */
-function zurücksetzen() {
- console.log('Zurücksetzen-Funktion aufgerufen');
- if (window.cy) {
- window.cy.fit();
- window.cy.center();
- console.log('Ansicht zurückgesetzt');
-
- // Zeige kurze Bestätigung an
- zeigeFlashNachricht('Ansicht zurückgesetzt', 'info');
- } else {
- console.error('Cytoscape-Instanz nicht verfügbar');
- }
-}
-
-/**
- * Schaltet die Anzeige der Kategorie-Legende um
- */
-function legendeUmschalten() {
- console.log('Legende-Umschalten-Funktion aufgerufen');
- const legende = document.getElementById('categoryLegend');
- if (legende) {
- const neuerZustand = legende.style.display === 'none' || legende.style.display === '' ? 'flex' : 'none';
- legende.style.display = neuerZustand;
- console.log('Legende ist jetzt:', neuerZustand === 'flex' ? 'sichtbar' : 'ausgeblendet');
-
- // Zeige kurze Bestätigung an
- zeigeFlashNachricht(
- neuerZustand === 'flex' ? 'Legende wird angezeigt' : 'Legende ausgeblendet',
- 'info'
- );
- } else {
- console.error('Legende-Element nicht gefunden');
- }
-}
-
-/**
- * Zeigt eine kurze Flash-Nachricht auf dem Bildschirm an
- * @param {string} nachricht - Die anzuzeigende Nachricht
- * @param {string} typ - Der Typ der Nachricht (info, success, warning, error)
- */
-function zeigeFlashNachricht(nachricht, typ = 'info') {
- console.log(`Flash-Nachricht: ${nachricht} (${typ})`);
-
- // Prüfe, ob bereits eine Flash-Nachricht existiert
- let flashElement = document.getElementById('flash-nachricht');
-
- // Falls nicht, erstelle sie
- if (!flashElement) {
- flashElement = document.createElement('div');
- flashElement.id = 'flash-nachricht';
- document.body.appendChild(flashElement);
-
- // Styles für das Flash-Element
- Object.assign(flashElement.style, {
- position: 'fixed',
- bottom: '20px',
- left: '50%',
- transform: 'translateX(-50%)',
- padding: '10px 20px',
- borderRadius: '5px',
- color: 'white',
- fontWeight: 'bold',
- zIndex: '9999',
- opacity: '0',
- transition: 'opacity 0.3s ease-in-out'
- });
- }
-
- // Setze Hintergrundfarbe je nach Typ
- const hintergrundFarben = {
- info: 'rgba(59, 130, 246, 0.9)',
- success: 'rgba(16, 185, 129, 0.9)',
- warning: 'rgba(245, 158, 11, 0.9)',
- error: 'rgba(220, 38, 38, 0.9)'
- };
-
- flashElement.style.backgroundColor = hintergrundFarben[typ] || hintergrundFarben.info;
- flashElement.textContent = nachricht;
-
- // Animiere das Einblenden
- flashElement.style.opacity = '1';
-
- // Ausblenden nach 2 Sekunden
- setTimeout(() => {
- flashElement.style.opacity = '0';
- }, 2000);
-}
-
-/**
- * Animiert einen Button beim Klicken
- * @param {HTMLElement} button - Das Button-Element, das animiert werden soll
- */
-function animateButtonClick(button) {
- // Aktuelle Transformation speichern
- const originalTransform = button.style.transform;
-
- // Animation anwenden
- button.style.transform = 'scale(0.95)';
-
- // Nach kurzer Zeit zurücksetzen
- setTimeout(() => {
- button.style.transform = originalTransform;
- }, 150);
-}
\ No newline at end of file
diff --git a/static/js/update_mindmap.js b/static/js/update_mindmap.js
index 26c88a5..20bbb52 100644
--- a/static/js/update_mindmap.js
+++ b/static/js/update_mindmap.js
@@ -1,58 +1,195 @@
/**
- * Mindmap-Funktionalitäten
- * Diese Datei enthält die grundlegenden Funktionen für die Mindmap-Visualisierung
+ * Update Mindmap
+ * Dieses Skript fügt Knoten zur Mindmap hinzu und stellt sicher,
+ * dass sie im neuronalen Netzwerk-Design angezeigt werden.
+ * Implementiert Lazy Loading & Progressive Disclosure
*/
-// Globale Variable für das Cytoscape-Objekt
-window.cy = null;
+// Neue zentrale Konfiguration
+const mindmapConfig = {
+ categories: {
+ 'Philosophie': {
+ icon: 'fa-solid fa-lightbulb',
+ color: '#b71c1c',
+ description: 'Die Lehre vom Denken und der Erkenntnis'
+ },
+ 'Wissenschaft': {
+ icon: 'fa-solid fa-atom',
+ color: '#f4b400',
+ description: 'Systematische Erforschung der Natur und Gesellschaft'
+ },
+ 'Technologie': {
+ icon: 'fa-solid fa-microchip',
+ color: '#0d47a1',
+ description: 'Anwendung wissenschaftlicher Erkenntnisse'
+ },
+ 'Künste': {
+ icon: 'fa-solid fa-palette',
+ color: '#c2185b',
+ description: 'Kreativer Ausdruck und künstlerische Gestaltung'
+ }
+ },
+ defaultNodeStyle: {
+ fontSize: 18,
+ fontColor: '#fff',
+ neuronSize: 8,
+ neuronActivity: 0.8
+ },
+ centerNodeStyle: {
+ fontSize: 22,
+ fontColor: '#222',
+ neuronSize: 12,
+ neuronActivity: 1.0,
+ color: '#f5f5f5',
+ icon: 'fa-solid fa-circle'
+ }
+};
-/**
- * Initialisiert die Mindmap mit Standarddaten
- */
-async function initializeMindmap() {
- console.log('Initialisiere Mindmap...');
-
- // Beispieldaten für die Mindmap (falls keine API-Daten verfügbar sind)
- const fallbackData = {
- nodes: [
- { id: 'wissen', name: 'Wissen', category: 'Zentral', description: 'Zentrum der Wissensdatenbank', has_children: true, is_center: true, color_code: '#f5f5f5' },
- { id: 'philosophie', name: 'Philosophie', category: 'Philosophie', description: 'Philosophisches Denken', has_children: true, is_center: false, color_code: '#9F7AEA' },
- { id: 'wissenschaft', name: 'Wissenschaft', category: 'Wissenschaft', description: 'Wissenschaftliche Erkenntnisse', has_children: true, is_center: false, color_code: '#60A5FA' },
- { id: 'technologie', name: 'Technologie', category: 'Technologie', description: 'Technologische Entwicklungen', has_children: true, is_center: false, color_code: '#10B981' },
- { id: 'kunst', name: 'Künste', category: 'Künste', description: 'Kreative Ausdrucksformen', has_children: true, is_center: false, color_code: '#F59E0B' },
- { id: 'psychologie', name: 'Psychologie', category: 'Psychologie', description: 'Menschliches Verhalten und Geist', has_children: true, is_center: false, color_code: '#EF4444' }
- ],
- edges: [
- { source: 'wissen', target: 'philosophie', strength: 0.8 },
- { source: 'wissen', target: 'wissenschaft', strength: 0.8 },
- { source: 'wissen', target: 'technologie', strength: 0.7 },
- { source: 'wissen', target: 'kunst', strength: 0.6 },
- { source: 'wissen', target: 'psychologie', strength: 0.7 },
- { source: 'wissenschaft', target: 'technologie', strength: 0.9 },
- { source: 'wissenschaft', target: 'philosophie', strength: 0.5 },
- { source: 'philosophie', target: 'psychologie', strength: 0.6 }
- ]
- };
-
+// Zentrale Styling-Konfiguration
+const mindmapStyles = {
+ node: {
+ base: {
+ 'background-color': 'data(color)',
+ 'label': 'data(label)',
+ 'color': '#ffffff',
+ 'text-background-color': 'rgba(0, 0, 0, 0.7)',
+ 'text-background-opacity': 0.8,
+ 'text-background-padding': '4px',
+ 'text-valign': 'center',
+ 'text-halign': 'center',
+ 'font-size': 16,
+ 'width': 40,
+ 'height': 40,
+ 'border-width': 2,
+ 'border-color': '#ffffff',
+ 'border-opacity': 0.8,
+ 'shape': 'ellipse',
+ 'background-opacity': 0.85
+ },
+ center: {
+ 'background-color': '#f5f5f5',
+ 'color': '#222',
+ 'font-size': 20,
+ 'border-width': 3,
+ 'width': 100,
+ 'height': 100
+ },
+ selected: {
+ 'border-color': '#f59e42',
+ 'border-width': 3,
+ 'background-opacity': 1
+ }
+ },
+ edge: {
+ base: {
+ 'width': function(ele) {
+ return ele.data('strength') ? ele.data('strength') * 2 : 1;
+ },
+ 'line-color': function(ele) {
+ const sourceColor = ele.source().data('color');
+ return sourceColor || '#8a8aaa';
+ },
+ 'line-opacity': function(ele) {
+ return ele.data('strength') ? ele.data('strength') * 0.6 : 0.4;
+ },
+ 'curve-style': 'bezier',
+ 'target-arrow-shape': 'none',
+ 'control-point-distances': [30, -30],
+ 'control-point-weights': [0.5, 0.5]
+ }
+ },
+ layout: {
+ base: {
+ name: 'cose',
+ animate: true,
+ animationDuration: 500,
+ refresh: 20,
+ fit: true,
+ padding: 30,
+ nodeRepulsion: 4500,
+ idealEdgeLength: 50,
+ edgeElasticity: 0.45,
+ randomize: true,
+ componentSpacing: 100,
+ nodeOverlap: 20,
+ gravity: 0.25,
+ initialTemp: 1000,
+ coolingFactor: 0.95,
+ minTemp: 1
+ }
+ }
+};
+
+// Globale Variable für die Mindmap-Daten
+let mindmapData = null;
+
+// Funktion zum Laden der Mindmap-Daten aus der Datenbank
+async function loadMindmapData(nodeId = null) {
try {
- // Versuche, Daten von der API zu laden
- const response = await fetch('/api/mindmap/root');
- let data;
+ const apiUrl = nodeId ? `/api/mindmap/${nodeId}` : '/api/mindmap/root';
+ console.log('Lade Mindmap-Daten von:', apiUrl);
- if (response.ok) {
- data = await response.json();
-
- // Prüfe, ob die API korrekte Daten zurückgegeben hat
- if (!data.nodes || !data.edges) {
- console.warn('API-Antwort hat ungültiges Format, verwende Fallback-Daten');
- data = fallbackData;
+ const response = await fetch(apiUrl);
+ console.log('API-Antwort Status:', response.status);
+
+ if (!response.ok) {
+ let errorData;
+ try {
+ errorData = await response.json();
+ console.log('API-Fehler Details:', errorData);
+ } catch (e) {
+ console.error('Fehler beim Parsen der Fehlerantwort:', e);
+ errorData = {
+ error: `HTTP-Fehler ${response.status}: ${response.statusText}`
+ };
}
- } else {
- console.warn('API-Anfrage fehlgeschlagen, verwende Fallback-Daten');
- data = fallbackData;
+
+ // Fehlerobjekt für die Benachrichtigung erstellen
+ const errorMessage = errorData.error || 'Unbekannter Fehler';
+
+ showUINotification(errorMessage, 'error');
+ throw new Error(errorMessage);
}
- // Cytoscape-Elemente erstellen
+ const data = await response.json();
+ console.log('Geladene Mindmap-Daten:', data);
+
+ if (!data.success) {
+ const errorMessage = data.error || 'Mindmap-Daten konnten nicht geladen werden';
+ showUINotification(errorMessage, 'error');
+ throw new Error(errorMessage);
+ }
+
+ // Überprüfen, ob Nodes und Edges existieren
+ if (!data.nodes || !data.edges) {
+ const errorMessage = 'Ungültiges Datenformat: Nodes oder Edges fehlen';
+ showUINotification(errorMessage, 'error');
+ throw new Error(errorMessage);
+ }
+
+ // Erfolgreiche Antwort
+ mindmapData = data; // Speichere die Daten in der globalen Variable
+ showUINotification('Mindmap-Daten erfolgreich geladen', 'success');
+ return data;
+ } catch (error) {
+ console.error('Fehler beim Laden der Mindmap-Daten:', error);
+
+ // Stelle sicher, dass wir eine aussagekräftige Fehlermeldung haben
+ const errorMessage = error.message || 'Unbekannter Fehler beim Laden der Mindmap-Daten';
+
+ showUINotification(errorMessage, 'error');
+ throw error;
+ }
+}
+
+// Funktion zum Initialisieren der Mindmap
+async function initializeMindmap() {
+ try {
+ const data = await loadMindmapData();
+ if (!data || !data.nodes || !data.edges) {
+ throw new Error('Ungültiges Datenformat: Mindmap-Daten fehlen oder sind unvollständig');
+ }
+
const elements = [
// Knoten
...data.nodes.map(node => ({
@@ -64,7 +201,8 @@ async function initializeMindmap() {
hasChildren: node.has_children,
expanded: false,
color: node.color_code,
- isCenter: node.is_center || false
+ fontColor: '#ffffff',
+ fontSize: node.is_center ? 20 : 16
}
})),
// Kanten
@@ -76,134 +214,1279 @@ async function initializeMindmap() {
}
}))
];
-
- // Cytoscape initialisieren
- const cyContainer = document.getElementById('cy');
-
- if (!cyContainer) {
- throw new Error('Container #cy nicht gefunden');
- }
-
- // Bestehende Cytoscape-Instanz zerstören, wenn vorhanden
- if (window.cy) {
+
+ // Bestehende Cytoscape-Instanz entfernen, falls vorhanden
+ if (window.cy && typeof window.cy.destroy === 'function') {
window.cy.destroy();
}
-
- // Neue Cytoscape-Instanz erstellen
+
+ const cyContainer = document.getElementById('cy');
+ if (!cyContainer) {
+ throw new Error('Mindmap-Container #cy nicht gefunden!');
+ }
+
window.cy = cytoscape({
container: cyContainer,
elements: elements,
style: [
{
selector: 'node',
- style: {
- 'background-color': 'data(color)',
- 'label': 'data(label)',
- 'color': '#ffffff',
- 'text-outline-color': 'black',
- 'text-outline-width': 1,
- 'text-valign': 'center',
- 'text-halign': 'center',
- 'font-size': 18,
- 'width': 50,
- 'height': 50,
- 'border-width': 2,
- 'border-color': '#ffffff',
- 'border-opacity': 0.6
- }
+ style: mindmapStyles.node.base
},
{
selector: 'node[isCenter]',
- style: {
- 'background-color': '#f5f5f5',
- 'color': '#222222',
- 'font-size': 24,
- 'width': 80,
- 'height': 80
- }
+ style: mindmapStyles.node.center
+ },
+ {
+ selector: 'node:selected',
+ style: mindmapStyles.node.selected
},
{
selector: 'edge',
- style: {
- 'width': function(ele) {
- return ele.data('strength') * 5;
- },
- 'line-color': 'rgba(255, 255, 255, 0.5)',
- 'opacity': 0.7,
- 'curve-style': 'bezier'
- }
+ style: mindmapStyles.edge.base
}
],
- 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
+ layout: mindmapStyles.layout.base
+ });
+
+ // Füge neuronale Eigenschaften zu allen Knoten hinzu
+ cy.nodes().forEach(node => {
+ const data = node.data();
+ // Verwende mindmapConfig für Kategorie-Farben oder einen Standardwert
+ const categoryColor = data.category && mindmapConfig.categories[data.category]
+ ? mindmapConfig.categories[data.category].color
+ : '#60a5fa';
+
+ node.data({
+ ...data,
+ neuronSize: data.neuronSize || 8,
+ neuronActivity: data.neuronActivity || 0.8,
+ refractionPeriod: Math.random() * 300 + 700,
+ threshold: Math.random() * 0.3 + 0.6,
+ lastFired: 0,
+ color: data.color || categoryColor
+ });
+ });
+
+ // Füge synaptische Eigenschaften zu allen Kanten hinzu
+ cy.edges().forEach(edge => {
+ const data = edge.data();
+ edge.data({
+ ...data,
+ strength: data.strength || 0.5,
+ conductionVelocity: Math.random() * 0.5 + 0.3,
+ latency: Math.random() * 100 + 50
+ });
+ });
+
+ // Event-Listener für Knoten-Klicks
+ cy.on('tap', 'node', async function(evt) {
+ const node = evt.target;
+ console.log('Node clicked:', node.id(), 'hasChildren:', node.data('hasChildren'), 'expanded:', node.data('expanded'));
+
+ if (node.data('hasChildren') && !node.data('expanded')) {
+ await loadSubthemes(node);
}
});
+
+ // Layout ausführen
+ cy.layout(mindmapStyles.layout.base).run();
- // Knoten sperren, damit sie nicht verschoben werden können
- window.cy.nodes().lock();
+ // Starte neuronale Aktivitätssimulation
+ startNeuralActivitySimulation(cy);
- console.log('Mindmap erfolgreich initialisiert');
- return window.cy;
+ // Mindmap mit echten Daten befüllen (Styles, Farben etc.)
+ updateMindmap();
+
+ return true;
} catch (error) {
- console.error('Fehler bei der Initialisierung der Mindmap:', error);
- throw error;
+ console.error('Fehler bei der Mindmap-Initialisierung:', error);
+ showUINotification({
+ error: 'Mindmap konnte nicht initialisiert werden',
+ details: error.message
+ }, 'error');
+ return false;
}
}
-/**
- * Speichert Änderungen an der Mindmap
- * @param {Object} cy - Die Cytoscape-Instanz
- */
-function saveMindmapChanges(cy) {
- console.log('Speichere Mindmap-Änderungen...');
+// Warte bis DOM geladen ist
+document.addEventListener('DOMContentLoaded', function() {
+ console.log('DOMContentLoaded Event ausgelöst');
- if (!cy) {
- console.error('Keine Cytoscape-Instanz übergeben');
+ // Prüfe, ob der Container existiert
+ const cyContainer = document.getElementById('cy');
+ console.log('Container gefunden:', cyContainer);
+
+ if (!cyContainer) {
+ console.error('Mindmap-Container #cy nicht gefunden!');
return;
}
- // Sammle alle Knoten und Kanten
- const nodes = cy.nodes().map(node => ({
- id: node.id(),
- name: node.data('label'),
- category: node.data('category'),
- description: node.data('description'),
- has_children: node.data('hasChildren'),
- is_center: node.data('isCenter'),
- color_code: node.data('color'),
- position: node.position()
- }));
+ // Prüfe, ob Cytoscape verfügbar ist
+ if (typeof cytoscape === 'undefined') {
+ console.error('Cytoscape ist nicht definiert!');
+ return;
+ }
+ console.log('Cytoscape ist verfügbar');
+
+ // Initialisiere die Mindmap
+ initializeMindmap()
+ .then(success => {
+ if (success) {
+ console.log('Mindmap wurde erfolgreich initialisiert');
+ // Event auslösen, damit andere Scripte reagieren können
+ document.dispatchEvent(new Event('mindmap-loaded'));
+ console.log('mindmap-loaded Event ausgelöst');
+ } else {
+ console.error('Mindmap-Initialisierung fehlgeschlagen');
+ }
+ })
+ .catch(error => {
+ console.error('Fehler bei der Mindmap-Initialisierung:', error);
+ showUINotification({
+ error: 'Mindmap konnte nicht initialisiert werden',
+ details: error.message
+ }, 'error');
+ });
+});
+
+// Funktion zum Initialisieren des neuronalen Designs
+function initializeNeuralDesign(cy) {
+ // Füge neuronale Eigenschaften zu allen Knoten hinzu
+ cy.nodes().forEach(node => {
+ const data = node.data();
+ // Verwende mindmapConfig für Kategorie-Farben oder einen Standardwert
+ const categoryColor = data.category && mindmapConfig.categories[data.category]
+ ? mindmapConfig.categories[data.category].color
+ : '#60a5fa';
+
+ node.data({
+ ...data,
+ neuronSize: data.neuronSize || 8,
+ neuronActivity: data.neuronActivity || 0.8,
+ refractionPeriod: Math.random() * 300 + 700,
+ threshold: Math.random() * 0.3 + 0.6,
+ lastFired: 0,
+ color: data.color || categoryColor
+ });
+ });
+
+ // Füge synaptische Eigenschaften zu allen Kanten hinzu
+ cy.edges().forEach(edge => {
+ const data = edge.data();
+ edge.data({
+ ...data,
+ strength: data.strength || 0.5,
+ conductionVelocity: Math.random() * 0.5 + 0.3,
+ latency: Math.random() * 100 + 50
+ });
+ });
+
+ // Wende neuronales Styling an
+ cy.style()
+ .selector('node')
+ .style({
+ 'background-color': 'data(color)',
+ 'label': 'data(label)',
+ 'color': '#fff',
+ 'text-background-color': 'rgba(0, 0, 0, 0.7)',
+ 'text-background-opacity': 0.8,
+ 'text-background-padding': '4px',
+ 'text-valign': 'center',
+ 'text-halign': 'center',
+ 'font-size': 16,
+ 'width': 40,
+ 'height': 40,
+ 'border-width': 2,
+ 'border-color': '#fff',
+ 'border-opacity': 0.8,
+ 'overlay-padding': 4,
+ 'z-index': 10,
+ 'shape': 'ellipse',
+ 'background-opacity': 0.85,
+ 'shadow-blur': 15,
+ 'shadow-color': 'data(color)',
+ 'shadow-opacity': 0.6,
+ 'shadow-offset-x': 0,
+ 'shadow-offset-y': 0
+ })
+ .selector('edge')
+ .style({
+ 'width': function(ele) {
+ return ele.data('strength') ? ele.data('strength') * 3 : 1;
+ },
+ 'curve-style': 'bezier',
+ 'line-color': function(ele) {
+ const sourceColor = ele.source().data('color');
+ return sourceColor || '#8a8aaa';
+ },
+ 'line-opacity': function(ele) {
+ return ele.data('strength') ? ele.data('strength') * 0.8 : 0.4;
+ },
+ 'line-style': function(ele) {
+ const strength = ele.data('strength');
+ if (!strength) return 'solid';
+ if (strength <= 0.4) return 'dotted';
+ if (strength <= 0.6) return 'dashed';
+ return 'solid';
+ },
+ 'target-arrow-shape': 'none',
+ 'source-endpoint': '0% 50%',
+ 'target-endpoint': '100% 50%',
+ 'transition-property': 'line-opacity, width',
+ 'transition-duration': '0.3s',
+ 'transition-timing-function': 'ease-in-out'
+ })
+ .update();
+
+ // Starte neuronale Aktivitätssimulation
+ startNeuralActivitySimulation(cy);
+}
+
+// Modifiziere die updateMindmap Funktion
+function updateMindmap() {
+ if (!cy) return;
- const edges = cy.edges().map(edge => ({
- source: edge.source().id(),
- target: edge.target().id(),
- strength: edge.data('strength')
- }));
+ // Bestehende Elemente entfernen
+ cy.elements().remove();
- // Daten zum Speichern vorbereiten
- const saveData = {
- nodes: nodes,
- edges: edges
+ // Neue Knoten hinzufügen
+ mindmapData.nodes.forEach(node => {
+ cy.add({
+ group: 'nodes',
+ data: {
+ id: node.id,
+ label: node.name,
+ category: node.category,
+ description: node.description,
+ hasChildren: node.has_children,
+ expanded: false,
+ color: node.color_code || mindmapConfig.categories[node.category]?.color || '#60a5fa',
+ icon: node.icon || mindmapConfig.categories[node.category]?.icon || 'fa-solid fa-circle'
+ }
+ });
+ });
+
+ // Neue Kanten hinzufügen
+ mindmapData.edges.forEach(edge => {
+ cy.add({
+ group: 'edges',
+ data: {
+ source: edge.source,
+ target: edge.target,
+ strength: edge.strength || 0.5
+ }
+ });
+ });
+
+ // Layout aktualisieren
+ cy.layout(mindmapStyles.layout.base).run();
+}
+
+/**
+ * Erweitert die Mindmap mit dem neuronalen Netzwerk-Design
+ */
+function enhanceMindmap() {
+ // Auf die bestehende Cytoscape-Instanz zugreifen
+ const cy = window.cy;
+
+ if (!cy) {
+ console.error('Keine Cytoscape-Instanz gefunden.');
+ return;
+ }
+
+ // Aktualisiere das Layout für eine bessere Verteilung
+ cy.layout({
+ name: 'cose',
+ animate: true,
+ animationDuration: 2000,
+ nodeDimensionsIncludeLabels: true,
+ padding: 100,
+ spacingFactor: 2,
+ randomize: true,
+ fit: true,
+ componentSpacing: 150,
+ nodeRepulsion: 10000,
+ edgeElasticity: 150,
+ nestingFactor: 1.5,
+ gravity: 100,
+ initialTemp: 1000,
+ coolingFactor: 0.95,
+ minTemp: 1
+ }).run();
+
+ // Neuronen-Namen mit besserer Lesbarkeit umgestalten
+ cy.style()
+ .selector('node')
+ .style({
+ 'text-background-color': 'rgba(10, 14, 25, 0.7)',
+ 'text-background-opacity': 0.7,
+ 'text-background-padding': '2px',
+ 'text-border-opacity': 0.2,
+ 'text-border-width': 1,
+ 'text-border-color': '#8b5cf6'
+ })
+ .update();
+
+ // Sicherstellen, dass alle Knoten Neuronen-Eigenschaften haben
+ cy.nodes().forEach(node => {
+ if (!node.data('neuronSize')) {
+ const neuronSize = Math.floor(Math.random() * 8) + 3;
+ node.data('neuronSize', neuronSize);
+ }
+
+ if (!node.data('neuronActivity')) {
+ const neuronActivity = Math.random() * 0.7 + 0.3;
+ node.data('neuronActivity', neuronActivity);
+ }
+
+ // Zusätzliche Neuronale Eigenschaften
+ node.data('pulseFrequency', Math.random() * 4 + 2); // Pulsfrequenz (2-6 Hz)
+ node.data('refractionPeriod', Math.random() * 300 + 700); // Refraktionszeit (700-1000ms)
+ node.data('threshold', Math.random() * 0.3 + 0.6); // Aktivierungsschwelle (0.6-0.9)
+ });
+
+ // Sicherstellen, dass alle Kanten Synapse-Eigenschaften haben
+ cy.edges().forEach(edge => {
+ if (!edge.data('strength')) {
+ const strength = Math.random() * 0.6 + 0.2;
+ edge.data('strength', strength);
+ }
+
+ // Zusätzliche synaptische Eigenschaften
+ edge.data('conductionVelocity', Math.random() * 0.5 + 0.3); // Leitungsgeschwindigkeit (0.3-0.8)
+ edge.data('latency', Math.random() * 100 + 50); // Signalverzögerung (50-150ms)
+ });
+
+ // Neuronales Netzwerk-Stil anwenden
+ applyNeuralNetworkStyle(cy);
+
+ console.log('Mindmap wurde erfolgreich im neuronalen Netzwerk-Stil aktualisiert');
+
+ // Spezielle Effekte für das neuronale Netzwerk hinzufügen
+ startNeuralActivitySimulation(cy);
+}
+
+/**
+ * Wendet detaillierte neuronale Netzwerkstile auf die Mindmap an
+ * @param {Object} cy - Cytoscape-Instanz
+ */
+function applyNeuralNetworkStyle(cy) {
+ cy.style()
+ .selector('node')
+ .style({
+ 'label': 'data(label)',
+ 'text-valign': 'center',
+ 'text-halign': 'center',
+ 'color': 'data(fontColor)',
+ 'text-outline-width': 2,
+ 'text-outline-color': 'rgba(0,0,0,0.8)',
+ 'text-outline-opacity': 0.9,
+ 'font-size': 'data(fontSize)',
+ 'font-weight': '500',
+ 'text-margin-y': 8,
+ 'width': function(ele) {
+ if (ele.data('isCenter')) return 120;
+ return 80;
+ },
+ 'height': function(ele) {
+ if (ele.data('isCenter')) return 120;
+ return 80;
+ },
+ 'background-color': 'data(color)',
+ 'background-opacity': 0.9,
+ 'border-width': 2,
+ 'border-color': '#ffffff',
+ 'border-opacity': 0.8,
+ 'shape': 'ellipse',
+ 'transition-property': 'background-color, background-opacity, border-width',
+ 'transition-duration': '0.3s',
+ 'transition-timing-function': 'ease-in-out'
+ })
+ .selector('edge')
+ .style({
+ 'width': function(ele) {
+ return ele.data('strength') ? ele.data('strength') * 3 : 1;
+ },
+ 'curve-style': 'bezier',
+ 'line-color': function(ele) {
+ const sourceColor = ele.source().data('color');
+ return sourceColor || '#8a8aaa';
+ },
+ 'line-opacity': function(ele) {
+ return ele.data('strength') ? ele.data('strength') * 0.8 : 0.4;
+ },
+ 'line-style': function(ele) {
+ const strength = ele.data('strength');
+ if (!strength) return 'solid';
+ if (strength <= 0.4) return 'dotted';
+ if (strength <= 0.6) return 'dashed';
+ return 'solid';
+ },
+ 'target-arrow-shape': 'none',
+ 'source-endpoint': '0% 50%',
+ 'target-endpoint': '100% 50%',
+ 'transition-property': 'line-opacity, width',
+ 'transition-duration': '0.3s',
+ 'transition-timing-function': 'ease-in-out'
+ })
+ .update();
+}
+
+// Vereinfachte neuronale Aktivitätssimulation
+function startNeuralActivitySimulation(cy) {
+ if (window.neuralInterval) clearInterval(window.neuralInterval);
+
+ const nodes = cy.nodes();
+ let currentTime = Date.now();
+
+ function simulateNeuralActivity() {
+ currentTime = Date.now();
+
+ nodes.forEach(node => {
+ const data = node.data();
+ const lastFired = data.lastFired || 0;
+ const timeSinceLastFire = currentTime - lastFired;
+
+ if (timeSinceLastFire > data.refractionPeriod) {
+ if (Math.random() < data.neuronActivity * 0.1) {
+ fireNeuron(node, true, currentTime);
+ }
+ }
+ });
+ }
+
+ function fireNeuron(node, state, currentTime) {
+ const data = node.data();
+ data.lastFired = currentTime;
+
+ node.style({
+ 'background-opacity': 1,
+ 'border-width': 3
+ });
+
+ setTimeout(() => {
+ node.style({
+ 'background-opacity': 0.9,
+ 'border-width': 2
+ });
+ }, 200);
+
+ if (state) {
+ propagateSignal(node, currentTime);
+ }
+ }
+
+ function propagateSignal(sourceNode, currentTime) {
+ const outgoingEdges = sourceNode.connectedEdges();
+
+ outgoingEdges.forEach(edge => {
+ const targetNode = edge.target();
+ const edgeData = edge.data();
+ const latency = edgeData.latency;
+
+ edge.style({
+ 'line-opacity': 0.8,
+ 'width': edgeData.strength * 3
+ });
+
+ setTimeout(() => {
+ edge.style({
+ 'line-opacity': edgeData.strength * 0.6,
+ 'width': edgeData.strength * 2
+ });
+ }, 200);
+
+ setTimeout(() => {
+ const targetData = targetNode.data();
+ const timeSinceLastFire = currentTime - (targetData.lastFired || 0);
+
+ if (timeSinceLastFire > targetData.refractionPeriod) {
+ const signalStrength = edgeData.strength *
+ edgeData.conductionVelocity *
+ sourceNode.data('neuronActivity');
+
+ if (signalStrength > targetData.threshold) {
+ fireNeuron(targetNode, true, currentTime + latency);
+ }
+ }
+ }, latency);
+ });
+ }
+
+ window.neuralInterval = setInterval(simulateNeuralActivity, 100);
+}
+
+// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises
+function showFlash(message, type = 'info') {
+ const flashContainer = createFlashContainer();
+ const flash = document.createElement('div');
+ flash.className = `flash-message ${type}`;
+ flash.textContent = message;
+ flashContainer.appendChild(flash);
+ document.body.appendChild(flashContainer);
+
+ setTimeout(() => {
+ flash.classList.add('show');
+ setTimeout(() => {
+ flash.classList.remove('show');
+ setTimeout(() => {
+ flashContainer.remove();
+ }, 300);
+ }, 3000);
+ }, 100);
+}
+
+/**
+ * Zeigt eine Benachrichtigung in der UI an
+ * @param {string|object} message - Die anzuzeigende Nachricht oder ein Fehlerobjekt
+ * @param {string} type - Der Typ der Benachrichtigung ('info', 'success', 'warning', 'error')
+ * @param {number} duration - Die Anzeigedauer in Millisekunden (Standard: 3000)
+ */
+function showUINotification(message, type = 'info', duration = 3000) {
+ // Container erstellen, falls er nicht existiert
+ let container = document.getElementById('notification-container');
+ if (!container) {
+ container = document.createElement('div');
+ container.id = 'notification-container';
+ container.style.position = 'fixed';
+ container.style.top = '1rem';
+ container.style.right = '1rem';
+ container.style.zIndex = '1000';
+ container.style.maxWidth = '400px';
+ document.body.appendChild(container);
+ }
+
+ // Benachrichtigung erstellen
+ const notification = document.createElement('div');
+ notification.className = `notification notification-${type}`;
+ notification.style.padding = '1rem';
+ notification.style.marginBottom = '0.5rem';
+ notification.style.borderRadius = '0.25rem';
+ notification.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
+ notification.style.position = 'relative';
+ notification.style.opacity = '0';
+ notification.style.transform = 'translateY(-20px)';
+ notification.style.transition = 'all 0.3s ease-in-out';
+
+ // Farben nach Typ
+ if (type === 'success') {
+ notification.style.backgroundColor = '#059669';
+ notification.style.color = '#ffffff';
+ } else if (type === 'error') {
+ notification.style.backgroundColor = '#DC2626';
+ notification.style.color = '#ffffff';
+ } else if (type === 'warning') {
+ notification.style.backgroundColor = '#F59E0B';
+ notification.style.color = '#ffffff';
+ } else {
+ notification.style.backgroundColor = '#3B82F6';
+ notification.style.color = '#ffffff';
+ }
+
+ // Nachrichteninhalt formatieren
+ let content = '';
+
+ if (typeof message === 'object' && message !== null) {
+ // Wenn es ein Fehler-Objekt ist
+ if (message.error) {
+ content = message.error;
+ if (message.details) {
+ content += `
${message.details}`;
+ }
+ } else {
+ // Versuche, das Objekt zu stringifizieren
+ try {
+ content = JSON.stringify(message);
+ } catch (e) {
+ content = 'Objekt konnte nicht angezeigt werden';
+ }
+ }
+ } else {
+ // String oder andere primitive Typen
+ content = message;
+ }
+
+ notification.innerHTML = content;
+
+ // Schließen-Button
+ const closeButton = document.createElement('span');
+ closeButton.innerHTML = '×';
+ closeButton.style.position = 'absolute';
+ closeButton.style.top = '0.25rem';
+ closeButton.style.right = '0.5rem';
+ closeButton.style.fontSize = '1.25rem';
+ closeButton.style.cursor = 'pointer';
+ closeButton.onclick = () => {
+ notification.style.opacity = '0';
+ notification.style.transform = 'translateY(-20px)';
+ setTimeout(() => {
+ if (notification.parentNode === container) {
+ container.removeChild(notification);
+ }
+ }, 300);
+ };
+ notification.appendChild(closeButton);
+
+ // Zur Seite hinzufügen
+ container.appendChild(notification);
+
+ // Animation starten
+ setTimeout(() => {
+ notification.style.opacity = '1';
+ notification.style.transform = 'translateY(0)';
+ }, 10);
+
+ // Automatisch ausblenden, wenn keine Dauer von 0 übergeben wurde
+ if (duration > 0) {
+ setTimeout(() => {
+ if (notification.parentNode === container) {
+ notification.style.opacity = '0';
+ notification.style.transform = 'translateY(-20px)';
+ setTimeout(() => {
+ if (notification.parentNode === container) {
+ container.removeChild(notification);
+ }
+ }, 300);
+ }
+ }, duration);
+ }
+}
+
+// Funktion zum Anzeigen der Bearbeitungssteuerungen
+function showEditingControls(nodeId) {
+ const container = nodeId ?
+ document.getElementById(`cy-${nodeId}`).parentElement :
+ document.getElementById('cy').parentElement;
+
+ if (!container) return;
+
+ // Erstelle Bearbeitungswerkzeuge, wenn sie noch nicht existieren
+ let editingControls = container.querySelector('.editing-controls');
+ if (!editingControls) {
+ editingControls = document.createElement('div');
+ editingControls.className = 'editing-controls';
+ editingControls.innerHTML = `
+