Skip to content

Commit

Permalink
pan on edge
Browse files Browse the repository at this point in the history
  • Loading branch information
JulianWielga committed Apr 19, 2024
1 parent 7c86d67 commit c63c351
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 50 deletions.
3 changes: 2 additions & 1 deletion designer/client/src/components/graph/EspNode/link.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable i18next/no-literal-string */
import { dia, routers } from "jointjs";
import { Edge, EdgeKind, ScenarioGraph, ProcessDefinitionData } from "../../../types";
import { Edge, EdgeKind, ProcessDefinitionData, ScenarioGraph } from "../../../types";
import NodeUtils from "../NodeUtils";

const LINK_TEXT_COLOR = "#686868";
Expand Down Expand Up @@ -76,6 +76,7 @@ export const defaultRouter: routers.RouterJSON = {
endDirections,
step: 15,
padding: 20,
maximumLoops: 200,
},
};

Expand Down
67 changes: 55 additions & 12 deletions designer/client/src/components/graph/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ import "./jqueryPassiveEvents";
// TODO: this is needed here due to our webpack config - needs fixing (NU-1559).
styles;

function clamp(number: number, max: number) {
return Math.round(Math.min(max, Math.max(-max, number)));
}

type Props = GraphProps & {
processCategory: string;
processDefinitionData: ProcessDefinitionData;
Expand Down Expand Up @@ -132,21 +136,63 @@ export class Graph extends React.Component<Props> {
return paper;
};

private bindMoveWithEdge(cellView: dia.CellView) {
const { paper, model } = cellView;
const cell = this.graph.getCell(model.id);
const border = 80;

const mousePosition = new g.Point(this.viewport.center());

const updateMousePosition = (cellView: dia.CellView, event: dia.Event) => {
mousePosition.update(event.clientX, event.clientY);
};

let frame: number;
const panWithEdge = () => {
const rect = this.viewport.clone().inflate(-border, -border);
if (!rect.containsPoint(mousePosition)) {
const distance = rect.pointNearestToPoint(mousePosition).difference(mousePosition);
const x = clamp(distance.x / 2, border / 4);
const y = clamp(distance.y / 2, border / 4);
this.panAndZoom.panBy({
x,
y,
});
if (isModelElement(cell)) {
const p = cell.position();
cell.position(p.x - x, p.y - y);
}
}
frame = requestAnimationFrame(panWithEdge);
};
frame = requestAnimationFrame(panWithEdge);

paper.on(Events.CELL_POINTERMOVE, updateMousePosition);
return () => {
paper.off(Events.CELL_POINTERMOVE, updateMousePosition);
cancelAnimationFrame(frame);
};
}

private bindPaperEvents() {
this.processGraphPaper
//trigger new custom event on finished cell move
.on(Events.CELL_POINTERDOWN, (cellView: dia.CellView) => {
const model = cellView.model;
const { model, paper } = cellView;

const moveCallback = () => {
cellView.once(Events.CELL_POINTERUP, () => {
cellView.trigger(Events.CELL_MOVED, cellView);
this.processGraphPaper.trigger(Events.CELL_MOVED, cellView);
paper.trigger(Events.CELL_MOVED, cellView);
});
};

model.once(Events.CHANGE_POSITION, moveCallback);
const cleanup = this.bindMoveWithEdge(cellView);

cellView.once(Events.CELL_POINTERUP, () => {
model.off(Events.CHANGE_POSITION, moveCallback);
cleanup();
});
})
//we want to inject node during 'Drag and Drop' from graph paper
Expand Down Expand Up @@ -621,18 +667,18 @@ export class Graph extends React.Component<Props> {
return model;
}

moveSelectedNodesRelatively(movedNodeId: string, position: Position): dia.Cell[] {
private moveSelectedNodesRelatively(movedNodeId: string, position: Position): dia.Cell[] {
this.redrawing = true;
const nodeIdsToBeMoved = without(this.props.selectionState, movedNodeId);
const cellsToBeMoved = nodeIdsToBeMoved.map((nodeId) => this.graph.getCell(nodeId));
const cellsToBeMoved = nodeIdsToBeMoved.map((nodeId) => this.graph.getCell(nodeId)).filter(isModelElement);
const { position: originalPosition } = this.findNodeInLayout(movedNodeId);
const offset = {
x: position.x - originalPosition.x,
y: position.y - originalPosition.y,
};
cellsToBeMoved.filter(isModelElement).forEach((cell) => {
cellsToBeMoved.forEach((cell) => {
const { position: originalPosition } = this.findNodeInLayout(cell.id.toString());
cell.position(originalPosition.x + offset.x, originalPosition.y + offset.y);
cell.position(originalPosition.x + offset.x, originalPosition.y + offset.y, { group: true });
});
this.redrawing = false;
return cellsToBeMoved;
Expand Down Expand Up @@ -663,10 +709,9 @@ export class Graph extends React.Component<Props> {
private bindNodesMoving(): void {
this.graph.on(
Events.CHANGE_POSITION,
rafThrottle((element: dia.Cell, position: Position) => {
if (this.redrawing || !isModelElement(element)) {
return;
}
rafThrottle((element: dia.Cell, position: dia.Point, options) => {
if (this.redrawing || !isModelElement(element)) return;
if (options.group) return;

const movingCells: dia.Cell[] = [element];
const nodeId = element.id.toString();
Expand All @@ -675,8 +720,6 @@ export class Graph extends React.Component<Props> {
const movedNodes = this.moveSelectedNodesRelatively(nodeId, position);
movingCells.push(...movedNodes);
}

this.panAndZoom.panToOverflow(movingCells, this.viewport);
}),
);
}
Expand Down
39 changes: 3 additions & 36 deletions designer/client/src/components/graph/PanZoomPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@ function isModified(event: MouseEvent | TouchEvent) {
return event.shiftKey || event.ctrlKey || event.altKey || event.metaKey;
}

function clamp(number: number, max: number) {
return Math.round(Math.min(max, Math.max(-max, number)));
}

function adjust(number: number, multi = 1, pow = 1) {
return Math.round((number >= 0 ? Math.pow(number, pow) : -Math.pow(-number, pow)) * multi);
}

function transformToCSSMatrix({ x, y, k }: ZoomTransform): string {
const matrix = [
[k.toFixed(4), 0, x.toFixed(4)],
Expand All @@ -33,9 +25,9 @@ export type Viewport = g.Rect;
export class PanZoomPlugin {
private zoomBehavior: ZoomBehavior<ZoomedElementBaseType, unknown>;
private paperSelection: Selection<SVGElement, unknown, null, undefined>;
private panBy = rafThrottle(({ x, y }: { x: number; y: number }) => {
this.paperSelection.interrupt("pan").transition("pan").duration(25).call(this.zoomBehavior.translateBy, x, y);
});
panBy = ({ x, y }: { x: number; y: number }) => {
this.paperSelection.call(this.zoomBehavior.translateBy, x, y);
};
private globalCursor: GlobalCursor;
private zoomTo = throttle((scale: number): void => {
this.paperSelection.transition().duration(750).call(this.zoomBehavior.scaleTo, scale);
Expand Down Expand Up @@ -115,31 +107,6 @@ export class PanZoomPlugin {
this.zoomTo(this.zoom * 0.5);
}

panToOverflow(cells: dia.Cell[], updatedViewport?: Viewport) {
this.viewport = updatedViewport;

const border = Math.min(100, adjust(this.viewport.width, 0.05), adjust(this.viewport.height, 0.05));
const adjustedViewport = this.viewport.inflate(-border, -border).round();

const cellsBBox = this.paper.localToClientRect(this.paper.model.getCellsBBox(cells)).round();

if (adjustedViewport.containsRect(cellsBBox)) {
return;
}

const top = Math.min(0, adjustedViewport.topLine().pointOffset(cellsBBox.topMiddle()));
const bottom = Math.max(0, adjustedViewport.bottomLine().pointOffset(cellsBBox.bottomMiddle()));
const left = Math.min(0, -adjustedViewport.leftLine().pointOffset(cellsBBox.leftMiddle()));
const right = Math.max(0, -adjustedViewport.rightLine().pointOffset(cellsBBox.rightMiddle()));

const x = -Math.round(left + right);
const y = -Math.round(top + bottom);
this.panBy({
x: clamp(adjust(x, 0.2, 1.5), 60),
y: clamp(adjust(y, 0.2, 1.5), 60),
});
}

private getTranslatedCenter = (center: g.Point, viewport: Viewport, scale: number) => {
const viewportRelativeCenter = viewport.translate(0, -viewport.y).center();
return viewportRelativeCenter.translate(center.scale(-scale, -scale));
Expand Down
2 changes: 1 addition & 1 deletion designer/client/src/components/sidePanels/SidePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function useGraphViewportAdjustment(side: keyof Graph["viewportAdjustment"], inV

useEffect(() => {
getGraph?.()?.adjustViewport({
[side]: ref.current?.getBoundingClientRect().width * isOccupied,
[side]: inView ? ref.current?.getBoundingClientRect().width * isOccupied : 0,
});
}, [getGraph, inView, isOccupied, side]);

Expand Down

0 comments on commit c63c351

Please sign in to comment.