From b1f3cc50ee34d5df834f07ad2630c64deed6bc30 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 16 Jun 2025 22:06:10 +1000 Subject: [PATCH] tweak stroke widths --- packages/common/src/constants.ts | 7 +-- packages/element/src/freedraw.ts | 24 ++++----- .../actions/actionProperties.test.tsx | 9 ++-- .../excalidraw/actions/actionProperties.tsx | 53 ++++++++++++------- packages/excalidraw/components/icons.tsx | 15 +++++- .../__snapshots__/contextmenu.test.tsx.snap | 49 ++++++++++++----- .../tests/__snapshots__/history.test.tsx.snap | 10 ++-- .../regressionTests.test.tsx.snap | 6 +-- .../excalidraw/tests/actionStyles.test.tsx | 2 +- .../excalidraw/tests/contextmenu.test.tsx | 2 +- 10 files changed, 111 insertions(+), 66 deletions(-) diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index b9e5661a9..e3c53820e 100644 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -385,8 +385,9 @@ export const ROUGHNESS = { export const STROKE_WIDTH = { thin: 1, - bold: 2, - extraBold: 4, + medium: 2, + bold: 4, + extraBold: 6, } as const; export const DEFAULT_ELEMENT_PROPS: { @@ -402,7 +403,7 @@ export const DEFAULT_ELEMENT_PROPS: { strokeColor: COLOR_PALETTE.black, backgroundColor: COLOR_PALETTE.transparent, fillStyle: "solid", - strokeWidth: 2, + strokeWidth: STROKE_WIDTH.medium, strokeStyle: "solid", roughness: ROUGHNESS.artist, opacity: 100, diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 7f984f6d3..90b5fed68 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -10,7 +10,7 @@ import type { ExcalidrawFreeDrawElement } from "./types"; export const DRAWING_CONFIGS = { default: { - streamline: 0.25, + streamline: 0.35, simplify: 0.25, }, // for optimal performance, we use a lower streamline and simplify @@ -62,10 +62,7 @@ const calculateVelocityBasedPressure = ( return Math.max(0.1, Math.min(1.0, pressure)); }; -export const getFreedrawStroke = ( - element: ExcalidrawFreeDrawElement, - debugParams?: { streamline?: number; simplify?: number }, -) => { +export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { // Compose points as [x, y, pressure] let points: [number, number, number][]; if (element.simulatePressure) { @@ -105,17 +102,15 @@ export const getFreedrawStroke = ( streamline, simplify, sizeMapping: ({ pressure: t }) => { - if (element.simulatePressure) { - return t + 0.2; - } - if (element.drawingConfigs?.pressureSensitivity === 0) { - return 1; + return 0.5; } - const minSize = 0.2; - const maxSize = 2; - return minSize + t * (maxSize - minSize); + if (element.simulatePressure) { + return 0.2 + t * 0.6; + } + + return 0.2 + t * 0.8; }, }); @@ -134,14 +129,13 @@ export const getFreedrawStroke = ( */ export const getFreeDrawSvgPath = ( element: ExcalidrawFreeDrawElement, - debugParams?: { streamline?: number; simplify?: number }, ): string => { // legacy, for backwards compatibility if (element.drawingConfigs === null) { return _legacy_getFreeDrawSvgPath(element); } - return getSvgPathFromStroke(getFreedrawStroke(element, debugParams)); + return getSvgPathFromStroke(getFreedrawStroke(element)); }; const roundPoint = (A: Point): string => { diff --git a/packages/excalidraw/actions/actionProperties.test.tsx b/packages/excalidraw/actions/actionProperties.test.tsx index 38419ce82..792c6c67e 100644 --- a/packages/excalidraw/actions/actionProperties.test.tsx +++ b/packages/excalidraw/actions/actionProperties.test.tsx @@ -145,26 +145,27 @@ describe("element locking", () => { queryByTestId(document.body, `strokeWidth-thin`), ).not.toBeChecked(); expect( - queryByTestId(document.body, `strokeWidth-bold`), + queryByTestId(document.body, `strokeWidth-medium`), ).not.toBeChecked(); expect( - queryByTestId(document.body, `strokeWidth-extraBold`), + queryByTestId(document.body, `strokeWidth-bold`), ).not.toBeChecked(); }); it("should show properties of different element types when selected", () => { const rect = API.createElement({ type: "rectangle", - strokeWidth: STROKE_WIDTH.bold, + strokeWidth: STROKE_WIDTH.medium, }); const text = API.createElement({ type: "text", fontFamily: FONT_FAMILY["Comic Shanns"], + strokeWidth: undefined, }); API.setElements([rect, text]); API.setSelectedElements([rect, text]); - expect(queryByTestId(document.body, `strokeWidth-bold`)).toBeChecked(); + expect(queryByTestId(document.body, `strokeWidth-medium`)).toBeChecked(); expect(queryByTestId(document.body, `font-family-code`)).toHaveClass( "active", ); diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index 9cf67dce1..de62cf95b 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -130,6 +130,7 @@ import { ArrowheadCrowfootOneOrManyIcon, strokeWidthFixedIcon, strokeWidthVariableIcon, + StrokeWidthMediumIcon, } from "../components/icons"; import { Fonts } from "../fonts"; @@ -509,6 +510,33 @@ export const actionChangeFillStyle = register({ }, }); +const WIDTHS = [ + { + value: STROKE_WIDTH.thin, + text: t("labels.thin"), + icon: StrokeWidthBaseIcon, + testId: "strokeWidth-thin", + }, + { + value: STROKE_WIDTH.medium, + text: t("labels.medium"), + icon: StrokeWidthMediumIcon, + testId: "strokeWidth-medium", + }, + { + value: STROKE_WIDTH.bold, + text: t("labels.bold"), + icon: StrokeWidthBoldIcon, + testId: "strokeWidth-bold", + }, + { + value: STROKE_WIDTH.extraBold, + text: t("labels.extraBold"), + icon: StrokeWidthExtraBoldIcon, + testId: "strokeWidth-extraBold", + }, +]; + export const actionChangeStrokeWidth = register({ name: "changeStrokeWidth", label: "labels.strokeWidth", @@ -530,26 +558,11 @@ export const actionChangeStrokeWidth = register({
, + modifiedTablerIconProps, +); + export const StrokeStyleSolidIcon = React.memo(({ theme }: { theme: Theme }) => createIcon( selecting 'Paste styles' in context menu pastes s "currentItemStartArrowhead": null, "currentItemStrokeColor": "#e03131", "currentItemStrokeStyle": "dotted", - "currentItemStrokeWidth": 2, + "currentItemStrokeWidth": 4, "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, @@ -3241,11 +3241,11 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "seed": 449462985, "strokeColor": "#e03131", "strokeStyle": "dotted", - "strokeWidth": 2, + "strokeWidth": 4, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 941653321, + "versionNonce": 1402203177, "width": 20, "x": -10, "y": 0, @@ -3272,14 +3272,14 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "roundness": { "type": 3, }, - "seed": 289600103, + "seed": 1898319239, "strokeColor": "#e03131", "strokeStyle": "dotted", - "strokeWidth": 2, + "strokeWidth": 4, "type": "rectangle", "updated": 1, - "version": 9, - "versionNonce": 640725609, + "version": 10, + "versionNonce": 941653321, "width": 20, "x": 20, "y": 30, @@ -3288,7 +3288,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of renders 1`] = `16`; +exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of renders 1`] = `17`; exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] redo stack 1`] = `[]`; @@ -3469,6 +3469,29 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s }, "id": "id11", }, + { + "appState": AppStateDelta { + "delta": Delta { + "deleted": {}, + "inserted": {}, + }, + }, + "elements": { + "added": {}, + "removed": {}, + "updated": { + "id3": { + "deleted": { + "strokeWidth": 4, + }, + "inserted": { + "strokeWidth": 2, + }, + }, + }, + }, + "id": "id13", + }, { "appState": AppStateDelta { "delta": Delta { @@ -3490,7 +3513,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s }, }, }, - "id": "id13", + "id": "id15", }, { "appState": AppStateDelta { @@ -3513,7 +3536,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s }, }, }, - "id": "id15", + "id": "id17", }, { "appState": AppStateDelta { @@ -3536,7 +3559,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s }, }, }, - "id": "id17", + "id": "id19", }, { "appState": AppStateDelta { @@ -3565,6 +3588,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "roughness": 2, "strokeColor": "#e03131", "strokeStyle": "dotted", + "strokeWidth": 4, }, "inserted": { "backgroundColor": "transparent", @@ -3573,11 +3597,12 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "roughness": 1, "strokeColor": "#1e1e1e", "strokeStyle": "solid", + "strokeWidth": 2, }, }, }, }, - "id": "id19", + "id": "id21", }, ] `; diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 70dff4bd6..edb7125cc 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -8913,7 +8913,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, @@ -9022,7 +9022,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, @@ -12075,7 +12075,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, @@ -12130,7 +12130,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, @@ -12275,7 +12275,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 86ef418bd..e78daa585 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -6880,7 +6880,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, @@ -9159,7 +9159,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, @@ -10167,7 +10167,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta "drawingConfigs": { "pressureSensitivity": 1, "simplify": "0.25000", - "streamline": "0.25000", + "streamline": "0.35000", }, "fillStyle": "solid", "frameId": null, diff --git a/packages/excalidraw/tests/actionStyles.test.tsx b/packages/excalidraw/tests/actionStyles.test.tsx index e81e9e4e4..46b0d1f0a 100644 --- a/packages/excalidraw/tests/actionStyles.test.tsx +++ b/packages/excalidraw/tests/actionStyles.test.tsx @@ -78,7 +78,7 @@ describe("actionStyles", () => { expect(firstRect.strokeColor).toBe("#e03131"); expect(firstRect.backgroundColor).toBe("#a5d8ff"); expect(firstRect.fillStyle).toBe("cross-hatch"); - expect(firstRect.strokeWidth).toBe(2); // Bold: 2 + expect(firstRect.strokeWidth).toBe(4); // Bold: 4 expect(firstRect.strokeStyle).toBe("dotted"); expect(firstRect.roughness).toBe(2); // Cartoonist: 2 expect(firstRect.opacity).toBe(60); diff --git a/packages/excalidraw/tests/contextmenu.test.tsx b/packages/excalidraw/tests/contextmenu.test.tsx index 75de2717f..07f383d37 100644 --- a/packages/excalidraw/tests/contextmenu.test.tsx +++ b/packages/excalidraw/tests/contextmenu.test.tsx @@ -381,7 +381,7 @@ describe("contextMenu element", () => { expect(firstRect.strokeColor).toBe("#e03131"); expect(firstRect.backgroundColor).toBe("#a5d8ff"); expect(firstRect.fillStyle).toBe("cross-hatch"); - expect(firstRect.strokeWidth).toBe(2); // Bold: 2 + expect(firstRect.strokeWidth).toBe(4); // Bold: 4 expect(firstRect.strokeStyle).toBe("dotted"); expect(firstRect.roughness).toBe(2); // Cartoonist: 2 expect(firstRect.opacity).toBe(60);