fix: Binding highlight stroke on sharp bindables

This commit is contained in:
Mark Tolmacs
2025-09-11 20:48:37 +02:00
parent 434ed03f1e
commit e5c7a6304e
2 changed files with 54 additions and 98 deletions

View File

@@ -21,7 +21,6 @@ import {
assertNever,
COLOR_PALETTE,
LINE_POLYGON_POINT_MERGE_DISTANCE,
THEME,
} from "@excalidraw/common";
import { RoughGenerator } from "roughjs/bin/generator";
@@ -33,7 +32,6 @@ import type { Mutable } from "@excalidraw/common/utility-types";
import type {
AppState,
EmbedsValidationStatus,
InteractiveCanvasAppState,
} from "@excalidraw/excalidraw/types";
import type {
ElementShape,
@@ -72,7 +70,6 @@ import type {
ExcalidrawFreeDrawElement,
ElementsMap,
ExcalidrawLineElement,
ExcalidrawBindableElement,
} from "./types";
import type { Drawable, Options } from "roughjs/bin/core";
@@ -108,31 +105,6 @@ export class ShapeCache {
ShapeCache.cache = new WeakMap();
};
public static generateBindableElementHighlight = <
T extends ExcalidrawBindableElement,
>(
element: T,
appState: Pick<InteractiveCanvasAppState, "theme">,
) => {
let shape =
(ShapeCache.get(element) as Drawable | null) ||
(ShapeCache.rg.rectangle(0, 0, element.width, element.height, {
roughness: 0,
strokeWidth: 2,
}) as Drawable);
// Clone the shape from the cache
shape = {
...shape,
options: {
...shape.options,
stroke: appState.theme === THEME.DARK ? "#035da1" : "#6abdfc",
},
};
return shape;
};
/**
* Generates & caches shape for element if not already cached, otherwise
* returns cached shape.

View File

@@ -17,11 +17,7 @@ import {
throttleRAF,
} from "@excalidraw/common";
import {
LinearElementEditor,
renderElement,
ShapeCache,
} from "@excalidraw/element";
import { LinearElementEditor, renderElement } from "@excalidraw/element";
import {
getOmitSidesForDevice,
getTransformHandles,
@@ -196,11 +192,6 @@ const renderBindingHighlightForBindableElement = (
switch (element.type) {
case "magicframe":
case "frame":
{
const {
options: { stroke: highlightStroke },
} = ShapeCache.generateBindableElementHighlight(element, appState);
context.save();
context.translate(
element.x + appState.scrollX,
@@ -208,7 +199,8 @@ const renderBindingHighlightForBindableElement = (
);
context.lineWidth = FRAME_STYLE.strokeWidth / appState.zoom.value;
context.strokeStyle = highlightStroke;
context.strokeStyle =
appState.theme === THEME.DARK ? "#035da1" : "#6abdfc";
if (FRAME_STYLE.radius && context.roundRect) {
context.beginPath();
@@ -226,15 +218,9 @@ const renderBindingHighlightForBindableElement = (
}
context.restore();
}
break;
case "image":
case "text":
{
const {
options: { stroke: highlightStroke },
} = ShapeCache.generateBindableElementHighlight(element, appState);
context.save();
context.translate(
element.x + appState.scrollX,
@@ -242,37 +228,35 @@ const renderBindingHighlightForBindableElement = (
);
context.lineWidth = FRAME_STYLE.strokeWidth / appState.zoom.value;
context.strokeStyle = highlightStroke;
context.strokeStyle =
appState.theme === THEME.DARK ? "#035da1" : "#6abdfc";
context.strokeRect(0, 0, element.width, element.height);
context.restore();
}
break;
default:
const cx =
(element.x + element.width / 2 + appState.scrollX) *
window.devicePixelRatio;
const cy =
(element.y + element.height / 2 + appState.scrollY) *
window.devicePixelRatio;
context.save();
context.translate(cx, cy);
context.rotate(element.angle);
context.translate(-cx, -cy);
context.translate(
appState.scrollX + element.x,
appState.scrollY + element.y,
);
const drawable = ShapeCache.generateBindableElementHighlight(
element,
renderElement(
{
...element,
strokeColor: appState.theme === THEME.DARK ? "#035da1" : "#6abdfc",
fillStyle: "solid",
backgroundColor: "transparent",
},
elementsMap,
allElementsMap,
rough.canvas(context.canvas),
context,
{
canvasBackgroundColor: "transparent",
imageCache: new Map(),
renderGrid: false,
isExporting: false,
embedsValidationStatus: new Map(),
elementsPendingErasure: new Set(),
pendingFlowchartNodes: null,
},
appState,
);
drawable.options.fill = "transparent";
rough.canvas(context.canvas).draw(drawable);
context.restore();
// Overdraw the arrow if exists (if there is a suggestedBinding it's an arrow)
if (appState.selectedLinearElement) {