simple_neural_network_visualizer / ConnectionManager.js
richardhcli
make new folder, subfolder of git, since images is too annoying to deal with
b012e8c
Raw
History Blame Contribute Delete
7.01 kB
/**
* ConnectionManager.js
* Manages connections (lines) between spheres
*/
class ConnectionManager {
constructor(scene) {
this.scene = scene;
this.connections = new Map();
this.connectionLines = new Map();
this.materials = new Map();
}
/**
* Create a connection between two spheres
* @param {string} id - Unique identifier for this connection
* @param {THREE.Vector3} startPos - Starting position
* @param {THREE.Vector3} endPos - Ending position
* @param {object} config - Configuration object
* @param {string} config.color - Hex color (default: '#00ff00')
* @param {number} config.lineWidth - Line width (default: 2)
* @param {string} config.fromSphere - Name of source sphere
* @param {string} config.toSphere - Name of target sphere
* @returns {THREE.Line} The created line object
*/
addConnection(id, startPos, endPos, config = {}) {
// Prevent duplicate IDs
if (this.connections.has(id)) {
console.warn(`Connection "${id}" already exists.`);
return null;
}
const color = config.color || '#00ff00';
const lineWidth = config.lineWidth || 2;
// Create geometry
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(
new Float32Array([
startPos.x, startPos.y, startPos.z,
endPos.x, endPos.y, endPos.z
]), 3
));
// Create material
const material = new THREE.LineBasicMaterial({
color: new THREE.Color(color),
linewidth: lineWidth,
transparent: true,
opacity: 0.8
});
// Create line
const line = new THREE.Line(geometry, material);
line.name = id;
line.userData = {
connectionId: id,
fromSphere: config.fromSphere,
toSphere: config.toSphere,
color: color,
lineWidth: lineWidth,
startPos: startPos.clone(),
endPos: endPos.clone()
};
// Add to scene
this.scene.add(line);
this.connections.set(id, line.userData);
this.connectionLines.set(id, line);
this.materials.set(id, material);
// console.log(`✓ Connection added: ${id} (${config.fromSphere} -> ${config.toSphere})`);
return line;
}
/**
* Remove a connection
* @param {string} id - Connection ID
*/
removeConnection(id) {
const line = this.connectionLines.get(id);
if (!line) {
console.warn(`Connection "${id}" not found.`);
return;
}
// Remove from scene
this.scene.remove(line);
// Clean up geometry and material
const geometry = line.geometry;
const material = this.materials.get(id);
if (geometry) geometry.dispose();
if (material) material.dispose();
// Remove from maps
this.connections.delete(id);
this.connectionLines.delete(id);
this.materials.delete(id);
// console.log(`✓ Connection removed: ${id}`);
}
/**
* Update connection position (useful for dynamic connections)
* @param {string} id - Connection ID
* @param {THREE.Vector3} startPos - New start position
* @param {THREE.Vector3} endPos - New end position
*/
updateConnectionPositions(id, startPos, endPos) {
const line = this.connectionLines.get(id);
if (!line) return;
const positions = line.geometry.attributes.position.array;
positions[0] = startPos.x;
positions[1] = startPos.y;
positions[2] = startPos.z;
positions[3] = endPos.x;
positions[4] = endPos.y;
positions[5] = endPos.z;
line.geometry.attributes.position.needsUpdate = true;
line.userData.startPos = startPos.clone();
line.userData.endPos = endPos.clone();
}
/**
* Update connection color
* @param {string} id - Connection ID
* @param {string} newColor - New hex color
*/
updateConnectionColor(id, newColor) {
const material = this.materials.get(id);
if (!material) return;
material.color.set(new THREE.Color(newColor));
this.connections.get(id).color = newColor;
}
/**
* Get connection by ID
* @param {string} id - Connection ID
* @returns {Object} Connection data
*/
getConnection(id) {
return this.connections.get(id);
}
/**
* Get all connections
* @returns {Array} Array of all connections
*/
getAllConnections() {
return Array.from(this.connections.entries()).map(([id, data]) => ({
id,
...data,
line: this.connectionLines.get(id)
}));
}
/**
* Get connections for a specific sphere
* @param {string} sphereName - Name of the sphere
* @returns {Array} Connections connected to this sphere
*/
getConnectionsForSphere(sphereName) {
return Array.from(this.connections.values()).filter(conn =>
conn.fromSphere === sphereName || conn.toSphere === sphereName
);
}
/**
* Remove all connections for a sphere (when sphere is deleted)
* @param {string} sphereName - Name of the sphere
*/
removeConnectionsForSphere(sphereName) {
const connectionsToRemove = Array.from(this.connections.keys()).filter(id => {
const conn = this.connections.get(id);
return conn.fromSphere === sphereName || conn.toSphere === sphereName;
});
connectionsToRemove.forEach(id => this.removeConnection(id));
}
/**
* Add a pulse effect to a connection
* @param {string} id - Connection ID
* @param {number} duration - Duration of pulse in ms
*/
pulseConnection(id, duration = 500) {
const material = this.materials.get(id);
if (!material) return;
const startOpacity = material.opacity;
const startTime = Date.now();
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = (elapsed % duration) / duration;
const opacityPulse = Math.sin(progress * Math.PI * 2);
material.opacity = startOpacity + opacityPulse * 0.2;
if (elapsed < duration * 2) {
requestAnimationFrame(animate);
} else {
material.opacity = startOpacity;
}
};
animate();
}
/**
* Clear all connections
*/
clearAll() {
const ids = Array.from(this.connections.keys());
ids.forEach(id => this.removeConnection(id));
console.log('✓ All connections cleared');
}
/**
* Get connection count
* @returns {number}
*/
getCount() {
return this.connections.size;
}
}