Skip to content

Commit aed1b65

Browse files
committed
fix(canvas): improve rounded rectangle rendering with Rough.js
1 parent aff9152 commit aed1b65

File tree

2 files changed

+47
-40
lines changed

2 files changed

+47
-40
lines changed

apps/collabydraw/canvas-engine/CanvasEngine.ts

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ import {
3030
getDashArrayDashed,
3131
getDashArrayDotted,
3232
RECT_CORNER_RADIUS_FACTOR,
33+
ROUND_RADIUS_FACTOR,
3334
WS_URL,
3435
} from "@/config/constants";
3536
import { MessageQueue } from "./MessageQueue";
3637
import { decryptData, encryptData } from "@/utils/crypto";
37-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
38-
// @ts-expect-error
39-
import { RoughCanvas } from "roughjs/canvas";
40-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
41-
// @ts-expect-error
42-
import { Options } from "roughjs/core";
38+
4339
import rough from "roughjs/bin/rough";
40+
import { RoughCanvas } from "roughjs/bin/canvas";
41+
import { Options } from "roughjs/bin/core";
42+
import type { Point } from "roughjs/bin/geometry";
43+
4444
import { getFontSize, getLineHeight } from "@/utils/textUtils";
4545
import { generateFreeDrawPath } from "./RenderElements";
4646

@@ -382,11 +382,15 @@ export class CanvasEngine {
382382
bgFill?: string,
383383
strokeStyle?: StrokeStyle,
384384
fillStyle?: FillStyle,
385-
hachureAngle: number = 60
385+
hachureAngle: number = 60,
386+
shapeType?: Shape["type"]
386387
): Options {
388+
const isCurveSensitive =
389+
shapeType === "ellipse" || shapeType === "free-draw";
390+
387391
const options: Options = {
388392
stroke: strokeFill,
389-
strokeWidth: strokeStyle !== "solid" ? strokeWidth + 0.5 : strokeWidth,
393+
strokeWidth: strokeStyle !== "solid" ? strokeWidth + 0.6 : strokeWidth,
390394
roughness: roughStyle,
391395
bowing: roughStyle === 0 ? 0 : 0.5 * roughStyle,
392396
fill: bgFill ?? "",
@@ -403,16 +407,26 @@ export class CanvasEngine {
403407
: strokeStyle === "dotted"
404408
? getDashArrayDotted(strokeWidth)
405409
: undefined,
410+
dashOffset:
411+
strokeStyle === "dashed" ? 5 : strokeStyle === "dotted" ? 2 : undefined,
412+
...(isCurveSensitive
413+
? {}
414+
: {
415+
curveFitting: 1,
416+
curveTightness: 1,
417+
preserveVertices: true,
418+
}),
419+
420+
// Ensure the sketchy path closely follows the original shape with minimal deviation
421+
// curveFitting: 1,
422+
423+
// Tightens the curves around corner control points for smoother rounded corners
424+
// curveTightness: 1,
425+
426+
// Prevents Rough.js from altering the actual vertex points — keeps the shape precise
427+
// preserveVertices: true,
406428
};
407429

408-
if (strokeStyle === "dashed") {
409-
options.dashOffset = 5;
410-
options.dashArray = getDashArrayDashed(strokeWidth);
411-
} else if (strokeStyle === "dotted") {
412-
options.dashOffset = 2;
413-
options.dashArray = getDashArrayDotted(strokeWidth);
414-
}
415-
416430
return options;
417431
}
418432

@@ -1369,28 +1383,19 @@ export class CanvasEngine {
13691383
);
13701384

13711385
if (rounded === "round") {
1372-
const radius = Math.min(
1373-
Math.abs(
1374-
Math.max(normalizedWidth, normalizedHeight) /
1375-
RECT_CORNER_RADIUS_FACTOR
1376-
),
1377-
normalizedWidth / 2,
1378-
normalizedHeight / 2
1379-
);
1380-
options.curveFitting = 1;
1381-
options.curveTightness = 1;
1386+
const r = Math.min(normalizedWidth, normalizedHeight) * ROUND_RADIUS_FACTOR;
13821387

13831388
this.roughCanvas.path(
1384-
`M ${posX + radius} ${posY}
1385-
L ${posX + normalizedWidth - radius} ${posY}
1386-
Q ${posX + normalizedWidth} ${posY} ${posX + normalizedWidth} ${posY + radius}
1387-
L ${posX + normalizedWidth} ${posY + normalizedHeight - radius}
1388-
Q ${posX + normalizedWidth} ${posY + normalizedHeight} ${posX + normalizedWidth - radius} ${posY + normalizedHeight}
1389-
L ${posX + radius} ${posY + normalizedHeight}
1390-
Q ${posX} ${posY + normalizedHeight} ${posX} ${posY + normalizedHeight - radius}
1391-
L ${posX} ${posY + radius}
1392-
Q ${posX} ${posY} ${posX + radius} ${posY}
1393-
Z`,
1389+
`M ${posX + r} ${posY}
1390+
L ${posX + normalizedWidth - r} ${posY}
1391+
Q ${posX + normalizedWidth} ${posY}, ${posX + normalizedWidth} ${posY + r}
1392+
L ${posX + normalizedWidth} ${posY + normalizedHeight - r}
1393+
Q ${posX + normalizedWidth} ${posY + normalizedHeight}, ${posX + normalizedWidth - r} ${posY + normalizedHeight}
1394+
L ${posX + r} ${posY + normalizedHeight}
1395+
Q ${posX} ${posY + normalizedHeight}, ${posX} ${posY + normalizedHeight - r}
1396+
L ${posX} ${posY + r}
1397+
Q ${posX} ${posY}, ${posX + r} ${posY}
1398+
Z`,
13941399
options
13951400
);
13961401
} else {
@@ -1447,7 +1452,9 @@ export class CanvasEngine {
14471452
roughStyle,
14481453
bgFill,
14491454
strokeStyle,
1450-
fillStyle
1455+
fillStyle,
1456+
60,
1457+
"ellipse"
14511458
);
14521459
this.roughCanvas.ellipse(
14531460
x,
@@ -1589,7 +1596,7 @@ export class CanvasEngine {
15891596
fillStyle
15901597
);
15911598

1592-
const diamondPoints = [
1599+
const diamondPoints: Point[] = [
15931600
[centerX, centerY - halfHeight],
15941601
[centerX + halfWidth, centerY],
15951602
[centerX, centerY + halfHeight],

apps/collabydraw/config/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export const CORNER_RADIUS_FACTOR = 20;
2+
export const ROUND_RADIUS_FACTOR = 0.25;
23
export const RECT_CORNER_RADIUS_FACTOR = CORNER_RADIUS_FACTOR;
34
export const DIAMOND_CORNER_RADIUS_PERCENTAGE = CORNER_RADIUS_FACTOR;
45
export const ERASER_TOLERANCE = 5;
@@ -15,6 +16,5 @@ export const getDashArrayDotted = (strokeWidth: number) => [
1516
strokeWidth * 2,
1617
];
1718

18-
export const BASE_URL =
19-
process.env.NEXT_PUBLIC_BASE_URL;
19+
export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
2020
export const WS_URL = process.env.NEXT_PUBLIC_WS_URL;

0 commit comments

Comments
 (0)