diff --git a/src/hooks/useCameraControls.ts b/src/hooks/useCameraControls.ts index 22b879c..470213f 100644 --- a/src/hooks/useCameraControls.ts +++ b/src/hooks/useCameraControls.ts @@ -1,5 +1,5 @@ import { useEffect } from "react" -import { Editor, TLEventMap, TLFrameShape, TLParentId } from "tldraw" +import { Editor, TLEventMap, TLFrameShape, TLParentId, TLShapeId } from "tldraw" import { useSearchParams } from "react-router-dom" // Define camera state interface @@ -38,35 +38,60 @@ export function useCameraControls(editor: Editor | null) { // Handle URL-based camera positioning useEffect(() => { - if (!editor) return - - const frameId = searchParams.get("frameId") - const x = searchParams.get("x") - const y = searchParams.get("y") - const zoom = searchParams.get("zoom") - - if (x && y && zoom) { - editor.setCamera({ - x: parseFloat(x), - y: parseFloat(y), - z: parseFloat(zoom), + if (!editor || !editor.store || !editor.getInstanceState().isFocused) { + console.log("Editor not ready:", { + editor: !!editor, + store: !!editor?.store, + isFocused: editor?.getInstanceState().isFocused, }) return } - if (frameId) { - const frame = editor.getShape(frameId as TLParentId) as TLFrameShape - if (!frame) { - console.warn("Frame not found:", frameId) - return - } + const x = searchParams.get("x") + const y = searchParams.get("y") + const zoom = searchParams.get("zoom") + const frameId = searchParams.get("frameId") + const isLocked = searchParams.get("isLocked") === "true" - // Use editor's built-in zoomToBounds with animation - editor.zoomToBounds(editor.getShapePageBounds(frame)!, { - inset: 32, - animation: { duration: 500 }, + console.log("Setting camera:", { x, y, zoom }) + + // Set camera position if coordinates exist + if (x && y && zoom) { + const position = { + x: parseFloat(x), + y: parseFloat(y), + z: parseFloat(zoom), + } + console.log("Camera position:", position) + + requestAnimationFrame(() => { + editor.setCamera(position, { animation: { duration: 0 } }) + console.log("Current camera:", editor.getCamera()) }) } + + // Handle frame-specific logic + if (frameId) { + const frame = editor.getShape(frameId as TLShapeId) + if (frame) { + editor.select(frameId as TLShapeId) + + // If x/y/zoom are not provided in URL, zoom to frame bounds + if (!x || !y || !zoom) { + editor.zoomToBounds(editor.getShapePageBounds(frame)!, { + animation: { duration: 0 }, + targetZoom: 1, + }) + } + + // Apply camera lock after camera is positioned + if (isLocked) { + requestAnimationFrame(() => { + editor.setCameraOptions({ isLocked: true }) + }) + } + } + } }, [editor, searchParams]) // Track camera changes @@ -100,12 +125,6 @@ export function useCameraControls(editor: Editor | null) { }) }, - 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() @@ -116,6 +135,12 @@ export function useCameraControls(editor: Editor | null) { navigator.clipboard.writeText(url.toString()) }, + copyFrameLink: (frameId: string) => { + const url = new URL(window.location.href) + url.searchParams.set("frameId", frameId) + navigator.clipboard.writeText(url.toString()) + }, + revertCamera: () => { if (!editor || cameraHistory.length === 0) return const previousCamera = cameraHistory.pop() diff --git a/src/ui/cameraUtils.ts b/src/ui/cameraUtils.ts index 11c94ab..09c8183 100644 --- a/src/ui/cameraUtils.ts +++ b/src/ui/cameraUtils.ts @@ -195,8 +195,8 @@ export const lockCameraToFrame = async (editor: Editor) => { ) // Set camera parameters first - url.searchParams.set("x", bounds.x.toString()) - url.searchParams.set("y", bounds.y.toString()) + url.searchParams.set("x", Math.round(bounds.x).toString()) + url.searchParams.set("y", Math.round(bounds.y).toString()) url.searchParams.set("zoom", targetZoom.toString()) // Add frame-specific parameters last diff --git a/src/utils/handleInitialPageLoad.ts b/src/utils/handleInitialPageLoad.ts index 1ce4fcd..88dbbdc 100644 --- a/src/utils/handleInitialPageLoad.ts +++ b/src/utils/handleInitialPageLoad.ts @@ -1,67 +1,73 @@ import { Editor, TLShapeId } from "tldraw" export const handleInitialPageLoad = (editor: Editor) => { + // Wait for editor to be ready + // if (!editor.isMounted()) { + // editor.once("mount", () => handleInitialPageLoad(editor)) + // return + // } + const url = new URL(window.location.href) + console.log("URL params:", { + x: url.searchParams.get("x"), + y: url.searchParams.get("y"), + zoom: url.searchParams.get("zoom"), + }) // Get camera parameters first const x = url.searchParams.get("x") const y = url.searchParams.get("y") const zoom = url.searchParams.get("zoom") - // Get shape/frame parameters last - const frameId = url.searchParams.get("frameId") - const shapeId = url.searchParams.get("shapeId") - const isLocked = url.searchParams.get("isLocked") === "true" + // Set camera position if coordinates exist + if (x && y && zoom) { + console.log("Setting camera to:", { + x: parseFloat(x), + y: parseFloat(y), + z: parseFloat(zoom), + }) - // Wait for next tick to ensure editor is ready - requestAnimationFrame(() => { - // Set camera position if coordinates exist - if (x && y && zoom) { + requestAnimationFrame(() => { editor.setCamera({ x: parseFloat(x), y: parseFloat(y), z: parseFloat(zoom), }) - } + }) + } - // Handle frame-specific logic - if (frameId) { - const frame = editor.getShape(frameId as TLShapeId) - if (frame) { - editor.select(frameId as TLShapeId) + // Get shape/frame parameters last + const frameId = url.searchParams.get("frameId") + const isLocked = url.searchParams.get("isLocked") === "true" - // If x/y/zoom are not provided in URL, zoom to frame bounds - if (!x || !y || !zoom) { - editor.zoomToBounds(editor.getShapePageBounds(frame)!, { - animation: { duration: 0 }, - targetZoom: 1, - }) - } + // Handle frame-specific logic + if (frameId) { + const frame = editor.getShape(frameId as TLShapeId) + if (frame) { + editor.select(frameId as TLShapeId) - // Apply camera lock after camera is positioned - if (isLocked) { - // Use requestAnimationFrame to ensure camera is set before locking - requestAnimationFrame(() => { - editor.setCameraOptions({ - isLocked: true, - // Optional: you may want to also set these options for locked frames - //shouldSnapToGrid: false, - //shouldUseEdgeScrolling: false, - }) - }) - } - } else { - console.warn("Frame not found:", frameId) + // If x/y/zoom are not provided in URL, zoom to frame bounds + if (!x || !y || !zoom) { + editor.zoomToBounds(editor.getShapePageBounds(frame)!, { + animation: { duration: 0 }, + targetZoom: 1, + }) } - } - // Handle shape-specific logic - else if (shapeId) { - const shape = editor.getShape(shapeId as TLShapeId) - if (shape) { - editor.select(shapeId as TLShapeId) - } else { - console.warn("Shape not found:", shapeId) + + // Apply camera lock after camera is positioned + if (isLocked) { + // Use requestAnimationFrame to ensure camera is set before locking + requestAnimationFrame(() => { + editor.setCameraOptions({ + isLocked: true, + // Optional: you may want to also set these options for locked frames + //shouldSnapToGrid: false, + //shouldUseEdgeScrolling: false, + }) + }) } + } else { + console.warn("Frame not found:", frameId) } - }) + } }