Skip to content

Commit

Permalink
feat: improve empty text element hit interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
pubuzhixing8 committed Dec 24, 2024
1 parent e925774 commit 03be33a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 18 deletions.
39 changes: 29 additions & 10 deletions packages/core/src/utils/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function getNearestPointBetweenPointAndEllipse(point: Point, center: Poin
const a = Math.abs(rectangleClient.width) / 2;
const b = Math.abs(rectangleClient.height) / 2;

[0, 1, 2, 3].forEach(x => {
[0, 1, 2, 3].forEach((x) => {
const xx = a * tx;
const yy = b * ty;

Expand Down Expand Up @@ -186,19 +186,38 @@ export const isPolylineHitRectangle = (points: Point[], rectangle: RectangleClie
if (i === len - 1 && !isClose) continue;
const p1 = points[i];
const p2 = points[(i + 1) % len];
const isHit =
isLineHitLine(p1, p2, rectanglePoints[0], rectanglePoints[1]) ||
isLineHitLine(p1, p2, rectanglePoints[1], rectanglePoints[2]) ||
isLineHitLine(p1, p2, rectanglePoints[2], rectanglePoints[3]) ||
isLineHitLine(p1, p2, rectanglePoints[3], rectanglePoints[0]);
const isHit = isLineHitRectangleEdge(p1, p2, rectangle);
if (isHit || isPointInPolygon(p1, rectanglePoints) || isPointInPolygon(p2, rectanglePoints)) {
return true;
}
}
return false;
};

export const isPolylineHitRectangleEdge = (points: Point[], rectangle: RectangleClient, isClose: boolean = true) => {
const len = points.length;
for (let i = 0; i < len; i++) {
if (i === len - 1 && !isClose) continue;
const p1 = points[i];
const p2 = points[(i + 1) % len];
const isHit = isLineHitRectangleEdge(p1, p2, rectangle);
if (isHit) {
return true;
}
}
return false;
};

export const isLineHitRectangleEdge = (p1: Point, p2: Point, rectangle: RectangleClient) => {
const rectanglePoints = RectangleClient.getCornerPoints(rectangle);
return (
isLineHitLine(p1, p2, rectanglePoints[0], rectanglePoints[1]) ||
isLineHitLine(p1, p2, rectanglePoints[1], rectanglePoints[2]) ||
isLineHitLine(p1, p2, rectanglePoints[2], rectanglePoints[3]) ||
isLineHitLine(p1, p2, rectanglePoints[3], rectanglePoints[0])
);
};

//https://stackoverflow.com/questions/22521982/check-if-point-is-inside-a-polygon
export const isPointInPolygon = (point: Point, points: Point[]) => {
// ray-casting algorithm based on
Expand Down Expand Up @@ -262,7 +281,7 @@ export const isPointInRoundRectangle = (point: Point, rectangle: RectangleClient
};

// https://gist.github.com/nicholaswmin/c2661eb11cad5671d816
export const catmullRomFitting = function(points: Point[]) {
export const catmullRomFitting = function (points: Point[]) {
const alpha = 0.5;
let p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M;
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
Expand Down Expand Up @@ -423,9 +442,9 @@ export function getCrossingPointsBetweenEllipseAndSegment(
return (
tValues
// Filter to only points that are on the segment.
.filter(t => !segment_only || (t >= 0 && t <= 1))
.filter((t) => !segment_only || (t >= 0 && t <= 1))
// Solve for points.
.map(t => [startPoint[0] + (endPoint[0] - startPoint[0]) * t + cx, startPoint[1] + (endPoint[1] - startPoint[1]) * t + cy])
.map((t) => [startPoint[0] + (endPoint[0] - startPoint[0]) * t + cx, startPoint[1] + (endPoint[1] - startPoint[1]) * t + cy])
);
}

Expand All @@ -439,4 +458,4 @@ export function getCrossingPointsBetweenEllipseAndSegment(
*/
export function getPointBetween(x0: number, y0: number, x1: number, y1: number, d = 0.5) {
return [x0 + (x1 - x0) * d, y0 + (y1 - y0) * d];
}
}
30 changes: 22 additions & 8 deletions packages/draw/src/utils/hit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
rotatePointsByElement,
rotateAntiPointsByElement,
isPointInPolygon,
rotatePointsByAngle
rotatePointsByAngle,
isPolylineHitRectangleEdge
} from '@plait/core';
import {
PlaitArrowLine,
Expand All @@ -30,8 +31,9 @@ import { getElementShape } from './shape';
import { getHitArrowLineTextIndex } from './position/arrow-line';
import { getTextRectangle, isClosedCustomGeometry, isClosedDrawElement, isClosedPoints } from './common';
import { isMultipleTextGeometry } from './multi-text-geometry';
import { isFilled, sortElementsByArea } from '@plait/common';
import { getFirstTextEditor, isFilled, sortElementsByArea } from '@plait/common';
import { getVectorLinePoints } from './vector-line';
import { Editor, Element } from 'slate';

export const isTextExceedingBounds = (geometry: PlaitGeometry) => {
const client = RectangleClient.getRectangleByPoints(geometry.points);
Expand Down Expand Up @@ -69,7 +71,7 @@ export const isRectangleHitElementText = (element: PlaitCommonGeometry, rectangl
const engine = getEngine<PlaitCommonGeometry>(element.shape);
if (isMultipleTextGeometry(element)) {
const texts = element.texts;
return texts.some(item => {
return texts.some((item) => {
const textClient = engine.getTextRectangle!(element, { id: item.id });
return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(textClient), element.angle);
});
Expand All @@ -83,7 +85,7 @@ export const isHitElementText = (element: PlaitCommonGeometry, point: Point) =>
const engine = getEngine<PlaitCommonGeometry>(element.shape);
if (isMultipleTextGeometry(element)) {
const texts = element.texts;
return texts.some(item => {
return texts.some((item) => {
const textClient = engine.getTextRectangle!(element, { id: item.id });
return RectangleClient.isPointInRectangle(textClient, point);
});
Expand All @@ -93,14 +95,19 @@ export const isHitElementText = (element: PlaitCommonGeometry, point: Point) =>
}
};

export const isEmptyTextElement = (element: PlaitCommonGeometry) => {
const editor = getFirstTextEditor(element);
return Editor.isEmpty(editor, editor.children[0] as Element);
};

export const isRectangleHitDrawElement = (board: PlaitBoard, element: PlaitElement, selection: Selection) => {
const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
if (PlaitDrawElement.isGeometry(element)) {
const isHitElement = isRectangleHitRotatedElement(board, rangeRectangle, element);
if (isHitElement) {
return isHitElement;
}
return isRectangleHitElementText(element, rangeRectangle);
return !isEmptyTextElement(element) && isRectangleHitElementText(element, rangeRectangle);
}

if (PlaitDrawElement.isImage(element)) {
Expand Down Expand Up @@ -131,7 +138,7 @@ export const isRectangleHitRotatedElement = (

export const isRectangleHitRotatedPoints = (rectangle: RectangleClient, points: Point[], angle: number | undefined) => {
let rotatedPoints = rotatePointsByAngle(points, angle) || points;
return isPolylineHitRectangle(rotatedPoints, rectangle);
return isPolylineHitRectangleEdge(rotatedPoints, rectangle);
};

export const getHitDrawElement = (board: PlaitBoard, elements: (PlaitDrawElement | PlaitCustomGeometry)[]) => {
Expand Down Expand Up @@ -164,12 +171,16 @@ export const getFirstFilledDrawElement = (board: PlaitBoard, elements: (PlaitDra
return filledElement;
};

export const isFilledDrawElement = (board: PlaitBoard, element: PlaitDrawElement | PlaitCustomGeometry) => {
return getFirstFilledDrawElement(board, [element]) !== null;
};

export const getFirstTextOrLineElement = (elements: PlaitElement[]) => {
const texts = elements.filter(item => PlaitDrawElement.isText(item));
const texts = elements.filter((item) => PlaitDrawElement.isText(item));
if (texts.length) {
return texts[0];
}
const lines = elements.filter(item => PlaitDrawElement.isArrowLine(item));
const lines = elements.filter((item) => PlaitDrawElement.isArrowLine(item));
if (lines.length) {
return lines[0];
}
Expand All @@ -188,6 +199,9 @@ export const isHitDrawElement = (board: PlaitBoard, element: PlaitElement, point
const textClient = getTextRectangle(element);
return RectangleClient.isPointInRectangle(textClient, point);
}
if (isEmptyTextElement(element) && !isFilledDrawElement(board, element)) {
return false;
}
const isHitText = isHitElementText(element, point);
return isHitText || engine.isInsidePoint(rectangle!, point);
}
Expand Down

0 comments on commit 03be33a

Please sign in to comment.