@ship-ui/core 0.15.32 → 0.15.35
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/fesm2022/ship-ui-core.mjs +134 -86
- package/fesm2022/ship-ui-core.mjs.map +1 -1
- package/index.d.ts +7 -6
- package/package.json +1 -1
|
@@ -758,6 +758,9 @@ class ShipBlueprintComponent {
|
|
|
758
758
|
#ZOOM_SPEED;
|
|
759
759
|
#MAX_ZOOM;
|
|
760
760
|
#MIN_ZOOM;
|
|
761
|
+
#NODE_WIDTH;
|
|
762
|
+
#NODE_HEADER_HEIGHT;
|
|
763
|
+
#PORT_ROW_HEIGHT;
|
|
761
764
|
#document;
|
|
762
765
|
#platformId;
|
|
763
766
|
#selfRef;
|
|
@@ -773,12 +776,17 @@ class ShipBlueprintComponent {
|
|
|
773
776
|
#draggedNodeId;
|
|
774
777
|
#dragOffset;
|
|
775
778
|
#connections;
|
|
779
|
+
#canvasWidth;
|
|
780
|
+
#canvasHeight;
|
|
776
781
|
#ctx;
|
|
777
782
|
#resizeObserver;
|
|
778
783
|
constructor() {
|
|
779
784
|
this.#ZOOM_SPEED = 0.01;
|
|
780
785
|
this.#MAX_ZOOM = 1.5;
|
|
781
786
|
this.#MIN_ZOOM = 0.5;
|
|
787
|
+
this.#NODE_WIDTH = 180;
|
|
788
|
+
this.#NODE_HEADER_HEIGHT = 40;
|
|
789
|
+
this.#PORT_ROW_HEIGHT = 28;
|
|
782
790
|
this.#document = inject(DOCUMENT);
|
|
783
791
|
this.#platformId = inject(PLATFORM_ID);
|
|
784
792
|
this.#selfRef = inject((ElementRef));
|
|
@@ -813,6 +821,31 @@ class ShipBlueprintComponent {
|
|
|
813
821
|
this.#draggedNodeId = signal(null, ...(ngDevMode ? [{ debugName: "#draggedNodeId" }] : []));
|
|
814
822
|
this.#dragOffset = signal(null, ...(ngDevMode ? [{ debugName: "#dragOffset" }] : []));
|
|
815
823
|
this.#connections = signal([], ...(ngDevMode ? [{ debugName: "#connections" }] : []));
|
|
824
|
+
this.#canvasWidth = signal(0, ...(ngDevMode ? [{ debugName: "#canvasWidth" }] : []));
|
|
825
|
+
this.#canvasHeight = signal(0, ...(ngDevMode ? [{ debugName: "#canvasHeight" }] : []));
|
|
826
|
+
this.visibleNodes = computed(() => {
|
|
827
|
+
const nodes = this.nodes();
|
|
828
|
+
const panX = this.panX();
|
|
829
|
+
const panY = this.panY();
|
|
830
|
+
const zoom = this.zoomLevel();
|
|
831
|
+
const width = this.#canvasWidth();
|
|
832
|
+
const height = this.#canvasHeight();
|
|
833
|
+
if (width === 0 || height === 0) {
|
|
834
|
+
return nodes;
|
|
835
|
+
}
|
|
836
|
+
const bufferX = width / zoom;
|
|
837
|
+
const bufferY = height / zoom;
|
|
838
|
+
const viewbox = {
|
|
839
|
+
x1: -panX / zoom - bufferX,
|
|
840
|
+
y1: -panY / zoom - bufferY,
|
|
841
|
+
x2: (-panX + width) / zoom + bufferX,
|
|
842
|
+
y2: (-panY + height) / zoom + bufferY,
|
|
843
|
+
};
|
|
844
|
+
return nodes.filter((node) => {
|
|
845
|
+
const [x, y] = node.coordinates;
|
|
846
|
+
return x > viewbox.x1 && x < viewbox.x2 && y > viewbox.y1 && y < viewbox.y2;
|
|
847
|
+
});
|
|
848
|
+
}, ...(ngDevMode ? [{ debugName: "visibleNodes" }] : []));
|
|
816
849
|
if (isPlatformBrowser(this.#platformId)) {
|
|
817
850
|
effect(() => {
|
|
818
851
|
this.asDots();
|
|
@@ -862,13 +895,71 @@ class ShipBlueprintComponent {
|
|
|
862
895
|
this.#resizeObserver.disconnect();
|
|
863
896
|
}
|
|
864
897
|
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
this.
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
898
|
+
onMouseUp(event) {
|
|
899
|
+
if (this.isLocked())
|
|
900
|
+
return;
|
|
901
|
+
this.endPan();
|
|
902
|
+
this.endNodeDrag();
|
|
903
|
+
}
|
|
904
|
+
onClick(event) {
|
|
905
|
+
const target = event.target;
|
|
906
|
+
if (this.draggingConnection()) {
|
|
907
|
+
if (!target.closest('.port')) {
|
|
908
|
+
this.cancelPortDrag();
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
else if (this.isLocked() && !target.closest('.midpoint-div')) {
|
|
912
|
+
this.closeMidpointDiv();
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
this.#handleConnectionClick(event);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
onEscape(event) {
|
|
919
|
+
if (this.draggingConnection()) {
|
|
920
|
+
this.cancelPortDrag();
|
|
921
|
+
}
|
|
922
|
+
else if (this.isLocked()) {
|
|
923
|
+
this.closeMidpointDiv();
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
onMouseMove(event) {
|
|
927
|
+
if (this.isLocked())
|
|
928
|
+
return;
|
|
929
|
+
if (this.#isNodeDragging()) {
|
|
930
|
+
this.nodeDrag(event);
|
|
931
|
+
}
|
|
932
|
+
else if (this.draggingConnection()) {
|
|
933
|
+
this.updatePathOnMove(event);
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
this.pan(event);
|
|
937
|
+
if (this.isHoveringNode()) {
|
|
938
|
+
this.highlightedConnection.set(null);
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
this.#checkConnectionHover(event);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
onTouchMove(event) {
|
|
946
|
+
event.preventDefault();
|
|
947
|
+
if (this.isLocked())
|
|
948
|
+
return;
|
|
949
|
+
if (this.#isNodeDragging()) {
|
|
950
|
+
this.nodeDrag(event.touches[0]);
|
|
951
|
+
}
|
|
952
|
+
else if (this.draggingConnection()) {
|
|
953
|
+
this.updatePathOnMove(event.touches[0]);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
this.handleTouchMove(event);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
onDocumentTouchEnd(event) {
|
|
960
|
+
if (this.isLocked())
|
|
961
|
+
return;
|
|
962
|
+
this.handleTouchEnd();
|
|
872
963
|
}
|
|
873
964
|
applyAutolayout() {
|
|
874
965
|
const newNodes = layoutNodes(this.nodes());
|
|
@@ -883,6 +974,8 @@ class ShipBlueprintComponent {
|
|
|
883
974
|
this.#ctx.scale(dpr, dpr);
|
|
884
975
|
canvas.style.width = `${rect.width}px`;
|
|
885
976
|
canvas.style.height = `${rect.height}px`;
|
|
977
|
+
this.#canvasWidth.set(rect.width);
|
|
978
|
+
this.#canvasHeight.set(rect.height);
|
|
886
979
|
this.drawCanvas();
|
|
887
980
|
}
|
|
888
981
|
drawCanvas() {
|
|
@@ -975,72 +1068,6 @@ class ShipBlueprintComponent {
|
|
|
975
1068
|
ctx.moveTo(x1, y1);
|
|
976
1069
|
ctx.bezierCurveTo(x1 + dx, y1, x2 - dx, y2, x2, y2);
|
|
977
1070
|
}
|
|
978
|
-
onMouseUp(event) {
|
|
979
|
-
if (this.isLocked())
|
|
980
|
-
return;
|
|
981
|
-
this.endPan();
|
|
982
|
-
this.endNodeDrag();
|
|
983
|
-
}
|
|
984
|
-
onClick(event) {
|
|
985
|
-
const target = event.target;
|
|
986
|
-
if (this.draggingConnection()) {
|
|
987
|
-
if (!target.closest('.port')) {
|
|
988
|
-
this.cancelPortDrag();
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
else if (this.isLocked() && !target.closest('.midpoint-div')) {
|
|
992
|
-
this.closeMidpointDiv();
|
|
993
|
-
}
|
|
994
|
-
else {
|
|
995
|
-
this.#handleConnectionClick(event);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
onEscape(event) {
|
|
999
|
-
if (this.draggingConnection()) {
|
|
1000
|
-
this.cancelPortDrag();
|
|
1001
|
-
}
|
|
1002
|
-
else if (this.isLocked()) {
|
|
1003
|
-
this.closeMidpointDiv();
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
onMouseMove(event) {
|
|
1007
|
-
if (this.isLocked())
|
|
1008
|
-
return;
|
|
1009
|
-
if (this.#isNodeDragging()) {
|
|
1010
|
-
this.nodeDrag(event);
|
|
1011
|
-
}
|
|
1012
|
-
else if (this.draggingConnection()) {
|
|
1013
|
-
this.updatePathOnMove(event);
|
|
1014
|
-
}
|
|
1015
|
-
else {
|
|
1016
|
-
this.pan(event);
|
|
1017
|
-
if (this.isHoveringNode()) {
|
|
1018
|
-
this.highlightedConnection.set(null);
|
|
1019
|
-
}
|
|
1020
|
-
else {
|
|
1021
|
-
this.#checkConnectionHover(event);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
onTouchMove(event) {
|
|
1026
|
-
event.preventDefault();
|
|
1027
|
-
if (this.isLocked())
|
|
1028
|
-
return;
|
|
1029
|
-
if (this.#isNodeDragging()) {
|
|
1030
|
-
this.nodeDrag(event.touches[0]);
|
|
1031
|
-
}
|
|
1032
|
-
else if (this.draggingConnection()) {
|
|
1033
|
-
this.updatePathOnMove(event.touches[0]);
|
|
1034
|
-
}
|
|
1035
|
-
else {
|
|
1036
|
-
this.handleTouchMove(event);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
onDocumentTouchEnd(event) {
|
|
1040
|
-
if (this.isLocked())
|
|
1041
|
-
return;
|
|
1042
|
-
this.handleTouchEnd();
|
|
1043
|
-
}
|
|
1044
1071
|
startNodeDrag(event, nodeId) {
|
|
1045
1072
|
event.stopPropagation();
|
|
1046
1073
|
event.preventDefault();
|
|
@@ -1163,16 +1190,25 @@ class ShipBlueprintComponent {
|
|
|
1163
1190
|
if (!node)
|
|
1164
1191
|
return [0, 0];
|
|
1165
1192
|
const portEl = this.#selfRef.nativeElement.querySelector(`[data-node-id="${nodeId}"][data-port-id="${portId}"]`);
|
|
1166
|
-
if (
|
|
1193
|
+
if (portEl) {
|
|
1194
|
+
const nodeWrapper = this.#selfRef.nativeElement.querySelector('.nodes-wrapper');
|
|
1195
|
+
const wrapperRect = nodeWrapper.getBoundingClientRect();
|
|
1196
|
+
const portRect = portEl.getBoundingClientRect();
|
|
1197
|
+
const portCenterX = portRect.left + portRect.width / 2;
|
|
1198
|
+
const portCenterY = portRect.top + portRect.height / 2;
|
|
1199
|
+
const worldX = (portCenterX - wrapperRect.left) / this.zoomLevel();
|
|
1200
|
+
const worldY = (portCenterY - wrapperRect.top) / this.zoomLevel();
|
|
1201
|
+
return [worldX, worldY];
|
|
1202
|
+
}
|
|
1203
|
+
const isInput = node.inputs.some((p) => p.id === portId);
|
|
1204
|
+
const portIndex = isInput
|
|
1205
|
+
? node.inputs.findIndex((p) => p.id === portId)
|
|
1206
|
+
: node.outputs.findIndex((p) => p.id === portId);
|
|
1207
|
+
if (portIndex === -1)
|
|
1167
1208
|
return node.coordinates;
|
|
1168
|
-
const
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
const portCenterX = portRect.left + portRect.width / 2;
|
|
1172
|
-
const portCenterY = portRect.top + portRect.height / 2;
|
|
1173
|
-
const worldX = (portCenterX - wrapperRect.left) / this.zoomLevel();
|
|
1174
|
-
const worldY = (portCenterY - wrapperRect.top) / this.zoomLevel();
|
|
1175
|
-
return [worldX, worldY];
|
|
1209
|
+
const portYOffset = this.#NODE_HEADER_HEIGHT + portIndex * this.#PORT_ROW_HEIGHT + this.#PORT_ROW_HEIGHT / 2;
|
|
1210
|
+
const portXOffset = isInput ? 0 : this.#NODE_WIDTH;
|
|
1211
|
+
return [node.coordinates[0] + portXOffset, node.coordinates[1] + portYOffset];
|
|
1176
1212
|
}
|
|
1177
1213
|
startPan(event) {
|
|
1178
1214
|
if (this.isLocked())
|
|
@@ -1419,6 +1455,14 @@ class ShipBlueprintComponent {
|
|
|
1419
1455
|
}
|
|
1420
1456
|
return newCoordinates;
|
|
1421
1457
|
}
|
|
1458
|
+
#validateNodes() {
|
|
1459
|
+
const duplicatePortIds = findDuplicatePortIDs(this.nodes());
|
|
1460
|
+
const duplicateNodeIds = findDuplicateNodeIDs(this.nodes());
|
|
1461
|
+
this.validationErrors.set({
|
|
1462
|
+
duplicateNodeIds,
|
|
1463
|
+
duplicatePortIds,
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1422
1466
|
#panToCoordinates(coords) {
|
|
1423
1467
|
const [x, y] = coords;
|
|
1424
1468
|
const rect = this.#selfRef.nativeElement.getBoundingClientRect();
|
|
@@ -1468,7 +1512,7 @@ class ShipBlueprintComponent {
|
|
|
1468
1512
|
class="nodes-wrapper"
|
|
1469
1513
|
[style.transform]="'translate(' + panX() + 'px, ' + panY() + 'px) scale(' + zoomLevel() + ')'"
|
|
1470
1514
|
[style.transform-origin]="'0 0'">
|
|
1471
|
-
@for (node of
|
|
1515
|
+
@for (node of visibleNodes(); track node.id) {
|
|
1472
1516
|
<sh-card
|
|
1473
1517
|
class="node type-c"
|
|
1474
1518
|
[style.transform]="getDisplayCoordinates(node)"
|
|
@@ -1561,7 +1605,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImpor
|
|
|
1561
1605
|
class="nodes-wrapper"
|
|
1562
1606
|
[style.transform]="'translate(' + panX() + 'px, ' + panY() + 'px) scale(' + zoomLevel() + ')'"
|
|
1563
1607
|
[style.transform-origin]="'0 0'">
|
|
1564
|
-
@for (node of
|
|
1608
|
+
@for (node of visibleNodes(); track node.id) {
|
|
1565
1609
|
<sh-card
|
|
1566
1610
|
class="node type-c"
|
|
1567
1611
|
[style.transform]="getDisplayCoordinates(node)"
|
|
@@ -1717,7 +1761,9 @@ class ShipCheckboxComponent {
|
|
|
1717
1761
|
<sh-icon class="inherit indeterminate-indicator">minus-bold</sh-icon>
|
|
1718
1762
|
</div>
|
|
1719
1763
|
|
|
1720
|
-
<
|
|
1764
|
+
<div class="label">
|
|
1765
|
+
<ng-content />
|
|
1766
|
+
</div>
|
|
1721
1767
|
`, isInline: true, dependencies: [{ kind: "component", type: ShipIconComponent, selector: "sh-icon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1722
1768
|
}
|
|
1723
1769
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ShipCheckboxComponent, decorators: [{
|
|
@@ -1731,7 +1777,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImpor
|
|
|
1731
1777
|
<sh-icon class="inherit indeterminate-indicator">minus-bold</sh-icon>
|
|
1732
1778
|
</div>
|
|
1733
1779
|
|
|
1734
|
-
<
|
|
1780
|
+
<div class="label">
|
|
1781
|
+
<ng-content />
|
|
1782
|
+
</div>
|
|
1735
1783
|
`,
|
|
1736
1784
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1737
1785
|
}]
|