Skip to content

Commit 5992571

Browse files
committed
feat(): 拓扑图支持快捷键shift快速选择和取消选择多个元素,原框选功能需要支持选中边
Closes CMDB_VIEW-314
1 parent 3c328cf commit 5992571

File tree

10 files changed

+85
-41
lines changed

10 files changed

+85
-41
lines changed

bricks/diagram/src/draw-canvas/CellComponent.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function CellComponent({
9696
onCellMouseLeave,
9797
}: CellComponentProps): JSX.Element | null {
9898
const {
99-
activeEditableEdge,
99+
activeEditableEdges,
100100
lineEditorState,
101101
smartConnectLineState,
102102
setSmartConnectLineState,
@@ -109,6 +109,15 @@ export function CellComponent({
109109
() => unrelatedCells.some((item) => sameTarget(item, cell)),
110110
[cell, unrelatedCells]
111111
);
112+
const activeEditableEdge = useMemo(
113+
() =>
114+
cell.type === "edge"
115+
? activeEditableEdges.find(
116+
(edge) => edge.source === cell.source && edge.target === cell.target
117+
)
118+
: null,
119+
[cell, activeEditableEdges]
120+
);
112121
// `containerRect` is undefined when it's an edge cell.
113122
const containerRect = useMemo((): DecoratorView | undefined => {
114123
if (isContainerDecoratorCell(cell) && isNoManualLayout(layout)) {
@@ -276,7 +285,6 @@ export function CellComponent({
276285
}, [cell, onCellMouseLeave]);
277286

278287
const active = targetIsActive(cell, activeTarget);
279-
280288
return (
281289
<g
282290
className={classNames("cell", {

bricks/diagram/src/draw-canvas/EdgeComponent.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,18 @@ export function EdgeComponent({
139139
if (element) {
140140
// Jest does not support `SVGPathElement::getTotalLength`
141141
setPathLength(element.getTotalLength?.() ?? 100);
142+
const rect = element.getBBox?.();
143+
edge.view = {
144+
...edge.view,
145+
x: rect?.x,
146+
y: rect?.y,
147+
width: rect?.width,
148+
height: rect?.height,
149+
};
142150
}
143151
updateLabelPosition();
144152
},
145-
[updateLabelPosition]
153+
[updateLabelPosition, edge]
146154
);
147155

148156
const [labelElement, setLabelElement] = useState<HTMLElement | null>(null);

bricks/diagram/src/draw-canvas/HoverStateContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const HoverStateContext = React.createContext<{
2323
smartConnectLineState: SmartConnectLineState | null;
2424
unsetHoverStateTimeoutRef: React.MutableRefObject<number | null>;
2525
hoverState: HoverState | null;
26-
activeEditableEdge: EdgeCell | null;
26+
activeEditableEdges: EdgeCell[];
2727
lineEditorState: LineEditorState | null;
2828
setLineEditorState: React.Dispatch<
2929
React.SetStateAction<LineEditorState | null>
@@ -48,7 +48,7 @@ export const HoverStateContext = React.createContext<{
4848
smartConnectLineState: null,
4949
unsetHoverStateTimeoutRef: { current: null },
5050
hoverState: null,
51-
activeEditableEdge: null,
51+
activeEditableEdges: [],
5252
lineEditorState: null,
5353
setLineEditorState: () => {},
5454
setHoverState: () => {},

bricks/diagram/src/draw-canvas/LineEditorComponent.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ const POINT_HELPER_BG_SIZE = 22;
1616
export interface LineEditorComponentProps {
1717
scale: number;
1818
editableLineMap: WeakMap<EdgeCell, EditableLine>;
19+
activeEditableEdge: EdgeCell;
1920
}
2021

2122
export function LineEditorComponent({
2223
scale,
2324
editableLineMap,
25+
activeEditableEdge,
2426
}: LineEditorComponentProps): JSX.Element | null {
25-
const { rootRef, activeEditableEdge, setLineEditorState } =
26-
useHoverStateContext();
27+
const { rootRef, setLineEditorState } = useHoverStateContext();
2728
const exitRef = useRef<SVGImageElement>(null);
2829
const entryRef = useRef<SVGImageElement>(null);
2930
const controlPointsRef = useRef<(SVGImageElement | null)[]>([]);
@@ -61,7 +62,6 @@ export function LineEditorComponent({
6162
? getControlPoints(editableLineMap.get(activeEditableEdge)!.points!)
6263
: [];
6364
}, [activeEditableEdge, editableLineMap]);
64-
6565
useEffect(() => {
6666
if (!activeEditableEdge) {
6767
return;

bricks/diagram/src/draw-canvas/index.tsx

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { ReactNextElement } from "@next-core/react-element";
1313
import type { UseSingleBrickConf } from "@next-core/react-runtime";
1414
import { unwrapProvider } from "@next-core/utils/general";
1515
import "@next-core/theme";
16-
import { uniqueId } from "lodash";
16+
import { get, uniqueId } from "lodash";
1717
import classNames from "classnames";
1818
import { select } from "d3-selection";
1919
import type { lockBodyScroll as _lockBodyScroll } from "@next-bricks/basic/data-providers/lock-body-scroll/lock-body-scroll";
@@ -520,7 +520,7 @@ class EoDrawCanvas extends ReactNextElement implements EoDrawCanvasProps {
520520
source,
521521
target,
522522
data,
523-
view: this.lineSettings,
523+
view: this.lineSettings!,
524524
};
525525
this.#canvasRef.current?.addEdge(newEdge);
526526
return newEdge;
@@ -1041,25 +1041,24 @@ function LegacyEoDrawCanvasComponent(
10411041
},
10421042
[zoomer]
10431043
);
1044-
10451044
const { lineConfMap, lineConnectorConf, markers } = useLineMarkers({
10461045
cells,
10471046
defaultEdgeLines,
10481047
lineConnector,
10491048
markerPrefix,
10501049
});
1050+
10511051
const editableLineMap = useEditableLineMap({ cells, lineConfMap });
1052-
const activeEditableEdge = useMemo(() => {
1053-
let edge: EdgeCell | undefined;
1054-
if (activeTarget?.type === "edge") {
1055-
edge = cells.find((cell) =>
1056-
targetIsActive(cell, activeTarget)
1057-
) as EdgeCell;
1058-
}
1059-
if (edge && editableLineMap.has(edge)) {
1060-
return edge;
1061-
}
1062-
return null;
1052+
1053+
const activeEditableEdges = useMemo(() => {
1054+
let edges: EdgeCell[] = [];
1055+
edges = cells.filter(
1056+
(cell) =>
1057+
targetIsActive(cell, activeTarget) &&
1058+
cell.type === "edge" &&
1059+
editableLineMap.has(cell)
1060+
) as EdgeCell[];
1061+
return edges;
10631062
}, [activeTarget, cells, editableLineMap]);
10641063

10651064
const ready = useReady({ cells, layout, centered });
@@ -1181,7 +1180,7 @@ function LegacyEoDrawCanvasComponent(
11811180
smartConnectLineState,
11821181
unsetHoverStateTimeoutRef,
11831182
hoverState,
1184-
activeEditableEdge,
1183+
activeEditableEdges,
11851184
lineEditorState,
11861185
setLineEditorState,
11871186
setHoverState,
@@ -1190,7 +1189,7 @@ function LegacyEoDrawCanvasComponent(
11901189
onChangeEdgeView: handleEdgeChangeView,
11911190
}),
11921191
[
1193-
activeEditableEdge,
1192+
activeEditableEdges,
11941193
handleEdgeChangeView,
11951194
handleSmartConnect,
11961195
hoverState,
@@ -1214,20 +1213,23 @@ function LegacyEoDrawCanvasComponent(
12141213
},
12151214
onLassoed(rect) {
12161215
setLassoRect(null);
1217-
const lassoedCells: (NodeCell | DecoratorCell)[] = [];
1216+
const lassoedCells: (NodeCell | DecoratorCell | EdgeCell)[] = [];
12181217
for (const cell of cells) {
12191218
if (
12201219
isContainerDecoratorCell(cell) ||
12211220
isNodeOrAreaDecoratorCell(cell) ||
1222-
isTextDecoratorCell(cell)
1221+
isTextDecoratorCell(cell) ||
1222+
isEdgeCell(cell)
12231223
) {
1224-
const x = cell.view.x;
1225-
const y = cell.view.y;
1224+
const x = get(cell, "view.x", 0);
1225+
const y = get(cell, "view.y", 0);
1226+
const width = get(cell, "view.width", 0);
1227+
const height = get(cell, "view.height", 0);
12261228
if (
12271229
x >= rect.x &&
1228-
x + cell.view.width <= rect.x + rect.width &&
1230+
x + width <= rect.x + rect.width &&
12291231
y >= rect.y &&
1230-
y + cell.view.height <= rect.y + rect.height
1232+
y + height <= rect.y + rect.height
12311233
) {
12321234
lassoedCells.push(cell);
12331235
}
@@ -1352,12 +1354,15 @@ function LegacyEoDrawCanvasComponent(
13521354
))}
13531355
</g>
13541356
<g>
1355-
{lineConnectorConf && (
1356-
<LineEditorComponent
1357-
editableLineMap={editableLineMap}
1358-
scale={transform.k}
1359-
/>
1360-
)}
1357+
{lineConnectorConf &&
1358+
activeEditableEdges?.map((activeEdge) => (
1359+
<LineEditorComponent
1360+
editableLineMap={editableLineMap}
1361+
scale={transform.k}
1362+
activeEditableEdge={activeEdge}
1363+
key={`${activeEdge.source}-${activeEdge.target}`}
1364+
/>
1365+
))}
13611366
</g>
13621367
{lineConnectorConf && (
13631368
<LineConnectorComponent

bricks/diagram/src/draw-canvas/interfaces.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ export interface EdgeView extends LineSettings {
9999
exitPosition?: NodePosition | null;
100100
entryPosition?: NodePosition | null;
101101
vertices?: NodePosition[] | null;
102+
x?: number;
103+
y?: number;
104+
width?: number;
105+
height?: number;
102106
}
103107

104108
export interface EdgeLineConf extends BaseEdgeLineConf {

bricks/diagram/src/draw-canvas/processors/handleKeyboard.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export function handleKeyboard(
3030
event.key ||
3131
/* istanbul ignore next: compatibility */ event.keyCode ||
3232
/* istanbul ignore next: compatibility */ event.which;
33-
3433
switch (key) {
3534
case "Backspace":
3635
case 8:

bricks/diagram/src/draw-canvas/processors/handleMouseDown.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
LayoutType,
88
NodeCell,
99
SnapToObjectPosition,
10+
ActiveTargetOfSingular,
1011
} from "../interfaces";
1112
import type {
1213
MoveCellPayload,
@@ -21,6 +22,7 @@ import {
2122
import { cellToTarget } from "./cellToTarget";
2223
import { getSnapPositions, type SnapPositions } from "./getSnapPositions";
2324
import { normalizeSnapOptions } from "./normalizeSnapOptions";
25+
import { sameTarget } from "./sameTarget";
2426
import { targetIsActive } from "./targetIsActive";
2527

2628
const HORIZONTAL_POSITIONS = ["left", "center", "right"];
@@ -58,9 +60,26 @@ export function handleMouseDown(
5860
) {
5961
event.stopPropagation();
6062
// Drag node
61-
if (action === "resize" || !targetIsActive(cell, activeTarget)) {
62-
onSwitchActiveTarget?.(cellToTarget(cell));
63+
const preActive = targetIsActive(cell, activeTarget);
64+
if (event.shiftKey) {
65+
const activeTargets = activeTarget
66+
? activeTarget?.type === "multi"
67+
? activeTarget.targets
68+
: [activeTarget]
69+
: [];
70+
let targets: ActiveTargetOfSingular[] = [];
71+
if (preActive) {
72+
targets = activeTargets.filter((target) => !sameTarget(target, cell));
73+
} else {
74+
targets = [...activeTargets, cell];
75+
}
76+
onSwitchActiveTarget?.({ type: "multi", targets });
77+
} else {
78+
if (action === "resize" || !preActive) {
79+
onSwitchActiveTarget?.(cellToTarget(cell));
80+
}
6381
}
82+
6483
if (isEdgeCell(cell)) {
6584
return;
6685
}

bricks/diagram/src/editable-label/styles.shadow.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
overflow: hidden;
4747
white-space: nowrap;
4848
text-overflow: ellipsis;
49+
user-select: none;
4950
}
5051

5152
.label.editing .label-text,

bricks/diagram/src/shared/canvas/styles.shadow.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777

7878
.decorator-area .area,
7979
.decorator-container .container {
80-
fill: rgba(119, 141, 195, 0.1);
80+
fill: rgba(73, 126, 255, 0.1);
8181
stroke: none;
8282
stroke-width: 0;
8383
}
@@ -214,7 +214,7 @@
214214
padding: 0.5em;
215215
text-align: center;
216216
font-size: 16px;
217-
background-color: rgba(119, 141, 195, 0.6);
217+
background-color: rgba(73, 126, 255, 0.6);
218218
overflow: hidden;
219219
}
220220

0 commit comments

Comments
 (0)