@plait/draw 0.53.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/plugins/with-draw-fragment.mjs +1 -1
- package/esm2022/plugins/with-draw-resize.mjs +56 -9
- package/esm2022/plugins/with-draw.mjs +4 -4
- package/esm2022/plugins/with-geometry-resize.mjs +7 -14
- package/esm2022/plugins/with-line-auto-complete-reaction.mjs +2 -2
- package/esm2022/plugins/with-line-auto-complete.mjs +15 -14
- package/esm2022/plugins/with-line-bound-reaction.mjs +19 -21
- package/esm2022/plugins/with-line-create.mjs +4 -4
- package/esm2022/plugins/with-line-resize.mjs +11 -12
- package/esm2022/transforms/line.mjs +4 -4
- package/esm2022/utils/geometry.mjs +31 -22
- package/esm2022/utils/hit.mjs +26 -26
- package/esm2022/utils/line/elbow.mjs +11 -6
- package/esm2022/utils/line/line-basic.mjs +21 -29
- package/esm2022/utils/line/line-common.mjs +3 -3
- package/esm2022/utils/line/line-resize.mjs +2 -2
- package/esm2022/utils/position/geometry.mjs +51 -21
- package/esm2022/utils/resize-snap.mjs +361 -0
- package/esm2022/utils/shape.mjs +2 -2
- package/fesm2022/plait-draw.mjs +432 -344
- 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 +6 -0
- package/utils/geometry.d.ts +7 -4
- package/utils/hit.d.ts +3 -1
- package/utils/line/elbow.d.ts +3 -0
- package/utils/line/line-basic.d.ts +4 -4
- package/utils/position/geometry.d.ts +10 -2
- package/utils/resize-snap.d.ts +49 -0
- package/utils/shape.d.ts +2 -2
- package/esm2022/utils/resize-align-reaction.mjs +0 -316
- package/esm2022/utils/resize-align.mjs +0 -37
- 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, createDebugGenerator, Point, RectangleClient, getElementById, rotatePointsByElement, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, rotatePoints, depthFirstRecursion,
|
|
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,8 +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
|
|
|
169
|
-
const debugKey$
|
|
170
|
-
const debugGenerator$
|
|
171
|
+
const debugKey$3 = 'debug:plait:line-mirror';
|
|
172
|
+
const debugGenerator$3 = createDebugGenerator(debugKey$3);
|
|
171
173
|
const alignPoints = (basePoint, movingPoint) => {
|
|
172
174
|
const newPoint = [...movingPoint];
|
|
173
175
|
if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
|
|
@@ -304,7 +306,7 @@ function getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRender
|
|
|
304
306
|
if (midDataPoints.length > 0) {
|
|
305
307
|
const handleRefPair = getLineHandleRefPair(board, element);
|
|
306
308
|
const params = getElbowLineRouteOptions(board, element, handleRefPair);
|
|
307
|
-
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params));
|
|
309
|
+
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
|
|
308
310
|
const nextKeyPoints = simplifyOrthogonalPoints(keyPoints.slice(1, keyPoints.length - 1));
|
|
309
311
|
const nextDataPoints = [nextRenderPoints[0], ...midDataPoints, nextRenderPoints[nextRenderPoints.length - 1]];
|
|
310
312
|
const mirrorDataPoints = getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params);
|
|
@@ -431,7 +433,7 @@ function findOrthogonalParallelSegments(segment, keyPoints) {
|
|
|
431
433
|
return parallelSegments;
|
|
432
434
|
}
|
|
433
435
|
function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, targetRectangle) {
|
|
434
|
-
debugGenerator$
|
|
436
|
+
debugGenerator$3.isDebug() && debugGenerator$3.clear();
|
|
435
437
|
const mirrorSegments = [];
|
|
436
438
|
for (let index = 0; index < parallelSegments.length; index++) {
|
|
437
439
|
const parallelPath = parallelSegments[index];
|
|
@@ -445,7 +447,7 @@ function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, t
|
|
|
445
447
|
const isValid = !RectangleClient.isHit(fakeRectangle, sourceRectangle) && !RectangleClient.isHit(fakeRectangle, targetRectangle);
|
|
446
448
|
if (isValid) {
|
|
447
449
|
mirrorSegments.push([startPoint, endPoint]);
|
|
448
|
-
debugGenerator$
|
|
450
|
+
debugGenerator$3.isDebug() && debugGenerator$3.drawPolygon(board, RectangleClient.getCornerPoints(fakeRectangle));
|
|
449
451
|
}
|
|
450
452
|
}
|
|
451
453
|
return mirrorSegments;
|
|
@@ -471,15 +473,20 @@ const hasIllegalElbowPoint = (midDataPoints) => {
|
|
|
471
473
|
});
|
|
472
474
|
};
|
|
473
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
|
+
};
|
|
474
482
|
const getElbowPoints = (board, element) => {
|
|
475
483
|
const handleRefPair = getLineHandleRefPair(board, element);
|
|
476
484
|
const params = getElbowLineRouteOptions(board, element, handleRefPair);
|
|
477
485
|
// console.log(params, 'params');
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
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));
|
|
481
488
|
}
|
|
482
|
-
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params));
|
|
489
|
+
const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
|
|
483
490
|
const nextKeyPoints = keyPoints.slice(1, keyPoints.length - 1);
|
|
484
491
|
if (element.points.length === 2) {
|
|
485
492
|
return simplifyOrthogonalPoints(keyPoints);
|
|
@@ -692,7 +699,7 @@ const drawHollowTriangleArrow = (source, target, options) => {
|
|
|
692
699
|
return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
|
|
693
700
|
};
|
|
694
701
|
|
|
695
|
-
const
|
|
702
|
+
const getElementShape = (value) => {
|
|
696
703
|
if (PlaitDrawElement.isImage(value)) {
|
|
697
704
|
return BasicShapes.rectangle;
|
|
698
705
|
}
|
|
@@ -710,29 +717,238 @@ class LineShapeGenerator extends Generator {
|
|
|
710
717
|
}
|
|
711
718
|
}
|
|
712
719
|
|
|
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
|
+
|
|
713
901
|
const getHitRectangleResizeHandleRef = (board, rectangle, point, angle = 0) => {
|
|
714
902
|
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
903
|
+
const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
|
|
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
|
+
}
|
|
719
943
|
});
|
|
720
|
-
return
|
|
944
|
+
return hitShape;
|
|
721
945
|
};
|
|
722
|
-
const
|
|
723
|
-
let geometry = null;
|
|
946
|
+
const traverseDrawShapes = (board, callback) => {
|
|
724
947
|
depthFirstRecursion(board, node => {
|
|
725
|
-
if (
|
|
726
|
-
|
|
727
|
-
client = RectangleClient.getOutlineRectangle(client, offset);
|
|
728
|
-
const shape = getShape(node);
|
|
729
|
-
const isHit = getEngine(shape).isInsidePoint(client, rotateAntiPointsByElement(point, node) || point);
|
|
730
|
-
if (isHit) {
|
|
731
|
-
geometry = node;
|
|
732
|
-
}
|
|
948
|
+
if (!PlaitBoard.isBoard(node) && PlaitDrawElement.isShapeElement(node)) {
|
|
949
|
+
callback(node);
|
|
733
950
|
}
|
|
734
951
|
}, getIsRecursionFunc(board), true);
|
|
735
|
-
return geometry;
|
|
736
952
|
};
|
|
737
953
|
|
|
738
954
|
const SHAPE_MAX_LENGTH = 6;
|
|
@@ -910,8 +1126,7 @@ function getMiddlePoints(board, element) {
|
|
|
910
1126
|
if (shape === LineShape.elbow) {
|
|
911
1127
|
const renderPoints = getElbowPoints(board, element);
|
|
912
1128
|
const options = getElbowLineRouteOptions(board, element);
|
|
913
|
-
|
|
914
|
-
if (!isIntersect) {
|
|
1129
|
+
if (!isUseDefaultOrthogonalRoute(element, options)) {
|
|
915
1130
|
const [nextSourcePoint, nextTargetPoint] = getNextSourceAndTargetPoints(board, element);
|
|
916
1131
|
for (let i = 0; i < renderPoints.length - 1; i++) {
|
|
917
1132
|
if ((i == 0 && Point.isEquals(renderPoints[i + 1], nextSourcePoint)) ||
|
|
@@ -951,20 +1166,18 @@ const drawLine = (board, element) => {
|
|
|
951
1166
|
arrow && lineG.appendChild(arrow);
|
|
952
1167
|
return lineG;
|
|
953
1168
|
};
|
|
954
|
-
const
|
|
1169
|
+
const getHitConnection = (board, point, hitElement) => {
|
|
955
1170
|
let rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
|
|
956
|
-
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
const
|
|
962
|
-
const shape =
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
return connector.find(point => {
|
|
967
|
-
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;
|
|
968
1181
|
});
|
|
969
1182
|
};
|
|
970
1183
|
const getLineTextRectangle = (board, element, index) => {
|
|
@@ -1001,13 +1214,9 @@ const Q2C = (points) => {
|
|
|
1001
1214
|
return result;
|
|
1002
1215
|
};
|
|
1003
1216
|
const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceElement, lineShapeG) => {
|
|
1004
|
-
const hitElement =
|
|
1005
|
-
const targetConnection = hitElement
|
|
1006
|
-
|
|
1007
|
-
: undefined;
|
|
1008
|
-
const sourceConnection = sourceElement
|
|
1009
|
-
? getConnectionByNearestPoint(board, rotateAntiPointsByElement(sourcePoint, sourceElement) || sourcePoint, sourceElement)
|
|
1010
|
-
: undefined;
|
|
1217
|
+
const hitElement = getSnappingGeometry(board, movingPoint);
|
|
1218
|
+
const targetConnection = hitElement ? getHitConnection(board, movingPoint, hitElement) : undefined;
|
|
1219
|
+
const sourceConnection = sourceElement ? getHitConnection(board, sourcePoint, sourceElement) : undefined;
|
|
1011
1220
|
const targetBoundId = hitElement ? hitElement.id : undefined;
|
|
1012
1221
|
const lineGenerator = new LineShapeGenerator(board);
|
|
1013
1222
|
const memorizedLatest = getLineMemorizedLatest();
|
|
@@ -1070,187 +1279,6 @@ const getSelectedImageElements = (board) => {
|
|
|
1070
1279
|
return selectedElements;
|
|
1071
1280
|
};
|
|
1072
1281
|
|
|
1073
|
-
var LineResizeHandle;
|
|
1074
|
-
(function (LineResizeHandle) {
|
|
1075
|
-
LineResizeHandle["source"] = "source";
|
|
1076
|
-
LineResizeHandle["target"] = "target";
|
|
1077
|
-
LineResizeHandle["addHandle"] = "addHandle";
|
|
1078
|
-
})(LineResizeHandle || (LineResizeHandle = {}));
|
|
1079
|
-
const getHitLineResizeHandleRef = (board, element, point) => {
|
|
1080
|
-
let dataPoints = PlaitLine.getPoints(board, element);
|
|
1081
|
-
const index = getHitPointIndex(dataPoints, point);
|
|
1082
|
-
if (index !== -1) {
|
|
1083
|
-
const handleIndex = index;
|
|
1084
|
-
if (index === 0) {
|
|
1085
|
-
return { handle: LineResizeHandle.source, handleIndex };
|
|
1086
|
-
}
|
|
1087
|
-
if (index === dataPoints.length - 1) {
|
|
1088
|
-
return { handle: LineResizeHandle.target, handleIndex };
|
|
1089
|
-
}
|
|
1090
|
-
// elbow line, data points only verify source connection point and target connection point
|
|
1091
|
-
if (element.shape !== LineShape.elbow) {
|
|
1092
|
-
return { handleIndex };
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
const middlePoints = getMiddlePoints(board, element);
|
|
1096
|
-
const indexOfMiddlePoints = getHitPointIndex(middlePoints, point);
|
|
1097
|
-
if (indexOfMiddlePoints !== -1) {
|
|
1098
|
-
return {
|
|
1099
|
-
handle: LineResizeHandle.addHandle,
|
|
1100
|
-
handleIndex: indexOfMiddlePoints
|
|
1101
|
-
};
|
|
1102
|
-
}
|
|
1103
|
-
return undefined;
|
|
1104
|
-
};
|
|
1105
|
-
function getHitPointIndex(points, movingPoint) {
|
|
1106
|
-
const rectangles = points.map(point => {
|
|
1107
|
-
return {
|
|
1108
|
-
x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
|
|
1109
|
-
y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
|
|
1110
|
-
width: RESIZE_HANDLE_DIAMETER,
|
|
1111
|
-
height: RESIZE_HANDLE_DIAMETER
|
|
1112
|
-
};
|
|
1113
|
-
});
|
|
1114
|
-
const rectangle = rectangles.find(rectangle => {
|
|
1115
|
-
return RectangleClient.isHit(RectangleClient.getRectangleByPoints([movingPoint, movingPoint]), rectangle);
|
|
1116
|
-
});
|
|
1117
|
-
return rectangle ? rectangles.indexOf(rectangle) : -1;
|
|
1118
|
-
}
|
|
1119
|
-
const getHitLineTextIndex = (board, element, point) => {
|
|
1120
|
-
const texts = element.texts;
|
|
1121
|
-
if (!texts.length)
|
|
1122
|
-
return -1;
|
|
1123
|
-
const points = getLinePoints(board, element);
|
|
1124
|
-
return texts.findIndex(text => {
|
|
1125
|
-
const center = getPointOnPolyline(points, text.position);
|
|
1126
|
-
const rectangle = {
|
|
1127
|
-
x: center[0] - text.width / 2,
|
|
1128
|
-
y: center[1] - text.height / 2,
|
|
1129
|
-
width: text.width,
|
|
1130
|
-
height: text.height
|
|
1131
|
-
};
|
|
1132
|
-
return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
|
|
1133
|
-
});
|
|
1134
|
-
};
|
|
1135
|
-
|
|
1136
|
-
const isTextExceedingBounds = (geometry) => {
|
|
1137
|
-
const client = RectangleClient.getRectangleByPoints(geometry.points);
|
|
1138
|
-
if (geometry.textHeight > client.height) {
|
|
1139
|
-
return true;
|
|
1140
|
-
}
|
|
1141
|
-
return false;
|
|
1142
|
-
};
|
|
1143
|
-
const isHitLineText = (board, element, point) => {
|
|
1144
|
-
return getHitLineTextIndex(board, element, point) !== -1;
|
|
1145
|
-
};
|
|
1146
|
-
const isHitPolyLine = (pathPoints, point) => {
|
|
1147
|
-
const distance = distanceBetweenPointAndSegments(pathPoints, point);
|
|
1148
|
-
return distance <= HIT_DISTANCE_BUFFER;
|
|
1149
|
-
};
|
|
1150
|
-
const isHitLine = (board, element, point) => {
|
|
1151
|
-
const points = getLinePoints(board, element);
|
|
1152
|
-
const isHitText = isHitLineText(board, element, point);
|
|
1153
|
-
return isHitText || isHitPolyLine(points, point);
|
|
1154
|
-
};
|
|
1155
|
-
const isRectangleHitDrawElement = (board, element, selection) => {
|
|
1156
|
-
const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
|
|
1157
|
-
if (PlaitDrawElement.isGeometry(element)) {
|
|
1158
|
-
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
1159
|
-
const centerPoint = RectangleClient.getCenterPoint(client);
|
|
1160
|
-
let rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), centerPoint, element.angle);
|
|
1161
|
-
if (isTextExceedingBounds(element)) {
|
|
1162
|
-
const textClient = getTextRectangle(element);
|
|
1163
|
-
rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(textClient), centerPoint, element.angle);
|
|
1164
|
-
}
|
|
1165
|
-
return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
|
|
1166
|
-
}
|
|
1167
|
-
if (PlaitDrawElement.isImage(element)) {
|
|
1168
|
-
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
1169
|
-
const rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), RectangleClient.getCenterPoint(client), element.angle);
|
|
1170
|
-
return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
|
|
1171
|
-
}
|
|
1172
|
-
if (PlaitDrawElement.isLine(element)) {
|
|
1173
|
-
const points = getLinePoints(board, element);
|
|
1174
|
-
return isPolylineHitRectangle(points, rangeRectangle);
|
|
1175
|
-
}
|
|
1176
|
-
return null;
|
|
1177
|
-
};
|
|
1178
|
-
const isHitDrawElement = (board, element, point) => {
|
|
1179
|
-
const rectangle = board.getRectangle(element);
|
|
1180
|
-
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
1181
|
-
if (element.angle) {
|
|
1182
|
-
point = rotate(point[0], point[1], centerPoint[0], centerPoint[1], -element.angle);
|
|
1183
|
-
}
|
|
1184
|
-
if (PlaitDrawElement.isGeometry(element)) {
|
|
1185
|
-
const fill = getFillByElement(board, element);
|
|
1186
|
-
const engine = getEngine(getShape(element));
|
|
1187
|
-
const nearestPoint = engine.getNearestPoint(rectangle, point);
|
|
1188
|
-
const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
|
|
1189
|
-
const isHitEdge = distance <= HIT_DISTANCE_BUFFER;
|
|
1190
|
-
if (isHitEdge) {
|
|
1191
|
-
return isHitEdge;
|
|
1192
|
-
}
|
|
1193
|
-
// when shape equals text, fill is not allowed
|
|
1194
|
-
if (fill !== DefaultGeometryStyle.fill && fill !== TRANSPARENT && !PlaitDrawElement.isText(element)) {
|
|
1195
|
-
const isHitInside = engine.isInsidePoint(rectangle, point);
|
|
1196
|
-
if (isHitInside) {
|
|
1197
|
-
return isHitInside;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
else {
|
|
1201
|
-
// if shape equals text, only check text rectangle
|
|
1202
|
-
if (PlaitDrawElement.isText(element)) {
|
|
1203
|
-
const textClient = getTextRectangle(element);
|
|
1204
|
-
let isHitText = RectangleClient.isPointInRectangle(textClient, point);
|
|
1205
|
-
return isHitText;
|
|
1206
|
-
}
|
|
1207
|
-
// check textRectangle of element
|
|
1208
|
-
const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
|
|
1209
|
-
const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
|
|
1210
|
-
if (isHitTextRectangle) {
|
|
1211
|
-
return isHitTextRectangle;
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
if (PlaitDrawElement.isImage(element)) {
|
|
1216
|
-
const client = RectangleClient.getRectangleByPoints(element.points);
|
|
1217
|
-
const rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), RectangleClient.getCenterPoint(client), element.angle);
|
|
1218
|
-
return isPointInPolygon(point, rotatedCornerPoints);
|
|
1219
|
-
}
|
|
1220
|
-
if (PlaitDrawElement.isLine(element)) {
|
|
1221
|
-
return isHitLine(board, element, point);
|
|
1222
|
-
}
|
|
1223
|
-
return null;
|
|
1224
|
-
};
|
|
1225
|
-
const isHitElementInside = (board, element, point) => {
|
|
1226
|
-
const rectangle = board.getRectangle(element);
|
|
1227
|
-
const centerPoint = RectangleClient.getCenterPoint(rectangle);
|
|
1228
|
-
if (element.angle) {
|
|
1229
|
-
point = rotate(point[0], point[1], centerPoint[0], centerPoint[1], -element.angle);
|
|
1230
|
-
}
|
|
1231
|
-
if (PlaitDrawElement.isGeometry(element)) {
|
|
1232
|
-
const engine = getEngine(getShape(element));
|
|
1233
|
-
const isHitInside = engine.isInsidePoint(rectangle, point);
|
|
1234
|
-
if (isHitInside) {
|
|
1235
|
-
return isHitInside;
|
|
1236
|
-
}
|
|
1237
|
-
if (engine.getTextRectangle) {
|
|
1238
|
-
const textClient = engine.getTextRectangle(element);
|
|
1239
|
-
const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
|
|
1240
|
-
if (isHitTextRectangle) {
|
|
1241
|
-
return isHitTextRectangle;
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
if (PlaitDrawElement.isImage(element)) {
|
|
1246
|
-
return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
|
|
1247
|
-
}
|
|
1248
|
-
if (PlaitDrawElement.isLine(element)) {
|
|
1249
|
-
return isHitLine(board, element, point);
|
|
1250
|
-
}
|
|
1251
|
-
return null;
|
|
1252
|
-
};
|
|
1253
|
-
|
|
1254
1282
|
const getCenterPointsOnPolygon$1 = (points) => {
|
|
1255
1283
|
const centerPoints = [];
|
|
1256
1284
|
for (let i = 0; i < points.length; i++) {
|
|
@@ -2329,36 +2357,45 @@ const getTextRectangle = (element) => {
|
|
|
2329
2357
|
y: elementRectangle.y + (elementRectangle.height - height) / 2
|
|
2330
2358
|
};
|
|
2331
2359
|
};
|
|
2332
|
-
const
|
|
2333
|
-
const
|
|
2360
|
+
const drawBoundReaction = (board, element, options = { hasMask: true, hasConnector: true }) => {
|
|
2361
|
+
const g = createG();
|
|
2334
2362
|
const rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2335
|
-
const activeRectangle = RectangleClient.inflate(rectangle,
|
|
2336
|
-
const shape =
|
|
2337
|
-
const
|
|
2363
|
+
const activeRectangle = RectangleClient.inflate(rectangle, SNAPPING_STROKE_WIDTH);
|
|
2364
|
+
const shape = getElementShape(element);
|
|
2365
|
+
const strokeG = drawGeometry(board, activeRectangle, shape, {
|
|
2338
2366
|
stroke: SELECTION_BORDER_COLOR,
|
|
2339
|
-
strokeWidth:
|
|
2340
|
-
fill: SELECTION_FILL_COLOR,
|
|
2341
|
-
fillStyle: 'solid'
|
|
2367
|
+
strokeWidth: SNAPPING_STROKE_WIDTH
|
|
2342
2368
|
});
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
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,
|
|
2350
2375
|
fillStyle: 'solid'
|
|
2351
2376
|
});
|
|
2352
|
-
|
|
2353
|
-
}
|
|
2354
|
-
|
|
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;
|
|
2355
2392
|
};
|
|
2356
2393
|
const drawGeometry = (board, outerRectangle, shape, options) => {
|
|
2357
2394
|
return getEngine(shape).draw(board, outerRectangle, options);
|
|
2358
2395
|
};
|
|
2359
2396
|
const getNearestPoint = (element, point) => {
|
|
2360
2397
|
const rectangle = RectangleClient.getRectangleByPoints(element.points);
|
|
2361
|
-
const shape =
|
|
2398
|
+
const shape = getElementShape(element);
|
|
2362
2399
|
return getEngine(shape).getNearestPoint(rectangle, point);
|
|
2363
2400
|
};
|
|
2364
2401
|
const getCenterPointsOnPolygon = (points) => {
|
|
@@ -2595,7 +2632,7 @@ const getConnectionPoint = (geometry, connection, direction, delta) => {
|
|
|
2595
2632
|
};
|
|
2596
2633
|
const getVectorByConnection = (boundElement, connection) => {
|
|
2597
2634
|
const rectangle = RectangleClient.getRectangleByPoints(boundElement.points);
|
|
2598
|
-
const shape =
|
|
2635
|
+
const shape = getElementShape(boundElement);
|
|
2599
2636
|
const engine = getEngine(shape);
|
|
2600
2637
|
let vector = [0, 0];
|
|
2601
2638
|
const direction = getDirectionByPointOfRectangle(connection);
|
|
@@ -2740,7 +2777,7 @@ const PlaitDrawElement = {
|
|
|
2740
2777
|
return false;
|
|
2741
2778
|
}
|
|
2742
2779
|
},
|
|
2743
|
-
|
|
2780
|
+
isShapeElement: (value) => {
|
|
2744
2781
|
return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
|
|
2745
2782
|
},
|
|
2746
2783
|
isBasicShape: (value) => {
|
|
@@ -2826,7 +2863,7 @@ const collectLineUpdatedRefsByGeometry = (board, geometry, refs) => {
|
|
|
2826
2863
|
const object = { ...line[handle] };
|
|
2827
2864
|
const linePoints = getLinePoints(board, line);
|
|
2828
2865
|
const point = isSourceBound ? linePoints[0] : linePoints[linePoints.length - 1];
|
|
2829
|
-
object.connection =
|
|
2866
|
+
object.connection = getHitConnection(board, point, geometry);
|
|
2830
2867
|
const path = PlaitBoard.findPath(board, line);
|
|
2831
2868
|
const index = refs.findIndex(obj => Path.equals(obj.path, path));
|
|
2832
2869
|
if (index === -1) {
|
|
@@ -2846,7 +2883,7 @@ const collectLineUpdatedRefsByGeometry = (board, geometry, refs) => {
|
|
|
2846
2883
|
const connectLineToGeometry = (board, lineElement, handle, geometryElement) => {
|
|
2847
2884
|
const linePoints = PlaitLine.getPoints(board, lineElement);
|
|
2848
2885
|
const point = handle === LineHandleKey.source ? linePoints[0] : linePoints[linePoints.length - 1];
|
|
2849
|
-
const connection =
|
|
2886
|
+
const connection = getHitConnection(board, point, geometryElement);
|
|
2850
2887
|
if (connection) {
|
|
2851
2888
|
let source = lineElement.source;
|
|
2852
2889
|
let target = lineElement.target;
|
|
@@ -3271,8 +3308,8 @@ class LineActiveGenerator extends Generator {
|
|
|
3271
3308
|
}
|
|
3272
3309
|
}
|
|
3273
3310
|
|
|
3274
|
-
const debugKey$
|
|
3275
|
-
const debugGenerator$
|
|
3311
|
+
const debugKey$2 = 'debug:plait:line-turning';
|
|
3312
|
+
const debugGenerator$2 = createDebugGenerator(debugKey$2);
|
|
3276
3313
|
class LineComponent extends CommonPluginElement {
|
|
3277
3314
|
constructor(viewContainerRef, cdr) {
|
|
3278
3315
|
super(cdr);
|
|
@@ -3297,7 +3334,7 @@ class LineComponent extends CommonPluginElement {
|
|
|
3297
3334
|
super.ngOnInit();
|
|
3298
3335
|
this.boundedElements = this.getBoundedElements();
|
|
3299
3336
|
this.drawText();
|
|
3300
|
-
debugGenerator$
|
|
3337
|
+
debugGenerator$2.isDebug() && debugGenerator$2.drawCircles(this.board, this.element.points.slice(1, -1), 4, true);
|
|
3301
3338
|
}
|
|
3302
3339
|
getBoundedElements() {
|
|
3303
3340
|
const boundedElements = {};
|
|
@@ -3766,7 +3803,7 @@ const withLineCreateByDraw = (board) => {
|
|
|
3766
3803
|
if (!PlaitBoard.isReadonly(board) && isLinePointer && isDrawingMode(board)) {
|
|
3767
3804
|
const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
3768
3805
|
start = point;
|
|
3769
|
-
const hitElement =
|
|
3806
|
+
const hitElement = getSnappingGeometry(board, point);
|
|
3770
3807
|
if (hitElement) {
|
|
3771
3808
|
sourceElement = hitElement;
|
|
3772
3809
|
}
|
|
@@ -3802,14 +3839,17 @@ const withLineCreateByDraw = (board) => {
|
|
|
3802
3839
|
return board;
|
|
3803
3840
|
};
|
|
3804
3841
|
|
|
3842
|
+
const debugKey$1 = 'debug:plait:align-for-geometry';
|
|
3843
|
+
const debugGenerator$1 = createDebugGenerator(debugKey$1);
|
|
3805
3844
|
const ALIGN_TOLERANCE = 2;
|
|
3806
3845
|
const EQUAL_SPACING = 10;
|
|
3807
3846
|
const ALIGN_SPACING = 24;
|
|
3808
|
-
class
|
|
3847
|
+
class ResizeSnapReaction {
|
|
3809
3848
|
constructor(board, activeElements) {
|
|
3810
3849
|
this.board = board;
|
|
3811
3850
|
this.activeElements = activeElements;
|
|
3812
3851
|
this.alignRectangles = this.getAlignRectangle();
|
|
3852
|
+
this.angle = getSelectionAngle(activeElements);
|
|
3813
3853
|
}
|
|
3814
3854
|
getAlignRectangle() {
|
|
3815
3855
|
const elements = findElements(this.board, {
|
|
@@ -3817,19 +3857,22 @@ class ResizeAlignReaction {
|
|
|
3817
3857
|
recursion: () => false,
|
|
3818
3858
|
isReverse: false
|
|
3819
3859
|
});
|
|
3820
|
-
return elements.map(item => this.board.getRectangle(item));
|
|
3860
|
+
return elements.map(item => getRectangleByAngle(this.board.getRectangle(item), item.angle) || this.board.getRectangle(item));
|
|
3821
3861
|
}
|
|
3822
|
-
|
|
3862
|
+
getSnapRef(resizeAlignDelta, resizeSnapOptions) {
|
|
3823
3863
|
const { deltaX, deltaY } = resizeAlignDelta;
|
|
3824
|
-
const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } =
|
|
3864
|
+
const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } = resizeSnapOptions;
|
|
3825
3865
|
const newResizeState = {
|
|
3826
3866
|
...resizeState,
|
|
3827
3867
|
endPoint: [resizeState.endPoint[0] + deltaX, resizeState.endPoint[1] + deltaY]
|
|
3828
3868
|
};
|
|
3829
3869
|
const { xZoom, yZoom } = getResizeZoom(newResizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
|
|
3830
|
-
|
|
3870
|
+
let activePoints = resizeOriginPoints.map(p => {
|
|
3831
3871
|
return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
|
|
3832
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
|
+
}
|
|
3833
3876
|
return {
|
|
3834
3877
|
deltaX,
|
|
3835
3878
|
deltaY,
|
|
@@ -3838,40 +3881,41 @@ class ResizeAlignReaction {
|
|
|
3838
3881
|
activePoints
|
|
3839
3882
|
};
|
|
3840
3883
|
}
|
|
3841
|
-
getEqualLineDelta(
|
|
3884
|
+
getEqualLineDelta(resizeSnapOptions) {
|
|
3842
3885
|
let equalLineDelta = {
|
|
3843
3886
|
deltaX: 0,
|
|
3844
3887
|
deltaY: 0
|
|
3845
3888
|
};
|
|
3846
|
-
const { isAspectRatio, activeRectangle } =
|
|
3889
|
+
const { isAspectRatio, activeRectangle } = resizeSnapOptions;
|
|
3847
3890
|
const widthAlignRectangle = this.alignRectangles.find(item => Math.abs(item.width - activeRectangle.width) < ALIGN_TOLERANCE);
|
|
3848
3891
|
if (widthAlignRectangle) {
|
|
3849
3892
|
const deltaWidth = widthAlignRectangle.width - activeRectangle.width;
|
|
3850
|
-
equalLineDelta.deltaX = deltaWidth *
|
|
3893
|
+
equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
|
|
3851
3894
|
if (isAspectRatio) {
|
|
3852
3895
|
const deltaHeight = deltaWidth / (activeRectangle.width / activeRectangle.height);
|
|
3853
|
-
equalLineDelta.deltaY = deltaHeight *
|
|
3896
|
+
equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
|
|
3854
3897
|
return equalLineDelta;
|
|
3855
3898
|
}
|
|
3856
3899
|
}
|
|
3857
3900
|
const heightAlignRectangle = this.alignRectangles.find(item => Math.abs(item.height - activeRectangle.height) < ALIGN_TOLERANCE);
|
|
3858
3901
|
if (heightAlignRectangle) {
|
|
3859
3902
|
const deltaHeight = heightAlignRectangle.height - activeRectangle.height;
|
|
3860
|
-
equalLineDelta.deltaY = deltaHeight *
|
|
3903
|
+
equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
|
|
3861
3904
|
if (isAspectRatio) {
|
|
3862
3905
|
const deltaWidth = deltaHeight * (activeRectangle.width / activeRectangle.height);
|
|
3863
|
-
equalLineDelta.deltaX = deltaWidth *
|
|
3906
|
+
equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
|
|
3864
3907
|
return equalLineDelta;
|
|
3865
3908
|
}
|
|
3866
3909
|
}
|
|
3867
3910
|
return equalLineDelta;
|
|
3868
3911
|
}
|
|
3869
|
-
drawEqualLines(activePoints,
|
|
3912
|
+
drawEqualLines(activePoints, resizeSnapOptions) {
|
|
3870
3913
|
let widthEqualPoints = [];
|
|
3871
3914
|
let heightEqualPoints = [];
|
|
3872
|
-
const drawHorizontalLine =
|
|
3873
|
-
const drawVerticalLine =
|
|
3874
|
-
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);
|
|
3875
3919
|
for (let alignRectangle of this.alignRectangles) {
|
|
3876
3920
|
if (activeRectangle.width === alignRectangle.width && drawHorizontalLine) {
|
|
3877
3921
|
widthEqualPoints.push(getEqualLinePoints(alignRectangle, true));
|
|
@@ -3889,12 +3933,12 @@ class ResizeAlignReaction {
|
|
|
3889
3933
|
const equalLinePoints = [...widthEqualPoints, ...heightEqualPoints];
|
|
3890
3934
|
return drawEqualLines(this.board, equalLinePoints);
|
|
3891
3935
|
}
|
|
3892
|
-
getAlignLineDelta(
|
|
3936
|
+
getAlignLineDelta(resizeSnapOptions) {
|
|
3893
3937
|
let alignLineDelta = {
|
|
3894
3938
|
deltaX: 0,
|
|
3895
3939
|
deltaY: 0
|
|
3896
3940
|
};
|
|
3897
|
-
const { isAspectRatio, activeRectangle, directionFactors } =
|
|
3941
|
+
const { isAspectRatio, activeRectangle, directionFactors } = resizeSnapOptions;
|
|
3898
3942
|
const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
|
|
3899
3943
|
const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
|
|
3900
3944
|
if (drawHorizontal) {
|
|
@@ -3923,9 +3967,12 @@ class ResizeAlignReaction {
|
|
|
3923
3967
|
}
|
|
3924
3968
|
return alignLineDelta;
|
|
3925
3969
|
}
|
|
3926
|
-
drawAlignLines(activePoints,
|
|
3970
|
+
drawAlignLines(activePoints, resizeSnapOptions) {
|
|
3971
|
+
debugGenerator$1.isDebug() && debugGenerator$1.clear();
|
|
3927
3972
|
let alignLinePoints = [];
|
|
3928
|
-
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' });
|
|
3929
3976
|
const alignAxisX = getTripleAlignAxis(activeRectangle, true);
|
|
3930
3977
|
const alignAxisY = getTripleAlignAxis(activeRectangle, false);
|
|
3931
3978
|
const alignLineRefs = [
|
|
@@ -3963,11 +4010,12 @@ class ResizeAlignReaction {
|
|
|
3963
4010
|
alignLinePoints.push([pointStart, pointEnd]);
|
|
3964
4011
|
}
|
|
3965
4012
|
};
|
|
3966
|
-
const { isAspectRatio, directionFactors } =
|
|
4013
|
+
const { isAspectRatio, directionFactors } = resizeSnapOptions;
|
|
3967
4014
|
const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
|
|
3968
4015
|
const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
|
|
3969
4016
|
for (let index = 0; index < this.alignRectangles.length; index++) {
|
|
3970
4017
|
const element = this.alignRectangles[index];
|
|
4018
|
+
debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, element);
|
|
3971
4019
|
if (isAlign(alignLineRefs[0].axis, element, alignLineRefs[0].isHorizontal)) {
|
|
3972
4020
|
alignLineRefs[0].alignRectangles.push(element);
|
|
3973
4021
|
}
|
|
@@ -4007,15 +4055,15 @@ class ResizeAlignReaction {
|
|
|
4007
4055
|
}
|
|
4008
4056
|
return drawAlignLines(this.board, alignLinePoints);
|
|
4009
4057
|
}
|
|
4010
|
-
|
|
4058
|
+
handleResizeSnap(resizeSnapOptions) {
|
|
4011
4059
|
const alignG = createG();
|
|
4012
|
-
let alignLineDelta = this.getEqualLineDelta(
|
|
4060
|
+
let alignLineDelta = this.getEqualLineDelta(resizeSnapOptions);
|
|
4013
4061
|
if (alignLineDelta.deltaX === 0 && alignLineDelta.deltaY === 0) {
|
|
4014
|
-
alignLineDelta = this.getAlignLineDelta(
|
|
4062
|
+
alignLineDelta = this.getAlignLineDelta(resizeSnapOptions);
|
|
4015
4063
|
}
|
|
4016
|
-
const equalLineRef = this.
|
|
4017
|
-
const equalLinesG = this.drawEqualLines(equalLineRef.activePoints,
|
|
4018
|
-
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);
|
|
4019
4067
|
alignG.append(equalLinesG, alignLinesG);
|
|
4020
4068
|
return { ...equalLineRef, alignG };
|
|
4021
4069
|
}
|
|
@@ -4115,8 +4163,7 @@ function getNearestAlignRectangle(alignRectangles, activeRectangle) {
|
|
|
4115
4163
|
});
|
|
4116
4164
|
return nearestRectangle;
|
|
4117
4165
|
}
|
|
4118
|
-
|
|
4119
|
-
function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
|
|
4166
|
+
function getResizeSnapRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
|
|
4120
4167
|
const { originPoint, handlePoint } = resizeOriginPointAndHandlePoint;
|
|
4121
4168
|
const { xZoom, yZoom } = getResizeZoom(resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
|
|
4122
4169
|
let activeElements;
|
|
@@ -4133,11 +4180,12 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
|
|
|
4133
4180
|
const points = resizeOriginPoints.map(p => {
|
|
4134
4181
|
return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
|
|
4135
4182
|
});
|
|
4136
|
-
const activeRectangle = RectangleClient.getRectangleByPoints(points)
|
|
4137
|
-
|
|
4183
|
+
const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(points), getSelectionAngle(activeElements)) ||
|
|
4184
|
+
RectangleClient.getRectangleByPoints(points);
|
|
4185
|
+
const resizeSnapReaction = new ResizeSnapReaction(board, activeElements);
|
|
4138
4186
|
const resizeHandlePoint = movePointByZoomAndOriginPoint(handlePoint, originPoint, xZoom, yZoom);
|
|
4139
4187
|
const [x, y] = getUnitVectorByPointAndPoint(originPoint, resizeHandlePoint);
|
|
4140
|
-
return
|
|
4188
|
+
return resizeSnapReaction.handleResizeSnap({
|
|
4141
4189
|
resizeState,
|
|
4142
4190
|
resizeOriginPoints,
|
|
4143
4191
|
activeRectangle,
|
|
@@ -4152,9 +4200,11 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
|
|
|
4152
4200
|
const debugKey = 'debug:plait:resize-for-rotation';
|
|
4153
4201
|
const debugGenerator = createDebugGenerator(debugKey);
|
|
4154
4202
|
function withDrawResize(board) {
|
|
4155
|
-
const { afterChange } = board;
|
|
4203
|
+
const { afterChange, drawActiveRectangle } = board;
|
|
4156
4204
|
let alignG;
|
|
4157
4205
|
let handleG;
|
|
4206
|
+
let needCustomActiveRectangle = false;
|
|
4207
|
+
let resizeActivePoints = null;
|
|
4158
4208
|
const canResize = () => {
|
|
4159
4209
|
const elements = getSelectedElements(board);
|
|
4160
4210
|
return elements.length > 1 && elements.every(el => PlaitDrawElement.isDrawElement(el));
|
|
@@ -4197,10 +4247,11 @@ function withDrawResize(board) {
|
|
|
4197
4247
|
resizeState.startPoint = rotatedStartPoint;
|
|
4198
4248
|
resizeState.endPoint = rotateEndPoint;
|
|
4199
4249
|
}
|
|
4200
|
-
const resizeAlignRef =
|
|
4250
|
+
const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
|
|
4201
4251
|
originPoint,
|
|
4202
4252
|
handlePoint
|
|
4203
4253
|
}, isAspectRatio, isFromCorner);
|
|
4254
|
+
resizeActivePoints = resizeAlignRef.activePoints;
|
|
4204
4255
|
alignG = resizeAlignRef.alignG;
|
|
4205
4256
|
PlaitBoard.getElementActiveHost(board).append(alignG);
|
|
4206
4257
|
if (bulkRotationRef) {
|
|
@@ -4235,9 +4286,17 @@ function withDrawResize(board) {
|
|
|
4235
4286
|
points = rotatedDataPoints(adjustTargetPoints, bulkRotationRef.newCenterPoint, bulkRotationRef.angle);
|
|
4236
4287
|
}
|
|
4237
4288
|
else {
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
}
|
|
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
|
+
}
|
|
4241
4300
|
}
|
|
4242
4301
|
if (PlaitDrawElement.isGeometry(target)) {
|
|
4243
4302
|
const { height: textHeight } = getFirstTextManage(target).getSize();
|
|
@@ -4264,6 +4323,12 @@ function withDrawResize(board) {
|
|
|
4264
4323
|
afterResize: (resizeRef) => {
|
|
4265
4324
|
alignG?.remove();
|
|
4266
4325
|
alignG = null;
|
|
4326
|
+
if (needCustomActiveRectangle) {
|
|
4327
|
+
needCustomActiveRectangle = false;
|
|
4328
|
+
resizeActivePoints = null;
|
|
4329
|
+
const selectedElements = getSelectedElements(board);
|
|
4330
|
+
Transforms.addSelectionWithTemporaryElements(board, selectedElements);
|
|
4331
|
+
}
|
|
4267
4332
|
}
|
|
4268
4333
|
};
|
|
4269
4334
|
withResize(board, options);
|
|
@@ -4276,7 +4341,9 @@ function withDrawResize(board) {
|
|
|
4276
4341
|
if (canResize() && !isSelectionMoving(board)) {
|
|
4277
4342
|
handleG = createG();
|
|
4278
4343
|
const elements = getSelectedElements(board);
|
|
4279
|
-
const boundingRectangle =
|
|
4344
|
+
const boundingRectangle = needCustomActiveRectangle
|
|
4345
|
+
? RectangleClient.getRectangleByPoints(resizeActivePoints)
|
|
4346
|
+
: getRectangleByElements(board, elements, false);
|
|
4280
4347
|
let corners = RectangleClient.getCornerPoints(boundingRectangle);
|
|
4281
4348
|
const angle = getSelectionAngle(elements);
|
|
4282
4349
|
if (angle) {
|
|
@@ -4290,6 +4357,16 @@ function withDrawResize(board) {
|
|
|
4290
4357
|
PlaitBoard.getElementActiveHost(board).append(handleG);
|
|
4291
4358
|
}
|
|
4292
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
|
+
};
|
|
4293
4370
|
return board;
|
|
4294
4371
|
}
|
|
4295
4372
|
const getResizeOriginPointAndHandlePoint = (board, resizeRef) => {
|
|
@@ -4345,6 +4422,24 @@ const movePointByZoomAndOriginPoint = (p, resizeOriginPoint, xZoom, yZoom) => {
|
|
|
4345
4422
|
const offsetY = (p[1] - resizeOriginPoint[1]) * yZoom;
|
|
4346
4423
|
return [p[0] + offsetX, p[1] + offsetY];
|
|
4347
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
|
+
};
|
|
4348
4443
|
|
|
4349
4444
|
const withGeometryResize = (board) => {
|
|
4350
4445
|
let alignG;
|
|
@@ -4376,26 +4471,19 @@ const withGeometryResize = (board) => {
|
|
|
4376
4471
|
},
|
|
4377
4472
|
onResize: (resizeRef, resizeState) => {
|
|
4378
4473
|
const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeRef.element.points));
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -resizeRef.element.angle);
|
|
4382
|
-
resizeState.startPoint = rotatedStartPoint;
|
|
4383
|
-
resizeState.endPoint = rotateEndPoint;
|
|
4384
|
-
}
|
|
4474
|
+
resizeState.startPoint = rotateAntiPointsByElement(resizeState.startPoint, resizeRef.element) || resizeState.startPoint;
|
|
4475
|
+
resizeState.endPoint = rotateAntiPointsByElement(resizeState.endPoint, resizeRef.element) || resizeState.endPoint;
|
|
4385
4476
|
alignG?.remove();
|
|
4386
4477
|
const isFromCorner = isCornerHandle(board, resizeRef.handle);
|
|
4387
4478
|
const isAspectRatio = resizeState.isShift || PlaitDrawElement.isImage(resizeRef.element);
|
|
4388
4479
|
const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
|
|
4389
|
-
const resizeAlignRef =
|
|
4480
|
+
const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
|
|
4390
4481
|
originPoint,
|
|
4391
4482
|
handlePoint
|
|
4392
4483
|
}, isAspectRatio, isFromCorner);
|
|
4393
4484
|
alignG = resizeAlignRef.alignG;
|
|
4394
4485
|
PlaitBoard.getElementActiveHost(board).append(alignG);
|
|
4395
4486
|
let points = resizeAlignRef.activePoints;
|
|
4396
|
-
if (angle) {
|
|
4397
|
-
points = resetPointsAfterResize(resizeRef.rectangle, RectangleClient.getRectangleByPoints(points), centerPoint, RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(points)), angle);
|
|
4398
|
-
}
|
|
4399
4487
|
if (PlaitDrawElement.isGeometry(resizeRef.element)) {
|
|
4400
4488
|
const { height: textHeight } = getFirstTextManage(resizeRef.element).getSize();
|
|
4401
4489
|
DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
|
|
@@ -4448,8 +4536,7 @@ const withLineResize = (board) => {
|
|
|
4448
4536
|
resizeRef.handle !== LineResizeHandle.source &&
|
|
4449
4537
|
resizeRef.handle !== LineResizeHandle.target) {
|
|
4450
4538
|
const params = getElbowLineRouteOptions(board, resizeRef.element);
|
|
4451
|
-
|
|
4452
|
-
if (isIntersect) {
|
|
4539
|
+
if (isUseDefaultOrthogonalRoute(resizeRef.element, params)) {
|
|
4453
4540
|
return;
|
|
4454
4541
|
}
|
|
4455
4542
|
const points = [...resizeRef.element.points];
|
|
@@ -4468,12 +4555,12 @@ const withLineResize = (board) => {
|
|
|
4468
4555
|
let source = { ...resizeRef.element.source };
|
|
4469
4556
|
let target = { ...resizeRef.element.target };
|
|
4470
4557
|
let handleIndex = resizeRef.handleIndex;
|
|
4471
|
-
const hitElement =
|
|
4558
|
+
const hitElement = getSnappingGeometry(board, resizeState.endPoint);
|
|
4472
4559
|
if (resizeRef.handle === LineResizeHandle.source || resizeRef.handle === LineResizeHandle.target) {
|
|
4473
4560
|
const object = resizeRef.handle === LineResizeHandle.source ? source : target;
|
|
4474
4561
|
points[handleIndex] = resizeState.endPoint;
|
|
4475
4562
|
if (hitElement) {
|
|
4476
|
-
object.connection =
|
|
4563
|
+
object.connection = getHitConnection(board, resizeState.endPoint, hitElement);
|
|
4477
4564
|
object.boundId = hitElement.id;
|
|
4478
4565
|
}
|
|
4479
4566
|
else {
|
|
@@ -4515,7 +4602,8 @@ const withLineResize = (board) => {
|
|
|
4515
4602
|
const newPoints = [...points];
|
|
4516
4603
|
newPoints[0] = drawPoints[0];
|
|
4517
4604
|
newPoints[newPoints.length - 1] = drawPoints[drawPoints.length - 1];
|
|
4518
|
-
if (resizeRef.element.shape !== LineShape.elbow
|
|
4605
|
+
if (resizeRef.element.shape !== LineShape.elbow ||
|
|
4606
|
+
(resizeRef.element.shape === LineShape.elbow && newPoints.length === 2)) {
|
|
4519
4607
|
newPoints.forEach((point, index) => {
|
|
4520
4608
|
if (index === handleIndex)
|
|
4521
4609
|
return;
|
|
@@ -4579,25 +4667,24 @@ const withLineBoundReaction = (board) => {
|
|
|
4579
4667
|
return PlaitDrawElement.isLine(element) && isSourceOrTarget;
|
|
4580
4668
|
});
|
|
4581
4669
|
if (isLinePointer || isLineResizing) {
|
|
4582
|
-
const hitElement =
|
|
4670
|
+
const hitElement = getHitGeometry(board, movingPoint);
|
|
4583
4671
|
if (hitElement) {
|
|
4584
|
-
const
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
}
|
|
4596
|
-
boundShapeG.appendChild(circleG);
|
|
4597
|
-
PlaitBoard.getElementActiveHost(board).append(boundShapeG);
|
|
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
|
+
}
|
|
4598
4684
|
if (hasValidAngle(hitElement)) {
|
|
4599
|
-
setAngleForG(boundShapeG, RectangleClient.
|
|
4685
|
+
setAngleForG(boundShapeG, RectangleClient.getCenterPointByPoints(hitElement.points), hitElement.angle);
|
|
4600
4686
|
}
|
|
4687
|
+
PlaitBoard.getElementActiveHost(board).append(boundShapeG);
|
|
4601
4688
|
}
|
|
4602
4689
|
}
|
|
4603
4690
|
pointerMove(event);
|
|
@@ -4746,7 +4833,7 @@ const withLineAutoCompleteReaction = (board) => {
|
|
|
4746
4833
|
const selectedElements = getSelectedDrawElements(board);
|
|
4747
4834
|
const targetElement = selectedElements.length === 1 && selectedElements[0];
|
|
4748
4835
|
const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4749
|
-
if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.
|
|
4836
|
+
if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
|
|
4750
4837
|
const points = getAutoCompletePoints(targetElement);
|
|
4751
4838
|
const hitIndex = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(movingPoint, targetElement) || movingPoint, points);
|
|
4752
4839
|
const hitPoint = points[hitIndex];
|
|
@@ -4774,7 +4861,7 @@ const withLineAutoCompleteReaction = (board) => {
|
|
|
4774
4861
|
const WithLineAutoCompletePluginKey = 'plait-line-auto-complete-plugin-key';
|
|
4775
4862
|
const withLineAutoComplete = (board) => {
|
|
4776
4863
|
const { pointerDown, pointerMove, globalPointerUp } = board;
|
|
4777
|
-
let
|
|
4864
|
+
let autoCompletePoint = null;
|
|
4778
4865
|
let lineShapeG = null;
|
|
4779
4866
|
let sourceElement;
|
|
4780
4867
|
let temporaryElement;
|
|
@@ -4782,13 +4869,13 @@ const withLineAutoComplete = (board) => {
|
|
|
4782
4869
|
const selectedElements = getSelectedDrawElements(board);
|
|
4783
4870
|
const targetElement = selectedElements.length === 1 && selectedElements[0];
|
|
4784
4871
|
const clickPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4785
|
-
if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.
|
|
4872
|
+
if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
|
|
4786
4873
|
const points = getAutoCompletePoints(targetElement);
|
|
4787
4874
|
const index = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(clickPoint, targetElement) || clickPoint, points);
|
|
4788
4875
|
const hitPoint = points[index];
|
|
4789
4876
|
if (hitPoint) {
|
|
4790
4877
|
temporaryDisableSelection(board);
|
|
4791
|
-
|
|
4878
|
+
autoCompletePoint = hitPoint;
|
|
4792
4879
|
sourceElement = targetElement;
|
|
4793
4880
|
BoardTransforms.updatePointerType(board, LineShape.elbow);
|
|
4794
4881
|
}
|
|
@@ -4799,18 +4886,19 @@ const withLineAutoComplete = (board) => {
|
|
|
4799
4886
|
lineShapeG?.remove();
|
|
4800
4887
|
lineShapeG = createG();
|
|
4801
4888
|
let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
|
|
4802
|
-
if (
|
|
4803
|
-
const distance = distanceBetweenPointAndPoint(...
|
|
4889
|
+
if (autoCompletePoint && sourceElement) {
|
|
4890
|
+
const distance = distanceBetweenPointAndPoint(...(rotateAntiPointsByElement(movingPoint, sourceElement) || movingPoint), ...autoCompletePoint);
|
|
4804
4891
|
if (distance > PRESS_AND_MOVE_BUFFER) {
|
|
4805
4892
|
const rectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
|
|
4806
|
-
const shape =
|
|
4893
|
+
const shape = getElementShape(sourceElement);
|
|
4807
4894
|
const engine = getEngine(shape);
|
|
4808
|
-
let sourcePoint = startPoint;
|
|
4809
4895
|
if (engine.getNearestCrossingPoint) {
|
|
4810
|
-
const crossingPoint = engine.getNearestCrossingPoint(rectangle,
|
|
4811
|
-
|
|
4896
|
+
const crossingPoint = engine.getNearestCrossingPoint(rectangle, autoCompletePoint);
|
|
4897
|
+
autoCompletePoint = crossingPoint;
|
|
4812
4898
|
}
|
|
4813
|
-
|
|
4899
|
+
// source point must be click point
|
|
4900
|
+
const rotatedSourcePoint = rotatePointsByElement(autoCompletePoint, sourceElement) || autoCompletePoint;
|
|
4901
|
+
temporaryElement = handleLineCreating(board, LineShape.elbow, rotatedSourcePoint, movingPoint, sourceElement, lineShapeG);
|
|
4814
4902
|
}
|
|
4815
4903
|
}
|
|
4816
4904
|
pointerMove(event);
|
|
@@ -4824,9 +4912,9 @@ const withLineAutoComplete = (board) => {
|
|
|
4824
4912
|
?.afterComplete;
|
|
4825
4913
|
afterComplete && afterComplete(temporaryElement);
|
|
4826
4914
|
}
|
|
4827
|
-
if (
|
|
4915
|
+
if (autoCompletePoint) {
|
|
4828
4916
|
BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
|
|
4829
|
-
|
|
4917
|
+
autoCompletePoint = null;
|
|
4830
4918
|
}
|
|
4831
4919
|
lineShapeG?.remove();
|
|
4832
4920
|
lineShapeG = null;
|
|
@@ -4968,8 +5056,8 @@ const withDraw = (board) => {
|
|
|
4968
5056
|
}
|
|
4969
5057
|
return isAlign(element);
|
|
4970
5058
|
};
|
|
4971
|
-
board.getRelatedFragment = (elements) => {
|
|
4972
|
-
const selectedElements = getSelectedElements(board);
|
|
5059
|
+
board.getRelatedFragment = (elements, originData) => {
|
|
5060
|
+
const selectedElements = originData || getSelectedElements(board);
|
|
4973
5061
|
const lineElements = board.children.filter(element => PlaitDrawElement.isLine(element));
|
|
4974
5062
|
const activeLines = lineElements.filter(line => {
|
|
4975
5063
|
const source = selectedElements.find(element => element.id === line.source.boundId);
|
|
@@ -4977,7 +5065,7 @@ const withDraw = (board) => {
|
|
|
4977
5065
|
const isSelected = selectedElements.includes(line);
|
|
4978
5066
|
return source && target && !isSelected;
|
|
4979
5067
|
});
|
|
4980
|
-
return getRelatedFragment([...elements, ...activeLines]);
|
|
5068
|
+
return getRelatedFragment([...elements, ...activeLines], originData);
|
|
4981
5069
|
};
|
|
4982
5070
|
return withDrawResize(withLineTextMove(withLineAutoCompleteReaction(withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withLineAutoComplete(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))))))))))));
|
|
4983
5071
|
};
|
|
@@ -4986,5 +5074,5 @@ const withDraw = (board) => {
|
|
|
4986
5074
|
* Generated bundle index. Do not edit.
|
|
4987
5075
|
*/
|
|
4988
5076
|
|
|
4989
|
-
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 };
|
|
4990
5078
|
//# sourceMappingURL=plait-draw.mjs.map
|