@plait/draw 0.1.0-next.11 → 0.1.0-next.12

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, ACTIVE_STROKE_WIDTH, RectangleClient, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, arrowPoints, createPath, drawLinearPath, distanceBetweenPointAndSegments, createMask, createRect, getElementById, findElements, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, isSelectionMoving, PlaitPluginElementComponent, transformPoint, toPoint, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
1
+ import { PlaitElement, ACTIVE_STROKE_WIDTH, RectangleClient, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegment, arrowPoints, createPath, drawLinearPath, getElementById, Direction, distanceBetweenPointAndSegments, createMask, createRect, findElements, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, isSelectionMoving, PlaitPluginElementComponent, 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, getFactorByPoints, Direction, getDirectionByPoint, getPoints, getPointOnPolyline, getDirectionFactor, Generator, normalizeShapePoints, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, PRIMARY_COLOR, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint } from '@plait/common';
5
+ import { getRectangleByPoints, getFactorByPoints, getPoints, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVector90, getDirectionByVector, getDirectionFactor, Generator, normalizeShapePoints, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, PRIMARY_COLOR, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, 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';
@@ -15,6 +15,10 @@ var GeometryShape;
15
15
  GeometryShape["roundRectangle"] = "roundRectangle";
16
16
  GeometryShape["parallelogram"] = "parallelogram";
17
17
  GeometryShape["text"] = "text";
18
+ GeometryShape["triangle"] = "triangle";
19
+ GeometryShape["leftArrow"] = "leftArrow";
20
+ GeometryShape["trapezoid"] = "trapezoid";
21
+ GeometryShape["rightArrow"] = "rightArrow";
18
22
  })(GeometryShape || (GeometryShape = {}));
19
23
  const PlaitGeometry = {
20
24
  getTextEditor(element) {
@@ -62,11 +66,19 @@ const PlaitLine = {
62
66
  }
63
67
  throw new Error('can not get correctly component in get text editor');
64
68
  },
69
+ isSourceMarkOrTargetMark(line, markType, handleKey) {
70
+ if (handleKey === LineHandleKey.source) {
71
+ return line.source.marker === markType;
72
+ }
73
+ else {
74
+ return line.target.marker === markType;
75
+ }
76
+ },
65
77
  isSourceMark(line, markType) {
66
- return line.source.marker === markType;
78
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.source);
67
79
  },
68
80
  isTargetMark(line, markType) {
69
- return line.target.marker === markType;
81
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.target);
70
82
  },
71
83
  isBoundElementOfSource(line, element) {
72
84
  return line.source.boundId === element.id;
@@ -139,6 +151,10 @@ var DrawPointerType;
139
151
  DrawPointerType["roundRectangle"] = "roundRectangle";
140
152
  DrawPointerType["parallelogram"] = "parallelogram";
141
153
  DrawPointerType["ellipse"] = "ellipse";
154
+ DrawPointerType["triangle"] = "triangle";
155
+ DrawPointerType["leftArrow"] = "leftArrow";
156
+ DrawPointerType["trapezoid"] = "trapezoid";
157
+ DrawPointerType["rightArrow"] = "rightArrow";
142
158
  })(DrawPointerType || (DrawPointerType = {}));
