feat(mindmap): enhance interaction and initialization logic in mindmap files

This commit is contained in:
2025-05-06 21:53:54 +01:00
parent 49e5e19b7c
commit aeb829e36a
6 changed files with 1806 additions and 2096 deletions

View File

@@ -6,19 +6,83 @@
// Warte bis DOM geladen ist
document.addEventListener('DOMContentLoaded', function() {
// Prüfe, ob wir auf der Mindmap-Seite sind
console.log('DOMContentLoaded Event ausgelöst');
// Prüfe, ob der Container existiert
const cyContainer = document.getElementById('cy');
console.log('Container gefunden:', cyContainer);
if (!cyContainer) {
console.log('Kein Mindmap-Container gefunden, überspringe Initialisierung.');
console.error('Mindmap-Container #cy nicht gefunden!');
return;
}
// Prüfe, ob Cytoscape verfügbar ist
if (typeof cytoscape === 'undefined') {
console.error('Cytoscape ist nicht definiert!');
return;
}
console.log('Cytoscape ist verfügbar');
// Beispiel-Daten (kannst du später ersetzen)
const elements = [
{ data: { id: 'a', label: 'Neuron A' } },
{ data: { id: 'b', label: 'Neuron B' } },
{ data: { id: 'c', label: 'Neuron C' } },
{ data: { source: 'a', target: 'b' } },
{ data: { source: 'a', target: 'c' } }
];
console.log('Initialisiere Cytoscape...');
// Auf das Laden der Mindmap warten
document.addEventListener('mindmap-loaded', function() {
console.log('Mindmap geladen, wende neuronales Netzwerk-Design an...');
updateMindmap();
// Initialisiere Cytoscape
window.cy = cytoscape({
container: cyContainer,
elements: elements,
style: [
{
selector: 'node',
style: {
'background-color': '#60a5fa',
'label': 'data(label)',
'color': '#fff',
'text-background-color': '#222a',
'text-background-opacity': 0.7,
'text-background-padding': '4px',
'text-valign': 'center',
'text-halign': 'center',
'font-size': 18,
'width': 40,
'height': 40,
'border-width': 4,
'border-color': '#a78bfa',
'shadow-blur': 20,
'shadow-color': '#a78bfa',
'shadow-opacity': 0.7,
}
},
{
selector: 'edge',
style: {
'width': 4,
'line-color': '#a78bfa',
'target-arrow-color': '#a78bfa',
'target-arrow-shape': 'triangle',
'curve-style': 'bezier'
}
}
],
layout: {
name: 'cose',
animate: true
}
});
console.log('Cytoscape initialisiert');
// Event auslösen, damit andere Scripte reagieren können
document.dispatchEvent(new Event('mindmap-loaded'));
console.log('mindmap-loaded Event ausgelöst');
});
// Mindmap-Daten
@@ -158,6 +222,15 @@ const mindmapData = {
]
};
// Kategorie-Farben definieren
const categoryColors = {
'Philosophie': '#60a5fa',
'Wissenschaft': '#8b5cf6',
'Technologie': '#10b981',
'Künste': '#f59e0b',
'Psychologie': '#ef4444'
};
// Mindmap aktualisieren
function updateMindmap() {
if (!cy) return;
@@ -173,7 +246,13 @@ function updateMindmap() {
id: node.id,
label: node.label,
category: node.category,
description: node.description
description: node.description,
color: categoryColors[node.category] || '#60a5fa',
neuronSize: Math.floor(Math.random() * 8) + 3,
neuronActivity: Math.random() * 0.7 + 0.3,
pulseFrequency: Math.random() * 4 + 2,
refractionPeriod: Math.random() * 300 + 700,
threshold: Math.random() * 0.3 + 0.6
}
});
});
@@ -185,30 +264,126 @@ function updateMindmap() {
data: {
source: edge.source,
target: edge.target,
label: edge.label
label: edge.label,
strength: Math.random() * 0.6 + 0.2,
conductionVelocity: Math.random() * 0.5 + 0.3,
latency: Math.random() * 100 + 50
}
});
});
// Neuronales Netzwerk-Styling anwenden
cy.style([
{
selector: 'node',
style: {
'label': 'data(label)',
'text-valign': 'center',
'text-halign': 'center',
'text-wrap': 'wrap',
'text-max-width': '100px',
'font-size': '14px',
'color': '#ffffff',
'text-outline-color': '#0a0e19',
'text-outline-width': 1.5,
'text-outline-opacity': 0.9,
'text-margin-y': 7,
'width': 'mapData(neuronSize, 3, 10, 15, 40)',
'height': 'mapData(neuronSize, 3, 10, 15, 40)',
'background-color': 'data(color)',
'background-opacity': 0.85,
'border-width': 0,
'shape': 'ellipse',
'shadow-blur': 'mapData(neuronActivity, 0.3, 1, 5, 15)',
'shadow-color': 'data(color)',
'shadow-opacity': 0.6,
'shadow-offset-x': 0,
'shadow-offset-y': 0,
'text-background-color': 'rgba(24, 28, 45, 0.7)',
'text-background-opacity': 0.8,
'text-background-shape': 'roundrectangle',
'text-background-padding': '4px',
'transition-property': 'background-color, shadow-blur, shadow-opacity, background-opacity',
'transition-duration': '0.5s'
}
},
{
selector: 'edge',
style: {
'width': 'mapData(strength, 0.2, 0.8, 0.7, 2)',
'curve-style': 'bezier',
'line-color': '#8a8aaa',
'line-opacity': 'mapData(strength, 0.2, 0.8, 0.4, 0.7)',
'line-style': function(ele) {
const strength = ele.data('strength');
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-color, width, line-style, line-opacity',
'transition-duration': '0.4s'
}
},
{
selector: ':selected',
style: {
'background-color': '#f59e0b',
'shadow-blur': 32,
'shadow-color': '#f59e0b',
'shadow-opacity': 1,
'border-width': 4,
'border-color': '#fff'
}
},
{
selector: '.highlighted',
style: {
'background-color': '#10b981',
'shadow-blur': 28,
'shadow-color': '#10b981',
'shadow-opacity': 1,
'line-color': '#10b981',
'target-arrow-color': '#10b981',
'transition-property': 'background-color, shadow-blur, shadow-opacity, line-color',
'transition-duration': '0.3s'
}
}
]);
// Layout anwenden
cy.layout({
name: 'cose',
idealEdgeLength: 100,
nodeOverlap: 20,
refresh: 20,
fit: true,
padding: 30,
animate: true,
animationDuration: 1800,
nodeDimensionsIncludeLabels: true,
padding: 100,
spacingFactor: 1.8,
randomize: false,
fit: true,
componentSpacing: 100,
nodeRepulsion: 400000,
nodeRepulsion: 8000,
edgeElasticity: 100,
nestingFactor: 5,
gravity: 80,
numIter: 1000,
initialTemp: 200,
coolingFactor: 0.95,
minTemp: 1.0
nestingFactor: 1.2,
gravity: 80
}).run();
// Pulsierende Soma-Effekte starten
if (window.pulseInterval) clearInterval(window.pulseInterval);
window.pulseInterval = setInterval(() => {
cy.nodes().forEach(node => {
const baseBlur = 18;
const pulse = 0.7 + 0.3 * Math.sin(Date.now() / 400 + node.id().charCodeAt(0));
node.style('shadow-blur', baseBlur * pulse);
node.style('shadow-opacity', 0.6 + 0.3 * pulse);
node.style('background-opacity', 0.85 + 0.1 * pulse);
});
}, 80);
// Neuronale Aktivität simulieren
startNeuralActivitySimulation(cy);
}
/**
@@ -358,160 +533,91 @@ function applyNeuralNetworkStyle(cy) {
* @param {Object} cy - Cytoscape-Instanz
*/
function startNeuralActivitySimulation(cy) {
// Neuronen-Zustand für die Simulation
const neuronStates = new Map();
if (window.neuralInterval) clearInterval(window.neuralInterval);
const nodes = cy.nodes();
const edges = cy.edges();
let currentTime = Date.now();
// Neuronale Aktivität simulieren
function simulateNeuralActivity() {
currentTime = Date.now();
// Initialisieren aller Neuronen-Zustände
cy.nodes().forEach(node => {
neuronStates.set(node.id(), {
potential: Math.random() * 0.3, // Startpotential
lastFired: 0, // Zeitpunkt der letzten Aktivierung
isRefractory: false, // Refraktärphase
refractoryUntil: 0 // Ende der Refraktärphase
});
// Zufällige Neuronen "feuern" lassen
nodes.forEach(node => {
const data = node.data();
const lastFired = data.lastFired || 0;
const timeSinceLastFire = currentTime - lastFired;
// Prüfen ob Neuron feuern kann (Refraktionsperiode)
if (timeSinceLastFire > data.refractionPeriod) {
// Zufälliges Feuern basierend auf Aktivität
if (Math.random() < data.neuronActivity * 0.1) {
fireNeuron(node, true, currentTime);
}
}
});
}
// Neuron feuern lassen
function fireNeuron(node, state, currentTime) {
const data = node.data();
data.lastFired = currentTime;
// Visuelles Feedback
node.style({
'background-opacity': 1,
'shadow-blur': 25,
'shadow-opacity': 0.9
});
// Neuronale Aktivität simulieren
function simulateNeuralActivity() {
const currentTime = Date.now();
const nodes = cy.nodes().toArray();
// Nach kurzer Zeit zurück zum Normalzustand
setTimeout(() => {
node.style({
'background-opacity': 0.85,
'shadow-blur': 18,
'shadow-opacity': 0.6
});
}, 200);
// Signal weiterleiten
if (state) {
propagateSignal(node, currentTime);
}
}
// Signal über Kanten weiterleiten
function propagateSignal(sourceNode, currentTime) {
const outgoingEdges = sourceNode.connectedEdges('out');
outgoingEdges.forEach(edge => {
const targetNode = edge.target();
const edgeData = edge.data();
const latency = edgeData.latency;
// Signal mit Verzögerung weiterleiten
setTimeout(() => {
const targetData = targetNode.data();
const timeSinceLastFire = currentTime - (targetData.lastFired || 0);
// Zufällige Stimulation eines Neurons
if (Math.random() > 0.7) {
const randomNodeIndex = Math.floor(Math.random() * nodes.length);
const randomNode = nodes[randomNodeIndex];
const state = neuronStates.get(randomNode.id());
if (state && !state.isRefractory) {
state.potential += 0.5; // Erhöhe das Potential durch externe Stimulation
}
// Prüfen ob Zielneuron feuern kann
if (timeSinceLastFire > targetData.refractionPeriod) {
// Signalstärke berechnen
const signalStrength = edgeData.strength *
edgeData.conductionVelocity *
sourceNode.data('neuronActivity');
// Neuron feuern lassen wenn Signal stark genug
if (signalStrength > targetData.threshold) {
fireNeuron(targetNode, true, currentTime + latency);
}
}
// Neuronen aktualisieren
nodes.forEach(node => {
const nodeId = node.id();
const state = neuronStates.get(nodeId);
const threshold = node.data('threshold') || 0.7;
const refractoryPeriod = node.data('refractionPeriod') || 1000;
// Überprüfen, ob die Refraktärphase beendet ist
if (state.isRefractory && currentTime >= state.refractoryUntil) {
state.isRefractory = false;
state.potential = 0.1; // Ruhepotential nach Refraktärphase
}
// Wenn nicht in Refraktärphase und Potential über Schwelle
if (!state.isRefractory && state.potential >= threshold) {
// Neuron feuert
fireNeuron(node, state, currentTime);
} else if (!state.isRefractory) {
// Potential langsam verlieren, wenn nicht gefeuert wird
state.potential *= 0.95;
}
});
// Simulation fortsetzen
requestAnimationFrame(simulateNeuralActivity);
}
// Neuron "feuern" lassen
function fireNeuron(node, state, currentTime) {
// Neuron aktivieren
node.animate({
style: {
'background-opacity': 1,
'shadow-opacity': 1,
'shadow-blur': 25
},
duration: 300,
easing: 'ease-in-cubic',
complete: function() {
// Zurück zum normalen Zustand
node.animate({
style: {
'background-opacity': 0.85,
'shadow-opacity': 0.6,
'shadow-blur': 'mapData(neuronActivity, 0.3, 1, 5, 15)'
},
duration: 600,
easing: 'ease-out-cubic'
});
}
});
// Refraktärphase setzen
state.isRefractory = true;
state.lastFired = currentTime;
state.refractoryPeriod = node.data('refractionPeriod') || 1000;
state.refractoryUntil = currentTime + state.refractoryPeriod;
state.potential = 0; // Potential zurücksetzen
// Signal über verbundene Synapsen weiterleiten
propagateSignal(node, currentTime);
}
// Signal über Synapsen propagieren
function propagateSignal(sourceNode, currentTime) {
// Verbundene Kanten auswählen
const edges = sourceNode.connectedEdges().filter(edge =>
edge.source().id() === sourceNode.id() // Nur ausgehende Kanten
);
// Durch alle Kanten iterieren
edges.forEach(edge => {
// Signalverzögerung basierend auf synaptischen Eigenschaften
const latency = edge.data('latency') || 100;
const strength = edge.data('strength') || 0.5;
// Signal entlang der Kante senden
setTimeout(() => {
edge.animate({
style: {
'line-color': '#a78bfa',
'line-opacity': 0.9,
'width': 2.5
},
duration: 200,
easing: 'ease-in',
complete: function() {
// Kante zurücksetzen
edge.animate({
style: {
'line-color': '#8a8aaa',
'line-opacity': 'mapData(strength, 0.2, 0.8, 0.4, 0.7)',
'width': 'mapData(strength, 0.2, 0.8, 0.7, 2)'
},
duration: 400,
easing: 'ease-out'
});
// Zielknoten potenzial erhöhen
const targetNode = edge.target();
const targetState = neuronStates.get(targetNode.id());
if (targetState && !targetState.isRefractory) {
// Potentialzunahme basierend auf synaptischer Stärke
targetState.potential += strength * 0.4;
// Subtile Anzeige der Potenzialänderung
targetNode.animate({
style: {
'background-opacity': Math.min(1, 0.85 + (strength * 0.2)),
'shadow-opacity': Math.min(1, 0.6 + (strength * 0.3)),
'shadow-blur': Math.min(25, 10 + (strength * 15))
},
duration: 300,
easing: 'ease-in-out'
});
}
}
});
}, latency);
});
}
// Starte die Simulation
simulateNeuralActivity();
}, latency);
});
}
// Simulation starten
window.neuralInterval = setInterval(simulateNeuralActivity, 100);
}
// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises