immersive2/src/diagram/functions/dropMesh.ts
Michael Mainguy e329b95f2f Fix AppConfig persistence and consolidate handle storage
AppConfig Persistence Fixes:
- Fix constructor to properly handle null localStorage values
- Add null check before JSON.parse to prevent errors
- Create fresh config copies with spread operator to avoid reference issues
- Add better error handling and logging for config loading
- Initialize handles array properly

React ConfigModal Improvements:
- Fix config initialization to get fresh values on render instead of stale module-level values
- Separate useEffect hooks for each config property (prevents unnecessary updates)
- Fix SegmentedControl string-to-number conversion (locationSnaps now use "0.01", "0.1" format)
- Enable/disable logic now properly sets values to 0 when disabled

Handle Storage Consolidation:
- Create dynamic HandleConfig type with Vec3 for serializable position/rotation/scale
- Add handles array to AppConfigType for flexible handle storage
- Replace individual localStorage keys with centralized AppConfig storage
- Add handle management methods: getHandleConfig, setHandleConfig, removeHandleConfig, getAllHandleConfigs
- Update Handle class to read from AppConfig instead of direct localStorage
- Update dropMesh to save handles via AppConfig using Vec3 serialization
- Convert between BabylonJS Vector3 and serializable Vec3 at conversion points

Benefits:
- Single source of truth for all configuration
- Proper localStorage persistence across page reloads
- Dynamic handle creation without code changes
- Type-safe configuration with proper JSON serialization
- Consolidated storage (one appConfig key instead of multiple handle-* keys)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 15:34:40 -06:00

85 lines
3.4 KiB
TypeScript

import {AbstractMesh, Vector3} from "@babylonjs/core";
import {DiagramManager} from "../diagramManager";
import {DiagramObject} from "../diagramObject";
import {MeshTypeEnum} from "../types/meshTypeEnum";
import {snapAll} from "../../controllers/functions/snapAll";
import {DiagramEvent, DiagramEventType} from "../types/diagramEntity";
import {DiagramEventObserverMask} from "../types/diagramEventObserverMask";
import {DefaultScene} from "../../defaultScene";
import {appConfigInstance} from "../../util/appConfig";
import {HandleConfig, Vec3} from "../../util/appConfigType";
export function dropMesh(mesh: AbstractMesh,
grabbedObject: DiagramObject,
pickPoint: Vector3,
grabbedMeshType: MeshTypeEnum,
diagramManager: DiagramManager): boolean {
if (!mesh) {
return false;
}
let dropped = false;
const diagramObject = grabbedObject;
switch (grabbedMeshType) {
case MeshTypeEnum.ENTITY:
if (diagramObject) {
diagramObject.baseTransform.setParent(null);
snapAll(grabbedObject.baseTransform, pickPoint);
diagramObject.mesh.computeWorldMatrix(true);
const event: DiagramEvent =
{
type: DiagramEventType.DROP,
entity: diagramObject.diagramEntity
}
diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
diagramObject.mesh.computeWorldMatrix(false);
diagramObject.grabbed = false;
dropped = true;
}
break;
case MeshTypeEnum.TOOL:
grabbedObject.baseTransform.setParent(null);
snapAll(grabbedObject.baseTransform, pickPoint);
diagramObject.mesh.computeWorldMatrix(true);
const event: DiagramEvent =
{
type: DiagramEventType.DROP,
entity: diagramObject.diagramEntity
}
diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
diagramObject.mesh.computeWorldMatrix(false);
grabbedObject.grabbed = false;
dropped = true;
break;
case MeshTypeEnum.HANDLE:
mesh.setParent(DefaultScene.Scene.getMeshByName("platform"));
// Get existing handle config or create new one
const existingConfig = appConfigInstance.getHandleConfig(mesh.id);
// Convert Vector3 to Vec3 for serialization
const position: Vec3 = {
x: mesh.position.x,
y: mesh.position.y,
z: mesh.position.z
};
const rotation: Vec3 = {
x: mesh.rotation.x,
y: mesh.rotation.y,
z: mesh.rotation.z
};
const handleConfig: HandleConfig = {
id: mesh.id,
label: existingConfig?.label || mesh.id, // Preserve label if exists
position: position,
rotation: rotation,
scale: existingConfig?.scale // Preserve scale if exists
};
// Save to AppConfig (which persists to localStorage)
appConfigInstance.setHandleConfig(handleConfig);
dropped = true;
break;
}
return dropped;
}