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, assertNever,
COLOR_PALETTE, COLOR_PALETTE,
LINE_POLYGON_POINT_MERGE_DISTANCE, LINE_POLYGON_POINT_MERGE_DISTANCE,
THEME,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { RoughGenerator } from "roughjs/bin/generator"; import { RoughGenerator } from "roughjs/bin/generator";
@@ -33,7 +32,6 @@ import type { Mutable } from "@excalidraw/common/utility-types";
import type { import type {
AppState, AppState,
EmbedsValidationStatus, EmbedsValidationStatus,
InteractiveCanvasAppState,
} from "@excalidraw/excalidraw/types"; } from "@excalidraw/excalidraw/types";
import type { import type {
ElementShape, ElementShape,
@@ -72,7 +70,6 @@ import type {
ExcalidrawFreeDrawElement, ExcalidrawFreeDrawElement,
ElementsMap, ElementsMap,
ExcalidrawLineElement, ExcalidrawLineElement,
ExcalidrawBindableElement,
} from "./types"; } from "./types";
import type { Drawable, Options } from "roughjs/bin/core"; import type { Drawable, Options } from "roughjs/bin/core";
@@ -108,31 +105,6 @@ export class ShapeCache {
ShapeCache.cache = new WeakMap(); 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 * Generates & caches shape for element if not already cached, otherwise
* returns cached shape. * returns cached shape.

View File

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