From 15dfe0cc7c4d3be57ddf24c203daea74f84a4cb4 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 2 Jun 2025 16:39:42 +1000 Subject: [PATCH 01/31] add stroke/pressure sensitivity to freedraw --- packages/element/src/newElement.ts | 2 ++ packages/element/src/renderElement.ts | 7 +++++-- packages/element/src/types.ts | 1 + packages/excalidraw/data/restore.ts | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/element/src/newElement.ts b/packages/element/src/newElement.ts index 69ccaf595f..5d6f6835ff 100644 --- a/packages/element/src/newElement.ts +++ b/packages/element/src/newElement.ts @@ -445,6 +445,7 @@ export const newFreeDrawElement = ( points?: ExcalidrawFreeDrawElement["points"]; simulatePressure: boolean; pressures?: ExcalidrawFreeDrawElement["pressures"]; + pressureSensitivity?: ExcalidrawFreeDrawElement["pressureSensitivity"]; } & ElementConstructorOpts, ): NonDeleted => { return { @@ -453,6 +454,7 @@ export const newFreeDrawElement = ( pressures: opts.pressures || [], simulatePressure: opts.simulatePressure, lastCommittedPoint: null, + pressureSensitivity: opts.pressureSensitivity ?? 1, }; }; diff --git a/packages/element/src/renderElement.ts b/packages/element/src/renderElement.ts index 2786f3f84a..5c5f7b99b9 100644 --- a/packages/element/src/renderElement.ts +++ b/packages/element/src/renderElement.ts @@ -1041,11 +1041,14 @@ export function getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]]; + const sensitivity = element.pressureSensitivity; + // Consider changing the options for simulated pressure vs real pressure const options: StrokeOptions = { simulatePressure: element.simulatePressure, - size: element.strokeWidth * 4.25, - thinning: 0.6, + // if sensitivity is not set, times 4.25 for backwards compatibility + size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), + thinning: 0.6 * (sensitivity ?? 1), smoothing: 0.5, streamline: 0.5, easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine diff --git a/packages/element/src/types.ts b/packages/element/src/types.ts index 23e4f99290..c11fecee3c 100644 --- a/packages/element/src/types.ts +++ b/packages/element/src/types.ts @@ -377,6 +377,7 @@ export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase & type: "freedraw"; points: readonly LocalPoint[]; pressures: readonly number[]; + pressureSensitivity: number | null; simulatePressure: boolean; lastCommittedPoint: LocalPoint | null; }>; diff --git a/packages/excalidraw/data/restore.ts b/packages/excalidraw/data/restore.ts index a609c0a0eb..fd0f43b616 100644 --- a/packages/excalidraw/data/restore.ts +++ b/packages/excalidraw/data/restore.ts @@ -302,6 +302,7 @@ const restoreElement = ( lastCommittedPoint: null, simulatePressure: element.simulatePressure, pressures: element.pressures, + pressureSensitivity: element.pressureSensitivity ?? null, }); } case "image": From ab6af41d334d428a51c51580a09e34f72b92183d Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 2 Jun 2025 16:43:12 +1000 Subject: [PATCH 02/31] add current item stroke sensivity --- packages/excalidraw/appState.ts | 6 ++++++ packages/excalidraw/types.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/packages/excalidraw/appState.ts b/packages/excalidraw/appState.ts index b45a6f7d30..ef6d03dc75 100644 --- a/packages/excalidraw/appState.ts +++ b/packages/excalidraw/appState.ts @@ -33,6 +33,7 @@ export const getDefaultAppState = (): Omit< currentItemFontFamily: DEFAULT_FONT_FAMILY, currentItemFontSize: DEFAULT_FONT_SIZE, currentItemOpacity: DEFAULT_ELEMENT_PROPS.opacity, + currentItemPressureSensitivity: 1, currentItemRoughness: DEFAULT_ELEMENT_PROPS.roughness, currentItemStartArrowhead: null, currentItemStrokeColor: DEFAULT_ELEMENT_PROPS.strokeColor, @@ -163,6 +164,11 @@ const APP_STATE_STORAGE_CONF = (< server: false, }, currentItemOpacity: { browser: true, export: false, server: false }, + currentItemPressureSensitivity: { + browser: true, + export: false, + server: false, + }, currentItemRoughness: { browser: true, export: false, server: false }, currentItemStartArrowhead: { browser: true, export: false, server: false }, currentItemStrokeColor: { browser: true, export: false, server: false }, diff --git a/packages/excalidraw/types.ts b/packages/excalidraw/types.ts index 6f3fd0efa8..ca092df395 100644 --- a/packages/excalidraw/types.ts +++ b/packages/excalidraw/types.ts @@ -333,6 +333,7 @@ export interface AppState { currentItemStrokeStyle: ExcalidrawElement["strokeStyle"]; currentItemRoughness: number; currentItemOpacity: number; + currentItemPressureSensitivity: number; currentItemFontFamily: FontFamilyValues; currentItemFontSize: number; currentItemTextAlign: TextAlign; From 1c611d6c4f7f364dfbce264fe58ba57086cac1ed Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 2 Jun 2025 16:44:30 +1000 Subject: [PATCH 03/31] add stroke sensivity action --- .../excalidraw/actions/actionProperties.tsx | 96 +++++++++++++++++++ packages/excalidraw/actions/index.ts | 1 + packages/excalidraw/actions/types.ts | 1 + packages/excalidraw/components/Actions.tsx | 8 +- packages/excalidraw/components/App.tsx | 1 + packages/excalidraw/locales/en.json | 1 + 6 files changed, 106 insertions(+), 2 deletions(-) diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index 30c9e74343..c5e6f61613 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -47,6 +47,7 @@ import { isArrowElement, isBoundToContainer, isElbowArrow, + isFreeDrawElement, isLinearElement, isLineElement, isTextElement, @@ -669,6 +670,26 @@ export const actionChangeStrokeStyle = register({ ), }); +export const actionChangePressureSensitivity = register({ + name: "changePressureSensitivity", + label: "labels.pressureSensitivity", + trackEvent: false, + perform: (elements, appState, value) => { + return { + elements, + appState: { ...appState, currentItemPressureSensitivity: value }, + captureUpdate: CaptureUpdateAction.IMMEDIATELY, + }; + }, + PanelComponent: ({ app, appState, updateData }) => { + if (appState.activeTool.type !== "freedraw") { + return null; + } + + return ; + }, +}); + export const actionChangeOpacity = register({ name: "changeOpacity", label: "labels.opacity", @@ -1857,3 +1878,78 @@ export const actionChangeArrowType = register({ ); }, }); + +const PressureSensitivityRange = ({ + updateData, + app, +}: { + updateData: (value: number) => void; + app: AppClassProperties; +}) => { + const rangeRef = useRef(null); + const valueRef = useRef(null); + const selectedElements = app.scene.getSelectedElements(app.state); + + let hasCommonPressureSensitivity = true; + const firstElement = selectedElements.find(isFreeDrawElement); + const leastCommonPressureSensitivity = selectedElements + .filter(isFreeDrawElement) + .reduce((acc, element) => { + const sensitivity = element.pressureSensitivity ?? 1; + if (acc != null && acc !== sensitivity) { + hasCommonPressureSensitivity = false; + } + if (acc == null || acc > sensitivity) { + return sensitivity; + } + return acc; + }, firstElement?.pressureSensitivity ?? null); + + const value = Math.round( + (leastCommonPressureSensitivity ?? + app.state.currentItemPressureSensitivity) * 100, + ); + + useEffect(() => { + if (rangeRef.current && valueRef.current) { + const rangeElement = rangeRef.current; + const valueElement = valueRef.current; + const inputWidth = rangeElement.offsetWidth; + const thumbWidth = 15; + const position = + (value / 100) * (inputWidth - thumbWidth) + thumbWidth / 2; + valueElement.style.left = `${position}px`; + rangeElement.style.background = `linear-gradient(to right, var(--color-slider-track) 0%, var(--color-slider-track) ${value}%, var(--button-bg) ${value}%, var(--button-bg) 100%)`; + } + }, [value]); + + return ( + + ); +}; diff --git a/packages/excalidraw/actions/index.ts b/packages/excalidraw/actions/index.ts index f37747aebd..54bdbdaaf8 100644 --- a/packages/excalidraw/actions/index.ts +++ b/packages/excalidraw/actions/index.ts @@ -13,6 +13,7 @@ export { actionChangeStrokeWidth, actionChangeFillStyle, actionChangeSloppiness, + actionChangePressureSensitivity, actionChangeOpacity, actionChangeFontSize, actionChangeFontFamily, diff --git a/packages/excalidraw/actions/types.ts b/packages/excalidraw/actions/types.ts index e6f3631263..adfc8cefa1 100644 --- a/packages/excalidraw/actions/types.ts +++ b/packages/excalidraw/actions/types.ts @@ -69,6 +69,7 @@ export type ActionName = | "changeStrokeStyle" | "changeArrowhead" | "changeArrowType" + | "changePressureSensitivity" | "changeOpacity" | "changeFontSize" | "toggleCanvasMenu" diff --git a/packages/excalidraw/components/Actions.tsx b/packages/excalidraw/components/Actions.tsx index 60dab78f4f..5b3015a4bd 100644 --- a/packages/excalidraw/components/Actions.tsx +++ b/packages/excalidraw/components/Actions.tsx @@ -169,8 +169,12 @@ export const SelectedShapeActions = ({ renderAction("changeStrokeWidth")} {(appState.activeTool.type === "freedraw" || - targetElements.some((element) => element.type === "freedraw")) && - renderAction("changeStrokeShape")} + targetElements.some((element) => element.type === "freedraw")) && ( + <> + {renderAction("changeStrokeShape")} + {renderAction("changePressureSensitivity")} + + )} {(hasStrokeStyle(appState.activeTool.type) || targetElements.some((element) => hasStrokeStyle(element.type))) && ( diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 15b5e5b6fd..45fc5109d8 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -7588,6 +7588,7 @@ class App extends React.Component { opacity: this.state.currentItemOpacity, roundness: null, simulatePressure, + pressureSensitivity: this.state.currentItemPressureSensitivity, locked: false, frameId: topLayerFrame ? topLayerFrame.id : null, points: [pointFrom(0, 0)], diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json index 736c417225..d9904838fc 100644 --- a/packages/excalidraw/locales/en.json +++ b/packages/excalidraw/locales/en.json @@ -32,6 +32,7 @@ "strokeStyle_dotted": "Dotted", "sloppiness": "Sloppiness", "opacity": "Opacity", + "pressureSensitivity": "Stroke sensitivity", "textAlign": "Text align", "edges": "Edges", "sharp": "Sharp", From 4e265629c31ff9a5cead7163331057433ad12c19 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 2 Jun 2025 17:00:19 +1000 Subject: [PATCH 04/31] tweak stroke rendering --- packages/element/src/renderElement.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/element/src/renderElement.ts b/packages/element/src/renderElement.ts index 5c5f7b99b9..b1dfe16483 100644 --- a/packages/element/src/renderElement.ts +++ b/packages/element/src/renderElement.ts @@ -1048,7 +1048,8 @@ export function getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { simulatePressure: element.simulatePressure, // if sensitivity is not set, times 4.25 for backwards compatibility size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), - thinning: 0.6 * (sensitivity ?? 1), + // if sensitivity is not set, set thinning to 0.6 for backwards compatibility + thinning: sensitivity !== null ? 0.5 * sensitivity : 0.6, smoothing: 0.5, streamline: 0.5, easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine From c7780cb9cb439cada4378be4598de7d01ff3ce63 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 2 Jun 2025 17:33:44 +1000 Subject: [PATCH 05/31] snapshots --- .../__snapshots__/contextmenu.test.tsx.snap | 17 +++++ .../tests/__snapshots__/history.test.tsx.snap | 63 +++++++++++++++++++ .../regressionTests.test.tsx.snap | 55 ++++++++++++++++ .../data/__snapshots__/restore.test.ts.snap | 1 + .../tests/__snapshots__/export.test.ts.snap | 1 + 5 files changed, 137 insertions(+) diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index 23f4ccb4f2..ea5f96d9ac 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -897,6 +897,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1100,6 +1101,7 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1316,6 +1318,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1649,6 +1652,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1982,6 +1986,7 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2198,6 +2203,7 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2439,6 +2445,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2741,6 +2748,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3113,6 +3121,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 60, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 2, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3596,6 +3605,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3921,6 +3931,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4246,6 +4257,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5527,6 +5539,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6748,6 +6761,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7683,6 +7697,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8683,6 +8698,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9674,6 +9690,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 080d8fbf05..be6cc48a8c 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -23,6 +23,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -614,6 +615,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1123,6 +1125,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1491,6 +1494,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1860,6 +1864,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2127,6 +2132,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2564,6 +2570,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2863,6 +2870,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3147,6 +3155,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3441,6 +3450,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3727,6 +3737,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3962,6 +3973,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4221,6 +4233,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4494,6 +4507,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4725,6 +4739,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4956,6 +4971,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5185,6 +5201,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5414,6 +5431,7 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5674,6 +5692,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6007,6 +6026,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6436,6 +6456,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6816,6 +6837,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7136,6 +7158,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7437,6 +7460,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7667,6 +7691,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8023,6 +8048,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8379,6 +8405,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8787,6 +8814,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8914,6 +8942,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte 50, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -9022,6 +9051,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte 50, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -9074,6 +9104,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9340,6 +9371,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9607,6 +9639,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9839,6 +9872,7 @@ exports[`history > multiplayer undo/redo > should override remotely added groups "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10140,6 +10174,7 @@ exports[`history > multiplayer undo/redo > should override remotely added points "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10482,6 +10517,7 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10718,6 +10754,7 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11168,6 +11205,7 @@ exports[`history > multiplayer undo/redo > should update history entries after r "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11426,6 +11464,7 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11665,6 +11704,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11906,6 +11946,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12061,6 +12102,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f 10, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -12115,6 +12157,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f 10, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -12258,6 +12301,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f 10, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -12309,6 +12353,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on s "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12556,6 +12601,7 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12797,6 +12843,7 @@ exports[`history > singleplayer undo/redo > should end up with no history entry "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13038,6 +13085,7 @@ exports[`history > singleplayer undo/redo > should iterate through the history w "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13287,6 +13335,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13622,6 +13671,7 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13794,6 +13844,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14082,6 +14133,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14349,6 +14401,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14629,6 +14682,7 @@ exports[`history > singleplayer undo/redo > should support appstate name or view "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14791,6 +14845,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -15492,6 +15547,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -16112,6 +16168,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -16732,6 +16789,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -17447,6 +17505,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -18200,6 +18259,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements' "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -18680,6 +18740,7 @@ exports[`history > singleplayer undo/redo > should support duplication of groups "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -19203,6 +19264,7 @@ exports[`history > singleplayer undo/redo > should support element creation, del "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -19664,6 +19726,7 @@ exports[`history > singleplayer undo/redo > should support linear element creati "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index a81ed30352..b179176fb5 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -23,6 +23,7 @@ exports[`given element A and group of elements B and given both are selected whe "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -445,6 +446,7 @@ exports[`given element A and group of elements B and given both are selected whe "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -857,6 +859,7 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1413,6 +1416,7 @@ exports[`regression tests > Drags selected element when hitting only bounding bo "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1618,6 +1622,7 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1998,6 +2003,7 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2234,6 +2240,7 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = ` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2414,6 +2421,7 @@ exports[`regression tests > can drag element that covers another element, while "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2737,6 +2745,7 @@ exports[`regression tests > change the properties of a shape > [end of test] app "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2986,6 +2995,7 @@ exports[`regression tests > click on an element and drag it > [dragged] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3227,6 +3237,7 @@ exports[`regression tests > click on an element and drag it > [end of test] appS "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3459,6 +3470,7 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`] "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3717,6 +3729,7 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4031,6 +4044,7 @@ exports[`regression tests > deleting last but one element in editing group shoul "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4461,6 +4475,7 @@ exports[`regression tests > deselects group of selected elements on pointer down "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4746,6 +4761,7 @@ exports[`regression tests > deselects group of selected elements on pointer up w "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5022,6 +5038,7 @@ exports[`regression tests > deselects selected element on pointer down when poin "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5232,6 +5249,7 @@ exports[`regression tests > deselects selected element, on pointer up, when clic "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5432,6 +5450,7 @@ exports[`regression tests > double click to edit a group > [end of test] appStat "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5819,6 +5838,7 @@ exports[`regression tests > drags selected elements from point inside common bou "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6112,6 +6132,7 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6883,6 +6904,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack 10, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -6934,6 +6956,7 @@ exports[`regression tests > given a group of selected elements with an element t "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7268,6 +7291,7 @@ exports[`regression tests > given a selected element A and a not selected elemen "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7547,6 +7571,7 @@ exports[`regression tests > given selected element A with lower z-index than uns "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7782,6 +7807,7 @@ exports[`regression tests > given selected element A with lower z-index than uns "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8020,6 +8046,7 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8200,6 +8227,7 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8380,6 +8408,7 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8560,6 +8589,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8784,6 +8814,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`] "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9008,6 +9039,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9151,6 +9183,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta 10, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -9202,6 +9235,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9426,6 +9460,7 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9606,6 +9641,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`] "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9830,6 +9866,7 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10010,6 +10047,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10153,6 +10191,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta 10, ], ], + "pressureSensitivity": 1, "pressures": [ 0, 0, @@ -10204,6 +10243,7 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10384,6 +10424,7 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10884,6 +10925,7 @@ exports[`regression tests > noop interaction after undo shouldn't create history "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11164,6 +11206,7 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = ` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11287,6 +11330,7 @@ exports[`regression tests > shift click on selected element should deselect it o "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11487,6 +11531,7 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11802,6 +11847,7 @@ exports[`regression tests > should group elements and ungroup them > [end of tes "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12219,6 +12265,7 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12843,6 +12890,7 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12969,6 +13017,7 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`] "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13590,6 +13639,7 @@ exports[`regression tests > switches from group of selected elements to another "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13931,6 +13981,7 @@ exports[`regression tests > switches selected element on pointer down > [end of "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14197,6 +14248,7 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`] "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14320,6 +14372,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14705,6 +14758,7 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes "currentItemFontFamily": 8, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14828,6 +14882,7 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = ` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, diff --git a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap index dfb0f8d2da..cc9e0b987d 100644 --- a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap +++ b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap @@ -191,6 +191,7 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` 10, ], ], + "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": { diff --git a/packages/utils/tests/__snapshots__/export.test.ts.snap b/packages/utils/tests/__snapshots__/export.test.ts.snap index 2c22874a9b..196e4e229f 100644 --- a/packages/utils/tests/__snapshots__/export.test.ts.snap +++ b/packages/utils/tests/__snapshots__/export.test.ts.snap @@ -23,6 +23,7 @@ exports[`exportToSvg > with default arguments 1`] = ` "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, + "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, From 660d21fe4690c68bc2490ad475c537c995f40aa7 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 5 Jun 2025 16:53:22 +1000 Subject: [PATCH 06/31] improve freedraw rendering --- packages/element/src/Shape.ts | 23 ++- packages/element/src/freedraw.ts | 208 ++++++++++++++++++++++++++ packages/element/src/index.ts | 1 + packages/element/src/renderElement.ts | 62 +------- packages/excalidraw/index.tsx | 2 +- 5 files changed, 227 insertions(+), 69 deletions(-) create mode 100644 packages/element/src/freedraw.ts diff --git a/packages/element/src/Shape.ts b/packages/element/src/Shape.ts index 4def419574..16da46381a 100644 --- a/packages/element/src/Shape.ts +++ b/packages/element/src/Shape.ts @@ -3,8 +3,6 @@ import { simplify } from "points-on-curve"; import { pointFrom, pointDistance, type LocalPoint } from "@excalidraw/math"; import { ROUGHNESS, isTransparent, assertNever } from "@excalidraw/common"; -import type { Mutable } from "@excalidraw/common/utility-types"; - import type { EmbedsValidationStatus } from "@excalidraw/excalidraw/types"; import type { ElementShapes } from "@excalidraw/excalidraw/scene/types"; @@ -22,6 +20,8 @@ import { canChangeRoundness } from "./comparisons"; import { generateFreeDrawShape } from "./renderElement"; import { getArrowheadPoints, getDiamondPoints } from "./bounds"; +import { getFreedrawStroke } from "./freedraw"; + import type { ExcalidrawElement, NonDeletedExcalidrawElement, @@ -514,12 +514,19 @@ export const _generateElementShape = ( generateFreeDrawShape(element); if (isPathALoop(element.points)) { - // generate rough polygon to fill freedraw shape - const simplifiedPoints = simplify( - element.points as Mutable, - 0.75, - ); - shape = generator.curve(simplifiedPoints as [number, number][], { + let points; + if (element.pressureSensitivity === null) { + // legacy freedraw + points = simplify(element.points as LocalPoint[], 0.75); + } else { + // new freedraw + const stroke = getFreedrawStroke(element); + points = stroke + .slice(0, Math.floor(stroke.length / 2)) + .map((p) => pointFrom(p[0], p[1])); + } + + shape = generator.curve(points, { ...generateRoughOptions(element), stroke: "none", }); diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts new file mode 100644 index 0000000000..168ae79ebd --- /dev/null +++ b/packages/element/src/freedraw.ts @@ -0,0 +1,208 @@ +import { LaserPointer, type Point } from "@excalidraw/laser-pointer"; + +import { round, type LocalPoint } from "@excalidraw/math"; + +import getStroke from "perfect-freehand"; + +import type { StrokeOptions } from "perfect-freehand"; + +import type { ExcalidrawFreeDrawElement } from "./types"; + +/** + * Calculates simulated pressure based on velocity between consecutive points. + * Fast movement (large distances) -> lower pressure + * Slow movement (small distances) -> higher pressure + */ +const calculateVelocityBasedPressure = ( + points: readonly LocalPoint[], + index: number, + pressureSensitivity: number | null, + maxDistance = 8, // Maximum expected distance for normalization +): number => { + // Handle pressure sensitivity + const sensitivity = pressureSensitivity ?? 1; // Default to 1 for backwards compatibility + + // If sensitivity is 0, return constant pressure + if (sensitivity === 0) { + return 0.6; + } + + // First point gets highest pressure + // This avoid "a dot followed by a line" effect, •== when first stroke is "slow" + if (index === 0) { + return 1; + } + + const [x1, y1] = points[index - 1]; + const [x2, y2] = points[index]; + + // Calculate distance between consecutive points + const distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); + + // Normalize distance and invert for pressure (0 = fast/low pressure, 1 = slow/high pressure) + const normalizedDistance = Math.min(distance / maxDistance, 1); + const basePressure = Math.max(0.1, 1 - normalizedDistance * 0.7); // Range: 0.1 to 1.0 + + // Apply pressure sensitivity (range 0-1): + // sensitivity = 0 -> constant pressure (handled above) + // sensitivity = 1 -> full velocity-based variation + // sensitivity < 1 -> interpolate between constant and velocity-based + const constantPressure = 0.5; + const pressure = + constantPressure + (basePressure - constantPressure) * sensitivity; + + return Math.max(0.1, Math.min(1.0, pressure)); +}; + +export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { + // Compose points as [x, y, pressure] + let points: [number, number, number][]; + if (element.simulatePressure) { + // Simulate pressure based on velocity between consecutive points + points = element.points.map(([x, y]: LocalPoint, i) => [ + x, + y, + calculateVelocityBasedPressure( + element.points, + i, + element.pressureSensitivity, + ), + ]); + } else { + points = element.points.map(([x, y]: LocalPoint, i) => [ + x, + y, + element.pressures?.[i] ?? 0.5, + ]); + } + + const laser = new LaserPointer({ + size: element.strokeWidth, + streamline: 0.62, + simplify: 0.3, + sizeMapping: ({ pressure: t }) => 0.2 + t, + }); + + for (const pt of points) { + laser.addPoint(pt); + } + laser.close(); + + return laser.getStrokeOutline(); +}; + +/** + * Generates an SVG path for a freedraw element using LaserPointer logic. + * Uses actual pressure data if available, otherwise simulates pressure based on velocity. + * No streamline, smoothing, or simulation is performed. + */ +export const getFreeDrawSvgPath = ( + element: ExcalidrawFreeDrawElement, +): string => { + // legacy, for backwards compatibility + if (element.pressureSensitivity === null) { + return _legacy_getFreeDrawSvgPath(element); + } + + return getSvgPathFromStroke(getFreedrawStroke(element)); +}; + +const roundPoint = (A: Point): string => { + return `${round(A[0], 4, "round")},${round(A[1], 4, "round")} `; +}; + +const average = (A: Point, B: Point): string => { + return `${round((A[0] + B[0]) / 2, 4, "round")},${round( + (A[1] + B[1]) / 2, + 4, + "round", + )} `; +}; + +const getSvgPathFromStroke = (points: Point[]): string => { + const len = points.length; + + if (len < 2) { + return ""; + } + + let a = points[0]; + let b = points[1]; + + if (len === 2) { + return `M${roundPoint(a)}L${roundPoint(b)}`; + } + + let result = ""; + + for (let i = 2, max = len - 1; i < max; i++) { + a = points[i]; + b = points[i + 1]; + result += average(a, b); + } + + return `M${roundPoint(points[0])}Q${roundPoint(points[1])}${average( + points[1], + points[2], + )}${points.length > 3 ? "T" : ""}${result}L${roundPoint(points[len - 1])}`; +}; + +function _legacy_getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { + // If input points are empty (should they ever be?) return a dot + const inputPoints = element.simulatePressure + ? element.points + : element.points.length + ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) + : [[0, 0, 0.5]]; + + const sensitivity = element.pressureSensitivity; + + // Consider changing the options for simulated pressure vs real pressure + const options: StrokeOptions = { + simulatePressure: element.simulatePressure, + // if sensitivity is not set, times 4.25 for backwards compatibility + size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), + // if sensitivity is not set, set thinning to 0.6 for backwards compatibility + thinning: sensitivity !== null ? 0.5 * sensitivity : 0.6, + smoothing: 0.5, + streamline: 0.5, + easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine + last: !!element.lastCommittedPoint, // LastCommittedPoint is added on pointerup + }; + + return _legacy_getSvgPathFromStroke( + getStroke(inputPoints as number[][], options), + ); +} + +const med = (A: number[], B: number[]) => { + return [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2]; +}; + +// Trim SVG path data so number are each two decimal points. This +// improves SVG exports, and prevents rendering errors on points +// with long decimals. +const TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g; + +const _legacy_getSvgPathFromStroke = (points: number[][]): string => { + if (!points.length) { + return ""; + } + + const max = points.length - 1; + + return points + .reduce( + (acc, point, i, arr) => { + if (i === max) { + acc.push(point, med(point, arr[0]), "L", arr[0], "Z"); + } else { + acc.push(point, med(point, arr[i + 1])); + } + return acc; + }, + ["M", points[0], "Q"], + ) + .join(" ") + .replace(TO_FIXED_PRECISION, "$1"); +}; diff --git a/packages/element/src/index.ts b/packages/element/src/index.ts index 93024f9940..8339b4ab50 100644 --- a/packages/element/src/index.ts +++ b/packages/element/src/index.ts @@ -91,6 +91,7 @@ export * from "./embeddable"; export * from "./flowchart"; export * from "./fractionalIndex"; export * from "./frame"; +export * from "./freedraw"; export * from "./groups"; export * from "./heading"; export * from "./image"; diff --git a/packages/element/src/renderElement.ts b/packages/element/src/renderElement.ts index b1dfe16483..ea8f303088 100644 --- a/packages/element/src/renderElement.ts +++ b/packages/element/src/renderElement.ts @@ -1,5 +1,4 @@ import rough from "roughjs/bin/rough"; -import { getStroke } from "perfect-freehand"; import { isRightAngleRads } from "@excalidraw/math"; @@ -58,6 +57,8 @@ import { getCornerRadius } from "./shapes"; import { ShapeCache } from "./ShapeCache"; +import { getFreeDrawSvgPath } from "./freedraw"; + import type { ExcalidrawElement, ExcalidrawTextElement, @@ -70,7 +71,6 @@ import type { ElementsMap, } from "./types"; -import type { StrokeOptions } from "perfect-freehand"; import type { RoughCanvas } from "roughjs/bin/canvas"; // using a stronger invert (100% vs our regular 93%) and saturate @@ -1032,61 +1032,3 @@ export function generateFreeDrawShape(element: ExcalidrawFreeDrawElement) { export function getFreeDrawPath2D(element: ExcalidrawFreeDrawElement) { return pathsCache.get(element); } - -export function getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { - // If input points are empty (should they ever be?) return a dot - const inputPoints = element.simulatePressure - ? element.points - : element.points.length - ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) - : [[0, 0, 0.5]]; - - const sensitivity = element.pressureSensitivity; - - // Consider changing the options for simulated pressure vs real pressure - const options: StrokeOptions = { - simulatePressure: element.simulatePressure, - // if sensitivity is not set, times 4.25 for backwards compatibility - size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), - // if sensitivity is not set, set thinning to 0.6 for backwards compatibility - thinning: sensitivity !== null ? 0.5 * sensitivity : 0.6, - smoothing: 0.5, - streamline: 0.5, - easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine - last: !!element.lastCommittedPoint, // LastCommittedPoint is added on pointerup - }; - - return getSvgPathFromStroke(getStroke(inputPoints as number[][], options)); -} - -function med(A: number[], B: number[]) { - return [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2]; -} - -// Trim SVG path data so number are each two decimal points. This -// improves SVG exports, and prevents rendering errors on points -// with long decimals. -const TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g; - -function getSvgPathFromStroke(points: number[][]): string { - if (!points.length) { - return ""; - } - - const max = points.length - 1; - - return points - .reduce( - (acc, point, i, arr) => { - if (i === max) { - acc.push(point, med(point, arr[0]), "L", arr[0], "Z"); - } else { - acc.push(point, med(point, arr[i + 1])); - } - return acc; - }, - ["M", points[0], "Q"], - ) - .join(" ") - .replace(TO_FIXED_PRECISION, "$1"); -} diff --git a/packages/excalidraw/index.tsx b/packages/excalidraw/index.tsx index 478ecc42f0..93d2504cd1 100644 --- a/packages/excalidraw/index.tsx +++ b/packages/excalidraw/index.tsx @@ -248,7 +248,7 @@ export { loadSceneOrLibraryFromBlob, loadLibraryFromBlob, } from "./data/blob"; -export { getFreeDrawSvgPath } from "@excalidraw/element"; +export { getFreeDrawSvgPath } from "@excalidraw/element/freedraw"; export { mergeLibraryItems, getLibraryItemsHash } from "./data/library"; export { isLinearElement } from "@excalidraw/element"; From c210b7b09272d91023276e5112a180e4f9c059c5 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 5 Jun 2025 23:00:40 +1000 Subject: [PATCH 07/31] improve params and real pressure --- packages/element/src/freedraw.ts | 38 +++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 168ae79ebd..3a7e6964df 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -1,6 +1,6 @@ import { LaserPointer, type Point } from "@excalidraw/laser-pointer"; -import { round, type LocalPoint } from "@excalidraw/math"; +import { clamp, round, type LocalPoint } from "@excalidraw/math"; import getStroke from "perfect-freehand"; @@ -43,10 +43,6 @@ const calculateVelocityBasedPressure = ( const normalizedDistance = Math.min(distance / maxDistance, 1); const basePressure = Math.max(0.1, 1 - normalizedDistance * 0.7); // Range: 0.1 to 1.0 - // Apply pressure sensitivity (range 0-1): - // sensitivity = 0 -> constant pressure (handled above) - // sensitivity = 1 -> full velocity-based variation - // sensitivity < 1 -> interpolate between constant and velocity-based const constantPressure = 0.5; const pressure = constantPressure + (basePressure - constantPressure) * sensitivity; @@ -69,18 +65,38 @@ export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { ), ]); } else { - points = element.points.map(([x, y]: LocalPoint, i) => [ - x, - y, - element.pressures?.[i] ?? 0.5, - ]); + const sensitivity = element.pressureSensitivity ?? 1; + points = element.points.map(([x, y]: LocalPoint, i) => { + if (sensitivity === 0) { + return [x, y, 0.5]; + } + + const rawPressure = element.pressures?.[i] ?? 0.5; + + const amplifiedPressure = Math.pow(rawPressure, 0.6); + const adjustedPressure = amplifiedPressure * sensitivity; + + return [x, y, clamp(adjustedPressure, 0.1, 1.0)]; + }); } const laser = new LaserPointer({ size: element.strokeWidth, streamline: 0.62, simplify: 0.3, - sizeMapping: ({ pressure: t }) => 0.2 + t, + sizeMapping: ({ pressure: t }) => { + if (element.simulatePressure) { + return t + 0.2; + } + + if (element.pressureSensitivity === 0) { + return 1; + } + + const minSize = 0.2; + const maxSize = 2; + return minSize + t * (maxSize - minSize); + }, }); for (const pt of points) { From df1f9281b4566e2c7a302864cdf6e832049e5d59 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 6 Jun 2025 00:31:35 +1000 Subject: [PATCH 08/31] change slider to radio --- .../excalidraw/actions/actionProperties.tsx | 123 +++++++----------- packages/excalidraw/actions/types.ts | 2 +- packages/excalidraw/components/Actions.tsx | 2 +- packages/excalidraw/components/icons.tsx | 68 ++++++++++ packages/excalidraw/locales/en.json | 4 +- 5 files changed, 118 insertions(+), 81 deletions(-) diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index c5e6f61613..d9a39330f5 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -128,6 +128,8 @@ import { ArrowheadCrowfootIcon, ArrowheadCrowfootOneIcon, ArrowheadCrowfootOneOrManyIcon, + strokeWidthFixedIcon, + strokeWidthVariableIcon, } from "../components/icons"; import { Fonts } from "../fonts"; @@ -671,8 +673,8 @@ export const actionChangeStrokeStyle = register({ }); export const actionChangePressureSensitivity = register({ - name: "changePressureSensitivity", - label: "labels.pressureSensitivity", + name: "changeStrokeType", + label: "labels.strokeType", trackEvent: false, perform: (elements, appState, value) => { return { @@ -686,7 +688,47 @@ export const actionChangePressureSensitivity = register({ return null; } - return ; + const selectedElements = app.scene.getSelectedElements(app.state); + const firstElement = selectedElements.find(isFreeDrawElement); + const commonPressureSensitivity = selectedElements + .filter(isFreeDrawElement) + .reduce((acc, element) => { + const sensitivity = element.pressureSensitivity ?? 1; + if (acc !== null && acc !== sensitivity) { + return null; // No common value + } + return sensitivity; + }, firstElement?.pressureSensitivity ?? null); + + const currentValue = + commonPressureSensitivity ?? appState.currentItemPressureSensitivity; + + return ( +
+ {t("labels.strokeType")} +
+ updateData(value)} + /> +
+
+ ); }, }); @@ -1878,78 +1920,3 @@ export const actionChangeArrowType = register({ ); }, }); - -const PressureSensitivityRange = ({ - updateData, - app, -}: { - updateData: (value: number) => void; - app: AppClassProperties; -}) => { - const rangeRef = useRef(null); - const valueRef = useRef(null); - const selectedElements = app.scene.getSelectedElements(app.state); - - let hasCommonPressureSensitivity = true; - const firstElement = selectedElements.find(isFreeDrawElement); - const leastCommonPressureSensitivity = selectedElements - .filter(isFreeDrawElement) - .reduce((acc, element) => { - const sensitivity = element.pressureSensitivity ?? 1; - if (acc != null && acc !== sensitivity) { - hasCommonPressureSensitivity = false; - } - if (acc == null || acc > sensitivity) { - return sensitivity; - } - return acc; - }, firstElement?.pressureSensitivity ?? null); - - const value = Math.round( - (leastCommonPressureSensitivity ?? - app.state.currentItemPressureSensitivity) * 100, - ); - - useEffect(() => { - if (rangeRef.current && valueRef.current) { - const rangeElement = rangeRef.current; - const valueElement = valueRef.current; - const inputWidth = rangeElement.offsetWidth; - const thumbWidth = 15; - const position = - (value / 100) * (inputWidth - thumbWidth) + thumbWidth / 2; - valueElement.style.left = `${position}px`; - rangeElement.style.background = `linear-gradient(to right, var(--color-slider-track) 0%, var(--color-slider-track) ${value}%, var(--button-bg) ${value}%, var(--button-bg) 100%)`; - } - }, [value]); - - return ( - - ); -}; diff --git a/packages/excalidraw/actions/types.ts b/packages/excalidraw/actions/types.ts index adfc8cefa1..2675fd6356 100644 --- a/packages/excalidraw/actions/types.ts +++ b/packages/excalidraw/actions/types.ts @@ -69,7 +69,7 @@ export type ActionName = | "changeStrokeStyle" | "changeArrowhead" | "changeArrowType" - | "changePressureSensitivity" + | "changeStrokeType" | "changeOpacity" | "changeFontSize" | "toggleCanvasMenu" diff --git a/packages/excalidraw/components/Actions.tsx b/packages/excalidraw/components/Actions.tsx index 5b3015a4bd..bec743ea7d 100644 --- a/packages/excalidraw/components/Actions.tsx +++ b/packages/excalidraw/components/Actions.tsx @@ -172,7 +172,7 @@ export const SelectedShapeActions = ({ targetElements.some((element) => element.type === "freedraw")) && ( <> {renderAction("changeStrokeShape")} - {renderAction("changePressureSensitivity")} + {renderAction("changeStrokeType")} )} diff --git a/packages/excalidraw/components/icons.tsx b/packages/excalidraw/components/icons.tsx index 29bdc6d3c7..90ffb339ed 100644 --- a/packages/excalidraw/components/icons.tsx +++ b/packages/excalidraw/components/icons.tsx @@ -2269,3 +2269,71 @@ export const elementLinkIcon = createIcon( , tablerIconProps, ); + +export const strokeWidthFixedIcon = createIcon( + + + + + + , + tablerIconProps, +); + +export const strokeWidthVariableIcon = createIcon( + + + + + + , + tablerIconProps, +); diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json index d9904838fc..db01d26ed6 100644 --- a/packages/excalidraw/locales/en.json +++ b/packages/excalidraw/locales/en.json @@ -32,7 +32,9 @@ "strokeStyle_dotted": "Dotted", "sloppiness": "Sloppiness", "opacity": "Opacity", - "pressureSensitivity": "Stroke sensitivity", + "strokeType": "Stroke Type", + "strokeWidthFixed": "Fixed width", + "strokeWidthVariable": "Variable width", "textAlign": "Text align", "edges": "Edges", "sharp": "Sharp", From a8857f284984ba9fc949a8354463882c11af3d0d Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 9 Jun 2025 17:53:14 +1000 Subject: [PATCH 09/31] debug sliders --- excalidraw-app/App.tsx | 2 + .../components/FreedrawDebugSliders.tsx | 84 +++++++++++++++++++ packages/element/src/freedraw.ts | 25 +++++- packages/excalidraw/components/App.tsx | 10 +++ 4 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 excalidraw-app/components/FreedrawDebugSliders.tsx diff --git a/excalidraw-app/App.tsx b/excalidraw-app/App.tsx index 932743ddfd..40c14ca3e3 100644 --- a/excalidraw-app/App.tsx +++ b/excalidraw-app/App.tsx @@ -134,6 +134,7 @@ import DebugCanvas, { } from "./components/DebugCanvas"; import { AIComponents } from "./components/AI"; import { ExcalidrawPlusIframeExport } from "./ExcalidrawPlusIframeExport"; +import { FreedrawDebugSliders } from "./components/FreedrawDebugSliders"; import "./index.scss"; @@ -1142,6 +1143,7 @@ const ExcalidrawWrapper = () => { ref={debugCanvasRef} /> )} + ); diff --git a/excalidraw-app/components/FreedrawDebugSliders.tsx b/excalidraw-app/components/FreedrawDebugSliders.tsx new file mode 100644 index 0000000000..607e066c3c --- /dev/null +++ b/excalidraw-app/components/FreedrawDebugSliders.tsx @@ -0,0 +1,84 @@ +import { useState, useEffect } from "react"; + +export const FreedrawDebugSliders = () => { + const [streamline, setStreamline] = useState(0.62); + const [simplify, setSimplify] = useState(0.3); + + useEffect(() => { + if (!window.h) { + window.h = {} as any; + } + if (!window.h.debugFreedraw) { + window.h.debugFreedraw = { streamline: 0.62, simplify: 0.3 }; + } + + setStreamline(window.h.debugFreedraw.streamline); + setSimplify(window.h.debugFreedraw.simplify); + }, []); + + const handleStreamlineChange = (value: number) => { + setStreamline(value); + if (window.h && window.h.debugFreedraw) { + window.h.debugFreedraw.streamline = value; + } + }; + + const handleSimplifyChange = (value: number) => { + setSimplify(value); + if (window.h && window.h.debugFreedraw) { + window.h.debugFreedraw.simplify = value; + } + }; + + return ( +
+
+ +
+
+ +
+
+ ); +}; diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 3a7e6964df..9fa9d9d2e6 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -50,7 +50,10 @@ const calculateVelocityBasedPressure = ( return Math.max(0.1, Math.min(1.0, pressure)); }; -export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { +export const getFreedrawStroke = ( + element: ExcalidrawFreeDrawElement, + debugParams?: { streamline?: number; simplify?: number }, +) => { // Compose points as [x, y, pressure] let points: [number, number, number][]; if (element.simulatePressure) { @@ -80,10 +83,23 @@ export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { }); } + const streamline = + (typeof window !== "undefined" && + window.h && + window.h.debugFreedraw?.streamline) ?? + debugParams?.streamline ?? + 0.62; + const simplify = + (typeof window !== "undefined" && + window.h && + window.h.debugFreedraw?.simplify) ?? + debugParams?.simplify ?? + 0.3; + const laser = new LaserPointer({ size: element.strokeWidth, - streamline: 0.62, - simplify: 0.3, + streamline: streamline === false ? 0.62 : streamline, + simplify: simplify === false ? 0.3 : simplify, sizeMapping: ({ pressure: t }) => { if (element.simulatePressure) { return t + 0.2; @@ -114,13 +130,14 @@ export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { */ export const getFreeDrawSvgPath = ( element: ExcalidrawFreeDrawElement, + debugParams?: { streamline?: number; simplify?: number }, ): string => { // legacy, for backwards compatibility if (element.pressureSensitivity === null) { return _legacy_getFreeDrawSvgPath(element); } - return getSvgPathFromStroke(getFreedrawStroke(element)); + return getSvgPathFromStroke(getFreedrawStroke(element, debugParams)); }; const roundPoint = (A: Point): string => { diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 45fc5109d8..3e3ccb49fc 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -11371,6 +11371,10 @@ declare global { app: InstanceType; history: History; store: Store; + debugFreedraw?: { + streamline: number; + simplify: number; + }; }; } } @@ -11379,6 +11383,12 @@ export const createTestHook = () => { if (isTestEnv() || isDevEnv()) { window.h = window.h || ({} as Window["h"]); + // Initialize debug freedraw parameters + window.h.debugFreedraw = window.h.debugFreedraw || { + streamline: 0.62, + simplify: 0.3, + }; + Object.defineProperties(window.h, { elements: { configurable: true, From e99baaa6bbd0d47d45f1ac121a1788141a55cfbe Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 9 Jun 2025 21:08:57 +1000 Subject: [PATCH 10/31] fix simulate pressure --- packages/excalidraw/components/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 3e3ccb49fc..04f8437707 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -7573,7 +7573,7 @@ class App extends React.Component { y: gridY, }); - const simulatePressure = event.pressure === 0.5; + const simulatePressure = event.pressure === 0.5 || event.pressure === 0; const element = newFreeDrawElement({ type: elementType, From c08840358ba5bc6f47866a6cdcddce67da7ea5fb Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Wed, 11 Jun 2025 18:05:46 +1000 Subject: [PATCH 11/31] fix: funky shape corners for freedraw --- packages/element/src/Shape.ts | 31 +++++++------- .../tests/__snapshots__/history.test.tsx.snap | 42 +++++-------------- .../regressionTests.test.tsx.snap | 24 +++-------- 3 files changed, 30 insertions(+), 67 deletions(-) diff --git a/packages/element/src/Shape.ts b/packages/element/src/Shape.ts index 16da46381a..f634fa5c3b 100644 --- a/packages/element/src/Shape.ts +++ b/packages/element/src/Shape.ts @@ -20,8 +20,6 @@ import { canChangeRoundness } from "./comparisons"; import { generateFreeDrawShape } from "./renderElement"; import { getArrowheadPoints, getDiamondPoints } from "./bounds"; -import { getFreedrawStroke } from "./freedraw"; - import type { ExcalidrawElement, NonDeletedExcalidrawElement, @@ -514,22 +512,21 @@ export const _generateElementShape = ( generateFreeDrawShape(element); if (isPathALoop(element.points)) { - let points; - if (element.pressureSensitivity === null) { - // legacy freedraw - points = simplify(element.points as LocalPoint[], 0.75); - } else { - // new freedraw - const stroke = getFreedrawStroke(element); - points = stroke - .slice(0, Math.floor(stroke.length / 2)) - .map((p) => pointFrom(p[0], p[1])); - } + const points = + element.pressureSensitivity === null + ? simplify(element.points as LocalPoint[], 0.75) + : simplify(element.points as LocalPoint[], 1.5); - shape = generator.curve(points, { - ...generateRoughOptions(element), - stroke: "none", - }); + shape = + element.pressureSensitivity === null + ? generator.curve(points, { + ...generateRoughOptions(element), + stroke: "none", + }) + : generator.polygon(points, { + ...generateRoughOptions(element), + stroke: "none", + }); } else { shape = null; } diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index be6cc48a8c..dd02103fb9 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -8943,15 +8943,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -9052,15 +9047,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -12103,14 +12093,10 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -12158,14 +12144,10 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#e03131", "strokeStyle": "solid", "strokeWidth": 2, @@ -12302,14 +12284,10 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#e03131", "strokeStyle": "solid", "strokeWidth": 2, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index b179176fb5..3fbebddd7a 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -6905,14 +6905,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -9184,14 +9180,10 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -10192,14 +10184,10 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta ], ], "pressureSensitivity": 1, - "pressures": [ - 0, - 0, - 0, - ], + "pressures": [], "roughness": 1, "roundness": null, - "simulatePressure": false, + "simulatePressure": true, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, From 37b75263f8b51b2ea446bb0e496e9fa3795b9107 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 13 Jun 2025 18:12:56 +1000 Subject: [PATCH 12/31] put streamline & simplify into ele obj too --- .../components/FreedrawDebugSliders.tsx | 11 ++++-- packages/element/src/Shape.ts | 4 +- packages/element/src/freedraw.ts | 37 +++++++++---------- packages/element/src/newElement.ts | 8 +++- packages/element/src/types.ts | 6 ++- .../excalidraw/actions/actionProperties.tsx | 4 +- packages/excalidraw/components/App.tsx | 20 +++++++--- packages/excalidraw/data/restore.ts | 3 +- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/excalidraw-app/components/FreedrawDebugSliders.tsx b/excalidraw-app/components/FreedrawDebugSliders.tsx index 607e066c3c..85d843e9a9 100644 --- a/excalidraw-app/components/FreedrawDebugSliders.tsx +++ b/excalidraw-app/components/FreedrawDebugSliders.tsx @@ -1,15 +1,20 @@ +import { DRAWING_CONFIGS } from "@excalidraw/element"; import { useState, useEffect } from "react"; export const FreedrawDebugSliders = () => { - const [streamline, setStreamline] = useState(0.62); - const [simplify, setSimplify] = useState(0.3); + const [streamline, setStreamline] = useState( + DRAWING_CONFIGS.default.streamline, + ); + const [simplify, setSimplify] = useState( + DRAWING_CONFIGS.default.simplify, + ); useEffect(() => { if (!window.h) { window.h = {} as any; } if (!window.h.debugFreedraw) { - window.h.debugFreedraw = { streamline: 0.62, simplify: 0.3 }; + window.h.debugFreedraw = DRAWING_CONFIGS.default; } setStreamline(window.h.debugFreedraw.streamline); diff --git a/packages/element/src/Shape.ts b/packages/element/src/Shape.ts index f634fa5c3b..3c7b04f413 100644 --- a/packages/element/src/Shape.ts +++ b/packages/element/src/Shape.ts @@ -513,12 +513,12 @@ export const _generateElementShape = ( if (isPathALoop(element.points)) { const points = - element.pressureSensitivity === null + element.drawingConfigs === null ? simplify(element.points as LocalPoint[], 0.75) : simplify(element.points as LocalPoint[], 1.5); shape = - element.pressureSensitivity === null + element.drawingConfigs === null ? generator.curve(points, { ...generateRoughOptions(element), stroke: "none", diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 9fa9d9d2e6..5d4696049f 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -8,6 +8,13 @@ import type { StrokeOptions } from "perfect-freehand"; import type { ExcalidrawFreeDrawElement } from "./types"; +export const DRAWING_CONFIGS = { + default: { + streamline: 0.25, + simplify: 0.1, + }, +} as const; + /** * Calculates simulated pressure based on velocity between consecutive points. * Fast movement (large distances) -> lower pressure @@ -16,7 +23,7 @@ import type { ExcalidrawFreeDrawElement } from "./types"; const calculateVelocityBasedPressure = ( points: readonly LocalPoint[], index: number, - pressureSensitivity: number | null, + pressureSensitivity: number | undefined, maxDistance = 8, // Maximum expected distance for normalization ): number => { // Handle pressure sensitivity @@ -64,11 +71,11 @@ export const getFreedrawStroke = ( calculateVelocityBasedPressure( element.points, i, - element.pressureSensitivity, + element.drawingConfigs?.pressureSensitivity, ), ]); } else { - const sensitivity = element.pressureSensitivity ?? 1; + const sensitivity = element.drawingConfigs?.pressureSensitivity ?? 1; points = element.points.map(([x, y]: LocalPoint, i) => { if (sensitivity === 0) { return [x, y, 0.5]; @@ -84,28 +91,20 @@ export const getFreedrawStroke = ( } const streamline = - (typeof window !== "undefined" && - window.h && - window.h.debugFreedraw?.streamline) ?? - debugParams?.streamline ?? - 0.62; + element.drawingConfigs?.streamline ?? DRAWING_CONFIGS.default.streamline; const simplify = - (typeof window !== "undefined" && - window.h && - window.h.debugFreedraw?.simplify) ?? - debugParams?.simplify ?? - 0.3; + element.drawingConfigs?.simplify ?? DRAWING_CONFIGS.default.simplify; const laser = new LaserPointer({ size: element.strokeWidth, - streamline: streamline === false ? 0.62 : streamline, - simplify: simplify === false ? 0.3 : simplify, + streamline, + simplify, sizeMapping: ({ pressure: t }) => { if (element.simulatePressure) { return t + 0.2; } - if (element.pressureSensitivity === 0) { + if (element.drawingConfigs?.pressureSensitivity === 0) { return 1; } @@ -133,7 +132,7 @@ export const getFreeDrawSvgPath = ( debugParams?: { streamline?: number; simplify?: number }, ): string => { // legacy, for backwards compatibility - if (element.pressureSensitivity === null) { + if (element.drawingConfigs === null) { return _legacy_getFreeDrawSvgPath(element); } @@ -188,7 +187,7 @@ function _legacy_getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]]; - const sensitivity = element.pressureSensitivity; + const sensitivity = element.drawingConfigs?.pressureSensitivity; // Consider changing the options for simulated pressure vs real pressure const options: StrokeOptions = { @@ -196,7 +195,7 @@ function _legacy_getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { // if sensitivity is not set, times 4.25 for backwards compatibility size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), // if sensitivity is not set, set thinning to 0.6 for backwards compatibility - thinning: sensitivity !== null ? 0.5 * sensitivity : 0.6, + thinning: sensitivity !== undefined ? 0.5 * sensitivity : 0.6, smoothing: 0.5, streamline: 0.5, easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine diff --git a/packages/element/src/newElement.ts b/packages/element/src/newElement.ts index 5d6f6835ff..c1ad2787ef 100644 --- a/packages/element/src/newElement.ts +++ b/packages/element/src/newElement.ts @@ -445,7 +445,7 @@ export const newFreeDrawElement = ( points?: ExcalidrawFreeDrawElement["points"]; simulatePressure: boolean; pressures?: ExcalidrawFreeDrawElement["pressures"]; - pressureSensitivity?: ExcalidrawFreeDrawElement["pressureSensitivity"]; + drawingConfigs?: ExcalidrawFreeDrawElement["drawingConfigs"]; } & ElementConstructorOpts, ): NonDeleted => { return { @@ -454,7 +454,11 @@ export const newFreeDrawElement = ( pressures: opts.pressures || [], simulatePressure: opts.simulatePressure, lastCommittedPoint: null, - pressureSensitivity: opts.pressureSensitivity ?? 1, + drawingConfigs: opts.drawingConfigs || { + pressureSensitivity: 1, + streamline: 0.25, + simplify: 0.1, + }, }; }; diff --git a/packages/element/src/types.ts b/packages/element/src/types.ts index c11fecee3c..fd03e91b97 100644 --- a/packages/element/src/types.ts +++ b/packages/element/src/types.ts @@ -377,9 +377,13 @@ export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase & type: "freedraw"; points: readonly LocalPoint[]; pressures: readonly number[]; - pressureSensitivity: number | null; simulatePressure: boolean; lastCommittedPoint: LocalPoint | null; + drawingConfigs: { + streamline?: number; + simplify?: number; + pressureSensitivity?: number; + } | null; }>; export type FileId = string & { _brand: "FileId" }; diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index d9a39330f5..9cf67dce15 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -693,12 +693,12 @@ export const actionChangePressureSensitivity = register({ const commonPressureSensitivity = selectedElements .filter(isFreeDrawElement) .reduce((acc, element) => { - const sensitivity = element.pressureSensitivity ?? 1; + const sensitivity = element.drawingConfigs?.pressureSensitivity ?? 1; if (acc !== null && acc !== sensitivity) { return null; // No common value } return sensitivity; - }, firstElement?.pressureSensitivity ?? null); + }, firstElement?.drawingConfigs?.pressureSensitivity ?? null); const currentValue = commonPressureSensitivity ?? appState.currentItemPressureSensitivity; diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 04f8437707..6edfb88d2f 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -104,7 +104,11 @@ import { Emitter, } from "@excalidraw/common"; -import { getCommonBounds, getElementAbsoluteCoords } from "@excalidraw/element"; +import { + DRAWING_CONFIGS, + getCommonBounds, + getElementAbsoluteCoords, +} from "@excalidraw/element"; import { bindOrUnbindLinearElements, @@ -7588,7 +7592,14 @@ class App extends React.Component { opacity: this.state.currentItemOpacity, roundness: null, simulatePressure, - pressureSensitivity: this.state.currentItemPressureSensitivity, + drawingConfigs: { + pressureSensitivity: this.state.currentItemPressureSensitivity, + streamline: + window.h?.debugFreedraw?.streamline ?? + DRAWING_CONFIGS.default.streamline, + simplify: + window.h?.debugFreedraw?.simplify ?? DRAWING_CONFIGS.default.simplify, + }, locked: false, frameId: topLayerFrame ? topLayerFrame.id : null, points: [pointFrom(0, 0)], @@ -11384,10 +11395,7 @@ export const createTestHook = () => { window.h = window.h || ({} as Window["h"]); // Initialize debug freedraw parameters - window.h.debugFreedraw = window.h.debugFreedraw || { - streamline: 0.62, - simplify: 0.3, - }; + window.h.debugFreedraw = window.h.debugFreedraw || DRAWING_CONFIGS.default; Object.defineProperties(window.h, { elements: { diff --git a/packages/excalidraw/data/restore.ts b/packages/excalidraw/data/restore.ts index fd0f43b616..9433745b9d 100644 --- a/packages/excalidraw/data/restore.ts +++ b/packages/excalidraw/data/restore.ts @@ -302,7 +302,8 @@ const restoreElement = ( lastCommittedPoint: null, simulatePressure: element.simulatePressure, pressures: element.pressures, - pressureSensitivity: element.pressureSensitivity ?? null, + // legacy, for backwards compatibility + drawingConfigs: element.drawingConfigs ?? null, }); } case "image": From c72c47f0cda8bab06d1eb34bac7493912e392b33 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 16 Jun 2025 17:19:55 +1000 Subject: [PATCH 13/31] remove debug and provide value for stylus --- excalidraw-app/App.tsx | 2 - .../components/FreedrawDebugSliders.tsx | 89 ------------------- packages/element/src/freedraw.ts | 5 ++ packages/excalidraw/components/App.tsx | 15 +--- .../tests/__snapshots__/history.test.tsx.snap | 30 +++++-- .../regressionTests.test.tsx.snap | 18 +++- .../data/__snapshots__/restore.test.ts.snap | 6 +- 7 files changed, 53 insertions(+), 112 deletions(-) delete mode 100644 excalidraw-app/components/FreedrawDebugSliders.tsx diff --git a/excalidraw-app/App.tsx b/excalidraw-app/App.tsx index 40c14ca3e3..932743ddfd 100644 --- a/excalidraw-app/App.tsx +++ b/excalidraw-app/App.tsx @@ -134,7 +134,6 @@ import DebugCanvas, { } from "./components/DebugCanvas"; import { AIComponents } from "./components/AI"; import { ExcalidrawPlusIframeExport } from "./ExcalidrawPlusIframeExport"; -import { FreedrawDebugSliders } from "./components/FreedrawDebugSliders"; import "./index.scss"; @@ -1143,7 +1142,6 @@ const ExcalidrawWrapper = () => { ref={debugCanvasRef} /> )} - ); diff --git a/excalidraw-app/components/FreedrawDebugSliders.tsx b/excalidraw-app/components/FreedrawDebugSliders.tsx deleted file mode 100644 index 85d843e9a9..0000000000 --- a/excalidraw-app/components/FreedrawDebugSliders.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { DRAWING_CONFIGS } from "@excalidraw/element"; -import { useState, useEffect } from "react"; - -export const FreedrawDebugSliders = () => { - const [streamline, setStreamline] = useState( - DRAWING_CONFIGS.default.streamline, - ); - const [simplify, setSimplify] = useState( - DRAWING_CONFIGS.default.simplify, - ); - - useEffect(() => { - if (!window.h) { - window.h = {} as any; - } - if (!window.h.debugFreedraw) { - window.h.debugFreedraw = DRAWING_CONFIGS.default; - } - - setStreamline(window.h.debugFreedraw.streamline); - setSimplify(window.h.debugFreedraw.simplify); - }, []); - - const handleStreamlineChange = (value: number) => { - setStreamline(value); - if (window.h && window.h.debugFreedraw) { - window.h.debugFreedraw.streamline = value; - } - }; - - const handleSimplifyChange = (value: number) => { - setSimplify(value); - if (window.h && window.h.debugFreedraw) { - window.h.debugFreedraw.simplify = value; - } - }; - - return ( -
-
- -
-
- -
-
- ); -}; diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 5d4696049f..7f984f6d31 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -11,6 +11,11 @@ import type { ExcalidrawFreeDrawElement } from "./types"; export const DRAWING_CONFIGS = { default: { streamline: 0.25, + simplify: 0.25, + }, + // for optimal performance, we use a lower streamline and simplify + stylus: { + streamline: 0.1, simplify: 0.1, }, } as const; diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 6edfb88d2f..d7750e4dd5 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -7594,11 +7594,9 @@ class App extends React.Component { simulatePressure, drawingConfigs: { pressureSensitivity: this.state.currentItemPressureSensitivity, - streamline: - window.h?.debugFreedraw?.streamline ?? - DRAWING_CONFIGS.default.streamline, - simplify: - window.h?.debugFreedraw?.simplify ?? DRAWING_CONFIGS.default.simplify, + ...(event.pointerType === "pen" + ? DRAWING_CONFIGS.stylus + : DRAWING_CONFIGS.default), }, locked: false, frameId: topLayerFrame ? topLayerFrame.id : null, @@ -11382,10 +11380,6 @@ declare global { app: InstanceType; history: History; store: Store; - debugFreedraw?: { - streamline: number; - simplify: number; - }; }; } } @@ -11394,9 +11388,6 @@ export const createTestHook = () => { if (isTestEnv() || isDevEnv()) { window.h = window.h || ({} as Window["h"]); - // Initialize debug freedraw parameters - window.h.debugFreedraw = window.h.debugFreedraw || DRAWING_CONFIGS.default; - Object.defineProperties(window.h, { elements: { configurable: true, diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index dd02103fb9..70dff4bd64 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -8910,6 +8910,11 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -8942,7 +8947,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte 50, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, @@ -9015,6 +9019,11 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -9046,7 +9055,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte 50, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, @@ -12064,6 +12072,11 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -12092,7 +12105,6 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, @@ -12115,6 +12127,11 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -12143,7 +12160,6 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, @@ -12256,6 +12272,11 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -12283,7 +12304,6 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 3fbebddd7a..86ef418bdd 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -6877,6 +6877,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -6904,7 +6909,6 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, @@ -9152,6 +9156,11 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -9179,7 +9188,6 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, @@ -10156,6 +10164,11 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta "backgroundColor": "transparent", "boundElements": null, "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.25000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -10183,7 +10196,6 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": null, diff --git a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap index cc9e0b987d..c389dc629e 100644 --- a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap +++ b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap @@ -170,6 +170,11 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` "backgroundColor": "transparent", "boundElements": [], "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.10000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -191,7 +196,6 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": { From b1f3cc50ee34d5df834f07ad2630c64deed6bc30 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 16 Jun 2025 22:06:10 +1000 Subject: [PATCH 14/31] 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 b9e5661a94..e3c53820e8 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 7f984f6d31..90b5fed680 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 38419ce827..792c6c67ec 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 9cf67dce15..de62cf95b6 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 70dff4bd64..edb7125cc8 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 86ef418bdd..e78daa585c 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 e81e9e4e40..46b0d1f0a9 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 75de2717f8..07f383d37e 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); From 8ceb55dd021ce10e6f082592becff9c3025f826a Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Thu, 26 Jun 2025 22:20:01 +0200 Subject: [PATCH 15/31] Revert "remove debug and provide value for stylus" This reverts commit c72c47f0cda8bab06d1eb34bac7493912e392b33. # Conflicts: # packages/element/src/freedraw.ts # packages/excalidraw/tests/__snapshots__/history.test.tsx.snap # packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap --- excalidraw-app/App.tsx | 2 + .../components/FreedrawDebugSliders.tsx | 88 +++++++++++++++++++ packages/excalidraw/components/App.tsx | 15 +++- .../data/__snapshots__/restore.test.ts.snap | 6 +- 4 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 excalidraw-app/components/FreedrawDebugSliders.tsx diff --git a/excalidraw-app/App.tsx b/excalidraw-app/App.tsx index 932743ddfd..40c14ca3e3 100644 --- a/excalidraw-app/App.tsx +++ b/excalidraw-app/App.tsx @@ -134,6 +134,7 @@ import DebugCanvas, { } from "./components/DebugCanvas"; import { AIComponents } from "./components/AI"; import { ExcalidrawPlusIframeExport } from "./ExcalidrawPlusIframeExport"; +import { FreedrawDebugSliders } from "./components/FreedrawDebugSliders"; import "./index.scss"; @@ -1142,6 +1143,7 @@ const ExcalidrawWrapper = () => { ref={debugCanvasRef} /> )} +
); diff --git a/excalidraw-app/components/FreedrawDebugSliders.tsx b/excalidraw-app/components/FreedrawDebugSliders.tsx new file mode 100644 index 0000000000..bf8b66b111 --- /dev/null +++ b/excalidraw-app/components/FreedrawDebugSliders.tsx @@ -0,0 +1,88 @@ +import { DRAWING_CONFIGS } from "@excalidraw/element"; +import { useState, useEffect } from "react"; + +export const FreedrawDebugSliders = () => { + const [streamline, setStreamline] = useState( + DRAWING_CONFIGS.default.streamline, + ); + const [simplify, setSimplify] = useState( + DRAWING_CONFIGS.default.simplify, + ); + + useEffect(() => { + if (!window.h) { + window.h = {} as any; + } + if (!window.h.debugFreedraw) { + window.h.debugFreedraw = DRAWING_CONFIGS.default; + } + + setStreamline(window.h.debugFreedraw.streamline); + setSimplify(window.h.debugFreedraw.simplify); + }, []); + + const handleStreamlineChange = (value: number) => { + setStreamline(value); + if (window.h && window.h.debugFreedraw) { + window.h.debugFreedraw.streamline = value; + } + }; + + const handleSimplifyChange = (value: number) => { + setSimplify(value); + if (window.h && window.h.debugFreedraw) { + window.h.debugFreedraw.simplify = value; + } + }; + + return ( +
+
+ +
+
+ +
+
+ ); +}; diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index d7750e4dd5..6edfb88d2f 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -7594,9 +7594,11 @@ class App extends React.Component { simulatePressure, drawingConfigs: { pressureSensitivity: this.state.currentItemPressureSensitivity, - ...(event.pointerType === "pen" - ? DRAWING_CONFIGS.stylus - : DRAWING_CONFIGS.default), + streamline: + window.h?.debugFreedraw?.streamline ?? + DRAWING_CONFIGS.default.streamline, + simplify: + window.h?.debugFreedraw?.simplify ?? DRAWING_CONFIGS.default.simplify, }, locked: false, frameId: topLayerFrame ? topLayerFrame.id : null, @@ -11380,6 +11382,10 @@ declare global { app: InstanceType; history: History; store: Store; + debugFreedraw?: { + streamline: number; + simplify: number; + }; }; } } @@ -11388,6 +11394,9 @@ export const createTestHook = () => { if (isTestEnv() || isDevEnv()) { window.h = window.h || ({} as Window["h"]); + // Initialize debug freedraw parameters + window.h.debugFreedraw = window.h.debugFreedraw || DRAWING_CONFIGS.default; + Object.defineProperties(window.h, { elements: { configurable: true, diff --git a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap index c389dc629e..cc9e0b987d 100644 --- a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap +++ b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap @@ -170,11 +170,6 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` "backgroundColor": "transparent", "boundElements": [], "customData": undefined, - "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.10000", - "streamline": "0.25000", - }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -196,6 +191,7 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` 10, ], ], + "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": { From 09876aba6d888e36b525dd7c2ef576aa4af89afd Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 27 Jun 2025 20:17:44 +1000 Subject: [PATCH 16/31] change to fixedStrokeWidth --- excalidraw-app/tests/LanguageList.test.tsx | 34 ----- packages/element/src/freedraw.ts | 42 +++--- packages/element/src/types.ts | 2 +- .../excalidraw/actions/actionProperties.tsx | 49 ++++--- packages/excalidraw/appState.ts | 4 +- packages/excalidraw/components/App.tsx | 2 +- .../__snapshots__/contextmenu.test.tsx.snap | 34 ++--- .../tests/__snapshots__/history.test.tsx.snap | 136 +++++++++--------- .../regressionTests.test.tsx.snap | 116 +++++++-------- .../data/__snapshots__/restore.test.ts.snap | 6 +- packages/excalidraw/types.ts | 2 +- .../tests/__snapshots__/export.test.ts.snap | 2 +- 12 files changed, 199 insertions(+), 230 deletions(-) delete mode 100644 excalidraw-app/tests/LanguageList.test.tsx diff --git a/excalidraw-app/tests/LanguageList.test.tsx b/excalidraw-app/tests/LanguageList.test.tsx deleted file mode 100644 index a0cfe07224..0000000000 --- a/excalidraw-app/tests/LanguageList.test.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { defaultLang } from "@excalidraw/excalidraw/i18n"; -import { UI } from "@excalidraw/excalidraw/tests/helpers/ui"; -import { - screen, - fireEvent, - waitFor, - render, -} from "@excalidraw/excalidraw/tests/test-utils"; - -import ExcalidrawApp from "../App"; - -describe("Test LanguageList", () => { - it("rerenders UI on language change", async () => { - await render(); - - // select rectangle tool to show properties menu - UI.clickTool("rectangle"); - // english lang should display `thin` label - expect(screen.queryByTitle(/thin/i)).not.toBeNull(); - fireEvent.click(document.querySelector(".dropdown-menu-button")!); - - fireEvent.change(document.querySelector(".dropdown-select__language")!, { - target: { value: "de-DE" }, - }); - // switching to german, `thin` label should no longer exist - await waitFor(() => expect(screen.queryByTitle(/thin/i)).toBeNull()); - // reset language - fireEvent.change(document.querySelector(".dropdown-select__language")!, { - target: { value: defaultLang.code }, - }); - // switching back to English - await waitFor(() => expect(screen.queryByTitle(/thin/i)).not.toBeNull()); - }); -}); diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 90b5fed680..21fcff79f6 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -11,11 +11,11 @@ import type { ExcalidrawFreeDrawElement } from "./types"; export const DRAWING_CONFIGS = { default: { streamline: 0.35, - simplify: 0.25, + simplify: 0.1, }, // for optimal performance, we use a lower streamline and simplify stylus: { - streamline: 0.1, + streamline: 0.35, simplify: 0.1, }, } as const; @@ -28,15 +28,11 @@ export const DRAWING_CONFIGS = { const calculateVelocityBasedPressure = ( points: readonly LocalPoint[], index: number, - pressureSensitivity: number | undefined, + fixedStrokeWidth: boolean | undefined, maxDistance = 8, // Maximum expected distance for normalization ): number => { - // Handle pressure sensitivity - const sensitivity = pressureSensitivity ?? 1; // Default to 1 for backwards compatibility - - // If sensitivity is 0, return constant pressure - if (sensitivity === 0) { - return 0.6; + if (fixedStrokeWidth) { + return 1; } // First point gets highest pressure @@ -56,8 +52,7 @@ const calculateVelocityBasedPressure = ( const basePressure = Math.max(0.1, 1 - normalizedDistance * 0.7); // Range: 0.1 to 1.0 const constantPressure = 0.5; - const pressure = - constantPressure + (basePressure - constantPressure) * sensitivity; + const pressure = constantPressure + (basePressure - constantPressure); return Math.max(0.1, Math.min(1.0, pressure)); }; @@ -65,7 +60,11 @@ const calculateVelocityBasedPressure = ( export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { // Compose points as [x, y, pressure] let points: [number, number, number][]; - if (element.simulatePressure) { + if (element.drawingConfigs?.fixedStrokeWidth) { + points = element.points.map( + ([x, y]: LocalPoint): [number, number, number] => [x, y, 1], + ); + } else if (element.simulatePressure) { // Simulate pressure based on velocity between consecutive points points = element.points.map(([x, y]: LocalPoint, i) => [ x, @@ -73,20 +72,15 @@ export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { calculateVelocityBasedPressure( element.points, i, - element.drawingConfigs?.pressureSensitivity, + element.drawingConfigs?.fixedStrokeWidth, ), ]); } else { - const sensitivity = element.drawingConfigs?.pressureSensitivity ?? 1; points = element.points.map(([x, y]: LocalPoint, i) => { - if (sensitivity === 0) { - return [x, y, 0.5]; - } - const rawPressure = element.pressures?.[i] ?? 0.5; const amplifiedPressure = Math.pow(rawPressure, 0.6); - const adjustedPressure = amplifiedPressure * sensitivity; + const adjustedPressure = amplifiedPressure; return [x, y, clamp(adjustedPressure, 0.1, 1.0)]; }); @@ -102,7 +96,7 @@ export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { streamline, simplify, sizeMapping: ({ pressure: t }) => { - if (element.drawingConfigs?.pressureSensitivity === 0) { + if (element.drawingConfigs?.fixedStrokeWidth) { return 0.5; } @@ -186,15 +180,11 @@ function _legacy_getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) { ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]]; - const sensitivity = element.drawingConfigs?.pressureSensitivity; - // Consider changing the options for simulated pressure vs real pressure const options: StrokeOptions = { simulatePressure: element.simulatePressure, - // if sensitivity is not set, times 4.25 for backwards compatibility - size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), - // if sensitivity is not set, set thinning to 0.6 for backwards compatibility - thinning: sensitivity !== undefined ? 0.5 * sensitivity : 0.6, + size: element.strokeWidth * 4.25, + thinning: 0.6, smoothing: 0.5, streamline: 0.5, easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine diff --git a/packages/element/src/types.ts b/packages/element/src/types.ts index fd03e91b97..2ae6455738 100644 --- a/packages/element/src/types.ts +++ b/packages/element/src/types.ts @@ -382,7 +382,7 @@ export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase & drawingConfigs: { streamline?: number; simplify?: number; - pressureSensitivity?: number; + fixedStrokeWidth?: boolean; } | null; }>; diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index de62cf95b6..17fd1986a4 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -559,7 +559,10 @@ export const actionChangeStrokeWidth = register({ isFreeDrawElement(element)) ? WIDTHS : WIDTHS.slice(0, 3) } @@ -690,31 +693,37 @@ export const actionChangePressureSensitivity = register({ label: "labels.strokeType", trackEvent: false, perform: (elements, appState, value) => { + const updatedElements = changeProperty(elements, appState, (el) => { + if (isFreeDrawElement(el)) { + return newElementWith(el, { + drawingConfigs: { + ...el.drawingConfigs, + fixedStrokeWidth: value, + }, + }); + } + return el; + }); + return { - elements, - appState: { ...appState, currentItemPressureSensitivity: value }, + elements: updatedElements, + appState: { ...appState, currentItemFixedStrokeWidth: value }, captureUpdate: CaptureUpdateAction.IMMEDIATELY, }; }, PanelComponent: ({ app, appState, updateData }) => { - if (appState.activeTool.type !== "freedraw") { - return null; - } - const selectedElements = app.scene.getSelectedElements(app.state); - const firstElement = selectedElements.find(isFreeDrawElement); - const commonPressureSensitivity = selectedElements - .filter(isFreeDrawElement) - .reduce((acc, element) => { - const sensitivity = element.drawingConfigs?.pressureSensitivity ?? 1; - if (acc !== null && acc !== sensitivity) { - return null; // No common value - } - return sensitivity; - }, firstElement?.drawingConfigs?.pressureSensitivity ?? null); + const freedraws = selectedElements.filter(isFreeDrawElement); + + const commonFixedStrokeWidth = + freedraws.length > 0 + ? freedraws.every((e) => e.drawingConfigs?.fixedStrokeWidth) + : null; const currentValue = - commonPressureSensitivity ?? appState.currentItemPressureSensitivity; + freedraws.length > 0 + ? freedraws.every((e) => e.drawingConfigs?.fixedStrokeWidth) || null + : appState.currentItemFixedStrokeWidth; return (
@@ -724,13 +733,13 @@ export const actionChangePressureSensitivity = register({ group="pressure-sensitivity" options={[ { - value: 0, + value: true, text: t("labels.strokeWidthFixed"), icon: strokeWidthFixedIcon, testId: "pressure-fixed", }, { - value: 1, + value: false, text: t("labels.strokeWidthVariable"), icon: strokeWidthVariableIcon, testId: "pressure-variable", diff --git a/packages/excalidraw/appState.ts b/packages/excalidraw/appState.ts index ef6d03dc75..70913c9ac9 100644 --- a/packages/excalidraw/appState.ts +++ b/packages/excalidraw/appState.ts @@ -33,7 +33,7 @@ export const getDefaultAppState = (): Omit< currentItemFontFamily: DEFAULT_FONT_FAMILY, currentItemFontSize: DEFAULT_FONT_SIZE, currentItemOpacity: DEFAULT_ELEMENT_PROPS.opacity, - currentItemPressureSensitivity: 1, + currentItemFixedStrokeWidth: true, currentItemRoughness: DEFAULT_ELEMENT_PROPS.roughness, currentItemStartArrowhead: null, currentItemStrokeColor: DEFAULT_ELEMENT_PROPS.strokeColor, @@ -164,7 +164,7 @@ const APP_STATE_STORAGE_CONF = (< server: false, }, currentItemOpacity: { browser: true, export: false, server: false }, - currentItemPressureSensitivity: { + currentItemFixedStrokeWidth: { browser: true, export: false, server: false, diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 6edfb88d2f..55c8ff7f45 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -7593,7 +7593,7 @@ class App extends React.Component { roundness: null, simulatePressure, drawingConfigs: { - pressureSensitivity: this.state.currentItemPressureSensitivity, + fixedStrokeWidth: this.state.currentItemFixedStrokeWidth, streamline: window.h?.debugFreedraw?.streamline ?? DRAWING_CONFIGS.default.streamline, diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index 1842c67daf..344c02f85b 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -894,10 +894,10 @@ exports[`contextMenu element > right-clicking on a group should select whole gro "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1098,10 +1098,10 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1315,10 +1315,10 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1649,10 +1649,10 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1983,10 +1983,10 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2200,10 +2200,10 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2442,10 +2442,10 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2745,10 +2745,10 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3118,10 +3118,10 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "currentItemBackgroundColor": "#a5d8ff", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "cross-hatch", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 60, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 2, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3627,10 +3627,10 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3953,10 +3953,10 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4279,10 +4279,10 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5561,10 +5561,10 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6783,10 +6783,10 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7719,10 +7719,10 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8720,10 +8720,10 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9712,10 +9712,10 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index edb7125cc8..2cc66921b0 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -20,10 +20,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -612,10 +612,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1122,10 +1122,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1491,10 +1491,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1861,10 +1861,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2129,10 +2129,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2567,10 +2567,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2867,10 +2867,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3152,10 +3152,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3447,10 +3447,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3734,10 +3734,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3970,10 +3970,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4230,10 +4230,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4504,10 +4504,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4736,10 +4736,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4968,10 +4968,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5198,10 +5198,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5428,10 +5428,10 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5689,10 +5689,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6023,10 +6023,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6453,10 +6453,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6834,10 +6834,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7155,10 +7155,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7457,10 +7457,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7688,10 +7688,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8045,10 +8045,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8402,10 +8402,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8811,10 +8811,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8911,8 +8911,8 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -9020,8 +9020,8 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -9099,10 +9099,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9366,10 +9366,10 @@ exports[`history > multiplayer undo/redo > should not override remote changes on "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9634,10 +9634,10 @@ exports[`history > multiplayer undo/redo > should not override remote changes on "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9867,10 +9867,10 @@ exports[`history > multiplayer undo/redo > should override remotely added groups "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10169,10 +10169,10 @@ exports[`history > multiplayer undo/redo > should override remotely added points "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10512,10 +10512,10 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10749,10 +10749,10 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11200,10 +11200,10 @@ exports[`history > multiplayer undo/redo > should update history entries after r "currentItemBackgroundColor": "#a5d8ff", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11459,10 +11459,10 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11699,10 +11699,10 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11941,10 +11941,10 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12073,8 +12073,8 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -12128,8 +12128,8 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -12273,8 +12273,8 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -12348,10 +12348,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on s "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12596,10 +12596,10 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12838,10 +12838,10 @@ exports[`history > singleplayer undo/redo > should end up with no history entry "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13080,10 +13080,10 @@ exports[`history > singleplayer undo/redo > should iterate through the history w "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13330,10 +13330,10 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13666,10 +13666,10 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13839,10 +13839,10 @@ exports[`history > singleplayer undo/redo > should not end up with history entry "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14128,10 +14128,10 @@ exports[`history > singleplayer undo/redo > should not end up with history entry "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14396,10 +14396,10 @@ exports[`history > singleplayer undo/redo > should not override appstate changes "currentItemBackgroundColor": "#a5d8ff", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14677,10 +14677,10 @@ exports[`history > singleplayer undo/redo > should support appstate name or view "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14840,10 +14840,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -15542,10 +15542,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -16163,10 +16163,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -16784,10 +16784,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -17500,10 +17500,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -18254,10 +18254,10 @@ exports[`history > singleplayer undo/redo > should support changes in elements' "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -18735,10 +18735,10 @@ exports[`history > singleplayer undo/redo > should support duplication of groups "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -19259,10 +19259,10 @@ exports[`history > singleplayer undo/redo > should support element creation, del "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -19721,10 +19721,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index e78daa585c..cfecb4b345 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -20,10 +20,10 @@ exports[`given element A and group of elements B and given both are selected whe "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -443,10 +443,10 @@ exports[`given element A and group of elements B and given both are selected whe "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -856,10 +856,10 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1413,10 +1413,10 @@ exports[`regression tests > Drags selected element when hitting only bounding bo "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -1619,10 +1619,10 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2000,10 +2000,10 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2237,10 +2237,10 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = ` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2418,10 +2418,10 @@ exports[`regression tests > can drag element that covers another element, while "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2742,10 +2742,10 @@ exports[`regression tests > change the properties of a shape > [end of test] app "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -2992,10 +2992,10 @@ exports[`regression tests > click on an element and drag it > [dragged] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3234,10 +3234,10 @@ exports[`regression tests > click on an element and drag it > [end of test] appS "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3467,10 +3467,10 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`] "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -3726,10 +3726,10 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4041,10 +4041,10 @@ exports[`regression tests > deleting last but one element in editing group shoul "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4472,10 +4472,10 @@ exports[`regression tests > deselects group of selected elements on pointer down "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -4758,10 +4758,10 @@ exports[`regression tests > deselects group of selected elements on pointer up w "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5035,10 +5035,10 @@ exports[`regression tests > deselects selected element on pointer down when poin "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5246,10 +5246,10 @@ exports[`regression tests > deselects selected element, on pointer up, when clic "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5447,10 +5447,10 @@ exports[`regression tests > double click to edit a group > [end of test] appStat "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -5835,10 +5835,10 @@ exports[`regression tests > drags selected elements from point inside common bou "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6129,10 +6129,10 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -6878,8 +6878,8 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -6953,10 +6953,10 @@ exports[`regression tests > given a group of selected elements with an element t "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7288,10 +7288,10 @@ exports[`regression tests > given a selected element A and a not selected elemen "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7568,10 +7568,10 @@ exports[`regression tests > given selected element A with lower z-index than uns "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -7804,10 +7804,10 @@ exports[`regression tests > given selected element A with lower z-index than uns "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8043,10 +8043,10 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8224,10 +8224,10 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8405,10 +8405,10 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8586,10 +8586,10 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -8811,10 +8811,10 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`] "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9036,10 +9036,10 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9157,8 +9157,8 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -9232,10 +9232,10 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9457,10 +9457,10 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9638,10 +9638,10 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`] "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -9863,10 +9863,10 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10044,10 +10044,10 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10165,8 +10165,8 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta "boundElements": null, "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, - "simplify": "0.25000", + "fixedStrokeWidth": true, + "simplify": "0.10000", "streamline": "0.35000", }, "fillStyle": "solid", @@ -10240,10 +10240,10 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10421,10 +10421,10 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -10922,10 +10922,10 @@ exports[`regression tests > noop interaction after undo shouldn't create history "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11203,10 +11203,10 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = ` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11327,10 +11327,10 @@ exports[`regression tests > shift click on selected element should deselect it o "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11528,10 +11528,10 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -11844,10 +11844,10 @@ exports[`regression tests > should group elements and ungroup them > [end of tes "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12262,10 +12262,10 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -12887,10 +12887,10 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13014,10 +13014,10 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`] "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13636,10 +13636,10 @@ exports[`regression tests > switches from group of selected elements to another "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -13978,10 +13978,10 @@ exports[`regression tests > switches selected element on pointer down > [end of "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14245,10 +14245,10 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`] "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14369,10 +14369,10 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14755,10 +14755,10 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 8, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, @@ -14879,10 +14879,10 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = ` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, diff --git a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap index cc9e0b987d..c389dc629e 100644 --- a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap +++ b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap @@ -170,6 +170,11 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` "backgroundColor": "transparent", "boundElements": [], "customData": undefined, + "drawingConfigs": { + "pressureSensitivity": 1, + "simplify": "0.10000", + "streamline": "0.25000", + }, "fillStyle": "solid", "frameId": null, "groupIds": [], @@ -191,7 +196,6 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` 10, ], ], - "pressureSensitivity": 1, "pressures": [], "roughness": 1, "roundness": { diff --git a/packages/excalidraw/types.ts b/packages/excalidraw/types.ts index ca092df395..b53a811550 100644 --- a/packages/excalidraw/types.ts +++ b/packages/excalidraw/types.ts @@ -333,7 +333,7 @@ export interface AppState { currentItemStrokeStyle: ExcalidrawElement["strokeStyle"]; currentItemRoughness: number; currentItemOpacity: number; - currentItemPressureSensitivity: number; + currentItemFixedStrokeWidth: boolean; currentItemFontFamily: FontFamilyValues; currentItemFontSize: number; currentItemTextAlign: TextAlign; diff --git a/packages/utils/tests/__snapshots__/export.test.ts.snap b/packages/utils/tests/__snapshots__/export.test.ts.snap index 196e4e229f..5a9a071118 100644 --- a/packages/utils/tests/__snapshots__/export.test.ts.snap +++ b/packages/utils/tests/__snapshots__/export.test.ts.snap @@ -20,10 +20,10 @@ exports[`exportToSvg > with default arguments 1`] = ` "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "solid", + "currentItemFixedStrokeWidth": true, "currentItemFontFamily": 5, "currentItemFontSize": 20, "currentItemOpacity": 100, - "currentItemPressureSensitivity": 1, "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, From abdacf8239146a5f3e1eebd224cc2dcf2f5861fd Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 27 Jun 2025 20:33:57 +1000 Subject: [PATCH 17/31] code cleanup --- packages/element/src/newElement.ts | 2 +- packages/excalidraw/actions/actionProperties.tsx | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/element/src/newElement.ts b/packages/element/src/newElement.ts index c1ad2787ef..cb0601ee05 100644 --- a/packages/element/src/newElement.ts +++ b/packages/element/src/newElement.ts @@ -455,7 +455,7 @@ export const newFreeDrawElement = ( simulatePressure: opts.simulatePressure, lastCommittedPoint: null, drawingConfigs: opts.drawingConfigs || { - pressureSensitivity: 1, + fixedStrokeWidth: true, streamline: 0.25, simplify: 0.1, }, diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index 190c494ec7..109958cc9d 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -712,14 +712,12 @@ export const actionChangePressureSensitivity = register({ const selectedElements = app.scene.getSelectedElements(app.state); const freedraws = selectedElements.filter(isFreeDrawElement); - const commonFixedStrokeWidth = - freedraws.length > 0 - ? freedraws.every((e) => e.drawingConfigs?.fixedStrokeWidth) - : null; - const currentValue = freedraws.length > 0 - ? freedraws.every((e) => e.drawingConfigs?.fixedStrokeWidth) || null + ? reduceToCommonValue( + freedraws, + (element) => element.drawingConfigs?.fixedStrokeWidth, + ) ?? null : appState.currentItemFixedStrokeWidth; return ( From 5666fd81990603ab768f0b326552965e9612922e Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 27 Jun 2025 20:51:50 +1000 Subject: [PATCH 18/31] update snap --- .../excalidraw/tests/data/__snapshots__/restore.test.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap index 97d06a0dbe..36aef9598f 100644 --- a/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap +++ b/packages/excalidraw/tests/data/__snapshots__/restore.test.ts.snap @@ -169,7 +169,7 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = ` "boundElements": [], "customData": undefined, "drawingConfigs": { - "pressureSensitivity": 1, + "fixedStrokeWidth": true, "simplify": "0.10000", "streamline": "0.25000", }, From 6d84fa21c5d2ff44e4d5cd3280ca3aba04e55e30 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:38:20 +0200 Subject: [PATCH 19/31] chore: bump @excalidraw/laser-pointer@1.3.2 --- packages/excalidraw/package.json | 2 +- packages/utils/package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/excalidraw/package.json b/packages/excalidraw/package.json index 7ebaed742b..ec257d64bc 100644 --- a/packages/excalidraw/package.json +++ b/packages/excalidraw/package.json @@ -72,7 +72,7 @@ }, "dependencies": { "@braintree/sanitize-url": "6.0.2", - "@excalidraw/laser-pointer": "1.3.1", + "@excalidraw/laser-pointer": "1.3.2", "@excalidraw/mermaid-to-excalidraw": "1.1.2", "@excalidraw/random-username": "1.1.0", "@radix-ui/react-popover": "1.1.6", diff --git a/packages/utils/package.json b/packages/utils/package.json index 6dc400c65c..d7537c3a9a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -49,7 +49,7 @@ }, "dependencies": { "@braintree/sanitize-url": "6.0.2", - "@excalidraw/laser-pointer": "1.3.1", + "@excalidraw/laser-pointer": "1.3.2", "browser-fs-access": "0.29.1", "open-color": "1.9.1", "pako": "2.0.3", diff --git a/yarn.lock b/yarn.lock index 21374749a6..c85c49c7af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1442,10 +1442,10 @@ resolved "https://registry.yarnpkg.com/@excalidraw/eslint-config/-/eslint-config-1.0.3.tgz#2122ef7413ae77874ae9848ce0f1c6b3f0d8bbbd" integrity sha512-GemHNF5Z6ga0BWBSX7GJaNBUchLu6RwTcAB84eX1MeckRNhNasAsPCdelDlFalz27iS4RuYEQh0bPE8SRxJgbQ== -"@excalidraw/laser-pointer@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@excalidraw/laser-pointer/-/laser-pointer-1.3.1.tgz#7c40836598e8e6ad91f01057883ed8b88fb9266c" - integrity sha512-psA1z1N2qeAfsORdXc9JmD2y4CmDwmuMRxnNdJHZexIcPwaNEyIpNcelw+QkL9rz9tosaN9krXuKaRqYpRAR6g== +"@excalidraw/laser-pointer@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@excalidraw/laser-pointer/-/laser-pointer-1.3.2.tgz#1f91182dfc77291df72551c83fa7bf9d740ad9ae" + integrity sha512-aKhVj3/lLV7TCkZr6q5kn9sBFxzpOQ/yyRwBGm6smsakMdp0o1FVp9HNKOPerEpkKEt34VTURekZLfqa3E1Few== "@excalidraw/markdown-to-text@0.1.2": version "0.1.2" From d9c85ff18f1eca576edd8397a19d955fb7ac93bb Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:56:47 +0200 Subject: [PATCH 20/31] bump extraBold width to 8 --- packages/common/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index 5d311eb500..434dd1bd09 100644 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -417,7 +417,7 @@ export const STROKE_WIDTH = { thin: 1, medium: 2, bold: 4, - extraBold: 6, + extraBold: 8, } as const; export const DEFAULT_ELEMENT_PROPS: { From 3c07ff358aee4dbc6a1eafa773615601d7287b07 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:07:12 +0200 Subject: [PATCH 21/31] differentiate freedraw config based on input type --- packages/element/src/freedraw.ts | 28 +++++++++++++++++++++----- packages/excalidraw/components/App.tsx | 9 +++++---- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/packages/element/src/freedraw.ts b/packages/element/src/freedraw.ts index 21fcff79f6..bc91490baf 100644 --- a/packages/element/src/freedraw.ts +++ b/packages/element/src/freedraw.ts @@ -6,20 +6,38 @@ import getStroke from "perfect-freehand"; import type { StrokeOptions } from "perfect-freehand"; -import type { ExcalidrawFreeDrawElement } from "./types"; +import type { ExcalidrawFreeDrawElement, PointerType } from "./types"; -export const DRAWING_CONFIGS = { +export const DRAWING_CONFIGS: Record< + PointerType | "default", + { streamline: number; simplify: number } +> = { default: { streamline: 0.35, simplify: 0.1, }, - // for optimal performance, we use a lower streamline and simplify - stylus: { - streamline: 0.35, + mouse: { + streamline: 0.6, + simplify: 0.1, + }, + pen: { + // for optimal performance, we use a lower streamline and simplify + streamline: 0.2, + simplify: 0.1, + }, + touch: { + streamline: 0.65, simplify: 0.1, }, } as const; +export const getFreedrawConfig = (eventType: string | null | undefined) => { + return ( + DRAWING_CONFIGS[(eventType as PointerType | null) || "default"] || + DRAWING_CONFIGS.default + ); +}; + /** * Calculates simulated pressure based on velocity between consecutive points. * Fast movement (large distances) -> lower pressure diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 2d76c38097..405eb045ee 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -233,6 +233,7 @@ import { isLineElement, isSimpleArrow, DRAWING_CONFIGS, + getFreedrawConfig, } from "@excalidraw/element"; import type { LocalPoint, Radians } from "@excalidraw/math"; @@ -7475,6 +7476,8 @@ class App extends React.Component { const simulatePressure = event.pressure === 0.5 || event.pressure === 0; + const freedrawConfig = getFreedrawConfig(event.pointerType); + const element = newFreeDrawElement({ type: elementType, x: gridX, @@ -7491,10 +7494,8 @@ class App extends React.Component { drawingConfigs: { fixedStrokeWidth: this.state.currentItemFixedStrokeWidth, streamline: - window.h?.debugFreedraw?.streamline ?? - DRAWING_CONFIGS.default.streamline, - simplify: - window.h?.debugFreedraw?.simplify ?? DRAWING_CONFIGS.default.simplify, + window.h?.debugFreedraw?.streamline ?? freedrawConfig.streamline, + simplify: window.h?.debugFreedraw?.simplify ?? freedrawConfig.simplify, }, locked: false, frameId: topLayerFrame ? topLayerFrame.id : null, From 0199c82e9830736748532d35ef21f6f1b73a6961 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:18:48 +0200 Subject: [PATCH 22/31] differentiate between constant/variable stroke type --- .../components/FreedrawDebugSliders.tsx | 8 +-- packages/element/src/freedraw.ts | 70 ++++++++++++++----- packages/excalidraw/components/App.tsx | 8 ++- 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/excalidraw-app/components/FreedrawDebugSliders.tsx b/excalidraw-app/components/FreedrawDebugSliders.tsx index bf8b66b111..2666a6f99a 100644 --- a/excalidraw-app/components/FreedrawDebugSliders.tsx +++ b/excalidraw-app/components/FreedrawDebugSliders.tsx @@ -3,10 +3,10 @@ import { useState, useEffect } from "react"; export const FreedrawDebugSliders = () => { const [streamline, setStreamline] = useState( - DRAWING_CONFIGS.default.streamline, + DRAWING_CONFIGS.default.variable.streamline, ); const [simplify, setSimplify] = useState( - DRAWING_CONFIGS.default.simplify, + DRAWING_CONFIGS.default.variable.simplify, ); useEffect(() => { @@ -14,7 +14,7 @@ export const FreedrawDebugSliders = () => { window.h = {} as any; } if (!window.h.debugFreedraw) { - window.h.debugFreedraw = DRAWING_CONFIGS.default; + window.h.debugFreedraw = DRAWING_CONFIGS.default.variable; } setStreamline(window.h.debugFreedraw.streamline); @@ -39,7 +39,7 @@ export const FreedrawDebugSliders = () => {
{ + return element.drawingConfigs?.fixedStrokeWidth ? "constant" : "variable"; +}; + export const DRAWING_CONFIGS: Record< PointerType | "default", - { streamline: number; simplify: number } + Record > = { default: { - streamline: 0.35, - simplify: 0.1, + constant: { + streamline: 0.35, + simplify: 0.1, + }, + variable: { + streamline: 0.35, + simplify: 0.1, + }, }, mouse: { - streamline: 0.6, - simplify: 0.1, + constant: { + streamline: 0.6, + simplify: 0.1, + }, + variable: { + streamline: 0.6, + simplify: 0.1, + }, }, pen: { - // for optimal performance, we use a lower streamline and simplify - streamline: 0.2, - simplify: 0.1, + constant: { + // for optimal performance, we use a lower streamline and simplify + streamline: 0.2, + simplify: 0.1, + }, + variable: { + // for optimal performance, we use a lower streamline and simplify + streamline: 0.2, + simplify: 0.1, + }, }, touch: { - streamline: 0.65, - simplify: 0.1, + constant: { + streamline: 0.65, + simplify: 0.1, + }, + variable: { + streamline: 0.65, + simplify: 0.1, + }, }, } as const; -export const getFreedrawConfig = (eventType: string | null | undefined) => { - return ( +export const getFreedrawConfig = ( + eventType: string | null | undefined, + strokeType: FreedrawStrokeType, +): { streamline: number; simplify: number } => { + const inputConfig = DRAWING_CONFIGS[(eventType as PointerType | null) || "default"] || - DRAWING_CONFIGS.default - ); + DRAWING_CONFIGS.default; + return inputConfig[strokeType]; }; /** @@ -105,9 +141,11 @@ export const getFreedrawStroke = (element: ExcalidrawFreeDrawElement) => { } const streamline = - element.drawingConfigs?.streamline ?? DRAWING_CONFIGS.default.streamline; + element.drawingConfigs?.streamline ?? + getFreedrawConfig("default", getElementStrokeType(element)).streamline; const simplify = - element.drawingConfigs?.simplify ?? DRAWING_CONFIGS.default.simplify; + element.drawingConfigs?.simplify ?? + getFreedrawConfig("default", getElementStrokeType(element)).simplify; const laser = new LaserPointer({ size: element.strokeWidth, diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 405eb045ee..91964e40ae 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -7476,7 +7476,10 @@ class App extends React.Component { const simulatePressure = event.pressure === 0.5 || event.pressure === 0; - const freedrawConfig = getFreedrawConfig(event.pointerType); + const freedrawConfig = getFreedrawConfig( + event.pointerType, + this.state.currentItemFixedStrokeWidth ? "constant" : "variable", + ); const element = newFreeDrawElement({ type: elementType, @@ -11159,7 +11162,8 @@ export const createTestHook = () => { window.h = window.h || ({} as Window["h"]); // Initialize debug freedraw parameters - window.h.debugFreedraw = window.h.debugFreedraw || DRAWING_CONFIGS.default; + window.h.debugFreedraw = + window.h.debugFreedraw || DRAWING_CONFIGS.default.variable; Object.defineProperties(window.h, { elements: { From 62e20aa2478cd4f9a49c641be550c0bbef808bea Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:48:59 +0200 Subject: [PATCH 23/31] improve debug --- .../components/FreedrawDebugSliders.tsx | 66 ++++++++++++++++++- packages/excalidraw/components/App.tsx | 22 +++++-- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/excalidraw-app/components/FreedrawDebugSliders.tsx b/excalidraw-app/components/FreedrawDebugSliders.tsx index 2666a6f99a..b5a665265f 100644 --- a/excalidraw-app/components/FreedrawDebugSliders.tsx +++ b/excalidraw-app/components/FreedrawDebugSliders.tsx @@ -1,6 +1,11 @@ -import { DRAWING_CONFIGS } from "@excalidraw/element"; +import { DRAWING_CONFIGS, isFreeDrawElement } from "@excalidraw/element"; import { useState, useEffect } from "react"; +import { useUIAppState } from "@excalidraw/excalidraw/context/ui-appState"; +import { useExcalidrawElements } from "@excalidraw/excalidraw/components/App"; + +import { round } from "../../packages/math/src"; + export const FreedrawDebugSliders = () => { const [streamline, setStreamline] = useState( DRAWING_CONFIGS.default.variable.streamline, @@ -14,7 +19,10 @@ export const FreedrawDebugSliders = () => { window.h = {} as any; } if (!window.h.debugFreedraw) { - window.h.debugFreedraw = DRAWING_CONFIGS.default.variable; + window.h.debugFreedraw = { + enabled: true, + ...DRAWING_CONFIGS.default.variable, + }; } setStreamline(window.h.debugFreedraw.streamline); @@ -35,6 +43,29 @@ export const FreedrawDebugSliders = () => { } }; + const [enabled, setEnabled] = useState( + window.h?.debugFreedraw?.enabled ?? true, + ); + + // counter incrasing each 50ms + const [, setCounter] = useState(0); + useEffect(() => { + const interval = setInterval(() => { + setCounter((prev) => prev + 1); + }, 50); + + return () => clearInterval(interval); + }, []); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const elements = useExcalidrawElements(); + const appState = useUIAppState(); + + const newFreedrawElement = + appState.newElement && isFreeDrawElement(appState.newElement) + ? appState.newElement + : null; + return (
{ fontFamily: "monospace", }} > + {newFreedrawElement && ( +
+ pressures:{" "} + {newFreedrawElement.simulatePressure + ? "simulated" + : JSON.stringify( + newFreedrawElement.pressures + .slice(-4) + .map((x) => round(x, 2)) + .join(" ") || [], + )}{" "} + ({round(window.__lastPressure__ || 0, 2) || "?"}) +
+ )} +
+ +