@libs-ui/components-draw-line 0.2.356-4 → 0.2.356-40

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.
@@ -178,32 +178,32 @@ class MoCanvasCalculatorDirectionElementUtil {
178
178
  }
179
179
  return false;
180
180
  });
181
- if (!elementBlockRoad || !elementBlockRoad.length) {
181
+ if (!elementBlockRoad?.length) {
182
182
  return undefined;
183
183
  }
184
184
  if (returnAllElementBlockRoad) {
185
185
  return elementBlockRoad;
186
186
  }
187
187
  if (direction === 'y') {
188
- return elementBlockRoad.reduce((a, b) => (Math.abs((a.y ?? 0) - start) < Math.abs((b.y ?? 0) - start) ? a : b));
188
+ return elementBlockRoad.reduce((a, b) => (Math.abs((a.y ?? 0) - start) < Math.abs((b.y ?? 0) - start) ? a : b), elementBlockRoad[0]);
189
189
  }
190
- return elementBlockRoad.reduce((a, b) => (Math.abs((a.x ?? 0) - start) < Math.abs((b.x ?? 0) - start) ? a : b));
190
+ return elementBlockRoad.reduce((a, b) => (Math.abs((a.x ?? 0) - start) < Math.abs((b.x ?? 0) - start) ? a : b), elementBlockRoad[0]);
191
191
  }
192
192
  // kiểm tra hướng thẳng vẽ về điểm end xem có bị chắn bởi khối nào không, nếu có thì phải lùi lại điểm end nhé.
