102 lines
3.6 KiB
TypeScript
102 lines
3.6 KiB
TypeScript
import { Text } from '@react-three/drei';
|
|
import * as THREE from 'three';
|
|
import type { Room3D } from '../../lib/layoutApi';
|
|
import { PlantPosition, VisMode, COLORS } from './types';
|
|
import { SmartRack } from './SmartRack';
|
|
|
|
// Mock environment data
|
|
const getMockRoomEnv = (roomName: string) => {
|
|
const hash = roomName.split('').reduce((a, b) => a + b.charCodeAt(0), 0);
|
|
return {
|
|
temp: 68 + (hash % 15),
|
|
humidity: 40 + (hash % 40),
|
|
};
|
|
};
|
|
|
|
const lerpColor = (c1: string, c2: string, t: number) => {
|
|
const c1c = new THREE.Color(c1);
|
|
const c2c = new THREE.Color(c2);
|
|
return '#' + c1c.lerp(c2c, Math.min(1, Math.max(0, t))).getHexString();
|
|
};
|
|
|
|
interface RoomObjectProps {
|
|
room: Room3D;
|
|
visMode: VisMode;
|
|
onPlantClick: (plant: PlantPosition) => void;
|
|
highlightedTags?: string[];
|
|
dimMode?: boolean;
|
|
}
|
|
|
|
export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMode }: RoomObjectProps) {
|
|
const env = getMockRoomEnv(room.name);
|
|
|
|
let floorColor: string = COLORS.ROOM_FLOOR;
|
|
if (visMode === 'TEMP') {
|
|
const t = (env.temp - 65) / 20;
|
|
floorColor = t < 0.5
|
|
? lerpColor(COLORS.TEMP_LOW, COLORS.TEMP_OPTIMAL, t * 2)
|
|
: lerpColor(COLORS.TEMP_OPTIMAL, COLORS.TEMP_HIGH, (t - 0.5) * 2);
|
|
} else if (visMode === 'HUMIDITY') {
|
|
const t = (env.humidity - 40) / 40;
|
|
floorColor = t < 0.5
|
|
? lerpColor(COLORS.HUMIDITY_DRY, COLORS.HUMIDITY_OPTIMAL, t * 2)
|
|
: lerpColor(COLORS.HUMIDITY_OPTIMAL, COLORS.HUMIDITY_WET, (t - 0.5) * 2);
|
|
}
|
|
|
|
return (
|
|
<group position={[room.posX, 0, room.posY]}>
|
|
<Text
|
|
position={[room.width / 2, 0.05, room.height / 2]}
|
|
rotation={[-Math.PI / 2, 0, 0]}
|
|
fontSize={Math.min(room.width, room.height) / 6}
|
|
color="#f8fafc"
|
|
fillOpacity={0.7}
|
|
anchorX="center"
|
|
anchorY="middle"
|
|
>
|
|
{room.name}
|
|
</Text>
|
|
|
|
{(visMode === 'TEMP' || visMode === 'HUMIDITY') && (
|
|
<Text
|
|
position={[room.width / 2, 4, room.height / 2]}
|
|
rotation={[-Math.PI / 4, 0, 0]}
|
|
fontSize={4}
|
|
color="#fff"
|
|
outlineColor="#000"
|
|
outlineWidth={0.15}
|
|
anchorX="center"
|
|
>
|
|
{visMode === 'TEMP' ? `${env.temp}°F` : `${env.humidity}%`}
|
|
</Text>
|
|
)}
|
|
|
|
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[room.width / 2, 0, room.height / 2]} receiveShadow>
|
|
<planeGeometry args={[room.width, room.height]} />
|
|
<meshStandardMaterial
|
|
color={floorColor}
|
|
roughness={0.95}
|
|
metalness={0.05}
|
|
transparent={visMode !== 'STANDARD'}
|
|
opacity={visMode !== 'STANDARD' ? 0.85 : 1}
|
|
/>
|
|
</mesh>
|
|
|
|
<lineSegments position={[room.width / 2, 0.02, room.height / 2]} rotation={[-Math.PI / 2, 0, 0]}>
|
|
<edgesGeometry args={[new THREE.PlaneGeometry(room.width, room.height)]} />
|
|
<lineBasicMaterial color="#64748b" />
|
|
</lineSegments>
|
|
|
|
{room.sections.map(section => (
|
|
<SmartRack
|
|
key={section.id}
|
|
section={section}
|
|
visMode={visMode}
|
|
onPlantClick={onPlantClick}
|
|
highlightedTags={highlightedTags}
|
|
dimMode={dimMode}
|
|
/>
|
|
))}
|
|
</group>
|
|
);
|
|
}
|