feat: better default radius sizes for rectangles (#5553)

Co-authored-by: Ryan <diweihao@bytedance.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Ryan Di
2022-12-08 23:48:49 +08:00
committed by GitHub
parent 65d84a5d5a
commit 5854ac3eed
39 changed files with 1861 additions and 818 deletions

View File

@ -1,3 +1,4 @@
import { ROUNDNESS } from "../constants";
import { getElementAbsoluteCoords, getElementBounds } from "./bounds";
import { ExcalidrawElement, ExcalidrawLinearElement } from "./types";
@ -22,6 +23,7 @@ const _ce = ({
backgroundColor: "#000",
fillStyle: "solid",
strokeWidth: 1,
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
roughness: 0,
opacity: 1,
x,

View File

@ -378,7 +378,7 @@ const generateLinearElementShape = (
const options = generateRoughOptions(element);
const method = (() => {
if (element.strokeSharpness !== "sharp") {
if (element.roundness) {
return "curve";
}
if (options.fill) {
@ -561,16 +561,12 @@ export const getResizedElementAbsoluteCoords = (
} else {
// Line
const gen = rough.generator();
const curve =
element.strokeSharpness === "sharp"
? gen.linearPath(
points as [number, number][],
generateRoughOptions(element),
)
: gen.curve(
points as [number, number][],
generateRoughOptions(element),
);
const curve = !element.roundness
? gen.linearPath(
points as [number, number][],
generateRoughOptions(element),
)
: gen.curve(points as [number, number][], generateRoughOptions(element));
const ops = getCurvePathOps(curve);
bounds = getMinMaxXYFromCurvePathOps(ops);
@ -588,12 +584,11 @@ export const getResizedElementAbsoluteCoords = (
export const getElementPointsCoords = (
element: ExcalidrawLinearElement,
points: readonly (readonly [number, number])[],
sharpness: ExcalidrawElement["strokeSharpness"],
): [number, number, number, number] => {
// This might be computationally heavey
const gen = rough.generator();
const curve =
sharpness === "sharp"
element.roundness == null
? gen.linearPath(
points as [number, number][],
generateRoughOptions(element),

View File

@ -25,6 +25,7 @@ import {
ExcalidrawFreeDrawElement,
ExcalidrawImageElement,
ExcalidrawLinearElement,
StrokeRoundness,
} from "./types";
import { getElementAbsoluteCoords, getCurvePathOps, Bounds } from "./bounds";
@ -419,7 +420,12 @@ const hitTestLinear = (args: HitTestArgs): boolean => {
if (args.check === isInsideCheck) {
const hit = shape.some((subshape) =>
hitTestCurveInside(subshape, relX, relY, element.strokeSharpness),
hitTestCurveInside(
subshape,
relX,
relY,
element.roundness ? "round" : "sharp",
),
);
if (hit) {
return true;
@ -851,7 +857,7 @@ const hitTestCurveInside = (
drawable: Drawable,
x: number,
y: number,
sharpness: ExcalidrawElement["strokeSharpness"],
roundness: StrokeRoundness,
) => {
const ops = getCurvePathOps(drawable);
const points: Mutable<Point>[] = [];
@ -875,7 +881,7 @@ const hitTestCurveInside = (
}
}
if (points.length >= 4) {
if (sharpness === "sharp") {
if (roundness === "sharp") {
return isPointInPolygon(points, x, y);
}
const polygonPoints = pointsOnBezierCurves(points, 10, 5);

View File

@ -527,7 +527,7 @@ export class LinearElementEditor {
endPoint[0],
endPoint[1],
);
if (element.points.length > 2 && element.strokeSharpness === "round") {
if (element.points.length > 2 && element.roundness) {
distance = getBezierCurveLength(element, endPoint);
}
@ -541,7 +541,7 @@ export class LinearElementEditor {
endPointIndex: number,
) {
let segmentMidPoint = centerPoint(startPoint, endPoint);
if (element.points.length > 2 && element.strokeSharpness === "round") {
if (element.points.length > 2 && element.roundness) {
const controlPoints = getControlPointsForBezierCurve(
element,
element.points[endPointIndex],
@ -1221,16 +1221,8 @@ export class LinearElementEditor {
offsetY: number,
otherUpdates?: { startBinding?: PointBinding; endBinding?: PointBinding },
) {
const nextCoords = getElementPointsCoords(
element,
nextPoints,
element.strokeSharpness || "round",
);
const prevCoords = getElementPointsCoords(
element,
element.points,
element.strokeSharpness || "round",
);
const nextCoords = getElementPointsCoords(element, nextPoints);
const prevCoords = getElementPointsCoords(element, element.points);
const nextCenterX = (nextCoords[0] + nextCoords[2]) / 2;
const nextCenterY = (nextCoords[1] + nextCoords[3]) / 2;
const prevCenterX = (prevCoords[0] + prevCoords[2]) / 2;

View File

@ -1,7 +1,7 @@
import { duplicateElement } from "./newElement";
import { mutateElement } from "./mutateElement";
import { API } from "../tests/helpers/api";
import { FONT_FAMILY } from "../constants";
import { FONT_FAMILY, ROUNDNESS } from "../constants";
import { isPrimitive } from "../utils";
const assertCloneObjects = (source: any, clone: any) => {
@ -25,7 +25,7 @@ it("clones arrow element", () => {
fillStyle: "hachure",
strokeWidth: 1,
strokeStyle: "solid",
strokeSharpness: "round",
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
roughness: 1,
opacity: 100,
});
@ -71,7 +71,7 @@ it("clones text element", () => {
fillStyle: "hachure",
strokeWidth: 1,
strokeStyle: "solid",
strokeSharpness: "round",
roundness: null,
roughness: 1,
opacity: 100,
text: "hello",

View File

@ -62,14 +62,15 @@ const _newElementBase = <T extends ExcalidrawElement>(
height = 0,
angle = 0,
groupIds = [],
strokeSharpness,
roundness = null,
boundElements = null,
link = null,
locked,
...rest
}: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">,
) => {
const element = {
// assign type to guard against excess properties
const element: Merge<ExcalidrawGenericElement, { type: T["type"] }> = {
id: rest.id || randomId(),
type,
x,
@ -85,7 +86,7 @@ const _newElementBase = <T extends ExcalidrawElement>(
roughness,
opacity,
groupIds,
strokeSharpness,
roundness,
seed: rest.seed ?? randomInteger(),
version: rest.version || 1,
versionNonce: rest.versionNonce ?? 0,

View File

@ -152,3 +152,5 @@ export const isBoundToContainer = (
isTextElement(element)
);
};
export const isUsingAdaptiveRadius = (type: string) => type === "rectangle";

View File

@ -1,5 +1,11 @@
import { Point } from "../types";
import { FONT_FAMILY, TEXT_ALIGN, THEME, VERTICAL_ALIGN } from "../constants";
import {
FONT_FAMILY,
ROUNDNESS,
TEXT_ALIGN,
THEME,
VERTICAL_ALIGN,
} from "../constants";
export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid";
@ -9,7 +15,8 @@ export type Theme = typeof THEME[keyof typeof THEME];
export type FontString = string & { _brand: "fontString" };
export type GroupId = string;
export type PointerType = "mouse" | "pen" | "touch";
export type StrokeSharpness = "round" | "sharp";
export type StrokeRoundness = "round" | "sharp";
export type RoundnessType = ValueOf<typeof ROUNDNESS>;
export type StrokeStyle = "solid" | "dashed" | "dotted";
export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN];
@ -25,7 +32,7 @@ type _ExcalidrawElementBase = Readonly<{
fillStyle: FillStyle;
strokeWidth: number;
strokeStyle: StrokeStyle;
strokeSharpness: StrokeSharpness;
roundness: null | { type: RoundnessType; value?: number };
roughness: number;
opacity: number;
width: number;