193
193
  static checkBlocksElementStraightY(startX, startY, endPosition, obstacleRect) {
194
194
  const elementBlockRoad = this.checkLinePassBlockHorizontal(startY, endPosition.y, startX, 'y', obstacleRect, true);
195
- if (!elementBlockRoad || !elementBlockRoad.length) {
195
+ if (!elementBlockRoad?.length) {
196
196
  return;
197
197
  }
198
- return elementBlockRoad.reduce((a, b) => (Math.abs(a.x ?? 0 - startX) < Math.abs(b.x ?? 0 - startX) ? a : b));
198
+ return elementBlockRoad.reduce((a, b) => (Math.abs(a.x ?? 0 - startX) < Math.abs(b.x ?? 0 - startX) ? a : b), elementBlockRoad[0]);
199
199
  }
200
200
  // kiểm tra hướng ngang vẽ về điểm end xem có bị chắn bởi khối nào không, nếu có thì phải lùi lại điểm end nhé.
201
201
  static checkBlocksElementX(startX, startY, endPosition, obstacleRect) {
202
202
  const elementBlockRoad = this.checkLinePassBlockHorizontal(startX, endPosition.x, startY, 'x', obstacleRect, true);
203
- if (!elementBlockRoad || !elementBlockRoad.length) {
203
+ if (!elementBlockRoad?.length) {
204
204
  return;
205
205
  }
206
- return elementBlockRoad.reduce((a, b) => (Math.abs((a.y ?? 0) - startY) < Math.abs((b.y ?? 0) - startY) ? a : b));
206
+ return elementBlockRoad.reduce((a, b) => (Math.abs((a.y ?? 0) - startY) < Math.abs((b.y ?? 0) - startY) ? a : b), elementBlockRoad[0]);
207
207
  }
208
208
  // kiểm tra hướng sang phải là tránh khối
209
209
  static checkAndAvoidBlocksLeft(startX, startY, lineCurve, endPosition, obstacleRect, separatedPoints) {
@@ -258,7 +258,7 @@ class MoCanvasCalculatorDirectionElementUtil {
258
258
  }
259
259
  const directionX = MoCanvasCalculatorDirectionElementUtil.checkUpDownLeftRight(startX, endPosition.x, 'x');
260
260
  coordLX.x = (elementBlockRoad.x ?? 0) - MoCanvasConnectNavigationNewElementUtil.ELEMENT_MARGIN_BETWEEN_BRANCH_DEFAULT / 2 - lineCurve / 2;
261
- let separatedPointsByPassElementOnRightSide = [];
261
+ const separatedPointsByPassElementOnRightSide = [];
262
262
  const { pathByPassQ, endPath } = MoCanvasCalculatorDirectionElementUtil.byPassElementOnRightSide(coordLX.x, coordLX.y ?? 0, endPosition.y, lineCurve, elementBlockRoad, directionX, separatedPointsByPassElementOnRightSide, 'checkAndAvoidBlocks', coordLX.x);
263
263
  let line = pathPre ? `${pathPre} L ${coordLX.x} ${coordLX.y} ${pathByPassQ}` : `L ${coordLX.x} ${coordLX.y} ${pathByPassQ}`;
264
264
  // tính trước trường hợp sau để lùi line
@@ -268,7 +268,6 @@ class MoCanvasCalculatorDirectionElementUtil {
268
268
  if (elementBlockRoadStraightLineY) {
269
269
  const XNew = (elementBlockRoadStraightLineY.x ?? 0) - MoCanvasConnectNavigationNewElementUtil.ELEMENT_MARGIN_BETWEEN_BRANCH_DEFAULT / 2 - lineCurve / 2;
270
270
  if (XNew < (endPath.x ?? 0)) {
271
- separatedPointsByPassElementOnRightSide = [];
272
271
  separatedPoints.push({ start: { x: startX, y: startY }, end: coordLX, mode: 'horizontal', id: 'checkAndAvoidBlocks', name: 'u' });
273
272
  line = pathPre ? `${pathPre} L ${coordLX.x} ${coordLX.y}` : `L ${coordLX.x} ${coordLX.y}`;
274
273
  return {
@@ -345,13 +344,12 @@ class MoCanvasCalculatorDirectionElementUtil {
345
344
  ignoreBypassElement = true;
346
345
  }
347
346
  coordLX.y = MoCanvasCalculatorBranchUtil.mathOperatorsCalculation(directionY, y, lineCurve * 2);
348
- let separatedPointsByPassElementOnRightSide = [];
347
+ const separatedPointsByPassElementOnRightSide = [];
349
348
  const { pathByPassQ, endPath } = MoCanvasCalculatorDirectionElementUtil.byPassElementOnTopBottomSide(coordLX.x ?? 0, coordLX.y ?? 0, endPosition.x, lineCurve, elementBlockRoad, directionY, separatedPointsByPassElementOnRightSide, key);
350
349
  let end = coordLX;
351
350
  let line = pathPre ? `${pathPre} L ${coordLX.x} ${coordLX.y}` : `L ${coordLX.x} ${coordLX.y}`;
352
351
  separatedPoints.push({ start: { x: startX, y: startY }, end: coordLX, mode: 'horizontal', id: key, name: 'b' });
353
352
  if (ignoreBypassElement) {
354
- separatedPointsByPassElementOnRightSide = [];
355
353
  separatedPoints.push({ start: coordLX, end, mode: 'horizontal', id: key, name: 'c' });
356
354
  return {
357
355
  path: line,
@@ -518,7 +516,6 @@ class MoCanvasConnectNavigationBottomLeftElementUtil {
518
516
  }
519
517
  separatedPoints.push(...avoidBlocksYLine);
520
518
  separatedPoints.push({ start: { x: straightLine.endPath.x ?? 0, y: straightLine.endPath.y ?? 0 }, end: endPosition, mode: 'vertical-single-curve', id: '4' });
521
- return;
522
519
  }
523
520
  }
524
521
 
@@ -594,9 +591,8 @@ class MoCanvasConnectNavigationNewElementUtil {
594
591
  endPath: LEnd,
595
592
  };
596
593
  }
597
- let lineCurveSubY = lineCurve;
598
594
  if (Math.abs((endPath.y ?? 0) - endPosition.y) < lineCurve * 2) {
599
- lineCurveSubY = Math.abs((endPath.y ?? 0) - endPosition.y) / 2;
595
+ const lineCurveSubY = Math.abs((endPath.y ?? 0) - endPosition.y) / 2;
600
596
  const coordQ1 = MoCanvasCalculatorDirectionElementUtil.drawLineQ({ x: endPath.x ?? 0, y: endPath.y ?? 0 }, `right-${directionY === 'above' ? 'above' : 'under'}`, lineCurveSubY * 2, lineCurveSubY); // tính đoạn cong từ đường ngang sang đường thẳng
601
597
  const pathQ1 = `Q ${coordQ1.x1},${coordQ1.y1} ${coordQ1.x},${coordQ1.y}`; // từ ngang sang thẳng phải có đường cong
602
598
  const coordQ2 = MoCanvasCalculatorDirectionElementUtil.drawLineQ({ x: coordQ1.x ?? 0, y: coordQ1.y ?? 0 }, `${directionY === 'above' ? 'above' : 'under'}-right`, lineCurveSubY * 2, lineCurveSubY); // tính đoạn cong từ đường thẳng sang ngang
@@ -1082,7 +1078,7 @@ class LibsUiComponentsDrawLineDirective {
1082
1078
  points.separatedPoints.forEach((separatedPoints) => {
1083
1079
  path += this.buildPathAndDrawSeparatedPoints(data, separatedPoints, separatedPoints.mode || mode);
1084
1080
  });
1085
- if (!points.pathElement || !points.pathElement.parentNode) {
1081
+ if (!points.pathElement?.parentNode) {
1086
1082
  const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1087
1083
  this.svgElement.append(pathElement);
1088
1084
  points.pathElement = pathElement;
@@ -1120,6 +1116,12 @@ class LibsUiComponentsDrawLineDirective {
1120
1116
  this.dataDraw?.forEach((item) => {
1121
1117
  const points = item.points;
1122
1118
  addPoints(points);
1119
+ // Nếu mode là s-line, thêm offset cho control points để viewBox đủ rộng cho curve vòng ra ngoài
1120
+ if (item.mode === 's-line') {
1121
+ const offsetDistance = 1000;
1122
+ xPoints.add(points.start.x + offsetDistance);
1123
+ xPoints.add(points.end.x - offsetDistance);
1124
+ }
1123
1125
  points.separatedPoints?.forEach((separatedPoints) => addPoints(separatedPoints));
1124
1126
  points.obstacleRect?.forEach((obstacleRect) => {
1125
1127
  addPoints({
@@ -1128,8 +1130,8 @@ class LibsUiComponentsDrawLineDirective {
1128
1130
  });
1129
1131
  });
1130
1132
  });
1131
- const xMax = this.viewBoxConfig?.width ?? ((xPoints.size ? Math.max(...xPoints) : 0) + 14);
1132
- const yMax = this.viewBoxConfig?.height ?? ((yPoints.size ? Math.max(...yPoints) : 0) + 14);
1133
+ const xMax = this.viewBoxConfig?.width ?? (xPoints.size ? Math.max(...xPoints) : 0) + 14;
1134
+ const yMax = this.viewBoxConfig?.height ?? (yPoints.size ? Math.max(...yPoints) : 0) + 14;
1133
1135
  if (!this.viewBoxConfig?.ignoreViewBox) {
1134
1136
  const rectSvgElement = this.svgElement.getBoundingClientRect();
1135
1137
  this.svgElement?.setAttribute('viewBox', `${this.viewBoxConfig?.minX ?? rectSvgElement.x} ${this.viewBoxConfig?.minY ?? rectSvgElement.y} ${xMax} ${yMax}`);
@@ -1175,12 +1177,17 @@ class LibsUiComponentsDrawLineDirective {
1175
1177
  curve = curve ?? 10;
1176
1178
  distancePoint = distancePoint ?? 10;
1177
1179
  }
1178
- if (mode === 'quart-in' || points.start.x === points.end.x || points.start.y === points.end.y) {
1179
- this.drawBalancedCurve(dPath, points);
1180
+ if (mode === 'quart-in' || mode === 's-line' || points.start.x === points.end.x || points.start.y === points.end.y) {
1181
+ if (mode !== 's-line') {
1182
+ this.drawBalancedCurve(dPath, points);
1183
+ }
1180
1184
  if (mode === 'quart-in') {
1181
1185
  dPath = {};
1182
1186
  this.drawBendBothEndsCurve(dPath, points);
1183
1187
  }
1188
+ if (mode === 's-line') {
1189
+ this.drawBendBothEndsCurveSLine(dPath, points);
1190
+ }
1184
1191
  points.pathElement?.setAttribute('d', this.builDAttributeToString(dPath));
1185
1192
  this.drawRectAndInitEvent(data, mode);
1186
1193
  return;
@@ -1252,6 +1259,22 @@ class LibsUiComponentsDrawLineDirective {
1252
1259
  { x: points.end.x, y: points.end.y },
1253
1260
  ];
1254
1261
  }
1262
+ drawBendBothEndsCurveSLine(dPath, points) {
1263
+ // Khi X gần nhau → giảm offset để tránh cong quá; khi X xa nhau → offset lớn hơn để tạo S-curve rõ ràng
1264
+ const deltaX = points.end.x - points.start.x;
1265
+ const offsetDistance = Math.min(180, Math.max(80, Math.abs(deltaX)));
1266
+ const deltaY = points.end.y - points.start.y;
1267
+ // LUÔN ĐI RA PHẢI từ start, VÀO TỪ TRÁI của end (hoặc giữ tại end nếu start ở trên end)
1268
+ const rightX = points.start.x + offsetDistance;
1269
+ const leftX = deltaY > 0 ? points.end.x : points.end.x - offsetDistance;
1270
+ dPath.M = { x: points.start.x, y: points.start.y };
1271
+ // Cubic bezier curve duy nhất với control points tính toán để tạo S-curve mượt
1272
+ dPath.C = [
1273
+ { x: rightX, y: points.start.y + deltaY * (deltaY < 0 || deltaX < 0 ? 0.5 : 0.1) },
1274
+ { x: leftX, y: points.end.y - deltaY * 0.5 },
1275
+ { x: points.end.x, y: points.end.y },
1276
+ ];
1277
+ }
1255
1278
  buildDAttributeByPointEndModeHorizontal(dPath, points, distancePoint, curve, mode) {
1256
1279
  if (!mode.includes('horizontal')) {
1257
1280
  return;
@@ -1388,6 +1411,14 @@ class LibsUiComponentsDrawLineDirective {
1388
1411
  }
1389
1412
  const modeHorizontal = pointStart.x < points.end.x ? 'right' : 'left';
1390
1413
  const modeVertical = pointStart.y < points.end.y ? 'bottom' : 'top';
1414
+ // Mode s-line: nếu end ở dưới start → mũi tên chỉ xuống (bottom); ngược lại → mũi tên chỉ ngang (right)
1415
+ if (mode === 's-line') {
1416
+ const deltaY = points.end.y - points.start.y;
1417
+ if (deltaY > 0) {
1418
+ return 'bottom';
1419
+ }
1420
+ return 'right';
1421
+ }
1391
1422
  if (mode?.includes('vertical') && !mode.includes('single-curve')) {
1392
1423
  return modeVertical;
1393
1424
  }