@plait/draw 0.75.0-next.9 → 0.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/engines/basic-shapes/cloud.d.ts +2 -12
- package/engines/uml/provided-interface.d.ts +0 -5
- package/esm2022/engines/basic-shapes/cloud.mjs +10 -11
- package/esm2022/engines/flowchart/note-curly-left.mjs +48 -12
- package/esm2022/engines/flowchart/note-curly-right.mjs +49 -10
- package/esm2022/engines/uml/actor.mjs +61 -44
- package/esm2022/engines/uml/assembly.mjs +72 -23
- package/esm2022/engines/uml/component.mjs +78 -33
- package/esm2022/engines/uml/deletion.mjs +28 -6
- package/esm2022/engines/uml/package.mjs +51 -21
- package/esm2022/engines/uml/provided-interface.mjs +53 -26
- package/esm2022/engines/uml/required-interface.mjs +51 -7
- package/esm2022/plugins/with-arrow-line-text-move.mjs +2 -2
- package/esm2022/plugins/with-table.mjs +3 -2
- package/esm2022/utils/hit.mjs +5 -5
- package/fesm2022/plait-draw.mjs +489 -178
- package/fesm2022/plait-draw.mjs.map +1 -1
- package/package.json +1 -1
package/fesm2022/plait-draw.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ACTIVE_STROKE_WIDTH, DEFAULT_COLOR, ThemeColorMode, PlaitElement, RectangleClient, getSelectedElements, idCreator, catmullRomFitting, PlaitBoard, createG, drawLinearPath, setStrokeLinecap, setPathStrokeLinecap, getNearestPointBetweenPointAndArc, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPointInPolygon, isLineHitRectangle, rotatePointsByAngle, createDebugGenerator, rotateAntiPointsByElement, getEllipseArcCenter, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, depthFirstRecursion, getIsRecursionFunc, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Point, arrowPoints, createPath, rotate, findElements, createMask, createRect, getElementById, rotatePointsByElement, PlaitNode, hasValidAngle, toViewBoxPoint, toHostPoint, Direction, rotatePoints, getRectangleByElements, getSelectionAngle, rotatedDataPoints, isAxisChangedByAngle, isSelectionMoving, drawRectangle, getRectangleByAngle, getSnapRectangles, getTripleAxis, getMinPointDelta, SNAP_TOLERANCE, drawPointSnapLines, drawSolidLines, getNearestPointBetweenPointAndSegments, isPointInEllipse, getNearestPointBetweenPointAndEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRoundRectangle, isPointInRoundRectangle, getCrossingPointsBetweenEllipseAndSegment, drawLine, Path, RgbaToHEX, SELECTION_RECTANGLE_CLASS_NAME, getHitElementByPoint, WritableClipboardOperationType, WritableClipboardType, addOrCreateClipboardContext, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER, isMainPointer, throttleRAF, getAngleBetweenPoints, normalizeAngle, degreesToRadians, rotateElements, MERGING, ROTATE_HANDLE_CLASS_NAME, isSelectedElement, isDragging } from '@plait/core';
|
|
1
|
+
import { ACTIVE_STROKE_WIDTH, DEFAULT_COLOR, ThemeColorMode, PlaitElement, RectangleClient, getSelectedElements, idCreator, catmullRomFitting, PlaitBoard, createG, drawLinearPath, setStrokeLinecap, setPathStrokeLinecap, getNearestPointBetweenPointAndArc, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPointInPolygon, isLineHitRectangle, rotatePointsByAngle, createDebugGenerator, rotateAntiPointsByElement, getEllipseArcCenter, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, depthFirstRecursion, getIsRecursionFunc, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Point, arrowPoints, createPath, rotate, findElements, createMask, createRect, getElementById, rotatePointsByElement, PlaitNode, hasValidAngle, toViewBoxPoint, toHostPoint, Direction, rotatePoints, getRectangleByElements, getSelectionAngle, rotatedDataPoints, isAxisChangedByAngle, isSelectionMoving, drawRectangle, getRectangleByAngle, getSnapRectangles, getTripleAxis, getMinPointDelta, SNAP_TOLERANCE, drawPointSnapLines, drawSolidLines, getNearestPointBetweenPointAndSegments, isPointInEllipse, getNearestPointBetweenPointAndEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRoundRectangle, isPointInRoundRectangle, getCrossingPointsBetweenEllipseAndSegment, drawLine, getNearestPointBetweenPointAndDiscreteSegments, getNearestPointBetweenPointAndSegment, Path, RgbaToHEX, SELECTION_RECTANGLE_CLASS_NAME, getHitElementByPoint, WritableClipboardOperationType, WritableClipboardType, addOrCreateClipboardContext, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER, isMainPointer, throttleRAF, getAngleBetweenPoints, normalizeAngle, degreesToRadians, rotateElements, MERGING, ROTATE_HANDLE_CLASS_NAME, isSelectedElement, isDragging } from '@plait/core';
|
|
2
2
|
import { DEFAULT_FILL, Alignment, WithTextPluginKey, TextManage, getMemorizedLatest, memorizeLatest, getPointOnPolyline, buildText, Generator, getStrokeLineDash, StrokeStyle, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getFirstTextEditor, sortElementsByArea, isFilled, getTextEditorsByElement, removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, getExtendPoint, getUnitVectorByPointAndPoint, getPointByVectorComponent, RESIZE_HANDLE_DIAMETER, measureElement, DEFAULT_FONT_FAMILY, getFirstTextManage, ActiveGenerator, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, normalizeShapePoints, resetPointsAfterResize, getDirectionByVector, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, ROTATE_HANDLE_DISTANCE_TO_ELEMENT, ROTATE_HANDLE_SIZE, isCornerHandle, getIndexByResizeHandle, withResize, drawHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, getDirectionFactorByDirectionComponent, buildClipboardData as buildClipboardData$1, insertClipboardData as insertClipboardData$1, getDirectionByPointOfRectangle, getDirectionFactor, rotateVector, getOppositeDirection, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, PRIMARY_COLOR, CommonElementFlavour, hasResizeHandle, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, isResizingByCondition, getRatioByPoint, getTextManages, ImageGenerator, ResizeHandle, addRotating, removeRotating, drawRotateHandle } from '@plait/common';
|
|
3
3
|
import { pointsOnBezierCurves } from 'points-on-curve';
|
|
4
4
|
import { TEXT_DEFAULT_HEIGHT, DEFAULT_FONT_SIZE, AlignEditor } from '@plait/text-plugins';
|
|
@@ -1069,7 +1069,7 @@ function generateCloudPath(rectangle) {
|
|
|
1069
1069
|
const xRadius = divisionWidth / 8.5;
|
|
1070
1070
|
const yRadius = divisionHeight / 20;
|
|
1071
1071
|
const startPoint = [rectangle.x + divisionWidth, rectangle.y + divisionHeight];
|
|
1072
|
-
const
|
|
1072
|
+
const arcCommands = [
|
|
1073
1073
|
{
|
|
1074
1074
|
rx: xRadius,
|
|
1075
1075
|
ry: yRadius * 1.2,
|
|
@@ -1143,15 +1143,15 @@ function generateCloudPath(rectangle) {
|
|
|
1143
1143
|
endY: rectangle.y + divisionHeight
|
|
1144
1144
|
}
|
|
1145
1145
|
];
|
|
1146
|
-
return { startPoint,
|
|
1146
|
+
return { startPoint, arcCommands };
|
|
1147
1147
|
}
|
|
1148
1148
|
const CloudEngine = {
|
|
1149
1149
|
draw(board, rectangle, options) {
|
|
1150
1150
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
1151
|
-
const { startPoint,
|
|
1151
|
+
const { startPoint, arcCommands } = generateCloudPath(rectangle);
|
|
1152
1152
|
const pathData = `M ${startPoint[0]} ${startPoint[1]} ` +
|
|
1153
|
-
|
|
1154
|
-
.map((
|
|
1153
|
+
arcCommands
|
|
1154
|
+
.map((command) => `A ${command.rx} ${command.ry} ${command.xAxisRotation} ${command.largeArcFlag} ${command.sweepFlag} ${command.endX} ${command.endY}`)
|
|
1155
1155
|
.join('\n') +
|
|
1156
1156
|
' Z';
|
|
1157
1157
|
const svgElement = rs.path(pathData, { ...options, fillStyle: 'solid' });
|
|
@@ -1166,19 +1166,18 @@ const CloudEngine = {
|
|
|
1166
1166
|
return RectangleClient.getCornerPoints(rectangle);
|
|
1167
1167
|
},
|
|
1168
1168
|
getNearestPoint(rectangle, point) {
|
|
1169
|
-
const { startPoint,
|
|
1169
|
+
const { startPoint, arcCommands } = generateCloudPath(rectangle);
|
|
1170
1170
|
let minDistance = Infinity;
|
|
1171
1171
|
let nearestPoint = point;
|
|
1172
|
-
// 检查每个弧段
|
|
1173
1172
|
let currentStart = startPoint;
|
|
1174
|
-
for (const
|
|
1175
|
-
const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart,
|
|
1173
|
+
for (const arcCommand of arcCommands) {
|
|
1174
|
+
const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart, arcCommand);
|
|
1176
1175
|
const distance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
|
|
1177
1176
|
if (distance < minDistance) {
|
|
1178
1177
|
minDistance = distance;
|
|
1179
1178
|
nearestPoint = arcNearestPoint;
|
|
1180
1179
|
}
|
|
1181
|
-
currentStart = [
|
|
1180
|
+
currentStart = [arcCommand.endX, arcCommand.endY];
|
|
1182
1181
|
}
|
|
1183
1182
|
return nearestPoint;
|
|
1184
1183
|
},
|
|
@@ -1216,7 +1215,7 @@ const isHitArrowLineText = (board, element, point) => {
|
|
|
1216
1215
|
return getHitArrowLineTextIndex(board, element, point) !== -1;
|
|
1217
1216
|
};
|
|
1218
1217
|
const isHitPolyLine = (pathPoints, point) => {
|
|
1219
|
-
const distance = distanceBetweenPointAndSegments(
|
|
1218
|
+
const distance = distanceBetweenPointAndSegments(point, pathPoints);
|
|
1220
1219
|
return distance <= HIT_DISTANCE_BUFFER;
|
|
1221
1220
|
};
|
|
1222
1221
|
const isHitArrowLine = (board, element, point) => {
|
|
@@ -1349,13 +1348,13 @@ const isHitDrawElement = (board, element, point, isStrict = true) => {
|
|
|
1349
1348
|
if (PlaitDrawElement.isGeometry(element) && rectangle) {
|
|
1350
1349
|
if (debugGenerator$4.isDebug() && shapes.includes(element.shape)) {
|
|
1351
1350
|
debugGenerator$4.clear();
|
|
1352
|
-
const { startPoint,
|
|
1353
|
-
const points = [startPoint, ...
|
|
1351
|
+
const { startPoint, arcCommands } = generateCloudPath(rectangle);
|
|
1352
|
+
const points = [startPoint, ...arcCommands.map((arc) => [arc.endX, arc.endY])];
|
|
1354
1353
|
debugGenerator$4.drawCircles(board, points, 5, false);
|
|
1355
1354
|
let minDistance = Infinity;
|
|
1356
1355
|
let nearestPoint = point;
|
|
1357
1356
|
let currentStart = startPoint;
|
|
1358
|
-
for (const arc of
|
|
1357
|
+
for (const arc of arcCommands) {
|
|
1359
1358
|
const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart, arc);
|
|
1360
1359
|
const distance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
|
|
1361
1360
|
const { center } = getEllipseArcCenter(currentStart, arc);
|
|
@@ -5358,19 +5357,57 @@ const InternalStorageEngine = {
|
|
|
5358
5357
|
}
|
|
5359
5358
|
};
|
|
5360
5359
|
|
|
5360
|
+
function generateNoteCurlyLeftPath(rectangle) {
|
|
5361
|
+
const curlyWidth = rectangle.width * 0.09;
|
|
5362
|
+
const rightX = rectangle.x + rectangle.width;
|
|
5363
|
+
const centerY = rectangle.y + rectangle.height / 2;
|
|
5364
|
+
return {
|
|
5365
|
+
startPoint: [rightX, rectangle.y],
|
|
5366
|
+
upperCurve: {
|
|
5367
|
+
controlPoint1: [rightX - curlyWidth, rectangle.y],
|
|
5368
|
+
controlPoint2: [rightX, centerY],
|
|
5369
|
+
endPoint: [rightX - curlyWidth, centerY]
|
|
5370
|
+
},
|
|
5371
|
+
lowerCurve: {
|
|
5372
|
+
controlPoint1: [rightX, centerY],
|
|
5373
|
+
controlPoint2: [rightX - curlyWidth, rectangle.y + rectangle.height],
|
|
5374
|
+
endPoint: [rightX, rectangle.y + rectangle.height]
|
|
5375
|
+
}
|
|
5376
|
+
};
|
|
5377
|
+
}
|
|
5361
5378
|
const NoteCurlyLeftEngine = {
|
|
5362
5379
|
draw(board, rectangle, options) {
|
|
5363
5380
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
5364
|
-
const
|
|
5365
|
-
|
|
5366
|
-
${
|
|
5367
|
-
${
|
|
5368
|
-
|
|
5369
|
-
${
|
|
5370
|
-
${
|
|
5381
|
+
const { startPoint, upperCurve, lowerCurve } = generateNoteCurlyLeftPath(rectangle);
|
|
5382
|
+
const pathData = [
|
|
5383
|
+
`M${startPoint[0]} ${startPoint[1]}`,
|
|
5384
|
+
`C${upperCurve.controlPoint1[0]} ${upperCurve.controlPoint1[1]},
|
|
5385
|
+
${upperCurve.controlPoint2[0]} ${upperCurve.controlPoint2[1]},
|
|
5386
|
+
${upperCurve.endPoint[0]} ${upperCurve.endPoint[1]}`,
|
|
5387
|
+
`C${lowerCurve.controlPoint1[0]} ${lowerCurve.controlPoint1[1]},
|
|
5388
|
+
${lowerCurve.controlPoint2[0]} ${lowerCurve.controlPoint2[1]},
|
|
5389
|
+
${lowerCurve.endPoint[0]} ${lowerCurve.endPoint[1]}`
|
|
5390
|
+
].join(' ');
|
|
5391
|
+
const shape = rs.path(pathData, { ...options, fillStyle: 'solid', fill: 'transparent' });
|
|
5371
5392
|
setStrokeLinecap(shape, 'round');
|
|
5372
5393
|
return shape;
|
|
5373
5394
|
},
|
|
5395
|
+
getNearestPoint(rectangle, point) {
|
|
5396
|
+
const { startPoint, upperCurve, lowerCurve } = generateNoteCurlyLeftPath(rectangle);
|
|
5397
|
+
const upperBezierPoints = pointsOnBezierCurves([startPoint, upperCurve.controlPoint1, upperCurve.controlPoint2, upperCurve.endPoint], 0.001);
|
|
5398
|
+
const lowerBezierPoints = pointsOnBezierCurves([upperCurve.endPoint, lowerCurve.controlPoint1, lowerCurve.controlPoint2, lowerCurve.endPoint], 0.001);
|
|
5399
|
+
const allPoints = [...upperBezierPoints, ...lowerBezierPoints];
|
|
5400
|
+
let minDistance = Infinity;
|
|
5401
|
+
let nearestPoint = point;
|
|
5402
|
+
for (const curvePoint of allPoints) {
|
|
5403
|
+
const distance = distanceBetweenPointAndPoint(point[0], point[1], curvePoint[0], curvePoint[1]);
|
|
5404
|
+
if (distance < minDistance) {
|
|
5405
|
+
minDistance = distance;
|
|
5406
|
+
nearestPoint = [...curvePoint];
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
return nearestPoint;
|
|
5410
|
+
},
|
|
5374
5411
|
isInsidePoint(rectangle, point) {
|
|
5375
5412
|
const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
|
|
5376
5413
|
return RectangleClient.isHit(rectangle, rangeRectangle);
|
|
@@ -5378,9 +5415,6 @@ const NoteCurlyLeftEngine = {
|
|
|
5378
5415
|
getCornerPoints(rectangle) {
|
|
5379
5416
|
return RectangleClient.getCornerPoints(rectangle);
|
|
5380
5417
|
},
|
|
5381
|
-
getNearestPoint(rectangle, point) {
|
|
5382
|
-
return getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
|
|
5383
|
-
},
|
|
5384
5418
|
getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
|
|
5385
5419
|
const corners = RectangleEngine.getCornerPoints(rectangle);
|
|
5386
5420
|
const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
|
|
@@ -5403,16 +5437,37 @@ const NoteCurlyLeftEngine = {
|
|
|
5403
5437
|
}
|
|
5404
5438
|
};
|
|
5405
5439
|
|
|
5440
|
+
function generateNoteCurlyRightPath(rectangle) {
|
|
5441
|
+
const curlyWidth = rectangle.width * 0.09;
|
|
5442
|
+
const centerY = rectangle.y + rectangle.height / 2;
|
|
5443
|
+
return {
|
|
5444
|
+
startPoint: [rectangle.x, rectangle.y],
|
|
5445
|
+
upperCurve: {
|
|
5446
|
+
controlPoint1: [rectangle.x + curlyWidth, rectangle.y],
|
|
5447
|
+
controlPoint2: [rectangle.x, centerY],
|
|
5448
|
+
endPoint: [rectangle.x + curlyWidth, centerY]
|
|
5449
|
+
},
|
|
5450
|
+
lowerCurve: {
|
|
5451
|
+
controlPoint1: [rectangle.x, centerY],
|
|
5452
|
+
controlPoint2: [rectangle.x + curlyWidth, rectangle.y + rectangle.height],
|
|
5453
|
+
endPoint: [rectangle.x, rectangle.y + rectangle.height]
|
|
5454
|
+
}
|
|
5455
|
+
};
|
|
5456
|
+
}
|
|
5406
5457
|
const NoteCurlyRightEngine = {
|
|
5407
5458
|
draw(board, rectangle, options) {
|
|
5408
5459
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
5409
|
-
const
|
|
5410
|
-
|
|
5411
|
-
${
|
|
5412
|
-
${
|
|
5413
|
-
|
|
5414
|
-
${
|
|
5415
|
-
${
|
|
5460
|
+
const { startPoint, upperCurve, lowerCurve } = generateNoteCurlyRightPath(rectangle);
|
|
5461
|
+
const pathData = [
|
|
5462
|
+
`M${startPoint[0]} ${startPoint[1]}`,
|
|
5463
|
+
`C${upperCurve.controlPoint1[0]} ${upperCurve.controlPoint1[1]},
|
|
5464
|
+
${upperCurve.controlPoint2[0]} ${upperCurve.controlPoint2[1]},
|
|
5465
|
+
${upperCurve.endPoint[0]} ${upperCurve.endPoint[1]}`,
|
|
5466
|
+
`C${lowerCurve.controlPoint1[0]} ${lowerCurve.controlPoint1[1]},
|
|
5467
|
+
${lowerCurve.controlPoint2[0]} ${lowerCurve.controlPoint2[1]},
|
|
5468
|
+
${lowerCurve.endPoint[0]} ${lowerCurve.endPoint[1]}`
|
|
5469
|
+
].join(' ');
|
|
5470
|
+
const shape = rs.path(pathData, { ...options, fillStyle: 'solid', fill: 'transparent' });
|
|
5416
5471
|
setStrokeLinecap(shape, 'round');
|
|
5417
5472
|
return shape;
|
|
5418
5473
|
},
|
|
@@ -5424,7 +5479,24 @@ const NoteCurlyRightEngine = {
|
|
|
5424
5479
|
return RectangleClient.getCornerPoints(rectangle);
|
|
5425
5480
|
},
|
|
5426
5481
|
getNearestPoint(rectangle, point) {
|
|
5427
|
-
|
|
5482
|
+
const { startPoint, upperCurve, lowerCurve } = generateNoteCurlyRightPath(rectangle);
|
|
5483
|
+
// 生成上部贝塞尔曲线的点
|
|
5484
|
+
const upperBezierPoints = pointsOnBezierCurves([startPoint, upperCurve.controlPoint1, upperCurve.controlPoint2, upperCurve.endPoint], 0.001);
|
|
5485
|
+
// 生成下部贝塞尔曲线的点
|
|
5486
|
+
const lowerBezierPoints = pointsOnBezierCurves([upperCurve.endPoint, lowerCurve.controlPoint1, lowerCurve.controlPoint2, lowerCurve.endPoint], 0.001);
|
|
5487
|
+
// 合并所有点
|
|
5488
|
+
const allPoints = [...upperBezierPoints, ...lowerBezierPoints];
|
|
5489
|
+
// 找到最近的点
|
|
5490
|
+
let minDistance = Infinity;
|
|
5491
|
+
let nearestPoint = [...point];
|
|
5492
|
+
for (const curvePoint of allPoints) {
|
|
5493
|
+
const distance = distanceBetweenPointAndPoint(point[0], point[1], curvePoint[0], curvePoint[1]);
|
|
5494
|
+
if (distance < minDistance) {
|
|
5495
|
+
minDistance = distance;
|
|
5496
|
+
nearestPoint = [...curvePoint];
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
return nearestPoint;
|
|
5428
5500
|
},
|
|
5429
5501
|
getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
|
|
5430
5502
|
const corners = RectangleEngine.getCornerPoints(rectangle);
|
|
@@ -5656,24 +5728,71 @@ function getHorizontalTextRectangle(cell) {
|
|
|
5656
5728
|
};
|
|
5657
5729
|
}
|
|
5658
5730
|
|
|
5731
|
+
function generateActorPath(rectangle) {
|
|
5732
|
+
const centerX = rectangle.x + rectangle.width / 2;
|
|
5733
|
+
const headRadius = { width: rectangle.width / 3 / 2, height: rectangle.height / 4 / 2 };
|
|
5734
|
+
const centerY = rectangle.y + rectangle.height / 4 / 2;
|
|
5735
|
+
return {
|
|
5736
|
+
headArcCommand: {
|
|
5737
|
+
rx: headRadius.width,
|
|
5738
|
+
ry: headRadius.height,
|
|
5739
|
+
xAxisRotation: 0,
|
|
5740
|
+
largeArcFlag: 0,
|
|
5741
|
+
sweepFlag: 1,
|
|
5742
|
+
endX: centerX,
|
|
5743
|
+
endY: rectangle.y
|
|
5744
|
+
},
|
|
5745
|
+
bodyLine: [
|
|
5746
|
+
[centerX, rectangle.y + rectangle.height / 4],
|
|
5747
|
+
[centerX, rectangle.y + (rectangle.height / 4) * 3]
|
|
5748
|
+
],
|
|
5749
|
+
armsLine: [
|
|
5750
|
+
[rectangle.x, rectangle.y + rectangle.height / 2],
|
|
5751
|
+
[rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
|
|
5752
|
+
],
|
|
5753
|
+
leftLegLine: [
|
|
5754
|
+
[centerX, rectangle.y + (rectangle.height / 4) * 3],
|
|
5755
|
+
[rectangle.x + rectangle.width / 12, rectangle.y + rectangle.height]
|
|
5756
|
+
],
|
|
5757
|
+
rightLegLine: [
|
|
5758
|
+
[centerX, rectangle.y + (rectangle.height / 4) * 3],
|
|
5759
|
+
[rectangle.x + (rectangle.width / 12) * 11, rectangle.y + rectangle.height]
|
|
5760
|
+
]
|
|
5761
|
+
};
|
|
5762
|
+
}
|
|
5659
5763
|
const ActorEngine = {
|
|
5660
5764
|
draw(board, rectangle, options) {
|
|
5661
5765
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
5662
|
-
const
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
M${
|
|
5672
|
-
|
|
5673
|
-
|
|
5766
|
+
const { headArcCommand, bodyLine, armsLine, leftLegLine, rightLegLine } = generateActorPath(rectangle);
|
|
5767
|
+
const pathData = [
|
|
5768
|
+
// 头部(从中间开始画)
|
|
5769
|
+
`M${bodyLine[0][0]} ${bodyLine[0][1]}`,
|
|
5770
|
+
`A${headArcCommand.rx} ${headArcCommand.ry} ${headArcCommand.xAxisRotation} ${headArcCommand.largeArcFlag} ${headArcCommand.sweepFlag} ${headArcCommand.endX} ${headArcCommand.endY}`,
|
|
5771
|
+
`A${headArcCommand.rx} ${headArcCommand.ry} ${headArcCommand.xAxisRotation} ${headArcCommand.largeArcFlag} ${headArcCommand.sweepFlag} ${bodyLine[0][0]} ${bodyLine[0][1]}`,
|
|
5772
|
+
// 身体
|
|
5773
|
+
`V${bodyLine[1][1]}`,
|
|
5774
|
+
// 手臂
|
|
5775
|
+
`M${armsLine[0][0]} ${armsLine[0][1]} H${armsLine[1][0]}`,
|
|
5776
|
+
// 腿
|
|
5777
|
+
`M${leftLegLine[0][0]} ${leftLegLine[0][1]} L${leftLegLine[1][0]} ${leftLegLine[1][1]}`,
|
|
5778
|
+
`M${rightLegLine[0][0]} ${rightLegLine[0][1]} L${rightLegLine[1][0]} ${rightLegLine[1][1]}`
|
|
5779
|
+
].join(' ');
|
|
5780
|
+
const shape = rs.path(pathData, { ...options, fillStyle: 'solid' });
|
|
5674
5781
|
setStrokeLinecap(shape, 'round');
|
|
5675
5782
|
return shape;
|
|
5676
5783
|
},
|
|
5784
|
+
getNearestPoint(rectangle, point) {
|
|
5785
|
+
const { headArcCommand, bodyLine, armsLine, leftLegLine, rightLegLine } = generateActorPath(rectangle);
|
|
5786
|
+
// 检查头部椭圆
|
|
5787
|
+
const headCenter = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 4 / 2];
|
|
5788
|
+
const nearestPointForHead = getNearestPointBetweenPointAndEllipse(point, headCenter, headArcCommand.rx, headArcCommand.ry);
|
|
5789
|
+
const distanceForHead = distanceBetweenPointAndPoint(...point, ...nearestPointForHead);
|
|
5790
|
+
// 检查所有线段
|
|
5791
|
+
const allSegments = [bodyLine, armsLine, leftLegLine, rightLegLine];
|
|
5792
|
+
const nearestPointForLines = getNearestPointBetweenPointAndDiscreteSegments(point, allSegments);
|
|
5793
|
+
const distanceForLines = distanceBetweenPointAndPoint(...point, ...nearestPointForLines);
|
|
5794
|
+
return distanceForHead < distanceForLines ? nearestPointForHead : nearestPointForLines;
|
|
5795
|
+
},
|
|
5677
5796
|
isInsidePoint(rectangle, point) {
|
|
5678
5797
|
const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
|
|
5679
5798
|
return RectangleClient.isHit(rectangle, rangeRectangle);
|
|
@@ -5681,35 +5800,6 @@ const ActorEngine = {
|
|
|
5681
5800
|
getCornerPoints(rectangle) {
|
|
5682
5801
|
return RectangleClient.getCornerPoints(rectangle);
|
|
5683
5802
|
},
|
|
5684
|
-
getNearestPoint(rectangle, point) {
|
|
5685
|
-
let nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
|
|
5686
|
-
if (nearestPoint[1] >= rectangle.y && nearestPoint[1] <= rectangle.y + rectangle.height / 4) {
|
|
5687
|
-
const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 4 / 2];
|
|
5688
|
-
nearestPoint = getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 3 / 2, rectangle.height / 4 / 2);
|
|
5689
|
-
return nearestPoint;
|
|
5690
|
-
}
|
|
5691
|
-
if (nearestPoint[1] >= rectangle.y + rectangle.height / 4 && nearestPoint[1] < rectangle.y + (rectangle.height / 4) * 3) {
|
|
5692
|
-
if (nearestPoint[1] === rectangle.x + rectangle.width / 2) {
|
|
5693
|
-
nearestPoint = getNearestPointBetweenPointAndSegments(point, [
|
|
5694
|
-
[rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 4],
|
|
5695
|
-
[rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height / 4) * 3]
|
|
5696
|
-
]);
|
|
5697
|
-
}
|
|
5698
|
-
else {
|
|
5699
|
-
nearestPoint = getNearestPointBetweenPointAndSegments(point, [
|
|
5700
|
-
[rectangle.x, rectangle.y + rectangle.height / 2],
|
|
5701
|
-
[rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
|
|
5702
|
-
]);
|
|
5703
|
-
}
|
|
5704
|
-
return nearestPoint;
|
|
5705
|
-
}
|
|
5706
|
-
nearestPoint = getNearestPointBetweenPointAndSegments(point, [
|
|
5707
|
-
[rectangle.x + rectangle.width / 12, rectangle.y + rectangle.height],
|
|
5708
|
-
[rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height / 4) * 3],
|
|
5709
|
-
[rectangle.x + (rectangle.width / 12) * 11, rectangle.y + rectangle.height]
|
|
5710
|
-
]);
|
|
5711
|
-
return nearestPoint;
|
|
5712
|
-
},
|
|
5713
5803
|
getConnectorPoints(rectangle) {
|
|
5714
5804
|
return RectangleClient.getEdgeCenterPoints(rectangle);
|
|
5715
5805
|
},
|
|
@@ -5794,18 +5884,41 @@ const ContainerEngine = {
|
|
|
5794
5884
|
}
|
|
5795
5885
|
};
|
|
5796
5886
|
|
|
5887
|
+
function generatePackagePath(rectangle) {
|
|
5888
|
+
const headerHeight = 25;
|
|
5889
|
+
const topWidth = rectangle.width * 0.7;
|
|
5890
|
+
const cornerX = rectangle.x + rectangle.width * 0.8;
|
|
5891
|
+
return {
|
|
5892
|
+
headerHeight,
|
|
5893
|
+
points: {
|
|
5894
|
+
leftTop: [rectangle.x, rectangle.y + headerHeight],
|
|
5895
|
+
topStart: [rectangle.x, rectangle.y],
|
|
5896
|
+
topEnd: [rectangle.x + topWidth, rectangle.y],
|
|
5897
|
+
cornerPoint: [cornerX, rectangle.y + headerHeight],
|
|
5898
|
+
rightTop: [rectangle.x + rectangle.width, rectangle.y + headerHeight],
|
|
5899
|
+
rightBottom: [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
|
|
5900
|
+
leftBottom: [rectangle.x, rectangle.y + rectangle.height],
|
|
5901
|
+
leftMiddle: [rectangle.x, rectangle.y + headerHeight],
|
|
5902
|
+
middlePoint: [cornerX, rectangle.y + headerHeight]
|
|
5903
|
+
}
|
|
5904
|
+
};
|
|
5905
|
+
}
|
|
5797
5906
|
const PackageEngine = {
|
|
5798
5907
|
draw(board, rectangle, options) {
|
|
5799
5908
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
5800
|
-
const
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
H${
|
|
5805
|
-
|
|
5806
|
-
H${
|
|
5807
|
-
V${
|
|
5808
|
-
H${
|
|
5909
|
+
const { points } = generatePackagePath(rectangle);
|
|
5910
|
+
const pathData = [
|
|
5911
|
+
`M${points.leftTop[0]} ${points.leftTop[1]}`,
|
|
5912
|
+
`V${points.topStart[1]}`,
|
|
5913
|
+
`H${points.topEnd[0]}`,
|
|
5914
|
+
`L${points.cornerPoint[0]} ${points.cornerPoint[1]}`,
|
|
5915
|
+
`H${points.rightTop[0]}`,
|
|
5916
|
+
`V${points.rightBottom[1]}`,
|
|
5917
|
+
`H${points.leftBottom[0]}`,
|
|
5918
|
+
`V${points.leftMiddle[1]}`,
|
|
5919
|
+
`H${points.middlePoint[0]}`
|
|
5920
|
+
].join(' ');
|
|
5921
|
+
const shape = rs.path(pathData, { ...options, fillStyle: 'solid' });
|
|
5809
5922
|
setStrokeLinecap(shape, 'round');
|
|
5810
5923
|
return shape;
|
|
5811
5924
|
},
|
|
@@ -5817,15 +5930,23 @@ const PackageEngine = {
|
|
|
5817
5930
|
return RectangleClient.getCornerPoints(rectangle);
|
|
5818
5931
|
},
|
|
5819
5932
|
getNearestPoint(rectangle, point) {
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
],
|
|
5827
|
-
|
|
5828
|
-
|
|
5933
|
+
const { points } = generatePackagePath(rectangle);
|
|
5934
|
+
const segments = [
|
|
5935
|
+
// 左边竖线
|
|
5936
|
+
[points.topStart, points.leftTop],
|
|
5937
|
+
[points.leftTop, points.leftBottom],
|
|
5938
|
+
// 底边
|
|
5939
|
+
[points.leftBottom, points.rightBottom],
|
|
5940
|
+
// 右边竖线
|
|
5941
|
+
[points.rightBottom, points.rightTop],
|
|
5942
|
+
// 顶部折线
|
|
5943
|
+
[points.topStart, points.topEnd],
|
|
5944
|
+
[points.topEnd, points.cornerPoint],
|
|
5945
|
+
[points.cornerPoint, points.rightTop],
|
|
5946
|
+
// 中间横线
|
|
5947
|
+
[points.leftMiddle, points.middlePoint]
|
|
5948
|
+
];
|
|
5949
|
+
return getNearestPointBetweenPointAndDiscreteSegments(point, segments);
|
|
5829
5950
|
},
|
|
5830
5951
|
getConnectorPoints(rectangle) {
|
|
5831
5952
|
return RectangleClient.getEdgeCenterPoints(rectangle);
|
|
@@ -5923,12 +6044,23 @@ const CombinedFragmentEngine = {
|
|
|
5923
6044
|
}
|
|
5924
6045
|
};
|
|
5925
6046
|
|
|
6047
|
+
function getDeletionLines(rectangle) {
|
|
6048
|
+
return [
|
|
6049
|
+
[
|
|
6050
|
+
[rectangle.x, rectangle.y],
|
|
6051
|
+
[rectangle.x + rectangle.width, rectangle.y + rectangle.height]
|
|
6052
|
+
],
|
|
6053
|
+
[
|
|
6054
|
+
[rectangle.x + rectangle.width, rectangle.y],
|
|
6055
|
+
[rectangle.x, rectangle.y + rectangle.height]
|
|
6056
|
+
]
|
|
6057
|
+
];
|
|
6058
|
+
}
|
|
5926
6059
|
const DeletionEngine = {
|
|
5927
6060
|
draw(board, rectangle, options) {
|
|
5928
6061
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
5929
|
-
const
|
|
5930
|
-
|
|
5931
|
-
`, { ...options, fillStyle: 'solid', strokeWidth: 4 });
|
|
6062
|
+
const lines = getDeletionLines(rectangle);
|
|
6063
|
+
const shape = rs.path(lines.map(([from, to]) => `M${from[0]} ${from[1]} L${to[0]} ${to[1]}`).join(' '), { ...options, fillStyle: 'solid', strokeWidth: 4 });
|
|
5932
6064
|
setStrokeLinecap(shape, 'round');
|
|
5933
6065
|
return shape;
|
|
5934
6066
|
},
|
|
@@ -5940,7 +6072,18 @@ const DeletionEngine = {
|
|
|
5940
6072
|
return RectangleClient.getCornerPoints(rectangle);
|
|
5941
6073
|
},
|
|
5942
6074
|
getNearestPoint(rectangle, point) {
|
|
5943
|
-
|
|
6075
|
+
const lines = getDeletionLines(rectangle);
|
|
6076
|
+
let minDistance = Infinity;
|
|
6077
|
+
let nearestPoint = point;
|
|
6078
|
+
lines.forEach(line => {
|
|
6079
|
+
const currentPoint = getNearestPointBetweenPointAndSegment(point, line);
|
|
6080
|
+
const distance = distanceBetweenPointAndPoint(point[0], point[1], currentPoint[0], currentPoint[1]);
|
|
6081
|
+
if (distance < minDistance) {
|
|
6082
|
+
minDistance = distance;
|
|
6083
|
+
nearestPoint = currentPoint;
|
|
6084
|
+
}
|
|
6085
|
+
});
|
|
6086
|
+
return nearestPoint;
|
|
5944
6087
|
},
|
|
5945
6088
|
getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
|
|
5946
6089
|
const corners = RectangleEngine.getCornerPoints(rectangle);
|
|
@@ -6048,24 +6191,60 @@ const NoteEngine = {
|
|
|
6048
6191
|
}
|
|
6049
6192
|
};
|
|
6050
6193
|
|
|
6194
|
+
function generateAssemblyPath(rectangle) {
|
|
6195
|
+
const centerY = rectangle.y + rectangle.height / 2;
|
|
6196
|
+
const firstLineEndX = rectangle.x + rectangle.width * 0.3;
|
|
6197
|
+
const circleWidth = rectangle.width * 0.13;
|
|
6198
|
+
const circleHeight = rectangle.height * 0.285;
|
|
6199
|
+
const verticalX = firstLineEndX + circleWidth;
|
|
6200
|
+
const verticalRadius = rectangle.width * 0.233;
|
|
6201
|
+
return {
|
|
6202
|
+
startPoint: [rectangle.x, centerY],
|
|
6203
|
+
line1: [
|
|
6204
|
+
[rectangle.x, centerY],
|
|
6205
|
+
[firstLineEndX, centerY]
|
|
6206
|
+
],
|
|
6207
|
+
circleArcCommand: {
|
|
6208
|
+
rx: circleWidth,
|
|
6209
|
+
ry: circleHeight,
|
|
6210
|
+
xAxisRotation: 0,
|
|
6211
|
+
largeArcFlag: 1,
|
|
6212
|
+
sweepFlag: 1,
|
|
6213
|
+
endX: firstLineEndX,
|
|
6214
|
+
endY: centerY
|
|
6215
|
+
},
|
|
6216
|
+
verticalArcCommand: {
|
|
6217
|
+
rx: verticalRadius,
|
|
6218
|
+
ry: rectangle.height / 2,
|
|
6219
|
+
xAxisRotation: 0,
|
|
6220
|
+
largeArcFlag: 0,
|
|
6221
|
+
sweepFlag: 1,
|
|
6222
|
+
endX: verticalX,
|
|
6223
|
+
endY: rectangle.y + rectangle.height
|
|
6224
|
+
},
|
|
6225
|
+
line2: [
|
|
6226
|
+
[verticalX + verticalRadius, centerY],
|
|
6227
|
+
[rectangle.x + rectangle.width, centerY]
|
|
6228
|
+
]
|
|
6229
|
+
};
|
|
6230
|
+
}
|
|
6051
6231
|
const AssemblyEngine = {
|
|
6052
6232
|
draw(board, rectangle, options) {
|
|
6053
6233
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
6054
|
-
const
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
`, {
|
|
6234
|
+
const { startPoint, line1, circleArcCommand, verticalArcCommand, line2 } = generateAssemblyPath(rectangle);
|
|
6235
|
+
const pathData = [
|
|
6236
|
+
`M${startPoint[0]} ${startPoint[1]}`,
|
|
6237
|
+
`H${line1[1][0]}`,
|
|
6238
|
+
// 画完整的圆形:先画一个半圆,再画另一个半圆
|
|
6239
|
+
`A${circleArcCommand.rx} ${circleArcCommand.ry} ${circleArcCommand.xAxisRotation} ${circleArcCommand.largeArcFlag} ${circleArcCommand.sweepFlag} ${line1[1][0] + circleArcCommand.rx * 2} ${circleArcCommand.endY}`,
|
|
6240
|
+
`A${circleArcCommand.rx} ${circleArcCommand.ry} ${circleArcCommand.xAxisRotation} ${circleArcCommand.largeArcFlag} ${circleArcCommand.sweepFlag} ${circleArcCommand.endX} ${circleArcCommand.endY}`,
|
|
6241
|
+
// 垂直椭圆
|
|
6242
|
+
`M${verticalArcCommand.endX} ${rectangle.y}`,
|
|
6243
|
+
`A${verticalArcCommand.rx} ${verticalArcCommand.ry} ${verticalArcCommand.xAxisRotation} ${verticalArcCommand.largeArcFlag} ${verticalArcCommand.sweepFlag} ${verticalArcCommand.endX} ${verticalArcCommand.endY}`,
|
|
6244
|
+
// 最后一条线
|
|
6245
|
+
`M${line2[0][0]} ${line2[0][1]} H${line2[1][0]}`
|
|
6246
|
+
].join(' ');
|
|
6247
|
+
const shape = rs.path(pathData, {
|
|
6069
6248
|
...options,
|
|
6070
6249
|
fillStyle: 'solid'
|
|
6071
6250
|
});
|
|
@@ -6083,11 +6262,25 @@ const AssemblyEngine = {
|
|
|
6083
6262
|
return RectangleClient.getEdgeCenterPoints(rectangle);
|
|
6084
6263
|
},
|
|
6085
6264
|
getNearestPoint(rectangle, point) {
|
|
6086
|
-
const
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6265
|
+
const { line1, line2, circleArcCommand, verticalArcCommand } = generateAssemblyPath(rectangle);
|
|
6266
|
+
// 检查直线段
|
|
6267
|
+
const nearestPointForLines = getNearestPointBetweenPointAndSegments(point, [...line1, ...line2]);
|
|
6268
|
+
const distanceForLines = distanceBetweenPointAndPoint(...point, ...nearestPointForLines);
|
|
6269
|
+
// 检查中间圆形
|
|
6270
|
+
const circleCenter = [line1[1][0] + circleArcCommand.rx, line1[1][1]];
|
|
6271
|
+
const nearestPointForCircle = getNearestPointBetweenPointAndEllipse(point, circleCenter, circleArcCommand.rx, circleArcCommand.ry);
|
|
6272
|
+
const distanceForCircle = distanceBetweenPointAndPoint(...point, ...nearestPointForCircle);
|
|
6273
|
+
// 检查垂直椭圆(使用 getNearestPointBetweenPointAndArc 处理半圆弧)
|
|
6274
|
+
const arcStartPoint = [verticalArcCommand.endX, rectangle.y];
|
|
6275
|
+
const nearestPointForEllipse = getNearestPointBetweenPointAndArc(point, arcStartPoint, verticalArcCommand);
|
|
6276
|
+
const distanceForEllipse = distanceBetweenPointAndPoint(...point, ...nearestPointForEllipse);
|
|
6277
|
+
// 返回最近的点
|
|
6278
|
+
const minDistance = Math.min(distanceForLines, distanceForCircle, distanceForEllipse);
|
|
6279
|
+
if (minDistance === distanceForLines)
|
|
6280
|
+
return nearestPointForLines;
|
|
6281
|
+
if (minDistance === distanceForCircle)
|
|
6282
|
+
return nearestPointForCircle;
|
|
6283
|
+
return nearestPointForEllipse;
|
|
6091
6284
|
},
|
|
6092
6285
|
getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
|
|
6093
6286
|
const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
|
|
@@ -6101,13 +6294,38 @@ const AssemblyEngine = {
|
|
|
6101
6294
|
}
|
|
6102
6295
|
};
|
|
6103
6296
|
|
|
6297
|
+
function generateRequiredInterfacePath(rectangle) {
|
|
6298
|
+
const arcWidth = rectangle.width * 0.39;
|
|
6299
|
+
const arcHeight = rectangle.height / 2;
|
|
6300
|
+
return {
|
|
6301
|
+
startPoint: [rectangle.x, rectangle.y],
|
|
6302
|
+
leftArcCommand: {
|
|
6303
|
+
rx: arcWidth,
|
|
6304
|
+
ry: arcHeight,
|
|
6305
|
+
xAxisRotation: 0,
|
|
6306
|
+
largeArcFlag: 0,
|
|
6307
|
+
sweepFlag: 1,
|
|
6308
|
+
endX: rectangle.x,
|
|
6309
|
+
endY: rectangle.y + rectangle.height
|
|
6310
|
+
},
|
|
6311
|
+
line: {
|
|
6312
|
+
startX: rectangle.x + rectangle.width * 0.41,
|
|
6313
|
+
startY: rectangle.y + rectangle.height / 2,
|
|
6314
|
+
endX: rectangle.x + rectangle.width,
|
|
6315
|
+
endY: rectangle.y + rectangle.height / 2
|
|
6316
|
+
}
|
|
6317
|
+
};
|
|
6318
|
+
}
|
|
6104
6319
|
const RequiredInterfaceEngine = {
|
|
6105
6320
|
draw(board, rectangle, options) {
|
|
6106
6321
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
6107
|
-
const
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6322
|
+
const { startPoint, leftArcCommand, line } = generateRequiredInterfacePath(rectangle);
|
|
6323
|
+
const pathData = [
|
|
6324
|
+
`M${startPoint[0]} ${startPoint[1]}`,
|
|
6325
|
+
`A${leftArcCommand.rx} ${leftArcCommand.ry} ${leftArcCommand.xAxisRotation} ${leftArcCommand.largeArcFlag} ${leftArcCommand.sweepFlag} ${leftArcCommand.endX} ${leftArcCommand.endY}`,
|
|
6326
|
+
`M${line.startX} ${line.startY} H${line.endX}`
|
|
6327
|
+
].join(' ');
|
|
6328
|
+
const shape = rs.path(pathData, {
|
|
6111
6329
|
...options,
|
|
6112
6330
|
fillStyle: 'solid',
|
|
6113
6331
|
fill: 'transparent'
|
|
@@ -6123,7 +6341,26 @@ const RequiredInterfaceEngine = {
|
|
|
6123
6341
|
return RectangleClient.getCornerPoints(rectangle);
|
|
6124
6342
|
},
|
|
6125
6343
|
getNearestPoint(rectangle, point) {
|
|
6126
|
-
|
|
6344
|
+
const { startPoint, leftArcCommand, line } = generateRequiredInterfacePath(rectangle);
|
|
6345
|
+
let minDistance = Infinity;
|
|
6346
|
+
let nearestPoint = point;
|
|
6347
|
+
// 检查圆弧段
|
|
6348
|
+
const arcNearestPoint = getNearestPointBetweenPointAndArc(point, startPoint, leftArcCommand);
|
|
6349
|
+
const arcDistance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
|
|
6350
|
+
if (arcDistance < minDistance) {
|
|
6351
|
+
minDistance = arcDistance;
|
|
6352
|
+
nearestPoint = arcNearestPoint;
|
|
6353
|
+
}
|
|
6354
|
+
// 检查直线段
|
|
6355
|
+
const lineStart = [line.startX, line.startY];
|
|
6356
|
+
const lineEnd = [line.endX, line.endY];
|
|
6357
|
+
const lineNearestPoint = getNearestPointBetweenPointAndSegment(point, [lineStart, lineEnd]);
|
|
6358
|
+
const lineDistance = distanceBetweenPointAndPoint(point[0], point[1], lineNearestPoint[0], lineNearestPoint[1]);
|
|
6359
|
+
if (lineDistance < minDistance) {
|
|
6360
|
+
minDistance = lineDistance;
|
|
6361
|
+
nearestPoint = lineNearestPoint;
|
|
6362
|
+
}
|
|
6363
|
+
return nearestPoint;
|
|
6127
6364
|
},
|
|
6128
6365
|
getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
|
|
6129
6366
|
const corners = RectangleEngine.getCornerPoints(rectangle);
|
|
@@ -6136,25 +6373,52 @@ const RequiredInterfaceEngine = {
|
|
|
6136
6373
|
};
|
|
6137
6374
|
|
|
6138
6375
|
const percentage = 0.54;
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
const
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6376
|
+
function generateProvidedInterfacePath(rectangle) {
|
|
6377
|
+
const centerY = rectangle.y + rectangle.height / 2;
|
|
6378
|
+
const rx = (rectangle.width * (1 - percentage)) / 2;
|
|
6379
|
+
const ry = rectangle.height / 2;
|
|
6380
|
+
const startPoint = [rectangle.x, centerY];
|
|
6381
|
+
const lineEndX = rectangle.x + rectangle.width * percentage;
|
|
6382
|
+
return {
|
|
6383
|
+
startPoint,
|
|
6384
|
+
line: {
|
|
6385
|
+
startX: startPoint[0],
|
|
6386
|
+
startY: centerY,
|
|
6387
|
+
endX: lineEndX,
|
|
6388
|
+
endY: centerY
|
|
6389
|
+
},
|
|
6390
|
+
arcCommands: [
|
|
6391
|
+
{
|
|
6392
|
+
rx,
|
|
6393
|
+
ry,
|
|
6394
|
+
xAxisRotation: 0,
|
|
6395
|
+
largeArcFlag: 1,
|
|
6396
|
+
sweepFlag: 1,
|
|
6397
|
+
endX: rectangle.x + rectangle.width,
|
|
6398
|
+
endY: centerY
|
|
6399
|
+
},
|
|
6400
|
+
{
|
|
6401
|
+
rx,
|
|
6402
|
+
ry,
|
|
6403
|
+
xAxisRotation: 0,
|
|
6404
|
+
largeArcFlag: 1,
|
|
6405
|
+
sweepFlag: 1,
|
|
6406
|
+
endX: lineEndX,
|
|
6407
|
+
endY: centerY
|
|
6408
|
+
}
|
|
6409
|
+
]
|
|
6410
|
+
};
|
|
6411
|
+
}
|
|
6149
6412
|
const ProvidedInterfaceEngine = {
|
|
6150
6413
|
draw(board, rectangle, options) {
|
|
6151
6414
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
6152
|
-
const startPoint =
|
|
6153
|
-
const
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6415
|
+
const { startPoint, line, arcCommands } = generateProvidedInterfacePath(rectangle);
|
|
6416
|
+
const pathData = [
|
|
6417
|
+
`M${startPoint[0]} ${startPoint[1]}`,
|
|
6418
|
+
`H${line.endX}`,
|
|
6419
|
+
...arcCommands.map((command) => `A${command.rx} ${command.ry} ${command.xAxisRotation} ${command.largeArcFlag} ${command.sweepFlag} ${command.endX} ${command.endY}`)
|
|
6420
|
+
].join(' ');
|
|
6421
|
+
const shape = rs.path(pathData, {
|
|
6158
6422
|
...options,
|
|
6159
6423
|
fillStyle: 'solid'
|
|
6160
6424
|
});
|
|
@@ -6172,17 +6436,17 @@ const ProvidedInterfaceEngine = {
|
|
|
6172
6436
|
return RectangleClient.getEdgeCenterPoints(rectangle);
|
|
6173
6437
|
},
|
|
6174
6438
|
getNearestPoint(rectangle, point) {
|
|
6175
|
-
const startPoint =
|
|
6176
|
-
|
|
6177
|
-
const
|
|
6439
|
+
const { startPoint, line, arcCommands } = generateProvidedInterfacePath(rectangle);
|
|
6440
|
+
// 检查直线段
|
|
6441
|
+
const lineStart = [line.startX, line.startY];
|
|
6442
|
+
const lineEnd = [line.endX, line.endY];
|
|
6443
|
+
const nearestPointForLine = getNearestPointBetweenPointAndSegments(point, [lineStart, lineEnd]);
|
|
6178
6444
|
const distanceForLine = distanceBetweenPointAndPoint(...point, ...nearestPointForLine);
|
|
6179
|
-
|
|
6180
|
-
const
|
|
6445
|
+
// 检查圆弧段
|
|
6446
|
+
const arcCenter = [rectangle.x + (3 * rectangle.width) / 4, line.startY];
|
|
6447
|
+
const nearestPointForEllipse = getNearestPointBetweenPointAndEllipse(point, arcCenter, arcCommands[0].rx, arcCommands[0].ry);
|
|
6181
6448
|
const distanceForEllipse = distanceBetweenPointAndPoint(...point, ...nearestPointForEllipse);
|
|
6182
|
-
|
|
6183
|
-
return nearestPointForLine;
|
|
6184
|
-
}
|
|
6185
|
-
return nearestPointForEllipse;
|
|
6449
|
+
return distanceForLine < distanceForEllipse ? nearestPointForLine : nearestPointForEllipse;
|
|
6186
6450
|
},
|
|
6187
6451
|
getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
|
|
6188
6452
|
const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
|
|
@@ -6198,30 +6462,84 @@ const ProvidedInterfaceEngine = {
|
|
|
6198
6462
|
}
|
|
6199
6463
|
};
|
|
6200
6464
|
|
|
6465
|
+
function generateComponentPath(rectangle) {
|
|
6466
|
+
const mainLineX = rectangle.x + 12;
|
|
6467
|
+
const boxWidth = rectangle.width > 70 ? 24 : rectangle.width * 0.2;
|
|
6468
|
+
const boxHeight = rectangle.height - 28 - rectangle.height * 0.35 > 1 ? 14 : rectangle.height * 0.175;
|
|
6469
|
+
const topBoxY = rectangle.y + rectangle.height * 0.175;
|
|
6470
|
+
const bottomBoxY = rectangle.y + rectangle.height - rectangle.height * 0.175 - boxHeight;
|
|
6471
|
+
return {
|
|
6472
|
+
boxSize: {
|
|
6473
|
+
width: boxWidth,
|
|
6474
|
+
height: boxHeight
|
|
6475
|
+
},
|
|
6476
|
+
points: {
|
|
6477
|
+
mainStart: [mainLineX, rectangle.y],
|
|
6478
|
+
topBoxStart: [mainLineX, topBoxY],
|
|
6479
|
+
topBoxEnd: [mainLineX, topBoxY + boxHeight],
|
|
6480
|
+
bottomBoxStart: [mainLineX, bottomBoxY],
|
|
6481
|
+
bottomBoxEnd: [mainLineX, bottomBoxY + boxHeight],
|
|
6482
|
+
mainEnd: [mainLineX, rectangle.y + rectangle.height],
|
|
6483
|
+
rightTop: [rectangle.x + rectangle.width, rectangle.y],
|
|
6484
|
+
rightBottom: [rectangle.x + rectangle.width, rectangle.y + rectangle.height]
|
|
6485
|
+
}
|
|
6486
|
+
};
|
|
6487
|
+
}
|
|
6201
6488
|
const ComponentEngine = {
|
|
6202
6489
|
draw(board, rectangle, options) {
|
|
6203
6490
|
const rs = PlaitBoard.getRoughSVG(board);
|
|
6204
|
-
const boxSize =
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
M${
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6491
|
+
const { boxSize, points } = generateComponentPath(rectangle);
|
|
6492
|
+
const pathData = [
|
|
6493
|
+
// 主矩形轮廓
|
|
6494
|
+
`M${points.mainStart[0]} ${points.mainStart[1]}`,
|
|
6495
|
+
`H${points.rightTop[0]}`,
|
|
6496
|
+
`V${points.rightBottom[1]}`,
|
|
6497
|
+
`H${points.mainEnd[0]}`,
|
|
6498
|
+
// 上方小矩形
|
|
6499
|
+
`M${points.topBoxStart[0]} ${points.topBoxStart[1]}`,
|
|
6500
|
+
`h${boxSize.width / 2} v${boxSize.height} h${-boxSize.width} v${-boxSize.height} h${boxSize.width / 2}`,
|
|
6501
|
+
// 下方小矩形
|
|
6502
|
+
`M${points.bottomBoxStart[0]} ${points.bottomBoxStart[1]}`,
|
|
6503
|
+
`h${boxSize.width / 2} v${boxSize.height} h${-boxSize.width} v${-boxSize.height} h${boxSize.width / 2}`,
|
|
6504
|
+
// 连接线
|
|
6505
|
+
`M${points.mainStart[0]} ${points.mainStart[1]}`,
|
|
6506
|
+
`V${points.topBoxStart[1]}`,
|
|
6507
|
+
`M${points.topBoxEnd[0]} ${points.topBoxEnd[1]}`,
|
|
6508
|
+
`V${points.bottomBoxStart[1]}`,
|
|
6509
|
+
`M${points.bottomBoxEnd[0]} ${points.bottomBoxEnd[1]}`,
|
|
6510
|
+
`V${points.mainEnd[1]}`
|
|
6511
|
+
].join(' ');
|
|
6512
|
+
const shape = rs.path(pathData, { ...options, fillStyle: 'solid' });
|
|
6222
6513
|
setStrokeLinecap(shape, 'round');
|
|
6223
6514
|
return shape;
|
|
6224
6515
|
},
|
|
6516
|
+
getNearestPoint(rectangle, point) {
|
|
6517
|
+
const { boxSize, points } = generateComponentPath(rectangle);
|
|
6518
|
+
const segments = [
|
|
6519
|
+
// 主矩形轮廓
|
|
6520
|
+
[points.mainStart, [points.rightTop[0], points.mainStart[1]]],
|
|
6521
|
+
[[points.rightTop[0], points.mainStart[1]], points.rightBottom],
|
|
6522
|
+
[points.rightBottom, [points.mainEnd[0], points.rightBottom[1]]],
|
|
6523
|
+
[[points.mainEnd[0], points.rightBottom[1]], points.mainStart],
|
|
6524
|
+
// 上方小矩形
|
|
6525
|
+
[points.topBoxStart, [points.topBoxStart[0] + boxSize.width / 2, points.topBoxStart[1]]],
|
|
6526
|
+
[[points.topBoxStart[0] + boxSize.width / 2, points.topBoxStart[1]], [points.topBoxStart[0] + boxSize.width / 2, points.topBoxEnd[1]]],
|
|
6527
|
+
[[points.topBoxStart[0] + boxSize.width / 2, points.topBoxEnd[1]], [points.topBoxStart[0] - boxSize.width / 2, points.topBoxEnd[1]]],
|
|
6528
|
+
[[points.topBoxStart[0] - boxSize.width / 2, points.topBoxEnd[1]], [points.topBoxStart[0] - boxSize.width / 2, points.topBoxStart[1]]],
|
|
6529
|
+
[[points.topBoxStart[0] - boxSize.width / 2, points.topBoxStart[1]], points.topBoxStart],
|
|
6530
|
+
// 下方小矩形
|
|
6531
|
+
[points.bottomBoxStart, [points.bottomBoxStart[0] + boxSize.width / 2, points.bottomBoxStart[1]]],
|
|
6532
|
+
[[points.bottomBoxStart[0] + boxSize.width / 2, points.bottomBoxStart[1]], [points.bottomBoxStart[0] + boxSize.width / 2, points.bottomBoxEnd[1]]],
|
|
6533
|
+
[[points.bottomBoxStart[0] + boxSize.width / 2, points.bottomBoxEnd[1]], [points.bottomBoxStart[0] - boxSize.width / 2, points.bottomBoxEnd[1]]],
|
|
6534
|
+
[[points.bottomBoxStart[0] - boxSize.width / 2, points.bottomBoxEnd[1]], [points.bottomBoxStart[0] - boxSize.width / 2, points.bottomBoxStart[1]]],
|
|
6535
|
+
[[points.bottomBoxStart[0] - boxSize.width / 2, points.bottomBoxStart[1]], points.bottomBoxStart],
|
|
6536
|
+
// 连接线
|
|
6537
|
+
[points.mainStart, points.topBoxStart],
|
|
6538
|
+
[points.topBoxEnd, points.bottomBoxStart],
|
|
6539
|
+
[points.bottomBoxEnd, points.mainEnd]
|
|
6540
|
+
];
|
|
6541
|
+
return getNearestPointBetweenPointAndDiscreteSegments(point, segments);
|
|
6542
|
+
},
|
|
6225
6543
|
isInsidePoint(rectangle, point) {
|
|
6226
6544
|
const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
|
|
6227
6545
|
return RectangleClient.isHit(rectangle, rangeRectangle);
|
|
@@ -6229,26 +6547,18 @@ const ComponentEngine = {
|
|
|
6229
6547
|
getCornerPoints(rectangle) {
|
|
6230
6548
|
return RectangleClient.getCornerPoints(rectangle);
|
|
6231
6549
|
},
|
|
6232
|
-
getNearestPoint(rectangle, point) {
|
|
6233
|
-
let nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
|
|
6234
|
-
if (nearestPoint[1] === rectangle.y + rectangle.height / 2) {
|
|
6235
|
-
nearestPoint = getNearestPointBetweenPointAndSegments(point, [
|
|
6236
|
-
[rectangle.x + 12, rectangle.y + rectangle.height * 0.175 + 14],
|
|
6237
|
-
[rectangle.x + 12, rectangle.y + rectangle.height - rectangle.height * 0.175 - 14]
|
|
6238
|
-
], false);
|
|
6239
|
-
}
|
|
6240
|
-
return nearestPoint;
|
|
6241
|
-
},
|
|
6242
6550
|
getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
|
|
6551
|
+
const { points } = generateComponentPath(rectangle);
|
|
6243
6552
|
const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
|
|
6244
|
-
return getUnitVectorByPointAndPoint(
|
|
6553
|
+
return getUnitVectorByPointAndPoint(points.mainStart, connectionPoint);
|
|
6245
6554
|
},
|
|
6246
6555
|
getConnectorPoints(rectangle) {
|
|
6556
|
+
const { points } = generateComponentPath(rectangle);
|
|
6247
6557
|
return [
|
|
6248
6558
|
[rectangle.x + rectangle.width / 2, rectangle.y],
|
|
6249
6559
|
[rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
|
|
6250
6560
|
[rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
|
|
6251
|
-
[
|
|
6561
|
+
[points.mainStart[0], rectangle.y + rectangle.height / 2]
|
|
6252
6562
|
];
|
|
6253
6563
|
},
|
|
6254
6564
|
getTextRectangle(element) {
|
|
@@ -8082,7 +8392,7 @@ const withArrowLineTextMove = (board) => {
|
|
|
8082
8392
|
if (element) {
|
|
8083
8393
|
const movingPoint = resizeState.endPoint;
|
|
8084
8394
|
const points = getArrowLinePoints(board, element);
|
|
8085
|
-
const distance = distanceBetweenPointAndSegments(
|
|
8395
|
+
const distance = distanceBetweenPointAndSegments(movingPoint, points);
|
|
8086
8396
|
if (distance <= movableBuffer) {
|
|
8087
8397
|
const point = getNearestPointBetweenPointAndSegments(movingPoint, points, false);
|
|
8088
8398
|
const position = getRatioByPoint(points, point);
|
|
@@ -8519,7 +8829,8 @@ const withTable = (board) => {
|
|
|
8519
8829
|
tableBoard.isRectangleHit = (element, selection) => {
|
|
8520
8830
|
if (PlaitDrawElement.isElementByTable(element)) {
|
|
8521
8831
|
const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
|
|
8522
|
-
|
|
8832
|
+
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
8833
|
+
return isLineHitRectangle(RectangleClient.getCornerPoints(client), rangeRectangle);
|
|
8523
8834
|
}
|
|
8524
8835
|
return isRectangleHit(element, selection);
|
|
8525
8836
|
};
|