@plait/draw 0.1.0-next.3 → 0.1.0-next.5

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.
@@ -1,8 +1,8 @@
1
- import { PlaitElement, RectangleClient, PlaitBoard, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegments, arrowPoints, drawLinearPath, getElementById, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, PlaitPluginElementComponent, isSelectionMoving, createMask, createRect, transformPoint, toPoint, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
1
+ import { PlaitElement, RectangleClient, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegments, setPathStrokeLinecap, arrowPoints, drawLinearPath, getElementById, findElements, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, PlaitPluginElementComponent, isSelectionMoving, createMask, createRect, transformPoint, toPoint, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
2
2
  import * as i0 from '@angular/core';
3
3
  import { Component, ChangeDetectionStrategy } from '@angular/core';
4
4
  import { Subject } from 'rxjs';
5
- import { getRectangleByPoints, Direction, getDirectionByPoint, getPoints, getPointOnPolyline, Generator, normalizeShapePoints, ActiveGenerator, RESIZE_HANDLE_DIAMETER, isVirtualKey, isSpaceHotkey, CommonTransforms, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint } from '@plait/common';
5
+ import { getRectangleByPoints, Direction, getDirectionByPoint, getPoints, getPointOnPolyline, getDirectionBetweenPointAndPoint, getDirectionFactor, Generator, normalizeShapePoints, ActiveGenerator, RESIZE_HANDLE_DIAMETER, isVirtualKey, isSpaceHotkey, isDndMode, isDrawingMode, CommonTransforms, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint } from '@plait/common';
6
6
  import { Alignment, buildText, AlignEditor, TextManage, DEFAULT_FONT_SIZE, getTextFromClipboard, getTextSize } from '@plait/text';
7
7
  import { isKeyHotkey } from 'is-hotkey';
8
8
  import { Node } from 'slate';
@@ -37,6 +37,33 @@ var LineShape;
37
37
  LineShape["curve"] = "curve";
38
38
  LineShape["elbow"] = "elbow";
39
39
  })(LineShape || (LineShape = {}));
40
+ const PlaitLine = {
41
+ getTextEditors(element) {
42
+ const component = PlaitElement.getComponent(element);
43
+ if (component) {
44
+ const manage = component.textManages.find(manage => manage.isEditing);
45
+ if (manage) {
46
+ return [manage.componentRef.instance.editor];
47
+ }
48
+ else {
49
+ return component.textManages.map(manage => manage.componentRef.instance.editor);
50
+ }
51
+ }
52
+ throw new Error('can not get correctly component in get text editor');
53
+ },
54
+ isSourceMark(line, markType) {
55
+ return line.source.marker === markType;
56
+ },
57
+ isTargetMark(line, markType) {
58
+ return line.target.marker === markType;
59
+ },
60
+ isBoundElementOfSource(line, element) {
61
+ return line.source.boundId === element.id;
62
+ },
63
+ isBoundElementOfTarget(line, element) {
64
+ return line.target.boundId === element.id;
65
+ }
66
+ };
40
67
 
