Compare commits
16 Commits
master
...
multi-curv
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c552ff4554 | ||
![]() |
26f9b54199 | ||
![]() |
7f5b7bab69 | ||
![]() |
bf7c91536f | ||
![]() |
4372e992e0 | ||
![]() |
1e4bfceb13 | ||
![]() |
539071fcfe | ||
![]() |
3700cf2d10 | ||
![]() |
89218ba596 | ||
![]() |
bc5436592e | ||
![]() |
750055ddfa | ||
![]() |
93e4cb8d25 | ||
![]() |
a2dd3c6ea2 | ||
![]() |
0360e64219 | ||
![]() |
c2867c9a93 | ||
![]() |
14bca119f7 |
@ -53,7 +53,7 @@
|
|||||||
"pwacompat": "2.0.17",
|
"pwacompat": "2.0.17",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"roughjs": "4.6.4",
|
"roughjs": "4.6.5",
|
||||||
"sass": "1.51.0",
|
"sass": "1.51.0",
|
||||||
"socket.io-client": "2.3.1",
|
"socket.io-client": "2.3.1",
|
||||||
"tunnel-rat": "0.1.2"
|
"tunnel-rat": "0.1.2"
|
||||||
|
@ -3750,9 +3750,32 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords(
|
||||||
|
event,
|
||||||
|
this.state,
|
||||||
|
);
|
||||||
|
|
||||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||||
|
|
||||||
if (selectedElements.length === 1 && isLinearElement(selectedElements[0])) {
|
if (selectedElements.length === 1 && isLinearElement(selectedElements[0])) {
|
||||||
|
if (!event[KEYS.CTRL_OR_CMD]) {
|
||||||
|
// If double clicked without any ctrl/cmd modifier on top of a point,
|
||||||
|
// toggle split mode for that point. Else, treat as regular double click.
|
||||||
|
const pointUnderCursorIndex =
|
||||||
|
LinearElementEditor.getPointIndexUnderCursor(
|
||||||
|
selectedElements[0],
|
||||||
|
this.state.zoom,
|
||||||
|
sceneX,
|
||||||
|
sceneY,
|
||||||
|
);
|
||||||
|
if (pointUnderCursorIndex >= 0) {
|
||||||
|
LinearElementEditor.toggleSegmentSplitAtIndex(
|
||||||
|
selectedElements[0],
|
||||||
|
pointUnderCursorIndex,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
event[KEYS.CTRL_OR_CMD] &&
|
event[KEYS.CTRL_OR_CMD] &&
|
||||||
(!this.state.editingLinearElement ||
|
(!this.state.editingLinearElement ||
|
||||||
@ -3776,11 +3799,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
resetCursor(this.interactiveCanvas);
|
resetCursor(this.interactiveCanvas);
|
||||||
|
|
||||||
let { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords(
|
|
||||||
event,
|
|
||||||
this.state,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedGroupIds = getSelectedGroupIds(this.state);
|
const selectedGroupIds = getSelectedGroupIds(this.state);
|
||||||
|
|
||||||
if (selectedGroupIds.length > 0) {
|
if (selectedGroupIds.length > 0) {
|
||||||
|
@ -285,6 +285,9 @@ const restoreElement = (
|
|||||||
points,
|
points,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
segmentSplitIndices: element.segmentSplitIndices
|
||||||
|
? [...element.segmentSplitIndices]
|
||||||
|
: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,7 +741,7 @@ export const getElementPointsCoords = (
|
|||||||
element: ExcalidrawLinearElement,
|
element: ExcalidrawLinearElement,
|
||||||
points: readonly (readonly [number, number])[],
|
points: readonly (readonly [number, number])[],
|
||||||
): [number, number, number, number] => {
|
): [number, number, number, number] => {
|
||||||
// This might be computationally heavey
|
// This might be computationally heavy
|
||||||
const gen = rough.generator();
|
const gen = rough.generator();
|
||||||
const curve =
|
const curve =
|
||||||
element.roundness == null
|
element.roundness == null
|
||||||
|
@ -547,7 +547,10 @@ export class LinearElementEditor {
|
|||||||
endPointIndex: number,
|
endPointIndex: number,
|
||||||
) {
|
) {
|
||||||
let segmentMidPoint = centerPoint(startPoint, endPoint);
|
let segmentMidPoint = centerPoint(startPoint, endPoint);
|
||||||
if (element.points.length > 2 && element.roundness) {
|
const splits = element.segmentSplitIndices || [];
|
||||||
|
const treatAsCurve =
|
||||||
|
splits.includes(endPointIndex) || splits.includes(endPointIndex - 1);
|
||||||
|
if (element.points.length > 2 && (element.roundness || treatAsCurve)) {
|
||||||
const controlPoints = getControlPointsForBezierCurve(
|
const controlPoints = getControlPointsForBezierCurve(
|
||||||
element,
|
element,
|
||||||
element.points[endPointIndex],
|
element.points[endPointIndex],
|
||||||
@ -1042,13 +1045,15 @@ export class LinearElementEditor {
|
|||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
let offsetY = 0;
|
let offsetY = 0;
|
||||||
|
|
||||||
const isDeletingOriginPoint = pointIndices.includes(0);
|
const indexSet = new Set(pointIndices);
|
||||||
|
|
||||||
|
const isDeletingOriginPoint = indexSet.has(0);
|
||||||
|
|
||||||
// if deleting first point, make the next to be [0,0] and recalculate
|
// if deleting first point, make the next to be [0,0] and recalculate
|
||||||
// positions of the rest with respect to it
|
// positions of the rest with respect to it
|
||||||
if (isDeletingOriginPoint) {
|
if (isDeletingOriginPoint) {
|
||||||
const firstNonDeletedPoint = element.points.find((point, idx) => {
|
const firstNonDeletedPoint = element.points.find((point, idx) => {
|
||||||
return !pointIndices.includes(idx);
|
return !indexSet.has(idx);
|
||||||
});
|
});
|
||||||
if (firstNonDeletedPoint) {
|
if (firstNonDeletedPoint) {
|
||||||
offsetX = firstNonDeletedPoint[0];
|
offsetX = firstNonDeletedPoint[0];
|
||||||
@ -1057,7 +1062,7 @@ export class LinearElementEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nextPoints = element.points.reduce((acc: Point[], point, idx) => {
|
const nextPoints = element.points.reduce((acc: Point[], point, idx) => {
|
||||||
if (!pointIndices.includes(idx)) {
|
if (!indexSet.has(idx)) {
|
||||||
acc.push(
|
acc.push(
|
||||||
!acc.length ? [0, 0] : [point[0] - offsetX, point[1] - offsetY],
|
!acc.length ? [0, 0] : [point[0] - offsetX, point[1] - offsetY],
|
||||||
);
|
);
|
||||||
@ -1065,7 +1070,22 @@ export class LinearElementEditor {
|
|||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY);
|
const splits: number[] = [];
|
||||||
|
(element.segmentSplitIndices || []).forEach((index) => {
|
||||||
|
if (!indexSet.has(index)) {
|
||||||
|
let shift = 0;
|
||||||
|
for (const pointIndex of pointIndices) {
|
||||||
|
if (index > pointIndex) {
|
||||||
|
shift++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
splits.push(index - shift);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY, {
|
||||||
|
segmentSplitIndices: splits.sort((a, b) => a - b),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static addPoints(
|
static addPoints(
|
||||||
@ -1204,9 +1224,13 @@ export class LinearElementEditor {
|
|||||||
midpoint,
|
midpoint,
|
||||||
...element.points.slice(segmentMidpoint.index!),
|
...element.points.slice(segmentMidpoint.index!),
|
||||||
];
|
];
|
||||||
|
const splits = (element.segmentSplitIndices || []).map((index) =>
|
||||||
|
index >= segmentMidpoint.index! ? index + 1 : index,
|
||||||
|
);
|
||||||
|
|
||||||
mutateElement(element, {
|
mutateElement(element, {
|
||||||
points,
|
points,
|
||||||
|
segmentSplitIndices: splits.sort((a, b) => a - b),
|
||||||
});
|
});
|
||||||
|
|
||||||
ret.pointerDownState = {
|
ret.pointerDownState = {
|
||||||
@ -1226,7 +1250,11 @@ export class LinearElementEditor {
|
|||||||
nextPoints: readonly Point[],
|
nextPoints: readonly Point[],
|
||||||
offsetX: number,
|
offsetX: number,
|
||||||
offsetY: number,
|
offsetY: number,
|
||||||
otherUpdates?: { startBinding?: PointBinding; endBinding?: PointBinding },
|
otherUpdates?: {
|
||||||
|
startBinding?: PointBinding;
|
||||||
|
endBinding?: PointBinding;
|
||||||
|
segmentSplitIndices?: number[];
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
const nextCoords = getElementPointsCoords(element, nextPoints);
|
const nextCoords = getElementPointsCoords(element, nextPoints);
|
||||||
const prevCoords = getElementPointsCoords(element, element.points);
|
const prevCoords = getElementPointsCoords(element, element.points);
|
||||||
@ -1472,6 +1500,27 @@ export class LinearElementEditor {
|
|||||||
|
|
||||||
return coords;
|
return coords;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static toggleSegmentSplitAtIndex(
|
||||||
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
|
index: number,
|
||||||
|
) {
|
||||||
|
let found = false;
|
||||||
|
const splitIndices = (element.segmentSplitIndices || []).filter((idx) => {
|
||||||
|
if (idx === index) {
|
||||||
|
found = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (!found) {
|
||||||
|
splitIndices.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutateElement(element, {
|
||||||
|
segmentSplitIndices: splitIndices.sort((a, b) => a - b),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeSelectedPoints = (
|
const normalizeSelectedPoints = (
|
||||||
|
@ -25,7 +25,7 @@ export const mutateElement = <TElement extends Mutable<ExcalidrawElement>>(
|
|||||||
|
|
||||||
// casting to any because can't use `in` operator
|
// casting to any because can't use `in` operator
|
||||||
// (see https://github.com/microsoft/TypeScript/issues/21732)
|
// (see https://github.com/microsoft/TypeScript/issues/21732)
|
||||||
const { points, fileId } = updates as any;
|
const { points, fileId, segmentSplitIndices } = updates as any;
|
||||||
|
|
||||||
if (typeof points !== "undefined") {
|
if (typeof points !== "undefined") {
|
||||||
updates = { ...getSizeFromPoints(points), ...updates };
|
updates = { ...getSizeFromPoints(points), ...updates };
|
||||||
@ -86,6 +86,7 @@ export const mutateElement = <TElement extends Mutable<ExcalidrawElement>>(
|
|||||||
if (
|
if (
|
||||||
typeof updates.height !== "undefined" ||
|
typeof updates.height !== "undefined" ||
|
||||||
typeof updates.width !== "undefined" ||
|
typeof updates.width !== "undefined" ||
|
||||||
|
typeof segmentSplitIndices !== "undefined" ||
|
||||||
typeof fileId != "undefined" ||
|
typeof fileId != "undefined" ||
|
||||||
typeof points !== "undefined"
|
typeof points !== "undefined"
|
||||||
) {
|
) {
|
||||||
|
@ -374,6 +374,7 @@ export const newLinearElement = (
|
|||||||
endBinding: null,
|
endBinding: null,
|
||||||
startArrowhead: opts.startArrowhead || null,
|
startArrowhead: opts.startArrowhead || null,
|
||||||
endArrowhead: opts.endArrowhead || null,
|
endArrowhead: opts.endArrowhead || null,
|
||||||
|
segmentSplitIndices: [],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ export type ExcalidrawLinearElement = _ExcalidrawElementBase &
|
|||||||
Readonly<{
|
Readonly<{
|
||||||
type: "line" | "arrow";
|
type: "line" | "arrow";
|
||||||
points: readonly Point[];
|
points: readonly Point[];
|
||||||
|
segmentSplitIndices: readonly number[] | null;
|
||||||
lastCommittedPoint: Point | null;
|
lastCommittedPoint: Point | null;
|
||||||
startBinding: PointBinding | null;
|
startBinding: PointBinding | null;
|
||||||
endBinding: PointBinding | null;
|
endBinding: PointBinding | null;
|
||||||
|
@ -166,6 +166,21 @@ const fillCircle = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fillSquare = (
|
||||||
|
context: CanvasRenderingContext2D,
|
||||||
|
cx: number,
|
||||||
|
cy: number,
|
||||||
|
side: number,
|
||||||
|
stroke = true,
|
||||||
|
) => {
|
||||||
|
context.beginPath();
|
||||||
|
context.rect(cx - side / 2, cy - side / 2, side, side);
|
||||||
|
context.fill();
|
||||||
|
if (stroke) {
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const strokeGrid = (
|
const strokeGrid = (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
gridSize: number,
|
gridSize: number,
|
||||||
@ -224,6 +239,7 @@ const renderSingleLinearPoint = (
|
|||||||
point: Point,
|
point: Point,
|
||||||
radius: number,
|
radius: number,
|
||||||
isSelected: boolean,
|
isSelected: boolean,
|
||||||
|
renderAsSquare: boolean,
|
||||||
isPhantomPoint = false,
|
isPhantomPoint = false,
|
||||||
) => {
|
) => {
|
||||||
context.strokeStyle = "#5e5ad8";
|
context.strokeStyle = "#5e5ad8";
|
||||||
@ -235,13 +251,29 @@ const renderSingleLinearPoint = (
|
|||||||
context.fillStyle = "rgba(177, 151, 252, 0.7)";
|
context.fillStyle = "rgba(177, 151, 252, 0.7)";
|
||||||
}
|
}
|
||||||
|
|
||||||
fillCircle(
|
const effectiveRadius = radius / appState.zoom.value;
|
||||||
context,
|
|
||||||
point[0],
|
if (renderAsSquare) {
|
||||||
point[1],
|
fillSquare(
|
||||||
radius / appState.zoom.value,
|
context,
|
||||||
!isPhantomPoint,
|
point[0],
|
||||||
);
|
point[1],
|
||||||
|
effectiveRadius * 2,
|
||||||
|
!isPhantomPoint,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fillCircle(context, point[0], point[1], effectiveRadius, !isPhantomPoint);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLinearPointAtIndexSquared = (
|
||||||
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
|
index: number,
|
||||||
|
) => {
|
||||||
|
const splitting = element.segmentSplitIndices
|
||||||
|
? element.segmentSplitIndices.includes(index)
|
||||||
|
: false;
|
||||||
|
return element.roundness ? splitting : !splitting;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderLinearPointHandles = (
|
const renderLinearPointHandles = (
|
||||||
@ -265,7 +297,14 @@ const renderLinearPointHandles = (
|
|||||||
const isSelected =
|
const isSelected =
|
||||||
!!appState.editingLinearElement?.selectedPointsIndices?.includes(idx);
|
!!appState.editingLinearElement?.selectedPointsIndices?.includes(idx);
|
||||||
|
|
||||||
renderSingleLinearPoint(context, appState, point, radius, isSelected);
|
renderSingleLinearPoint(
|
||||||
|
context,
|
||||||
|
appState,
|
||||||
|
point,
|
||||||
|
radius,
|
||||||
|
isSelected,
|
||||||
|
isLinearPointAtIndexSquared(element, idx),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
//Rendering segment mid points
|
//Rendering segment mid points
|
||||||
@ -293,6 +332,7 @@ const renderLinearPointHandles = (
|
|||||||
segmentMidPoint,
|
segmentMidPoint,
|
||||||
radius,
|
radius,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
highlightPoint(segmentMidPoint, context, appState);
|
highlightPoint(segmentMidPoint, context, appState);
|
||||||
} else {
|
} else {
|
||||||
@ -303,6 +343,7 @@ const renderLinearPointHandles = (
|
|||||||
segmentMidPoint,
|
segmentMidPoint,
|
||||||
radius,
|
radius,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (appState.editingLinearElement || points.length === 2) {
|
} else if (appState.editingLinearElement || points.length === 2) {
|
||||||
@ -312,6 +353,7 @@ const renderLinearPointHandles = (
|
|||||||
segmentMidPoint,
|
segmentMidPoint,
|
||||||
POINT_HANDLE_SIZE / 2,
|
POINT_HANDLE_SIZE / 2,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -324,16 +366,16 @@ const highlightPoint = (
|
|||||||
point: Point,
|
point: Point,
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
appState: InteractiveCanvasAppState,
|
appState: InteractiveCanvasAppState,
|
||||||
|
renderAsSquare = false,
|
||||||
) => {
|
) => {
|
||||||
context.fillStyle = "rgba(105, 101, 219, 0.4)";
|
context.fillStyle = "rgba(105, 101, 219, 0.4)";
|
||||||
|
const radius = LinearElementEditor.POINT_HANDLE_SIZE / appState.zoom.value;
|
||||||
|
|
||||||
fillCircle(
|
if (renderAsSquare) {
|
||||||
context,
|
fillSquare(context, point[0], point[1], radius * 2, false);
|
||||||
point[0],
|
} else {
|
||||||
point[1],
|
fillCircle(context, point[0], point[1], radius, false);
|
||||||
LinearElementEditor.POINT_HANDLE_SIZE / appState.zoom.value,
|
}
|
||||||
false,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const renderLinearElementPointHighlight = (
|
const renderLinearElementPointHighlight = (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
@ -355,10 +397,15 @@ const renderLinearElementPointHighlight = (
|
|||||||
element,
|
element,
|
||||||
hoverPointIndex,
|
hoverPointIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
context.translate(appState.scrollX, appState.scrollY);
|
context.translate(appState.scrollX, appState.scrollY);
|
||||||
|
highlightPoint(
|
||||||
highlightPoint(point, context, appState);
|
point,
|
||||||
|
context,
|
||||||
|
appState,
|
||||||
|
isLinearPointAtIndexSquared(element, hoverPointIndex),
|
||||||
|
);
|
||||||
context.restore();
|
context.restore();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import { generateFreeDrawShape } from "../renderer/renderElement";
|
|||||||
import { isTransparent, assertNever } from "../utils";
|
import { isTransparent, assertNever } from "../utils";
|
||||||
import { simplify } from "points-on-curve";
|
import { simplify } from "points-on-curve";
|
||||||
import { ROUGHNESS } from "../constants";
|
import { ROUGHNESS } from "../constants";
|
||||||
|
import { Point } from "../types";
|
||||||
|
|
||||||
const getDashArrayDashed = (strokeWidth: number) => [8, 8 + strokeWidth];
|
const getDashArrayDashed = (strokeWidth: number) => [8, 8 + strokeWidth];
|
||||||
|
|
||||||
@ -228,18 +229,44 @@ export const _generateElementShape = (
|
|||||||
|
|
||||||
// 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]] as Point[]);
|
||||||
|
|
||||||
// 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
|
||||||
|
const splits = element.segmentSplitIndices || [];
|
||||||
if (!element.roundness) {
|
if (!element.roundness) {
|
||||||
if (options.fill) {
|
if (splits.length === 0) {
|
||||||
shape = [generator.polygon(points as [number, number][], options)];
|
if (options.fill) {
|
||||||
|
shape = [generator.polygon(points as [number, number][], options)];
|
||||||
|
} else {
|
||||||
|
shape = [
|
||||||
|
generator.linearPath(points as [number, number][], options),
|
||||||
|
];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
shape = [generator.linearPath(points as [number, number][], options)];
|
const splitInverse: number[] = [];
|
||||||
|
const splitSet = new Set(splits);
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
if (!splitSet.has(i)) {
|
||||||
|
splitInverse.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shape = [
|
||||||
|
generator.curve(
|
||||||
|
computeMultipleCurvesFromSplits(points, splitInverse),
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shape = [generator.curve(points as [number, number][], options)];
|
shape = [
|
||||||
|
generator.curve(
|
||||||
|
computeMultipleCurvesFromSplits(points, splits),
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// add lines only in arrow
|
// add lines only in arrow
|
||||||
@ -376,3 +403,22 @@ export const _generateElementShape = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const computeMultipleCurvesFromSplits = (
|
||||||
|
points: readonly Point[],
|
||||||
|
splits: readonly number[],
|
||||||
|
): [number, number][][] => {
|
||||||
|
const pointList: Point[][] = [];
|
||||||
|
let currentIndex = 0;
|
||||||
|
for (const index of splits) {
|
||||||
|
const slice = points.slice(currentIndex, index + 1);
|
||||||
|
if (slice.length) {
|
||||||
|
pointList.push([...slice]);
|
||||||
|
}
|
||||||
|
currentIndex = index;
|
||||||
|
}
|
||||||
|
if (currentIndex < points.length - 1) {
|
||||||
|
pointList.push(points.slice(currentIndex));
|
||||||
|
}
|
||||||
|
return pointList as [number, number][][];
|
||||||
|
};
|
||||||
|
@ -6459,10 +6459,10 @@ rollup@^3.25.2:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
roughjs@4.6.4:
|
roughjs@4.6.5:
|
||||||
version "4.6.4"
|
version "4.6.5"
|
||||||
resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.4.tgz#b6f39b44645854a6e0a4a28b078368701eb7f939"
|
resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.5.tgz#1db965cf1a043cb7f05181dd7d119f7960fba8d8"
|
||||||
integrity sha512-s6EZ0BntezkFYMf/9mGn7M8XGIoaav9QQBCnJROWB3brUWQ683Q2LbRD/hq0Z3bAJ/9NVpU/5LpiTWvQMyLDhw==
|
integrity sha512-4Q6XBbZWlp8yj1uipq2bQ1CPlxMhW/ukufwkuhh+2L79utk+O5kMSbfVh4UNBMtKJ3PxHQ9Ou3ncNt1iQcphJA==
|
||||||
dependencies:
|
dependencies:
|
||||||
hachure-fill "^0.5.2"
|
hachure-fill "^0.5.2"
|
||||||
path-data-parser "^0.1.0"
|
path-data-parser "^0.1.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user