fix: resize non solid lines/arrows/draws (#1608)
This commit is contained in:
parent
7f35b805d1
commit
6b628bb1a6
@ -1,9 +1,12 @@
|
|||||||
import { ExcalidrawElement, ExcalidrawLinearElement } from "./types";
|
import { ExcalidrawElement, ExcalidrawLinearElement } from "./types";
|
||||||
import { rotate } from "../math";
|
import { rotate } from "../math";
|
||||||
import rough from "roughjs/bin/rough";
|
import rough from "roughjs/bin/rough";
|
||||||
import { Drawable, Op, Options } from "roughjs/bin/core";
|
import { Drawable, Op } from "roughjs/bin/core";
|
||||||
import { Point } from "../types";
|
import { Point } from "../types";
|
||||||
import { getShapeForElement } from "../renderer/renderElement";
|
import {
|
||||||
|
getShapeForElement,
|
||||||
|
generateRoughOptions,
|
||||||
|
} from "../renderer/renderElement";
|
||||||
import { isLinearElement } from "./typeChecks";
|
import { isLinearElement } from "./typeChecks";
|
||||||
import { rescalePoints } from "../points";
|
import { rescalePoints } from "../points";
|
||||||
|
|
||||||
@ -323,13 +326,11 @@ export const getResizedElementAbsoluteCoords = (
|
|||||||
rescalePoints(1, nextHeight, element.points),
|
rescalePoints(1, nextHeight, element.points),
|
||||||
);
|
);
|
||||||
|
|
||||||
const options: Options = {
|
|
||||||
strokeWidth: element.strokeWidth,
|
|
||||||
roughness: element.roughness,
|
|
||||||
seed: element.seed,
|
|
||||||
};
|
|
||||||
const gen = rough.generator();
|
const gen = rough.generator();
|
||||||
const curve = gen.curve(points as [number, number][], options);
|
const curve = gen.curve(
|
||||||
|
points as [number, number][],
|
||||||
|
generateRoughOptions(element),
|
||||||
|
);
|
||||||
const ops = getCurvePathOps(curve);
|
const ops = getCurvePathOps(curve);
|
||||||
const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops);
|
const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops);
|
||||||
return [
|
return [
|
||||||
|
@ -152,6 +152,70 @@ export function invalidateShapeForElement(element: ExcalidrawElement) {
|
|||||||
shapeCache.delete(element);
|
shapeCache.delete(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateRoughOptions(element: ExcalidrawElement): Options {
|
||||||
|
const options: Options = {
|
||||||
|
seed: element.seed,
|
||||||
|
strokeLineDash:
|
||||||
|
element.strokeStyle === "dashed"
|
||||||
|
? DASHARRAY_DASHED
|
||||||
|
: element.strokeStyle === "dotted"
|
||||||
|
? DASHARRAY_DOTTED
|
||||||
|
: undefined,
|
||||||
|
// for non-solid strokes, disable multiStroke because it tends to make
|
||||||
|
// dashes/dots overlay each other
|
||||||
|
disableMultiStroke: element.strokeStyle !== "solid",
|
||||||
|
// for non-solid strokes, increase the width a bit to make it visually
|
||||||
|
// similar to solid strokes, because we're also disabling multiStroke
|
||||||
|
strokeWidth:
|
||||||
|
element.strokeStyle !== "solid"
|
||||||
|
? element.strokeWidth + 0.5
|
||||||
|
: element.strokeWidth,
|
||||||
|
// when increasing strokeWidth, we must explicitly set fillWeight and
|
||||||
|
// hachureGap because if not specified, roughjs uses strokeWidth to
|
||||||
|
// calculate them (and we don't want the fills to be modified)
|
||||||
|
fillWeight: element.strokeWidth / 2,
|
||||||
|
hachureGap: element.strokeWidth * 4,
|
||||||
|
roughness: element.roughness,
|
||||||
|
stroke: element.strokeColor,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (element.type) {
|
||||||
|
case "rectangle":
|
||||||
|
case "diamond":
|
||||||
|
case "ellipse": {
|
||||||
|
options.fillStyle = element.fillStyle;
|
||||||
|
options.fill =
|
||||||
|
element.backgroundColor === "transparent"
|
||||||
|
? undefined
|
||||||
|
: element.backgroundColor;
|
||||||
|
if (element.type === "ellipse") {
|
||||||
|
options.curveFitting = 1;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
case "line":
|
||||||
|
case "draw":
|
||||||
|
case "arrow": {
|
||||||
|
// If shape is a line and is a closed shape,
|
||||||
|
// fill the shape if a color is set.
|
||||||
|
if (element.type === "line" || element.type === "draw") {
|
||||||
|
if (isPathALoop(element.points)) {
|
||||||
|
options.fillStyle = element.fillStyle;
|
||||||
|
options.fill =
|
||||||
|
element.backgroundColor === "transparent"
|
||||||
|
? undefined
|
||||||
|
: element.backgroundColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`Unimplemented type ${element.type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function generateElement(
|
function generateElement(
|
||||||
element: NonDeletedExcalidrawElement,
|
element: NonDeletedExcalidrawElement,
|
||||||
generator: RoughGenerator,
|
generator: RoughGenerator,
|
||||||
@ -161,44 +225,15 @@ function generateElement(
|
|||||||
if (!shape) {
|
if (!shape) {
|
||||||
elementWithCanvasCache.delete(element);
|
elementWithCanvasCache.delete(element);
|
||||||
|
|
||||||
const strokeLineDash =
|
|
||||||
element.strokeStyle === "dashed"
|
|
||||||
? DASHARRAY_DASHED
|
|
||||||
: element.strokeStyle === "dotted"
|
|
||||||
? DASHARRAY_DOTTED
|
|
||||||
: undefined;
|
|
||||||
// for non-solid strokes, disable multiStroke because it tends to make
|
|
||||||
// dashes/dots overlay each other
|
|
||||||
const disableMultiStroke = element.strokeStyle !== "solid";
|
|
||||||
// for non-solid strokes, increase the width a bit to make it visually
|
|
||||||
// similar to solid strokes, because we're also disabling multiStroke
|
|
||||||
const strokeWidth =
|
|
||||||
element.strokeStyle !== "solid"
|
|
||||||
? element.strokeWidth + 0.5
|
|
||||||
: element.strokeWidth;
|
|
||||||
// when increasing strokeWidth, we must explicitly set fillWeight and
|
|
||||||
// hachureGap because if not specified, roughjs uses strokeWidth to
|
|
||||||
// calculate them (and we don't want the fills to be modified)
|
|
||||||
const fillWeight = element.strokeWidth / 2;
|
|
||||||
const hachureGap = element.strokeWidth * 4;
|
|
||||||
|
|
||||||
switch (element.type) {
|
switch (element.type) {
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
shape = generator.rectangle(0, 0, element.width, element.height, {
|
shape = generator.rectangle(
|
||||||
strokeWidth,
|
0,
|
||||||
fillWeight,
|
0,
|
||||||
hachureGap,
|
element.width,
|
||||||
strokeLineDash,
|
element.height,
|
||||||
disableMultiStroke,
|
generateRoughOptions(element),
|
||||||
stroke: element.strokeColor,
|
);
|
||||||
fill:
|
|
||||||
element.backgroundColor === "transparent"
|
|
||||||
? undefined
|
|
||||||
: element.backgroundColor,
|
|
||||||
fillStyle: element.fillStyle,
|
|
||||||
roughness: element.roughness,
|
|
||||||
seed: element.seed,
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "diamond": {
|
case "diamond": {
|
||||||
@ -219,21 +254,7 @@ function generateElement(
|
|||||||
[bottomX, bottomY],
|
[bottomX, bottomY],
|
||||||
[leftX, leftY],
|
[leftX, leftY],
|
||||||
],
|
],
|
||||||
{
|
generateRoughOptions(element),
|
||||||
strokeWidth,
|
|
||||||
fillWeight,
|
|
||||||
hachureGap,
|
|
||||||
strokeLineDash,
|
|
||||||
disableMultiStroke,
|
|
||||||
stroke: element.strokeColor,
|
|
||||||
fill:
|
|
||||||
element.backgroundColor === "transparent"
|
|
||||||
? undefined
|
|
||||||
: element.backgroundColor,
|
|
||||||
fillStyle: element.fillStyle,
|
|
||||||
roughness: element.roughness,
|
|
||||||
seed: element.seed,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -243,54 +264,18 @@ function generateElement(
|
|||||||
element.height / 2,
|
element.height / 2,
|
||||||
element.width,
|
element.width,
|
||||||
element.height,
|
element.height,
|
||||||
{
|
generateRoughOptions(element),
|
||||||
strokeWidth,
|
|
||||||
fillWeight,
|
|
||||||
hachureGap,
|
|
||||||
strokeLineDash,
|
|
||||||
disableMultiStroke,
|
|
||||||
stroke: element.strokeColor,
|
|
||||||
fill:
|
|
||||||
element.backgroundColor === "transparent"
|
|
||||||
? undefined
|
|
||||||
: element.backgroundColor,
|
|
||||||
fillStyle: element.fillStyle,
|
|
||||||
roughness: element.roughness,
|
|
||||||
seed: element.seed,
|
|
||||||
curveFitting: 1,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "line":
|
case "line":
|
||||||
case "draw":
|
case "draw":
|
||||||
case "arrow": {
|
case "arrow": {
|
||||||
const options: Options = {
|
const options = generateRoughOptions(element);
|
||||||
strokeWidth,
|
|
||||||
fillWeight,
|
|
||||||
hachureGap,
|
|
||||||
strokeLineDash,
|
|
||||||
disableMultiStroke,
|
|
||||||
stroke: element.strokeColor,
|
|
||||||
seed: element.seed,
|
|
||||||
roughness: element.roughness,
|
|
||||||
};
|
|
||||||
|
|
||||||
// points array can be empty in the beginning, so it is important to add
|
// points array can be empty in the beginning, so it is important to add
|
||||||
// initial position to it
|
// initial position to it
|
||||||
const points = element.points.length ? element.points : [[0, 0]];
|
const points = element.points.length ? element.points : [[0, 0]];
|
||||||
|
|
||||||
// If shape is a line and is a closed shape,
|
|
||||||
// fill the shape if a color is set.
|
|
||||||
if (element.type === "line" || element.type === "draw") {
|
|
||||||
if (isPathALoop(element.points)) {
|
|
||||||
options.fillStyle = element.fillStyle;
|
|
||||||
options.fill =
|
|
||||||
element.backgroundColor === "transparent"
|
|
||||||
? undefined
|
|
||||||
: element.backgroundColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// curve is always the first element
|
// curve is always the first element
|
||||||
// this simplifies finding the curve for an element
|
// this simplifies finding the curve for an element
|
||||||
shape = [generator.curve(points as [number, number][], options)];
|
shape = [generator.curve(points as [number, number][], options)];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user