@plait/draw 0.52.0 → 0.54.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/constants/geometry.d.ts +3 -1
- package/esm2022/constants/geometry.mjs +4 -2
- package/esm2022/generators/line-auto-complete.generator.mjs +1 -1
- package/esm2022/interfaces/index.mjs +2 -2
- package/esm2022/interfaces/line.mjs +20 -8
- package/esm2022/line.component.mjs +5 -17
- package/esm2022/plugins/with-draw-fragment.mjs +1 -1
- package/esm2022/plugins/with-draw-hotkey.mjs +9 -7
- package/esm2022/plugins/with-draw-resize.mjs +114 -13
- package/esm2022/plugins/with-draw.mjs +5 -12
- package/esm2022/plugins/with-geometry-resize.mjs +8 -5
- package/esm2022/plugins/with-line-auto-complete-reaction.mjs +7 -4
- package/esm2022/plugins/with-line-auto-complete.mjs +17 -16
- package/esm2022/plugins/with-line-bound-reaction.mjs +20 -19
- package/esm2022/plugins/with-line-create.mjs +4 -4
- package/esm2022/plugins/with-line-resize.mjs +10 -11
- package/esm2022/transforms/line.mjs +4 -4
- package/esm2022/utils/geometry.mjs +31 -22
- package/esm2022/utils/hit.mjs +29 -27
- package/esm2022/utils/line/elbow.mjs +22 -9
- package/esm2022/utils/line/line-basic.mjs +21 -25
- package/esm2022/utils/line/line-common.mjs +27 -15
- package/esm2022/utils/line/line-resize.mjs +7 -11
- package/esm2022/utils/position/geometry.mjs +52 -20
- package/esm2022/utils/resize-snap.mjs +361 -0
- package/esm2022/utils/shape.mjs +2 -2
- package/fesm2022/plait-draw.mjs +556 -437
- package/fesm2022/plait-draw.mjs.map +1 -1
- package/generators/line-auto-complete.generator.d.ts +3 -3
- package/interfaces/index.d.ts +2 -2
- package/package.json +1 -1
- package/plugins/with-draw-fragment.d.ts +2 -2
- package/plugins/with-draw-resize.d.ts +12 -0
- package/utils/geometry.d.ts +7 -4
- package/utils/hit.d.ts +3 -1
- package/utils/line/elbow.d.ts +6 -13
- package/utils/line/line-basic.d.ts +4 -4
- package/utils/line/line-common.d.ts +3 -13
- package/utils/position/geometry.d.ts +12 -5
- package/utils/resize-snap.d.ts +49 -0
- package/utils/shape.d.ts +2 -2
- package/esm2022/generators/group.generator.mjs +0 -20
- package/esm2022/group.component.mjs +0 -47
- package/esm2022/utils/resize-align-reaction.mjs +0 -316
- package/esm2022/utils/resize-align.mjs +0 -37
- package/generators/group.generator.d.ts +0 -6
- package/group.component.d.ts +0 -17
- package/utils/resize-align-reaction.d.ts +0 -42
- package/utils/resize-align.d.ts +0 -8
package/fesm2022/plait-draw.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ACTIVE_STROKE_WIDTH, ThemeColorMode, Point, RectangleClient, getElementById, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate,
|
|
2
|
-
import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator,
|
|
1
|
+
import { ACTIVE_STROKE_WIDTH, ThemeColorMode, createDebugGenerator, Point, RectangleClient, getElementById, rotatePointsByElement, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, rotateAntiPointsByElement, rotatePoints, depthFirstRecursion, PlaitBoard, getIsRecursionFunc, idCreator, catmullRomFitting, findElements, createMask, createRect, getSelectedElements, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, Direction, hasValidAngle, Path, PlaitNode, toViewBoxPoint, toHostPoint, isSelectionMoving, RgbaToHEX, PlaitElement, getHitElementByPoint, preventTouchMove, createClipboardContext, WritableClipboardType, addClipboardContext, getSelectionAngle, getRectangleByAngle, getRectangleByElements, rotatedDataPoints, isAxisChangedByAngle, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER } from '@plait/core';
|
|
2
|
+
import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, RESIZE_HANDLE_DIAMETER, getPointOnPolyline, TRANSPARENT, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, getMemorizedLatest, memorizeLatest, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getDirectionByVector, getOppositeDirection, getDirectionFactor, rotateVector, getDirectionByPointOfRectangle, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, normalizeShapePoints, getFirstTextEditor, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, resetPointsAfterResize, getDirectionFactorByDirectionComponent, isCornerHandle, getFirstTextManage, withResize, drawHandle, getIndexByResizeHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, isResizingByCondition, getRatioByPoint, ImageGenerator, ResizeHandle } from '@plait/common';
|
|
3
3
|
import { Alignment, buildText, DEFAULT_FONT_SIZE, getTextSize, AlignEditor, TextManage } from '@plait/text';
|
|
4
4
|
import { pointsOnBezierCurves } from 'points-on-curve';
|
|
5
5
|
import * as i0 from '@angular/core';
|
|
@@ -111,7 +111,9 @@ const DefaultFlowchartPropertyMap = {
|
|
|
111
111
|
[FlowchartSymbols.delay]: DefaultFlowchartProperty,
|
|
112
112
|
[FlowchartSymbols.storedData]: DefaultFlowchartProperty
|
|
113
113
|
};
|
|
114
|
-
const
|
|
114
|
+
const LINE_HIT_GEOMETRY_BUFFER = 10;
|
|
115
|
+
const LINE_SNAPPING_BUFFER = 6;
|
|
116
|
+
const LINE_SNAPPING_CONNECTOR_BUFFER = 8;
|
|
115
117
|
|
|
116
118
|
const getGeometryPointers = () => {
|
|
117
119
|
return [...Object.keys(BasicShapes), ...Object.keys(FlowchartSymbols)];
|
|
@@ -166,6 +168,8 @@ const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
|
|
|
166
168
|
const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
|
|
167
169
|
const LINE_ALIGN_TOLERANCE = 3;
|
|
168
170
|
|
|
171
|
+
const debugKey$3 = 'debug:plait:line-mirror';
|
|
172
|
+
const debugGenerator$3 = createDebugGenerator(debugKey$3);
|
|
169
173
|
const alignPoints = (basePoint, movingPoint) => {
|
|
170
174
|
const newPoint = [...movingPoint];
|
|
171
175
|
if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
|
|
@@ -302,7 +306,7 @@ function getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRender
|
|
|
302
306
|
if (midDataPoints.length > 0) {
|
|
303
307
|
const handleRefPair = getLineHandleRefPair(board, element);
|
|
304
308
|
const params = getElbowLineRouteOptions(board, element, handleRefPair);
|
|
305
|
-
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params));
|
|
309
|
+
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
|
|
306
310
|
const nextKeyPoints = simplifyOrthogonalPoints(keyPoints.slice(1, keyPoints.length - 1));
|
|
307
311
|
const nextDataPoints = [nextRenderPoints[0], ...midDataPoints, nextRenderPoints[nextRenderPoints.length - 1]];
|
|
308
312
|
const mirrorDataPoints = getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params);
|
|
@@ -429,6 +433,7 @@ function findOrthogonalParallelSegments(segment, keyPoints) {
|
|
|
429
433
|
return parallelSegments;
|
|
430
434
|
}
|
|
431
435
|
function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, targetRectangle) {
|
|
436
|
+
debugGenerator$3.isDebug() && debugGenerator$3.clear();
|
|
432
437
|
const mirrorSegments = [];
|
|
433
438
|
for (let index = 0; index < parallelSegments.length; index++) {
|
|
434
439
|
const parallelPath = parallelSegments[index];
|
|
@@ -442,14 +447,7 @@ function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, t
|
|
|
442
447
|
const isValid = !RectangleClient.isHit(fakeRectangle, sourceRectangle) && !RectangleClient.isHit(fakeRectangle, targetRectangle);
|
|
443
448
|
if (isValid) {
|
|
444
449
|
mirrorSegments.push([startPoint, endPoint]);
|
|
445
|
-
|
|
446
|
-
// fakeRectangle.x,
|
|
447
|
-
// fakeRectangle.y,
|
|
448
|
-
// fakeRectangle.width,
|
|
449
|
-
// fakeRectangle.height,
|
|
450
|
-
// { stroke: 'blue' }
|
|
451
|
-
// );
|
|
452
|
-
// PlaitBoard.getElementActiveHost(board).append(fakeRectangleG);
|
|
450
|
+
debugGenerator$3.isDebug() && debugGenerator$3.drawPolygon(board, RectangleClient.getCornerPoints(fakeRectangle));
|
|
453
451
|
}
|
|
454
452
|
}
|
|
455
453
|
return mirrorSegments;
|
|
@@ -475,15 +473,20 @@ const hasIllegalElbowPoint = (midDataPoints) => {
|
|
|
475
473
|
});
|
|
476
474
|
};
|
|
477
475
|
|
|
476
|
+
const isSelfLoop = (element) => {
|
|
477
|
+
return element.source.boundId && element.source.boundId === element.target.boundId;
|
|
478
|
+
};
|
|
479
|
+
const isUseDefaultOrthogonalRoute = (element, options) => {
|
|
480
|
+
return isSourceAndTargetIntersect(options) && !isSelfLoop(element);
|
|
481
|
+
};
|
|
478
482
|
const getElbowPoints = (board, element) => {
|
|
479
483
|
const handleRefPair = getLineHandleRefPair(board, element);
|
|
480
484
|
const params = getElbowLineRouteOptions(board, element, handleRefPair);
|
|
481
485
|
// console.log(params, 'params');
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
return simplifyOrthogonalPoints(getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, 0));
|
|
486
|
+
if (isUseDefaultOrthogonalRoute(element, params)) {
|
|
487
|
+
return simplifyOrthogonalPoints(getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, DEFAULT_ROUTE_MARGIN));
|
|
485
488
|
}
|
|
486
|
-
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params));
|
|
489
|
+
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
|
|
487
490
|
const nextKeyPoints = keyPoints.slice(1, keyPoints.length - 1);
|
|
488
491
|
if (element.points.length === 2) {
|
|
489
492
|
return simplifyOrthogonalPoints(keyPoints);
|
|
@@ -549,8 +552,16 @@ const getSourceAndTargetRectangle = (board, element, handleRefPair) => {
|
|
|
549
552
|
const target = handleRefPair.target;
|
|
550
553
|
targetElement = createFakeElement(target.point, target.vector);
|
|
551
554
|
}
|
|
552
|
-
|
|
553
|
-
const
|
|
555
|
+
let sourceRectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
|
|
556
|
+
const rotatedSourceCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(sourceRectangle), sourceElement) ||
|
|
557
|
+
RectangleClient.getCornerPoints(sourceRectangle);
|
|
558
|
+
sourceRectangle = RectangleClient.getRectangleByPoints(rotatedSourceCornerPoints);
|
|
559
|
+
sourceRectangle = RectangleClient.inflate(sourceRectangle, getStrokeWidthByElement(sourceElement) * 2);
|
|
560
|
+
let targetRectangle = RectangleClient.getRectangleByPoints(targetElement.points);
|
|
561
|
+
const rotatedTargetCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(targetRectangle), targetElement) ||
|
|
562
|
+
RectangleClient.getCornerPoints(targetRectangle);
|
|
563
|
+
targetRectangle = RectangleClient.getRectangleByPoints(rotatedTargetCornerPoints);
|
|
564
|
+
targetRectangle = RectangleClient.inflate(targetRectangle, getStrokeWidthByElement(targetElement) * 2);
|
|
554
565
|
return {
|
|
555
566
|
sourceRectangle,
|
|
556
567
|
targetRectangle
|
|
@@ -688,7 +699,7 @@ const drawHollowTriangleArrow = (source, target, options) => {
|
|
|
688
699
|
return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
|
|
689
700
|
};
|
|
690
701
|
|
|
691
|
-
const
|
|
702
|
+
const getElementShape = (value) => {
|
|
692
703
|
if (PlaitDrawElement.isImage(value)) {
|
|
693
704
|
return BasicShapes.rectangle;
|
|
694
705
|
}
|
|
@@ -706,27 +717,238 @@ class LineShapeGenerator extends Generator {
|
|
|
706
717
|
}
|
|
707
718
|
}
|
|
708
719
|
|
|
709
|
-
|
|
720
|
+
var LineResizeHandle;
|
|
721
|
+
(function (LineResizeHandle) {
|
|
722
|
+
LineResizeHandle["source"] = "source";
|
|
723
|
+
LineResizeHandle["target"] = "target";
|
|
724
|
+
LineResizeHandle["addHandle"] = "addHandle";
|
|
725
|
+
})(LineResizeHandle || (LineResizeHandle = {}));
|
|
726
|
+
const getHitLineResizeHandleRef = (board, element, point) => {
|
|
727
|
+
let dataPoints = PlaitLine.getPoints(board, element);
|
|
728
|
+
const index = getHitPointIndex(dataPoints, point);
|
|
729
|
+
if (index !== -1) {
|
|
730
|
+
const handleIndex = index;
|
|
731
|
+
if (index === 0) {
|
|
732
|
+
return { handle: LineResizeHandle.source, handleIndex };
|
|
733
|
+
}
|
|
734
|
+
if (index === dataPoints.length - 1) {
|
|
735
|
+
return { handle: LineResizeHandle.target, handleIndex };
|
|
736
|
+
}
|
|
737
|
+
// elbow line, data points only verify source connection point and target connection point
|
|
738
|
+
if (element.shape !== LineShape.elbow) {
|
|
739
|
+
return { handleIndex };
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const middlePoints = getMiddlePoints(board, element);
|
|
743
|
+
const indexOfMiddlePoints = getHitPointIndex(middlePoints, point);
|
|
744
|
+
if (indexOfMiddlePoints !== -1) {
|
|
745
|
+
return {
|
|
746
|
+
handle: LineResizeHandle.addHandle,
|
|
747
|
+
handleIndex: indexOfMiddlePoints
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
return undefined;
|
|
751
|
+
};
|
|
752
|
+
function getHitPointIndex(points, movingPoint) {
|
|
753
|
+
const rectangles = points.map(point => {
|
|
754
|
+
return {
|
|
755
|
+
x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
|
|
756
|
+
y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
|
|
757
|
+
width: RESIZE_HANDLE_DIAMETER,
|
|
758
|
+
height: RESIZE_HANDLE_DIAMETER
|
|
759
|
+
};
|
|
760
|
+
});
|
|
761
|
+
const rectangle = rectangles.find(rectangle => {
|
|
762
|
+
return RectangleClient.isHit(RectangleClient.getRectangleByPoints([movingPoint, movingPoint]), rectangle);
|
|
763
|
+
});
|
|
764
|
+
return rectangle ? rectangles.indexOf(rectangle) : -1;
|
|
765
|
+
}
|
|
766
|
+
const getHitLineTextIndex = (board, element, point) => {
|
|
767
|
+
const texts = element.texts;
|
|
768
|
+
if (!texts.length)
|
|
769
|
+
return -1;
|
|
770
|
+
const points = getLinePoints(board, element);
|
|
771
|
+
return texts.findIndex(text => {
|
|
772
|
+
const center = getPointOnPolyline(points, text.position);
|
|
773
|
+
const rectangle = {
|
|
774
|
+
x: center[0] - text.width / 2,
|
|
775
|
+
y: center[1] - text.height / 2,
|
|
776
|
+
width: text.width,
|
|
777
|
+
height: text.height
|
|
778
|
+
};
|
|
779
|
+
return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
|
|
780
|
+
});
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
const isTextExceedingBounds = (geometry) => {
|
|
784
|
+
const client = RectangleClient.getRectangleByPoints(geometry.points);
|
|
785
|
+
if (geometry.textHeight > client.height) {
|
|
786
|
+
return true;
|
|
787
|
+
}
|
|
788
|
+
return false;
|
|
789
|
+
};
|
|
790
|
+
const isHitLineText = (board, element, point) => {
|
|
791
|
+
return getHitLineTextIndex(board, element, point) !== -1;
|
|
792
|
+
};
|
|
793
|
+
const isHitPolyLine = (pathPoints, point) => {
|
|
794
|
+
const distance = distanceBetweenPointAndSegments(pathPoints, point);
|
|
795
|
+
return distance <= HIT_DISTANCE_BUFFER;
|
|
796
|
+
};
|
|
797
|
+
const isHitLine = (board, element, point) => {
|
|
798
|
+
const points = getLinePoints(board, element);
|
|
799
|
+
const isHitText = isHitLineText(board, element, point);
|
|
800
|
+
return isHitText || isHitPolyLine(points, point);
|
|
801
|
+
};
|
|
802
|
+
const isRectangleHitDrawElement = (board, element, selection) => {
|
|
803
|
+
const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
|
|
804
|
+
if (PlaitDrawElement.isGeometry(element)) {
|
|
805
|
+
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
806
|
+
let rotatedCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(client), element) || RectangleClient.getCornerPoints(client);
|
|
807
|
+
if (isTextExceedingBounds(element)) {
|
|
808
|
+
const textClient = getTextRectangle(element);
|
|
809
|
+
rotatedCornerPoints =
|
|
810
|
+
rotatePointsByElement(RectangleClient.getCornerPoints(textClient), element) || RectangleClient.getCornerPoints(textClient);
|
|
811
|
+
}
|
|
812
|
+
return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
|
|
813
|
+
}
|
|
814
|
+
if (PlaitDrawElement.isImage(element)) {
|
|
815
|
+
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
816
|
+
const rotatedCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(client), element) || RectangleClient.getCornerPoints(client);
|
|
817
|
+
return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
|
|
818
|
+
}
|
|
819
|
+
if (PlaitDrawElement.isLine(element)) {
|
|
820
|
+
const points = getLinePoints(board, element);
|
|
821
|
+
return isPolylineHitRectangle(points, rangeRectangle);
|
|
822
|
+
}
|
|
823
|
+
return null;
|
|
824
|
+
};
|
|
825
|
+
const isHitDrawElement = (board, element, point) => {
|
|
826
|
+
const rectangle = board.getRectangle(element);
|
|
827
|
+
point = rotateAntiPointsByElement(point, element) || point;
|
|
828
|
+
if (PlaitDrawElement.isGeometry(element)) {
|
|
829
|
+
const fill = getFillByElement(board, element);
|
|
830
|
+
if (isHitEdgeOfShape(board, element, point, HIT_DISTANCE_BUFFER)) {
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
const engine = getEngine(getElementShape(element));
|
|
834
|
+
// when shape equals text, fill is not allowed
|
|
835
|
+
if (fill !== DefaultGeometryStyle.fill && fill !== TRANSPARENT && !PlaitDrawElement.isText(element)) {
|
|
836
|
+
const isHitInside = engine.isInsidePoint(rectangle, point);
|
|
837
|
+
if (isHitInside) {
|
|
838
|
+
return isHitInside;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
// if shape equals text, only check text rectangle
|
|
843
|
+
if (PlaitDrawElement.isText(element)) {
|
|
844
|
+
const textClient = getTextRectangle(element);
|
|
845
|
+
let isHitText = RectangleClient.isPointInRectangle(textClient, point);
|
|
846
|
+
return isHitText;
|
|
847
|
+
}
|
|
848
|
+
// check textRectangle of element
|
|
849
|
+
const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
|
|
850
|
+
const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
|
|
851
|
+
if (isHitTextRectangle) {
|
|
852
|
+
return isHitTextRectangle;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (PlaitDrawElement.isImage(element)) {
|
|
857
|
+
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
858
|
+
return RectangleClient.isPointInRectangle(client, point);
|
|
859
|
+
}
|
|
860
|
+
if (PlaitDrawElement.isLine(element)) {
|
|
861
|
+
return isHitLine(board, element, point);
|
|
862
|
+
}
|
|
863
|
+
return null;
|
|
864
|
+
};
|
|
865
|
+
const isHitEdgeOfShape = (board, element, point, hitDistanceBuffer) => {
|
|
866
|
+
const nearestPoint = getNearestPoint(element, point);
|
|
867
|
+
const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
|
|
868
|
+
return distance <= hitDistanceBuffer;
|
|
869
|
+
};
|
|
870
|
+
const isInsideOfShape = (board, element, point, hitDistanceBuffer) => {
|
|
871
|
+
const client = RectangleClient.inflate(RectangleClient.getRectangleByPoints(element.points), hitDistanceBuffer);
|
|
872
|
+
return getEngine(getElementShape(element)).isInsidePoint(client, point);
|
|
873
|
+
};
|
|
874
|
+
const isHitElementInside = (board, element, point) => {
|
|
875
|
+
const rectangle = board.getRectangle(element);
|
|
876
|
+
point = rotateAntiPointsByElement(point, element) || point;
|
|
877
|
+
if (PlaitDrawElement.isGeometry(element)) {
|
|
878
|
+
const engine = getEngine(getElementShape(element));
|
|
879
|
+
const isHitInside = engine.isInsidePoint(rectangle, point);
|
|
880
|
+
if (isHitInside) {
|
|
881
|
+
return isHitInside;
|
|
882
|
+
}
|
|
883
|
+
if (engine.getTextRectangle) {
|
|
884
|
+
const textClient = engine.getTextRectangle(element);
|
|
885
|
+
const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
|
|
886
|
+
if (isHitTextRectangle) {
|
|
887
|
+
return isHitTextRectangle;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (PlaitDrawElement.isImage(element)) {
|
|
892
|
+
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
893
|
+
return RectangleClient.isPointInRectangle(client, point);
|
|
894
|
+
}
|
|
895
|
+
if (PlaitDrawElement.isLine(element)) {
|
|
896
|
+
return isHitLine(board, element, point);
|
|
897
|
+
}
|
|
898
|
+
return null;
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
const getHitRectangleResizeHandleRef = (board, rectangle, point, angle = 0) => {
|
|
902
|
+
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
710
903
|
const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
|
|
711
|
-
|
|
712
|
-
|
|
904
|
+
if (angle) {
|
|
905
|
+
const rotatedPoint = rotatePoints([point], centerPoint, -angle)[0];
|
|
906
|
+
let result = resizeHandleRefs.find(resizeHandleRef => {
|
|
907
|
+
return RectangleClient.isHit(RectangleClient.getRectangleByPoints([rotatedPoint, rotatedPoint]), resizeHandleRef.rectangle);
|
|
908
|
+
});
|
|
909
|
+
if (result) {
|
|
910
|
+
result.cursorClass = getRotatedResizeCursorClassByAngle(result.cursorClass, angle);
|
|
911
|
+
}
|
|
912
|
+
return result;
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
return resizeHandleRefs.find(resizeHandleRef => {
|
|
916
|
+
return RectangleClient.isHit(RectangleClient.getRectangleByPoints([point, point]), resizeHandleRef.rectangle);
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
const getSnappingGeometry = (board, point) => {
|
|
921
|
+
let hitElement = getHitGeometry(board, point);
|
|
922
|
+
if (hitElement) {
|
|
923
|
+
const ref = getSnappingRef(board, hitElement, point);
|
|
924
|
+
if (ref.isHitConnector || ref.isHitEdge) {
|
|
925
|
+
return hitElement;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return null;
|
|
929
|
+
};
|
|
930
|
+
const getSnappingRef = (board, hitElement, point) => {
|
|
931
|
+
const rotatedPoint = rotateAntiPointsByElement(point, hitElement) || point;
|
|
932
|
+
const connectorPoint = getHitConnectorPoint(rotatedPoint, hitElement);
|
|
933
|
+
const edgePoint = getNearestPoint(hitElement, rotatedPoint);
|
|
934
|
+
const isHitEdge = isHitEdgeOfShape(board, hitElement, rotatedPoint, LINE_SNAPPING_BUFFER);
|
|
935
|
+
return { isHitEdge, isHitConnector: !!connectorPoint, connectorPoint, edgePoint };
|
|
936
|
+
};
|
|
937
|
+
const getHitGeometry = (board, point, offset = LINE_HIT_GEOMETRY_BUFFER) => {
|
|
938
|
+
let hitShape = null;
|
|
939
|
+
traverseDrawShapes(board, (element) => {
|
|
940
|
+
if (hitShape === null && isInsideOfShape(board, element, rotateAntiPointsByElement(point, element) || point, offset * 2)) {
|
|
941
|
+
hitShape = element;
|
|
942
|
+
}
|
|
713
943
|
});
|
|
714
|
-
return
|
|
944
|
+
return hitShape;
|
|
715
945
|
};
|
|
716
|
-
const
|
|
717
|
-
let geometry = null;
|
|
946
|
+
const traverseDrawShapes = (board, callback) => {
|
|
718
947
|
depthFirstRecursion(board, node => {
|
|
719
|
-
if (
|
|
720
|
-
|
|
721
|
-
client = RectangleClient.getOutlineRectangle(client, offset);
|
|
722
|
-
const shape = getShape(node);
|
|
723
|
-
const isHit = getEngine(shape).isInsidePoint(client, point);
|
|
724
|
-
if (isHit) {
|
|
725
|
-
geometry = node;
|
|
726
|
-
}
|
|
948
|
+
if (!PlaitBoard.isBoard(node) && PlaitDrawElement.isShapeElement(node)) {
|
|
949
|
+
callback(node);
|
|
727
950
|
}
|
|
728
951
|
}, getIsRecursionFunc(board), true);
|
|
729
|
-
return geometry;
|
|
730
952
|
};
|
|
731
953
|
|
|
732
954
|
const SHAPE_MAX_LENGTH = 6;
|
|
@@ -904,8 +1126,7 @@ function getMiddlePoints(board, element) {
|
|
|
904
1126
|
if (shape === LineShape.elbow) {
|
|
905
1127
|
const renderPoints = getElbowPoints(board, element);
|
|
906
1128
|
const options = getElbowLineRouteOptions(board, element);
|
|
907
|
-
|
|
908
|
-
if (!isIntersect) {
|
|
1129
|
+
if (!isUseDefaultOrthogonalRoute(element, options)) {
|
|
909
1130
|
const [nextSourcePoint, nextTargetPoint] = getNextSourceAndTargetPoints(board, element);
|
|
910
1131
|
for (let i = 0; i < renderPoints.length - 1; i++) {
|
|
911
1132
|
if ((i == 0 && Point.isEquals(renderPoints[i + 1], nextSourcePoint)) ||
|
|
@@ -945,20 +1166,18 @@ const drawLine = (board, element) => {
|
|
|
945
1166
|
arrow && lineG.appendChild(arrow);
|
|
946
1167
|
return lineG;
|
|
947
1168
|
};
|
|
948
|
-
const
|
|
1169
|
+
const getHitConnection = (board, point, hitElement) => {
|
|
949
1170
|
let rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const
|
|
956
|
-
const shape =
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
return connector.find(point => {
|
|
961
|
-
return RectangleClient.isHit(pointRectangle, RectangleClient.getRectangleByPoints([point, point]));
|
|
1171
|
+
const ref = getSnappingRef(board, hitElement, point);
|
|
1172
|
+
const connectionPoint = ref.connectorPoint || ref.edgePoint;
|
|
1173
|
+
return [(connectionPoint[0] - rectangle.x) / rectangle.width, (connectionPoint[1] - rectangle.y) / rectangle.height];
|
|
1174
|
+
};
|
|
1175
|
+
const getHitConnectorPoint = (point, hitElement) => {
|
|
1176
|
+
const rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
|
|
1177
|
+
const shape = getElementShape(hitElement);
|
|
1178
|
+
const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
|
|
1179
|
+
return connectorPoints.find(connectorPoint => {
|
|
1180
|
+
return distanceBetweenPointAndPoint(...connectorPoint, ...point) <= LINE_SNAPPING_CONNECTOR_BUFFER;
|
|
962
1181
|
});
|
|
963
1182
|
};
|
|
964
1183
|
const getLineTextRectangle = (board, element, index) => {
|
|
@@ -995,9 +1214,9 @@ const Q2C = (points) => {
|
|
|
995
1214
|
return result;
|
|
996
1215
|
};
|
|
997
1216
|
const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceElement, lineShapeG) => {
|
|
998
|
-
const hitElement =
|
|
999
|
-
const targetConnection = hitElement ?
|
|
1000
|
-
const
|
|
1217
|
+
const hitElement = getSnappingGeometry(board, movingPoint);
|
|
1218
|
+
const targetConnection = hitElement ? getHitConnection(board, movingPoint, hitElement) : undefined;
|
|
1219
|
+
const sourceConnection = sourceElement ? getHitConnection(board, sourcePoint, sourceElement) : undefined;
|
|
1001
1220
|
const targetBoundId = hitElement ? hitElement.id : undefined;
|
|
1002
1221
|
const lineGenerator = new LineShapeGenerator(board);
|
|
1003
1222
|
const memorizedLatest = getLineMemorizedLatest();
|
|
@@ -1006,7 +1225,7 @@ const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceEl
|
|
|
1006
1225
|
targetMarker = memorizedLatest.target;
|
|
1007
1226
|
sourceMarker && delete memorizedLatest.source;
|
|
1008
1227
|
targetMarker && delete memorizedLatest.target;
|
|
1009
|
-
const temporaryLineElement = createLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || LineMarkerType.none, connection:
|
|
1228
|
+
const temporaryLineElement = createLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || LineMarkerType.none, connection: sourceConnection, boundId: sourceElement?.id }, { marker: targetMarker || LineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
|
|
1010
1229
|
strokeWidth: DefaultLineStyle.strokeWidth,
|
|
1011
1230
|
...memorizedLatest
|
|
1012
1231
|
});
|
|
@@ -1060,185 +1279,6 @@ const getSelectedImageElements = (board) => {
|
|
|
1060
1279
|
return selectedElements;
|
|
1061
1280
|
};
|
|
1062
1281
|
|
|
1063
|
-
var LineResizeHandle;
|
|
1064
|
-
(function (LineResizeHandle) {
|
|
1065
|
-
LineResizeHandle["source"] = "source";
|
|
1066
|
-
LineResizeHandle["target"] = "target";
|
|
1067
|
-
LineResizeHandle["addHandle"] = "addHandle";
|
|
1068
|
-
})(LineResizeHandle || (LineResizeHandle = {}));
|
|
1069
|
-
const getHitLineResizeHandleRef = (board, element, point) => {
|
|
1070
|
-
let dataPoints = PlaitLine.getPoints(board, element);
|
|
1071
|
-
const index = getHitPointIndex(dataPoints, point);
|
|
1072
|
-
if (index !== -1) {
|
|
1073
|
-
const handleIndex = index;
|
|
1074
|
-
if (index === 0) {
|
|
1075
|
-
return { handle: LineResizeHandle.source, handleIndex };
|
|
1076
|
-
}
|
|
1077
|
-
if (index === dataPoints.length - 1) {
|
|
1078
|
-
return { handle: LineResizeHandle.target, handleIndex };
|
|
1079
|
-
}
|
|
1080
|
-
// elbow line, data points only verify source connection point and target connection point
|
|
1081
|
-
if (element.shape !== LineShape.elbow) {
|
|
1082
|
-
return { handleIndex };
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
const middlePoints = getMiddlePoints(board, element);
|
|
1086
|
-
const indexOfMiddlePoints = getHitPointIndex(middlePoints, point);
|
|
1087
|
-
if (indexOfMiddlePoints !== -1) {
|
|
1088
|
-
return {
|
|
1089
|
-
handle: LineResizeHandle.addHandle,
|
|
1090
|
-
handleIndex: indexOfMiddlePoints
|
|
1091
|
-
};
|
|
1092
|
-
}
|
|
1093
|
-
return undefined;
|
|
1094
|
-
};
|
|
1095
|
-
function getHitPointIndex(points, movingPoint) {
|
|
1096
|
-
const rectangles = points.map(point => {
|
|
1097
|
-
return {
|
|
1098
|
-
x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
|
|
1099
|
-
y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
|
|
1100
|
-
width: RESIZE_HANDLE_DIAMETER,
|
|
1101
|
-
height: RESIZE_HANDLE_DIAMETER
|
|
1102
|
-
};
|
|
1103
|
-
});
|
|
1104
|
-
const rectangle = rectangles.find(rectangle => {
|
|
1105
|
-
return RectangleClient.isHit(RectangleClient.getRectangleByPoints([movingPoint, movingPoint]), rectangle);
|
|
1106
|
-
});
|
|
1107
|
-
return rectangle ? rectangles.indexOf(rectangle) : -1;
|
|
1108
|
-
}
|
|
1109
|
-
const getHitLineTextIndex = (board, element, point) => {
|
|
1110
|
-
const texts = element.texts;
|
|
1111
|
-
if (!texts.length)
|
|
1112
|
-
return -1;
|
|
1113
|
-
const points = getLinePoints(board, element);
|
|
1114
|
-
return texts.findIndex(text => {
|
|
1115
|
-
const center = getPointOnPolyline(points, text.position);
|
|
1116
|
-
const rectangle = {
|
|
1117
|
-
x: center[0] - text.width / 2,
|
|
1118
|
-
y: center[1] - text.height / 2,
|
|
1119
|
-
width: text.width,
|
|
1120
|
-
height: text.height
|
|
1121
|
-
};
|
|
1122
|
-
return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
|
|
1123
|
-
});
|
|
1124
|
-
};
|
|
1125
|
-
|
|
1126
|
-
const isTextExceedingBounds = (geometry) => {
|
|
1127
|
-
const client = RectangleClient.getRectangleByPoints(geometry.points);
|
|
1128
|
-
if (geometry.textHeight > client.height) {
|
|
1129
|
-
return true;
|
|
1130
|
-
}
|
|
1131
|
-
return false;
|
|
1132
|
-
};
|
|
1133
|
-
const isHitLineText = (board, element, point) => {
|
|
1134
|
-
return getHitLineTextIndex(board, element, point) !== -1;
|
|
1135
|
-
};
|
|
1136
|
-
const isHitPolyLine = (pathPoints, point) => {
|
|
1137
|
-
const distance = distanceBetweenPointAndSegments(pathPoints, point);
|
|
1138
|
-
return distance <= HIT_DISTANCE_BUFFER;
|
|
1139
|
-
};
|
|
1140
|
-
const isHitLine = (board, element, point) => {
|
|
1141
|
-
const points = getLinePoints(board, element);
|
|
1142
|
-
const isHitText = isHitLineText(board, element, point);
|
|
1143
|
-
return isHitText || isHitPolyLine(points, point);
|
|
1144
|
-
};
|
|
1145
|
-
const isRectangleHitDrawElement = (board, element, selection) => {
|
|
1146
|
-
const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
|
|
1147
|
-
if (PlaitDrawElement.isGeometry(element)) {
|
|
1148
|
-
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
1149
|
-
const centerPoint = RectangleClient.getCenterPoint(client);
|
|
1150
|
-
let rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), centerPoint, element.angle);
|
|
1151
|
-
if (isTextExceedingBounds(element)) {
|
|
1152
|
-
const textClient = getTextRectangle(element);
|
|
1153
|
-
rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(textClient), centerPoint, element.angle);
|
|
1154
|
-
}
|
|
1155
|
-
return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
|
|
1156
|
-
}
|
|
1157
|
-
if (PlaitDrawElement.isImage(element)) {
|
|
1158
|
-
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
1159
|
-
const rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), RectangleClient.getCenterPoint(client), element.angle);
|
|
1160
|
-
return isPolylineHitRectangle(rotatedCornerPoints, client);
|
|
1161
|
-
}
|
|
1162
|
-
if (PlaitDrawElement.isLine(element)) {
|
|
1163
|
-
const points = getLinePoints(board, element);
|
|
1164
|
-
return isPolylineHitRectangle(points, rangeRectangle);
|
|
1165
|
-
}
|
|
1166
|
-
return null;
|
|
1167
|
-
};
|
|
1168
|
-
const isHitDrawElement = (board, element, point) => {
|
|
1169
|
-
const rectangle = board.getRectangle(element);
|
|
1170
|
-
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
1171
|
-
if (element.angle) {
|
|
1172
|
-
point = rotate(point[0], point[1], centerPoint[0], centerPoint[1], -element.angle);
|
|
1173
|
-
}
|
|
1174
|
-
if (PlaitDrawElement.isGeometry(element)) {
|
|
1175
|
-
const fill = getFillByElement(board, element);
|
|
1176
|
-
const engine = getEngine(getShape(element));
|
|
1177
|
-
const nearestPoint = engine.getNearestPoint(rectangle, point);
|
|
1178
|
-
const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
|
|
1179
|
-
const isHitEdge = distance <= HIT_DISTANCE_BUFFER;
|
|
1180
|
-
if (isHitEdge) {
|
|
1181
|
-
return isHitEdge;
|
|
1182
|
-
}
|
|
1183
|
-
// when shape equals text, fill is not allowed
|
|
1184
|
-
if (fill !== DefaultGeometryStyle.fill && fill !== TRANSPARENT && !PlaitDrawElement.isText(element)) {
|
|
1185
|
-
const isHitInside = engine.isInsidePoint(rectangle, point);
|
|
1186
|
-
if (isHitInside) {
|
|
1187
|
-
return isHitInside;
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
else {
|
|
1191
|
-
// if shape equals text, only check text rectangle
|
|
1192
|
-
if (PlaitDrawElement.isText(element)) {
|
|
1193
|
-
const textClient = getTextRectangle(element);
|
|
1194
|
-
let isHitText = RectangleClient.isPointInRectangle(textClient, point);
|
|
1195
|
-
return isHitText;
|
|
1196
|
-
}
|
|
1197
|
-
// check textRectangle of element
|
|
1198
|
-
const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
|
|
1199
|
-
const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
|
|
1200
|
-
if (isHitTextRectangle) {
|
|
1201
|
-
return isHitTextRectangle;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
if (PlaitDrawElement.isImage(element)) {
|
|
1206
|
-
return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
|
|
1207
|
-
}
|
|
1208
|
-
if (PlaitDrawElement.isLine(element)) {
|
|
1209
|
-
return isHitLine(board, element, point);
|
|
1210
|
-
}
|
|
1211
|
-
return null;
|
|
1212
|
-
};
|
|
1213
|
-
const isHitElementInside = (board, element, point) => {
|
|
1214
|
-
const rectangle = board.getRectangle(element);
|
|
1215
|
-
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
1216
|
-
if (element.angle) {
|
|
1217
|
-
point = rotate(point[0], point[1], centerPoint[0], centerPoint[1], -element.angle);
|
|
1218
|
-
}
|
|
1219
|
-
if (PlaitDrawElement.isGeometry(element)) {
|
|
1220
|
-
const engine = getEngine(getShape(element));
|
|
1221
|
-
const isHitInside = engine.isInsidePoint(rectangle, point);
|
|
1222
|
-
if (isHitInside) {
|
|
1223
|
-
return isHitInside;
|
|
1224
|
-
}
|
|
1225
|
-
if (engine.getTextRectangle) {
|
|
1226
|
-
const textClient = engine.getTextRectangle(element);
|
|
1227
|
-
const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
|
|
1228
|
-
if (isHitTextRectangle) {
|
|
1229
|
-
return isHitTextRectangle;
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
if (PlaitDrawElement.isImage(element)) {
|
|
1234
|
-
return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
|
|
1235
|
-
}
|
|
1236
|
-
if (PlaitDrawElement.isLine(element)) {
|
|
1237
|
-
return isHitLine(board, element, point);
|
|
1238
|
-
}
|
|
1239
|
-
return null;
|
|
1240
|
-
};
|
|
1241
|
-
|
|
1242
1282
|
const getCenterPointsOnPolygon$1 = (points) => {
|
|
1243
1283
|
const centerPoints = [];
|
|
1244
1284
|
for (let i = 0; i < points.length; i++) {
|
|
@@ -2317,36 +2357,45 @@ const getTextRectangle = (element) => {
|
|
|
2317
2357
|
y: elementRectangle.y + (elementRectangle.height - height) / 2
|
|
2318
2358
|
};
|
|
2319
2359
|
};
|
|
2320
|
-
const
|
|
2321
|
-
const
|
|
2360
|
+
const drawBoundReaction = (board, element, options = { hasMask: true, hasConnector: true }) => {
|
|
2361
|
+
const g = createG();
|
|
2322
2362
|
const rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2323
|
-
const activeRectangle = RectangleClient.inflate(rectangle,
|
|
2324
|
-
const shape =
|
|
2325
|
-
const
|
|
2363
|
+
const activeRectangle = RectangleClient.inflate(rectangle, SNAPPING_STROKE_WIDTH);
|
|
2364
|
+
const shape = getElementShape(element);
|
|
2365
|
+
const strokeG = drawGeometry(board, activeRectangle, shape, {
|
|
2326
2366
|
stroke: SELECTION_BORDER_COLOR,
|
|
2327
|
-
strokeWidth:
|
|
2328
|
-
fill: SELECTION_FILL_COLOR,
|
|
2329
|
-
fillStyle: 'solid'
|
|
2367
|
+
strokeWidth: SNAPPING_STROKE_WIDTH
|
|
2330
2368
|
});
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
fill: '#FFF',
|
|
2369
|
+
g.appendChild(strokeG);
|
|
2370
|
+
if (options.hasMask) {
|
|
2371
|
+
const maskG = drawGeometry(board, activeRectangle, shape, {
|
|
2372
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
2373
|
+
strokeWidth: 0,
|
|
2374
|
+
fill: SELECTION_FILL_COLOR,
|
|
2338
2375
|
fillStyle: 'solid'
|
|
2339
2376
|
});
|
|
2340
|
-
|
|
2341
|
-
}
|
|
2342
|
-
|
|
2377
|
+
g.appendChild(maskG);
|
|
2378
|
+
}
|
|
2379
|
+
if (options.hasConnector) {
|
|
2380
|
+
const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
|
|
2381
|
+
connectorPoints.forEach(point => {
|
|
2382
|
+
const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 8, {
|
|
2383
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
2384
|
+
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
2385
|
+
fill: '#FFF',
|
|
2386
|
+
fillStyle: 'solid'
|
|
2387
|
+
});
|
|
2388
|
+
g.appendChild(circleG);
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2391
|
+
return g;
|
|
2343
2392
|
};
|
|
2344
2393
|
const drawGeometry = (board, outerRectangle, shape, options) => {
|
|
2345
2394
|
return getEngine(shape).draw(board, outerRectangle, options);
|
|
2346
2395
|
};
|
|
2347
2396
|
const getNearestPoint = (element, point) => {
|
|
2348
2397
|
const rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2349
|
-
const shape =
|
|
2398
|
+
const shape = getElementShape(element);
|
|
2350
2399
|
return getEngine(shape).getNearestPoint(rectangle, point);
|
|
2351
2400
|
};
|
|
2352
2401
|
const getCenterPointsOnPolygon = (points) => {
|
|
@@ -2537,24 +2586,36 @@ const getLineHandleRefPair = (board, element) => {
|
|
|
2537
2586
|
if (sourceBoundElement) {
|
|
2538
2587
|
const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.source) ? 0 : strokeWidth;
|
|
2539
2588
|
const sourceVector = getVectorByConnection(sourceBoundElement, element.source.connection);
|
|
2540
|
-
|
|
2541
|
-
sourceDirection = direction ? direction : sourceDirection;
|
|
2542
|
-
sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
|
|
2589
|
+
sourceHandleRef.vector = sourceVector;
|
|
2543
2590
|
sourceHandleRef.boundElement = sourceBoundElement;
|
|
2591
|
+
if (hasValidAngle(sourceBoundElement)) {
|
|
2592
|
+
const direction = getDirectionByVector(rotateVector(sourceVector, sourceBoundElement.angle));
|
|
2593
|
+
sourceDirection = direction ? direction : sourceDirection;
|
|
2594
|
+
}
|
|
2595
|
+
else {
|
|
2596
|
+
const direction = getDirectionByVector(sourceVector);
|
|
2597
|
+
sourceDirection = direction ? direction : sourceDirection;
|
|
2598
|
+
}
|
|
2544
2599
|
sourceHandleRef.direction = sourceDirection;
|
|
2545
|
-
|
|
2546
|
-
sourceHandleRef.
|
|
2600
|
+
sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
|
|
2601
|
+
sourceHandleRef.point = rotatePointsByElement(sourcePoint, sourceBoundElement) || sourcePoint;
|
|
2547
2602
|
}
|
|
2548
2603
|
if (targetBoundElement) {
|
|
2549
2604
|
const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.target) ? 0 : strokeWidth;
|
|
2550
2605
|
const targetVector = getVectorByConnection(targetBoundElement, element.target.connection);
|
|
2551
|
-
|
|
2552
|
-
targetDirection = direction ? direction : targetDirection;
|
|
2553
|
-
targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
|
|
2606
|
+
targetHandleRef.vector = targetVector;
|
|
2554
2607
|
targetHandleRef.boundElement = targetBoundElement;
|
|
2608
|
+
if (hasValidAngle(targetBoundElement)) {
|
|
2609
|
+
const direction = getDirectionByVector(rotateVector(targetVector, targetBoundElement.angle));
|
|
2610
|
+
targetDirection = direction ? direction : targetDirection;
|
|
2611
|
+
}
|
|
2612
|
+
else {
|
|
2613
|
+
const direction = getDirectionByVector(targetVector);
|
|
2614
|
+
targetDirection = direction ? direction : targetDirection;
|
|
2615
|
+
}
|
|
2555
2616
|
targetHandleRef.direction = targetDirection;
|
|
2556
|
-
|
|
2557
|
-
targetHandleRef.
|
|
2617
|
+
targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
|
|
2618
|
+
targetHandleRef.point = rotatePointsByElement(targetPoint, targetBoundElement) || targetPoint;
|
|
2558
2619
|
}
|
|
2559
2620
|
return { source: sourceHandleRef, target: targetHandleRef };
|
|
2560
2621
|
};
|
|
@@ -2571,7 +2632,7 @@ const getConnectionPoint = (geometry, connection, direction, delta) => {
|
|
|
2571
2632
|
};
|
|
2572
2633
|
const getVectorByConnection = (boundElement, connection) => {
|
|
2573
2634
|
const rectangle = RectangleClient.getRectangleByPoints(boundElement.points);
|
|
2574
|
-
const shape =
|
|
2635
|
+
const shape = getElementShape(boundElement);
|
|
2575
2636
|
const engine = getEngine(shape);
|
|
2576
2637
|
let vector = [0, 0];
|
|
2577
2638
|
const direction = getDirectionByPointOfRectangle(connection);
|
|
@@ -2659,12 +2720,24 @@ const PlaitLine = {
|
|
|
2659
2720
|
return line.target.boundId === element.id;
|
|
2660
2721
|
},
|
|
2661
2722
|
getPoints(board, line) {
|
|
2662
|
-
let sourcePoint
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2723
|
+
let sourcePoint;
|
|
2724
|
+
if (line.source.boundId) {
|
|
2725
|
+
const sourceElement = getElementById(board, line.source.boundId);
|
|
2726
|
+
const sourceConnectionPoint = getConnectionPoint(sourceElement, line.source.connection);
|
|
2727
|
+
sourcePoint = rotatePointsByElement(sourceConnectionPoint, sourceElement) || sourceConnectionPoint;
|
|
2728
|
+
}
|
|
2729
|
+
else {
|
|
2730
|
+
sourcePoint = line.points[0];
|
|
2731
|
+
}
|
|
2732
|
+
let targetPoint;
|
|
2733
|
+
if (line.target.boundId) {
|
|
2734
|
+
const targetElement = getElementById(board, line.target.boundId);
|
|
2735
|
+
const targetConnectionPoint = getConnectionPoint(targetElement, line.target.connection);
|
|
2736
|
+
targetPoint = rotatePointsByElement(targetConnectionPoint, targetElement) || targetConnectionPoint;
|
|
2737
|
+
}
|
|
2738
|
+
else {
|
|
2739
|
+
targetPoint = line.points[line.points.length - 1];
|
|
2740
|
+
}
|
|
2668
2741
|
const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
|
|
2669
2742
|
return [sourcePoint, ...restPoints, targetPoint];
|
|
2670
2743
|
}
|
|
@@ -2704,7 +2777,7 @@ const PlaitDrawElement = {
|
|
|
2704
2777
|
return false;
|
|
2705
2778
|
}
|
|
2706
2779
|
},
|
|
2707
|
-
|
|
2780
|
+
isShapeElement: (value) => {
|
|
2708
2781
|
return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
|
|
2709
2782
|
},
|
|
2710
2783
|
isBasicShape: (value) => {
|
|
@@ -2790,7 +2863,7 @@ const collectLineUpdatedRefsByGeometry = (board, geometry, refs) => {
|
|
|
2790
2863
|
const object = { ...line[handle] };
|
|
2791
2864
|
const linePoints = getLinePoints(board, line);
|
|
2792
2865
|
const point = isSourceBound ? linePoints[0] : linePoints[linePoints.length - 1];
|
|
2793
|
-
object.connection =
|
|
2866
|
+
object.connection = getHitConnection(board, point, geometry);
|
|
2794
2867
|
const path = PlaitBoard.findPath(board, line);
|
|
2795
2868
|
const index = refs.findIndex(obj => Path.equals(obj.path, path));
|
|
2796
2869
|
if (index === -1) {
|
|
@@ -2810,7 +2883,7 @@ const collectLineUpdatedRefsByGeometry = (board, geometry, refs) => {
|
|
|
2810
2883
|
const connectLineToGeometry = (board, lineElement, handle, geometryElement) => {
|
|
2811
2884
|
const linePoints = PlaitLine.getPoints(board, lineElement);
|
|
2812
2885
|
const point = handle === LineHandleKey.source ? linePoints[0] : linePoints[linePoints.length - 1];
|
|
2813
|
-
const connection =
|
|
2886
|
+
const connection = getHitConnection(board, point, geometryElement);
|
|
2814
2887
|
if (connection) {
|
|
2815
2888
|
let source = lineElement.source;
|
|
2816
2889
|
let target = lineElement.target;
|
|
@@ -3235,6 +3308,8 @@ class LineActiveGenerator extends Generator {
|
|
|
3235
3308
|
}
|
|
3236
3309
|
}
|
|
3237
3310
|
|
|
3311
|
+
const debugKey$2 = 'debug:plait:line-turning';
|
|
3312
|
+
const debugGenerator$2 = createDebugGenerator(debugKey$2);
|
|
3238
3313
|
class LineComponent extends CommonPluginElement {
|
|
3239
3314
|
constructor(viewContainerRef, cdr) {
|
|
3240
3315
|
super(cdr);
|
|
@@ -3259,21 +3334,7 @@ class LineComponent extends CommonPluginElement {
|
|
|
3259
3334
|
super.ngOnInit();
|
|
3260
3335
|
this.boundedElements = this.getBoundedElements();
|
|
3261
3336
|
this.drawText();
|
|
3262
|
-
|
|
3263
|
-
// points.forEach((p, index) => {
|
|
3264
|
-
// if (index === 0) {
|
|
3265
|
-
// return;
|
|
3266
|
-
// }
|
|
3267
|
-
// if (index === points.length - 1) {
|
|
3268
|
-
// return;
|
|
3269
|
-
// }
|
|
3270
|
-
// const dataPointG = PlaitBoard.getRoughSVG(this.board).circle(p[0], p[1], 8 * index, {
|
|
3271
|
-
// stroke: '#f08c02',
|
|
3272
|
-
// fill: '#f08c02',
|
|
3273
|
-
// fillStyle: 'solid'
|
|
3274
|
-
// });
|
|
3275
|
-
// PlaitBoard.getElementActiveHost(this.board).append(dataPointG);
|
|
3276
|
-
// });
|
|
3337
|
+
debugGenerator$2.isDebug() && debugGenerator$2.drawCircles(this.board, this.element.points.slice(1, -1), 4, true);
|
|
3277
3338
|
}
|
|
3278
3339
|
getBoundedElements() {
|
|
3279
3340
|
const boundedElements = {};
|
|
@@ -3429,10 +3490,13 @@ const withDrawHotkey = (board) => {
|
|
|
3429
3490
|
};
|
|
3430
3491
|
board.dblClick = (event) => {
|
|
3431
3492
|
event.preventDefault();
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
const
|
|
3435
|
-
|
|
3493
|
+
if (!PlaitBoard.isReadonly(board)) {
|
|
3494
|
+
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
3495
|
+
const hitElement = getHitElementByPoint(board, point);
|
|
3496
|
+
if (hitElement && PlaitDrawElement.isGeometry(hitElement)) {
|
|
3497
|
+
const component = PlaitElement.getComponent(hitElement);
|
|
3498
|
+
component.editText();
|
|
3499
|
+
}
|
|
3436
3500
|
}
|
|
3437
3501
|
dblClick(event);
|
|
3438
3502
|
};
|
|
@@ -3739,7 +3803,7 @@ const withLineCreateByDraw = (board) => {
|
|
|
3739
3803
|
if (!PlaitBoard.isReadonly(board) && isLinePointer && isDrawingMode(board)) {
|
|
3740
3804
|
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
3741
3805
|
start = point;
|
|
3742
|
-
const hitElement =
|
|
3806
|
+
const hitElement = getSnappingGeometry(board, point);
|
|
3743
3807
|
if (hitElement) {
|
|
3744
3808
|
sourceElement = hitElement;
|
|
3745
3809
|
}
|
|
@@ -3775,14 +3839,17 @@ const withLineCreateByDraw = (board) => {
|
|
|
3775
3839
|
return board;
|
|
3776
3840
|
};
|
|
3777
3841
|
|
|
3842
|
+
const debugKey$1 = 'debug:plait:align-for-geometry';
|
|
3843
|
+
const debugGenerator$1 = createDebugGenerator(debugKey$1);
|
|
3778
3844
|
const ALIGN_TOLERANCE = 2;
|
|
3779
3845
|
const EQUAL_SPACING = 10;
|
|
3780
3846
|
const ALIGN_SPACING = 24;
|
|
3781
|
-
class
|
|
3847
|
+
class ResizeSnapReaction {
|
|
3782
3848
|
constructor(board, activeElements) {
|
|
3783
3849
|
this.board = board;
|
|
3784
3850
|
this.activeElements = activeElements;
|
|
3785
3851
|
this.alignRectangles = this.getAlignRectangle();
|
|
3852
|
+
this.angle = getSelectionAngle(activeElements);
|
|
3786
3853
|
}
|
|
3787
3854
|
getAlignRectangle() {
|
|
3788
3855
|
const elements = findElements(this.board, {
|
|
@@ -3790,19 +3857,22 @@ class ResizeAlignReaction {
|
|
|
3790
3857
|
recursion: () => false,
|
|
3791
3858
|
isReverse: false
|
|
3792
3859
|
});
|
|
3793
|
-
return elements.map(item => this.board.getRectangle(item));
|
|
3860
|
+
return elements.map(item => getRectangleByAngle(this.board.getRectangle(item), item.angle) || this.board.getRectangle(item));
|
|
3794
3861
|
}
|
|
3795
|
-
|
|
3862
|
+
getSnapRef(resizeAlignDelta, resizeSnapOptions) {
|
|
3796
3863
|
const { deltaX, deltaY } = resizeAlignDelta;
|
|
3797
|
-
const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } =
|
|
3864
|
+
const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } = resizeSnapOptions;
|
|
3798
3865
|
const newResizeState = {
|
|
3799
3866
|
...resizeState,
|
|
3800
3867
|
endPoint: [resizeState.endPoint[0] + deltaX, resizeState.endPoint[1] + deltaY]
|
|
3801
3868
|
};
|
|
3802
3869
|
const { xZoom, yZoom } = getResizeZoom(newResizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
|
|
3803
|
-
|
|
3870
|
+
let activePoints = resizeOriginPoints.map(p => {
|
|
3804
3871
|
return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
|
|
3805
3872
|
});
|
|
3873
|
+
if (this.angle) {
|
|
3874
|
+
activePoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(resizeOriginPoints), RectangleClient.getRectangleByPoints(activePoints), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeOriginPoints)), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(activePoints)), this.angle);
|
|
3875
|
+
}
|
|
3806
3876
|
return {
|
|
3807
3877
|
deltaX,
|
|
3808
3878
|
deltaY,
|
|
@@ -3811,40 +3881,41 @@ class ResizeAlignReaction {
|
|
|
3811
3881
|
activePoints
|
|
3812
3882
|
};
|
|
3813
3883
|
}
|
|
3814
|
-
getEqualLineDelta(
|
|
3884
|
+
getEqualLineDelta(resizeSnapOptions) {
|
|
3815
3885
|
let equalLineDelta = {
|
|
3816
3886
|
deltaX: 0,
|
|
3817
3887
|
deltaY: 0
|
|
3818
3888
|
};
|
|
3819
|
-
const { isAspectRatio, activeRectangle } =
|
|
3889
|
+
const { isAspectRatio, activeRectangle } = resizeSnapOptions;
|
|
3820
3890
|
const widthAlignRectangle = this.alignRectangles.find(item => Math.abs(item.width - activeRectangle.width) < ALIGN_TOLERANCE);
|
|
3821
3891
|
if (widthAlignRectangle) {
|
|
3822
3892
|
const deltaWidth = widthAlignRectangle.width - activeRectangle.width;
|
|
3823
|
-
equalLineDelta.deltaX = deltaWidth *
|
|
3893
|
+
equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
|
|
3824
3894
|
if (isAspectRatio) {
|
|
3825
3895
|
const deltaHeight = deltaWidth / (activeRectangle.width / activeRectangle.height);
|
|
3826
|
-
equalLineDelta.deltaY = deltaHeight *
|
|
3896
|
+
equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
|
|
3827
3897
|
return equalLineDelta;
|
|
3828
3898
|
}
|
|
3829
3899
|
}
|
|
3830
3900
|
const heightAlignRectangle = this.alignRectangles.find(item => Math.abs(item.height - activeRectangle.height) < ALIGN_TOLERANCE);
|
|
3831
3901
|
if (heightAlignRectangle) {
|
|
3832
3902
|
const deltaHeight = heightAlignRectangle.height - activeRectangle.height;
|
|
3833
|
-
equalLineDelta.deltaY = deltaHeight *
|
|
3903
|
+
equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
|
|
3834
3904
|
if (isAspectRatio) {
|
|
3835
3905
|
const deltaWidth = deltaHeight * (activeRectangle.width / activeRectangle.height);
|
|
3836
|
-
equalLineDelta.deltaX = deltaWidth *
|
|
3906
|
+
equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
|
|
3837
3907
|
return equalLineDelta;
|
|
3838
3908
|
}
|
|
3839
3909
|
}
|
|
3840
3910
|
return equalLineDelta;
|
|
3841
3911
|
}
|
|
3842
|
-
drawEqualLines(activePoints,
|
|
3912
|
+
drawEqualLines(activePoints, resizeSnapOptions) {
|
|
3843
3913
|
let widthEqualPoints = [];
|
|
3844
3914
|
let heightEqualPoints = [];
|
|
3845
|
-
const drawHorizontalLine =
|
|
3846
|
-
const drawVerticalLine =
|
|
3847
|
-
const activeRectangle = RectangleClient.getRectangleByPoints(activePoints)
|
|
3915
|
+
const drawHorizontalLine = resizeSnapOptions.directionFactors[0] !== 0 || resizeSnapOptions.isAspectRatio;
|
|
3916
|
+
const drawVerticalLine = resizeSnapOptions.directionFactors[1] !== 0 || resizeSnapOptions.isAspectRatio;
|
|
3917
|
+
const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), this.angle) ||
|
|
3918
|
+
RectangleClient.getRectangleByPoints(activePoints);
|
|
3848
3919
|
for (let alignRectangle of this.alignRectangles) {
|
|
3849
3920
|
if (activeRectangle.width === alignRectangle.width && drawHorizontalLine) {
|
|
3850
3921
|
widthEqualPoints.push(getEqualLinePoints(alignRectangle, true));
|
|
@@ -3862,12 +3933,12 @@ class ResizeAlignReaction {
|
|
|
3862
3933
|
const equalLinePoints = [...widthEqualPoints, ...heightEqualPoints];
|
|
3863
3934
|
return drawEqualLines(this.board, equalLinePoints);
|
|
3864
3935
|
}
|
|
3865
|
-
getAlignLineDelta(
|
|
3936
|
+
getAlignLineDelta(resizeSnapOptions) {
|
|
3866
3937
|
let alignLineDelta = {
|
|
3867
3938
|
deltaX: 0,
|
|
3868
3939
|
deltaY: 0
|
|
3869
3940
|
};
|
|
3870
|
-
const { isAspectRatio, activeRectangle, directionFactors } =
|
|
3941
|
+
const { isAspectRatio, activeRectangle, directionFactors } = resizeSnapOptions;
|
|
3871
3942
|
const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
|
|
3872
3943
|
const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
|
|
3873
3944
|
if (drawHorizontal) {
|
|
@@ -3896,9 +3967,12 @@ class ResizeAlignReaction {
|
|
|
3896
3967
|
}
|
|
3897
3968
|
return alignLineDelta;
|
|
3898
3969
|
}
|
|
3899
|
-
drawAlignLines(activePoints,
|
|
3970
|
+
drawAlignLines(activePoints, resizeSnapOptions) {
|
|
3971
|
+
debugGenerator$1.isDebug() && debugGenerator$1.clear();
|
|
3900
3972
|
let alignLinePoints = [];
|
|
3901
|
-
const activeRectangle = RectangleClient.getRectangleByPoints(activePoints)
|
|
3973
|
+
const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), this.angle) ||
|
|
3974
|
+
RectangleClient.getRectangleByPoints(activePoints);
|
|
3975
|
+
debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, activeRectangle, { stroke: 'green' });
|
|
3902
3976
|
const alignAxisX = getTripleAlignAxis(activeRectangle, true);
|
|
3903
3977
|
const alignAxisY = getTripleAlignAxis(activeRectangle, false);
|
|
3904
3978
|
const alignLineRefs = [
|
|
@@ -3936,11 +4010,12 @@ class ResizeAlignReaction {
|
|
|
3936
4010
|
alignLinePoints.push([pointStart, pointEnd]);
|
|
3937
4011
|
}
|
|
3938
4012
|
};
|
|
3939
|
-
const { isAspectRatio, directionFactors } =
|
|
4013
|
+
const { isAspectRatio, directionFactors } = resizeSnapOptions;
|
|
3940
4014
|
const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
|
|
3941
4015
|
const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
|
|
3942
4016
|
for (let index = 0; index < this.alignRectangles.length; index++) {
|
|
3943
4017
|
const element = this.alignRectangles[index];
|
|
4018
|
+
debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, element);
|
|
3944
4019
|
if (isAlign(alignLineRefs[0].axis, element, alignLineRefs[0].isHorizontal)) {
|
|
3945
4020
|
alignLineRefs[0].alignRectangles.push(element);
|
|
3946
4021
|
}
|
|
@@ -3980,15 +4055,15 @@ class ResizeAlignReaction {
|
|
|
3980
4055
|
}
|
|
3981
4056
|
return drawAlignLines(this.board, alignLinePoints);
|
|
3982
4057
|
}
|
|
3983
|
-
|
|
4058
|
+
handleResizeSnap(resizeSnapOptions) {
|
|
3984
4059
|
const alignG = createG();
|
|
3985
|
-
let alignLineDelta = this.getEqualLineDelta(
|
|
4060
|
+
let alignLineDelta = this.getEqualLineDelta(resizeSnapOptions);
|
|
3986
4061
|
if (alignLineDelta.deltaX === 0 && alignLineDelta.deltaY === 0) {
|
|
3987
|
-
alignLineDelta = this.getAlignLineDelta(
|
|
4062
|
+
alignLineDelta = this.getAlignLineDelta(resizeSnapOptions);
|
|
3988
4063
|
}
|
|
3989
|
-
const equalLineRef = this.
|
|
3990
|
-
const equalLinesG = this.drawEqualLines(equalLineRef.activePoints,
|
|
3991
|
-
const alignLinesG = this.drawAlignLines(equalLineRef.activePoints,
|
|
4064
|
+
const equalLineRef = this.getSnapRef(alignLineDelta, resizeSnapOptions);
|
|
4065
|
+
const equalLinesG = this.drawEqualLines(equalLineRef.activePoints, resizeSnapOptions);
|
|
4066
|
+
const alignLinesG = this.drawAlignLines(equalLineRef.activePoints, resizeSnapOptions);
|
|
3992
4067
|
alignG.append(equalLinesG, alignLinesG);
|
|
3993
4068
|
return { ...equalLineRef, alignG };
|
|
3994
4069
|
}
|
|
@@ -4088,8 +4163,7 @@ function getNearestAlignRectangle(alignRectangles, activeRectangle) {
|
|
|
4088
4163
|
});
|
|
4089
4164
|
return nearestRectangle;
|
|
4090
4165
|
}
|
|
4091
|
-
|
|
4092
|
-
function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
|
|
4166
|
+
function getResizeSnapRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
|
|
4093
4167
|
const { originPoint, handlePoint } = resizeOriginPointAndHandlePoint;
|
|
4094
4168
|
const { xZoom, yZoom } = getResizeZoom(resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
|
|
4095
4169
|
let activeElements;
|
|
@@ -4106,11 +4180,12 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
|
|
|
4106
4180
|
const points = resizeOriginPoints.map(p => {
|
|
4107
4181
|
return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
|
|
4108
4182
|
});
|
|
4109
|
-
const activeRectangle = RectangleClient.getRectangleByPoints(points)
|
|
4110
|
-
|
|
4183
|
+
const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(points), getSelectionAngle(activeElements)) ||
|
|
4184
|
+
RectangleClient.getRectangleByPoints(points);
|
|
4185
|
+
const resizeSnapReaction = new ResizeSnapReaction(board, activeElements);
|
|
4111
4186
|
const resizeHandlePoint = movePointByZoomAndOriginPoint(handlePoint, originPoint, xZoom, yZoom);
|
|
4112
4187
|
const [x, y] = getUnitVectorByPointAndPoint(originPoint, resizeHandlePoint);
|
|
4113
|
-
return
|
|
4188
|
+
return resizeSnapReaction.handleResizeSnap({
|
|
4114
4189
|
resizeState,
|
|
4115
4190
|
resizeOriginPoints,
|
|
4116
4191
|
activeRectangle,
|
|
@@ -4122,10 +4197,14 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
|
|
|
4122
4197
|
});
|
|
4123
4198
|
}
|
|
4124
4199
|
|
|
4200
|
+
const debugKey = 'debug:plait:resize-for-rotation';
|
|
4201
|
+
const debugGenerator = createDebugGenerator(debugKey);
|
|
4125
4202
|
function withDrawResize(board) {
|
|
4126
|
-
const { afterChange } = board;
|
|
4203
|
+
const { afterChange, drawActiveRectangle } = board;
|
|
4127
4204
|
let alignG;
|
|
4128
4205
|
let handleG;
|
|
4206
|
+
let needCustomActiveRectangle = false;
|
|
4207
|
+
let resizeActivePoints = null;
|
|
4129
4208
|
const canResize = () => {
|
|
4130
4209
|
const elements = getSelectedElements(board);
|
|
4131
4210
|
return elements.length > 1 && elements.every(el => PlaitDrawElement.isDrawElement(el));
|
|
@@ -4136,7 +4215,8 @@ function withDrawResize(board) {
|
|
|
4136
4215
|
hitTest: (point) => {
|
|
4137
4216
|
const elements = getSelectedElements(board);
|
|
4138
4217
|
const boundingRectangle = getRectangleByElements(board, elements, false);
|
|
4139
|
-
const
|
|
4218
|
+
const angle = getSelectionAngle(elements);
|
|
4219
|
+
const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point, angle);
|
|
4140
4220
|
if (handleRef) {
|
|
4141
4221
|
return {
|
|
4142
4222
|
element: elements,
|
|
@@ -4149,20 +4229,75 @@ function withDrawResize(board) {
|
|
|
4149
4229
|
},
|
|
4150
4230
|
onResize: (resizeRef, resizeState) => {
|
|
4151
4231
|
alignG?.remove();
|
|
4232
|
+
debugGenerator.isDebug() && debugGenerator.clear();
|
|
4152
4233
|
const isFromCorner = isCornerHandle(board, resizeRef.handle);
|
|
4153
4234
|
const isAspectRatio = resizeState.isShift || isFromCorner;
|
|
4235
|
+
const centerPoint = RectangleClient.getCenterPoint(resizeRef.rectangle);
|
|
4154
4236
|
const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
|
|
4155
|
-
const
|
|
4237
|
+
const angle = getSelectionAngle(resizeRef.element);
|
|
4238
|
+
let bulkRotationRef;
|
|
4239
|
+
if (angle) {
|
|
4240
|
+
bulkRotationRef = {
|
|
4241
|
+
angle: angle,
|
|
4242
|
+
offsetX: 0,
|
|
4243
|
+
offsetY: 0,
|
|
4244
|
+
newCenterPoint: [0, 0]
|
|
4245
|
+
};
|
|
4246
|
+
const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -bulkRotationRef.angle);
|
|
4247
|
+
resizeState.startPoint = rotatedStartPoint;
|
|
4248
|
+
resizeState.endPoint = rotateEndPoint;
|
|
4249
|
+
}
|
|
4250
|
+
const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
|
|
4156
4251
|
originPoint,
|
|
4157
4252
|
handlePoint
|
|
4158
4253
|
}, isAspectRatio, isFromCorner);
|
|
4254
|
+
resizeActivePoints = resizeAlignRef.activePoints;
|
|
4159
4255
|
alignG = resizeAlignRef.alignG;
|
|
4160
4256
|
PlaitBoard.getElementActiveHost(board).append(alignG);
|
|
4161
|
-
|
|
4162
|
-
const
|
|
4163
|
-
|
|
4257
|
+
if (bulkRotationRef) {
|
|
4258
|
+
const boundingBoxCornerPoints = RectangleClient.getPoints(resizeRef.rectangle);
|
|
4259
|
+
const resizedBoundingBoxCornerPoints = boundingBoxCornerPoints.map(p => {
|
|
4164
4260
|
return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
|
|
4165
4261
|
});
|
|
4262
|
+
const newBoundingBox = RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints);
|
|
4263
|
+
debugGenerator.isDebug() && debugGenerator.drawRectangle(board, newBoundingBox, { stroke: 'blue' });
|
|
4264
|
+
const newBoundingBoxCenter = RectangleClient.getCenterPoint(newBoundingBox);
|
|
4265
|
+
const adjustedNewBoundingBoxPoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(boundingBoxCornerPoints), RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints), centerPoint, newBoundingBoxCenter, bulkRotationRef.angle);
|
|
4266
|
+
const newCenter = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(adjustedNewBoundingBoxPoints));
|
|
4267
|
+
bulkRotationRef = Object.assign(bulkRotationRef, {
|
|
4268
|
+
offsetX: newCenter[0] - newBoundingBoxCenter[0],
|
|
4269
|
+
offsetY: newCenter[1] - newBoundingBoxCenter[1],
|
|
4270
|
+
newCenterPoint: newCenter
|
|
4271
|
+
});
|
|
4272
|
+
debugGenerator.isDebug() && debugGenerator.drawRectangle(board, adjustedNewBoundingBoxPoints);
|
|
4273
|
+
}
|
|
4274
|
+
resizeRef.element.forEach(target => {
|
|
4275
|
+
const path = PlaitBoard.findPath(board, target);
|
|
4276
|
+
let points;
|
|
4277
|
+
if (bulkRotationRef) {
|
|
4278
|
+
const reversedPoints = rotatedDataPoints(target.points, centerPoint, -bulkRotationRef.angle);
|
|
4279
|
+
points = reversedPoints.map((p) => {
|
|
4280
|
+
return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
|
|
4281
|
+
});
|
|
4282
|
+
const adjustTargetPoints = points.map(p => [
|
|
4283
|
+
p[0] + bulkRotationRef.offsetX,
|
|
4284
|
+
p[1] + bulkRotationRef.offsetY
|
|
4285
|
+
]);
|
|
4286
|
+
points = rotatedDataPoints(adjustTargetPoints, bulkRotationRef.newCenterPoint, bulkRotationRef.angle);
|
|
4287
|
+
}
|
|
4288
|
+
else {
|
|
4289
|
+
if (hasValidAngle(target)) {
|
|
4290
|
+
needCustomActiveRectangle = true;
|
|
4291
|
+
}
|
|
4292
|
+
if (hasValidAngle(target) && isAxisChangedByAngle(target.angle)) {
|
|
4293
|
+
points = getResizePointsByOtherwiseAxis(board, target.points, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
|
|
4294
|
+
}
|
|
4295
|
+
else {
|
|
4296
|
+
points = target.points.map(p => {
|
|
4297
|
+
return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
|
|
4298
|
+
});
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4166
4301
|
if (PlaitDrawElement.isGeometry(target)) {
|
|
4167
4302
|
const { height: textHeight } = getFirstTextManage(target).getSize();
|
|
4168
4303
|
DrawTransforms.resizeGeometry(board, points, textHeight, path);
|
|
@@ -4188,6 +4323,12 @@ function withDrawResize(board) {
|
|
|
4188
4323
|
afterResize: (resizeRef) => {
|
|
4189
4324
|
alignG?.remove();
|
|
4190
4325
|
alignG = null;
|
|
4326
|
+
if (needCustomActiveRectangle) {
|
|
4327
|
+
needCustomActiveRectangle = false;
|
|
4328
|
+
resizeActivePoints = null;
|
|
4329
|
+
const selectedElements = getSelectedElements(board);
|
|
4330
|
+
Transforms.addSelectionWithTemporaryElements(board, selectedElements);
|
|
4331
|
+
}
|
|
4191
4332
|
}
|
|
4192
4333
|
};
|
|
4193
4334
|
withResize(board, options);
|
|
@@ -4200,15 +4341,32 @@ function withDrawResize(board) {
|
|
|
4200
4341
|
if (canResize() && !isSelectionMoving(board)) {
|
|
4201
4342
|
handleG = createG();
|
|
4202
4343
|
const elements = getSelectedElements(board);
|
|
4203
|
-
const boundingRectangle =
|
|
4204
|
-
|
|
4205
|
-
|
|
4344
|
+
const boundingRectangle = needCustomActiveRectangle
|
|
4345
|
+
? RectangleClient.getRectangleByPoints(resizeActivePoints)
|
|
4346
|
+
: getRectangleByElements(board, elements, false);
|
|
4347
|
+
let corners = RectangleClient.getCornerPoints(boundingRectangle);
|
|
4348
|
+
const angle = getSelectionAngle(elements);
|
|
4349
|
+
if (angle) {
|
|
4350
|
+
const centerPoint = RectangleClient.getCenterPoint(boundingRectangle);
|
|
4351
|
+
corners = rotatePoints(corners, centerPoint, angle);
|
|
4352
|
+
}
|
|
4353
|
+
corners.forEach(corner => {
|
|
4206
4354
|
const g = drawHandle(board, corner);
|
|
4207
4355
|
handleG && handleG.append(g);
|
|
4208
4356
|
});
|
|
4209
4357
|
PlaitBoard.getElementActiveHost(board).append(handleG);
|
|
4210
4358
|
}
|
|
4211
4359
|
};
|
|
4360
|
+
board.drawActiveRectangle = () => {
|
|
4361
|
+
if (needCustomActiveRectangle) {
|
|
4362
|
+
const rectangle = RectangleClient.getRectangleByPoints(resizeActivePoints);
|
|
4363
|
+
return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
|
|
4364
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
4365
|
+
strokeWidth: ACTIVE_STROKE_WIDTH
|
|
4366
|
+
});
|
|
4367
|
+
}
|
|
4368
|
+
return drawActiveRectangle();
|
|
4369
|
+
};
|
|
4212
4370
|
return board;
|
|
4213
4371
|
}
|
|
4214
4372
|
const getResizeOriginPointAndHandlePoint = (board, resizeRef) => {
|
|
@@ -4264,6 +4422,24 @@ const movePointByZoomAndOriginPoint = (p, resizeOriginPoint, xZoom, yZoom) => {
|
|
|
4264
4422
|
const offsetY = (p[1] - resizeOriginPoint[1]) * yZoom;
|
|
4265
4423
|
return [p[0] + offsetX, p[1] + offsetY];
|
|
4266
4424
|
};
|
|
4425
|
+
/**
|
|
4426
|
+
* 1. Rotate 90°
|
|
4427
|
+
* 2. Scale based on the rotated points
|
|
4428
|
+
* 3. Reverse rotate the scaled points by 90°
|
|
4429
|
+
*/
|
|
4430
|
+
const getResizePointsByOtherwiseAxis = (board, points, resizeOriginPoint, xZoom, yZoom) => {
|
|
4431
|
+
const currentRectangle = RectangleClient.getRectangleByPoints(points);
|
|
4432
|
+
debugGenerator.isDebug() && debugGenerator.drawRectangle(board, currentRectangle, { stroke: 'black' });
|
|
4433
|
+
let resultPoints = points;
|
|
4434
|
+
resultPoints = rotatePoints(resultPoints, RectangleClient.getCenterPoint(currentRectangle), (1 / 2) * Math.PI);
|
|
4435
|
+
debugGenerator.isDebug() && debugGenerator.drawRectangle(board, resultPoints, { stroke: 'blue' });
|
|
4436
|
+
resultPoints = resultPoints.map(p => {
|
|
4437
|
+
return movePointByZoomAndOriginPoint(p, resizeOriginPoint, xZoom, yZoom);
|
|
4438
|
+
});
|
|
4439
|
+
debugGenerator.isDebug() && debugGenerator.drawRectangle(board, resultPoints);
|
|
4440
|
+
const newRectangle = RectangleClient.getRectangleByPoints(resultPoints);
|
|
4441
|
+
return rotatePoints(resultPoints, RectangleClient.getCenterPoint(newRectangle), -(1 / 2) * Math.PI);
|
|
4442
|
+
};
|
|
4267
4443
|
|
|
4268
4444
|
const withGeometryResize = (board) => {
|
|
4269
4445
|
let alignG;
|
|
@@ -4281,7 +4457,7 @@ const withGeometryResize = (board) => {
|
|
|
4281
4457
|
const targetComponent = PlaitElement.getComponent(selectedElements[0]);
|
|
4282
4458
|
if (targetComponent.activeGenerator.hasResizeHandle) {
|
|
4283
4459
|
const rectangle = board.getRectangle(target);
|
|
4284
|
-
const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point);
|
|
4460
|
+
const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, target.angle);
|
|
4285
4461
|
if (handleRef) {
|
|
4286
4462
|
return {
|
|
4287
4463
|
element: target,
|
|
@@ -4294,11 +4470,14 @@ const withGeometryResize = (board) => {
|
|
|
4294
4470
|
return null;
|
|
4295
4471
|
},
|
|
4296
4472
|
onResize: (resizeRef, resizeState) => {
|
|
4473
|
+
const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeRef.element.points));
|
|
4474
|
+
resizeState.startPoint = rotateAntiPointsByElement(resizeState.startPoint, resizeRef.element) || resizeState.startPoint;
|
|
4475
|
+
resizeState.endPoint = rotateAntiPointsByElement(resizeState.endPoint, resizeRef.element) || resizeState.endPoint;
|
|
4297
4476
|
alignG?.remove();
|
|
4298
4477
|
const isFromCorner = isCornerHandle(board, resizeRef.handle);
|
|
4299
4478
|
const isAspectRatio = resizeState.isShift || PlaitDrawElement.isImage(resizeRef.element);
|
|
4300
4479
|
const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
|
|
4301
|
-
const resizeAlignRef =
|
|
4480
|
+
const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
|
|
4302
4481
|
originPoint,
|
|
4303
4482
|
handlePoint
|
|
4304
4483
|
}, isAspectRatio, isFromCorner);
|
|
@@ -4357,8 +4536,7 @@ const withLineResize = (board) => {
|
|
|
4357
4536
|
resizeRef.handle !== LineResizeHandle.source &&
|
|
4358
4537
|
resizeRef.handle !== LineResizeHandle.target) {
|
|
4359
4538
|
const params = getElbowLineRouteOptions(board, resizeRef.element);
|
|
4360
|
-
|
|
4361
|
-
if (isIntersect) {
|
|
4539
|
+
if (isUseDefaultOrthogonalRoute(resizeRef.element, params)) {
|
|
4362
4540
|
return;
|
|
4363
4541
|
}
|
|
4364
4542
|
const points = [...resizeRef.element.points];
|
|
@@ -4377,12 +4555,12 @@ const withLineResize = (board) => {
|
|
|
4377
4555
|
let source = { ...resizeRef.element.source };
|
|
4378
4556
|
let target = { ...resizeRef.element.target };
|
|
4379
4557
|
let handleIndex = resizeRef.handleIndex;
|
|
4380
|
-
const hitElement =
|
|
4558
|
+
const hitElement = getSnappingGeometry(board, resizeState.endPoint);
|
|
4381
4559
|
if (resizeRef.handle === LineResizeHandle.source || resizeRef.handle === LineResizeHandle.target) {
|
|
4382
4560
|
const object = resizeRef.handle === LineResizeHandle.source ? source : target;
|
|
4383
4561
|
points[handleIndex] = resizeState.endPoint;
|
|
4384
4562
|
if (hitElement) {
|
|
4385
|
-
object.connection =
|
|
4563
|
+
object.connection = getHitConnection(board, resizeState.endPoint, hitElement);
|
|
4386
4564
|
object.boundId = hitElement.id;
|
|
4387
4565
|
}
|
|
4388
4566
|
else {
|
|
@@ -4424,7 +4602,8 @@ const withLineResize = (board) => {
|
|
|
4424
4602
|
const newPoints = [...points];
|
|
4425
4603
|
newPoints[0] = drawPoints[0];
|
|
4426
4604
|
newPoints[newPoints.length - 1] = drawPoints[drawPoints.length - 1];
|
|
4427
|
-
if (resizeRef.element.shape !== LineShape.elbow
|
|
4605
|
+
if (resizeRef.element.shape !== LineShape.elbow ||
|
|
4606
|
+
(resizeRef.element.shape === LineShape.elbow && newPoints.length === 2)) {
|
|
4428
4607
|
newPoints.forEach((point, index) => {
|
|
4429
4608
|
if (index === handleIndex)
|
|
4430
4609
|
return;
|
|
@@ -4488,21 +4667,23 @@ const withLineBoundReaction = (board) => {
|
|
|
4488
4667
|
return PlaitDrawElement.isLine(element) && isSourceOrTarget;
|
|
4489
4668
|
});
|
|
4490
4669
|
if (isLinePointer || isLineResizing) {
|
|
4491
|
-
const hitElement =
|
|
4670
|
+
const hitElement = getHitGeometry(board, movingPoint);
|
|
4492
4671
|
if (hitElement) {
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
}
|
|
4505
|
-
|
|
4672
|
+
const ref = getSnappingRef(board, hitElement, movingPoint);
|
|
4673
|
+
const isSnapping = ref.isHitEdge || ref.isHitConnector;
|
|
4674
|
+
boundShapeG = drawBoundReaction(board, hitElement, { hasMask: isSnapping, hasConnector: true });
|
|
4675
|
+
if (isSnapping) {
|
|
4676
|
+
const circleG = drawCircle(PlaitBoard.getRoughSVG(board), ref.connectorPoint || ref.edgePoint, 6, {
|
|
4677
|
+
stroke: SELECTION_BORDER_COLOR,
|
|
4678
|
+
strokeWidth: SNAPPING_STROKE_WIDTH,
|
|
4679
|
+
fill: SELECTION_BORDER_COLOR,
|
|
4680
|
+
fillStyle: 'solid'
|
|
4681
|
+
});
|
|
4682
|
+
boundShapeG.appendChild(circleG);
|
|
4683
|
+
}
|
|
4684
|
+
if (hasValidAngle(hitElement)) {
|
|
4685
|
+
setAngleForG(boundShapeG, RectangleClient.getCenterPointByPoints(hitElement.points), hitElement.angle);
|
|
4686
|
+
}
|
|
4506
4687
|
PlaitBoard.getElementActiveHost(board).append(boundShapeG);
|
|
4507
4688
|
}
|
|
4508
4689
|
}
|
|
@@ -4652,9 +4833,9 @@ const withLineAutoCompleteReaction = (board) => {
|
|
|
4652
4833
|
const selectedElements = getSelectedDrawElements(board);
|
|
4653
4834
|
const targetElement = selectedElements.length === 1 && selectedElements[0];
|
|
4654
4835
|
const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4655
|
-
if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.
|
|
4836
|
+
if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
|
|
4656
4837
|
const points = getAutoCompletePoints(targetElement);
|
|
4657
|
-
const hitIndex = getHitIndexOfAutoCompletePoint(movingPoint, points);
|
|
4838
|
+
const hitIndex = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(movingPoint, targetElement) || movingPoint, points);
|
|
4658
4839
|
const hitPoint = points[hitIndex];
|
|
4659
4840
|
const component = PlaitElement.getComponent(targetElement);
|
|
4660
4841
|
component.lineAutoCompleteGenerator.recoverAutoCompleteG();
|
|
@@ -4667,6 +4848,9 @@ const withLineAutoCompleteReaction = (board) => {
|
|
|
4667
4848
|
});
|
|
4668
4849
|
PlaitBoard.getElementActiveHost(board).append(reactionG);
|
|
4669
4850
|
PlaitBoard.getBoardContainer(board).classList.add(CursorClass.crosshair);
|
|
4851
|
+
if (hasValidAngle(targetElement)) {
|
|
4852
|
+
setAngleForG(reactionG, RectangleClient.getCenterPoint(board.getRectangle(targetElement)), targetElement.angle);
|
|
4853
|
+
}
|
|
4670
4854
|
}
|
|
4671
4855
|
}
|
|
4672
4856
|
pointerMove(event);
|
|
@@ -4677,7 +4861,7 @@ const withLineAutoCompleteReaction = (board) => {
|
|
|
4677
4861
|
const WithLineAutoCompletePluginKey = 'plait-line-auto-complete-plugin-key';
|
|
4678
4862
|
const withLineAutoComplete = (board) => {
|
|
4679
4863
|
const { pointerDown, pointerMove, globalPointerUp } = board;
|
|
4680
|
-
let
|
|
4864
|
+
let autoCompletePoint = null;
|
|
4681
4865
|
let lineShapeG = null;
|
|
4682
4866
|
let sourceElement;
|
|
4683
4867
|
let temporaryElement;
|
|
@@ -4685,13 +4869,13 @@ const withLineAutoComplete = (board) => {
|
|
|
4685
4869
|
const selectedElements = getSelectedDrawElements(board);
|
|
4686
4870
|
const targetElement = selectedElements.length === 1 && selectedElements[0];
|
|
4687
4871
|
const clickPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4688
|
-
if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.
|
|
4872
|
+
if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
|
|
4689
4873
|
const points = getAutoCompletePoints(targetElement);
|
|
4690
|
-
const index = getHitIndexOfAutoCompletePoint(clickPoint, points);
|
|
4874
|
+
const index = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(clickPoint, targetElement) || clickPoint, points);
|
|
4691
4875
|
const hitPoint = points[index];
|
|
4692
4876
|
if (hitPoint) {
|
|
4693
4877
|
temporaryDisableSelection(board);
|
|
4694
|
-
|
|
4878
|
+
autoCompletePoint = hitPoint;
|
|
4695
4879
|
sourceElement = targetElement;
|
|
4696
4880
|
BoardTransforms.updatePointerType(board, LineShape.elbow);
|
|
4697
4881
|
}
|
|
@@ -4702,18 +4886,19 @@ const withLineAutoComplete = (board) => {
|
|
|
4702
4886
|
lineShapeG?.remove();
|
|
4703
4887
|
lineShapeG = createG();
|
|
4704
4888
|
let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4705
|
-
if (
|
|
4706
|
-
const distance = distanceBetweenPointAndPoint(...movingPoint, ...
|
|
4889
|
+
if (autoCompletePoint && sourceElement) {
|
|
4890
|
+
const distance = distanceBetweenPointAndPoint(...(rotateAntiPointsByElement(movingPoint, sourceElement) || movingPoint), ...autoCompletePoint);
|
|
4707
4891
|
if (distance > PRESS_AND_MOVE_BUFFER) {
|
|
4708
4892
|
const rectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
|
|
4709
|
-
const shape =
|
|
4893
|
+
const shape = getElementShape(sourceElement);
|
|
4710
4894
|
const engine = getEngine(shape);
|
|
4711
|
-
let sourcePoint = startPoint;
|
|
4712
4895
|
if (engine.getNearestCrossingPoint) {
|
|
4713
|
-
const crossingPoint = engine.getNearestCrossingPoint(rectangle,
|
|
4714
|
-
|
|
4896
|
+
const crossingPoint = engine.getNearestCrossingPoint(rectangle, autoCompletePoint);
|
|
4897
|
+
autoCompletePoint = crossingPoint;
|
|
4715
4898
|
}
|
|
4716
|
-
|
|
4899
|
+
// source point must be click point
|
|
4900
|
+
const rotatedSourcePoint = rotatePointsByElement(autoCompletePoint, sourceElement) || autoCompletePoint;
|
|
4901
|
+
temporaryElement = handleLineCreating(board, LineShape.elbow, rotatedSourcePoint, movingPoint, sourceElement, lineShapeG);
|
|
4717
4902
|
}
|
|
4718
4903
|
}
|
|
4719
4904
|
pointerMove(event);
|
|
@@ -4727,9 +4912,9 @@ const withLineAutoComplete = (board) => {
|
|
|
4727
4912
|
?.afterComplete;
|
|
4728
4913
|
afterComplete && afterComplete(temporaryElement);
|
|
4729
4914
|
}
|
|
4730
|
-
if (
|
|
4915
|
+
if (autoCompletePoint) {
|
|
4731
4916
|
BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
|
|
4732
|
-
|
|
4917
|
+
autoCompletePoint = null;
|
|
4733
4918
|
}
|
|
4734
4919
|
lineShapeG?.remove();
|
|
4735
4920
|
lineShapeG = null;
|
|
@@ -4787,66 +4972,6 @@ const withLineTextMove = (board) => {
|
|
|
4787
4972
|
return board;
|
|
4788
4973
|
};
|
|
4789
4974
|
|
|
4790
|
-
class GroupGenerator extends Generator {
|
|
4791
|
-
canDraw(element) {
|
|
4792
|
-
return true;
|
|
4793
|
-
}
|
|
4794
|
-
draw(element, partialSelected) {
|
|
4795
|
-
const options = {
|
|
4796
|
-
stroke: '',
|
|
4797
|
-
strokeWidth: ACTIVE_STROKE_WIDTH,
|
|
4798
|
-
strokeLineDash: [5]
|
|
4799
|
-
};
|
|
4800
|
-
if (partialSelected) {
|
|
4801
|
-
options.stroke = '#999';
|
|
4802
|
-
}
|
|
4803
|
-
const rectangle = getRectangleByGroup(this.board, element, true);
|
|
4804
|
-
return drawRectangle(this.board, rectangle, options);
|
|
4805
|
-
}
|
|
4806
|
-
}
|
|
4807
|
-
|
|
4808
|
-
class GroupComponent extends CommonPluginElement {
|
|
4809
|
-
constructor(viewContainerRef, cdr) {
|
|
4810
|
-
super(cdr);
|
|
4811
|
-
this.viewContainerRef = viewContainerRef;
|
|
4812
|
-
this.cdr = cdr;
|
|
4813
|
-
}
|
|
4814
|
-
initializeGenerator() {
|
|
4815
|
-
this.activeGenerator = new ActiveGenerator(this.board, {
|
|
4816
|
-
getRectangle: (element) => {
|
|
4817
|
-
return getRectangleByGroup(this.board, element);
|
|
4818
|
-
},
|
|
4819
|
-
getStrokeWidth: () => 0,
|
|
4820
|
-
getStrokeOpacity: () => 0,
|
|
4821
|
-
hasResizeHandle: () => {
|
|
4822
|
-
return !isSelectionMoving(this.board);
|
|
4823
|
-
}
|
|
4824
|
-
});
|
|
4825
|
-
this.groupGenerator = new GroupGenerator(this.board);
|
|
4826
|
-
}
|
|
4827
|
-
ngOnInit() {
|
|
4828
|
-
super.ngOnInit();
|
|
4829
|
-
this.initializeGenerator();
|
|
4830
|
-
}
|
|
4831
|
-
onContextChanged(value, previous) {
|
|
4832
|
-
const elementsInGroup = getElementsInGroup(this.board, value.element, false, true);
|
|
4833
|
-
const isPartialSelectGroup = elementsInGroup.some(item => isSelectedElementOrGroup(this.board, item)) &&
|
|
4834
|
-
!elementsInGroup.every(item => isSelectedElementOrGroup(this.board, item));
|
|
4835
|
-
this.groupGenerator.processDrawing(value.element, this.g, isPartialSelectGroup);
|
|
4836
|
-
}
|
|
4837
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GroupComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4838
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: GroupComponent, isStandalone: true, selector: "plait-group", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4839
|
-
}
|
|
4840
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GroupComponent, decorators: [{
|
|
4841
|
-
type: Component,
|
|
4842
|
-
args: [{
|
|
4843
|
-
selector: 'plait-group',
|
|
4844
|
-
template: ``,
|
|
4845
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4846
|
-
standalone: true
|
|
4847
|
-
}]
|
|
4848
|
-
}], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });
|
|
4849
|
-
|
|
4850
4975
|
const withDraw = (board) => {
|
|
4851
4976
|
const { drawElement, getRectangle, isRectangleHit, isHit, isInsidePoint, isMovable, isAlign, getRelatedFragment } = board;
|
|
4852
4977
|
board.drawElement = (context) => {
|
|
@@ -4859,9 +4984,6 @@ const withDraw = (board) => {
|
|
|
4859
4984
|
else if (PlaitDrawElement.isImage(context.element)) {
|
|
4860
4985
|
return ImageComponent;
|
|
4861
4986
|
}
|
|
4862
|
-
else if (PlaitGroupElement.isGroup(context.element)) {
|
|
4863
|
-
return GroupComponent;
|
|
4864
|
-
}
|
|
4865
4987
|
return drawElement(context);
|
|
4866
4988
|
};
|
|
4867
4989
|
board.getRectangle = (element) => {
|
|
@@ -4880,9 +5002,6 @@ const withDraw = (board) => {
|
|
|
4880
5002
|
if (PlaitDrawElement.isImage(element)) {
|
|
4881
5003
|
return RectangleClient.getRectangleByPoints(element.points);
|
|
4882
5004
|
}
|
|
4883
|
-
if (PlaitGroupElement.isGroup(element)) {
|
|
4884
|
-
return getRectangleByGroup(board, element);
|
|
4885
|
-
}
|
|
4886
5005
|
return getRectangle(element);
|
|
4887
5006
|
};
|
|
4888
5007
|
board.isRectangleHit = (element, selection) => {
|
|
@@ -4937,8 +5056,8 @@ const withDraw = (board) => {
|
|
|
4937
5056
|
}
|
|
4938
5057
|
return isAlign(element);
|
|
4939
5058
|
};
|
|
4940
|
-
board.getRelatedFragment = (elements) => {
|
|
4941
|
-
const selectedElements = getSelectedElements(board);
|
|
5059
|
+
board.getRelatedFragment = (elements, originData) => {
|
|
5060
|
+
const selectedElements = originData || getSelectedElements(board);
|
|
4942
5061
|
const lineElements = board.children.filter(element => PlaitDrawElement.isLine(element));
|
|
4943
5062
|
const activeLines = lineElements.filter(line => {
|
|
4944
5063
|
const source = selectedElements.find(element => element.id === line.source.boundId);
|
|
@@ -4946,7 +5065,7 @@ const withDraw = (board) => {
|
|
|
4946
5065
|
const isSelected = selectedElements.includes(line);
|
|
4947
5066
|
return source && target && !isSelected;
|
|
4948
5067
|
});
|
|
4949
|
-
return getRelatedFragment([...elements, ...activeLines]);
|
|
5068
|
+
return getRelatedFragment([...elements, ...activeLines], originData);
|
|
4950
5069
|
};
|
|
4951
5070
|
return withDrawResize(withLineTextMove(withLineAutoCompleteReaction(withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withLineAutoComplete(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))))))))))));
|
|
4952
5071
|
};
|
|
@@ -4955,5 +5074,5 @@ const withDraw = (board) => {
|
|
|
4955
5074
|
* Generated bundle index. Do not edit.
|
|
4956
5075
|
*/
|
|
4957
5076
|
|
|
4958
|
-
export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C,
|
|
5077
|
+
export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LINE_HIT_GEOMETRY_BUFFER, LINE_SNAPPING_BUFFER, LINE_SNAPPING_CONNECTOR_BUFFER, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, WithLineAutoCompletePluginKey, alignElbowSegment, alignPoints, createDefaultFlowchart, createDefaultGeometry, createGeometryElement, createLineElement, createTextElement, drawBoundReaction, drawGeometry, drawLine, drawLineArrow, getAutoCompletePoints, getBasicPointers, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultTextPoints, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnection, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getIndexAndDeleteCountByKeyPoint, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getLines, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getTextShapeProperty, getVectorByConnection, handleLineCreating, hasIllegalElbowPoint, insertElement, isHitDrawElement, isHitEdgeOfShape, isHitElementInside, isHitLine, isHitLineText, isHitPolyLine, isInsideOfShape, isRectangleHitDrawElement, isSelfLoop, isTextExceedingBounds, isUpdatedHandleIndex, isUseDefaultOrthogonalRoute, memorizeLatestShape, memorizeLatestText, withDraw, withLineAutoComplete };
|
|
4959
5078
|
//# sourceMappingURL=plait-draw.mjs.map
|