143
159
  const GeometryPointer = [
144
160
  DrawPointerType.rectangle,
@@ -146,7 +162,11 @@ const GeometryPointer = [
146
162
  DrawPointerType.diamond,
147
163
  DrawPointerType.ellipse,
148
164
  DrawPointerType.parallelogram,
149
- DrawPointerType.roundRectangle
165
+ DrawPointerType.roundRectangle,
166
+ DrawPointerType.triangle,
167
+ DrawPointerType.leftArrow,
168
+ DrawPointerType.trapezoid,
169
+ DrawPointerType.rightArrow
150
170
  ];
151
171
 
152
172
  const getStrokeWidthByElement = (element) => {
@@ -183,9 +203,16 @@ const DiamondEngine = {
183
203
  const controlPoints = RectangleClient.getEdgeCenterPoints(rectangle);
184
204
  return isPointInPolygon(point, controlPoints);
185
205
  },
206
+ getCornerPoints(rectangle) {
207
+ return RectangleClient.getEdgeCenterPoints(rectangle);
208
+ },
186
209
  getNearestPoint(rectangle, point) {
187
- const connectorPoints = RectangleClient.getEdgeCenterPoints(rectangle);
188
- return getNearestPointBetweenPointAndSegments(point, connectorPoints);
210
+ return getNearestPointBetweenPointAndSegments(point, DiamondEngine.getCornerPoints(rectangle));
211
+ },
212
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
213
+ const corners = DiamondEngine.getCornerPoints(rectangle);
214
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
215
+ return getEdgeOnPolygonByPoint(corners, point);
189
216
  },
190
217
  getConnectorPoints(rectangle) {
191
218
  return RectangleClient.getEdgeCenterPoints(rectangle);
@@ -202,10 +229,22 @@ const EllipseEngine = {
202
229
  const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
203
230
  return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
204
231
  },
232
+ getCornerPoints(rectangle) {
233
+ return RectangleClient.getEdgeCenterPoints(rectangle);
234
+ },
205
235
  getNearestPoint(rectangle, point) {
206
236
  const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
207
237
  return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
208
238
  },
239
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
240
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
241
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
242
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
243
+ const a = rectangle.width / 2;
244
+ const b = rectangle.height / 2;
245
+ const slope = getTangentSlope(point[0], point[1], a, b);
246
+ return getVectorBySlope(point[0], point[1], slope);
247
+ },
209
248
  getConnectorPoints(rectangle) {
210
249
  return RectangleClient.getEdgeCenterPoints(rectangle);
211
250
  }
@@ -245,29 +284,104 @@ function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation =
245
284
  const signY = point[1] > center[1] ? 1 : -1;
246
285
  return [center[0] + a * tx * signX, center[1] + b * ty * signY];
247
286
  }
287
+ /**
288
+ * the result of slope is based on Cartesian coordinate system
289
+ * x, y are based on the position in the Cartesian coordinate system
290
+ */
291
+ function getTangentSlope(x, y, a, b) {
292
+ const k = (-b * b * x) / (a * a * y);
293
+ return k;
294
+ }
295
+ /**
296
+ * x, y are based on the position in the Cartesian coordinate system
297
+ */
298
+ function getVectorBySlope(x, y, slope) {
299
+ const deltaX = 30;
300
+ const deltaY = -slope * deltaX;
301
+ let start = [0 - deltaX, 0 - deltaY];
302
+ let end = [0 + deltaX, 0 + deltaY];
303
+ // y < 0 acts on the lower half of the x-axis, with the starting point at the top and the end point at the bottom.
304
+ if (y < 0) {
305
+ const temp = start;
306
+ start = end;
307
+ end = temp;
308
+ }
309
+ const vector = [end[0] - start[0], end[1] - start[1]];
310
+ return vector;
311
+ }
312
+
313
+ const LeftArrowEngine = {
314
+ draw(board, rectangle, options) {
315
+ const points = getLeftArrowPoints(rectangle);
316
+ const rs = PlaitBoard.getRoughSVG(board);
317
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
318
+ setStrokeLinecap(polygon, 'round');
319
+ return polygon;
320
+ },
321
+ getCornerPoints(rectangle) {
322
+ return getLeftArrowPoints(rectangle);
323
+ },
324
+ isHit(rectangle, point) {
325
+ const points = getLeftArrowPoints(rectangle);
326
+ return isPointInPolygon(point, points);
327
+ },
328
+ getNearestPoint(rectangle, point) {
329
+ const cornerPoints = getLeftArrowPoints(rectangle);
330
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
331
+ },
332
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
333
+ const corners = getLeftArrowPoints(rectangle);
334
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
335
+ return getEdgeOnPolygonByPoint(corners, point);
336
+ },
337
+ getConnectorPoints(rectangle) {
338
+ return [
339
+ [rectangle.x, rectangle.y + rectangle.height / 2],
340
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
341
+ ];
342
+ }
343
+ };
344
+ const getLeftArrowPoints = (rectangle) => {
345
+ return [
346
+ [rectangle.x, rectangle.y + rectangle.height / 2],
347
+ [rectangle.x + rectangle.width * 0.32, rectangle.y],
348
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height * 0.2],
349
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * 0.2],
350
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * 0.8],
351
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height * 0.8],
352
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height]
353
+ ];
354
+ };
248
355
 
