chore:Basic interactive canvas animation re-render trigger for highlights

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs
2025-09-16 20:35:17 +02:00
parent 5b77409eff
commit 345e3f68f1
4 changed files with 54 additions and 2 deletions

View File

@@ -135,7 +135,7 @@ export const actionFinalize = register<FormData>({
}
const activeToolLocked = appState.activeTool?.locked;
console.log("finalize - activeToolLocked:", activeToolLocked);
return {
elements:
element.points.length < 2 || isInvisiblySmallElement(element)

View File

@@ -619,7 +619,7 @@ class App extends React.Component<AppProps, AppState> {
public flowChartCreator: FlowChartCreator = new FlowChartCreator();
private flowChartNavigator: FlowChartNavigator = new FlowChartNavigator();
private bindModeHandler: ReturnType<typeof setTimeout> | null = null;
bindModeHandler: ReturnType<typeof setTimeout> | null = null;
hitLinkElement?: NonDeletedExcalidrawElement;
lastPointerDownEvent: React.PointerEvent<HTMLElement> | null = null;

View File

@@ -1,12 +1,14 @@
import React, { useEffect, useRef } from "react";
import {
BIND_MODE_TIMEOUT,
CURSOR_TYPE,
isShallowEqual,
sceneCoordsToViewportCoords,
} from "@excalidraw/common";
import type {
ExcalidrawBindableElement,
NonDeletedExcalidrawElement,
NonDeletedSceneElementsMap,
} from "@excalidraw/element/types";
@@ -79,6 +81,54 @@ type InteractiveCanvasProps = {
const InteractiveCanvas = (props: InteractiveCanvasProps) => {
const isComponentMounted = useRef(false);
// START - Binding highlight timeout animation
const currentSuggestedBinding = useRef<ExcalidrawBindableElement | null>(
null,
);
const animationInterval = useRef<NodeJS.Timeout | null>(null);
const [animationFrameCount, triggerAnnimationRerender] = React.useState(0);
if (props.app.state.suggestedBinding === null && animationInterval.current) {
clearInterval(animationInterval.current);
animationInterval.current = null;
triggerAnnimationRerender(0);
}
if (currentSuggestedBinding.current !== props.appState.suggestedBinding) {
if (animationInterval.current !== null) {
currentSuggestedBinding.current = props.appState.suggestedBinding;
clearInterval(animationInterval.current);
animationInterval.current = null;
triggerAnnimationRerender(0);
}
}
if (
animationFrameCount > BIND_MODE_TIMEOUT / 10 &&
animationInterval.current
) {
clearInterval(animationInterval.current);
animationInterval.current = null;
triggerAnnimationRerender(0);
} else if (
props.app.state.bindMode === "orbit" &&
props.app.bindModeHandler // Timeout is running
) {
if (animationInterval.current === null) {
animationInterval.current = setInterval(() => {
triggerAnnimationRerender((count) => count + 1);
}, 1000 / 60 /* 60 FPS animation */);
}
} else {
// eslint-disable-next-line no-lonely-if
if (animationInterval.current) {
clearInterval(animationInterval.current);
animationInterval.current = null;
triggerAnnimationRerender(0);
}
}
// END - Binding highlight timeout animation
useEffect(() => {
if (!isComponentMounted.current) {
isComponentMounted.current = true;

View File

@@ -747,6 +747,8 @@ export type AppClassProperties = {
updateEditorAtom: App["updateEditorAtom"];
defaultSelectionTool: "selection" | "lasso";
bindModeHandler: App["bindModeHandler"];
};
export type PointerDownState = Readonly<{