mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-11-01 03:14:29 +01:00
chore: Additional master merge
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
@@ -1,12 +1,29 @@
|
|||||||
import { LaserPointer, type Point } from "@excalidraw/laser-pointer";
|
import { LaserPointer, type Point } from "@excalidraw/laser-pointer";
|
||||||
|
|
||||||
import { clamp, round, type LocalPoint } from "@excalidraw/math";
|
import {
|
||||||
|
clamp,
|
||||||
|
lineSegment,
|
||||||
|
pointFrom,
|
||||||
|
pointRotateRads,
|
||||||
|
round,
|
||||||
|
type LocalPoint,
|
||||||
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import getStroke from "perfect-freehand";
|
import getStroke from "perfect-freehand";
|
||||||
|
|
||||||
|
import { invariant } from "@excalidraw/common";
|
||||||
|
|
||||||
|
import type { GlobalPoint, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
|
import { getElementBounds } from "./bounds";
|
||||||
|
|
||||||
import type { StrokeOptions } from "perfect-freehand";
|
import type { StrokeOptions } from "perfect-freehand";
|
||||||
|
|
||||||
import type { ExcalidrawFreeDrawElement, PointerType } from "./types";
|
import type {
|
||||||
|
ElementsMap,
|
||||||
|
ExcalidrawFreeDrawElement,
|
||||||
|
PointerType,
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
export const STROKE_OPTIONS: Record<
|
export const STROKE_OPTIONS: Record<
|
||||||
PointerType | "default",
|
PointerType | "default",
|
||||||
@@ -276,3 +293,81 @@ const _legacy_getSvgPathFromStroke = (points: number[][]): string => {
|
|||||||
.join(" ")
|
.join(" ")
|
||||||
.replace(TO_FIXED_PRECISION, "$1");
|
.replace(TO_FIXED_PRECISION, "$1");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getFreedrawOutlineAsSegments(
|
||||||
|
element: ExcalidrawFreeDrawElement,
|
||||||
|
points: [number, number][],
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
) {
|
||||||
|
const bounds = getElementBounds(
|
||||||
|
{
|
||||||
|
...element,
|
||||||
|
angle: 0 as Radians,
|
||||||
|
},
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
const center = pointFrom<GlobalPoint>(
|
||||||
|
(bounds[0] + bounds[2]) / 2,
|
||||||
|
(bounds[1] + bounds[3]) / 2,
|
||||||
|
);
|
||||||
|
|
||||||
|
invariant(points.length >= 2, "Freepath outline must have at least 2 points");
|
||||||
|
|
||||||
|
return points.slice(2).reduce(
|
||||||
|
(acc, curr) => {
|
||||||
|
acc.push(
|
||||||
|
lineSegment<GlobalPoint>(
|
||||||
|
acc[acc.length - 1][1],
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(curr[0] + element.x, curr[1] + element.y),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
[
|
||||||
|
lineSegment<GlobalPoint>(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
points[0][0] + element.x,
|
||||||
|
points[0][1] + element.y,
|
||||||
|
),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
points[1][0] + element.x,
|
||||||
|
points[1][1] + element.y,
|
||||||
|
),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFreedrawOutlinePoints(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]];
|
||||||
|
|
||||||
|
// Consider changing the options for simulated pressure vs real pressure
|
||||||
|
const options: StrokeOptions = {
|
||||||
|
simulatePressure: element.simulatePressure,
|
||||||
|
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
|
||||||
|
last: !!element.lastCommittedPoint, // LastCommittedPoint is added on pointerup
|
||||||
|
};
|
||||||
|
|
||||||
|
return getStroke(inputPoints as number[][], options) as [number, number][];
|
||||||
|
}
|
||||||
|
|||||||
@@ -9050,13 +9050,13 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 50,
|
"height": 50,
|
||||||
"id": "id0",
|
"id": "id0",
|
||||||
@@ -9157,13 +9157,13 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 50,
|
"height": 50,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
@@ -12234,13 +12234,13 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 10,
|
||||||
"id": "id5",
|
"id": "id5",
|
||||||
@@ -12289,13 +12289,13 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 10,
|
||||||
"id": "id9",
|
"id": "id9",
|
||||||
@@ -12434,13 +12434,13 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 10,
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
|
|||||||
@@ -7029,13 +7029,13 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 10,
|
||||||
"index": "a7",
|
"index": "a7",
|
||||||
@@ -9352,13 +9352,13 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
@@ -10387,13 +10387,13 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": null,
|
"boundElements": null,
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.35000",
|
"streamline": "0.35000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 30,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
|
|||||||
@@ -168,13 +168,13 @@ exports[`restoreElements > should restore freedraw element correctly 1`] = `
|
|||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"boundElements": [],
|
"boundElements": [],
|
||||||
"customData": undefined,
|
"customData": undefined,
|
||||||
"drawingConfigs": {
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"freedrawOptions": {
|
||||||
"fixedStrokeWidth": true,
|
"fixedStrokeWidth": true,
|
||||||
"simplify": "0.10000",
|
"simplify": "0.10000",
|
||||||
"streamline": "0.25000",
|
"streamline": "0.25000",
|
||||||
},
|
},
|
||||||
"fillStyle": "solid",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"id": "id-freedraw01",
|
"id": "id-freedraw01",
|
||||||
|
|||||||
Reference in New Issue
Block a user