249
356
  const ParallelogramEngine = {
250
357
  draw(board, rectangle, options) {
251
- const points = getParallelogramPoints(rectangle);
358
+ const points = getParallelogramCornerPoints(rectangle);
252
359
  const rs = PlaitBoard.getRoughSVG(board);
253
360
  const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
254
361
  setStrokeLinecap(polygon, 'round');
255
362
  return polygon;
256
363
  },
257
364
  isHit(rectangle, point) {
258
- const parallelogramPoints = getParallelogramPoints(rectangle);
365
+ const parallelogramPoints = getParallelogramCornerPoints(rectangle);
259
366
  return isPointInPolygon(point, parallelogramPoints);
260
367
  },
368
+ getCornerPoints(rectangle) {
369
+ return getParallelogramCornerPoints(rectangle);
370
+ },
261
371
  getNearestPoint(rectangle, point) {
262
- const cornerPoints = getParallelogramPoints(rectangle);
263
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
372
+ return getNearestPointBetweenPointAndSegments(point, ParallelogramEngine.getCornerPoints(rectangle));
373
+ },
374
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
375
+ const corners = getParallelogramCornerPoints(rectangle);
376
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
377
+ return getEdgeOnPolygonByPoint(corners, point);
264
378
  },
265
379
  getConnectorPoints(rectangle) {
266
- const cornerPoints = getParallelogramPoints(rectangle);
380
+ const cornerPoints = getParallelogramCornerPoints(rectangle);
267
381
  return getCenterPointsOnPolygon(cornerPoints);
268
382
  }
269
383
  };
270
- const getParallelogramPoints = (rectangle) => {
384
+ const getParallelogramCornerPoints = (rectangle) => {
271
385
  return [
272
386
  [rectangle.x + rectangle.width / 4, rectangle.y],
273
387
  [rectangle.x + rectangle.width, rectangle.y],
@@ -284,15 +398,65 @@ const RectangleEngine = {
284
398
  const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
285
399
  return RectangleClient.isHit(rectangle, rangeRectangle);
286
400
  },
401
+ getCornerPoints(rectangle) {
402
+ return RectangleClient.getCornerPoints(rectangle);
403
+ },
287
404
  getNearestPoint(rectangle, point) {
288
- const cornerPoints = RectangleClient.getCornerPoints(rectangle);
289
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
405
+ return getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
406
+ },
407
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
408
+ const corners = RectangleEngine.getCornerPoints(rectangle);
409
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
410
+ return getEdgeOnPolygonByPoint(corners, point);
290
411
  },
291
412
  getConnectorPoints(rectangle) {
292
413
  return RectangleClient.getEdgeCenterPoints(rectangle);
293
414
  }
294
415
  };
295
416
 
417
+ const RightArrowEngine = {
418
+ draw(board, rectangle, options) {
419
+ const points = getRightArrowPoints(rectangle);
420
+ const rs = PlaitBoard.getRoughSVG(board);
421
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
422
+ setStrokeLinecap(polygon, 'round');
423
+ return polygon;
424
+ },
425
+ getCornerPoints(rectangle) {
426
+ return getRightArrowPoints(rectangle);
427
+ },
428
+ isHit(rectangle, point) {
429
+ const points = getRightArrowPoints(rectangle);
430
+ return isPointInPolygon(point, points);
431
+ },
432
+ getNearestPoint(rectangle, point) {
433
+ const cornerPoints = getRightArrowPoints(rectangle);
434
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
435
+ },
436
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
437
+ const corners = getRightArrowPoints(rectangle);
438
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
439
+ return getEdgeOnPolygonByPoint(corners, point);
440
+ },
441
+ getConnectorPoints(rectangle) {
442
+ return [
443
+ [rectangle.x, rectangle.y + rectangle.height / 2],
444
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
445
+ ];
446
+ }
447
+ };
448
+ const getRightArrowPoints = (rectangle) => {
449
+ return [
450
+ [rectangle.x, rectangle.y + rectangle.height * 0.2],
451
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.2],
452
+ [rectangle.x + rectangle.width * 0.68, rectangle.y],
453
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
454
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height],
455
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.8],
456
+ [rectangle.x, rectangle.y + rectangle.height * 0.8]
457
+ ];
458
+ };
459
+
296
460
  const RoundRectangleEngine = {
297
461
  draw(board, rectangle, options) {
298
462
  return drawRoundRectangle(PlaitBoard.getRoughSVG(board), rectangle.x, rectangle.y, rectangle.x + rectangle.width, rectangle.y + rectangle.height, { ...options, fillStyle: 'solid' }, false, getRoundRectangleRadius(rectangle));
@@ -300,9 +464,17 @@ const RoundRectangleEngine = {
300
464
  isHit(rectangle, point) {
301
465
  return isPointInRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
302
466
  },
467
+ getCornerPoints(rectangle) {
468
+ return RectangleClient.getCornerPoints(rectangle);
469
+ },
303
470
  getNearestPoint(rectangle, point) {
304
471
  return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
305
472
  },
473
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
474
+ const corners = RectangleEngine.getCornerPoints(rectangle);
475
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
476
+ return getEdgeOnPolygonByPoint(corners, point);
477
+ },
306
478
  getConnectorPoints(rectangle) {
307
479
  return RectangleClient.getEdgeCenterPoints(rectangle);
308
480
  }
@@ -340,13 +512,93 @@ function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius)
340
512
  return result;
341
513
  }
