Skip to content

Commit 0c29583

Browse files
committed
changes
2 parents 7cd6285 + 26784b8 commit 0c29583

28 files changed

+4559
-10818
lines changed

.gitignore

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
node_modules
22
.DS_Store
3-
dist/
4-
extension/bundle.js
5-
package/react-time-travel-1.0.1.tgz
3+
src/extension/build/bundles
4+
package/react-time-travel-*.tgz
65
tictactoe
7-
tictactoe/build/bundle.js
8-
tictactoe/package-lock.json
96
parents
107
coverage

package-lock.json

Lines changed: 0 additions & 10658 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"build": "webpack --mode production",
77
"dev": "webpack --mode development --watch",
8-
"test": "jest --verbose --coverage"
8+
"test": "jest --verbose --coverage --watchAll"
99
},
1010
"keywords": [
1111
"react",
@@ -37,6 +37,7 @@
3737
"eslint-plugin-jsx-a11y": "^6.2.3",
3838
"eslint-plugin-react": "^7.14.2",
3939
"jest": "^24.8.0",
40+
"jest-cli": "^24.8.0",
4041
"node-sass": "^4.12.0",
4142
"sass-loader": "^7.1.0",
4243
"style-loader": "^0.23.1",
@@ -46,6 +47,7 @@
4647
},
4748
"dependencies": {
4849
"auto-bind": "^2.1.0",
50+
"d3": "^3.5.17",
4951
"prop-types": "^15.7.2",
5052
"rc-slider": "^8.6.13",
5153
"rc-tooltip": "^3.7.3",

package/tree.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class Tree {
44
// give it a special state = 'root'
55
// a setState function that just calls the callback instantly
66
if (!useStateInstead) {
7-
this.component = (component === 'root') ? { state: 'root', setState: (partial, callback) => callback() } : component;
7+
this.component = (component === 'root') ? { state: 'root', setState: (partial, callback) => callback() } : component;
88
} else {
99
this.state = component;
1010
this.name = name;

src/app/__tests__/action.test.jsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,41 +10,51 @@ describe('unit testing for Action.jsx', () => {
1010
const props = {
1111
selected: true,
1212
handleChangeSnapshot: jest.fn(),
13-
handleSendSnapshot: jest.fn(),
13+
handleJumpSnapshot: jest.fn(),
1414
index: 1,
1515
};
1616
beforeEach(() => {
1717
wrapper = shallow(<Action {...props} />);
1818
});
1919

20-
describe('<Action> component', () => {
21-
it("<Action> should have a className 'action-component selected' if props.selected is true", () => {
20+
describe('Component', () => {
21+
test("should have a className 'action-component selected' if props.selected is true", () => {
2222
wrapper.setProps({ selected: true });
2323
expect(wrapper.hasClass('action-component selected')).toEqual(true);
2424
});
2525

26-
it("<Action> shouldn't have a className 'action-component selected' if props.selected is false", () => {
26+
test("shouldn't have a className 'action-component selected' if props.selected is false", () => {
2727
wrapper.setProps({ selected: false });
2828
expect(wrapper.hasClass('action-component selected')).toEqual(false);
2929
});
3030

31-
it('<Action> should have a text that is equal to props.index', () => {
31+
test('should have a text that is equal to props.index', () => {
3232
expect(wrapper.find('.action-component-text').text()).toEqual(props.index.toString());
3333
});
34+
35+
test('should invoke changeSnapshot method when clicked', () => {
36+
wrapper.find('.action-component').simulate('click');
37+
expect(props.handleChangeSnapshot).toHaveBeenCalled();
38+
});
3439
});
3540

36-
describe('jump button', () => {
37-
it('Should render a jump button', () => {
38-
expect(wrapper.type()).toEqual('div');
39-
expect(wrapper.find('button')).toHaveLength(1);
41+
describe('Jump Button', () => {
42+
test("should render a div with a className 'jump-button' inside action-component", () => {
43+
expect(
44+
wrapper
45+
.find('.action-component')
46+
.children()
47+
.find('.jump-button'),
48+
).toHaveLength(1);
4049
});
4150

42-
it('Should invoke the sendSnapshot method when the jump button is clicked', () => {
51+
test('should invoke jumpSnapshot method when clicked', () => {
4352
wrapper
44-
.find('button')
45-
.at(0)
53+
.find('.action-component')
54+
.children()
55+
.find('.jump-button')
4656
.simulate('click');
47-
expect(props.handleSendSnapshot).toHaveBeenCalled();
57+
expect(props.handleJumpSnapshot).toHaveBeenCalled();
4858
});
4959
});
5060
});

src/app/components/Action.jsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,37 @@ import PropTypes from 'prop-types';
33

44
const Action = (props) => {
55
const {
6-
selected, handleChangeSnapshot, handleJumpSnapshot, index,
6+
selected, handleChangeSnapshot, handleJumpSnapshot, index, sliderIndex,
77
} = props;
8+
89
return (
910
<div
1011
className={selected ? 'action-component selected' : 'action-component'}
1112
onClick={() => handleChangeSnapshot(index)}
1213
role="presentation"
14+
style={index > sliderIndex ? { color: '#5f6369' } : {}}
1315
>
1416
<div className="action-component-text">{index}</div>
15-
<div
17+
<button
1618
className="jump-button"
17-
onClick={() => handleJumpSnapshot(index)}
19+
onClick={(e) => {
20+
e.stopPropagation();
21+
handleJumpSnapshot(index);
22+
}}
1823
tabIndex={index}
19-
role="button"
24+
type="button"
2025
>
2126
Jump
22-
</div>
27+
</button>
2328
</div>
2429
);
2530
};
2631

27-
// Action.propTypes = {
28-
// selected: PropTypes.bool,
29-
// index: PropTypes.number,
30-
// };
32+
Action.propTypes = {
33+
selected: PropTypes.bool.isRequired,
34+
index: PropTypes.number.isRequired,
35+
handleChangeSnapshot: PropTypes.func.isRequired,
36+
handleJumpSnapshot: PropTypes.func.isRequired,
37+
};
3138

3239
export default Action;

src/app/components/App.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Component } from 'react';
1+
import React from 'react';
22
import MainContainer from '../containers/MainContainer';
33

44
const App = () => <MainContainer />;

src/app/components/Chart.jsx

Lines changed: 203 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,206 @@
1-
import React from 'react';
1+
import React, { Component } from 'react';
2+
import '../styles/components/_d3Tree.scss';
3+
import * as d3 from 'd3';
24

3-
const Chart = props => <div>Chart</div>;
5+
let root;
6+
7+
class Chart extends Component {
8+
constructor(props) {
9+
super(props);
10+
}
11+
12+
componentDidMount() {
13+
root = JSON.parse(JSON.stringify(this.props.snapshot));
14+
this.maked3Tree();
15+
}
16+
17+
componentWillUpdate(prevProps) {
18+
if (this.props.snapshot !== prevProps.snapshot) {
19+
root = JSON.parse(JSON.stringify(prevProps.snapshot));
20+
this.maked3Tree();
21+
}
22+
}
23+
24+
removed3Tree() {
25+
const { anchor } = this.refs;
26+
while (anchor.hasChildNodes()) {
27+
anchor.removeChild(anchor.lastChild);
28+
}
29+
}
30+
31+
maked3Tree() {
32+
this.removed3Tree();
33+
34+
const margin = {
35+
top: 20,
36+
right: 120,
37+
bottom: 20,
38+
left: 120,
39+
};
40+
const width = 960 - margin.right - margin.left;
41+
const height = 800 - margin.top - margin.bottom;
42+
43+
let i = 0;
44+
const duration = 750;
45+
46+
const tree = d3.layout.tree().size([height, width]);
47+
48+
const diagonal = d3.svg.diagonal().projection(d => [d.y, d.x]);
49+
50+
const svg = d3
51+
.select(this.refs.anchor)
52+
.append('svg')
53+
.attr('width', width + margin.right + margin.left)
54+
.attr('height', height + margin.top + margin.bottom)
55+
.append('g')
56+
.attr('transform', `translate(${margin.left},${margin.top})`);
57+
58+
root.x0 = height / 2;
59+
root.y0 = 0;
60+
61+
function update(source) {
62+
// Compute the new tree layout.
63+
const nodes = tree.nodes(root).reverse();
64+
const links = tree.links(nodes);
65+
66+
// Normalize for fixed-depth.
67+
nodes.forEach((d) => {
68+
d.y = d.depth * 180;
69+
});
70+
71+
// Update the nodes…
72+
const node = svg.selectAll('g.node').data(nodes, d => d.id || (d.id = ++i));
73+
74+
// Enter any new nodes at the parent's previous position.
75+
const nodeEnter = node
76+
.enter()
77+
.append('g')
78+
.attr('class', 'node')
79+
.attr('transform', d => `translate(${source.y0},${source.x0})`)
80+
.on('click', click)
81+
.on('mouseover', mouseover)
82+
.on('mouseout', mouseout);
83+
84+
nodeEnter
85+
.append('circle')
86+
.attr('r', 1e-6)
87+
.style('fill', d => (d._children ? 'lightsteelblue' : '#fff'));
88+
89+
nodeEnter
90+
.append('text')
91+
.attr('x', d => (d.children || d._children ? -10 : 10))
92+
.attr('dy', '.35em')
93+
.attr('text-anchor', d => (d.children || d._children ? 'end' : 'start'))
94+
.text(d => d.name)
95+
.style('fill-opacity', 1e-6);
96+
97+
// Transition nodes to their new position.
98+
const nodeUpdate = node
99+
.transition()
100+
.duration(duration)
101+
.attr('transform', d => `translate(${d.y},${d.x})`);
102+
103+
nodeUpdate
104+
.select('circle')
105+
.attr('r', 4.5)
106+
.style('fill', d => (d._children ? 'lightsteelblue' : '#fff'));
107+
108+
nodeUpdate.select('text').style('fill-opacity', 1);
109+
110+
// Transition exiting nodes to the parent's new position.
111+
const nodeExit = node
112+
.exit()
113+
.transition()
114+
.duration(duration)
115+
.attr('transform', d => `translate(${source.y},${source.x})`)
116+
.remove();
117+
118+
nodeExit.select('circle').attr('r', 1e-6);
119+
120+
nodeExit.select('text').style('fill-opacity', 1e-6);
121+
122+
// Update the links…
123+
const link = svg.selectAll('path.link').data(links, d => d.target.id);
124+
125+
// Enter any new links at the parent's previous position.
126+
link
127+
.enter()
128+
.insert('path', 'g')
129+
.attr('class', 'link')
130+
.attr('d', (d) => {
131+
const o = { x: source.x0, y: source.y0 };
132+
return diagonal({ source: o, target: o });
133+
});
134+
135+
// Transition links to their new position.
136+
link
137+
.transition()
138+
.duration(duration)
139+
.attr('d', diagonal);
140+
141+
// Transition exiting nodes to the parent's new position.
142+
link
143+
.exit()
144+
.transition()
145+
.duration(duration)
146+
.attr('d', (d) => {
147+
const o = { x: source.x, y: source.y };
148+
return diagonal({ source: o, target: o });
149+
})
150+
.remove();
151+
152+
// Stash the old positions for transition.
153+
nodes.forEach((d) => {
154+
d.x0 = d.x;
155+
d.y0 = d.y;
156+
});
157+
}
158+
159+
// Toggle children on click.
160+
function click(d) {
161+
if (d.children) {
162+
d._children = d.children;
163+
d.children = null;
164+
} else {
165+
d.children = d._children;
166+
d._children = null;
167+
}
168+
update(d);
169+
}
170+
171+
// Show state on mouse over
172+
function mouseover(d) {
173+
d3.select(this)
174+
.append('text')
175+
.attr('class', 'hover')
176+
.attr('transform', d => 'translate(5, -10)')
177+
.text(d.state === undefined ? '' : JSON.stringify(d.state));
178+
}
179+
180+
// Toggle children on click.
181+
function mouseout(d) {
182+
d3.select(this)
183+
.select('text.hover')
184+
.remove();
185+
}
186+
187+
function collapse(d) {
188+
if (d.children) {
189+
d._children = d.children;
190+
d._children.forEach(collapse);
191+
d.children = null;
192+
}
193+
}
194+
195+
// root.children.forEach(collapse);
196+
update(root);
197+
198+
// d3.select(self.frameElement).style("height", "800px");
199+
}
200+
201+
render() {
202+
return <div ref="anchor" className="d3Container" width="100%" />;
203+
}
204+
}
4205

5206
export default Chart;

0 commit comments

Comments
 (0)