Skip to content
This repository was archived by the owner on Sep 17, 2021. It is now read-only.

Commit e9b54c9

Browse files
committed
Working canvas plotting.
1 parent 25865d2 commit e9b54c9

File tree

12 files changed

+4714
-146
lines changed

12 files changed

+4714
-146
lines changed

package-lock.json

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

package.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,18 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6+
"@nivo/line": "^0.52.1",
7+
"d3-array": "^2.0.3",
8+
"d3-axis": "^1.0.12",
9+
"d3-scale": "^3.0.0",
10+
"d3-time": "^1.0.11",
11+
"d3-time-format": "^2.1.3",
12+
"lodash": "^4.17.11",
13+
"nivo": "^0.31.0",
14+
"plotly.js": "^1.45.3",
615
"react": "^16.8.4",
716
"react-dom": "^16.8.4",
17+
"react-plotly.js": "^2.3.0",
818
"react-scripts": "2.1.8"
919
},
1020
"scripts": {
@@ -21,5 +31,8 @@
2131
"not dead",
2232
"not ie <= 11",
2333
"not op_mini all"
24-
]
34+
],
35+
"devDependencies": {
36+
"canvas": "^2.4.1"
37+
}
2538
}

public/index.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222
work correctly both with client-side routing and a non-root public URL.
2323
Learn how to configure a non-root public URL by running `npm run build`.
2424
-->
25-
<title>React App</title>
25+
<title>FTP Demo</title>
26+
<script src="https://www-bd.fnal.gov/acnet/acnet.js"></script>
27+
<script src="https://www-bd.fnal.gov/acnet/proto_lib.js"></script>
28+
<script src="https://www-bd.fnal.gov/acnet/dpm_protocol.js"></script>
29+
<script src="https://www-bd.fnal.gov/acnet/dpm.js"></script>
2630
</head>
2731
<body>
2832
<noscript>You need to enable JavaScript to run this app.</noscript>

src/Animation.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React, { Component } from 'react';
2+
import Canvas from './Canvas';
3+
4+
class Animation extends Component {
5+
constructor(props) {
6+
super(props);
7+
8+
this.state = {
9+
data: null
10+
}
11+
12+
this.updateAnimationState = this.updateAnimationState.bind(this);
13+
}
14+
15+
componentDidMount() {
16+
this.rafId = requestAnimationFrame(this.updateAnimationState);
17+
}
18+
19+
updateAnimationState() {
20+
this.setState({ data: this.props.data });
21+
this.rafId = requestAnimationFrame(this.updateAnimationState);
22+
}
23+
24+
componentWillUnmount() {
25+
cancelAnimationFrame(this.rafId);
26+
}
27+
28+
render() {
29+
const { data, ...otherProps } = this.props;
30+
return (
31+
<Canvas data={this.state.data} {...otherProps} />
32+
);
33+
}
34+
}
35+
36+
export default Animation;

src/App.css

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/App.js

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/App.test.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/Canvas.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React, { Component } from 'react';
2+
import PureCanvas from './PureCanvas';
3+
4+
class Canvas extends Component {
5+
constructor(props) {
6+
super(props);
7+
this.saveContext = this.saveContext.bind(this);
8+
}
9+
10+
saveContext(ctx) {
11+
this.ctx = ctx;
12+
}
13+
14+
componentDidUpdate() {
15+
const { data, maxLength } = this.props;
16+
const width = this.ctx.canvas.width;
17+
const height = this.ctx.canvas.height;
18+
this.ctx.save();
19+
this.ctx.beginPath();
20+
this.ctx.clearRect(0, 0, width, height);
21+
22+
if (Array.isArray(data)) { // This must come first; typeof Array == "object"
23+
data.forEach(({ x, y }, i) => {
24+
const length = maxLength;
25+
const pointsPerPixel = 1; // TODO: This should be a prop
26+
27+
if (i === 0) {
28+
this.ctx.moveTo(i * pointsPerPixel, y * 20 - 800);
29+
} else {
30+
this.ctx.lineTo(i * pointsPerPixel, y * 20 - 800);
31+
}
32+
})
33+
} else if (typeof data === "object") {
34+
const values = Object.values(data);
35+
values.forEach(localData => {
36+
localData.forEach(({ x, y }, i) => {
37+
const pointsPerPixel = width / maxLength;
38+
39+
if (i === 0) {
40+
this.ctx.moveTo(i * pointsPerPixel, y);
41+
} else {
42+
this.ctx.lineTo(i * pointsPerPixel, y);
43+
}
44+
})
45+
});
46+
}
47+
48+
this.ctx.strokeStyle = "red";
49+
this.ctx.stroke();
50+
this.ctx.restore();
51+
}
52+
53+
render() {
54+
return (
55+
<PureCanvas
56+
contextRef={this.saveContext}
57+
width={this.props.width}
58+
height={this.props.height}
59+
/>
60+
);
61+
}
62+
}
63+
64+
export default Canvas;

