Skip to content

Commit cf298f4

Browse files
BulletChart component
1 parent fe06db2 commit cf298f4

File tree

3 files changed

+331
-10
lines changed

3 files changed

+331
-10
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from 'react';
2+
import HorizontalBulletGraph from './HorizontalBulletGraph';
3+
4+
// PropTypes is a separate package now:
5+
import PropTypes from 'prop-types';
6+
7+
class BulletGraph extends React.Component {
8+
9+
// Use static properties for propTypes/defaultProps
10+
static propTypes = {
11+
title: PropTypes.string.isRequired,
12+
textLabel: PropTypes.string.isRequired,
13+
scaleMin: PropTypes.number.isRequired,
14+
scaleMax: PropTypes.number.isRequired,
15+
performanceVal: PropTypes.number,
16+
symbolMarker: PropTypes.number,
17+
badVal: PropTypes.number,
18+
satisfactoryVal: PropTypes.number,
19+
unitsPrefix: PropTypes.string,
20+
unitsSuffix: PropTypes.string,
21+
titleStyle: PropTypes.string,
22+
textFont: PropTypes.string,
23+
badColor: PropTypes.string,
24+
satisfactoryColor: PropTypes.string,
25+
goodColor: PropTypes.string,
26+
height: PropTypes.number,
27+
width: PropTypes.number
28+
}
29+
30+
static defaultProps = {
31+
badColor: "#999999",
32+
satisfactoryColor: "#bbbbbb",
33+
goodColor: "#dddddd",
34+
width: 500,
35+
height: 38
36+
}
37+
38+
render() {
39+
return ( <
40+
div className = "BulletGraph" >
41+
<
42+
HorizontalBulletGraph title = { this.props.title }
43+
textLabel = { this.props.textLabel }
44+
scaleMin = { this.props.scaleMin }
45+
scaleMax = { this.props.scaleMax }
46+
performanceVal = { this.props.performanceVal }
47+
symbolMarker = { this.props.symbolMarker }
48+
badVal = { this.props.badVal }
49+
satisfactoryVal = { this.props.satisfactoryVal }
50+
unitsSuffix = { this.props.unitsSuffix }
51+
unitsPrefix = { this.props.unitsPrefix }
52+
titleStyle = { this.props.titleStyle }
53+
textFont = { this.props.textFont }
54+
badColor = { this.props.badColor }
55+
satisfactoryColor = { this.props.satisfactoryColor }
56+
goodColor = { this.props.goodColor }
57+
height = { this.props.height }
58+
width = { this.props.width }
59+
/> < /
60+
div >
61+
);
62+
}
63+
};
64+
65+
export default BulletGraph;
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import React from 'react';
2+
3+
4+
// PropTypes is a separate package now:
5+
import PropTypes from 'prop-types';
6+
7+
class HorizontalBulletGraph extends React.Component {
8+
render() {
9+
// Normalize values which exceed scaleMax prop
10+
let badVal = Math.min(this.props.badVal, this.props.scaleMax),
11+
satisfactoryVal = Math.min(this.props.satisfactoryVal, this.props.scaleMax),
12+
performanceVal = Math.min(this.props.performanceVal, this.props.scaleMax),
13+
symbolMarker = Math.min(this.props.symbolMarker, this.props.scaleMax);
14+
15+
// Scale tick component props to specified component width prop
16+
let widthScale = this.props.width /
17+
(this.props.scaleMax - this.props.scaleMin);
18+
19+
let horizontalBulletGraphStyles = {
20+
display: "flex",
21+
justifyContent: "flex-end"
22+
};
23+
24+
let graphStyles = {
25+
position: "relative"
26+
};
27+
28+
let goodValStyles = {
29+
backgroundColor: this.props.goodColor,
30+
height: this.props.height + "px",
31+
width: this.props.width + "px",
32+
zIndex: 1
33+
};
34+
35+
let titleStyles = {
36+
fontSize: "18px",
37+
lineHeight: this.props.height + "px",
38+
margin: "0",
39+
textAlign: "right",
40+
whiteSpace: "nowrap"
41+
};
42+
43+
let textLabelStyles = {
44+
fontSize: "12px",
45+
margin: "0",
46+
textAlign: "right"
47+
};
48+
49+
let legendStyles = {
50+
paddingRight: "10px"
51+
};
52+
53+
let satisfactoryValStyles = {
54+
backgroundColor: this.props.satisfactoryColor,
55+
height: this.props.height + "px",
56+
left: "0",
57+
position: "absolute",
58+
top: "0",
59+
width: (this.props.satisfactoryVal - this.props.scaleMin) * widthScale + "px",
60+
zIndex: 2
61+
};
62+
63+
let badValStyles = {
64+
backgroundColor: this.props.badColor,
65+
height: this.props.height + "px",
66+
left: "0",
67+
position: "absolute",
68+
top: "0",
69+
width: (badVal - this.props.scaleMin) * widthScale + "px",
70+
zIndex: 3
71+
};
72+
73+
let performanceWidth = (performanceVal - this.props.scaleMin) * widthScale;
74+
75+
let performanceValStyles = {
76+
backgroundColor: "black",
77+
height: this.props.height / 3 + "px",
78+
left: "0",
79+
marginBottom: this.props.height / 3 + "px",
80+
marginTop: this.props.height / 3 + "px",
81+
position: "absolute",
82+
top: "0",
83+
width: performanceWidth + "px",
84+
zIndex: 4
85+
};
86+
87+
let symbolMarkerWidth = this.props.width * 0.01,
88+
// Should not exceed boundaries qualitative range boundaries
89+
symbolMarkerPos = (symbolMarker - this.props.scaleMin) * widthScale * 0.99;
90+
91+
let symbolMarkerStyles = {
92+
backgroundColor: "black",
93+
left: symbolMarkerPos + "px",
94+
height: this.props.height * 0.8 + "px",
95+
marginBottom: this.props.height * 0.1 + "px",
96+
marginTop: this.props.height * 0.1 + "px",
97+
position: "absolute",
98+
top: "0",
99+
width: symbolMarkerWidth + "px",
100+
zIndex: 4
101+
};
102+
103+
let quantitativeScaleStyles = {
104+
left: "0",
105+
position: "absolute",
106+
top: this.props.height + "px"
107+
};
108+
109+
let tickIncrement = (this.props.scaleMax - this.props.scaleMin) / 5;
110+
111+
let ticks = Array.from({ length: 6 }, (tick, i) => {
112+
let tickLeft = parseInt(i * tickIncrement * widthScale * 0.996, 10),
113+
numLeft = tickLeft - 50,
114+
tickWidth = this.props.width * 0.005;
115+
116+
return {
117+
key: i,
118+
numStyles: {
119+
fontSize: "14px",
120+
left: numLeft + "px",
121+
paddingLeft: "2px",
122+
position: "absolute",
123+
textAlign: "center",
124+
top: "0",
125+
width: "100px"
126+
},
127+
tickStyles: {
128+
backgroundColor: "black",
129+
height: "10px",
130+
left: tickLeft + "px",
131+
position: "absolute",
132+
textAlign: "center",
133+
top: "-0px",
134+
width: tickWidth + "px"
135+
},
136+
value: i * tickIncrement + this.props.scaleMin
137+
}
138+
});
139+
140+
return ( <
141+
div style = { horizontalBulletGraphStyles } >
142+
143+
<
144+
div style = { legendStyles } >
145+
<
146+
p style = { titleStyles } > { this.props.title } < /p> <
147+
p style = { textLabelStyles } > { this.props.textLabel } < /p> < /
148+
div >
149+
150+
<
151+
div className = "Graph"
152+
style = { graphStyles } >
153+
<
154+
div style = { goodValStyles } > < /div>
155+
156+
{
157+
!isNaN(satisfactoryVal) && < div style = { satisfactoryValStyles } > < /div> }
158+
159+
{
160+
!isNaN(badVal) && < div style = { badValStyles } > < /div> }
161+
162+
{
163+
!isNaN(performanceVal) && < div style = { performanceValStyles } > < /div> }
164+
165+
{
166+
!isNaN(symbolMarker) && < div style = { symbolMarkerStyles } > < /div> }
167+
168+
<
169+
div className = "QuantitativeScale"
170+
style = { quantitativeScaleStyles } >
171+
172+
{
173+
ticks.map((tick) => ( <
174+
div key = { tick.key }
175+
style = { tick.tickStyles } >
176+
<
177+
/div>
178+
))
179+
}
180+
181+
{
182+
ticks.map((tick) => ( <
183+
p key = { tick.key }
184+
style = { tick.numStyles } > { this.props.unitsPrefix || '' } { tick.value } { this.props.unitsSuffix || '' } <
185+
/p>
186+
))
187+
}
188+
189+
<
190+
/div> < /
191+
div >
192+
193+
<
194+
/div>
195+
);
196+
}
197+
};
198+
199+
export default HorizontalBulletGraph;
Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,71 @@
1-
import React from "react";
2-
import "./MetricsBulletChart.css";
1+
import React from "react";
2+
import BulletGraph from './BulletGraph/BulletGraph';
3+
4+
// PropTypes is a separate package now:
5+
import PropTypes from 'prop-types';
36

