put streamline & simplify into ele obj too

This commit is contained in:
Ryan Di 2025-06-13 18:12:56 +10:00
parent c08840358b
commit 37b75263f8
8 changed files with 57 additions and 36 deletions

View File

@ -1,15 +1,20 @@
import { DRAWING_CONFIGS } from "@excalidraw/element";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
export const FreedrawDebugSliders = () => { export const FreedrawDebugSliders = () => {
const [streamline, setStreamline] = useState(0.62); const [streamline, setStreamline] = useState<number>(
const [simplify, setSimplify] = useState(0.3); DRAWING_CONFIGS.default.streamline,
);
const [simplify, setSimplify] = useState<number>(
DRAWING_CONFIGS.default.simplify,
);
useEffect(() => { useEffect(() => {
if (!window.h) { if (!window.h) {
window.h = {} as any; window.h = {} as any;
} }
if (!window.h.debugFreedraw) { if (!window.h.debugFreedraw) {
window.h.debugFreedraw = { streamline: 0.62, simplify: 0.3 }; window.h.debugFreedraw = DRAWING_CONFIGS.default;
} }
setStreamline(window.h.debugFreedraw.streamline); setStreamline(window.h.debugFreedraw.streamline);

View File

@ -513,12 +513,12 @@ export const _generateElementShape = (
if (isPathALoop(element.points)) { if (isPathALoop(element.points)) {
const points = const points =
element.pressureSensitivity === null element.drawingConfigs === null
? simplify(element.points as LocalPoint[], 0.75) ? simplify(element.points as LocalPoint[], 0.75)
: simplify(element.points as LocalPoint[], 1.5); : simplify(element.points as LocalPoint[], 1.5);
shape = shape =
element.pressureSensitivity === null element.drawingConfigs === null
? generator.curve(points, { ? generator.curve(points, {
...generateRoughOptions(element), ...generateRoughOptions(element),
stroke: "none", stroke: "none",

View File

@ -8,6 +8,13 @@ import type { StrokeOptions } from "perfect-freehand";
import type { ExcalidrawFreeDrawElement } from "./types"; 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. * Calculates simulated pressure based on velocity between consecutive points.
* Fast movement (large distances) -> lower pressure * Fast movement (large distances) -> lower pressure
@ -16,7 +23,7 @@ import type { ExcalidrawFreeDrawElement } from "./types";
const calculateVelocityBasedPressure = ( const calculateVelocityBasedPressure = (
points: readonly LocalPoint[], points: readonly LocalPoint[],
index: number, index: number,
pressureSensitivity: number | null, pressureSensitivity: number | undefined,
maxDistance = 8, // Maximum expected distance for normalization maxDistance = 8, // Maximum expected distance for normalization
): number => { ): number => {
// Handle pressure sensitivity // Handle pressure sensitivity
@ -64,11 +71,11 @@ export const getFreedrawStroke = (
calculateVelocityBasedPressure( calculateVelocityBasedPressure(
element.points, element.points,
i, i,
element.pressureSensitivity, element.drawingConfigs?.pressureSensitivity,
), ),
]); ]);
} else { } else {
const sensitivity = element.pressureSensitivity ?? 1; const sensitivity = element.drawingConfigs?.pressureSensitivity ?? 1;
points = element.points.map(([x, y]: LocalPoint, i) => { points = element.points.map(([x, y]: LocalPoint, i) => {
if (sensitivity === 0) { if (sensitivity === 0) {
return [x, y, 0.5]; return [x, y, 0.5];
@ -84,28 +91,20 @@ export const getFreedrawStroke = (
} }
const streamline = const streamline =
(typeof window !== "undefined" && element.drawingConfigs?.streamline ?? DRAWING_CONFIGS.default.streamline;
window.h &&
window.h.debugFreedraw?.streamline) ??
debugParams?.streamline ??
0.62;
const simplify = const simplify =
(typeof window !== "undefined" && element.drawingConfigs?.simplify ?? DRAWING_CONFIGS.default.simplify;
window.h &&
window.h.debugFreedraw?.simplify) ??
debugParams?.simplify ??
0.3;
const laser = new LaserPointer({ const laser = new LaserPointer({
size: element.strokeWidth, size: element.strokeWidth,
streamline: streamline === false ? 0.62 : streamline, streamline,
simplify: simplify === false ? 0.3 : simplify, simplify,
sizeMapping: ({ pressure: t }) => { sizeMapping: ({ pressure: t }) => {
if (element.simulatePressure) { if (element.simulatePressure) {
return t + 0.2; return t + 0.2;
} }
if (element.pressureSensitivity === 0) { if (element.drawingConfigs?.pressureSensitivity === 0) {
return 1; return 1;
} }
@ -133,7 +132,7 @@ export const getFreeDrawSvgPath = (
debugParams?: { streamline?: number; simplify?: number }, debugParams?: { streamline?: number; simplify?: number },
): string => { ): string => {
// legacy, for backwards compatibility // legacy, for backwards compatibility
if (element.pressureSensitivity === null) { if (element.drawingConfigs === null) {
return _legacy_getFreeDrawSvgPath(element); return _legacy_getFreeDrawSvgPath(element);
} }
@ -188,7 +187,7 @@ function _legacy_getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) {
? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) ? element.points.map(([x, y], i) => [x, y, element.pressures[i]])
: [[0, 0, 0.5]]; : [[0, 0, 0.5]];
const sensitivity = element.pressureSensitivity; const sensitivity = element.drawingConfigs?.pressureSensitivity;
// Consider changing the options for simulated pressure vs real pressure // Consider changing the options for simulated pressure vs real pressure
const options: StrokeOptions = { const options: StrokeOptions = {
@ -196,7 +195,7 @@ function _legacy_getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) {
// if sensitivity is not set, times 4.25 for backwards compatibility // if sensitivity is not set, times 4.25 for backwards compatibility
size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25), size: element.strokeWidth * (sensitivity !== null ? 1 : 4.25),
// if sensitivity is not set, set thinning to 0.6 for backwards compatibility // 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, smoothing: 0.5,
streamline: 0.5, streamline: 0.5,
easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine

View File

@ -445,7 +445,7 @@ export const newFreeDrawElement = (
points?: ExcalidrawFreeDrawElement["points"]; points?: ExcalidrawFreeDrawElement["points"];
simulatePressure: boolean; simulatePressure: boolean;
pressures?: ExcalidrawFreeDrawElement["pressures"]; pressures?: ExcalidrawFreeDrawElement["pressures"];
pressureSensitivity?: ExcalidrawFreeDrawElement["pressureSensitivity"]; drawingConfigs?: ExcalidrawFreeDrawElement["drawingConfigs"];
} & ElementConstructorOpts, } & ElementConstructorOpts,
): NonDeleted<ExcalidrawFreeDrawElement> => { ): NonDeleted<ExcalidrawFreeDrawElement> => {
return { return {
@ -454,7 +454,11 @@ export const newFreeDrawElement = (
pressures: opts.pressures || [], pressures: opts.pressures || [],
simulatePressure: opts.simulatePressure, simulatePressure: opts.simulatePressure,
lastCommittedPoint: null, lastCommittedPoint: null,
pressureSensitivity: opts.pressureSensitivity ?? 1, drawingConfigs: opts.drawingConfigs || {
pressureSensitivity: 1,
streamline: 0.25,
simplify: 0.1,
},
}; };
}; };

View File

@ -377,9 +377,13 @@ export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase &
type: "freedraw"; type: "freedraw";
points: readonly LocalPoint[]; points: readonly LocalPoint[];
pressures: readonly number[]; pressures: readonly number[];
pressureSensitivity: number | null;
simulatePressure: boolean; simulatePressure: boolean;
lastCommittedPoint: LocalPoint | null; lastCommittedPoint: LocalPoint | null;
drawingConfigs: {
streamline?: number;
simplify?: number;
pressureSensitivity?: number;
} | null;
}>; }>;
export type FileId = string & { _brand: "FileId" }; export type FileId = string & { _brand: "FileId" };

View File

@ -693,12 +693,12 @@ export const actionChangePressureSensitivity = register({
const commonPressureSensitivity = selectedElements const commonPressureSensitivity = selectedElements
.filter(isFreeDrawElement) .filter(isFreeDrawElement)
.reduce((acc, element) => { .reduce((acc, element) => {
const sensitivity = element.pressureSensitivity ?? 1; const sensitivity = element.drawingConfigs?.pressureSensitivity ?? 1;
if (acc !== null && acc !== sensitivity) { if (acc !== null && acc !== sensitivity) {
return null; // No common value return null; // No common value
} }
return sensitivity; return sensitivity;
}, firstElement?.pressureSensitivity ?? null); }, firstElement?.drawingConfigs?.pressureSensitivity ?? null);
const currentValue = const currentValue =
commonPressureSensitivity ?? appState.currentItemPressureSensitivity; commonPressureSensitivity ?? appState.currentItemPressureSensitivity;

View File

@ -104,7 +104,11 @@ import {
Emitter, Emitter,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { getCommonBounds, getElementAbsoluteCoords } from "@excalidraw/element"; import {
DRAWING_CONFIGS,
getCommonBounds,
getElementAbsoluteCoords,
} from "@excalidraw/element";
import { import {
bindOrUnbindLinearElements, bindOrUnbindLinearElements,
@ -7588,7 +7592,14 @@ class App extends React.Component<AppProps, AppState> {
opacity: this.state.currentItemOpacity, opacity: this.state.currentItemOpacity,
roundness: null, roundness: null,
simulatePressure, 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, locked: false,
frameId: topLayerFrame ? topLayerFrame.id : null, frameId: topLayerFrame ? topLayerFrame.id : null,
points: [pointFrom<LocalPoint>(0, 0)], points: [pointFrom<LocalPoint>(0, 0)],
@ -11384,10 +11395,7 @@ export const createTestHook = () => {
window.h = window.h || ({} as Window["h"]); window.h = window.h || ({} as Window["h"]);
// Initialize debug freedraw parameters // Initialize debug freedraw parameters
window.h.debugFreedraw = window.h.debugFreedraw || { window.h.debugFreedraw = window.h.debugFreedraw || DRAWING_CONFIGS.default;
streamline: 0.62,
simplify: 0.3,
};
Object.defineProperties(window.h, { Object.defineProperties(window.h, {
elements: { elements: {

View File

@ -302,7 +302,8 @@ const restoreElement = (
lastCommittedPoint: null, lastCommittedPoint: null,
simulatePressure: element.simulatePressure, simulatePressure: element.simulatePressure,
pressures: element.pressures, pressures: element.pressures,
pressureSensitivity: element.pressureSensitivity ?? null, // legacy, for backwards compatibility
drawingConfigs: element.drawingConfigs ?? null,
}); });
} }
case "image": case "image":