src/Dpm.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { Component } from 'react';
2+
3+
class Dpm extends Component {
4+
constructor(props) {
5+
super(props);
6+
7+
this.state = {
8+
data: null,
9+
info: null,
10+
isLoading: false,
11+
error: null,
12+
};
13+
14+
this.dpm = new window.DPM();
15+
16+
this.addRequest = drfString => {
17+
this.dpm.addRequest(drfString, (data, info) => {
18+
this.setState({
19+
data,
20+
[drfString]: { data, info },
21+
isLoading: false
22+
});
23+
}, error => {
24+
this.setState({
25+
error,
26+
isLoading: false
27+
});
28+
});
29+
}
30+
31+
if (Array.isArray(this.props.drf)) {
32+
this.props.drf.forEach(this.addRequest);
33+
} else if (typeof this.props.drf === "string") {
34+
this.addRequest(this.props.drf);
35+
} else {
36+
this.setState({
37+
error: "No valid DRF property",
38+
isLoading: false
39+
});
40+
41+
console.error("No valid DRF property");
42+
}
43+
}
44+
45+
componentDidMount() {
46+
this.setState({ isLoading: true });
47+
this.dpm.start();
48+
}
49+
50+
render() {
51+
return this.props.children(this.state);
52+
}
53+
}
54+
55+
export default Dpm;

src/Ftp.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import React, { Component } from 'react';
2+
import Animation from './Animation';
3+
4+
class Ftp extends Component {
5+
constructor(props) {
6+
super(props);
7+
8+
this.state = {
9+
data: [],
10+
info: null,
11+
isLoading: false,
12+
error: null,
13+
};
14+
}
15+
16+
componentWillReceiveProps() {
17+
const { data: newData, info: newInfo } = this.props.data;
18+
19+
this.setState(({ data }) => {
20+
let combinedData = data.slice(); // Copy Array
21+
combinedData.push({ x: newData.timestamp, y: newData.data });
22+
if (combinedData.length > 800) {
23+
combinedData = combinedData.slice(800 / 4);
24+
}
25+
return {
26+
data: combinedData,
27+
info: newInfo
28+
}
29+
});
30+
}
31+
32+
render() {
33+
return <Animation
34+
width={this.props.width}
35+
height={this.props.height}
36+
data={this.state.data}
37+
/>;
38+
}
39+
}
40+
41+
export default Ftp;
42+
43+
// const date = new Date()
44+
// date.setMinutes(0)
45+
// date.setSeconds(0)
46+
// date.setMilliseconds(0)
47+
48+
// this.state = {
49+
// dataA: range(7920).map(i => ({
50+
// x: time.timeMinute.offset(date, i * 30),
51+
// y: 10 + Math.round(Math.random() * 20),
52+
// })),
53+
// dataB: range(7920).map(i => ({
54+
// x: time.timeMinute.offset(date, i * 30),
55+
// y: 30 + Math.round(Math.random() * 20),
56+
// })),
57+
// dataC: range(7920).map(i => ({
58+
// x: time.timeMinute.offset(date, i * 30),
59+
// y: 50 + Math.round(Math.random() * 20),
60+
// })),
61+
// dataD: range(7920).map(i => ({
62+
// x: time.timeMinute.offset(date, i * 30),
63+
// y: 70 + Math.round(Math.random() * 20),
64+
// })),
65+
// }
66+
67+
// next = () => {
68+
// const packageSize = 7910;
69+
// const dataA = this.state.dataA.slice(packageSize);
70+
// const dataB = this.state.dataB.slice(packageSize);
71+
// const dataC = this.state.dataC.slice(packageSize);
72+
// const dataD = this.state.dataD.slice(packageSize);
73+
74+
// Array(packageSize).fill(null).forEach(_ => {
75+
// dataA.push({
76+
// x: time.timeMinute.offset(last(dataA).x, 30),
77+
// y: 10 + Math.round(Math.random() * 20),
78+
// });
79+
// dataB.push({
80+
// x: time.timeMinute.offset(last(dataB).x, 30),
81+
// y: 30 + Math.round(Math.random() * 20),
82+
// });
83+
// dataC.push({
84+
// x: time.timeMinute.offset(last(dataC).x, 30),
85+
// y: 50 + Math.round(Math.random() * 20),
86+
// });
87+
// dataD.push({
88+
// x: time.timeMinute.offset(last(dataD).x, 30),
89+
// y: 70 + Math.round(Math.random() * 20),
90+
// });
91+
// });
92+
93+
// this.setState({ dataA, dataB, dataC, dataD });
94+
// }

0 commit comments

Comments
 (0)