/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * Camera state slice */ import type { StateCreator } from 'zustand'; import type { CameraRotation, CameraCallbacks, ProjectionMode } from '../types.js'; import { CAMERA_DEFAULTS } from '../constants.js'; export interface CameraSlice { // State cameraRotation: CameraRotation; cameraCallbacks: CameraCallbacks; projectionMode: ProjectionMode; onCameraRotationChange: ((rotation: CameraRotation) => void) | null; onScaleChange: ((scale: number) => void) | null; // Actions setCameraRotation: (rotation: CameraRotation) => void; setCameraCallbacks: (callbacks: CameraCallbacks) => void; setProjectionMode: (mode: ProjectionMode) => void; toggleProjectionMode: () => void; setOnCameraRotationChange: (callback: ((rotation: CameraRotation) => void) | null) => void; updateCameraRotationRealtime: (rotation: CameraRotation) => void; setOnScaleChange: (callback: ((scale: number) => void) | null) => void; updateScaleRealtime: (scale: number) => void; } export const createCameraSlice: StateCreator = (set, get) => ({ // Initial state cameraRotation: { azimuth: CAMERA_DEFAULTS.AZIMUTH, elevation: CAMERA_DEFAULTS.ELEVATION, }, cameraCallbacks: {}, projectionMode: 'perspective', onCameraRotationChange: null, onScaleChange: null, // Actions setCameraRotation: (cameraRotation) => set({ cameraRotation }), setCameraCallbacks: (cameraCallbacks) => set({ cameraCallbacks }), setProjectionMode: (projectionMode) => { get().cameraCallbacks.setProjectionMode?.(projectionMode); set({ projectionMode }); }, toggleProjectionMode: () => { const newMode = get().projectionMode === 'perspective' ? 'orthographic' : 'perspective'; get().cameraCallbacks.setProjectionMode?.(newMode); set({ projectionMode: newMode }); }, setOnCameraRotationChange: (onCameraRotationChange) => set({ onCameraRotationChange }), updateCameraRotationRealtime: (rotation) => { const callback = get().onCameraRotationChange; if (callback) { // Use direct callback - no React state update, no re-renders callback(rotation); } // Don't update store state during real-time updates }, setOnScaleChange: (onScaleChange) => set({ onScaleChange }), updateScaleRealtime: (scale) => { const callback = get().onScaleChange; if (callback) { // Use direct callback - no React state update, no re-renders callback(scale); } // Don't update store state during real-time updates }, });