342
514
 
515
+ const TrapezoidEngine = {
516
+ draw(board, rectangle, options) {
517
+ const points = getTrapezoidPoints(rectangle);
518
+ const rs = PlaitBoard.getRoughSVG(board);
519
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
520
+ setStrokeLinecap(polygon, 'round');
521
+ return polygon;
522
+ },
523
+ isHit(rectangle, point) {
524
+ const points = getTrapezoidPoints(rectangle);
525
+ return isPointInPolygon(point, points);
526
+ },
527
+ getNearestPoint(rectangle, point) {
528
+ const cornerPoints = getTrapezoidPoints(rectangle);
529
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
530
+ },
531
+ getConnectorPoints(rectangle) {
532
+ const points = getTrapezoidPoints(rectangle);
533
+ return getCenterPointsOnPolygon(points);
534
+ },
535
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
536
+ const corners = getTrapezoidPoints(rectangle);
537
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
538
+ return getEdgeOnPolygonByPoint(corners, point);
539
+ },
540
+ getCornerPoints(rectangle) {
541
+ return getTrapezoidPoints(rectangle);
542
+ }
543
+ };
544
+ const getTrapezoidPoints = (rectangle) => {
545
+ return [
546
+ [rectangle.x + rectangle.width * 0.15, rectangle.y],
547
+ [rectangle.x + rectangle.width * 0.85, rectangle.y],
548
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
549
+ [rectangle.x, rectangle.y + rectangle.height]
550
+ ];
551
+ };
552
+
553
+ const TriangleEngine = {
554
+ draw(board, rectangle, options) {
555
+ const points = getTrianglePoints(rectangle);
556
+ const rs = PlaitBoard.getRoughSVG(board);
557
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
558
+ setStrokeLinecap(polygon, 'round');
559
+ return polygon;
560
+ },
561
+ isHit(rectangle, point) {
562
+ const points = getTrianglePoints(rectangle);
563
+ return isPointInPolygon(point, points);
564
+ },
565
+ getNearestPoint(rectangle, point) {
566
+ const cornerPoints = getTrianglePoints(rectangle);
567
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
568
+ },
569
+ getConnectorPoints(rectangle) {
570
+ const cornerPoints = getTrianglePoints(rectangle);
571
+ const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
572
+ return [...lineCenterPoints, ...cornerPoints];
573
+ },
574
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
575
+ const corners = getTrianglePoints(rectangle);
576
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
577
+ return getEdgeOnPolygonByPoint(corners, point);
578
+ },
579
+ getCornerPoints(rectangle) {
580
+ return getTrianglePoints(rectangle);
581
+ }
582
+ };
583
+ const getTrianglePoints = (rectangle) => {
584
+ return [
585
+ [rectangle.x + rectangle.width / 2, rectangle.y],
586
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
587
+ [rectangle.x, rectangle.y + rectangle.height]
588
+ ];
589
+ };
590
+
343
591
  const ShapeEngineMap = {
344
592
  [GeometryShape.rectangle]: RectangleEngine,
345
593
  [GeometryShape.diamond]: DiamondEngine,
346
594
  [GeometryShape.ellipse]: EllipseEngine,
347
595
  [GeometryShape.parallelogram]: ParallelogramEngine,
348
596
  [GeometryShape.roundRectangle]: RoundRectangleEngine,
349
- [GeometryShape.text]: RectangleEngine
597
+ [GeometryShape.text]: RectangleEngine,
598
+ [GeometryShape.triangle]: TriangleEngine,
599
+ [GeometryShape.leftArrow]: LeftArrowEngine,
600
+ [GeometryShape.trapezoid]: TrapezoidEngine,
601
+ [GeometryShape.rightArrow]: RightArrowEngine
350
602
  };
