Merge commit

This commit is contained in:
Mark Tolmacs
2025-11-10 16:15:28 +01:00
86 changed files with 7110 additions and 5308 deletions

View File

@@ -15,7 +15,6 @@ import {
getGlobalFixedPointForBindableElement,
isArrowElement,
isBindableElement,
isFixedPointBinding,
} from "@excalidraw/element";
import {
@@ -35,7 +34,6 @@ import type {
ExcalidrawBindableElement,
FixedPointBinding,
OrderedExcalidrawElement,
PointBinding,
} from "@excalidraw/element/types";
import { STORAGE_KEYS } from "../app_constants";
@@ -44,7 +42,7 @@ const renderLine = (
context: CanvasRenderingContext2D,
zoom: number,
segment: LineSegment<GlobalPoint>,
color: string,
color: string
) => {
context.save();
context.strokeStyle = color;
@@ -59,7 +57,7 @@ const renderCubicBezier = (
context: CanvasRenderingContext2D,
zoom: number,
[start, control1, control2, end]: Curve<GlobalPoint>,
color: string,
color: string
) => {
context.save();
context.strokeStyle = color;
@@ -71,7 +69,7 @@ const renderCubicBezier = (
control2[0] * zoom,
control2[1] * zoom,
end[0] * zoom,
end[1] * zoom,
end[1] * zoom
);
context.stroke();
context.restore();
@@ -91,92 +89,88 @@ const renderOrigin = (context: CanvasRenderingContext2D, zoom: number) => {
const _renderBinding = (
context: CanvasRenderingContext2D,
binding: FixedPointBinding | PointBinding,
binding: FixedPointBinding,
elementsMap: ElementsMap,
zoom: number,
width: number,
height: number,
color: string,
color: string
) => {
if (isFixedPointBinding(binding)) {
if (!binding.fixedPoint) {
console.warn("Binding must have a fixedPoint");
return;
}
const bindable = elementsMap.get(
binding.elementId,
) as ExcalidrawBindableElement;
const [x, y] = getGlobalFixedPointForBindableElement(
binding.fixedPoint,
bindable,
elementsMap,
);
context.save();
context.strokeStyle = color;
context.lineWidth = 1;
context.beginPath();
context.moveTo(x * zoom, y * zoom);
context.bezierCurveTo(
x * zoom - width,
y * zoom - height,
x * zoom - width,
y * zoom + height,
x * zoom,
y * zoom,
);
context.stroke();
context.restore();
if (!binding.fixedPoint) {
console.warn("Binding must have a fixedPoint");
return;
}
const bindable = elementsMap.get(
binding.elementId
) as ExcalidrawBindableElement;
const [x, y] = getGlobalFixedPointForBindableElement(
binding.fixedPoint,
bindable,
elementsMap
);
context.save();
context.strokeStyle = color;
context.lineWidth = 1;
context.beginPath();
context.moveTo(x * zoom, y * zoom);
context.bezierCurveTo(
x * zoom - width,
y * zoom - height,
x * zoom - width,
y * zoom + height,
x * zoom,
y * zoom
);
context.stroke();
context.restore();
};
const _renderBindableBinding = (
binding: FixedPointBinding | PointBinding,
binding: FixedPointBinding,
context: CanvasRenderingContext2D,
elementsMap: ElementsMap,
zoom: number,
width: number,
height: number,
color: string,
color: string
) => {
if (isFixedPointBinding(binding)) {
const bindable = elementsMap.get(
binding.elementId,
) as ExcalidrawBindableElement;
if (!binding.fixedPoint) {
console.warn("Binding must have a fixedPoint");
return;
}
const [x, y] = getGlobalFixedPointForBindableElement(
binding.fixedPoint,
bindable,
elementsMap,
);
context.save();
context.strokeStyle = color;
context.lineWidth = 1;
context.beginPath();
context.moveTo(x * zoom, y * zoom);
context.bezierCurveTo(
x * zoom + width,
y * zoom + height,
x * zoom + width,
y * zoom - height,
x * zoom,
y * zoom,
);
context.stroke();
context.restore();
const bindable = elementsMap.get(
binding.elementId
) as ExcalidrawBindableElement;
if (!binding.fixedPoint) {
console.warn("Binding must have a fixedPoint");
return;
}
const [x, y] = getGlobalFixedPointForBindableElement(
binding.fixedPoint,
bindable,
elementsMap
);
context.save();
context.strokeStyle = color;
context.lineWidth = 1;
context.beginPath();
context.moveTo(x * zoom, y * zoom);
context.bezierCurveTo(
x * zoom + width,
y * zoom + height,
x * zoom + width,
y * zoom - height,
x * zoom,
y * zoom
);
context.stroke();
context.restore();
};
const renderBindings = (
context: CanvasRenderingContext2D,
elements: readonly OrderedExcalidrawElement[],
zoom: number,
zoom: number
) => {
const elementsMap = arrayToMap(elements);
const dim = 16;
@@ -197,12 +191,12 @@ const renderBindings = (
_renderBinding(
context,
element.startBinding as FixedPointBinding,
element.startBinding,
elementsMap,
zoom,
dim,
dim,
"red",
element.startBinding?.mode === "orbit" ? "red" : "black"
);
}
@@ -221,7 +215,7 @@ const renderBindings = (
zoom,
dim,
dim,
"red",
element.endBinding?.mode === "orbit" ? "red" : "black"
);
}
}
@@ -233,7 +227,7 @@ const renderBindings = (
}
const arrow = elementsMap.get(
boundElement.id,
boundElement.id
) as ExcalidrawArrowElement;
if (arrow && arrow.startBinding?.elementId === element.id) {
@@ -244,7 +238,7 @@ const renderBindings = (
zoom,
dim,
dim,
"green",
"green"
);
}
if (arrow && arrow.endBinding?.elementId === element.id) {
@@ -255,7 +249,7 @@ const renderBindings = (
zoom,
dim,
dim,
"green",
"green"
);
}
});
@@ -266,7 +260,7 @@ const renderBindings = (
const render = (
frame: DebugElement[],
context: CanvasRenderingContext2D,
appState: AppState,
appState: AppState
) => {
frame.forEach((el: DebugElement) => {
switch (true) {
@@ -275,7 +269,7 @@ const render = (
context,
appState.zoom.value,
el.data as LineSegment<GlobalPoint>,
el.color,
el.color
);
break;
case isCurve(el.data):
@@ -283,7 +277,7 @@ const render = (
context,
appState.zoom.value,
el.data as Curve<GlobalPoint>,
el.color,
el.color
);
break;
default:
@@ -296,11 +290,11 @@ const _debugRenderer = (
canvas: HTMLCanvasElement,
appState: AppState,
elements: readonly OrderedExcalidrawElement[],
scale: number,
scale: number
) => {
const [normalizedWidth, normalizedHeight] = getNormalizedCanvasDimensions(
canvas,
scale,
scale
);
const context = bootstrapCanvas({
@@ -315,7 +309,7 @@ const _debugRenderer = (
context.save();
context.translate(
appState.scrollX * appState.zoom.value,
appState.scrollY * appState.zoom.value,
appState.scrollY * appState.zoom.value
);
renderOrigin(context, appState.zoom.value);
@@ -340,7 +334,7 @@ const _debugRenderer = (
if (window.visualDebug) {
window.visualDebug!.data =
window.visualDebug?.data.map((frame) =>
frame.filter((el) => el.permanent),
frame.filter((el) => el.permanent)
) ?? [];
}
};
@@ -360,7 +354,7 @@ export const saveDebugState = (debug: { enabled: boolean }) => {
try {
localStorage.setItem(
STORAGE_KEYS.LOCAL_STORAGE_DEBUG,
JSON.stringify(debug),
JSON.stringify(debug)
);
} catch (error: any) {
console.error(error);
@@ -372,18 +366,18 @@ export const debugRenderer = throttleRAF(
canvas: HTMLCanvasElement,
appState: AppState,
elements: readonly OrderedExcalidrawElement[],
scale: number,
scale: number
) => {
_debugRenderer(canvas, appState, elements, scale);
},
{ trailing: true },
{ trailing: true }
);
export const loadSavedDebugState = () => {
let debug;
try {
const savedDebugState = localStorage.getItem(
STORAGE_KEYS.LOCAL_STORAGE_DEBUG,
STORAGE_KEYS.LOCAL_STORAGE_DEBUG
);
if (savedDebugState) {
debug = JSON.parse(savedDebugState) as { enabled: boolean };
@@ -523,7 +517,7 @@ const DebugCanvas = React.forwardRef<HTMLCanvasElement, DebugCanvasProps>(
Debug Canvas
</canvas>
);
},
}
);
export default DebugCanvas;