Skip to content

Commit

Permalink
Merge pull request #1382 from easyops-cn/steve/fix-canvas
Browse files Browse the repository at this point in the history
Steve/fix-canvas
  • Loading branch information
panzekun authored Oct 28, 2024
2 parents 9bc7dc4 + 57ca221 commit 7b27a0a
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 37 deletions.
9 changes: 9 additions & 0 deletions bricks/diagram/src/display-canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface EoDisplayCanvasProps {
scaleRange?: RangeTuple;
hideZoomBar?: boolean;
autoCenterWhenCellsChange?: boolean;
doNotResetActiveTargetForSelector?: string;
}

/**
Expand Down Expand Up @@ -155,6 +156,9 @@ class EoDisplayCanvas extends ReactNextElement implements EoDisplayCanvasProps {
@property({ type: Boolean })
accessor autoCenterWhenCellsChange: boolean | undefined;

@property()
accessor doNotResetActiveTargetForSelector: string | undefined;

@event({ type: "activeTarget.change" })
accessor #activeTargetChangeEvent!: EventEmitter<ActiveTarget | null>;

Expand Down Expand Up @@ -201,6 +205,9 @@ class EoDisplayCanvas extends ReactNextElement implements EoDisplayCanvasProps {
pannable={this.pannable}
scaleRange={this.scaleRange}
hideZoomBar={this.hideZoomBar}
doNotResetActiveTargetForSelector={
this.doNotResetActiveTargetForSelector
}
autoCenterWhenCellsChange={this.autoCenterWhenCellsChange}
onActiveTargetChange={this.#handleActiveTargetChange}
onSwitchActiveTarget={this.#handleSwitchActiveTarget}
Expand Down Expand Up @@ -237,6 +244,7 @@ function EoDisplayCanvasComponent({
scaleRange: _scaleRange,
hideZoomBar,
autoCenterWhenCellsChange,
doNotResetActiveTargetForSelector,
onActiveTargetChange,
onSwitchActiveTarget,
onCellContextMenu,
Expand Down Expand Up @@ -319,6 +327,7 @@ function EoDisplayCanvasComponent({
const activeTarget = useActiveTarget({
rootRef,
activeTarget: _activeTarget,
doNotResetActiveTargetForSelector,
onActiveTargetChange,
});

Expand Down
3 changes: 2 additions & 1 deletion bricks/diagram/src/draw-canvas/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export const SYMBOL_FOR_SIZE_INITIALIZED = Symbol.for("size-initialized");
export const SYMBOL_FOR_LAYOUT_INITIALIZED = Symbol.for("layout-initialized");
export const DEFAULT_NODE_SIZE = 20;
export const DEFAULT_NODE_GAP = 36;
export const DEFAULT_NODE_GAP_H = 36;
export const DEFAULT_NODE_GAP_V = 50;
export const DEFAULT_AREA_WIDTH = 180;
export const DEFAULT_AREA_HEIGHT = 120;
export const DEFAULT_SCALE_RANGE_MIN = 0.5;
Expand Down
12 changes: 11 additions & 1 deletion bricks/diagram/src/draw-canvas/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ describe("eo-draw-canvas", () => {
const element = document.createElement("eo-draw-canvas") as EoDrawCanvas;
element.defaultNodeBricks = [{ useBrick: { brick: "div" } }];
element.fadeUnrelatedCells = true;
element.doNotResetActiveTargetForSelector = "#omit-target";
element.cells = [
{
type: "decorator",
Expand Down Expand Up @@ -515,6 +516,14 @@ describe("eo-draw-canvas", () => {
view: { x: 20, y: 20, width: 20, height: 20 },
});

const omitTarget = document.createElement("div");
omitTarget.id = "omit-target";
document.body.appendChild(omitTarget);
act(() => {
fireEvent.click(omitTarget);
});
expect(onActiveTargetChange).toHaveBeenCalledTimes(1);

act(() => {
fireEvent.click(element.shadowRoot!.querySelector("svg")!);
});
Expand All @@ -523,6 +532,7 @@ describe("eo-draw-canvas", () => {

act(() => {
document.body.removeChild(element);
document.body.removeChild(omitTarget);
});
});

Expand Down Expand Up @@ -940,7 +950,7 @@ describe("eo-draw-canvas", () => {
height: 20,
width: 20,
x: 20,
y: 86,
y: 100,
},
},
],
Expand Down
9 changes: 9 additions & 0 deletions bricks/diagram/src/draw-canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export interface EoDrawCanvasProps {
lineSettings?: LineSettings;
lineConnector?: LineConnecterConf | boolean;
allowEdgeToArea?: boolean;
doNotResetActiveTargetForSelector?: string;
}

export type DragBehavior = "none" | "lasso" | "grab";
Expand Down Expand Up @@ -284,6 +285,9 @@ class EoDrawCanvas extends ReactNextElement implements EoDrawCanvasProps {
@property({ attribute: false })
accessor lineConnector: LineConnecterConf | boolean | undefined;

@property()
accessor doNotResetActiveTargetForSelector: string | undefined;

@event({ type: "activeTarget.change" })
accessor #activeTargetChangeEvent!: EventEmitter<ActiveTarget | null>;

Expand Down Expand Up @@ -575,6 +579,9 @@ class EoDrawCanvas extends ReactNextElement implements EoDrawCanvasProps {
lineSettings={this.lineSettings}
lineConnector={this.lineConnector}
allowEdgeToArea={this.allowEdgeToArea}
doNotResetActiveTargetForSelector={
this.doNotResetActiveTargetForSelector
}
onActiveTargetChange={this.#handleActiveTargetChange}
onSwitchActiveTarget={this.#handleSwitchActiveTarget}
onCellMove={this.#handleCellMove}
Expand Down Expand Up @@ -652,6 +659,7 @@ function LegacyEoDrawCanvasComponent(
lineSettings,
lineConnector,
allowEdgeToArea,
doNotResetActiveTargetForSelector,
onActiveTargetChange,
onSwitchActiveTarget,
onCellMove,
Expand Down Expand Up @@ -865,6 +873,7 @@ function LegacyEoDrawCanvasComponent(
const activeTarget = useActiveTarget({
rootRef,
activeTarget: _activeTarget,
doNotResetActiveTargetForSelector,
onActiveTargetChange,
});

Expand Down
23 changes: 6 additions & 17 deletions bricks/diagram/src/draw-canvas/processors/updateCells.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ describe("updateCells", () => {
type: "node",
view: {
x: 20,
y: 216,
y: 230,
height: 80,
width: 120,
},
Expand All @@ -399,7 +399,7 @@ describe("updateCells", () => {
type: "node",
view: {
x: 20,
y: 216,
y: 230,
height: 80,
width: 120,
},
Expand Down Expand Up @@ -777,26 +777,15 @@ describe("updateCells", () => {
id: "1",
type: "node",
view: {
x: 60,
y: 40,
width: 120,
height: 80,
},
},
],
updated: [
{
id: "1",
type: "node",
view: {
x: 60,
y: 40,
x: 100,
y: 30,
width: 120,
height: 80,
},
},
],
shouldReCenter: true,
updated: [],
shouldReCenter: false,
});
});
});
33 changes: 17 additions & 16 deletions bricks/diagram/src/draw-canvas/processors/updateCells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import type {
SizeTuple,
TransformLiteral,
} from "../../diagram/interfaces";
import { DEFAULT_NODE_GAP, SYMBOL_FOR_SIZE_INITIALIZED } from "../constants";
import {
DEFAULT_NODE_GAP_H,
DEFAULT_NODE_GAP_V,
SYMBOL_FOR_SIZE_INITIALIZED,
} from "../constants";
import type {
Cell,
InitialCell,
Expand Down Expand Up @@ -135,41 +139,36 @@ export function updateCells({
if (rightMostNode) {
// Place unpositioned nodes on the right side of the rightmost positioned siblings.
nextX =
rightMostNode.view.x + rightMostNode.view.width + DEFAULT_NODE_GAP;
rightMostNode.view.x +
rightMostNode.view.width +
DEFAULT_NODE_GAP_H;
nextY = rightMostNode.view.y;
} else {
// If there are no positioned siblings, just place them below the parent.
const totalWidth = updateCandidates.reduce(
(acc, node) => acc + node.view.width + DEFAULT_NODE_GAP,
-DEFAULT_NODE_GAP
(acc, node) => acc + node.view.width + DEFAULT_NODE_GAP_H,
-DEFAULT_NODE_GAP_H
);
nextX =
parentNode.view.x - totalWidth / 2 + parentNode.view.width / 2;
nextY = parentNode.view.y + parentNode.view.height + DEFAULT_NODE_GAP;
nextY =
parentNode.view.y + parentNode.view.height + DEFAULT_NODE_GAP_V;
}
for (const node of updateCandidates) {
node.view.x = nextX;
node.view.y = nextY;
nextX += node.view.width + DEFAULT_NODE_GAP;
nextX += node.view.width + DEFAULT_NODE_GAP_H;
}
}
}
}

if (!handled) {
// By default, place unpositioned nodes in a grid.
let maxWidth = defaultNodeSize[0];
let maxHeight = defaultNodeSize[1];
const positionedNodes: NodeCell[] = [];
let hasDecorators = false;
for (const cell of newCells) {
if (isNodeCell(cell)) {
if (cell.view.width > maxWidth) {
maxWidth = cell.view.width;
}
if (cell.view.height > maxHeight) {
maxHeight = cell.view.height;
}
if (cell.view.x === undefined || cell.view.y === undefined) {
updateCandidates.push(cell);
} else {
Expand All @@ -192,12 +191,14 @@ export function updateCells({

let getNodeView: (id: NodeId) => NodeView;

// If there is no positioned nodes, or only one while without decorators,
// If there is no positioned nodes, or only one while without decorators and unpositioned nodes exist,
// then there is no relative positions, we can place the nodes with dagre layout.
// Otherwise, use the force layout.
if (
positionedNodes.length === 0 ||
(positionedNodes.length === 1 && !hasDecorators)
(positionedNodes.length === 1 &&
!hasDecorators &&
updateCandidates.length > 0)
) {
// The positioned node (if exists) will be updated.
updateCandidates.push(...positionedNodes);
Expand Down
16 changes: 14 additions & 2 deletions bricks/diagram/src/shared/canvas/useActiveTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { sameTarget } from "../../draw-canvas/processors/sameTarget";
export interface UseActiveTargetOptions {
rootRef: React.RefObject<SVGGElement>;
activeTarget?: ActiveTarget | null;
doNotResetActiveTargetForSelector?: string;
onActiveTargetChange(target: ActiveTarget | null): void;
}

Expand All @@ -13,6 +14,7 @@ export type UseActiveTargetResult = ActiveTarget | null;
export function useActiveTarget({
rootRef,
activeTarget: _activeTarget,
doNotResetActiveTargetForSelector,
onActiveTargetChange,
}: UseActiveTargetOptions): UseActiveTargetResult {
const newActiveTarget = _activeTarget ?? null;
Expand Down Expand Up @@ -44,15 +46,25 @@ export function useActiveTarget({
const rootIndex = path.indexOf(rootRef.current!);
// Reset active target to null when clicking outside of the cells container,
// Or inside the cells container but not on any cell.
if (rootIndex <= 0) {
if (
rootIndex <= 0 &&
!(
doNotResetActiveTargetForSelector &&
path.some(
(el) =>
el instanceof Element &&
el.matches(doNotResetActiveTargetForSelector)
)
)
) {
setActiveTarget(null);
}
};
document.addEventListener("click", resetActiveTarget);
return () => {
document.removeEventListener("click", resetActiveTarget);
};
}, [activeTarget, rootRef]);
}, [activeTarget, doNotResetActiveTargetForSelector, rootRef]);

return activeTarget;
}

0 comments on commit 7b27a0a

Please sign in to comment.