351
603
  const getEngine = (shape) => {
352
604
  return ShapeEngineMap[shape];
@@ -428,6 +680,17 @@ const getCenterPointsOnPolygon = (points) => {
428
680
  }
429
681
  return centerPoint;
430
682
  };
683
+ const getEdgeOnPolygonByPoint = (corners, point) => {
684
+ for (let index = 1; index <= corners.length; index++) {
685
+ let start = corners[index - 1];
686
+ let end = index === corners.length ? corners[0] : corners[index];
687
+ const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
688
+ if (distance < 1) {
689
+ return [start, end];
690
+ }
691
+ }
692
+ return null;
693
+ };
431
694
 
432
695
  const drawLineArrow = (element, points, options) => {
433
696
  const arrowG = createG();
@@ -531,21 +794,48 @@ const getLinePoints = (board, element) => {
531
794
  return element.shape === LineShape.elbow ? getElbowPoints(board, element) : getStraightPoints(board, element);
532
795
  };
533
796
  const getStraightPoints = (board, element) => {
534
- return [getSourcePoint(board, element), getTargetPoint(board, element)];
797
+ return getLineHandlePoints(board, element);
798
+ };
799
+ const getLineHandlePoints = (board, element) => {
800
+ const handleRefPair = getLineHandleRefPair(board, element);
801
+ return [handleRefPair.source.point, handleRefPair.target.point];
802
+ };
803
+ const getLineHandleRefPair = (board, element) => {
804
+ const strokeWidth = getStrokeWidthByElement(element);
805
+ const sourceBoundElement = element.source.boundId ? getElementById(board, element.source.boundId) : undefined;
806
+ const targetBoundElement = element.target.boundId ? getElementById(board, element.target.boundId) : undefined;
807
+ let sourcePoint = sourceBoundElement ? getConnectionPoint(sourceBoundElement, element.source.connection) : element.points[0];
808
+ let targetPoint = targetBoundElement
809
+ ? getConnectionPoint(targetBoundElement, element.target.connection)
810
+ : element.points[element.points.length - 1];
811
+ let sourceDirection = sourcePoint[0] < targetPoint[0] ? Direction.right : Direction.left;
812
+ let targetDirection = sourcePoint[0] < targetPoint[0] ? Direction.left : Direction.right;
813
+ const sourceHandleRef = { key: LineHandleKey.source, point: sourcePoint, direction: sourceDirection };
814
+ const targetHandleRef = { key: LineHandleKey.target, point: targetPoint, direction: targetDirection };
815
+ if (sourceBoundElement) {
816
+ const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.source) ? 0 : strokeWidth;
817
+ const direction = getDirectionByBoundElementAndConnection(board, sourceBoundElement, element.source.connection);
818
+ sourceDirection = direction ? direction : sourceDirection;
819
+ sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
820
+ sourceHandleRef.boundElement = sourceBoundElement;
821
+ sourceHandleRef.direction = sourceDirection;
822
+ sourceHandleRef.point = sourcePoint;
823
+ }
824
+ if (targetBoundElement) {
825
+ const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.target) ? 0 : strokeWidth;
826
+ const direction = getDirectionByBoundElementAndConnection(board, targetBoundElement, element.target.connection);
827
+ targetDirection = direction ? direction : targetDirection;
828
+ targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
829
+ targetHandleRef.boundElement = sourceBoundElement;
830
+ targetHandleRef.direction = targetDirection;
831
+ targetHandleRef.point = targetPoint;
832
+ }
833
+ return { source: sourceHandleRef, target: targetHandleRef };
535
834
  };
