fix camera history
This commit is contained in:
parent
1d817c8e0f
commit
7f497ae8d8
|
|
@ -1,12 +1,42 @@
|
|||
import { useEffect } from 'react';
|
||||
import { Editor, TLFrameShape, TLParentId } from 'tldraw';
|
||||
import { Editor, TLEventMap, TLFrameShape, TLParentId } from 'tldraw';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
const initialCamera = { x: 0, y: 0, z: 1 };
|
||||
// Define camera state interface
|
||||
interface CameraState {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
|
||||
const MAX_HISTORY = 10;
|
||||
let cameraHistory: CameraState[] = [];
|
||||
|
||||
// Improved camera change tracking with debouncing
|
||||
const trackCameraChange = (editor: Editor) => {
|
||||
// Only track if not in animation
|
||||
if (editor.getCameraState() === 'moving') return;
|
||||
|
||||
const currentCamera = editor.getCamera();
|
||||
const lastPosition = cameraHistory[cameraHistory.length - 1];
|
||||
|
||||
// Enhanced threshold check for meaningful changes
|
||||
if (!lastPosition ||
|
||||
(Math.abs(lastPosition.x - currentCamera.x) > 1 ||
|
||||
Math.abs(lastPosition.y - currentCamera.y) > 1 ||
|
||||
Math.abs(lastPosition.z - currentCamera.z) > 0.1)) {
|
||||
|
||||
cameraHistory.push({ ...currentCamera });
|
||||
if (cameraHistory.length > MAX_HISTORY) {
|
||||
cameraHistory.shift();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function useCameraControls(editor: Editor | null) {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
// Handle URL-based camera positioning
|
||||
useEffect(() => {
|
||||
if (!editor) return;
|
||||
|
||||
|
|
@ -15,82 +45,88 @@ export function useCameraControls(editor: Editor | null) {
|
|||
const y = searchParams.get('y');
|
||||
const zoom = searchParams.get('zoom');
|
||||
|
||||
console.log('Loading camera position:', { frameId, x, y, zoom });
|
||||
|
||||
if (x && y && zoom) {
|
||||
editor.setCamera({
|
||||
x: parseFloat(x),
|
||||
y: parseFloat(y),
|
||||
z: parseFloat(zoom)
|
||||
});
|
||||
console.log('Camera position set from URL params');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frameId) return;
|
||||
|
||||
if (frameId) {
|
||||
const frame = editor.getShape(frameId as TLParentId) as TLFrameShape;
|
||||
if (!frame) {
|
||||
console.warn('Frame not found:', frameId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use editor's built-in zoomToBounds with animation
|
||||
editor.zoomToBounds(
|
||||
editor.getShapePageBounds(frame)!,
|
||||
{
|
||||
inset: 32,
|
||||
targetZoom: editor.getCamera().z,
|
||||
animation: { duration: 500 }
|
||||
}
|
||||
);
|
||||
|
||||
const newUrl = new URL(window.location.href);
|
||||
newUrl.searchParams.set('frameId', frameId);
|
||||
window.history.replaceState(null, '', newUrl.toString());
|
||||
}
|
||||
}, [editor, searchParams]);
|
||||
|
||||
const copyLocationLink = () => {
|
||||
// Track camera changes
|
||||
useEffect(() => {
|
||||
if (!editor) return;
|
||||
|
||||
const handler = () => {
|
||||
if (editor.getCameraState() !== 'moving') {
|
||||
trackCameraChange(editor);
|
||||
}
|
||||
};
|
||||
|
||||
editor.on('viewportChange' as keyof TLEventMap, handler);
|
||||
|
||||
return () => {
|
||||
editor.off('viewportChange' as keyof TLEventMap, handler);
|
||||
};
|
||||
}, [editor]);
|
||||
|
||||
// Enhanced camera control functions
|
||||
return {
|
||||
zoomToFrame: (frameId: string) => {
|
||||
if (!editor) return;
|
||||
const frame = editor.getShape(frameId as TLParentId) as TLFrameShape;
|
||||
if (!frame) return;
|
||||
|
||||
editor.zoomToBounds(
|
||||
editor.getShapePageBounds(frame)!,
|
||||
{
|
||||
inset: 32,
|
||||
animation: { duration: 500 }
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
copyFrameLink: (frameId: string) => {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('frameId', frameId);
|
||||
navigator.clipboard.writeText(url.toString());
|
||||
},
|
||||
|
||||
copyLocationLink: () => {
|
||||
if (!editor) return;
|
||||
const camera = editor.getCamera();
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('x', camera.x.toString());
|
||||
url.searchParams.set('y', camera.y.toString());
|
||||
url.searchParams.set('zoom', camera.z.toString());
|
||||
console.log('Copying location link:', url.toString());
|
||||
navigator.clipboard.writeText(url.toString());
|
||||
};
|
||||
},
|
||||
|
||||
const zoomToFrame = (frameId: string) => {
|
||||
if (!editor) return;
|
||||
|
||||
const frame = editor.getShape(frameId as TLParentId) as TLFrameShape;
|
||||
if (!frame) {
|
||||
console.warn('Frame not found:', frameId);
|
||||
return;
|
||||
}
|
||||
|
||||
editor.zoomToBounds(
|
||||
editor.getShapePageBounds(frame)!,
|
||||
{
|
||||
inset: 32,
|
||||
targetZoom: editor.getCamera().z,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const copyFrameLink = (frameId: string) => {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('frameId', frameId);
|
||||
console.log('Copying frame link:', url.toString());
|
||||
navigator.clipboard.writeText(url.toString());
|
||||
};
|
||||
|
||||
return {
|
||||
zoomToFrame,
|
||||
copyFrameLink,
|
||||
copyLocationLink,
|
||||
revertCamera: () => {
|
||||
if (!editor) return
|
||||
editor.setCamera(initialCamera)
|
||||
if (!editor || cameraHistory.length === 0) return;
|
||||
const previousCamera = cameraHistory.pop();
|
||||
if (previousCamera) {
|
||||
editor.setCamera(previousCamera, { animation: { duration: 200 } });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue