Files
AFFiNE-Mirror/libs/components/board-shapes/src/triangle-util/triangle-helpers.ts
T
2022-07-22 15:49:21 +08:00

114 lines
3.3 KiB
TypeScript

import { Utils } from '@tldraw/core';
import Vec from '@tldraw/vec';
import getStroke, { getStrokePoints } from 'perfect-freehand';
import type { ShapeStyles } from '@toeverything/components/board-types';
import { getShapeStyle, getOffsetPolygon } from '../shared';
export function getTrianglePoints(size: number[], offset = 0, rotation = 0) {
const [w, h] = size;
let points = [
[w / 2, 0],
[w, h],
[0, h],
];
if (offset) points = getOffsetPolygon(points, offset);
if (rotation)
points = points.map(pt => Vec.rotWith(pt, [w / 2, h / 2], rotation));
return points;
}
export function getTriangleCentroid(size: number[]) {
const [w, h] = size;
const points = [
[w / 2, 0],
[w, h],
[0, h],
];
return [
(points[0][0] + points[1][0] + points[2][0]) / 3,
(points[0][1] + points[1][1] + points[2][1]) / 3,
];
}
function getTriangleDrawPoints(
id: string,
size: number[],
strokeWidth: number
) {
const [w, h] = size;
const getRandom = Utils.rng(id);
// Random corner offsets
const offsets = Array.from(Array(3)).map(() => {
return [
getRandom() * strokeWidth * 0.75,
getRandom() * strokeWidth * 0.75,
];
});
// Corners
const corners = [
Vec.add([w / 2, 0], offsets[0]),
Vec.add([w, h], offsets[1]),
Vec.add([0, h], offsets[2]),
];
// Which side to start drawing first
const rm = Math.round(Math.abs(getRandom() * 2 * 3));
// Number of points per side
// Inset each line by the corner radii and let the freehand algo
// interpolate points for the corners.
const lines = Utils.rotateArray(
[
Vec.pointsBetween(corners[0], corners[1], 32),
Vec.pointsBetween(corners[1], corners[2], 32),
Vec.pointsBetween(corners[2], corners[0], 32),
],
rm
);
// For the final points, include the first half of the first line again,
// so that the line wraps around and avoids ending on a sharp corner.
// This has a bit of finesse and magic—if you change the points between
// function, then you'll likely need to change this one too.
const points = [...lines.flat(), ...lines[0]];
return {
points,
};
}
function getDrawStrokeInfo(id: string, size: number[], style: ShapeStyles) {
const { strokeWidth } = getShapeStyle(style);
const { points } = getTriangleDrawPoints(id, size, strokeWidth);
const options = {
size: strokeWidth,
thinning: 0.65,
streamline: 0.3,
smoothing: 1,
simulatePressure: false,
last: true,
};
return { points, options };
}
export function getTrianglePath(
id: string,
size: number[],
style: ShapeStyles
) {
const { points, options } = getDrawStrokeInfo(id, size, style);
const stroke = getStroke(points, options);
return Utils.getSvgPathFromStroke(stroke);
}
// eslint-disable-next-line @typescript-eslint/naming-convention
export function getTriangleIndicatorPathTDSnapshot(
id: string,
size: number[],
style: ShapeStyles
) {
const { points, options } = getDrawStrokeInfo(id, size, style);
const strokePoints = getStrokePoints(points, options);
return Utils.getSvgPathFromStroke(
strokePoints.map(pt => pt.point.slice(0, 2)),
false
);
}