@libs-ui/components-draw-line 0.2.356-38 → 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
@@ -991,7 +987,6 @@ class LibsUiComponentsDrawLineDirective {
991
987
  });
992
988
  }
993
989
  startProcessDataRow(dataDraw) {
994
- console.log('12121212dataDraw', dataDraw);
995
990
  this.zone.runOutsideAngular(() => {
996
991
  dataDraw.forEach((item) => {
997
992
  const { pathElement, arrowElement, circleStartElement, circleEndElement } = this.createPathAndArrowElement(item.id);
@@ -1083,7 +1078,7 @@ class LibsUiComponentsDrawLineDirective {
1083
1078
  points.separatedPoints.forEach((separatedPoints) => {
1084
1079
  path += this.buildPathAndDrawSeparatedPoints(data, separatedPoints, separatedPoints.mode || mode);
1085
1080
  });
1086
- if (!points.pathElement || !points.pathElement.parentNode) {
1081
+ if (!points.pathElement?.parentNode) {
1087
1082
  const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1088
1083
  this.svgElement.append(pathElement);
1089
1084
  points.pathElement = pathElement;
@@ -1121,6 +1116,12 @@ class LibsUiComponentsDrawLineDirective {
1121
1116
  this.dataDraw?.forEach((item) => {
1122
1117
  const points = item.points;
1123
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
+ }
1124
1125
  points.separatedPoints?.forEach((separatedPoints) => addPoints(separatedPoints));
1125
1126
  points.obstacleRect?.forEach((obstacleRect) => {
1126
1127
  addPoints({
@@ -1129,8 +1130,8 @@ class LibsUiComponentsDrawLineDirective {
1129
1130
  });
1130
1131
  });
1131
1132
  });
1132
- const xMax = this.viewBoxConfig?.width ?? ((xPoints.size ? Math.max(...xPoints) : 0) + 14);
1133
- 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;
1134
1135
  if (!this.viewBoxConfig?.ignoreViewBox) {
1135
1136
  const rectSvgElement = this.svgElement.getBoundingClientRect();
1136
1137
  this.svgElement?.setAttribute('viewBox', `${this.viewBoxConfig?.minX ?? rectSvgElement.x} ${this.viewBoxConfig?.minY ?? rectSvgElement.y} ${xMax} ${yMax}`);
@@ -1176,12 +1177,17 @@ class LibsUiComponentsDrawLineDirective {
1176
1177
  curve = curve ?? 10;
1177
1178
  distancePoint = distancePoint ?? 10;
1178
1179
  }
1179
- if (mode === 'quart-in' || points.start.x === points.end.x || points.start.y === points.end.y) {
1180
- 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
+ }
1181
1184
  if (mode === 'quart-in') {
1182
1185
  dPath = {};
1183
1186
  this.drawBendBothEndsCurve(dPath, points);
1184
1187
  }
1188
+ if (mode === 's-line') {
1189
+ this.drawBendBothEndsCurveSLine(dPath, points);
1190
+ }
1185
1191
  points.pathElement?.setAttribute('d', this.builDAttributeToString(dPath));
1186
1192
  this.drawRectAndInitEvent(data, mode);
1187
1193
  return;
@@ -1253,6 +1259,22 @@ class LibsUiComponentsDrawLineDirective {
1253
1259
  { x: points.end.x, y: points.end.y },
1254
1260
  ];
1255
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
+ }
1256
1278
  buildDAttributeByPointEndModeHorizontal(dPath, points, distancePoint, curve, mode) {
1257
1279
  if (!mode.includes('horizontal')) {
1258
1280
  return;
@@ -1389,6 +1411,14 @@ class LibsUiComponentsDrawLineDirective {
1389
1411
  }
1390
1412
  const modeHorizontal = pointStart.x < points.end.x ? 'right' : 'left';
1391
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
+ }
1392
1422
  if (mode?.includes('vertical') && !mode.includes('single-curve')) {
1393
1423
  return modeVertical;
1394
1424
  }