[debug] 2

This commit is contained in:
dwelle 2024-02-07 16:10:47 +01:00
parent 72de65e482
commit d5f55aba44
2 changed files with 207 additions and 21 deletions

View file

@ -27,6 +27,7 @@ import {
LiveCollaborationTrigger, LiveCollaborationTrigger,
TTDDialog, TTDDialog,
TTDDialogTrigger, TTDDialogTrigger,
getCommonBounds,
} from "../packages/excalidraw/index"; } from "../packages/excalidraw/index";
import { import {
AppState, AppState,
@ -35,6 +36,7 @@ import {
BinaryFiles, BinaryFiles,
ExcalidrawInitialDataState, ExcalidrawInitialDataState,
UIAppState, UIAppState,
ScrollConstraints,
} from "../packages/excalidraw/types"; } from "../packages/excalidraw/types";
import { import {
debounce, debounce,
@ -98,15 +100,161 @@ import { useAtomWithInitialValue } from "../packages/excalidraw/jotai";
import { appJotaiStore } from "./app-jotai"; import { appJotaiStore } from "./app-jotai";
import "./index.scss"; import "./index.scss";
import { ResolutionType } from "../packages/excalidraw/utility-types"; import { Merge, ResolutionType } from "../packages/excalidraw/utility-types";
import { ShareableLinkDialog } from "../packages/excalidraw/components/ShareableLinkDialog"; import { ShareableLinkDialog } from "../packages/excalidraw/components/ShareableLinkDialog";
import { openConfirmModal } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState"; import { openConfirmModal } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState";
import { OverwriteConfirmDialog } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm"; import { OverwriteConfirmDialog } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm";
import Trans from "../packages/excalidraw/components/Trans"; import Trans from "../packages/excalidraw/components/Trans";
import { ShareDialog, shareDialogStateAtom } from "./share/ShareDialog"; import { ShareDialog, shareDialogStateAtom } from "./share/ShareDialog";
import { getSelectedElements } from "../packages/excalidraw/scene";
polyfill(); polyfill();
type DebugScrollConstraints = Merge<
ScrollConstraints,
{ viewportZoomFactor: number; enabled: boolean }
>;
const ConstraintsSettings = ({
initialConstraints,
excalidrawAPI,
}: {
initialConstraints: DebugScrollConstraints;
excalidrawAPI: ExcalidrawImperativeAPI;
}) => {
const [constraints, setConstraints] =
useState<DebugScrollConstraints>(initialConstraints);
useEffect(() => {
// add JSON-stringified constraints into url hash for easy sharing
const hash = new URLSearchParams(window.location.hash.slice(1));
hash.set(
"constraints",
encodeURIComponent(
window.btoa(JSON.stringify(constraints)).replace(/=+/, ""),
),
);
window.location.hash = decodeURIComponent(hash.toString());
}, [constraints]);
const [selection, setSelection] = useState<ExcalidrawElement[]>([]);
useEffect(() => {
return excalidrawAPI.onChange((elements, appState) => {
setSelection(getSelectedElements(elements, appState));
});
}, [excalidrawAPI]);
return (
<div
style={{
display: "flex",
position: "fixed",
bottom: 10,
left: "calc(50%)",
transform: "translateX(-50%)",
gap: "0.6rem",
zIndex: 999999,
}}
>
enabled:{" "}
<input
type="checkbox"
defaultChecked={!!constraints.enabled}
onChange={(e) =>
setConstraints((s) => ({ ...s, enabled: e.target.checked }))
}
/>
x:{" "}
<input
placeholder="x"
size={4}
value={constraints.x.toString()}
onChange={(e) =>
setConstraints((s) => ({
...s,
x: parseInt(e.target.value) ?? 0,
}))
}
/>
y:{" "}
<input
placeholder="y"
size={4}
value={constraints.y.toString()}
onChange={(e) =>
setConstraints((s) => ({
...s,
y: parseInt(e.target.value) ?? 0,
}))
}
/>
w:{" "}
<input
placeholder="width"
size={4}
value={constraints.width.toString()}
onChange={(e) =>
setConstraints((s) => ({
...s,
x: parseInt(e.target.value) ?? 200,
}))
}
/>
h:{" "}
<input
placeholder="height"
size={4}
value={constraints.height.toString()}
onChange={(e) =>
setConstraints((s) => ({
...s,
x: parseInt(e.target.value) ?? 200,
}))
}
/>
zoomFactor:
<input
placeholder="height"
type="number"
min="0.1"
max="1"
step="0.1"
value={constraints.viewportZoomFactor.toString()}
onChange={(e) =>
setConstraints((s) => ({
...s,
viewportZoomFactor: parseFloat(e.target.value.toString()) ?? 0.7,
}))
}
/>
lockZoom:{" "}
<input
type="checkbox"
defaultChecked={!!constraints.lockZoom}
onChange={(e) =>
setConstraints((s) => ({ ...s, lockZoom: e.target.checked }))
}
/>
{selection.length > 0 && (
<button
onClick={() => {
const bbox = getCommonBounds(selection);
setConstraints((s) => ({
...s,
x: Math.round(bbox[0]),
y: Math.round(bbox[1]),
width: Math.round(bbox[2] - bbox[0]),
height: Math.round(bbox[3] - bbox[1]),
}));
}}
>
use selection
</button>
)}
</div>
);
};
window.EXCALIDRAW_THROTTLE_RENDER = true; window.EXCALIDRAW_THROTTLE_RENDER = true;
let isSelfEmbedding = false; let isSelfEmbedding = false;
@ -151,10 +299,22 @@ const initializeScene = async (opts: {
) )
> => { > => {
const searchParams = new URLSearchParams(window.location.search); const searchParams = new URLSearchParams(window.location.search);
const hashParams = new URLSearchParams(window.location.hash.slice(1));
const id = searchParams.get("id"); const id = searchParams.get("id");
const jsonBackendMatch = window.location.hash.match( const shareableLink = hashParams.get("json")?.split(",");
/^#json=([a-zA-Z0-9_-]+),([a-zA-Z0-9_-]+)$/,
if (shareableLink) {
hashParams.delete("json");
const hash = `#${decodeURIComponent(hashParams.toString())}`;
window.history.replaceState(
{},
APP_NAME,
`${window.location.origin}${hash}`,
); );
}
console.log({ shareableLink });
const externalUrlMatch = window.location.hash.match(/^#url=(.*)$/); const externalUrlMatch = window.location.hash.match(/^#url=(.*)$/);
const localDataState = importFromLocalStorage(); const localDataState = importFromLocalStorage();
@ -164,7 +324,7 @@ const initializeScene = async (opts: {
} = await loadScene(null, null, localDataState); } = await loadScene(null, null, localDataState);
let roomLinkData = getCollaborationLinkData(window.location.href); let roomLinkData = getCollaborationLinkData(window.location.href);
const isExternalScene = !!(id || jsonBackendMatch || roomLinkData); const isExternalScene = !!(id || shareableLink || roomLinkData);
if (isExternalScene) { if (isExternalScene) {
if ( if (
// don't prompt if scene is empty // don't prompt if scene is empty
@ -174,16 +334,17 @@ const initializeScene = async (opts: {
// otherwise, prompt whether user wants to override current scene // otherwise, prompt whether user wants to override current scene
(await openConfirmModal(shareableLinkConfirmDialog)) (await openConfirmModal(shareableLinkConfirmDialog))
) { ) {
if (jsonBackendMatch) { if (shareableLink) {
scene = await loadScene( scene = await loadScene(
jsonBackendMatch[1], shareableLink[0],
jsonBackendMatch[2], shareableLink[1],
localDataState, localDataState,
); );
console.log(">>>>", scene);
} }
scene.scrollToContent = true; scene.scrollToContent = true;
if (!roomLinkData) { if (!roomLinkData) {
window.history.replaceState({}, APP_NAME, window.location.origin); // window.history.replaceState({}, APP_NAME, window.location.origin);
} }
} else { } else {
// https://github.com/excalidraw/excalidraw/issues/1919 // https://github.com/excalidraw/excalidraw/issues/1919
@ -200,7 +361,7 @@ const initializeScene = async (opts: {
} }
roomLinkData = null; roomLinkData = null;
window.history.replaceState({}, APP_NAME, window.location.origin); // window.history.replaceState({}, APP_NAME, window.location.origin);
} }
} else if (externalUrlMatch) { } else if (externalUrlMatch) {
window.history.replaceState({}, APP_NAME, window.location.origin); window.history.replaceState({}, APP_NAME, window.location.origin);
@ -261,12 +422,12 @@ const initializeScene = async (opts: {
key: roomLinkData.roomKey, key: roomLinkData.roomKey,
}; };
} else if (scene) { } else if (scene) {
return isExternalScene && jsonBackendMatch return isExternalScene && shareableLink
? { ? {
scene, scene,
isExternalScene, isExternalScene,
id: jsonBackendMatch[1], id: shareableLink[0],
key: jsonBackendMatch[2], key: shareableLink[1],
} }
: { scene, isExternalScene: false }; : { scene, isExternalScene: false };
} }
@ -672,6 +833,31 @@ const ExcalidrawWrapper = () => {
[setShareDialogState], [setShareDialogState],
); );
const [constraints] = useState<DebugScrollConstraints>(() => {
const stored = new URLSearchParams(location.hash.slice(1)).get(
"constraints",
);
let storedConstraints = {};
if (stored) {
try {
storedConstraints = JSON.parse(window.atob(stored));
} catch {}
}
return {
x: 0,
y: 0,
width: document.body.clientWidth,
height: document.body.clientHeight,
lockZoom: false,
viewportZoomFactor: 0.7,
enabled: true,
...storedConstraints,
};
});
console.log(constraints);
// browsers generally prevent infinite self-embedding, there are // browsers generally prevent infinite self-embedding, there are
// cases where it still happens, and while we disallow self-embedding // cases where it still happens, and while we disallow self-embedding
// by not whitelisting our own origin, this serves as an additional guard // by not whitelisting our own origin, this serves as an additional guard
@ -753,14 +939,14 @@ const ExcalidrawWrapper = () => {
/> />
); );
}} }}
scrollConstraints={{ scrollConstraints={constraints.enabled ? constraints : undefined}
x: 0,
y: 0,
width: 2560,
height: 1300,
lockZoom: false,
}}
> >
{excalidrawAPI && (
<ConstraintsSettings
excalidrawAPI={excalidrawAPI}
initialConstraints={constraints}
/>
)}
<AppMainMenu <AppMainMenu
onCollabDialogOpen={onCollabDialogOpen} onCollabDialogOpen={onCollabDialogOpen}
isCollaborating={isCollaborating} isCollaborating={isCollaborating}

View file

@ -77,7 +77,7 @@ const calculateZoomLevel = (
width: AppState["width"], width: AppState["width"],
height: AppState["height"], height: AppState["height"],
) => { ) => {
const DEFAULT_VIEWPORT_ZOOM_FACTOR = 0.7; const DEFAULT_VIEWPORT_ZOOM_FACTOR = 0.2;
const viewportZoomFactor = scrollConstraints.viewportZoomFactor const viewportZoomFactor = scrollConstraints.viewportZoomFactor
? Math.min(1, Math.max(scrollConstraints.viewportZoomFactor, 0.1)) ? Math.min(1, Math.max(scrollConstraints.viewportZoomFactor, 0.1))