File size: 6,760 Bytes
b012e8c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | /**
* SphereManager.js
* Manages the creation, deletion, and customization of spheres in the Three.js scene
*/
class SphereManager {
constructor(scene) {
this.scene = scene;
this.spheres = new Map();
this.sphereMeshes = new Map();
this.geometries = new Map();
this.materials = new Map();
}
/**
* Create and add a new sphere to the scene
* @param {string} name - Unique identifier for the sphere
* @param {object} config - Configuration object
* @param {number} config.radius - Sphere radius (default: 1)
* @param {string} config.color - Hex color (default: '#ff0000')
* @param {THREE.Vector3} config.position - Position vector (default: 0,0,0)
* @param {number} config.opacity - Opacity 0-1 (default: 1)
* @returns {THREE.Mesh} The created sphere mesh
*/
addSphere(name, config = {}) {
// Prevent duplicate names
if (this.spheres.has(name)) {
console.warn(`Sphere with name "${name}" already exists. Skipping.`);
return null;
}
// Set defaults
const radius = config.radius || 1;
const color = config.color || '#ff0000';
const position = config.position || new THREE.Vector3(0, 0, 0);
const opacity = config.opacity !== undefined ? config.opacity : 1;
// Create geometry and material
const geometry = new THREE.SphereGeometry(radius, 32, 32);
const material = new THREE.MeshStandardMaterial({
color: new THREE.Color(color),
opacity: opacity,
transparent: opacity < 1,
emissive: new THREE.Color(color),
emissiveIntensity: 0.3,
metalness: 0.3,
roughness: 0.4
});
// Create mesh
const mesh = new THREE.Mesh(geometry, material);
mesh.position.copy(position);
mesh.name = name;
mesh.userData = {
sphereName: name,
radius: radius,
originalColor: color,
connections: []
};
// Store references
this.scene.add(mesh);
this.spheres.set(name, mesh.userData);
this.sphereMeshes.set(name, mesh);
this.geometries.set(name, geometry);
this.materials.set(name, material);
console.log(`✓ Sphere added: ${name}`, config);
return mesh;
}
/**
* Remove a sphere from the scene
* @param {string} name - Name of the sphere to remove
*/
removeSphere(name) {
const mesh = this.sphereMeshes.get(name);
if (!mesh) {
console.warn(`Sphere "${name}" not found.`);
return;
}
// Remove from scene
this.scene.remove(mesh);
// Clean up geometry and material
const geometry = this.geometries.get(name);
const material = this.materials.get(name);
if (geometry) geometry.dispose();
if (material) material.dispose();
// Remove from maps
this.spheres.delete(name);
this.sphereMeshes.delete(name);
this.geometries.delete(name);
this.materials.delete(name);
console.log(`✓ Sphere removed: ${name}`);
}
/**
* Update sphere properties
* @param {string} name - Name of the sphere
* @param {object} config - Properties to update
*/
updateSphere(name, config = {}) {
const mesh = this.sphereMeshes.get(name);
if (!mesh) {
console.warn(`Sphere "${name}" not found.`);
return;
}
// Update position
if (config.position) {
mesh.position.copy(config.position);
}
// Update color
if (config.color) {
const colorObj = new THREE.Color(config.color);
mesh.material.color.copy(colorObj);
mesh.material.emissive.copy(colorObj);
mesh.userData.originalColor = config.color;
}
// Update opacity
if (config.opacity !== undefined) {
mesh.material.opacity = config.opacity;
mesh.material.transparent = config.opacity < 1;
}
// Update scale (for size changes without recreating geometry)
if (config.scale !== undefined) {
mesh.scale.set(config.scale, config.scale, config.scale);
}
console.log(`✓ Sphere updated: ${name}`);
}
/**
* Get sphere mesh by name
* @param {string} name - Name of the sphere
* @returns {THREE.Mesh} The sphere mesh
*/
getSphere(name) {
return this.sphereMeshes.get(name);
}
/**
* Get all spheres
* @returns {Array} Array of sphere data
*/
getAllSpheres() {
return Array.from(this.spheres.entries()).map(([name, data]) => ({
name,
...data,
mesh: this.sphereMeshes.get(name)
}));
}
/**
* Change sphere color with animation
* @param {string} name - Name of the sphere
* @param {string} newColor - New hex color
* @param {number} duration - Animation duration in ms
*/
changeColorSmooth(name, newColor, duration = 500) {
const mesh = this.sphereMeshes.get(name);
if (!mesh) return;
const startColor = mesh.material.color.getHex();
const endColor = new THREE.Color(newColor).getHex();
const startTime = Date.now();
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
const currentColor = new THREE.Color().lerpHexColors(startColor, endColor, progress);
mesh.material.color.copy(currentColor);
mesh.material.emissive.copy(currentColor);
if (progress < 1) {
requestAnimationFrame(animate);
} else {
mesh.userData.originalColor = newColor;
}
};
animate();
}
/**
* Add a glow effect to a sphere
* @param {string} name - Name of the sphere
* @param {boolean} enable - Whether to enable glow
*/
setGlow(name, enable = true) {
const mesh = this.sphereMeshes.get(name);
if (!mesh) return;
if (enable) {
mesh.material.emissiveIntensity = 0.8;
} else {
mesh.material.emissiveIntensity = 0.3;
}
}
/**
* Clear all spheres
*/
clearAll() {
const names = Array.from(this.spheres.keys());
names.forEach(name => this.removeSphere(name));
console.log('✓ All spheres cleared');
}
/**
* Get sphere count
* @returns {number}
*/
getCount() {
return this.spheres.size;
}
}
|