[skip ci] Refactor

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
feat/remove-ga
Mark Tolmacs 1 week ago
parent 5d76a274ba
commit 17a625787b
No known key found for this signature in database

@ -35,7 +35,7 @@ import type { ElementUpdate } from "./mutateElement";
import { mutateElement } from "./mutateElement";
import type Scene from "../scene/Scene";
import { LinearElementEditor } from "./linearElementEditor";
import { arrayToMap, invariant, tupleToCoors } from "../utils";
import { arrayToMap, tupleToCoors } from "../utils";
import { KEYS } from "../keys";
import { getBoundTextElement, handleBindTextResize } from "./textElement";
import { aabbForElement, getElementShape, pointInsideBounds } from "../shapes";
@ -66,19 +66,9 @@ import {
vectorScale,
vectorNormalize,
vectorRotate,
curve,
} from "../../math";
import { distanceToBindableElement } from "./distance";
import { intersectElementWithLine } from "./collision";
import { RoughGenerator } from "roughjs/bin/generator";
import { _generateElementShape } from "../scene/Shape";
import { COLOR_PALETTE } from "../colors";
import {
debugClear,
debugDrawCubicBezier,
debugDrawLine,
debugDrawPoint,
} from "../visualdebug";
export type SuggestedBinding =
| NonDeleted<ExcalidrawBindableElement>
@ -1036,157 +1026,6 @@ export const snapToMid = (
return p;
};
/**
* In order to precisely determine the binding point even for rough rounded linear elements,
* we need to calculate the tangent vector at the start or end of the linear element from the
* render shape itself (not the start/end points).
*
* @param linearElement The linear element to determine the endpoint tangent vector for
* @param startOrEnd Specify 'start' or 'end' to determine which endpoint tangent you need
* @returns The tangent vector
*/
const getLinearElementTangentVectorAtStartOrEnd = (
linearElement: ExcalidrawLinearElement,
startOrEnd: "start" | "end",
) => {
import.meta.env.DEV &&
invariant(
linearElement.points.length > 1,
"line must have at least 2 points to determine tangent vector",
);
if (linearElement.roundness == null || isElbowArrow(linearElement)) {
return vectorFromPoint(
linearElement.points[
startOrEnd === "start" ? 0 : linearElement.points.length - 1
],
linearElement.points[
startOrEnd === "start" ? 1 : linearElement.points.length - 2
],
);
}
// NOTE: Using _generateElementShape to not pollute the shape cache with fake
// shapes that are only used for determining the tangent vector
const shapes =
linearElement.roughness > 0
? _generateElementShape(
{
...linearElement,
roughness: 0, // We need the exact linear shape, not a rough shape
},
new RoughGenerator(),
{
isExporting: false,
canvasBackgroundColor: COLOR_PALETTE.white,
embedsValidationStatus: null,
},
)
: _generateElementShape(linearElement, new RoughGenerator(), {
isExporting: false,
canvasBackgroundColor: COLOR_PALETTE.white,
embedsValidationStatus: null,
});
import.meta.env.DEV &&
invariant(
shapes != null &&
Array.isArray(shapes) &&
shapes.length > 0 &&
shapes[0].shape === "curve" &&
shapes[0].sets[0] &&
shapes[0].sets[0].type === "path",
"shape must be an array of Drawable with at least one shape",
);
// @ts-ignore
const ops = shapes[0].sets[0].ops;
const bcurve = ops[startOrEnd === "start" ? 1 : ops.length - 1];
import.meta.env.DEV &&
invariant(bcurve.op === "bcurveTo", "selected op must be a bcurve");
debugClear();
debugDrawCubicBezier(
curve(
pointFrom<GlobalPoint>(
linearElement.x +
ops[startOrEnd === "start" ? 2 : ops.length - 2].data[4],
linearElement.y +
ops[startOrEnd === "start" ? 2 : ops.length - 2].data[5],
),
pointFrom<GlobalPoint>(
linearElement.x + bcurve.data[1],
linearElement.y + bcurve.data[2],
),
pointFrom<GlobalPoint>(
linearElement.x + bcurve.data[2],
linearElement.y + bcurve.data[3],
),
pointFrom<GlobalPoint>(
linearElement.x + bcurve.data[4],
linearElement.y + bcurve.data[5],
),
),
{ color: "red", permanent: true },
);
// debugDrawPoint(
// pointFrom<GlobalPoint>(
// linearElement.x + bcurve.data[1],
// linearElement.y + bcurve.data[2],
// ),
// { color: "red", permanent: true },
// );
// debugDrawPoint(
// pointFrom<GlobalPoint>(
// linearElement.x + bcurve.data[2],
// linearElement.y + bcurve.data[3],
// ),
// { color: "red", permanent: true },
// );
// debugDrawPoint(
// pointFrom<GlobalPoint>(
// linearElement.x + bcurve.data[4],
// linearElement.y + bcurve.data[5],
// ),
// { color: "green", permanent: true },
// );
// debugDrawLine(
// line(
// pointFrom<GlobalPoint>(
// linearElement.x + bcurve.data[2],
// linearElement.y + bcurve.data[3],
// ),
// pointFrom<GlobalPoint>(
// linearElement.x + bcurve.data[4],
// linearElement.y + bcurve.data[5],
// ),
// ),
// { color: "red", permanent: true },
// );
// debugDrawLine(
// line(
// pointFrom<GlobalPoint>(
// linearElement.x + bcurve.data[1],
// linearElement.y + bcurve.data[2],
// ),
// pointFrom<GlobalPoint>(
// linearElement.x + ops[ops.length - 2][4],
// linearElement.y + ops[ops.length - 2][5],
// ),
// ),
// { color: "green", permanent: true },
// );
return startOrEnd === "start"
? vectorFromPoint(
pointFrom<LocalPoint>(0, 0),
pointFrom<LocalPoint>(bcurve.data[2], bcurve.data[3]),
)
: vectorFromPoint(
pointFrom<LocalPoint>(bcurve.data[2], bcurve.data[3]),
pointFrom<LocalPoint>(bcurve.data[4], bcurve.data[5]),
);
};
const updateBoundPoint = (
linearElement: NonDeleted<ExcalidrawLinearElement>,
startOrEnd: "startBinding" | "endBinding",
@ -1255,10 +1094,6 @@ const updateBoundPoint = (
if (binding.gap === 0) {
newEdgePoint = focusPointAbsolute;
} else {
const tangentVector = getLinearElementTangentVectorAtStartOrEnd(
linearElement,
startOrEnd === "startBinding" ? "start" : "end",
);
const edgePointAbsolute =
LinearElementEditor.getPointAtIndexGlobalCoordinates(
linearElement,

@ -1,6 +1,6 @@
import type { Point as RoughPoint } from "roughjs/bin/geometry";
import type { Drawable, Options } from "roughjs/bin/core";
import type { RoughGenerator } from "roughjs/bin/generator";
import { RoughGenerator } from "roughjs/bin/generator";
import { getDiamondPoints, getArrowheadPoints } from "../element";
import type { ElementShapes } from "./types";
import type {
@ -11,7 +11,7 @@ import type {
Arrowhead,
} from "../element/types";
import { generateFreeDrawShape } from "../renderer/renderElement";
import { isTransparent, assertNever } from "../utils";
import { isTransparent, assertNever, invariant } from "../utils";
import { simplify } from "points-on-curve";
import { ROUGHNESS } from "../constants";
import {
@ -23,9 +23,15 @@ import {
} from "../element/typeChecks";
import { canChangeRoundness } from "./comparisons";
import type { EmbedsValidationStatus } from "../types";
import { pointFrom, pointDistance, type LocalPoint } from "../../math";
import {
pointFrom,
pointDistance,
type LocalPoint,
vectorFromPoint,
} from "../../math";
import { getCornerRadius, isPathALoop } from "../shapes";
import { headingForPointIsHorizontal } from "../element/heading";
import { COLOR_PALETTE } from "../colors";
const getDashArrayDashed = (strokeWidth: number) => [8, 8 + strokeWidth];
@ -587,3 +593,83 @@ const generateElbowArrowShape = (
return d.join(" ");
};
/**
* In order to precisely determine the binding point even for rough rounded linear elements,
* we need to calculate the tangent vector at the start or end of the linear element from the
* render shape itself (not the start/end points).
*
* @param linearElement The linear element to determine the endpoint tangent vector for
* @param startOrEnd Specify 'start' or 'end' to determine which endpoint tangent you need
* @returns The tangent vector
*/
export const getLinearElementTangentVectorAtStartOrEnd = (
linearElement: ExcalidrawLinearElement,
startOrEnd: "start" | "end",
) => {
import.meta.env.DEV &&
invariant(
linearElement.points.length > 1,
"line must have at least 2 points to determine tangent vector",
);
if (linearElement.roundness == null || isElbowArrow(linearElement)) {
return vectorFromPoint(
linearElement.points[
startOrEnd === "start" ? 0 : linearElement.points.length - 1
],
linearElement.points[
startOrEnd === "start" ? 1 : linearElement.points.length - 2
],
);
}
// NOTE: Using _generateElementShape to not pollute the shape cache with fake
// shapes that are only used for determining the tangent vector
const shapes =
linearElement.roughness > 0
? _generateElementShape(
{
...linearElement,
roughness: 0, // We need the exact linear shape, not a rough shape
},
new RoughGenerator(),
{
isExporting: false,
canvasBackgroundColor: COLOR_PALETTE.white,
embedsValidationStatus: null,
},
)
: _generateElementShape(linearElement, new RoughGenerator(), {
isExporting: false,
canvasBackgroundColor: COLOR_PALETTE.white,
embedsValidationStatus: null,
});
import.meta.env.DEV &&
invariant(
shapes != null &&
Array.isArray(shapes) &&
shapes.length > 0 &&
shapes[0].shape === "curve" &&
shapes[0].sets[0] &&
shapes[0].sets[0].type === "path",
"shape must be an array of Drawable with at least one shape",
);
// @ts-ignore
const ops = shapes[0].sets[0].ops;
const bcurve = ops[startOrEnd === "start" ? 1 : ops.length - 1];
import.meta.env.DEV &&
invariant(bcurve.op === "bcurveTo", "selected op must be a bcurve");
return startOrEnd === "start"
? vectorFromPoint(
pointFrom<LocalPoint>(0, 0),
pointFrom<LocalPoint>(bcurve.data[2], bcurve.data[3]),
)
: vectorFromPoint(
pointFrom<LocalPoint>(bcurve.data[2], bcurve.data[3]),
pointFrom<LocalPoint>(bcurve.data[4], bcurve.data[5]),
);
};

Loading…
Cancel
Save