Skip to content

Commit 2b8d8a3

Browse files
authored
Merge pull request #2 from math-dot-random/featurebranch
Stock chart changes
2 parents 539c41c + 50b2b3f commit 2b8d8a3

19 files changed

Lines changed: 650 additions & 78 deletions

FEC/README.md

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,20 @@
1-
Project Name
21

3-
> Project description
2+
> Dynamically generated stock price history chart using a mysql database
43
54
## Related Projects
65

7-
- https://github.com/teamName/repo
8-
- https://github.com/teamName/repo
9-
- https://github.com/teamName/repo
10-
- https://github.com/teamName/repo
6+
- https://github.com/math-dot-random/earnings-chart
7+
- https://github.com/math-dot-random/trade-panel
8+
- https://github.com/math-dot-random/price-paid-chart
9+
- https://github.com/math-dot-random/suggestions
1110

12-
## Table of Contents
11+
## Directions
1312

14-
1. [Usage](#Usage)
15-
1. [Requirements](#requirements)
16-
1. [Development](#development)
13+
1. To create mysql database execute this file from the command line by typing:
14+
mysql -u root -p < schema.sql
1715

18-
## Usage
16+
2. To seed data execute this file from the command line by typing:
17+
mysql -u root -p < mysqldata.sql
1918

20-
> Some usage instructions
2119

22-
## Requirements
2320

24-
An `nvmrc` file is included if using [nvm](https://github.com/creationix/nvm).
25-
26-
- Node 6.13.0
27-
- etc
28-
29-
## Development
30-
31-
### Installing Dependencies
32-
33-
From within the root directory:
34-
35-
```sh
36-
npm install -g webpack
37-
npm install
38-
```

FEC/client/src/components/App.jsx

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,45 @@
11
import React from 'react';
22
const $ = require('jquery');
3-
3+
import StockChart from './StockChart.jsx';
44

55
class App extends React.Component {
66
constructor(props) {
77
super(props);
8-
}
8+
this.state = {
9+
priceData:[],
10+
currentPrice: 0,
11+
stockName: '',
12+
date: new Date(),
13+
stockData: [],
14+
closingCost: 0,
15+
type: '1D',
16+
ticker: 'TSLA',
917

18+
}
19+
this.retrieveData = this.retrieveData.bind(this);
20+
this.handleGraphTypeChange = this.handleGraphTypeChange.bind(this);
21+
this.generateStockDataArray = this.generateStockDataArray.bind(this);
22+
}
1023

1124
componentDidMount() {
25+
//retrieve the path and filename of current page
26+
let pathName = window.location.pathname.match(/\/stocks\/(\w+)/i);
27+
let ticker = pathName ? pathName[1] : null;
28+
if (ticker) {
29+
this.setState({ticker}, () => this.retrieveData());
30+
}
31+
}
32+
33+
//a function that makes an http GET request using the ticker and graph type
34+
retrieveData() {
1235
$.ajax({
13-
url: '/api/stocks/prices',
36+
url: `/api/stocks/${this.state.ticker}/prices/${this.state.type}`,
1437
type: 'GET',
1538
success: (data) => {
39+
this.setState({
40+
priceData: data,
41+
stockName: data[0].name
42+
}, () => this.generateStockDataArray())
1643
console.log('GET request successful', data);
1744
},
1845
error: (err) => {
@@ -21,14 +48,104 @@ class App extends React.Component {
2148
})
2249
}
2350

51+
//a function that updates the type and data on the state when the graph type is changed
52+
handleGraphTypeChange(event) {
53+
event.preventDefault();
54+
this.setState({
55+
type: event.target.name
56+
}, () => this.retrieveData())
57+
}
58+
59+
//a function that creates a stock data object for each retrieved price data point
60+
generateStockDataArray() {
61+
let graphData = [];
62+
let today = this.state.date;
63+
let type = this.state.type;
64+
let dd = String(today.getDate()).padStart(2, '0');
65+
let mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
66+
let yyyy = today.getFullYear();
67+
let month;
68+
let schedule = ['9:00 AM', '9:30 AM', '10:00 AM', '10:30 AM', '11:30 AM', '12:00 PM', '12:30 PM', '1:00 PM', '1:30 PM', '2:00 PM', '2:30 PM', '3:00 PM', '3:30 PM', '4:00 PM', '4:30 PM', '5:00 PM']
69+
if(mm === 0) {
70+
month = 'JAN';
71+
} else if (mm === 1) {
72+
month = 'FEB';
73+
}else if (mm === 2) {
74+
month = 'MAR';
75+
}else if (mm === 3) {
76+
month = 'APR';
77+
}else if (mm === 4) {
78+
month = 'MAY';
79+
}else if (mm === 5) {
80+
month = 'JUN';
81+
}else if (mm === 6) {
82+
month = 'JUL';
83+
}else if (mm === 7) {
84+
month = 'AUG';
85+
}else if (mm === 8) {
86+
month = 'SEPT';
87+
}else if (mm === 9) {
88+
month = 'OCT';
89+
}else if (mm === 10) {
90+
month = 'NOV';
91+
}else if (mm === 11) {
92+
month = 'DEC'
93+
}
94+
const data = this.state.priceData.slice();
95+
if (type === '1D') {
96+
for (var i = 0; i < data.length; i++) {
97+
graphData.push({dateString: `${schedule[i]} ET`, x: i, y: data[i].price});
98+
}
99+
this.setState({
100+
stockData: graphData
101+
})
102+
} else if (type === '1W') {
103+
for (var i = 0; i < data.length; i++) {
104+
graphData.push({dateString: `${schedule[i]}, ${month} ${dd} ET`, x: i, y: data[i].price});
105+
}
106+
this.setState({
107+
stockData: graphData
108+
})
109+
} else if (type === '1M') {
110+
for (var i = 0; i < data.length; i++) {
111+
graphData.push({dateString: `${schedule[i]}, ${month} ${dd} ET`, x: i, y: data[i].price});
112+
}
113+
this.setState({
114+
stockData: graphData
115+
})
116+
} else if (type ==='3M') {
117+
for (var i = 0; i < data.length; i++) {
118+
graphData.push({dateString: `${schedule[i]}, ${month} ${dd} ET`, x: i, y: data[i].price});
119+
}
120+
this.setState({
121+
stockData: graphData
122+
})
123+
} else if (type === '1Y') {
124+
for (var i = 0; i < data.length; i++) {
125+
graphData.push({dateString: today, x: i, y: data[i].price});
126+
}
127+
this.setState({
128+
stockData: graphData
129+
})
130+
} else if (type === '5Y') {
131+
for (var i = 0; i < data.length; i++) {
132+
graphData.push({dateString: today, x: i, y: data[i].price});
133+
}
134+
this.setState({
135+
stockData: graphData
136+
})
137+
}
138+
}
139+
24140
render () {
25141
return (
26142
<div>
27-
<h1> Robinhood.com </h1>
28-
<h3> Stock Chart </h3>
143+
<StockChart currentPrice={this.state.currentPrice} stockName={this.state.stockName} stockData={this.state.stockData} market={this.state.market} handleGraphTypeChange={this.handleGraphTypeChange} type={this.state.type}/>
29144
</div>
145+
30146
)
31147
}
32-
}
148+
};
149+
150+
export default App;
33151

34-
export default App;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import React from 'react';
2+
3+
class LineChart extends React.Component {
4+
constructor(props) {
5+
super(props);
6+
7+
this.state = {
8+
}
9+
this.getMinX = this.getMinX.bind(this);
10+
this.getMaxX = this.getMaxX.bind(this);
11+
this.getMinY = this.getMinY.bind(this);
12+
this.getMaxY = this.getMaxY.bind(this);
13+
this.getSvgX = this.getSvgX.bind(this);
14+
this.getSvgY = this.getSvgY.bind(this);
15+
16+
}
17+
18+
// GET MAX & MIN X
19+
//x min and max are the first and last values in the data array
20+
getMinX() {
21+
console.log('stockData', this.props.stockData);
22+
const data = this.props.stockData;
23+
if (data.length > 0) {
24+
return data[0].x;
25+
} else {
26+
return;
27+
}
28+
29+
}
30+
getMaxX() {
31+
const data = this.props.stockData;
32+
if (data.length > 0) {
33+
return data[data.length - 1].x;
34+
} else {
35+
return;
36+
}
37+
}
38+
39+
// GET MAX & MIN Y
40+
//a function that reduces the input data array and returns a minimum y value
41+
getMinY() {
42+
const data = this.props.stockData;
43+
if (data.length > 0) {
44+
return data.reduce((min, p) => p.y < min ? p.y : min, data[0].y);
45+
}
46+
}
47+
48+
//a function that reduces the input data array and returns a maximum y value
49+
getMaxY() {
50+
const data = this.props.stockData;
51+
if (data.length > 0) {
52+
return data.reduce((max, p) => p.y > max ? p.y : max, data[0].y);
53+
} else {
54+
return;
55+
}
56+
}
57+
58+
//LINE CHART COORDINATE HELPER FUNCTIONS
59+
60+
//a function that creates an x coordinate point
61+
getSvgX(x) {
62+
const {svgWidth} = this.props;
63+
return (x / this.getMaxX() * svgWidth);
64+
}
65+
66+
//a function that creates an y coordinate point
67+
getSvgY(y) {
68+
const {svgHeight} = this.props;
69+
return svgHeight - (y / this.getMaxY() * svgHeight);
70+
}
71+
72+
//MAKE PATH
73+
//a function that creates the svg line graph by generating the html path
74+
makePath() {
75+
const data = this.props.stockData;
76+
if (!data.length) {
77+
return;
78+
} else {
79+
const {color} = this.props;
80+
let pathD = `M ${this.getSvgX(data[0].x)} ${this.getSvgY(data[0].y)} `;
81+
pathD += data.map((point) => {
82+
return `L ${this.getSvgX(point.x)} ${this.getSvgY(point.y)} `;
83+
});
84+
return (
85+
<path className="stock_chart_path" d={pathD} style={{stroke: color, strokeWidth: 3, fill: "none"}} />
86+
);
87+
}
88+
}
89+
90+
//Create Data Point Line
91+
makeDottedLine() {
92+
const minX = this.getMinX();
93+
const maxX = this.getMaxX();
94+
const minY = this.getMinY();
95+
return (
96+
<g className="stock_chart_line">
97+
<line
98+
style={{stroke: "black", strokeWidth: 1, fill: "none", strokeDasharray:`1, ${676/(this.props.stockData.length)}`, strokeDashoffset: 0}}
99+
x1={this.getSvgX(minX)} y1={this.getSvgY(minY)}
100+
x2={this.getSvgX(maxX)} y2={this.getSvgY(minY)} />
101+
</g>
102+
);
103+
}
104+
105+
render() {
106+
const {svgHeight, svgWidth} = this.props;
107+
const graph = this.props.stockData.length ? (<svg viewBox={`0 0 ${svgWidth} ${svgHeight}`} width="676" height="196">
108+
{this.makePath()}
109+
{this.makeDottedLine()}
110+
</svg>) : (<div> Graph Currently Unavailable </div>);
111+
return (
112+
<div>
113+
{graph}
114+
</div>
115+
)
116+
}
117+
}
118+
119+
LineChart.defaultProps = {
120+
data: [],
121+
color: '#21CE99',
122+
svgHeight: 196,
123+
svgWidth: 676
124+
}
125+
126+
export default LineChart;

0 commit comments

Comments
 (0)