41
68
  const PlaitDrawElement = {
42
69
  isGeometry: (value) => {
@@ -125,7 +152,9 @@ const DiamondEngine = {
125
152
  draw(board, rectangle, options) {
126
153
  const points = RectangleClient.getEdgeCenterPoints(rectangle);
127
154
  const rs = PlaitBoard.getRoughSVG(board);
128
- return rs.polygon(points, { ...options, fillStyle: 'solid' });
155
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
156
+ setStrokeLinecap(polygon, 'round');
157
+ return polygon;
129
158
  },
130
159
  isHit(rectangle, point) {
131
160
  const controlPoints = RectangleClient.getEdgeCenterPoints(rectangle);
@@ -198,7 +227,9 @@ const ParallelogramEngine = {
198
227
  draw(board, rectangle, options) {
199
228
  const points = getParallelogramPoints(rectangle);
200
229
  const rs = PlaitBoard.getRoughSVG(board);
201
- return rs.polygon(points, { ...options, fillStyle: 'solid' });
230
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
231
+ setStrokeLinecap(polygon, 'round');
232
+ return polygon;
202
233
  },
203
234
  isHit(rectangle, point) {
204
235
  const parallelogramPoints = getParallelogramPoints(rectangle);
@@ -375,6 +406,7 @@ const getCenterPointsOnPolygon = (points) => {
375
406
  return centerPoint;
376
407
  };
377
408
 
409
+ const BOUNDED_HANDLE_OFFSET = 0.5;
378
410
  const createLineElement = (shape, points, source, target, options) => {
379
411
  return {
380
412
  id: idCreator(),
@@ -438,26 +470,32 @@ const drawElbowLine = (board, element) => {
438
470
  const elbowLine = PlaitBoard.getRoughSVG(board).linearPath(points, options);
439
471
  const path = elbowLine.querySelector('path');
440
472
  path?.setAttribute('mask', `url(#${element.id})`);
473
+ setPathStrokeLinecap(elbowLine, 'square');
441
474
  lineG.appendChild(elbowLine);
442
475
  const arrow = drawLineArrow(element, points, options);
443
476
  arrow && lineG.appendChild(arrow);
444
477
  return lineG;
445
478
  };
446
479
  const drawLineArrow = (element, points, options) => {
447
- const sourceMarker = element.source.marker;
448
- const targetMarker = element.target.marker;
449
480
  const arrowG = createG();
450
- if (sourceMarker === LineMarkerType.none && targetMarker === LineMarkerType.none)
481
+ if (PlaitLine.isSourceMark(element, LineMarkerType.none) && PlaitLine.isTargetMark(element, LineMarkerType.none)) {
451
482
  return null;
452
- if (sourceMarker === LineMarkerType.arrow) {
483
+ }
484
+ if (PlaitLine.isSourceMark(element, LineMarkerType.arrow)) {
453
485
  const sourcePoint = points[0];
454
- const { pointLeft, pointRight } = arrowPoints(points[1], sourcePoint, 10, 20);
486
+ const { pointLeft, pointRight } = arrowPoints(points[1], sourcePoint, 12, 40);
455
487
  const sourceArrow = drawLinearPath([pointLeft, sourcePoint, pointRight], options);
456
488
  arrowG.appendChild(sourceArrow);
457
489
  }
458
- if (targetMarker === LineMarkerType.arrow) {
459
- const endPoint = points[points.length - 1];
460
- const { pointLeft, pointRight } = arrowPoints(points[points.length - 2], endPoint, 10, 20);
490
+ if (PlaitLine.isTargetMark(element, LineMarkerType.arrow)) {
491
+ const _endPoint = points[points.length - 1];
492
+ const arrowDirection = getDirectionBetweenPointAndPoint(points[points.length - 2], _endPoint);
493
+ const directionFactor = getDirectionFactor(arrowDirection);
494
+ const endPoint = [
495
+ _endPoint[0] + BOUNDED_HANDLE_OFFSET * directionFactor.x,
496
+ _endPoint[1] + BOUNDED_HANDLE_OFFSET * directionFactor.y
497
+ ];
498
+ const { pointLeft, pointRight } = arrowPoints(points[points.length - 2], endPoint, 12, 40);
461
499
  const targetArrow = drawLinearPath([pointLeft, endPoint, pointRight], options);
462
500
  arrowG.appendChild(targetArrow);
463
501
  }
@@ -465,24 +503,29 @@ const drawLineArrow = (element, points, options) => {
465
503
  };
466
504
  const getSourcePoint = (board, element) => {
467
505
  if (element.source.boundId) {
506
+ const connectionOffset = PlaitLine.isSourceMark(element, LineMarkerType.arrow) ? BOUNDED_HANDLE_OFFSET : 0;
468
507
  const boundElement = getElementById(board, element.source.boundId);
469
- return boundElement ? normalizeConnection(boundElement, element.source.connection) : element.points[0];
508
+ return boundElement ? getConnectionPoint(boundElement, element.source.connection, connectionOffset) : element.points[0];
470
509
  }
471
510
  return element.points[0];
472
511
  };
473
512
  const getTargetPoint = (board, element) => {
474
513
  if (element.target.boundId) {
514
+ const connectionOffset = PlaitLine.isTargetMark(element, LineMarkerType.arrow) ? BOUNDED_HANDLE_OFFSET : 0;
475
515
  const boundElement = getElementById(board, element.target.boundId);
476
- return boundElement ? normalizeConnection(boundElement, element.target.connection) : element.points[element.points.length - 1];
516
+ return boundElement
517
+ ? getConnectionPoint(boundElement, element.target.connection, connectionOffset)
518
+ : element.points[element.points.length - 1];
477
519
  }
478
520
  return element.points[element.points.length - 1];
479
521
  };
480
- const normalizeConnection = (geometry, connection) => {
522
+ const getConnectionPoint = (geometry, connection, offset) => {
481
523
  const rectangle = getRectangleByPoints(geometry.points);
482
524
  const strokeWidth = getStrokeWidthByElement(geometry);
525
+ const directionFactor = getDirectionFactor(getDirectionByPoint(connection, Direction.bottom));
483
526
  return [
484
- rectangle.x - strokeWidth / 2 + (rectangle.width + strokeWidth) * connection[0],
485
- rectangle.y - strokeWidth / 2 + (rectangle.height + strokeWidth) * connection[1]
527
+ rectangle.x + rectangle.width * connection[0] + strokeWidth * directionFactor.x + offset * directionFactor.x,
528
+ rectangle.y + rectangle.height * connection[1] + strokeWidth * directionFactor.y + offset * directionFactor.y
486
529
  ];
487
530
  };
488
531
  const transformPointToConnection = (board, point, hitElement) => {
@@ -513,18 +556,11 @@ const getLineTextRectangle = (board, element, index) => {
513
556
  height: text.height
514
557
  };
515
558
  };
516
-
517
- var DrawCreateMode;
518
- (function (DrawCreateMode) {
519
- DrawCreateMode["drag"] = "drag";
520
- DrawCreateMode["draw"] = "draw";
521
- })(DrawCreateMode || (DrawCreateMode = {}));
522
- const BOARD_TO_CREATE_MODE = new WeakMap();
523
- const getCreateMode = (board) => {
524
- return BOARD_TO_CREATE_MODE.get(board);
525
- };
526
- const setCreateMode = (board, mode) => {
527
- BOARD_TO_CREATE_MODE.set(board, mode);
559
+ const getBoardLines = (board) => {
560
+ return findElements(board, {
561
+ match: (element) => PlaitDrawElement.isLine(element),
562
+ recursion: (element) => PlaitDrawElement.isDrawElement(element)
563
+ });
528
564
  };
529
565
 
530
566
  const getSelectedDrawElements = (board) => {
@@ -686,7 +722,7 @@ class GeometryComponent extends PlaitPluginElementComponent {
686
722
  },
687
723
  hasResizeHandle: () => {
688
724
  const selectedElements = getSelectedElements(this.board);
689
- if (PlaitBoard.hasBeenTextEditing(this.board)) {
725
+ if (PlaitBoard.hasBeenTextEditing(this.board) && PlaitDrawElement.isText(this.element)) {
690
726
  return false;
691
727
  }
692
728
  return selectedElements.length === 1 && !isSelectionMoving(this.board);
@@ -982,32 +1018,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
982
1018
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
983
1019
 
984
1020
  const withDrawHotkey = (board) => {
985
- const { keydown } = board;
1021
+ const { keydown, dblclick } = board;
986
1022
  board.keydown = (event) => {
987
1023
  const selectedElements = getSelectedElements(board);
988
1024
  const isSingleSelection = selectedElements.length === 1;
989
1025
  const targetElement = selectedElements[0];
990
- if (!isVirtualKey(event) && !isSpaceHotkey(event) && isSingleSelection && PlaitDrawElement.isDrawElement(targetElement)) {
1026
+ if (!isVirtualKey(event) && !isSpaceHotkey(event) && isSingleSelection && PlaitDrawElement.isGeometry(targetElement)) {
991
1027
  event.preventDefault();
992
1028
  PlaitElement.getComponent(targetElement).editText();
993
1029
  return;
994
1030
  }
995
1031
  keydown(event);
996
1032
  };
1033
+ board.dblclick = (event) => {
1034
+ event.preventDefault();
1035
+ const geometries = getSelectedGeometryElements(board);
1036
+ if (geometries.length === 1) {
1037
+ const component = PlaitElement.getComponent(geometries[0]);
1038
+ component.editText();
1039
+ }
1040
+ dblclick(event);
1041
+ };
997
1042
  return board;
998
1043
  };
999
1044
 
1000
1045
  const withGeometryCreateByDrag = (board) => {
1001
1046
  const { pointerMove, pointerUp } = board;
1002
- let createMode = undefined;
1003
1047
  let geometryShapeG = null;
1004
1048
  board.pointerMove = (event) => {
1005
1049
  geometryShapeG?.remove();
1006
1050
  geometryShapeG = createG();
1007
- createMode = getCreateMode(board);
1008
1051
  const geometryGenerator = new GeometryShapeGenerator(board);
1009
1052
  const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
1010
- const dragMode = isGeometryPointer && createMode === DrawCreateMode.drag;
1053
+ const dragMode = isGeometryPointer && isDndMode(board);
1011
1054
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1012
1055
  const pointer = PlaitBoard.getPointer(board);
1013
1056
  if (dragMode) {
@@ -1031,7 +1074,7 @@ const withGeometryCreateByDrag = (board) => {
1031
1074
  board.pointerUp = (event) => {
1032
1075
  const pointer = PlaitBoard.getPointer(board);
1033
1076
  const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
1034
- const dragMode = isGeometryPointer && createMode === DrawCreateMode.drag;
1077
+ const dragMode = isGeometryPointer && isDndMode(board);
1035
1078
  if (dragMode) {
1036
1079
  const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1037
1080
  const points = getDefaultGeometryPoints(pointer, targetPoint);
@@ -1065,9 +1108,8 @@ const withGeometryCreateByDraw = (board) => {
1065
1108
  keyup(event);
1066
1109
  };
1067
1110
  board.pointerDown = (event) => {
1068
- const createMode = getCreateMode(board);
1069
1111
  const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
1070
- if (isGeometryPointer && createMode === DrawCreateMode.draw) {
1112
+ if (isGeometryPointer && isDrawingMode(board)) {
1071
1113
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1072
1114
  start = point;
1073
1115
  preventTouchMove(board, true);
@@ -1159,14 +1201,44 @@ const buildClipboardData = (board, elements, startPoint) => {
1159
1201
  return { ...element, points };
1160
1202
  }
1161
1203
  if (PlaitDrawElement.isLine(element)) {
1204
+ let source = { ...element.source };
1205
+ let target = { ...element.target };
1206
+ if (element.source.boundId && !getElementById(board, element.source.boundId, elements)) {
1207
+ delete source.boundId;
1208
+ delete source.connection;
1209
+ }
1210
+ if (element.target.boundId && !getElementById(board, element.target.boundId, elements)) {
1211
+ delete target.boundId;
1212
+ delete target.connection;
1213
+ }
1162
1214
  const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
1163
- return { ...element, points };
1215
+ return { ...element, points, source, target };
1164
1216
  }
1165
1217
  return element;
1166
1218
  });
1167
1219
  };
1168
1220
  const insertClipboardData = (board, elements, startPoint) => {
1169
- elements.forEach(element => {
1221
+ const lines = elements.filter(value => PlaitDrawElement.isLine(value));
1222
+ const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value));
1223
+ geometries.forEach(element => {
1224
+ const sourceLines = [];
1225
+ const targetLines = [];
1226
+ lines.forEach(line => {
1227
+ if (PlaitLine.isBoundElementOfSource(line, element)) {
1228
+ sourceLines.push(line);
1229
+ }
1230
+ if (PlaitLine.isBoundElementOfTarget(line, element)) {
1231
+ targetLines.push(line);
1232
+ }
1233
+ });
1234
+ element.id = idCreator();
1235
+ // update lines
1236
+ sourceLines.forEach(sourceLine => (sourceLine.source.boundId = element.id));
1237
+ targetLines.forEach(targetLine => (targetLine.target.boundId = element.id));
1238
+ element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
1239
+ Transforms.insertNode(board, element, [board.children.length]);
1240
+ });
1241
+ lines.forEach(element => {
1170
1242
  element.id = idCreator();
1171
1243
  element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
1172
1244
  Transforms.insertNode(board, element, [board.children.length]);
@@ -1179,10 +1251,15 @@ const withDrawFragment = (baseBoard) => {
1179
1251
  board.deleteFragment = (data) => {
1180
1252
  const drawElements = getSelectedDrawElements(board);
1181
1253
  if (drawElements.length) {
1182
- const geometryElements = drawElements.filter(value => PlaitDrawElement.isDrawElement(value));
1183
- // query bound lines
1184
- const boundLineElements = [];
1185
- CommonTransforms.removeElements(board, [...geometryElements, ...boundLineElements]);
1254
+ const lines = getBoardLines(board);
1255
+ const geometryElements = drawElements.filter(value => PlaitDrawElement.isGeometry(value));
1256
+ const lineElements = drawElements.filter(value => PlaitDrawElement.isLine(value));
1257
+ const boundLineElements = lines.filter(line => geometryElements.find(geometry => PlaitLine.isBoundElementOfSource(line, geometry) || PlaitLine.isBoundElementOfTarget(line, geometry)));
1258
+ CommonTransforms.removeElements(board, [
1259
+ ...geometryElements,
1260
+ ...lineElements,
1261
+ ...boundLineElements.filter(line => !lineElements.includes(line))
1262
+ ]);
1186
1263
  }
1187
1264
  deleteFragment(data);
1188
1265
  };
@@ -1254,9 +1331,8 @@ const withLineCreateByDraw = (board) => {
1254
1331
  let lineShapeG = null;
1255
1332
  let temporaryElement = null;
1256
1333
  board.pointerDown = (event) => {
1257
- const createMode = getCreateMode(board);
1258
1334
  const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
1259
- if (isLinePointer && createMode === DrawCreateMode.draw) {
1335
+ if (isLinePointer && isDrawingMode(board)) {
1260
1336
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1261
1337
  start = point;
1262
1338
  const hitElement = getHitOutlineGeometry(board, point, -4);
@@ -1548,6 +1624,11 @@ const withDraw = (board) => {
1548
1624
  if (PlaitDrawElement.isGeometry(element)) {
1549
1625
  return getRectangleByPoints(element.points);
1550
1626
  }
1627
+ if (PlaitDrawElement.isLine(element)) {
1628
+ const source = getSourcePoint(board, element);
1629
+ const target = getTargetPoint(board, element);
1630
+ return getRectangleByPoints([source, target]);
1631
+ }
1551
1632
  return getRectangle(element);
1552
1633
  };
1553
1634
  board.isHitSelection = (element, range) => {
@@ -1583,14 +1664,6 @@ const withDraw = (board) => {
1583
1664
  }
1584
1665
  return isMovable(element);
1585
1666
  };
1586
- board.dblclick = (event) => {
1587
- const element = getSelectedElements(board)[0];
1588
- if (element && PlaitDrawElement.isGeometry(element)) {
1589
- const component = PlaitElement.getComponent(element);
1590
- component.editText();
1591
- }
1592
- dblclick(event);
1593
- };
1594
1667
  return withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withGeometryCreateByDrag(withGeometryCreateByDraw(withDrawFragment(withDrawHotkey(board)))))))));
1595
1668
  };
1596
1669
 
@@ -1598,5 +1671,5 @@ const withDraw = (board) => {
1598
1671
  * Generated bundle index. Do not edit.
1599
1672
  */
1600
1673
 
1601
- export { DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawCreateMode, DrawPointerType, GeometryPointer, GeometryShape, GeometryThreshold, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, ShapeDefaultSpace, createGeometryElement, createLineElement, drawBoundMask, drawElbowLine, drawGeometry, drawLineArrow, getCenterPointsOnPolygon, getCreateMode, getElbowPoints, getHitConnectorPoint, getHitLineTextIndex, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedLineElements, getSourcePoint, getTargetPoint, getTextRectangle, isHitLineText, isHitPolyLine, normalizeConnection, setCreateMode, transformPointToConnection, withDraw };
1674
+ export { DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawPointerType, GeometryComponent, GeometryPointer, GeometryShape, GeometryThreshold, LineComponent, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, ShapeDefaultSpace, createGeometryElement, createLineElement, drawBoundMask, drawElbowLine, drawGeometry, drawLineArrow, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getElbowPoints, getHitConnectorPoint, getHitLineTextIndex, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedLineElements, getSourcePoint, getTargetPoint, getTextRectangle, isHitLineText, isHitPolyLine, transformPointToConnection, withDraw };
1602
1675
  //# sourceMappingURL=plait-draw.mjs.map