536
835
  const getElbowPoints = (board, element) => {
537
836
  if (element.points.length === 2) {
538
- const source = getSourcePoint(board, element);
539
- const target = getTargetPoint(board, element);
540
- let sourceDirection = source[0] < target[0] ? Direction.right : Direction.left;
541
- let targetDirection = source[0] < target[0] ? Direction.left : Direction.right;
542
- if (element.source.connection) {
543
- sourceDirection = getDirectionByPoint(element.source.connection, sourceDirection);
544
- }
545
- if (element.target.connection) {
546
- targetDirection = getDirectionByPoint(element.target.connection, targetDirection);
547
- }
548
- const points = getPoints(source, sourceDirection, target, targetDirection, 30);
837
+ const handleRefPair = getLineHandleRefPair(board, element);
838
+ const points = getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, 30);
549
839
  return points;
550
840
  }
551
841
  return element.points;
@@ -614,33 +904,42 @@ function drawMask(board, element, id) {
614
904
  maskTargetFillRect.setAttribute('opacity', '0');
615
905
  return { mask, maskTargetFillRect };
616
906
  }
617
- const getSourcePoint = (board, element) => {
618
- if (element.source.boundId) {
619
- const strokeWidth = getStrokeWidthByElement(element);
620
- const connectionOffset = PlaitLine.isSourceMark(element, LineMarkerType.none) ? 0 : strokeWidth;
621
- const boundElement = getElementById(board, element.source.boundId);
622
- return boundElement ? getConnectionPoint(boundElement, element.source.connection, connectionOffset) : element.points[0];
907
+ const getDirectionByBoundElementAndConnection = (board, boundElement, connection) => {
908
+ const rectangle = getRectangleByPoints(boundElement.points);
909
+ const engine = getEngine(boundElement.shape);
910
+ const direction = getDirectionByPointOfRectangle(connection);
911
+ if (direction) {
912
+ return direction;
623
913
  }
624
- return element.points[0];
625
- };
626
- const getTargetPoint = (board, element) => {
627
- if (element.target.boundId) {
628
- const strokeWidth = getStrokeWidthByElement(element);
629
- const connectionOffset = PlaitLine.isTargetMark(element, LineMarkerType.none) ? 0 : strokeWidth;
630
- const boundElement = getElementById(board, element.target.boundId);
631
- return boundElement
632
- ? getConnectionPoint(boundElement, element.target.connection, connectionOffset)
633
- : element.points[element.points.length - 1];
914
+ if (engine.getEdgeByConnectionPoint) {
915
+ const edge = engine.getEdgeByConnectionPoint(rectangle, connection);
916
+ if (edge) {
917
+ const vector = [edge[1][0] - edge[0][0], edge[1][1] - edge[0][1]];
918
+ const vector90 = rotateVector90(vector);
919
+ const direction = getDirectionByVector(vector90);
920
+ return direction;
921
+ }
922
+ }
923
+ if (engine.getTangentVectorByConnectionPoint) {
924
+ const vector = engine.getTangentVectorByConnectionPoint(rectangle, connection);
925
+ if (vector) {
926
+ const vector90 = rotateVector90(vector);
927
+ const direction = getDirectionByVector(vector90);
928
+ return direction;
929
+ }
634
930
  }
635
- return element.points[element.points.length - 1];
931
+ return null;
636
932
  };
637
- const getConnectionPoint = (geometry, connection, offset) => {
933
+ const getConnectionPoint = (geometry, connection, direction, delta) => {
638
934
  const rectangle = getRectangleByPoints(geometry.points);
639
- const directionFactor = getDirectionFactor(getDirectionByPoint(connection, Direction.bottom));
640
- return [
641
- rectangle.x + rectangle.width * connection[0] + directionFactor.x * offset,
642
- rectangle.y + rectangle.height * connection[1] + directionFactor.y * offset
643
- ];
935
+ if (direction && delta) {
936
+ const directionFactor = getDirectionFactor(direction);
937
+ const point = RectangleClient.getConnectionPoint(rectangle, connection);
938
+ return [point[0] + directionFactor.x * delta, point[1] + directionFactor.y * delta];
939
+ }
940
+ else {
941
+ return RectangleClient.getConnectionPoint(rectangle, connection);
942
+ }
644
943
  };
645
944
  const transformPointToConnection = (board, point, hitElement) => {
646
945
  let rectangle = getRectangleByPoints(hitElement.points);
@@ -972,8 +1271,7 @@ class LineActiveGenerator extends Generator {
972
1271
  if (this.hasResizeHandle) {
973
1272
  activeG.classList.add('active');
974
1273
  activeG.classList.add('line-handle');
975
- const sourcePoint = getSourcePoint(this.board, element);
976
- const targetPoint = getTargetPoint(this.board, element);
1274
+ const [sourcePoint, targetPoint] = getLineHandlePoints(this.board, element);
977
1275
  const sourceCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), sourcePoint, RESIZE_HANDLE_DIAMETER, {
978
1276
  stroke: '#999999',
979
1277
  strokeWidth: 1,
@@ -1596,8 +1894,7 @@ var LineResizeHandle;
1596
1894
  LineResizeHandle["target"] = "target";
1597
1895
  })(LineResizeHandle || (LineResizeHandle = {}));
1598
1896
  const getHitLineResizeHandleRef = (board, element, point) => {
1599
- const sourcePoint = getSourcePoint(board, element);
1600
- const targetPoint = getTargetPoint(board, element);
1897
+ const [sourcePoint, targetPoint] = getLineHandlePoints(board, element);
1601
1898
  const sourceRectangle = {
1602
1899
  x: sourcePoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1603
1900
  y: sourcePoint[1] - RESIZE_HANDLE_DIAMETER / 2,
@@ -1813,5 +2110,5 @@ const withDraw = (board) => {
1813
2110
  * Generated bundle index. Do not edit.
1814
2111
  */
1815
2112
 
1816
- export { DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawPointerType, DrawTransforms, GeometryComponent, GeometryPointer, GeometryShape, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, ShapeDefaultSpace, StrokeStyle, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getElbowPoints, getFillByElement, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedLineElements, getSourcePoint, getStraightPoints, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTargetPoint, getTextRectangle, isHitLineText, isHitPolyLine, transformPointToConnection, withDraw };
2113
+ export { DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawPointerType, DrawTransforms, GeometryComponent, GeometryPointer, GeometryShape, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, ShapeDefaultSpace, StrokeStyle, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getDirectionByBoundElementAndConnection, getEdgeOnPolygonByPoint, getElbowPoints, getFillByElement, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLineHandlePoints, getLineHandleRefPair, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedLineElements, getStraightPoints, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, isHitLineText, isHitPolyLine, transformPointToConnection, withDraw };
1817
2114
  //# sourceMappingURL=plait-draw.mjs.map