@leafer-in/linker 2.3.1 → 2.3.3

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/dist/linker.cjs CHANGED
@@ -21,7 +21,7 @@ class LinkerData extends draw.LineData {
21
21
  }
22
22
  }
23
23
 
24
- const {directionData: directionData} = draw.AroundHelper;
24
+ const {directionData: directionData$1} = draw.AroundHelper;
25
25
 
26
26
  const directionNames = [ "top-left", "top", "top-right", "right", "bottom-right", "bottom", "bottom-left", "left", "center" ];
27
27
 
@@ -137,8 +137,8 @@ function getPointDirection(boxPoint, bounds, eight) {
137
137
  const {width: width, height: height} = bounds;
138
138
  const hitRadiusX = width / 4;
139
139
  const hitRadiusY = height / 4;
140
- for (let i = 0; i < directionData.length; i++) {
141
- const unit = directionData[i];
140
+ for (let i = 0; i < directionData$1.length; i++) {
141
+ const unit = directionData$1[i];
142
142
  const px = unit.x * width;
143
143
  const py = unit.y * height;
144
144
  const dx = boxPoint.x - px;
@@ -183,7 +183,386 @@ function linkerPointType(defaultValue) {
183
183
  }));
184
184
  }
185
185
 
186
- const {moveTo: moveTo, bezierCurveTo: bezierCurveTo, drawPoints: drawPoints$1} = draw.PathCommandDataHelper;
186
+ const {directionData: directionData} = draw.AroundHelper;
187
+
188
+ const {moveTo: moveTo$1, lineTo: lineTo$1} = draw.PathCommandDataHelper;
189
+
190
+ const POLYLINE_X = 0, POLYLINE_Y = 1;
191
+
192
+ const POLYLINE_EPSILON = .001;
193
+
194
+ const POLYLINE_MIN_SEGMENT = 4;
195
+
196
+ const POLYLINE_TURN_WEIGHT = 1.5;
197
+
198
+ function getPolylineDirectionIndex(direction) {
199
+ switch (direction) {
200
+ case "top-left":
201
+ return 0;
202
+
203
+ case "top":
204
+ return 1;
205
+
206
+ case "top-right":
207
+ return 2;
208
+
209
+ case "right":
210
+ return 3;
211
+
212
+ case "bottom-right":
213
+ return 4;
214
+
215
+ case "bottom":
216
+ return 5;
217
+
218
+ case "bottom-left":
219
+ return 6;
220
+
221
+ case "left":
222
+ return 7;
223
+
224
+ default:
225
+ return 8;
226
+ }
227
+ }
228
+
229
+ function getPolylinePorts(direction, point, target, bounds, targetBounds, ports) {
230
+ const data = directionData[getPolylineDirectionIndex(direction)];
231
+ const dx = Math.sign(data.x - .5), dy = Math.sign(data.y - .5);
232
+ const cx = bounds ? bounds.x + bounds.width / 2 : point.x;
233
+ const cy = bounds ? bounds.y + bounds.height / 2 : point.y;
234
+ const tx = targetBounds ? targetBounds.x + targetBounds.width / 2 : target.x;
235
+ const ty = targetBounds ? targetBounds.y + targetBounds.height / 2 : target.y;
236
+ const deltaX = tx - cx, deltaY = ty - cy;
237
+ const xSign = dx || (deltaX >= 0 ? 1 : -1);
238
+ const ySign = dy || (deltaY >= 0 ? 1 : -1);
239
+ const xPort = POLYLINE_X * 2 + (xSign > 0 ? 1 : 0);
240
+ const yPort = POLYLINE_Y * 2 + (ySign > 0 ? 1 : 0);
241
+ if (dx && !dy) {
242
+ ports[0] = xPort;
243
+ return 1;
244
+ }
245
+ if (dy && !dx) {
246
+ ports[0] = yPort;
247
+ return 1;
248
+ }
249
+ if (Math.abs(deltaX) >= Math.abs(deltaY)) {
250
+ ports[0] = xPort;
251
+ ports[1] = yPort;
252
+ } else {
253
+ ports[0] = yPort;
254
+ ports[1] = xPort;
255
+ }
256
+ return 2;
257
+ }
258
+
259
+ function getPolylineExit(point, bounds, port, clearance, result) {
260
+ const axis = port >> 1, sign = port & 1 ? 1 : -1;
261
+ if (axis === POLYLINE_X) {
262
+ const boundary = bounds ? sign > 0 ? bounds.x + bounds.width : bounds.x : point.x;
263
+ result[0] = boundary + sign * clearance;
264
+ result[1] = point.y;
265
+ } else {
266
+ const boundary = bounds ? sign > 0 ? bounds.y + bounds.height : bounds.y : point.y;
267
+ result[0] = point.x;
268
+ result[1] = boundary + sign * clearance;
269
+ }
270
+ }
271
+
272
+ function isPolylinePointBlocked(x, y, bounds, clearance) {
273
+ if (!bounds) return false;
274
+ const left = bounds.x - clearance, right = bounds.x + bounds.width + clearance;
275
+ const top = bounds.y - clearance, bottom = bounds.y + bounds.height + clearance;
276
+ return x > left + POLYLINE_EPSILON && x < right - POLYLINE_EPSILON && y > top + POLYLINE_EPSILON && y < bottom - POLYLINE_EPSILON;
277
+ }
278
+
279
+ function isPolylineSegmentBlocked(x1, y1, x2, y2, bounds, clearance) {
280
+ if (!bounds) return false;
281
+ const left = bounds.x - clearance, right = bounds.x + bounds.width + clearance;
282
+ const top = bounds.y - clearance, bottom = bounds.y + bounds.height + clearance;
283
+ if (Math.abs(y1 - y2) <= POLYLINE_EPSILON) {
284
+ return y1 > top + POLYLINE_EPSILON && y1 < bottom - POLYLINE_EPSILON && Math.max(Math.min(x1, x2), left + POLYLINE_EPSILON) < Math.min(Math.max(x1, x2), right - POLYLINE_EPSILON);
285
+ }
286
+ if (Math.abs(x1 - x2) <= POLYLINE_EPSILON) {
287
+ return x1 > left + POLYLINE_EPSILON && x1 < right - POLYLINE_EPSILON && Math.max(Math.min(y1, y2), top + POLYLINE_EPSILON) < Math.min(Math.max(y1, y2), bottom - POLYLINE_EPSILON);
288
+ }
289
+ return true;
290
+ }
291
+
292
+ function addPolylineBoundsCoordinates(xs, ys, bounds, clearance, margin) {
293
+ if (!bounds) return;
294
+ const left = bounds.x - clearance, right = bounds.x + bounds.width + clearance;
295
+ const top = bounds.y - clearance, bottom = bounds.y + bounds.height + clearance;
296
+ xs.push(left, right, left - margin, right + margin);
297
+ ys.push(top, bottom, top - margin, bottom + margin);
298
+ }
299
+
300
+ function sortPolylineCoordinates(values) {
301
+ values.sort((a, b) => a - b);
302
+ let write = 0;
303
+ for (let i = 0; i < values.length; i++) {
304
+ if (!write || Math.abs(values[i] - values[write - 1]) > POLYLINE_EPSILON) values[write++] = values[i];
305
+ }
306
+ values.length = write;
307
+ }
308
+
309
+ function getPolylineCoordinateIndex(values, value) {
310
+ for (let i = 0; i < values.length; i++) {
311
+ if (Math.abs(values[i] - value) <= POLYLINE_EPSILON) return i;
312
+ }
313
+ return -1;
314
+ }
315
+
316
+ function getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey) {
317
+ const startAxis = startPort >> 1, endAxis = endPort >> 1;
318
+ const startSign = startPort & 1 ? 1 : -1, endSign = endPort & 1 ? 1 : -1;
319
+ if (startAxis === endAxis && startSign === -endSign) return startAxis;
320
+ return Math.abs(ex - sx) >= Math.abs(ey - sy) ? POLYLINE_X : POLYLINE_Y;
321
+ }
322
+
323
+ function getPolylineMidpointRoute(result, startPoint, endPoint, sx, sy, ex, ey, midpointAxis, startBounds, endBounds, clearance) {
324
+ const midpointX = (sx + ex) / 2, midpointY = (sy + ey) / 2;
325
+ result.length = 0;
326
+ result.push(startPoint.x, startPoint.y, sx, sy);
327
+ if (midpointAxis === POLYLINE_X) {
328
+ result.push(midpointX, sy, midpointX, ey);
329
+ } else {
330
+ result.push(sx, midpointY, ex, midpointY);
331
+ }
332
+ result.push(ex, ey, endPoint.x, endPoint.y);
333
+ for (let i = 4; i < result.length - 2; i += 2) {
334
+ const x1 = result[i - 2], y1 = result[i - 1];
335
+ const x2 = result[i], y2 = result[i + 1];
336
+ if (isPolylineSegmentBlocked(x1, y1, x2, y2, startBounds, clearance) || isPolylineSegmentBlocked(x1, y1, x2, y2, endBounds, clearance)) return Infinity;
337
+ }
338
+ return getPolylineScore(result, clearance);
339
+ }
340
+
341
+ function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, startBounds, endBounds, clearance) {
342
+ const startExit = [], endExit = [];
343
+ getPolylineExit(startPoint, startBounds, startPort, clearance, startExit);
344
+ getPolylineExit(endPoint, endBounds, endPort, clearance, endExit);
345
+ const sx = startExit[0], sy = startExit[1], ex = endExit[0], ey = endExit[1];
346
+ const startAxis = startPort >> 1, endAxis = endPort >> 1;
347
+ const startSign = startPort & 1 ? 1 : -1, endSign = endPort & 1 ? 1 : -1;
348
+ const startStub = Math.abs(sx - startPoint.x) + Math.abs(sy - startPoint.y);
349
+ const endStub = Math.abs(ex - endPoint.x) + Math.abs(ey - endPoint.y);
350
+ if (isPolylineSegmentBlocked(startPoint.x, startPoint.y, sx, sy, endBounds, clearance) || isPolylineSegmentBlocked(endPoint.x, endPoint.y, ex, ey, startBounds, clearance)) return Infinity;
351
+ const midpointAxis = getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey);
352
+ const midpointScore = getPolylineMidpointRoute(result, startPoint, endPoint, sx, sy, ex, ey, midpointAxis, startBounds, endBounds, clearance);
353
+ if (midpointScore < Infinity) return midpointScore;
354
+ const margin = Math.max(clearance, POLYLINE_MIN_SEGMENT) * 2;
355
+ const xs = [ sx, ex, (sx + ex) / 2 ], ys = [ sy, ey, (sy + ey) / 2 ];
356
+ addPolylineBoundsCoordinates(xs, ys, startBounds, clearance, margin);
357
+ addPolylineBoundsCoordinates(xs, ys, endBounds, clearance, margin);
358
+ let minX = Math.min(...xs), maxX = Math.max(...xs);
359
+ let minY = Math.min(...ys), maxY = Math.max(...ys);
360
+ xs.push(minX - margin * 2, maxX + margin * 2);
361
+ ys.push(minY - margin * 2, maxY + margin * 2);
362
+ sortPolylineCoordinates(xs);
363
+ sortPolylineCoordinates(ys);
364
+ const nx = xs.length, ny = ys.length;
365
+ const startXIndex = getPolylineCoordinateIndex(xs, sx), startYIndex = getPolylineCoordinateIndex(ys, sy);
366
+ const endXIndex = getPolylineCoordinateIndex(xs, ex), endYIndex = getPolylineCoordinateIndex(ys, ey);
367
+ if (startXIndex < 0 || startYIndex < 0 || endXIndex < 0 || endYIndex < 0) return Infinity;
368
+ const startNode = startYIndex * nx + startXIndex, endNode = endYIndex * nx + endXIndex;
369
+ const total = nx * ny * 3;
370
+ const distance = new Float64Array(total), previous = new Int32Array(total), visited = new Uint8Array(total);
371
+ distance.fill(Infinity);
372
+ previous.fill(-1);
373
+ const startState = startNode * 3;
374
+ distance[startState] = 0;
375
+ const turnCost = Math.max(POLYLINE_MIN_SEGMENT, clearance * POLYLINE_TURN_WEIGHT);
376
+ let currentState = -1, currentNode = -1, currentAxis = 0;
377
+ let currentX = 0, currentY = 0, currentDistance = 0;
378
+ const relax = (nextXIndex, nextYIndex, axis, sign) => {
379
+ const nextX = xs[nextXIndex], nextY = ys[nextYIndex];
380
+ const nextNode = nextYIndex * nx + nextXIndex;
381
+ if (isPolylinePointBlocked(nextX, nextY, startBounds, clearance) || isPolylinePointBlocked(nextX, nextY, endBounds, clearance)) return;
382
+ if (isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, startBounds, clearance) || isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, endBounds, clearance)) return;
383
+ if (currentState === startState) {
384
+ if (axis === startAxis + 1) {
385
+ if (sign !== startSign) return;
386
+ } else if (startStub <= POLYLINE_EPSILON) return;
387
+ }
388
+ if (nextNode === endNode) {
389
+ if (axis === endAxis + 1) {
390
+ if (sign !== -endSign) return;
391
+ } else if (endStub <= POLYLINE_EPSILON) return;
392
+ }
393
+ const nextState = nextNode * 3 + axis;
394
+ if (visited[nextState]) return;
395
+ const segmentLength = Math.abs(nextX - currentX) + Math.abs(nextY - currentY);
396
+ let cost = currentDistance + segmentLength;
397
+ if (currentAxis && currentAxis !== axis) {
398
+ cost += turnCost;
399
+ const turnCoordinate = currentAxis === POLYLINE_X + 1 ? currentX : currentY;
400
+ const preferredCoordinate = midpointAxis === POLYLINE_X ? (sx + ex) / 2 : (sy + ey) / 2;
401
+ if (Math.abs(turnCoordinate - preferredCoordinate) > POLYLINE_EPSILON) cost += turnCost * 2;
402
+ }
403
+ if (cost < distance[nextState]) {
404
+ distance[nextState] = cost;
405
+ previous[nextState] = currentState;
406
+ }
407
+ };
408
+ let bestState = -1;
409
+ for (let iteration = 0; iteration < total; iteration++) {
410
+ let minDistance = Infinity, state = -1;
411
+ for (let i = 0; i < total; i++) {
412
+ if (!visited[i] && distance[i] < minDistance) {
413
+ minDistance = distance[i];
414
+ state = i;
415
+ }
416
+ }
417
+ if (state < 0) break;
418
+ currentState = state;
419
+ currentNode = Math.floor(state / 3);
420
+ currentAxis = state % 3;
421
+ currentDistance = minDistance;
422
+ visited[state] = 1;
423
+ if (currentNode === endNode) {
424
+ bestState = state;
425
+ break;
426
+ }
427
+ const xIndex = currentNode % nx, yIndex = Math.floor(currentNode / nx);
428
+ currentX = xs[xIndex];
429
+ currentY = ys[yIndex];
430
+ if (xIndex > 0) relax(xIndex - 1, yIndex, POLYLINE_X + 1, -1);
431
+ if (xIndex < nx - 1) relax(xIndex + 1, yIndex, POLYLINE_X + 1, 1);
432
+ if (yIndex > 0) relax(xIndex, yIndex - 1, POLYLINE_Y + 1, -1);
433
+ if (yIndex < ny - 1) relax(xIndex, yIndex + 1, POLYLINE_Y + 1, 1);
434
+ }
435
+ if (bestState < 0) return Infinity;
436
+ const reverse = [];
437
+ let state = bestState;
438
+ while (state >= 0) {
439
+ const node = Math.floor(state / 3);
440
+ reverse.push(xs[node % nx], ys[Math.floor(node / nx)]);
441
+ if (state === startState) break;
442
+ state = previous[state];
443
+ }
444
+ if (state !== startState) return Infinity;
445
+ result.length = 0;
446
+ result.push(startPoint.x, startPoint.y, sx, sy);
447
+ for (let i = reverse.length - 4; i >= 0; i -= 2) result.push(reverse[i], reverse[i + 1]);
448
+ result.push(endPoint.x, endPoint.y);
449
+ return distance[bestState] + startStub + endStub;
450
+ }
451
+
452
+ function appendPolylinePoint(points, x, y) {
453
+ const length = points.length;
454
+ if (length >= 2 && Math.abs(points[length - 2] - x) <= POLYLINE_EPSILON && Math.abs(points[length - 1] - y) <= POLYLINE_EPSILON) return;
455
+ points.push(x, y);
456
+ }
457
+
458
+ function appendPolylineOrthogonal(points, x1, y1, x2, y2, firstAxis = POLYLINE_X) {
459
+ if (Math.abs(x1 - x2) > POLYLINE_EPSILON && Math.abs(y1 - y2) > POLYLINE_EPSILON) {
460
+ if (firstAxis === POLYLINE_X) {
461
+ const midX = (x1 + x2) / 2;
462
+ appendPolylinePoint(points, midX, y1);
463
+ appendPolylinePoint(points, midX, y2);
464
+ } else {
465
+ const midY = (y1 + y2) / 2;
466
+ appendPolylinePoint(points, x1, midY);
467
+ appendPolylinePoint(points, x2, midY);
468
+ }
469
+ }
470
+ appendPolylinePoint(points, x2, y2);
471
+ }
472
+
473
+ function getPolylineEditPath(result, startPoint, endPoint, startPort, endPort, startBounds, endBounds, points, clearance) {
474
+ if (points.length % 2) return Infinity;
475
+ for (let i = 0; i < points.length; i++) if (!Number.isFinite(points[i])) return Infinity;
476
+ const startExit = [], endExit = [];
477
+ getPolylineExit(startPoint, startBounds, startPort, clearance, startExit);
478
+ getPolylineExit(endPoint, endBounds, endPort, clearance, endExit);
479
+ const sx = startExit[0], sy = startExit[1], ex = endExit[0], ey = endExit[1];
480
+ if (isPolylineSegmentBlocked(startPoint.x, startPoint.y, sx, sy, endBounds, clearance) || isPolylineSegmentBlocked(endPoint.x, endPoint.y, ex, ey, startBounds, clearance)) return Infinity;
481
+ result.length = 0;
482
+ appendPolylinePoint(result, startPoint.x, startPoint.y);
483
+ appendPolylinePoint(result, sx, sy);
484
+ let x = sx, y = sy;
485
+ for (let i = 0; i < points.length; i += 2) {
486
+ const nx = points[i], ny = points[i + 1];
487
+ appendPolylineOrthogonal(result, x, y, nx, ny, i === 0 && clearance === 0 ? startPort >> 1 : POLYLINE_X);
488
+ x = nx;
489
+ y = ny;
490
+ }
491
+ const endAxis = endPort >> 1;
492
+ if (Math.abs(x - ex) > POLYLINE_EPSILON && Math.abs(y - ey) > POLYLINE_EPSILON) {
493
+ if (endAxis === POLYLINE_X) appendPolylinePoint(result, x, ey); else appendPolylinePoint(result, ex, y);
494
+ }
495
+ appendPolylinePoint(result, ex, ey);
496
+ appendPolylinePoint(result, endPoint.x, endPoint.y);
497
+ return getPolylineScore(result, clearance);
498
+ }
499
+
500
+ function getPolylineScore(points, clearance) {
501
+ let length = 0, turns = 0, previousAxis = -1;
502
+ for (let i = 2; i < points.length; i += 2) {
503
+ const dx = points[i] - points[i - 2], dy = points[i + 1] - points[i - 1];
504
+ if (Math.abs(dx) <= POLYLINE_EPSILON && Math.abs(dy) <= POLYLINE_EPSILON) continue;
505
+ const axis = Math.abs(dx) > POLYLINE_EPSILON ? POLYLINE_X : POLYLINE_Y;
506
+ length += Math.abs(dx) + Math.abs(dy);
507
+ if (previousAxis !== -1 && previousAxis !== axis) turns++;
508
+ previousAxis = axis;
509
+ }
510
+ return length + turns * Math.max(clearance, POLYLINE_MIN_SEGMENT) * POLYLINE_TURN_WEIGHT;
511
+ }
512
+
513
+ function simplifyPolyline(points) {
514
+ let write = 2;
515
+ for (let read = 2; read < points.length; read += 2) {
516
+ const x = points[read], y = points[read + 1];
517
+ const px = points[write - 2], py = points[write - 1];
518
+ if (Math.abs(x - px) <= POLYLINE_EPSILON && Math.abs(y - py) <= POLYLINE_EPSILON) continue;
519
+ if (write >= 4) {
520
+ const ax = points[write - 4], ay = points[write - 3];
521
+ const horizontal = Math.abs(ay - py) <= POLYLINE_EPSILON && Math.abs(py - y) <= POLYLINE_EPSILON && (px - ax) * (x - px) >= 0;
522
+ const vertical = Math.abs(ax - px) <= POLYLINE_EPSILON && Math.abs(px - x) <= POLYLINE_EPSILON && (py - ay) * (y - py) >= 0;
523
+ if (horizontal || vertical) {
524
+ points[write - 2] = x;
525
+ points[write - 1] = y;
526
+ continue;
527
+ }
528
+ }
529
+ points[write++] = x;
530
+ points[write++] = y;
531
+ }
532
+ points.length = write;
533
+ }
534
+
535
+ function drawPolyline(path, startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance = 8, points) {
536
+ if (!Number.isFinite(startPoint.x) || !Number.isFinite(startPoint.y) || !Number.isFinite(endPoint.x) || !Number.isFinite(endPoint.y)) return false;
537
+ if (startBounds && (!Number.isFinite(startBounds.x) || !Number.isFinite(startBounds.y) || !Number.isFinite(startBounds.width) || !Number.isFinite(startBounds.height) || startBounds.width < 0 || startBounds.height < 0)) return false;
538
+ if (endBounds && (!Number.isFinite(endBounds.x) || !Number.isFinite(endBounds.y) || !Number.isFinite(endBounds.width) || !Number.isFinite(endBounds.height) || endBounds.width < 0 || endBounds.height < 0)) return false;
539
+ clearance = Number.isFinite(clearance) ? Math.max(0, clearance) : 8;
540
+ const startPorts = [], endPorts = [];
541
+ const startCount = getPolylinePorts(startDirection, startPoint, endPoint, startBounds, endBounds, startPorts);
542
+ const endCount = getPolylinePorts(endDirection, endPoint, startPoint, endBounds, startBounds, endPorts);
543
+ const candidate = [], best = [];
544
+ let bestScore = Infinity;
545
+ for (let pass = 0; pass < 2 && bestScore === Infinity; pass++) {
546
+ const currentClearance = pass === 0 ? clearance : 0;
547
+ for (let i = 0; i < startCount; i++) {
548
+ for (let j = 0; j < endCount; j++) {
549
+ const score = points !== undefined ? getPolylineEditPath(candidate, startPoint, endPoint, startPorts[i], endPorts[j], startBounds, endBounds, points, currentClearance) : getPolylineRoute(candidate, startPoint, endPoint, startPorts[i], endPorts[j], startBounds, endBounds, currentClearance);
550
+ if (score < bestScore) {
551
+ bestScore = score;
552
+ best.length = 0;
553
+ for (let k = 0; k < candidate.length; k++) best.push(candidate[k]);
554
+ }
555
+ }
556
+ }
557
+ }
558
+ if (!best.length) return false;
559
+ if (points === undefined) simplifyPolyline(best);
560
+ moveTo$1(path, best[0], best[1]);
561
+ for (let i = 2; i < best.length; i += 2) lineTo$1(path, best[i], best[i + 1]);
562
+ return true;
563
+ }
564
+
565
+ const {moveTo: moveTo, lineTo: lineTo, bezierCurveTo: bezierCurveTo, drawPoints: drawPoints$1} = draw.PathCommandDataHelper;
187
566
 
