feat(mindmap): enhance interaction and initialization logic in mindmap files
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user