periodic_table / PeriodicTableComponent.js
AK51's picture
Upload 18 files
ab59545 verified
import * as THREE from 'three';
import { getElementPosition, ELEMENT_COLORS } from './elementLayout.js';
export class PeriodicTableComponent {
constructor(scene, dataManager) {
this.scene = scene;
this.dataManager = dataManager;
this.elementMeshes = new Map();
this.highlightedElement = null;
this.selectedElement = null;
}
createPeriodicTable() {
const elements = this.dataManager.getAllElements();
elements.forEach(symbol => {
const elementData = this.dataManager.getElementData(symbol);
const position = getElementPosition(symbol);
if (!position) return;
// Create element tile
const geometry = new THREE.BoxGeometry(0.9, 0.9, 0.1);
const color = ELEMENT_COLORS[elementData.category] || ELEMENT_COLORS.unknown;
const material = new THREE.MeshStandardMaterial({
color: color,
emissive: 0x000000,
metalness: 0.3,
roughness: 0.7
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(position.x, position.y, position.z);
mesh.userData = { symbol, elementData };
this.scene.add(mesh);
this.elementMeshes.set(symbol, mesh);
// Add text label
this.addTextLabel(symbol, position);
});
}
addTextLabel(symbol, position) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 128;
canvas.height = 128;
context.fillStyle = 'white';
context.font = 'bold 60px Arial';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(symbol, 64, 64);
const texture = new THREE.CanvasTexture(canvas);
const spriteMaterial = new THREE.SpriteMaterial({ map: texture });
const sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(0.6, 0.6, 1);
sprite.position.set(position.x, position.y, position.z + 0.1);
this.scene.add(sprite);
}
highlightElement(symbol) {
// Reset previous highlight
if (this.highlightedElement && this.highlightedElement !== this.selectedElement) {
const prevMesh = this.elementMeshes.get(this.highlightedElement);
if (prevMesh) {
prevMesh.material.emissive.setHex(0x000000);
}
}
// Apply new highlight
if (symbol && symbol !== this.selectedElement) {
const mesh = this.elementMeshes.get(symbol);
if (mesh) {
mesh.material.emissive.setHex(0x444444);
}
}
this.highlightedElement = symbol;
}
selectElement(symbol) {
// Reset previous selection
if (this.selectedElement) {
const prevMesh = this.elementMeshes.get(this.selectedElement);
if (prevMesh) {
prevMesh.material.emissive.setHex(0x000000);
}
}
// Apply new selection
if (symbol) {
const mesh = this.elementMeshes.get(symbol);
if (mesh) {
mesh.material.emissive.setHex(0x00ff00);
}
}
this.selectedElement = symbol;
}
getElementAtPosition(x, y, camera) {
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2(x, y);
raycaster.setFromCamera(mouse, camera);
const meshes = Array.from(this.elementMeshes.values());
const intersects = raycaster.intersectObjects(meshes);
if (intersects.length > 0) {
return intersects[0].object.userData.symbol;
}
return null;
}
getSelectedElement() {
return this.selectedElement;
}
}