47
class MetricsBulletChart extends React.Component {
5-
render() {
6-
return (
7-
<div className="metrics-bullet-chart">
8-
<h1>MetricsBulletChart</h1>
9-
</div>
10-
);
11-
}
8+
// Use static properties for propTypes/defaultProps
9+
static propTypes = {
10+
mocks: PropTypes.array
11+
}
12+
13+
static defaultProps = {
14+
mocks: []
15+
}
16+
17+
// Initialize state right in the class body,
18+
// with a property initializer:
19+
state = {
20+
mocks: [{
21+
title: "Complexity Simp. ",
22+
textLabel: "values",
23+
scaleMin: 0,
24+
scaleMax: 58,
25+
performanceVal: 33.6,
26+
symbolMarker: 33.6,
27+
badVal: 26,
28+
satisfactoryVal: 58,
29+
width: 600
30+
}, ]
31+
}
32+
33+
render() {
34+
return ( <
35+
div className = "App" >
36+
<
37+
div className = "Container" >
38+
39+
{
40+
this.state.mocks.map((graph, i) => {
41+
return ( <
42+
BulletGraph className = "BulletGraph"
43+
key = { i }
44+
title = { graph.title }
45+
textLabel = { graph.textLabel }
46+
scaleMin = { graph.scaleMin }
47+
scaleMax = { graph.scaleMax }
48+
performanceVal = { graph.performanceVal }
49+
symbolMarker = { graph.symbolMarker }
50+
badVal = { graph.badVal }
51+
satisfactoryVal = { graph.satisfactoryVal }
52+
unitsSuffix = { graph.unitsSuffix }
53+
unitsPrefix = { graph.unitsPrefix }
54+
height = { graph.height }
55+
width = { graph.width }
56+
/>
57+
)
58+
})
59+
}
60+
61+
<
62+
/div>
63+
64+
<
65+
/div>
66+
);
67+
}
68+
1269
}
1370

14-
export default MetricsBulletChart;
71+
export default MetricsBulletChart;

0 commit comments

Comments
 (0)