Skip to content

Commit

Permalink
refactor(d3): upgrades D3 dep to v5, adjusts lib API (#125)
Browse files Browse the repository at this point in the history
refactor: gets basic tree rendering working with D3@5.x.x (#125)

* Lib types (`TreeNode`) still need to be unified with D3 generics
(`HierarchyPointNode<T>`)

* offset-on-translate needs to be ported to v5 to avoid jump-on-grab
issue

fix(diagonal path): fixes diagonal path fns for v5

feat(demo): adds "step" pathFn button

fix(straight path): reimplements drawStraightPath for D3 v5

fix(zoom): fixes pan and zoom jump for v5 API

fix: fixes translation origins for Node

test(link): fixes expected path string output

chore(demo): adds missing toggle for props.shouldCollapseNeighborNodes

chore(scripts): adds `jest --findRelatedTests` for staged files

fix: remaps some undefined prop access, type sigs for tree methods

test(tree): fix prop selection `nodeData` -> `data`

test(node): adjusts mock data for new NodeProps shape

chore: clean up console statement

fix(tree): fixes props.collapseNeighborNodes regression
  • Loading branch information
bkrem committed Feb 14, 2020
1 parent 407c40a commit 9336178
Show file tree
Hide file tree
Showing 11 changed files with 793 additions and 232 deletions.
22 changes: 22 additions & 0 deletions demo/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class App extends Component {
translateX: 200,
translateY: 300,
collapsible: true,
shouldCollapseNeighborNodes: false,
initialDepth: 1,
depthFactor: undefined,
zoomable: true,
Expand Down Expand Up @@ -201,6 +202,10 @@ class App extends Component {
this.setState(prevState => ({ collapsible: !prevState.collapsible }));
}

toggleCollapseNeighborNodes = () => {
this.setState(prevState => ({ shouldCollapseNeighborNodes: !prevState.shouldCollapseNeighborNodes }));
}

toggleZoomable() {
this.setState(prevState => ({ zoomable: !prevState.zoomable }));
}
Expand Down Expand Up @@ -419,6 +424,13 @@ class App extends Component {
>
{'Straight'}
</button>
<button
type="button"
className="btn btn-controls btn-block"
onClick={() => this.setPathFunc('step')}
>
{'Step'}
</button>
</div>

<div className="prop-container">
Expand All @@ -430,6 +442,15 @@ class App extends Component {
/>
</div>

<div className="prop-container">
<span className="prop">Collapse neighbor nodes</span>
<Switch
name="collapseNeighborsBtn"
checked={this.state.shouldCollapseNeighborNodes}
onChange={this.toggleCollapseNeighborNodes}
/>
</div>

<div className="prop-container">
<label className="prop" htmlFor="nodeSvgShape">
Node SVG Shape
Expand Down Expand Up @@ -680,6 +701,7 @@ class App extends Component {
depthFactor={this.state.depthFactor}
textLayout={this.state.textLayout}
styles={this.state.styles}
shouldCollapseNeighborNodes={this.state.shouldCollapseNeighborNodes}
onUpdate={(...args) => {console.log(args)}}
onClick={(...args) => { console.log('onClick'); console.log(args) }}
onLinkClick={(...args) => { console.log('onLinkClick'); console.log(args) }}
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@
"src/**/*.js": [
"eslint",
"prettier --write",
"jest --findRelatedTests",
"git add"
],
"src/**/*.{ts,tsx}": [
"prettier --write",
"jest --findRelatedTests",
"git add"
]
},
Expand All @@ -69,14 +71,14 @@
},
"dependencies": {
"clone": "^2.1.1",
"d3": "3.5.17",
"deep-equal": "^2.0.1",
"prop-types": "^15.5.10",
"react-lifecycles-compat": "^3.0.4",
"react-transition-group": "^1.1.3",
"uuid": "^3.0.1"
},
"peerDependencies": {
"d3": "^5.0.0",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
Expand All @@ -86,10 +88,12 @@
"@babel/preset-env": "^7.8.3",
"@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@types/d3": "^5.7.2",
"@types/react": "^16.9.17",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
"coveralls": "^3.0.0",
"d3": "^5.15.0",
"enzyme": "^3.4.4",
"enzyme-adapter-react-16": "^1.2.0",
"eslint": "4.16.0",
Expand Down
41 changes: 13 additions & 28 deletions src/Link/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import React, { SyntheticEvent } from 'react';
import { svg, select } from 'd3';
import { select, linkHorizontal, linkVertical, HierarchyPointNode } from 'd3';
import {
Orientation,
EnhancedTreeNode,
TreeLink,
PathFunctionOption,
PathFunction,
TreeNodeDatum,
} from '../types/common';
import './style.css';

type LinkEventHandler = (
source: EnhancedTreeNode,
target: EnhancedTreeNode,
source: HierarchyPointNode<TreeNodeDatum>,
target: HierarchyPointNode<TreeNodeDatum>,
evt: SyntheticEvent
) => void;

Expand Down Expand Up @@ -64,7 +64,7 @@ export default class Link extends React.PureComponent<LinkProps, LinkState> {
.transition()
.duration(transitionDuration)
.style('opacity', opacity)
.each('end', done);
.on('end', done);
}
}

Expand All @@ -77,32 +77,17 @@ export default class Link extends React.PureComponent<LinkProps, LinkState> {
}

drawDiagonalPath(linkData: LinkProps['linkData'], orientation: LinkProps['orientation']) {
const diagonal = svg
.diagonal()
.projection(d => (orientation === 'horizontal' ? [d.y, d.x] : [d.x, d.y]));
return diagonal(linkData);
const { source, target } = linkData;
return orientation === 'horizontal'
? linkHorizontal()({ source: [source.y, source.x], target: [target.y, target.x] })
: linkVertical()({ source: [source.x, source.y], target: [target.x, target.y] });
}

drawStraightPath(linkData: LinkProps['linkData'], orientation: LinkProps['orientation']) {
const straight = svg
.line()
.interpolate('basis')
.x(d => d.x)
.y(d => d.y);

let data = [
{ x: linkData.source.x, y: linkData.source.y },
{ x: linkData.target.x, y: linkData.target.y },
];

if (orientation === 'horizontal') {
data = [
{ x: linkData.source.y, y: linkData.source.x },
{ x: linkData.target.y, y: linkData.target.x },
];
}

return straight(data);
const { source, target } = linkData;
return orientation === 'horizontal'
? `M${source.y},${source.x}L${target.y},${target.x}`
: `M${source.x},${source.y}L${target.x},${target.y}`;
}

drawElbowPath(linkData: LinkProps['linkData'], orientation: LinkProps['orientation']) {
Expand Down
30 changes: 15 additions & 15 deletions src/Link/tests/index.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { shallow, mount } from 'enzyme';

import Link from '../index';
import Link from '../index.tsx';

describe('<Link />', () => {
const linkData = {
Expand Down Expand Up @@ -83,33 +83,33 @@ describe('<Link />', () => {

it('returns an appropriate elbowPath according to `props.orientation`', () => {
expect(Link.prototype.drawElbowPath(linkData, 'horizontal')).toBe(
`M${linkData.source.y},${linkData.source.x}V${linkData.target.x}H${linkData.target.y}`,
`M${linkData.source.y},${linkData.source.x}V${linkData.target.x}H${linkData.target.y}`
);
expect(Link.prototype.drawElbowPath(linkData, 'vertical')).toBe(
`M${linkData.source.x},${linkData.source.y}V${linkData.target.y}H${linkData.target.x}`,
`M${linkData.source.x},${linkData.source.y}V${linkData.target.y}H${linkData.target.x}`
);
});

it('returns an appropriate diagonal according to `props.orientation`', () => {
const ymean = (linkData.target.y + linkData.source.y) / 2;
expect(Link.prototype.drawDiagonalPath(linkData, 'horizontal')).toBe(
`M${linkData.source.y},${linkData.source.x}` +
`C${ymean},${linkData.source.x} ${ymean},${linkData.target.x} ` +
`${linkData.target.y},${linkData.target.x}`,
`C${ymean},${linkData.source.x},${ymean},${linkData.target.x},` +
`${linkData.target.y},${linkData.target.x}`
);
expect(Link.prototype.drawDiagonalPath(linkData, 'vertical')).toBe(
`M${linkData.source.x},${linkData.source.y}` +
`C${linkData.source.x},${ymean} ${linkData.target.x},${ymean} ` +
`${linkData.target.x},${linkData.target.y}`,
`C${linkData.source.x},${ymean},${linkData.target.x},${ymean},` +
`${linkData.target.x},${linkData.target.y}`
);
});

it('returns an appropriate straightPath according to `props.orientation`', () => {
expect(Link.prototype.drawStraightPath(linkData, 'horizontal')).toBe(
`M${linkData.source.y},${linkData.source.x}L${linkData.target.y},${linkData.target.x}`,
`M${linkData.source.y},${linkData.source.x}L${linkData.target.y},${linkData.target.x}`
);
expect(Link.prototype.drawStraightPath(linkData, 'vertical')).toBe(
`M${linkData.source.x},${linkData.source.y}L${linkData.target.x},${linkData.target.y}`,
`M${linkData.source.x},${linkData.source.y}L${linkData.target.x},${linkData.target.y}`
);
});

Expand All @@ -118,10 +118,10 @@ describe('<Link />', () => {
const deltaY = target.y - source.y;

expect(Link.prototype.drawStepPath(linkData, 'horizontal')).toBe(
`M${source.y},${source.x} H${source.y + deltaY / 2} V${target.x} H${target.y}`,
`M${source.y},${source.x} H${source.y + deltaY / 2} V${target.x} H${target.y}`
);
expect(Link.prototype.drawStepPath(linkData, 'vertical')).toBe(
`M${source.x},${source.y} V${source.y + deltaY / 2} H${target.x} V${target.y}`,
`M${source.x},${source.y} V${source.y + deltaY / 2} H${target.x} V${target.y}`
);
});

Expand All @@ -131,7 +131,7 @@ describe('<Link />', () => {

expect(renderedComponent.instance().applyOpacity).toHaveBeenCalledWith(
fixture,
mockProps.transitionDuration,
mockProps.transitionDuration
);
});

Expand All @@ -146,7 +146,7 @@ describe('<Link />', () => {
expect(onClickSpy).toHaveBeenCalledWith(
linkData.source,
linkData.target,
expect.objectContaining(mockEvt),
expect.objectContaining(mockEvt)
);
});

Expand All @@ -160,7 +160,7 @@ describe('<Link />', () => {
expect(onMouseOverSpy).toHaveBeenCalledWith(
linkData.source,
linkData.target,
expect.objectContaining(mockEvt),
expect.objectContaining(mockEvt)
);
});

Expand All @@ -174,7 +174,7 @@ describe('<Link />', () => {
expect(onMouseOutSpy).toHaveBeenCalledWith(
linkData.source,
linkData.target,
expect.objectContaining(mockEvt),
expect.objectContaining(mockEvt)
);
});
});
Expand Down

0 comments on commit 9336178

Please sign in to comment.