Skip to content

Commit

Permalink
implement layoutStage prop, udpate readme and add example
Browse files Browse the repository at this point in the history
  • Loading branch information
Layvier committed Mar 9, 2021
1 parent b721cb0 commit 7bf6710
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 7 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,16 @@ If you need to handle button presses, pass custom data, or do something I can't
renderNode = (
node: NodeOptions,
reportSize: ReportSize,
valueCache: ValueCache
valueCache: ValueCache,
layoutStage: number
) => {
return (
<Node
key={node.id}
node={node}
reportSize={reportSize}
valueCache={valueCache}
layoutStage={layoutStage}
html={true}
>
{{
Expand Down Expand Up @@ -439,3 +441,6 @@ Currently dagre labelpos is not respected, it can be passed but internally the e

Currently you cannot change the original prop data and see a change on the graph without changing the "stage" prop on DagreReact. The graph internally takes a copy of the data props on first render and that is the data that is manipulated and rendered internally. The data props are then ignored until the stage value changes. This was a decision made so that the component is not changing your state without telling you. Changing the data without triggering dagre to re-layout is not advised anyway as any style change will change the size of a node and should trigger a full stage layout. This can make using the default built in labels and shapes difficult if you want to change the background on mouse over for example, a possible work around is provided on MouseEvents example. A better solution would be to create your own shape component that takes in the style props that you can store separately from the node data. Again only do this if you know that the change does not affect the width and height on the node.

## Changing of node size

In the case of triggering of change affecting the width or height of the nodes, the full dagre layout needs to rerender. For this purpose, use layoutStage in the same way you would use the stage prop. You must then pass the layoutStage variable to the Node component in the renderNode method (see [Override render methods example](#override-render-methods))
2 changes: 2 additions & 0 deletions example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { CustomButtonNodes} from "./examples/CustomButtonNodes";
import { PanAndZoom } from "./examples/PanAndZoom";
import { Tooltips } from "./examples/Tooltips";
import { CustomStyles } from "./examples/CustomStyles";
import { NodeSize } from "./examples/NodeSize";

class App extends React.Component<{}, {}> {
render() {
Expand All @@ -37,6 +38,7 @@ class App extends React.Component<{}, {}> {
<Route path="/panAndZoom" component={PanAndZoom} />
<Route path="/tooltips" component={Tooltips} />
<Route path="/customStyles" component={CustomStyles} />
<Route path="/nodeSize" component={NodeSize} />
</Switch>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions example/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const Sidebar: React.FC<{}> = () => {
<li><Link to='/panAndZoom'>Pan and zoom</Link></li>
<li><Link to='/tooltips'>Tooltips</Link></li>
<li><Link to='/customStyles'>Custom styles</Link></li>
<li><Link to='/nodeSize'>Resize</Link></li>
</ul>
</div>
);
Expand Down
70 changes: 70 additions & 0 deletions example/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1018,3 +1018,73 @@ export const customStyles: {
}
]
};

export const customNodeSize: {
nodes: Array<RecursivePartial<NodeOptions>>;
edges: Array<RecursivePartial<EdgeOptions>>;
} = {
nodes: [
{
id: "1",
label: "Phase 1",
styles: {
shape: {
styles: { fillOpacity: 1, fill: "#fff", stroke: "#fff" }
}
},
meta: {
description: "Scan watch directory for new files"
}
},
{
id: "2",
label: "Phase 2",
styles: {
shape: {
styles: { fillOpacity: 1, fill: "#fff", stroke: "#fff" }
}
},
meta: {
description: "Create queue jobs for identified files"
}
},
{
id: "3",
label: "Phase 3",
styles: {
shape: {
styles: { fillOpacity: 1, fill: "#fff", stroke: "#fff" }
}
},
meta: {
description: "Execute processing of new jobs"
}
},
{
id: "4",
label: "Phase 4",
styles: {
shape: {
styles: { fillOpacity: 1, fill: "#fff", stroke: "#fff" }
}
},
meta: {
description: "Store results of processing"
}
}
],
edges: [
{
from: "1",
to: "2"
},
{
from: "2",
to: "3"
},
{
from: "3",
to: "4"
}
]
};
120 changes: 120 additions & 0 deletions example/examples/NodeSize.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from 'react';

import {
DagreReact,
Node,
Rect,
ValueCache,
RecursivePartial,
ReportSize,
Size,
NodeOptions,
EdgeOptions,
} from '../../dist/';
import { customNodeSize } from '../data';

type CustomNodesState = {
nodes: Array<RecursivePartial<NodeOptions>>;
edges: Array<RecursivePartial<EdgeOptions>>;
layoutStage: number;
};

export class NodeSize extends React.Component<{}, CustomNodesState> {
constructor(props: {}) {
super(props);

this.state = {
...customNodeSize,
layoutStage: 0,
};
}

resize = () => {
this.setState({ layoutStage: this.state.layoutStage + 1 });
};

renderNode = (
node: NodeOptions,
reportSize: ReportSize,
valueCache: ValueCache,
layoutStage: number
) => {
return (
<Node
key={node.id}
node={node}
reportSize={reportSize}
valueCache={valueCache}
html={true}
layoutStage={layoutStage}
>
{{
shape: (innerSize: Size) => (
<Rect node={node} innerSize={innerSize} />
),
label: () => (
<CustomLabel
title={node.label}
description={node.meta.description}
multiplier={this.state.layoutStage}
/>
),
}}
</Node>
);
};

render() {
const { nodes, edges } = this.state;

return (
<div style={{ height: '100%' }}>
<h1>Resize</h1>
<p>Example that shows the resizing of a custom node label</p>
<div>
<input type="button" value="Resize" onClick={this.resize} />
</div>
<svg id="schedule" width={800} height={800}>
<DagreReact
layoutStage={this.state.layoutStage}
nodes={nodes}
edges={edges}
renderNode={this.renderNode}
graphOptions={{
marginx: 15,
marginy: 15,
rankdir: 'TB',
ranksep: 55,
nodesep: 15,
}}
/>
</svg>
</div>
);
}
}

type CustomLabelProps = {
title: string;
description: string;
multiplier: number;
};

const CustomLabel: React.FC<CustomLabelProps> = ({
title,
description,
multiplier,
}) => {
return (
<div
style={{
padding: '10px',
border: '2px solid #000',
width: `${180 + multiplier * 10}px`,
}}
>
<div style={{ fontSize: '20px', fontWeight: 'bold' }}>{title}</div>
<div>{description}</div>
</div>
);
};
11 changes: 9 additions & 2 deletions src/DagreReact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ export interface DagreReactProps {
graphLayoutComplete: (width?: number, height?: number) => void;
graphOptions: GraphOptions;
stage: number;
layoutStage: number;
renderNode?: (
node: NodeOptions,
reportSize: ReportSize,
valueCache: ValueCache
valueCache: ValueCache,
layoutStage: number
) => React.ReactElement<any>;
renderEdge?: (
index: number,
Expand Down Expand Up @@ -70,6 +72,7 @@ type DagreReactState = {
shapes: ShapesDefinition;
graph: Graph;
previousStage: number;
layoutStage: number;
};

const getShapeDefinitionFunc = (
Expand Down Expand Up @@ -97,6 +100,7 @@ export default class DagreReact extends React.Component<
graphOptions: {},
graphLayoutComplete: () => {},
stage: 1,
layoutStage: 1,
};

constructor(props: DagreReactProps) {
Expand All @@ -118,6 +122,7 @@ export default class DagreReact extends React.Component<
shapes: { ...builtInShapes, ...props.customShapes },
graph: graph,
previousStage: props.stage,
layoutStage: props.layoutStage,
};

this.valueCache = new ValueCache();
Expand Down Expand Up @@ -188,7 +193,8 @@ export default class DagreReact extends React.Component<
return renderNodeFunc(
node,
this.reportNodeSize.bind(this, index),
this.valueCache
this.valueCache,
this.props.layoutStage
);
})}
{edges.map((edgeMeta, index) => {
Expand Down Expand Up @@ -222,6 +228,7 @@ export default class DagreReact extends React.Component<
reportSize={reportSize}
valueCache={valueCache}
html={nodeLabel.html}
layoutStage={this.props.layoutStage}
>
{{
shape: (innerSize: Size) => (
Expand Down
17 changes: 14 additions & 3 deletions src/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type NodeProps = {
reportSize: ReportSize;
valueCache: ValueCache;
html: boolean;
layoutStage?: number;
children: {
shape: (innerSize: Size) => React.ReactElement<any>;
label: () => React.ReactElement<any>;
Expand All @@ -25,14 +26,22 @@ const Node: React.FC<NodeProps> = ({
node,
reportSize,
valueCache,
layoutStage,
html,
children,
}) => {
const targetRef = React.useRef<SVGGElement>(null);
const labelRef = React.useRef<any>(null);
const shapeRef = React.useRef<SVGGElement>(null);

const labelSize = useSize(labelRef, `Node: ${node.id} - labelSize`);
const labelSize = useSize(
labelRef,
`Node: ${node.id} - labelSize`,
undefined,
undefined,
undefined,
layoutStage
);

const labelWithPaddingSize = {
width: labelSize.width,
Expand Down Expand Up @@ -70,14 +79,16 @@ const Node: React.FC<NodeProps> = ({
`Node: ${node.id} - shapeSize`,
undefined,
undefined,
labelSize
labelSize,
layoutStage
);
useSize(
targetRef,
`Node: ${node.id} - nodesize`,
{ width: node.width, height: node.height },
reportSize,
shapeSize
shapeSize,
layoutStage
);

// TODO probably a better solution for this, maybe just editing node to store the shapesize
Expand Down
4 changes: 3 additions & 1 deletion src/useSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ function useSize(
tag: string,
size?: Size,
reportSize?: ReportSize,
monitorSize?: Size
monitorSize?: Size,
layoutStage?: number
) {
const [dim, setDim] = useState({
height: 0,
Expand Down Expand Up @@ -60,6 +61,7 @@ function useSize(
reportSize,
monitorSize ? monitorSize.height : undefined,
monitorSize ? monitorSize.width : undefined,
layoutStage,
]);

return dim;
Expand Down

0 comments on commit 7bf6710

Please sign in to comment.