(http://kpostigo.com/)",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/kennetpostigo/component-kit/issues"
26 | },
27 | "homepage": "https://github.com/kennetpostigo/component-kit#readme",
28 | "peerDependencies": {
29 | "react": "^0.14.0 || ^15.0.0"
30 | },
31 | "devDependencies": {
32 | "babel-cli": "6.10.1",
33 | "babel-core": "6.9.1",
34 | "babel-loader": "6.2.4",
35 | "babel-plugin-syntax-jsx": "6.8.0",
36 | "babel-preset-es2015": "6.9.0",
37 | "babel-preset-react": "6.5.0",
38 | "cross-env": "1.0.8",
39 | "eslint": "2.12.0",
40 | "eslint-plugin-babel": "3.2.0",
41 | "eslint-plugin-react": "5.1.1",
42 | "webpack": "1.13.1"
43 | },
44 | "dependencies": {
45 | "aphrodite": "0.3.3",
46 | "d3": "3.5.17",
47 | "react-faux-dom": "2.5.0",
48 | "react-motion": "0.4.4"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Cards from './layout/Cards.js';
2 | // import Chips from './layout/Chips.js';
3 | import FooterNavigation from './layout/FooterNavigation.js';
4 | // import Navigation from './layout/Navigation.js';
5 | import Panels from './layout/Panels.js';
6 | import Platter from './layout/Platter.js';
7 | // import Snackbar from './layout/Snackbar.js';
8 | import Tabs from './layout/Tabs.js';
9 | // import Tooltips from './layout/Tooltips.js';
10 | import XYAxis from './visualization/XYAxis.js';
11 | import Legend from './visualization/Legend.js';
12 | import AreaChart from './visualization/AreaChart.js';
13 | import BarChart from './visualization/BarChart.js';
14 | import LineChart from './visualization/LineChart.js';
15 | import PieChart from './visualization/PieChart.js';
16 | import RadarChart from './visualization/RadarChart.js';
17 | import RadarArea from './visualization/RadarArea.js';
18 | import RadialBarChart from './visualization/RadialBarChart.js';
19 | import Responsive from './visualization/Responsive.js';
20 | import ScatterPlot from './visualization/ScatterPlot.js';
21 | import TreeMap from './visualization/TreeMap.js';
22 |
23 | export {
24 | Cards,
25 | // Chips,
26 | FooterNavigation,
27 | // Navigation,
28 | Panels,
29 | Platter,
30 | // Snackbar,
31 | Tabs,
32 | // Tooltips,
33 | XYAxis,
34 | Legend,
35 | AreaChart,
36 | BarChart,
37 | LineChart,
38 | PieChart,
39 | RadarChart,
40 | RadarArea,
41 | RadialBarChart,
42 | Responsive,
43 | ScatterPlot,
44 | TreeMap,
45 | }
46 |
--------------------------------------------------------------------------------
/src/layout/Cards.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, css } from 'aphrodite';
3 |
4 | function Cards (props) {
5 | const styles = StyleSheet.create({
6 | cards: {
7 | boxShadow: "0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)",
8 | width: props.width || 300,
9 | height: props.height || 350,
10 | },
11 | img: {
12 | width: props.imgWidth || 300,
13 | height: props.imgHeight || 200
14 | },
15 | graphBox: {
16 | display: 'flex',
17 | alignItem: 'center',
18 | justifyContent: 'center',
19 | borderBottom: "1px solid #CFCCCC"
20 | },
21 | graphInner: {
22 |
23 | },
24 | fill: {
25 | padding: 10
26 | },
27 | h3: {
28 | color: '48494c',
29 | fontWeight: 300,
30 | lineHeight: 1.5,
31 | font: 'helvetica, sans-serif',
32 | fontSize: 20,
33 | marginTop: 6,
34 | marginBottom: 0
35 | },
36 | p: {
37 | marginTop: 5,
38 | lineHeight: 1.5,
39 | font: 'helvetica, sans-serif',
40 | fontSize: 15,
41 | color: '#636363'
42 | },
43 | link: {
44 | textDecoration: 'none',
45 | marginRight: 20,
46 | font: 'helvetica, sans-serif',
47 | color: props.linkColor || '#505052',
48 | padding: 5,
49 | ':hover': {
50 | backgroundColor: '#f1f1f1',
51 | }
52 | }
53 | });
54 | if(props.graph) var graph = props.graph
55 | return (
56 |
57 | {
58 | (props.graph)
59 | ?
60 |
61 | {props.graph}
62 |
63 | :
64 |

65 | }
66 |
67 | {
68 | (props.children)
69 | ?
70 | props.children
71 | :
72 |
73 |
{props.header}
74 |
{props.detail}
75 | {props.links.map((link, key) => {
76 | return
{link.title.toUpperCase()}
77 | })}
78 |
79 | }
80 |
81 |
82 | );
83 | }
84 |
85 | Cards.propTypes = {
86 | imgURI: React.PropTypes.string,
87 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
88 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
89 | imgWidth: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
90 | imgHeight: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
91 | header: React.PropTypes.string,
92 | detail: React.PropTypes.string,
93 | links: React.PropTypes.arrayOf(React.PropTypes.shape({
94 | link: React.PropTypes.string,
95 | title: React.PropTypes.string
96 | })),
97 | linkColor: React.PropTypes.string,
98 | graph: React.PropTypes.element
99 | };
100 |
101 | export default Cards;
102 |
--------------------------------------------------------------------------------
/src/layout/Chips.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function Chips (props) {
4 | return (
5 |
6 |
7 |
8 | );
9 | }
10 |
11 | export default Chips;
12 |
--------------------------------------------------------------------------------
/src/layout/FooterNavigation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { css, StyleSheet } from 'aphrodite';
3 |
4 | function FooterNavigation (props) {
5 | var cols = Math.round(12 /props.views.length);
6 |
7 | var styles = StyleSheet.create({
8 | footerNav: {
9 | width: '100%',
10 | height: props.height || 60,
11 | position: 'fixed',
12 | bottom: 0,
13 | backgroundColor: props.backgroundColor || '#fff',
14 | boxShadow: '0px 0px 5px rgba(0,0,0,.3);'
15 | },
16 | icon: {
17 | textDecoration: 'none',
18 | textAlign: 'center',
19 | fontSize: 20,
20 | marginTop: 5,
21 | marginBottom: 3
22 | },
23 | center: {
24 | textDecoration: 'none',
25 | textAlign: 'center'
26 | },
27 | title: {
28 | textAlign: 'center',
29 | fontSize: 16,
30 | marginTop: 0,
31 | marginBottom: 5,
32 | textDecoration: 'none'
33 | }
34 | });
35 |
36 | return (
37 |
38 |
39 |
40 | {
41 | (props.children)
42 | ?
43 | props.children
44 | :
45 | props.views.map((view, key) => {
46 | return (
47 |
53 | );
54 | })
55 | }
56 |
57 |
58 |
59 | );
60 | }
61 | FooterNavigation.propTypes = {
62 | views: React.PropTypes.arrayOf(React.PropTypes.shape({
63 | link: React.PropTypes.string,
64 | icon: React.PropTypes.string,
65 | title: React.PropTypes.string
66 | })),
67 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
68 | };
69 |
70 | export default FooterNavigation;
71 |
--------------------------------------------------------------------------------
/src/layout/Navigation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function Navigation (props) {
4 | return (
5 |
6 |
7 |
8 | );
9 | }
10 |
11 | export default Navigation;
12 |
--------------------------------------------------------------------------------
/src/layout/Panels.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, css } from 'aphrodite';
3 |
4 | class Panels extends React.Component {
5 |
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | open: false
10 | };
11 | this.toggle = this.toggle.bind(this);
12 | }
13 |
14 | toggle () {
15 | this.setState({open: !this.state.open});
16 | }
17 |
18 | render () {
19 | const styles = StyleSheet.create({
20 | panels: {
21 | boxShadow: "0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)",
22 | width: this.props.width || 400,
23 | minHeight: this.props.height || 35,
24 | },
25 | title: {
26 | color: '#212121',
27 | fontSize: 15,
28 | padding: 0,
29 | marginTop: 15,
30 | float: 'left'
31 | },
32 | toggle: {
33 | height: 25,
34 | width: 25,
35 | textAlign: 'center',
36 | color: '#212121',
37 | fontSize: 15,
38 | paddingTop: 0,
39 | marginTop: 15,
40 | borderRadius: '50%',
41 | float: 'right',
42 | ':hover': {
43 | backgroundColor: '#f1f1f1',
44 | }
45 | },
46 | body:{
47 | display: 'flex',
48 | justifyContent: 'center',
49 | alignItems: 'center',
50 | textAlign: 'center',
51 | }
52 | });
53 | return (
54 |
55 | {
56 | (!this.state.open)
57 | ?
58 |
59 |
60 |
61 |
{this.props.title}
62 |
63 |
66 |
67 |
68 |
69 | :
70 |
71 |
72 |
73 |
{this.props.title}
74 |
75 |
78 |
79 |
80 | {this.props.children}
81 |
82 |
83 | }
84 |
85 | );
86 | }
87 | }
88 |
89 | Panels.propTypes = {
90 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
91 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
92 | title: React.PropTypes.string
93 | };
94 |
95 | export default Panels;
96 |
--------------------------------------------------------------------------------
/src/layout/Platter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { css, StyleSheet } from 'aphrodite';
3 |
4 | function Platter (props) {
5 | const styles = StyleSheet.create({
6 | platter: {
7 | backgroundColor: props.backgroundColor || '#fff',
8 | boxShadow: "0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)",
9 | width: props.width || 400,
10 | height: props.height || 350,
11 | paddingTop: 15,
12 | paddingLeft: 15,
13 | paddingRight: 15,
14 | paddingBottom: 15,
15 | display: 'flex',
16 | justifyContent: 'center',
17 | alignItems: 'center',
18 | textAlign: 'center',
19 | }
20 | });
21 |
22 | return (
23 |
24 | {props.children}
25 |
26 | );
27 | }
28 |
29 | Platter.PropTypes = {
30 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
31 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
32 | backgroundColor: React.PropTypes.string
33 | };
34 |
35 | export default Platter;
36 |
--------------------------------------------------------------------------------
/src/layout/Snackbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function Snackbar (props) {
4 | return (
5 |
6 |
7 |
8 | );
9 | }
10 |
11 | export default Snackbar;
12 |
--------------------------------------------------------------------------------
/src/layout/Tabs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, css } from 'aphrodite';
3 |
4 | class Tabs extends React.Component {
5 | constructor (props) {
6 | super(props);
7 | this.state = {
8 | activeTab: 0
9 | }
10 | }
11 |
12 | toggle (tab) {
13 | this.setState({activeTab: tab});
14 | }
15 | render () {
16 | const styles = StyleSheet.create({
17 | tabs: {
18 | width: this.props.width || 300,
19 | height: this.props.height || 500,
20 | backgroundColor: this.props.backGroundColor || '#fff',
21 | boxShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)'
22 | },
23 | tabList: {
24 | margin: 0,
25 | padding: 0,
26 | width: '100%'
27 | },
28 | tabItem: {
29 | textAlign: 'center',
30 | display: 'inline-block',
31 | listStyle: 'none',
32 | boxShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)'
33 | },
34 | activeTab: {
35 | textAlign: 'center',
36 | display: 'inline-block',
37 | listStyle: 'none',
38 | boxShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)',
39 | borderBottom: `2px solid ${this.props.tabColor || '#3949AB'}`
40 | },
41 | component: {
42 | display: 'flex',
43 | justifyContent: 'center',
44 | alignItems: 'center',
45 | textAlign: 'center',
46 | paddingTop: 20
47 | }
48 | })
49 | const cols = Math.round(12 / this.props.tabs.length);
50 | const TabComponent = this.props.tabs[this.state.activeTab].component;
51 | return (
52 |
53 |
54 | {
55 | this.props.tabs.map((tab, key) => {
56 | return (
57 | - this.toggle(key)}
58 | key={key}
59 | className={(this.state.activeTab === key)
60 | ? `${css(styles.activeTab)} col-xs-${cols}`
61 | : `${css(styles.tabItem)} col-xs-${cols}`
62 | }
63 | >
64 |
{tab.title}
65 |
66 | )
67 | })
68 | }
69 |
70 |
71 | {TabComponent}
72 |
73 |
74 |
75 | );
76 | }
77 | }
78 |
79 | Tabs.propTypes = {
80 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
81 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
82 | backGroundColor: React.PropTypes.string,
83 | tabColor: React.PropTypes.string,
84 | tabs: React.PropTypes.arrayOf(React.PropTypes.shape({
85 | title: React.PropTypes.string,
86 | component: React.PropTypes.element
87 | }))
88 | };
89 |
90 | export default Tabs;
91 |
--------------------------------------------------------------------------------
/src/layout/Tooltips.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function Tooltips (props) {
4 | return (
5 |
6 |
7 |
8 | );
9 | }
10 |
11 | export default Tooltips;
12 |
--------------------------------------------------------------------------------
/src/styles/main.css:
--------------------------------------------------------------------------------
1 | .AreaChart, .LineChart, .ScatterPlot, .BarChart{
2 | /*z-index: 10;*/
3 | position: absolute;
4 | }
5 | .plane{
6 | display: inline-block;
7 | }
8 | /* Chart Start*/
9 | .XYAxis{
10 | z-index:1;
11 | position: relative;
12 | }
13 |
14 | .XYC{
15 | display: inline-block;
16 | }
17 |
18 | .axis path,
19 | .axis line{
20 | /*fill: none;*/
21 | stroke: rgb(102, 102, 102);
22 | }
23 |
24 | .axis text {
25 | font-size: 12px;
26 | fill: rgb(102, 102, 102)
27 | }
28 |
29 | .tick text{
30 | font-size: 12px;
31 | fill: rgb(102, 102, 102);
32 | }
33 |
34 | .tick line{
35 | opacity: 0.2;
36 | stroke: rgb(102, 102, 102);
37 | }
38 |
39 | /* Chart End*/
40 |
41 | /* BarChart Start */
42 |
43 | .bar {
44 | fill: rgb(136, 132, 216);
45 | fill-opacity: 0.6;
46 | }
47 |
48 | /* BarChart End */
49 |
50 | /* AreaChart Start */
51 | .area {
52 | stroke-linecap:round;
53 | stroke-linehoin: round;
54 | }
55 | /* AreaChart End */
56 |
57 | /* LineChart Start */
58 |
59 | .circle{
60 | fill: rgb(255, 255, 255);
61 | stroke: rgb(136, 132, 216);
62 | }
63 |
64 | .line{
65 | fill: none;
66 | stroke: #ffc952;
67 | stroke-width: 2px;
68 | }
69 | /* LineChart End */
70 |
71 | /* PieChart Start */
72 | .PieChart{
73 | display:inline-block;
74 | }
75 | .arc text {
76 | font: 10px sans-serif;
77 | fill: #fff;
78 | text-anchor: middle;
79 | }
80 |
81 | /*.area {
82 | fill: rgb(136, 132, 216);
83 | stroke-width: 0;
84 | }*/
85 |
86 | /* PieChart End */
87 |
88 | /* TreeMap */
89 | .node {
90 | border: solid 1px white;
91 | font: 10px sans-serif;
92 | line-height: 12px;
93 | overflow: hidden;
94 | position: absolute;
95 | text-indent: 2px;
96 | }
97 |
98 | /* TreeMap End */
99 |
100 |
101 | /* Radar */
102 | .RadarChart{
103 | display: block;
104 | }
105 | /* Radar End */
106 |
107 |
108 |
109 |
110 |
111 |
112 | html {
113 | font-family: sans-serif;
114 | -ms-text-size-adjust: 100%;
115 | -webkit-text-size-adjust: 100%;
116 | }
117 | body {
118 | margin: 0;
119 | }
120 | article,
121 | aside,
122 | details,
123 | figcaption,
124 | figure,
125 | footer,
126 | header,
127 | hgroup,
128 | main,
129 | menu,
130 | nav,
131 | section,
132 | summary {
133 | display: block;
134 | }
135 | audio,
136 | canvas,
137 | progress,
138 | video {
139 | display: inline-block;
140 | vertical-align: baseline;
141 | }
142 | audio:not([controls]) {
143 | display: none;
144 | height: 0;
145 | }
146 | [hidden],
147 | template {
148 | display: none;
149 | }
150 | a {
151 | background-color: transparent;
152 | }
153 | a:active,
154 | a:hover {
155 | outline: 0;
156 | }
157 | abbr[title] {
158 | border-bottom: 1px dotted;
159 | }
160 | b,
161 | strong {
162 | font-weight: bold;
163 | }
164 | dfn {
165 | font-style: italic;
166 | }
167 | h1 {
168 | font-size: 2em;
169 | margin: 0.67em 0;
170 | }
171 | mark {
172 | background: #ff0;
173 | color: #000;
174 | }
175 | small {
176 | font-size: 80%;
177 | }
178 | sub,
179 | sup {
180 | font-size: 75%;
181 | line-height: 0;
182 | position: relative;
183 | vertical-align: baseline;
184 | }
185 | sup {
186 | top: -0.5em;
187 | }
188 | sub {
189 | bottom: -0.25em;
190 | }
191 | img {
192 | border: 0;
193 | }
194 | svg:not(:root) {
195 | overflow: hidden;
196 | }
197 | figure {
198 | margin: 1em 40px;
199 | }
200 | hr {
201 | -webkit-box-sizing: content-box;
202 | -moz-box-sizing: content-box;
203 | box-sizing: content-box;
204 | height: 0;
205 | }
206 | pre {
207 | overflow: auto;
208 | }
209 | code,
210 | kbd,
211 | pre,
212 | samp {
213 | font-family: monospace, monospace;
214 | font-size: 1em;
215 | }
216 | button,
217 | input,
218 | optgroup,
219 | select,
220 | textarea {
221 | color: inherit;
222 | font: inherit;
223 | margin: 0;
224 | }
225 | button {
226 | overflow: visible;
227 | }
228 | button,
229 | select {
230 | text-transform: none;
231 | }
232 | button,
233 | html input[type="button"],
234 | input[type="reset"],
235 | input[type="submit"] {
236 | -webkit-appearance: button;
237 | cursor: pointer;
238 | }
239 | button[disabled],
240 | html input[disabled] {
241 | cursor: default;
242 | }
243 | button::-moz-focus-inner,
244 | input::-moz-focus-inner {
245 | border: 0;
246 | padding: 0;
247 | }
248 | input {
249 | line-height: normal;
250 | }
251 | input[type="checkbox"],
252 | input[type="radio"] {
253 | -webkit-box-sizing: border-box;
254 | -moz-box-sizing: border-box;
255 | box-sizing: border-box;
256 | padding: 0;
257 | }
258 | input[type="number"]::-webkit-inner-spin-button,
259 | input[type="number"]::-webkit-outer-spin-button {
260 | height: auto;
261 | }
262 | input[type="search"] {
263 | -webkit-appearance: textfield;
264 | -webkit-box-sizing: content-box;
265 | -moz-box-sizing: content-box;
266 | box-sizing: content-box;
267 | }
268 | input[type="search"]::-webkit-search-cancel-button,
269 | input[type="search"]::-webkit-search-decoration {
270 | -webkit-appearance: none;
271 | }
272 | fieldset {
273 | border: 1px solid #c0c0c0;
274 | margin: 0 2px;
275 | padding: 0.35em 0.625em 0.75em;
276 | }
277 | legend {
278 | border: 0;
279 | padding: 0;
280 | }
281 | textarea {
282 | overflow: auto;
283 | }
284 | optgroup {
285 | font-weight: bold;
286 | }
287 | table {
288 | border-collapse: collapse;
289 | border-spacing: 0;
290 | }
291 | td,
292 | th {
293 | padding: 0;
294 | }
295 | * {
296 | -webkit-box-sizing: border-box;
297 | -moz-box-sizing: border-box;
298 | box-sizing: border-box;
299 | }
300 | *:before,
301 | *:after {
302 | -webkit-box-sizing: border-box;
303 | -moz-box-sizing: border-box;
304 | box-sizing: border-box;
305 | }
306 | html {
307 | font-size: 10px;
308 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
309 | }
310 | body {
311 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
312 | font-size: 14px;
313 | line-height: 1.42857143;
314 | color: #333333;
315 | background-color: #ffffff;
316 | }
317 | input,
318 | button,
319 | select,
320 | textarea {
321 | font-family: inherit;
322 | font-size: inherit;
323 | line-height: inherit;
324 | }
325 | a {
326 | color: #337ab7;
327 | text-decoration: none;
328 | }
329 | a:hover,
330 | a:focus {
331 | color: #23527c;
332 | text-decoration: underline;
333 | }
334 | a:focus {
335 | outline: thin dotted;
336 | outline: 5px auto -webkit-focus-ring-color;
337 | outline-offset: -2px;
338 | }
339 | figure {
340 | margin: 0;
341 | }
342 | img {
343 | vertical-align: middle;
344 | }
345 | .img-responsive {
346 | display: block;
347 | max-width: 100%;
348 | height: auto;
349 | }
350 | .img-rounded {
351 | border-radius: 6px;
352 | }
353 | .img-thumbnail {
354 | padding: 4px;
355 | line-height: 1.42857143;
356 | background-color: #ffffff;
357 | border: 1px solid #dddddd;
358 | border-radius: 4px;
359 | -webkit-transition: all 0.2s ease-in-out;
360 | -o-transition: all 0.2s ease-in-out;
361 | transition: all 0.2s ease-in-out;
362 | display: inline-block;
363 | max-width: 100%;
364 | height: auto;
365 | }
366 | .img-circle {
367 | border-radius: 50%;
368 | }
369 | hr {
370 | margin-top: 20px;
371 | margin-bottom: 20px;
372 | border: 0;
373 | border-top: 1px solid #eeeeee;
374 | }
375 | .sr-only {
376 | position: absolute;
377 | width: 1px;
378 | height: 1px;
379 | margin: -1px;
380 | padding: 0;
381 | overflow: hidden;
382 | clip: rect(0, 0, 0, 0);
383 | border: 0;
384 | }
385 | .sr-only-focusable:active,
386 | .sr-only-focusable:focus {
387 | position: static;
388 | width: auto;
389 | height: auto;
390 | margin: 0;
391 | overflow: visible;
392 | clip: auto;
393 | }
394 | [role="button"] {
395 | cursor: pointer;
396 | }
397 | .container {
398 | margin-right: auto;
399 | margin-left: auto;
400 | padding-left: 15px;
401 | padding-right: 15px;
402 | }
403 | @media (min-width: 768px) {
404 | .container {
405 | width: 750px;
406 | }
407 | }
408 | @media (min-width: 992px) {
409 | .container {
410 | width: 970px;
411 | }
412 | }
413 | @media (min-width: 1200px) {
414 | .container {
415 | width: 1170px;
416 | }
417 | }
418 | .container-fluid {
419 | margin-right: auto;
420 | margin-left: auto;
421 | padding-left: 15px;
422 | padding-right: 15px;
423 | }
424 | .row {
425 | margin-left: -15px;
426 | margin-right: -15px;
427 | }
428 | .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
429 | position: relative;
430 | min-height: 1px;
431 | padding-left: 15px;
432 | padding-right: 15px;
433 | }
434 | .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
435 | float: left;
436 | }
437 | .col-xs-12 {
438 | width: 100%;
439 | }
440 | .col-xs-11 {
441 | width: 91.66666667%;
442 | }
443 | .col-xs-10 {
444 | width: 83.33333333%;
445 | }
446 | .col-xs-9 {
447 | width: 75%;
448 | }
449 | .col-xs-8 {
450 | width: 66.66666667%;
451 | }
452 | .col-xs-7 {
453 | width: 58.33333333%;
454 | }
455 | .col-xs-6 {
456 | width: 50%;
457 | }
458 | .col-xs-5 {
459 | width: 41.66666667%;
460 | }
461 | .col-xs-4 {
462 | width: 33.33333333%;
463 | }
464 | .col-xs-3 {
465 | width: 25%;
466 | }
467 | .col-xs-2 {
468 | width: 16.66666667%;
469 | }
470 | .col-xs-1 {
471 | width: 8.33333333%;
472 | }
473 | .col-xs-pull-12 {
474 | right: 100%;
475 | }
476 | .col-xs-pull-11 {
477 | right: 91.66666667%;
478 | }
479 | .col-xs-pull-10 {
480 | right: 83.33333333%;
481 | }
482 | .col-xs-pull-9 {
483 | right: 75%;
484 | }
485 | .col-xs-pull-8 {
486 | right: 66.66666667%;
487 | }
488 | .col-xs-pull-7 {
489 | right: 58.33333333%;
490 | }
491 | .col-xs-pull-6 {
492 | right: 50%;
493 | }
494 | .col-xs-pull-5 {
495 | right: 41.66666667%;
496 | }
497 | .col-xs-pull-4 {
498 | right: 33.33333333%;
499 | }
500 | .col-xs-pull-3 {
501 | right: 25%;
502 | }
503 | .col-xs-pull-2 {
504 | right: 16.66666667%;
505 | }
506 | .col-xs-pull-1 {
507 | right: 8.33333333%;
508 | }
509 | .col-xs-pull-0 {
510 | right: auto;
511 | }
512 | .col-xs-push-12 {
513 | left: 100%;
514 | }
515 | .col-xs-push-11 {
516 | left: 91.66666667%;
517 | }
518 | .col-xs-push-10 {
519 | left: 83.33333333%;
520 | }
521 | .col-xs-push-9 {
522 | left: 75%;
523 | }
524 | .col-xs-push-8 {
525 | left: 66.66666667%;
526 | }
527 | .col-xs-push-7 {
528 | left: 58.33333333%;
529 | }
530 | .col-xs-push-6 {
531 | left: 50%;
532 | }
533 | .col-xs-push-5 {
534 | left: 41.66666667%;
535 | }
536 | .col-xs-push-4 {
537 | left: 33.33333333%;
538 | }
539 | .col-xs-push-3 {
540 | left: 25%;
541 | }
542 | .col-xs-push-2 {
543 | left: 16.66666667%;
544 | }
545 | .col-xs-push-1 {
546 | left: 8.33333333%;
547 | }
548 | .col-xs-push-0 {
549 | left: auto;
550 | }
551 | .col-xs-offset-12 {
552 | margin-left: 100%;
553 | }
554 | .col-xs-offset-11 {
555 | margin-left: 91.66666667%;
556 | }
557 | .col-xs-offset-10 {
558 | margin-left: 83.33333333%;
559 | }
560 | .col-xs-offset-9 {
561 | margin-left: 75%;
562 | }
563 | .col-xs-offset-8 {
564 | margin-left: 66.66666667%;
565 | }
566 | .col-xs-offset-7 {
567 | margin-left: 58.33333333%;
568 | }
569 | .col-xs-offset-6 {
570 | margin-left: 50%;
571 | }
572 | .col-xs-offset-5 {
573 | margin-left: 41.66666667%;
574 | }
575 | .col-xs-offset-4 {
576 | margin-left: 33.33333333%;
577 | }
578 | .col-xs-offset-3 {
579 | margin-left: 25%;
580 | }
581 | .col-xs-offset-2 {
582 | margin-left: 16.66666667%;
583 | }
584 | .col-xs-offset-1 {
585 | margin-left: 8.33333333%;
586 | }
587 | .col-xs-offset-0 {
588 | margin-left: 0%;
589 | }
590 | @media (min-width: 768px) {
591 | .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
592 | float: left;
593 | }
594 | .col-sm-12 {
595 | width: 100%;
596 | }
597 | .col-sm-11 {
598 | width: 91.66666667%;
599 | }
600 | .col-sm-10 {
601 | width: 83.33333333%;
602 | }
603 | .col-sm-9 {
604 | width: 75%;
605 | }
606 | .col-sm-8 {
607 | width: 66.66666667%;
608 | }
609 | .col-sm-7 {
610 | width: 58.33333333%;
611 | }
612 | .col-sm-6 {
613 | width: 50%;
614 | }
615 | .col-sm-5 {
616 | width: 41.66666667%;
617 | }
618 | .col-sm-4 {
619 | width: 33.33333333%;
620 | }
621 | .col-sm-3 {
622 | width: 25%;
623 | }
624 | .col-sm-2 {
625 | width: 16.66666667%;
626 | }
627 | .col-sm-1 {
628 | width: 8.33333333%;
629 | }
630 | .col-sm-pull-12 {
631 | right: 100%;
632 | }
633 | .col-sm-pull-11 {
634 | right: 91.66666667%;
635 | }
636 | .col-sm-pull-10 {
637 | right: 83.33333333%;
638 | }
639 | .col-sm-pull-9 {
640 | right: 75%;
641 | }
642 | .col-sm-pull-8 {
643 | right: 66.66666667%;
644 | }
645 | .col-sm-pull-7 {
646 | right: 58.33333333%;
647 | }
648 | .col-sm-pull-6 {
649 | right: 50%;
650 | }
651 | .col-sm-pull-5 {
652 | right: 41.66666667%;
653 | }
654 | .col-sm-pull-4 {
655 | right: 33.33333333%;
656 | }
657 | .col-sm-pull-3 {
658 | right: 25%;
659 | }
660 | .col-sm-pull-2 {
661 | right: 16.66666667%;
662 | }
663 | .col-sm-pull-1 {
664 | right: 8.33333333%;
665 | }
666 | .col-sm-pull-0 {
667 | right: auto;
668 | }
669 | .col-sm-push-12 {
670 | left: 100%;
671 | }
672 | .col-sm-push-11 {
673 | left: 91.66666667%;
674 | }
675 | .col-sm-push-10 {
676 | left: 83.33333333%;
677 | }
678 | .col-sm-push-9 {
679 | left: 75%;
680 | }
681 | .col-sm-push-8 {
682 | left: 66.66666667%;
683 | }
684 | .col-sm-push-7 {
685 | left: 58.33333333%;
686 | }
687 | .col-sm-push-6 {
688 | left: 50%;
689 | }
690 | .col-sm-push-5 {
691 | left: 41.66666667%;
692 | }
693 | .col-sm-push-4 {
694 | left: 33.33333333%;
695 | }
696 | .col-sm-push-3 {
697 | left: 25%;
698 | }
699 | .col-sm-push-2 {
700 | left: 16.66666667%;
701 | }
702 | .col-sm-push-1 {
703 | left: 8.33333333%;
704 | }
705 | .col-sm-push-0 {
706 | left: auto;
707 | }
708 | .col-sm-offset-12 {
709 | margin-left: 100%;
710 | }
711 | .col-sm-offset-11 {
712 | margin-left: 91.66666667%;
713 | }
714 | .col-sm-offset-10 {
715 | margin-left: 83.33333333%;
716 | }
717 | .col-sm-offset-9 {
718 | margin-left: 75%;
719 | }
720 | .col-sm-offset-8 {
721 | margin-left: 66.66666667%;
722 | }
723 | .col-sm-offset-7 {
724 | margin-left: 58.33333333%;
725 | }
726 | .col-sm-offset-6 {
727 | margin-left: 50%;
728 | }
729 | .col-sm-offset-5 {
730 | margin-left: 41.66666667%;
731 | }
732 | .col-sm-offset-4 {
733 | margin-left: 33.33333333%;
734 | }
735 | .col-sm-offset-3 {
736 | margin-left: 25%;
737 | }
738 | .col-sm-offset-2 {
739 | margin-left: 16.66666667%;
740 | }
741 | .col-sm-offset-1 {
742 | margin-left: 8.33333333%;
743 | }
744 | .col-sm-offset-0 {
745 | margin-left: 0%;
746 | }
747 | }
748 | @media (min-width: 992px) {
749 | .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
750 | float: left;
751 | }
752 | .col-md-12 {
753 | width: 100%;
754 | }
755 | .col-md-11 {
756 | width: 91.66666667%;
757 | }
758 | .col-md-10 {
759 | width: 83.33333333%;
760 | }
761 | .col-md-9 {
762 | width: 75%;
763 | }
764 | .col-md-8 {
765 | width: 66.66666667%;
766 | }
767 | .col-md-7 {
768 | width: 58.33333333%;
769 | }
770 | .col-md-6 {
771 | width: 50%;
772 | }
773 | .col-md-5 {
774 | width: 41.66666667%;
775 | }
776 | .col-md-4 {
777 | width: 33.33333333%;
778 | }
779 | .col-md-3 {
780 | width: 25%;
781 | }
782 | .col-md-2 {
783 | width: 16.66666667%;
784 | }
785 | .col-md-1 {
786 | width: 8.33333333%;
787 | }
788 | .col-md-pull-12 {
789 | right: 100%;
790 | }
791 | .col-md-pull-11 {
792 | right: 91.66666667%;
793 | }
794 | .col-md-pull-10 {
795 | right: 83.33333333%;
796 | }
797 | .col-md-pull-9 {
798 | right: 75%;
799 | }
800 | .col-md-pull-8 {
801 | right: 66.66666667%;
802 | }
803 | .col-md-pull-7 {
804 | right: 58.33333333%;
805 | }
806 | .col-md-pull-6 {
807 | right: 50%;
808 | }
809 | .col-md-pull-5 {
810 | right: 41.66666667%;
811 | }
812 | .col-md-pull-4 {
813 | right: 33.33333333%;
814 | }
815 | .col-md-pull-3 {
816 | right: 25%;
817 | }
818 | .col-md-pull-2 {
819 | right: 16.66666667%;
820 | }
821 | .col-md-pull-1 {
822 | right: 8.33333333%;
823 | }
824 | .col-md-pull-0 {
825 | right: auto;
826 | }
827 | .col-md-push-12 {
828 | left: 100%;
829 | }
830 | .col-md-push-11 {
831 | left: 91.66666667%;
832 | }
833 | .col-md-push-10 {
834 | left: 83.33333333%;
835 | }
836 | .col-md-push-9 {
837 | left: 75%;
838 | }
839 | .col-md-push-8 {
840 | left: 66.66666667%;
841 | }
842 | .col-md-push-7 {
843 | left: 58.33333333%;
844 | }
845 | .col-md-push-6 {
846 | left: 50%;
847 | }
848 | .col-md-push-5 {
849 | left: 41.66666667%;
850 | }
851 | .col-md-push-4 {
852 | left: 33.33333333%;
853 | }
854 | .col-md-push-3 {
855 | left: 25%;
856 | }
857 | .col-md-push-2 {
858 | left: 16.66666667%;
859 | }
860 | .col-md-push-1 {
861 | left: 8.33333333%;
862 | }
863 | .col-md-push-0 {
864 | left: auto;
865 | }
866 | .col-md-offset-12 {
867 | margin-left: 100%;
868 | }
869 | .col-md-offset-11 {
870 | margin-left: 91.66666667%;
871 | }
872 | .col-md-offset-10 {
873 | margin-left: 83.33333333%;
874 | }
875 | .col-md-offset-9 {
876 | margin-left: 75%;
877 | }
878 | .col-md-offset-8 {
879 | margin-left: 66.66666667%;
880 | }
881 | .col-md-offset-7 {
882 | margin-left: 58.33333333%;
883 | }
884 | .col-md-offset-6 {
885 | margin-left: 50%;
886 | }
887 | .col-md-offset-5 {
888 | margin-left: 41.66666667%;
889 | }
890 | .col-md-offset-4 {
891 | margin-left: 33.33333333%;
892 | }
893 | .col-md-offset-3 {
894 | margin-left: 25%;
895 | }
896 | .col-md-offset-2 {
897 | margin-left: 16.66666667%;
898 | }
899 | .col-md-offset-1 {
900 | margin-left: 8.33333333%;
901 | }
902 | .col-md-offset-0 {
903 | margin-left: 0%;
904 | }
905 | }
906 | @media (min-width: 1200px) {
907 | .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
908 | float: left;
909 | }
910 | .col-lg-12 {
911 | width: 100%;
912 | }
913 | .col-lg-11 {
914 | width: 91.66666667%;
915 | }
916 | .col-lg-10 {
917 | width: 83.33333333%;
918 | }
919 | .col-lg-9 {
920 | width: 75%;
921 | }
922 | .col-lg-8 {
923 | width: 66.66666667%;
924 | }
925 | .col-lg-7 {
926 | width: 58.33333333%;
927 | }
928 | .col-lg-6 {
929 | width: 50%;
930 | }
931 | .col-lg-5 {
932 | width: 41.66666667%;
933 | }
934 | .col-lg-4 {
935 | width: 33.33333333%;
936 | }
937 | .col-lg-3 {
938 | width: 25%;
939 | }
940 | .col-lg-2 {
941 | width: 16.66666667%;
942 | }
943 | .col-lg-1 {
944 | width: 8.33333333%;
945 | }
946 | .col-lg-pull-12 {
947 | right: 100%;
948 | }
949 | .col-lg-pull-11 {
950 | right: 91.66666667%;
951 | }
952 | .col-lg-pull-10 {
953 | right: 83.33333333%;
954 | }
955 | .col-lg-pull-9 {
956 | right: 75%;
957 | }
958 | .col-lg-pull-8 {
959 | right: 66.66666667%;
960 | }
961 | .col-lg-pull-7 {
962 | right: 58.33333333%;
963 | }
964 | .col-lg-pull-6 {
965 | right: 50%;
966 | }
967 | .col-lg-pull-5 {
968 | right: 41.66666667%;
969 | }
970 | .col-lg-pull-4 {
971 | right: 33.33333333%;
972 | }
973 | .col-lg-pull-3 {
974 | right: 25%;
975 | }
976 | .col-lg-pull-2 {
977 | right: 16.66666667%;
978 | }
979 | .col-lg-pull-1 {
980 | right: 8.33333333%;
981 | }
982 | .col-lg-pull-0 {
983 | right: auto;
984 | }
985 | .col-lg-push-12 {
986 | left: 100%;
987 | }
988 | .col-lg-push-11 {
989 | left: 91.66666667%;
990 | }
991 | .col-lg-push-10 {
992 | left: 83.33333333%;
993 | }
994 | .col-lg-push-9 {
995 | left: 75%;
996 | }
997 | .col-lg-push-8 {
998 | left: 66.66666667%;
999 | }
1000 | .col-lg-push-7 {
1001 | left: 58.33333333%;
1002 | }
1003 | .col-lg-push-6 {
1004 | left: 50%;
1005 | }
1006 | .col-lg-push-5 {
1007 | left: 41.66666667%;
1008 | }
1009 | .col-lg-push-4 {
1010 | left: 33.33333333%;
1011 | }
1012 | .col-lg-push-3 {
1013 | left: 25%;
1014 | }
1015 | .col-lg-push-2 {
1016 | left: 16.66666667%;
1017 | }
1018 | .col-lg-push-1 {
1019 | left: 8.33333333%;
1020 | }
1021 | .col-lg-push-0 {
1022 | left: auto;
1023 | }
1024 | .col-lg-offset-12 {
1025 | margin-left: 100%;
1026 | }
1027 | .col-lg-offset-11 {
1028 | margin-left: 91.66666667%;
1029 | }
1030 | .col-lg-offset-10 {
1031 | margin-left: 83.33333333%;
1032 | }
1033 | .col-lg-offset-9 {
1034 | margin-left: 75%;
1035 | }
1036 | .col-lg-offset-8 {
1037 | margin-left: 66.66666667%;
1038 | }
1039 | .col-lg-offset-7 {
1040 | margin-left: 58.33333333%;
1041 | }
1042 | .col-lg-offset-6 {
1043 | margin-left: 50%;
1044 | }
1045 | .col-lg-offset-5 {
1046 | margin-left: 41.66666667%;
1047 | }
1048 | .col-lg-offset-4 {
1049 | margin-left: 33.33333333%;
1050 | }
1051 | .col-lg-offset-3 {
1052 | margin-left: 25%;
1053 | }
1054 | .col-lg-offset-2 {
1055 | margin-left: 16.66666667%;
1056 | }
1057 | .col-lg-offset-1 {
1058 | margin-left: 8.33333333%;
1059 | }
1060 | .col-lg-offset-0 {
1061 | margin-left: 0%;
1062 | }
1063 | }
1064 | .clearfix:before,
1065 | .clearfix:after,
1066 | .container:before,
1067 | .container:after,
1068 | .container-fluid:before,
1069 | .container-fluid:after,
1070 | .row:before,
1071 | .row:after {
1072 | content: " ";
1073 | display: table;
1074 | }
1075 | .clearfix:after,
1076 | .container:after,
1077 | .container-fluid:after,
1078 | .row:after {
1079 | clear: both;
1080 | }
1081 | .center-block {
1082 | display: block;
1083 | margin-left: auto;
1084 | margin-right: auto;
1085 | }
1086 | .pull-right {
1087 | float: right !important;
1088 | }
1089 | .pull-left {
1090 | float: left !important;
1091 | }
1092 | .hide {
1093 | display: none !important;
1094 | }
1095 | .show {
1096 | display: block !important;
1097 | }
1098 | .invisible {
1099 | visibility: hidden;
1100 | }
1101 | .text-hide {
1102 | font: 0/0 a;
1103 | color: transparent;
1104 | text-shadow: none;
1105 | background-color: transparent;
1106 | border: 0;
1107 | }
1108 | .hidden {
1109 | display: none !important;
1110 | }
1111 | .affix {
1112 | position: fixed;
1113 | }
1114 |
--------------------------------------------------------------------------------
/src/utils/Dividends.js:
--------------------------------------------------------------------------------
1 | export function getDividends (number, arrSize) {
2 | var arr = [0];
3 | var result = number / arrSize;
4 |
5 | while (arr.length < arrSize) {
6 | arr.push(Math.round(result * (arr.length + 1)));
7 | }
8 | return arr;
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/DynamicScales.js:
--------------------------------------------------------------------------------
1 | var data2 = [
2 | {x: 1999, y: 20},
3 | {x: 2001, y: 0},
4 | {x: 2002, y: 30},
5 | {x: 2003, y: 45},
6 | {x: 2004, y: 46},
7 | {x: 2005, y: 37},
8 | {x: 2006, y: 20},
9 | {x: 2007, y: 15},
10 | {x: 2008, y: 30},
11 | {x: 2009, y: 11},
12 | {x: 2010, y: 12},
13 | {x: 2011, y: 22},
14 | {x: 2012, y: 23},
15 | {x: 2013, y: 33},
16 | {x: 2014, y: 30},
17 | {x: 2015, y: 44},
18 | {x: 2016, y: 40},
19 | {x: 2017, y: 55},
20 | {x: 2018, y: 50},
21 | {x: 2019, y: 66},
22 | {x: 2020, y: 60},
23 | {x: 2021, y: 75},
24 | {x: 2022, y: 70},
25 | {x: 2023, y: 80},
26 | {x: 2024, y: 60},
27 | {x: 2025, y: 40},
28 | {x: 2026, y: 100},
29 | {x: 2027, y: 92},
30 | {x: 2028, y: 32},
31 | {x: 2029, y: 72},
32 | {x: 2030, y: 74},
33 | ];
34 |
35 | export function determineScales (data, xDataKey, yDataKey, defaultOrdinal) {
36 | var ix = [],iy = [],
37 | sx = [],sy = [],
38 | x,y;
39 |
40 | data.map((datum, key) => {
41 | if ((datum[xDataKey] === undefined || datum[xDataKey] === null )|| (datum[yDataKey] === null || datum[yDataKey] == undefined)) {
42 | console.error(`Some of your data contains 'null' or 'undefined' values at index ${key}`);
43 | }
44 | if (typeof datum[xDataKey] === 'string') {
45 | sx.push(datum[xDataKey]);
46 | } else {
47 | ix.push(datum[xDataKey]);
48 | }
49 | if (typeof datum[yDataKey] === 'string') {
50 | sy.push(datum[yDataKey]);
51 | } else {
52 | iy.push(datum[yDataKey]);
53 | }
54 | });
55 |
56 | if (ix > sx) {
57 | x = 'linear';
58 | } else {
59 | x = 'ordinal';
60 | }
61 |
62 | if (iy > sy) {
63 | y = 'linear';
64 | } else {
65 | y = 'ordinal';
66 | }
67 |
68 | if (defaultOrdinal === 'x') {
69 | return {x: 'ordinal', y};
70 | } else if (defaultOrdinal === 'y'){
71 | return {x, y: 'ordinal'};
72 | } else if (defaultOrdinal === 'xy') {
73 | return {x: 'ordinal', y: 'ordinal'};
74 | } else {
75 | return {x, y};
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/visualization/AreaChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class AreaChart extends React.Component {
6 | render () {
7 | const data = this.props.data,
8 | xDataKey = this.props.xDataKey,
9 | yDataKey = this.props.yDataKey,
10 | dataKey = this.props.dataKey || yDataKey,
11 | width= this.props.width || 350,
12 | height = this.props.height || 300,
13 | innerW = width - 60,
14 | innerH = height - 60,
15 | xScale = this.props.xScale,
16 | yScale = this.props.yScale,
17 | color = this.props.color || '#ff7473',
18 | colorOpacity = this.props.colorOpacity || 1;
19 |
20 | var area = d3.svg.area()
21 | .interpolate("monotone")
22 | .x((d) => xScale(d[xDataKey]))
23 | .y0(innerH)
24 | .y1((d) => yScale(d[dataKey]));
25 |
26 | var planeElement = ReactFauxDOM.createElement('svg')
27 | var plane = d3.select(planeElement)
28 | .attr('class', 'AreaChart')
29 | .attr('width', width)
30 | .attr('height', height)
31 | .style('z-index', this.props.zIndex)
32 | .style('position', 'absolute');
33 |
34 | var g = plane.append('g')
35 | .attr('class', 'plane')
36 | .attr('width', innerW)
37 | .attr('height', innerH)
38 | .attr('transform', `translate(50, 20)`)
39 | .style('display', 'inline-block');
40 |
41 | g.append('path')
42 | .datum(data)
43 | .attr('class', 'area')
44 | .attr('d', area)
45 | .style('fill', color)
46 | .style('stroke-linecap', 'round')
47 | .style('stroke-linehoin', 'round')
48 | .style('fill-opacity', colorOpacity);
49 |
50 | return plane.node().toReact();
51 | }
52 | }
53 |
54 | AreaChart.propTypes = {
55 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
56 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
57 | data: React.PropTypes.array,
58 | dataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
59 | color: React.PropTypes.string,
60 | colorOpacity: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number])
61 | }
62 |
63 | export default AreaChart;
64 |
--------------------------------------------------------------------------------
/src/visualization/BarChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class BarChart extends React.Component {
6 | render () {
7 | const data = this.props.data,
8 | xDataKey = this.props.xDataKey,
9 | yDataKey = this.props.yDataKey,
10 | dataKey = this.props.dataKey || yDataKey,
11 | width= this.props.width || 350,
12 | height = this.props.height || 300,
13 | innerW = width - 60,
14 | innerH = height - 60,
15 | xScale = this.props.xScale,
16 | yScale = this.props.yScale,
17 | scaleTypes = this.props.scaleTypes,
18 | color = this.props.color || 'rgb(136, 132, 216)',
19 | colorOpacity = this.props.colorOpacity || 0.6;
20 |
21 | var planeElement = ReactFauxDOM.createElement('svg')
22 | var plane = d3.select(planeElement)
23 | .attr('class', 'BarChart')
24 | .attr('width', width)
25 | .attr('height', height)
26 | .style('z-index', this.props.zIndex)
27 | .style('position', 'absolute');
28 |
29 | var g = plane.append('g')
30 | .attr('class', 'plane')
31 | .attr('width', innerW)
32 | .attr('height', innerH)
33 | .attr('transform', `translate(50, 20)`)
34 | .style('display', 'inline-block');
35 |
36 | if (scaleTypes.x === 'ordinal') {
37 | g.selectAll('.bar')
38 | .data(data)
39 | .enter().append('rect')
40 | .attr('class', 'bar')
41 | .attr('x', (d) => xScale(d[xDataKey]))
42 | .attr('y', (d) => yScale(d[dataKey]))
43 | .attr('height', (d) => innerH - yScale(d[dataKey]))
44 | .attr('width', xScale.rangeBand())
45 | .style('fill', color)
46 | .style('fill-opacity', colorOpacity);
47 | } else {
48 | g.selectAll('.bar')
49 | .data(data)
50 | .enter().append('rect')
51 | .attr('class', 'bar')
52 | .style('fill', color)
53 | .style('fill-opacity', colorOpacity)
54 | .attr('x', (d) => xScale(d[xDataKey]))
55 | .attr('y', (d, i) => yScale.rangeBand(d[dataKey]) * i)
56 | .attr('height', (d, i) => innerH - yScale(d[dataKey]))
57 | .attr('width', '7');
58 | }
59 |
60 | return plane.node().toReact();
61 | }
62 | }
63 |
64 | BarChart.propTypes = {
65 | width: React.PropTypes.number,
66 | height: React.PropTypes.number,
67 | data: React.PropTypes.array,
68 | dataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
69 | color: React.PropTypes.string,
70 | colorOpacity: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number])
71 | }
72 |
73 | export default BarChart;
74 |
--------------------------------------------------------------------------------
/src/visualization/Legend.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class Legend extends React.Component {
6 | render () {
7 | return (
8 | LEGEND UNDER CONSTRUCTION
9 | );
10 | }
11 | }
12 |
13 | export default Legend;
14 |
15 | // var legend = g.selectAll('.legend')
16 | // .data(color.domain())
17 | // .enter().append('g')
18 | // .attr('class', 'legend')
19 | // .attr('transform', (d, i) => `translate(0, ${i * 20})`);
20 | //
21 | // legend.append('rect')
22 | // .attr('x', innerW - 18)
23 | // .attr('width', 18)
24 | // .attr('height', 18)
25 | // .style('fill', color);
26 | //
27 | // legend.append('text')
28 | // .attr('x', width - 24)
29 | // .attr('y', 9)
30 | // .attr('dy', '.35em')
31 | // .style('text-anchor', 'end')
32 | // .text((d) => d.t);
33 |
--------------------------------------------------------------------------------
/src/visualization/LineChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class LineChart extends React.Component {
6 | render () {
7 | const data = this.props.data,
8 | xDataKey = this.props.xDataKey,
9 | yDataKey = this.props.yDataKey,
10 | dataKey = this.props.dataKey || yDataKey,
11 | width= this.props.width || 350,
12 | height = this.props.height || 300,
13 | innerW = width - 60,
14 | innerH = height - 60,
15 | xScale = this.props.xScale,
16 | yScale = this.props.yScale,
17 | color = this.props.color || '#47b8e0',
18 | pointBorderColor = this.props.pointBorderColor || '#ffc952',
19 | pointColor = this.props.pointColor || '#fff';
20 |
21 |
22 | var line = d3.svg.line()
23 | .interpolate("monotone")
24 | .x((d) => xScale(d[xDataKey]))
25 | .y((d) => yScale(d[dataKey]));
26 |
27 | var planeElement = ReactFauxDOM.createElement('svg')
28 | var plane = d3.select(planeElement)
29 | .attr('class', 'LineChart')
30 | .attr('width', width)
31 | .attr('height', height)
32 | .style('z-index', this.props.zIndex)
33 | .style('position', 'absolute');
34 |
35 | var g = plane.append('g')
36 | .attr('class', 'plane')
37 | .attr('width', innerW)
38 | .attr('height', innerH)
39 | .attr('transform', `translate(50, 20)`)
40 | .style('display', 'inline-block');
41 |
42 | g.append('path')
43 | .datum(data)
44 | .attr('class', 'line')
45 | .attr('d', line)
46 | .style('fill', 'none')
47 | .style('stroke', color)
48 | .style('stroke-width', 2);
49 |
50 | g.selectAll('circle')
51 | .data(data)
52 | .enter().append('circle')
53 | .attr('class', 'circle')
54 | .attr('cx', (d) => xScale(d[xDataKey]))
55 | .attr('cy', (d) => yScale(d[dataKey]))
56 | .attr('r', 3)
57 | .style('fill', pointColor)
58 | .style('stroke', pointBorderColor);
59 |
60 | return plane.node().toReact();
61 | }
62 | }
63 |
64 | LineChart.propTypes = {
65 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
66 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
67 | data: React.PropTypes.array,
68 | dataPoints: React.PropTypes.bool,
69 | dataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
70 | color: React.PropTypes.string,
71 | pointColor: React.PropTypes.string,
72 | pointBorderColor: React.PropTypes.string
73 | }
74 |
75 | export default LineChart;
76 |
--------------------------------------------------------------------------------
/src/visualization/PieChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class PieChart extends React.Component {
6 | render () {
7 | const data = this.props.data,
8 | dataKey = this.props.dataKey || 'y',
9 | labelKey = this.props.labelKey || 'x',
10 | width= this.props.width || 350,
11 | height = this.props.height || 300,
12 | radius = Math.min(width, height) /2.1,
13 | donut = this.props.donut,
14 | colorFill = (donut) ? radius - radius / donut : 0,
15 | textColor = this.props.textColor || '#fff',
16 | colors = this.props.colors || ["#e1eef6","#ff5f2e","#fcbe32","#004e66",
17 | "#ff7473","#ffc952","#47b8e0","#34314c","#47b8e0","#47b8e0"],
18 | color = d3.scale.ordinal()
19 | .range(colors);
20 |
21 | var arc = d3.svg.arc()
22 | .outerRadius(radius - 10)
23 | .innerRadius(colorFill);
24 |
25 | var labelArc = d3.svg.arc()
26 | .outerRadius(radius - 40)
27 | .innerRadius(radius - 40);
28 |
29 | var pie = d3.layout.pie()
30 | .sort(null)
31 | .value((d) => d[dataKey]);
32 |
33 | var chart = d3.select(ReactFauxDOM.createElement('svg'))
34 | .attr('class', 'PieChart')
35 | .attr('width', width)
36 | .attr('height', height)
37 | .style('display', 'inline-block')
38 |
39 | var g = chart.append('g')
40 | .attr('transform', `translate(${width / 2}, ${height / 2})`)
41 | .style('display', 'inline-block');
42 |
43 | var slice = g.selectAll('.arc')
44 | .data(pie(data))
45 | .enter().append('g')
46 | .attr('class', 'arc');
47 |
48 | slice.append('path')
49 | .attr('d', arc)
50 | .style('fill', (d) => color(d.data[labelKey]));
51 |
52 | slice.append('text')
53 | .attr('transform', (d) => `translate(${labelArc.centroid(d)})`)
54 | .attr('dy', '.35em')
55 | .text((d) => d.data[labelKey])
56 | .style('font', '11px sans-serif')
57 | .style('fill', textColor)
58 | .style('text-anchor', 'middle');
59 |
60 | return chart.node().toReact();
61 | }
62 | }
63 |
64 | PieChart.propTypes = {
65 | width: React.PropTypes.number,
66 | height: React.PropTypes.number,
67 | colors: React.PropTypes.array,
68 | donut: React.PropTypes.number,
69 | data: React.PropTypes.array,
70 | dataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
71 | labelKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
72 | textColor: React.PropTypes.string
73 | }
74 |
75 | export default PieChart;
76 |
--------------------------------------------------------------------------------
/src/visualization/RadarArea.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 | import { getDividends } from './../utils/Dividends.js';
5 |
6 | class RadarArea extends React.Component {
7 | render () {
8 | const width = this.props.width || 350,
9 | height = this.props.height || 300,
10 | data = this.props.data,
11 | rangeKey = this.props.rangeKey,
12 | labelKey = this.props.labelKey,
13 | dataKey = this.props.dataKey || rangeKey,
14 | largestTick = this.props.largestTick,
15 | numBars = this.props.numBars,
16 | barHeight = this.props.barHeight,
17 | color = this.props.color,
18 | colorOpacity = this.props.colorOpacity || 0.7;
19 |
20 | var radius = d3.scale.linear()
21 | .domain([0,largestTick])
22 | .range([0, barHeight]);
23 |
24 | var line = d3.svg.line.radial()
25 | .interpolate('linear-closed')
26 | .radius((d) => radius(d[dataKey]))
27 | .angle((d,i) => (i * 2 * Math.PI / numBars));
28 |
29 | var area = d3.svg.area.radial()
30 | .interpolate(line.interpolate())
31 | .innerRadius(radius(0))
32 | .outerRadius(line.radius())
33 | .angle(line.angle());
34 |
35 | var plane = d3.select(ReactFauxDOM.createElement('svg'))
36 | .attr('class', 'RadarArea')
37 | .attr('width', width)
38 | .attr('height', height)
39 | .style('position', 'absolute');
40 |
41 | var g = plane.append('g')
42 | .attr('transform', `translate(${width / 2}, ${height / 2} )`)
43 | .style('z-index', this.props.zIndex)
44 | .style('display', 'inline-block');
45 |
46 | var layer = g.selectAll('.layer')
47 | .data([data]).enter()
48 | .append('path')
49 | .attr('class', 'layer')
50 | .attr('d', (d) => area(d))
51 | .style('fill', color)
52 | .style('fill-opacity', colorOpacity)
53 | .style('stroke', '#CFCCCC')
54 | .style('stroke-width', '0.5px')
55 | .style('font-size', 12);
56 |
57 | return plane.node().toReact();
58 | }
59 | }
60 |
61 | RadarArea.propTypes = {
62 | dataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
63 | color: React.PropTypes.string,
64 | colorOpacity: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number])
65 | };
66 |
67 | export default RadarArea;
68 |
--------------------------------------------------------------------------------
/src/visualization/RadarChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 | import { getDividends } from './../utils/Dividends.js';
5 |
6 | class RadarChart extends React.Component {
7 | render () {
8 | const width = this.props.width || 350,
9 | height = this.props.height || 300,
10 | data = this.props.data,
11 | rangeKey = this.props.rangeKey,
12 | labelKey = this.props.labelKey,
13 | barHeight = height / 2 - 40,
14 | tickValues = data.map((d) => d[rangeKey]),
15 | largestTick = Math.max(...tickValues),
16 | tickSpace = getDividends(largestTick, 6);
17 |
18 | var plane = d3.select(ReactFauxDOM.createElement('svg'))
19 | .attr('class', 'RadarChart')
20 | .attr('width', width)
21 | .attr('height', height)
22 | .style('position', 'relative')
23 | .style('display', 'inline-block');
24 |
25 | var g = plane.append('g')
26 | .attr('transform', `translate(${width / 2}, ${height / 2} )`);
27 |
28 | var numBars = data.length;
29 |
30 | var radius = d3.scale.linear()
31 | .domain([0,largestTick])
32 | .range([0, barHeight]);
33 |
34 | var line = d3.svg.line.radial()
35 | .interpolate('linear-closed')
36 | .radius((d) => radius(d[rangeKey]))
37 | .angle((d,i) => (i * 2 * Math.PI / numBars));
38 |
39 | var area = d3.svg.area.radial()
40 | .interpolate(line.interpolate())
41 | .innerRadius(radius(0))
42 | .outerRadius(line.radius())
43 | .angle(line.angle());
44 |
45 | tickValues.sort((a,b) => b - a);
46 |
47 | var tickPath = g.selectAll('.tickPath')
48 | .data(tickSpace).enter()
49 |
50 | tickPath.append('path')
51 | .attr('class', 'tickPath')
52 | .attr('d', function(d) {
53 | var tickArray = [], i;
54 | for (i = 0; i < numBars; i++) tickArray.push({[rangeKey]: d});
55 | return area(tickArray);
56 | })
57 | .style('fill', 'none')
58 | .style('stroke', (d,i) => (i === 0) ? 'rgb(102, 102, 102)' : 'rgb(102, 102, 102)')
59 | .style('stroke-width', (d,i) => (i === 0) ? '.8px' : '.5px');
60 |
61 | g.selectAll('text')
62 | .data(tickSpace).enter()
63 | .append('text')
64 | .text((d) => d)
65 | .attr('y', (d) => radius(-d) + 20)
66 | .attr('x', + 3)
67 | .style('font-size', 12)
68 | .style('fill', '#CFCCCC');
69 |
70 | var lines = g.selectAll('line')
71 | .data(data)
72 | .enter().append('g')
73 | .attr('class', 'lines');
74 |
75 | lines.append('line')
76 | .attr('y2', - barHeight )
77 | .style('stroke', '#5e5e5e')
78 | .style('stroke-width', '.5px')
79 | .attr('transform', (d, i) => `rotate(${(i * 360 / numBars)})`);
80 |
81 | lines.append('text')
82 | .attr('class', 'names')
83 | .attr('x', (d, i) => (barHeight + 13) * Math.sin((i * 2 * Math.PI / numBars)))
84 | .attr('y', (d, i) => -(barHeight + 13) * Math.cos((i * 2 * Math.PI / numBars)))
85 | .attr('text-anchor', function(d,i) {
86 | if (i === 0 || i === numBars / 2) {
87 | return 'middle';
88 | }else if (i <= numBars / 2) {
89 | return 'begin';
90 | }else {
91 | return 'end';
92 | }
93 | })
94 | .style('font-weight', 'bold')
95 | .style('fill', '#CFCCCC')
96 | .text((d) => d[labelKey]);
97 |
98 | return (
99 |
100 | {
101 | (typeof this.props.children !== 'array') ?
102 | React.Children.map(this.props.children, (child, key) => {
103 | return React.cloneElement(child, { zIndex: key + 1, data, rangeKey, labelKey, width, height, largestTick, numBars, barHeight});
104 | })
105 | :
106 | React.cloneElement(this.props.children, { zIndex: 10 , data, rangeKey, labelKey, width, height, largestTick, numBars, barHeight})
107 | }
108 | {plane.node().toReact()}
109 |
110 | );
111 | }
112 | }
113 |
114 | RadarChart.propTypes = {
115 | width: React.PropTypes.number,
116 | height: React.PropTypes.number,
117 | data: React.PropTypes.array.isRequired,
118 | rangeKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
119 | labelKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired
120 | };
121 |
122 | export default RadarChart;
123 |
--------------------------------------------------------------------------------
/src/visualization/RadialBarChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class RadialBarChart extends React.Component {
6 | render () {
7 | const {width, height, data, colors} = this.props,
8 | innerW = width - 0,
9 | innerH = height - 40,
10 | radiusMax = (height / 2.2),
11 | xColumn = "name",
12 | sliceSizeColumn = "population",
13 | colorColumn = "religion";
14 |
15 | var xScale = d3.scale.ordinal().rangePoints([0, width]);
16 |
17 | var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
18 | .outerTickSize(0);
19 |
20 | var colorScale = d3.scale.ordinal()
21 | .range(colors);
22 |
23 | var angleScale = d3.scale.linear();
24 |
25 | var chart = d3.select(ReactFauxDOM.createElement('svg'))
26 | .attr('class', 'RadialBarChart')
27 | .attr('width', width)
28 | .attr('height', height);
29 |
30 | var g = chart.append("g")
31 | .attr('class', 'plane')
32 | .attr("transform", "translate(" + 11 + "," + 33 + ")");
33 |
34 | var pieG = g.append("g");
35 |
36 | var pie = d3.layout.pie();
37 | var arc = d3.svg.arc();
38 |
39 | xScale.domain(data.map((d) => d.name));
40 |
41 | colorScale.domain(data.map((d) => d[colorColumn]));
42 |
43 | pie.value((d) => d[sliceSizeColumn]);
44 |
45 | angleScale.domain([0, d3.max(data, (d) => d[sliceSizeColumn])])
46 | .range([0, Math.PI]);
47 |
48 | var pieData = pie(data);
49 | pieData.forEach(function (d){
50 | d.startAngle = 0;
51 | d.endAngle = angleScale(d.value);
52 | });
53 |
54 | pieG.attr("transform", `translate(${width / 2}, ${innerH}) rotate(-90)`)
55 | .attr('class', `pieSlice`);
56 |
57 | var slices = pieG.selectAll("path")
58 | .data(pieData);
59 |
60 | slices.append('text')
61 | .attr('dy', '.35em')
62 | .text((d) => d.population);
63 |
64 | slices.enter().append("path")
65 | .attr("d", function (d, i){
66 | arc
67 | .innerRadius(function(d) {
68 | return i / (pieData.length - 1) * radiusMax;
69 | })
70 | .outerRadius(function(d) {
71 | return (i + 1) / (pieData.length - 1) * radiusMax;
72 | });
73 | return arc(d);
74 | })
75 | .attr("fill", function (d){ return colorScale(d.data[colorColumn]); });
76 | slices.exit().remove();
77 |
78 | return chart.node().toReact();
79 | }
80 |
81 | }
82 |
83 | RadialBarChart.propTypes = {
84 | data: React.PropTypes.array,
85 | width: React.PropTypes.number,
86 | height: React.PropTypes.number,
87 | colors: React.PropTypes.array
88 | };
89 |
90 | export default RadialBarChart;
91 |
--------------------------------------------------------------------------------
/src/visualization/Responsive.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { findDOMNode } from 'react-dom';
3 |
4 | class Responsive extends React.Component{
5 | constructor () {
6 | super();
7 | this.state = {
8 | size: {
9 | w: 0,
10 | h: 0
11 | }
12 | }
13 | }
14 |
15 | componentDidMount () {
16 | window.addEventListener('resize', this.fitToParentSize.bind(this));
17 | this.fitToParentSize();
18 | }
19 |
20 | componentWillReceiveProps () {
21 | this.setState({
22 | size: {
23 | w: this.props.width,
24 | h: this.props.height
25 | }
26 | });
27 | this.fitToParentSize();
28 | }
29 |
30 | componentWillUnmount() {
31 | window.removeEventListener('resize', this.fitToParentSize.bind(this));
32 | }
33 |
34 | fitToParentSize () {
35 | let elem = findDOMNode(this);
36 | let w = elem.parentNode.offsetWidth;
37 | let h = elem.parentNode.offsetHeight;
38 | let currentSize = this.state.size;
39 |
40 | if (w !== currentSize.w || h !== currentSize.h) {
41 | this.setState({
42 | size: {
43 | w: w,
44 | h: h
45 | }
46 | });
47 | }
48 | }
49 |
50 | render () {
51 |
52 | let {width, height} = this.props;
53 |
54 | width = this.state.size.w;
55 | height = this.state.size.h;
56 |
57 | var Charts = React.cloneElement(this.props.children, { width, height});
58 |
59 | return Charts;
60 | }
61 | };
62 |
63 | export default Responsive;
64 |
--------------------------------------------------------------------------------
/src/visualization/ScatterPlot.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class ScatterPlot extends React.Component {
6 | render () {
7 | const data = this.props.data,
8 | xDataKey = this.props.xDataKey,
9 | yDataKey = this.props.yDataKey,
10 | dataKey = this.props.dataKey,
11 | scatterKey = this.props.scatterKey || yDataKey,
12 | width= this.props.width || 350,
13 | height = this.props.height || 300,
14 | innerW = width - 60,
15 | innerH = height - 60,
16 | xScale = this.props.xScale,
17 | yScale = this.props.yScale,
18 | pointRadius= this.props.pointRadius || 3.5,
19 | color = (this.props.colors) ? d3.scale.ordinal().range(this.props.colors) : d3.scale.category10();
20 |
21 | var planeElement = ReactFauxDOM.createElement('svg')
22 | var plane = d3.select(planeElement)
23 | .attr('class', 'ScatterPlot')
24 | .attr('width', width)
25 | .attr('height', height)
26 | .style('position', 'absolute');
27 |
28 | var g = plane.append('g')
29 | .attr('class', 'plane')
30 | .attr('width', innerW)
31 | .attr('height', innerH)
32 | .attr('transform', `translate(50, 20)`)
33 | .style('display', 'inline-block');
34 |
35 | g.selectAll('.dot')
36 | .data(data)
37 | .enter().append('circle')
38 | .attr('class', 'dot')
39 | .attr('r', pointRadius)
40 | .attr('cx', (d) => xScale(d[xDataKey]))
41 | .attr('cy', (d) => yScale(d[dataKey]))
42 | .style('fill', (d) => color(d[scatterKey]));
43 |
44 | return plane.node().toReact();
45 | }
46 | }
47 |
48 | ScatterPlot.propTypes = {
49 | width: React.PropTypes.number,
50 | height: React.PropTypes.number,
51 | data: React.PropTypes.array,
52 | colors: React.PropTypes.array,
53 | dataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
54 | scatterKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
55 | pointRadius: React.PropTypes.number
56 | }
57 |
58 | export default ScatterPlot;
59 |
--------------------------------------------------------------------------------
/src/visualization/TreeMap.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 |
5 | class TreeMap extends React.Component {
6 | render () {
7 | const { root, width, height } = this.props;
8 | const innerW = width - 60,
9 | innerH = height - 60;
10 |
11 | var color = d3.scale.category20c();
12 |
13 | var treemap = d3.layout.treemap()
14 | .size([width, height])
15 | .sticky(true)
16 | .value((d) => d.size);
17 |
18 | var chart = d3.select(ReactFauxDOM.createElement('div'))
19 | .style('position', 'relative')
20 | .style('width', width)
21 | .style('height', height)
22 | .attr('class', 'TreeMap')
23 | .style('left', `10px`)
24 | .style('top', `40px`);
25 |
26 | var node = chart.datum(root)
27 | .selectAll('.node')
28 | .data(treemap.nodes)
29 | .enter().append('div')
30 | .attr('class', 'node')
31 | .style("left", (d) => d.x + "px")
32 | .style("top", (d) => d.y + "px")
33 | .style("width", (d) => Math.max(0, d.dx - 1) + "px")
34 | .style("height", (d) => Math.max(0, d.dy - 1) + "px")
35 | .style('background', (d) => (d.children) ? color (d.name) : null)
36 | .style('border', 'solid 1px white')
37 | .style('10px', 'sans-serif')
38 | .style('line-height', 12)
39 | .style('overflow', 'hidden')
40 | .style('position', 'absolute')
41 | .style('text-indent', 2)
42 | .text((d) => (d.children) ? null : d.name);
43 |
44 | return chart.node().toReact();
45 | }
46 | }
47 |
48 | TreeMap.propTypes = {
49 | width: React.PropTypes.number,
50 | height: React.PropTypes.number,
51 | root: React.PropTypes.object
52 | }
53 |
54 | export default TreeMap;
55 |
--------------------------------------------------------------------------------
/src/visualization/XYAxis.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 | import ReactFauxDOM from 'react-faux-dom';
4 | import { determineScales } from './../utils/DynamicScales.js';
5 |
6 | class XYAxis extends React.Component {
7 | scales () {
8 | var xScale, yScale,
9 | xyConfig = this.props.xyConfig || {},
10 | data = (xyConfig.data) ? xyConfig.data : this.props.data,
11 | xDataKey = (xyConfig.xDataKey) ? xyConfig.xDataKey : this.props.xDataKey || 'x',
12 | yDataKey = (xyConfig.yDataKey) ? xyConfig.yDataKey : this.props.yDataKey || 'y',
13 | width = (xyConfig.width) ? xyConfig.width : this.props.width || 350,
14 | height = (xyConfig.height) ? xyConfig.height : this.props.height || 300,
15 | innerW = width - 60,
16 | innerH = height - 60,
17 | defaultOrdinal = (xyConfig.defaultOrdinal) ? xyConfig.defaultOrdinal
18 | : this.props.defaultOrdinal,
19 | scaleTypes = (defaultOrdinal) ? determineScales(data, xDataKey, yDataKey, defaultOrdinal)
20 | : determineScales(data, xDataKey, yDataKey);
21 |
22 | if (scaleTypes.x === 'linear') {
23 | xScale = d3.scale.linear()
24 | .domain(d3.extent(data, (d) => d[xDataKey]))
25 | .range([0, innerW]);
26 | } else {
27 | xScale = d3.scale.ordinal()
28 | .domain(data.map((d) => d[xDataKey]))
29 | .rangeRoundBands([0, innerW], .2);
30 | }
31 |
32 | if (scaleTypes.y === 'linear') {
33 | yScale = d3.scale.linear()
34 | .domain([0, d3.max(data, (d) => d[yDataKey])])
35 | .range([innerH, 0]);
36 | } else {
37 | yScale = d3.scale.ordinal()
38 | .domain(data.map((d) => d[yDataKey]))
39 | .rangeRoundBands([0, innerH], 0);
40 | }
41 | return {xScale, yScale, innerH, innerW, scaleTypes};
42 | }
43 |
44 | makeGrid () {
45 | var xAxis, yAxis,
46 | scales = this.scales(),
47 | xScale = scales.xScale,
48 | yScale= scales.yScale,
49 | xyConfig = this.props.xyConfig || {},
50 | xTicks = (xyConfig.xTicks) ? xyConfig.xTicks : this.props.xTicks || 4,
51 | yTicks = (xyConfig.yTicks) ? xyConfig.yTicks : this.props.yTicks || 4,
52 | grid = (xyConfig.grid) ? xyConfig.grid : this.props.grid || true;
53 |
54 | if (grid) {
55 | if (xTicks) {
56 | xAxis = d3.svg.axis()
57 | .scale(xScale)
58 | .ticks(xTicks)
59 | .orient('bottom')
60 | .innerTickSize(-scales.innerH)
61 | .outerTickSize(0)
62 | .tickPadding(3);
63 |
64 | yAxis = d3.svg.axis()
65 | .scale(yScale)
66 | .ticks(yTicks)
67 | .orient('left')
68 | .innerTickSize(-scales.innerW)
69 | .outerTickSize(0)
70 | .tickPadding(3);
71 | } else {
72 | xAxis = d3.svg.axis()
73 | .scale(xScale)
74 | .orient('bottom')
75 | .innerTickSize(-scales.innerH)
76 | .outerTickSize(0)
77 | .tickPadding(3);
78 |
79 | yAxis = d3.svg.axis()
80 | .scale(yScale)
81 | .orient('left')
82 | .innerTickSize(-scales.innerW)
83 | .outerTickSize(0)
84 | .tickPadding(3);
85 | }
86 |
87 | } else {
88 | if (yTicks) {
89 | xAxis = d3.svg.axis()
90 | .scale(xScale)
91 | .ticks(xTicks)
92 | .orient('bottom')
93 | .outerTickSize(0)
94 | .tickPadding(3);
95 |
96 | yAxis = d3.svg.axis()
97 | .scale(yScale)
98 | .ticks(yTicks)
99 | .orient('left')
100 | .outerTickSize(0)
101 | .tickPadding(3);
102 | } else {
103 | xAxis = d3.svg.axis()
104 | .scale(xScale)
105 | .orient('bottom')
106 | .outerTickSize(0)
107 | .tickPadding(3);
108 |
109 | yAxis = d3.svg.axis()
110 | .scale(yScale)
111 | .orient('left')
112 | .outerTickSize(0)
113 | .tickPadding(3);
114 | }
115 | }
116 | return {xAxis, yAxis, xScale, yScale, scaleTypes: scales.scaleTypes};
117 | }
118 |
119 | render () {
120 | const xyConfig = this.props.xyConfig || {},
121 | data = (xyConfig.data) ? xyConfig.data : this.props.data,
122 | xDataKey = (xyConfig.xDataKey) ? xyConfig.xDataKey : this.props.xDataKey || 'x',
123 | yDataKey = (xyConfig.yDataKey) ? xyConfig.yDataKey : this.props.yDataKey || 'y',
124 | width = (xyConfig.width) ? xyConfig.width : this.props.width || 350,
125 | height = (xyConfig.height) ? xyConfig.height : this.props.height || 300,
126 | innerW = width - 60,
127 | innerH = height - 60,
128 | xLabel = (xyConfig.xLabel) ? xyConfig.xLabel : this.props.xLabel || 'x-axis',
129 | yLabel = (xyConfig.yLabel) ? xyConfig.yLabel : this.props.yLabel || 'y-axis',
130 | gridLineType = (xyConfig.gridLines) ? (xyConfig.gridLines !== 'solid') ? '3,3' : '' : (this.props.gridLines !== 'solid') ? '3,3' : '',
131 | grid = this.makeGrid(),
132 | xScale = grid.xScale,
133 | yScale = grid.yScale,
134 | xAxis = grid.xAxis,
135 | yAxis = grid.yAxis,
136 | scaleTypes = grid.scaleTypes;
137 |
138 | var planeElement = ReactFauxDOM.createElement('svg')
139 | var plane = d3.select(planeElement)
140 | .attr('class', 'XYAxis')
141 | .attr('width', width)
142 | .attr('height', height)
143 | .style('position', 'relative')
144 | .style('z-index', 0);
145 |
146 | var g = plane.append('g')
147 | .attr('class', 'plane')
148 | .attr('transform', `translate(50, 20)`)
149 | .style('display', 'inline-block');
150 |
151 | var xLines = g.append("g")
152 | .attr('class', 'x axis')
153 | .attr('transform', `translate(0, ${innerH})`)
154 | .call(xAxis)
155 | .style('fill', 'rgb(102, 102, 102)')
156 | .style('stroke', 'rgb(102, 102, 102)')
157 | .style('font-size', 12)
158 | .style('letter-spacing', 1.5)
159 | .style('font-weight', 100);
160 |
161 | xLines.selectAll('line')
162 | .style('stroke-width', '1')
163 | .style('stroke', 'rgb(102, 102, 102)')
164 | .style('opacity', 0.2)
165 | .style('stroke-dasharray', (gridLineType))
166 | .style('fill', 'rgb(102, 102, 102)')
167 | .style('font-size', 12);
168 |
169 | xLines.append('text')
170 | .attr('class', 'label')
171 | .attr('x', innerW)
172 | .attr('y', -6)
173 | .style('text-anchor', 'end')
174 | .text(xLabel)
175 | .style('fill', 'rgb(102, 102, 102)')
176 | .style('font-size', 12);
177 |
178 | var yLines = g.append('g')
179 | .attr('class', 'y axis')
180 | .call(yAxis)
181 | .style('fill', 'rgb(102, 102, 102)')
182 | .style('stroke', 'rgb(102, 102, 102)')
183 | .style('font-size', 12)
184 | .style('letter-spacing', 1)
185 | .style('font-weight', 100);
186 |
187 | yLines.selectAll('line')
188 | .style('stroke-width', '1')
189 | .style('stroke', 'rgb(102, 102, 102)')
190 | .style('opacity', 0.2)
191 | .style('stroke-dasharray', (gridLineType))
192 | .style('fill', 'rgb(102, 102, 102)')
193 | .style('font-size', 12);
194 |
195 | yLines.append('text')
196 | .attr('transform', 'rotate(-90)')
197 | .attr('y', 6)
198 | .attr('dy', '.71em')
199 | .style('text-anchor', 'end')
200 | .text(yLabel)
201 | .style('fill', 'rgb(102, 102, 102)')
202 | .style('font-size', 12);
203 |
204 | return (
205 |
206 | {
207 | (typeof this.props.children !== 'array') ?
208 | React.Children.map(this.props.children, (child, key) => {
209 | return React.cloneElement(child, { zIndex: key + 1, data, xDataKey, yDataKey, width, height, xAxis, yAxis, xScale, yScale, scaleTypes});
210 | })
211 | :
212 | React.cloneElement(this.props.children, { zIndex: 10 , data, xDataKey, yDataKey, width, height, xAxis, yAxis, xScale, yScale, scaleTypes})
213 | }
214 | {plane.node().toReact()}
215 |
216 | );
217 | }
218 | }
219 |
220 | XYAxis.propTypes = {
221 | xyConfig: React.PropTypes.object,
222 | width: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
223 | height: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
224 | data: React.PropTypes.array,
225 | xdataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
226 | ydataKey: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
227 | defaultOrdinal: React.PropTypes.oneOf(['x', 'y', 'xy']),
228 | xTicks: React.PropTypes.number,
229 | yTicks: React.PropTypes.number,
230 | xLabel: React.PropTypes.string,
231 | yLabel: React.PropTypes.string,
232 | grid: React.PropTypes.bool,
233 | gridLines: React.PropTypes.oneOf(['solid', 'dashed']),
234 | }
235 |
236 | export default XYAxis;
237 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var env = process.env.NODE_ENV;
3 |
4 | var config = {
5 |
6 | output: {
7 | library: 'component-kit',
8 | libraryTarget: 'umd'
9 | },
10 |
11 | externals: [
12 | {
13 | react: {
14 | root: 'React',
15 | commonjs2: 'react',
16 | commonjs: 'react',
17 | amd: 'react'
18 | }
19 | }
20 | ],
21 |
22 | module: {
23 | loaders: [
24 | {
25 | test: /\.js$/,
26 | exclude: /node_modules/,
27 | loader: 'babel'
28 | }
29 | ]
30 | },
31 |
32 | node: {
33 | Buffer: false
34 | },
35 |
36 | plugins: [
37 | new webpack.optimize.OccurenceOrderPlugin(),
38 | new webpack.optimize.DedupePlugin(),
39 | new webpack.DefinePlugin({
40 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
41 | })
42 | ]
43 |
44 | }
45 |
46 | if (env === 'production') {
47 | config.plugins.push(
48 | new webpack.optimize.UglifyJsPlugin({
49 | compressor: {
50 | pure_getters: true,
51 | unsafe: true,
52 | unsafe_comps: true,
53 | screw_ie8: true,
54 | warnings: false
55 | }
56 | })
57 | )
58 | }
59 |
60 | module.exports = config;
61 |
--------------------------------------------------------------------------------