188
567
  const {isEmpty: isEmpty, getPoint: getPoint} = draw.BoundsHelper;
189
568
 
@@ -276,7 +655,7 @@ exports.Linker = class Linker extends draw.Line {
276
655
  }
277
656
  }
278
657
  updateLinkerPoint(type) {
279
- const {startPoint: startPoint, endPoint: endPoint} = this;
658
+ const {startPoint: startPoint, endPoint: endPoint, lineType: lineType} = this;
280
659
  const nowPoint = type === "end" ? endPoint : startPoint;
281
660
  if (nowPoint) {
282
661
  const data = {};
@@ -301,6 +680,7 @@ exports.Linker = class Linker extends draw.Line {
301
680
  if (isEmpty(boxBounds)) draw.LeafHelper.updateBounds(ui);
302
681
  p = getPoint(boxBounds, point, true);
303
682
  ui.getWorldPointByBox(p, this, false, true);
683
+ if (lineType === "polyline") data.bounds = ui.getBounds("box", this.parent);
304
684
  }
305
685
  } else {
306
686
  if (draw.isObject(point)) p = point;
@@ -326,56 +706,69 @@ exports.Linker = class Linker extends draw.Line {
326
706
  }
327
707
  const startPoint = startData.point, endPoint = endData.point;
328
708
  const startDirection = startData.direction, endDirection = endData.direction;
329
- const half = {
330
- x: abs((startPoint.x - endPoint.x) / 2),
331
- y: abs((startPoint.y - endPoint.y) / 2)
332
- };
333
709
  const arrowWidth = this.__.strokeWidth * 8;
334
- let minCtrl;
335
- if (this.__.__useArrow) {
336
- const ratio = min(getDistance(startPoint, endPoint) / (arrowWidth * 25), 1);
337
- minCtrl = max(arrowWidth * ratio * 12, arrowWidth * 3);
338
- } else {
339
- minCtrl = arrowWidth * 2;
340
- }
341
- if (endDirection) {
342
- if (isOppositeDirection(startDirection, endDirection) && startDirection === getDirectionForFromPoint(startPoint, endPoint)) {
710
+ switch (data.lineType) {
711
+ case "straight":
712
+ moveTo(path, startPoint.x, startPoint.y);
713
+ lineTo(path, endPoint.x, endPoint.y);
714
+ break;
715
+
716
+ case "polyline":
717
+ drawPolyline(path, startPoint, endPoint, startDirection, endDirection, startData.bounds, endData.bounds, arrowWidth, hasPoints && draw.PointHelper.toNumberPoints(data.points));
718
+ break;
719
+
720
+ case "curve":
721
+ default:
722
+ const half = {
723
+ x: abs((startPoint.x - endPoint.x) / 2),
724
+ y: abs((startPoint.y - endPoint.y) / 2)
725
+ };
726
+ let minCtrl;
727
+ if (this.__.__useArrow) {
728
+ const ratio = min(getDistance(startPoint, endPoint) / (arrowWidth * 25), 1);
729
+ minCtrl = max(arrowWidth * ratio * 12, arrowWidth * 3);
730
+ } else {
343
731
  minCtrl = arrowWidth * 2;
344
732
  }
345
- }
346
- half.x = max(minCtrl, half.x);
347
- half.y = max(minCtrl, half.y);
348
- if (hasPoints) {
349
- minCtrl *= .6;
350
- const points = draw.PointHelper.toNumberPoints(data.points);
351
- drawPoints$1(path, [ startPoint.x, startPoint.y, ...points, endPoint.x, endPoint.y ], data.curve, false, data);
352
- if (startDirection) {
353
- const handleX = path[4];
354
- const handleY = path[5];
355
- half.x = max(minCtrl, abs(handleX - startPoint.x));
356
- half.y = max(minCtrl, abs(handleY - startPoint.y));
357
- const startCtrlPoint = getCtrlPoint(this, startNode, startPoint, startDirection, half);
358
- path[4] = startCtrlPoint.x;
359
- path[5] = startCtrlPoint.y;
360
- }
361
- const len = path.length;
362
733
  if (endDirection) {
363
- const handleX = path[len - 4];
364
- const handleY = path[len - 3];
365
- half.x = max(minCtrl, abs(handleX - endPoint.x));
366
- half.y = max(minCtrl, abs(handleY - endPoint.y));
367
- const endCtrlPoint = getCtrlPoint(this, endNode, endPoint, endDirection, half);
368
- path[len - 4] = endCtrlPoint.x;
369
- path[len - 3] = endCtrlPoint.y;
734
+ if (isOppositeDirection(startDirection, endDirection) && startDirection === getDirectionForFromPoint(startPoint, endPoint)) {
735
+ minCtrl = arrowWidth * 2;
736
+ }
737
+ }
738
+ half.x = max(minCtrl, half.x);
739
+ half.y = max(minCtrl, half.y);
740
+ if (hasPoints) {
741
+ minCtrl *= .6;
742
+ const points = draw.PointHelper.toNumberPoints(data.points);
743
+ drawPoints$1(path, [ startPoint.x, startPoint.y, ...points, endPoint.x, endPoint.y ], data.curve, false, data);
744
+ if (startDirection) {
745
+ const handleX = path[4];
746
+ const handleY = path[5];
747
+ half.x = max(minCtrl, abs(handleX - startPoint.x));
748
+ half.y = max(minCtrl, abs(handleY - startPoint.y));
749
+ const startCtrlPoint = getCtrlPoint(this, startNode, startPoint, startDirection, half);
750
+ path[4] = startCtrlPoint.x;
751
+ path[5] = startCtrlPoint.y;
752
+ }
753
+ const len = path.length;
754
+ if (endDirection) {
755
+ const handleX = path[len - 4];
756
+ const handleY = path[len - 3];
757
+ half.x = max(minCtrl, abs(handleX - endPoint.x));
758
+ half.y = max(minCtrl, abs(handleY - endPoint.y));
759
+ const endCtrlPoint = getCtrlPoint(this, endNode, endPoint, endDirection, half);
760
+ path[len - 4] = endCtrlPoint.x;
761
+ path[len - 3] = endCtrlPoint.y;
762
+ } else {
763
+ path[len - 4] = endPoint.x;
764
+ path[len - 3] = endPoint.y;
765
+ }
370
766
  } else {
371
- path[len - 4] = endPoint.x;
372
- path[len - 3] = endPoint.y;
767
+ const startCtrlPoint = startDirection ? getCtrlPoint(this, startNode, startPoint, startDirection, half) : startPoint;
768
+ const endCtrlPoint = endDirection ? getCtrlPoint(this, endNode, endPoint, endDirection, half) : endPoint;
769
+ moveTo(path, startPoint.x, startPoint.y);
770
+ bezierCurveTo(path, startCtrlPoint.x, startCtrlPoint.y, endCtrlPoint.x, endCtrlPoint.y, endPoint.x, endPoint.y);
373
771
  }
374
- } else {
375
- const startCtrlPoint = startDirection ? getCtrlPoint(this, startNode, startPoint, startDirection, half) : startPoint;
376
- const endCtrlPoint = endDirection ? getCtrlPoint(this, endNode, endPoint, endDirection, half) : endPoint;
377
- moveTo(path, startPoint.x, startPoint.y);
378
- bezierCurveTo(path, startCtrlPoint.x, startCtrlPoint.y, endCtrlPoint.x, endCtrlPoint.y, endPoint.x, endPoint.y);
379
772
  }
380
773
  }
381
774
  createStartPoint(worldPoint, node, options) {
@@ -445,6 +838,8 @@ exports.Linker = class Linker extends draw.Line {
445
838
 
446
839
  __decorate([ draw.dataProcessor(LinkerData) ], exports.Linker.prototype, "__", void 0);
447
840
 
841
+ __decorate([ draw.boundsType("curve") ], exports.Linker.prototype, "lineType", void 0);
842
+
448
843
  __decorate([ linkerPointType() ], exports.Linker.prototype, "startPoint", void 0);
449
844
 
450
845
  __decorate([ linkerPointType() ], exports.Linker.prototype, "endPoint", void 0);