41 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
42 | */
43 |
44 | /** @license React v0.19.1
45 | * scheduler.production.min.js
46 | *
47 | * Copyright (c) Facebook, Inc. and its affiliates.
48 | *
49 | * This source code is licensed under the MIT license found in the
50 | * LICENSE file in the root directory of this source tree.
51 | */
52 |
53 | /** @license React v16.13.1
54 | * react-is.production.min.js
55 | *
56 | * Copyright (c) Facebook, Inc. and its affiliates.
57 | *
58 | * This source code is licensed under the MIT license found in the
59 | * LICENSE file in the root directory of this source tree.
60 | */
61 |
62 | /** @license React v16.14.0
63 | * react-dom-server.browser.production.min.js
64 | *
65 | * Copyright (c) Facebook, Inc. and its affiliates.
66 | *
67 | * This source code is licensed under the MIT license found in the
68 | * LICENSE file in the root directory of this source tree.
69 | */
70 |
71 | /** @license React v16.14.0
72 | * react-dom.production.min.js
73 | *
74 | * Copyright (c) Facebook, Inc. and its affiliates.
75 | *
76 | * This source code is licensed under the MIT license found in the
77 | * LICENSE file in the root directory of this source tree.
78 | */
79 |
80 | /** @license React v16.14.0
81 | * react.production.min.js
82 | *
83 | * Copyright (c) Facebook, Inc. and its affiliates.
84 | *
85 | * This source code is licensed under the MIT license found in the
86 | * LICENSE file in the root directory of this source tree.
87 | */
88 |
--------------------------------------------------------------------------------
/docs/build/index.html:
--------------------------------------------------------------------------------
1 | Reactochart Docs Loading...
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Redirect
4 |
5 |
6 |
7 | Redirecting to docs...
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/src/ExampleSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import PropTypes from 'prop-types';
4 | import _ from 'lodash';
5 | import * as d3 from 'd3'; // eslint-disable-line no-restricted-imports
6 | import Playground from 'component-playground';
7 |
8 | // import *all* reactochart components/utils - usually you'd import one at a time
9 | import * as Reactochart from '../../src';
10 |
11 | import {
12 | randomWalk,
13 | randomWalkSeries,
14 | randomWalkTimeSeries,
15 | } from './data/util';
16 | window.Reactochart = Reactochart;
17 |
18 | export default class ExampleSection extends React.Component {
19 | static propTypes = {
20 | codeText: PropTypes.string,
21 | scope: PropTypes.object,
22 | isExpanded: PropTypes.bool,
23 | label: PropTypes.node,
24 | id: PropTypes.string,
25 | description: PropTypes.node,
26 | onClick: PropTypes.func,
27 | };
28 | static defaultProps = {
29 | codeText: '',
30 | scope: {},
31 | isExpanded: true,
32 | label: 'Example',
33 | id: '',
34 | };
35 |
36 | onClick = e => {
37 | if (this.props.onClick) {
38 | this.props.onClick(e, this.props.id);
39 | }
40 | };
41 |
42 | render() {
43 | const { codeText, isExpanded, label, id, description } = this.props;
44 | const scope = {
45 | React,
46 | ReactDOM,
47 | d3,
48 | _,
49 | randomWalk,
50 | randomWalkSeries,
51 | randomWalkTimeSeries,
52 | // include all Reactochart components in scope
53 | ...Reactochart,
54 | ...this.props.scope,
55 | };
56 |
57 | return (
58 |
63 |
64 |
65 | {label || id} {isExpanded ? '▼' : '►'}
66 |
67 |
68 | {isExpanded ? (
69 |
70 | {description ? (
71 |
{description}
72 | ) : null}
73 |
74 |
75 | ) : null}
76 |
77 |
78 | );
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/docs/src/Lesson.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class Lesson extends React.Component {
5 | static propTypes = {
6 | name: PropTypes.string,
7 | children: PropTypes.any,
8 | };
9 |
10 | render() {
11 | const { name, children } = this.props;
12 |
13 | return (
14 |
15 |
{name}
16 |
17 | {children}
18 |
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/docs/src/data/util.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | export function randomWalk(length = 100, start = 0, variance = 10) {
4 | return _.reduce(
5 | _.range(length - 1),
6 | sequence => {
7 | return sequence.concat(_.last(sequence) + _.random(-variance, variance));
8 | },
9 | [start],
10 | );
11 | }
12 |
13 | export function randomWalkSeries(length = 100, start = 0, variance = 10) {
14 | return randomWalk(length, start, variance).map((n, i) => [i, n]);
15 | }
16 |
17 | export function randomWalkTimeSeries(
18 | length = 100,
19 | start = 0,
20 | variance = 10,
21 | startDate = new Date(2015, 0, 1),
22 | ) {
23 | let date = startDate;
24 | return randomWalk(length, start, variance).map(n => {
25 | date = new Date(date.getTime() + 24 * 60 * 60 * 1000);
26 | return [date, n];
27 | });
28 | }
29 |
30 | export function removeRandomData(data, removeCount = 5) {
31 | const gapData = data.slice();
32 | _.times(removeCount, () => {
33 | if (!gapData.length) return;
34 | const gapIndex = _.random(gapData.length - 1);
35 | gapData.splice(gapIndex, 1);
36 | });
37 | return gapData;
38 | }
39 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaBarChart/AreaBarChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'rates-by-age',
10 | label: 'Smoking Rates by Age',
11 | codeText: require('./examples/RatesByAge.js.example').default,
12 | },
13 | {
14 | id: 'basic',
15 | label: 'Basic AreaBarChart',
16 | codeText: require('./examples/AreaBarChart.js.example').default,
17 | },
18 | ];
19 |
20 | export default class AreaBarChartExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaBarChart/examples/AreaBarChart.js.example:
--------------------------------------------------------------------------------
1 | const AreaBarChartExample = (props) => {
2 | return
3 |
4 |
5 | Math.sin(d / 10) * 10}
8 | xEnd={d => Math.sin((d + 1) / 10) * 10}
9 | y={d => Math.cos(d / (Math.PI))}
10 | />
11 |
12 |
13 |
14 | Math.cos(d / (Math.PI))}
18 | y={d => Math.sin(d / 10) * 10}
19 | yEnd={d => Math.sin((d + 1) / 10) * 10}
20 | />
21 |
22 |
23 | };
24 |
25 | ReactDOM.render( , mountNode);
26 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaBarChart/examples/RatesByAge.js.example:
--------------------------------------------------------------------------------
1 | const RatesByAge = (props) => {
2 | return
3 |
US Smoking Rates by Age Group
4 |
5 |
6 |
7 | d.ageMin}
15 | xEnd={d => d.ageMax}
16 | y={d => d.rate}
17 | />
18 |
19 |
20 | };
21 |
22 | ReactDOM.render( , mountNode);
23 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaChart/AreaChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic AreaChart',
11 | codeText: require('./examples/AreaChart.js.example').default,
12 | },
13 | {
14 | id: 'twoDatasets',
15 | label: 'Area Chart with Two Datasets',
16 | codeText: require('./examples/Area2Datasets.js.example').default,
17 | },
18 | {
19 | id: 'difference',
20 | label: 'Difference Area Chart',
21 | codeText: require('./examples/AreaDifference.js.example').default,
22 | },
23 | ];
24 |
25 | export default class AreaChartExamples extends React.Component {
26 | render() {
27 | return (
28 |
29 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
30 |
31 | {examples.map(example => {
32 | return ;
33 | })}
34 |
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaChart/examples/Area2Datasets.js.example:
--------------------------------------------------------------------------------
1 | class Area2DatasetsExample extends React.Component {
2 | render() {
3 | const data1 = randomWalkTimeSeries(115).map(([x,y]) => ({x, y}));
4 | const data2 = randomWalkTimeSeries(115).map(([x,y]) => ({x, y}));
5 |
6 | // we have two datasets, but AreaChart takes one combined dataset
7 | // so combine the two datasets into one using the combineDatasets utility function
8 | // (import from 'Reactochart/utils')
9 | // original datasets are of the shape [{x: ..., y: 20}]
10 | // combined is of the shape [{x: ..., y0: 20, y1: 30}]
11 | const combined = utils.Data.combineDatasets([
12 | {data: data1, combineKey: 'x', dataKeys: {y: 'y0'}},
13 | {data: data2, combineKey: 'x', dataKeys: {y: 'y1'}}
14 | ], 'x');
15 |
16 | return
17 |
18 |
19 | d.x}
22 | y={d => d.y0}
23 | yEnd={d => d.y1}
24 | />
25 |
26 |
27 | }
28 | }
29 |
30 | ReactDOM.render( , mountNode);
31 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaChart/examples/AreaChart.js.example:
--------------------------------------------------------------------------------
1 | const AreaChartExample = (props) => {
2 | return
3 |
4 |
5 |
6 | d}
9 | y={d => Math.sin(d / 10) * 10}
10 | yEnd={d => Math.cos((d + 1) / 10) * 10}
11 | />
12 |
13 |
14 | }
15 |
16 | ReactDOM.render( , mountNode);
17 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaChart/examples/AreaDifference.js.example:
--------------------------------------------------------------------------------
1 | class AreaDifferenceExample extends React.Component {
2 | render() {
3 | const data1 = randomWalkTimeSeries(115).map(([x, y]) => ({x, y}));
4 | const data2 = randomWalkTimeSeries(115).map(([x, y]) => ({x, y}));
5 |
6 | // we have two datasets, but AreaChart takes one combined dataset
7 | // so combine the two datasets into one using the combineDatasets utility function
8 | // (from 'reactochart/utils/Data')
9 | const combined = utils.Data.combineDatasets([
10 | {data: data1, combineKey: 'x', dataKeys: {y: 'y0'}},
11 | {data: data2, combineKey: 'x', dataKeys: {y: 'y1'}}
12 | ], 'x');
13 |
14 | return
15 |
16 |
17 |
18 | d.x}
24 | y={d => d.y0}
25 | yEnd={d => d.y1}
26 | />
27 | d.x} y={d => d.y}
30 | lineStyle={{strokeWidth: 3}}
31 | />
32 | d.x} y={d => d.y}
35 | />
36 |
37 |
38 | }
39 | }
40 | ReactDOM.render( , mountNode);
41 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaHeatmap/AreaHeatmapDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic AreaHeatmap',
11 | codeText: require('./examples/AreaHeatmap.js.example').default,
12 | },
13 | ];
14 |
15 | export default class AreaHeatmapExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/AreaHeatmap/examples/AreaHeatmap.js.example:
--------------------------------------------------------------------------------
1 | const AreaHeatmapExample = (props) => {
2 | const gridData = _.range(30).map(m => {
3 | return _.range(30).map(n => {
4 | return {
5 | x: n,
6 | xEnd: n + 1,
7 | y: m,
8 | yEnd: m + 1,
9 | value: Math.sin(m * n * 0.01)
10 | };
11 | });
12 | });
13 |
14 | const data = _.flatten(gridData);
15 |
16 | return
17 |
18 |
19 |
20 | d.value}
23 | x={d => d.x}
24 | xEnd={d => d.xEnd}
25 | y={d => d.y}
26 | yEnd={d => d.yEnd}
27 | rectStyle={{fill: 'rebeccapurple'}}
28 | />
29 |
30 |
31 |
32 |
33 |
34 | d.value}
37 | x={d => d.x}
38 | xEnd={d => d.xEnd}
39 | y={d => d.y}
40 | yEnd={d => d.yEnd}
41 | rectStyle={{fill: '#41ab5d'}}
42 | />
43 | d.value * -1}
46 | x={d => d.x}
47 | xEnd={d => d.xEnd}
48 | y={d => d.y}
49 | yEnd={d => d.yEnd}
50 | rectStyle={{fill: '#fc4e2a'}}
51 | />
52 |
53 |
;
54 | };
55 |
56 | ReactDOM.render( , mountNode);
57 |
--------------------------------------------------------------------------------
/docs/src/docs/AriaLabelContainer/AriaLabelContainerDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'one-dataset',
10 | label: 'With One Dataset',
11 | codeText: require('./examples/OneDataset.js.example').default,
12 | },
13 | {
14 | id: 'two-dataset',
15 | label: 'With Two Datasets',
16 | codeText: require('./examples/TwoDatasets.js.example').default,
17 | },
18 | {
19 | id: 'action',
20 | label: 'With Interactions',
21 | codeText: require('./examples/WithActions.js.example').default,
22 | },
23 | ];
24 |
25 | export default class AriaLabelContainerExamples extends React.Component {
26 | render() {
27 | return (
28 |
29 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
30 |
31 | {examples.map(example => {
32 | return ;
33 | })}
34 |
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/src/docs/AriaLabelContainer/examples/OneDataset.js.example:
--------------------------------------------------------------------------------
1 | const AriaLabelContainerExample = (props) => {
2 | const data = _.range(10).map(d => ({
3 | x: d,
4 | y: Math.round(d * Math.random() * 10)
5 | }))
6 | return
7 |
8 |
9 | d.x}
12 | y={d => d.y}
13 | lineStyle={{stroke: '#ff7f0e', strokeWidth: 3}}
14 | />
15 | {
17 | const { 0: dataPoint } = datasets;
18 | if(xValue){
19 | return `xValue, ${dataPoint.x}; yValue, ${dataPoint.y}`
20 | }
21 | }}
22 | datasetWithAccessor={
23 | [{
24 | data: data,
25 | accessor: d => d.x
26 | }]
27 | }
28 | />
29 | ;
30 | };
31 |
32 | ReactDOM.render( , mountNode);
33 |
--------------------------------------------------------------------------------
/docs/src/docs/AriaLabelContainer/examples/TwoDatasets.js.example:
--------------------------------------------------------------------------------
1 | const AriaLabelContainerExample = (props) => {
2 | const data0 = _.range(10).map(d => ({
3 | x: d,
4 | y: Math.round(d * Math.random() * 10)
5 | }))
6 | const data1 = _.range(7).map(d => ({
7 | x: d,
8 | y: Math.round(d * Math.random() * 10)
9 | }))
10 |
11 | const ariaLabelGenerator = (xValue, datasets) => {
12 | const { 0: data0Point, 1: data1Point } = datasets;
13 | let ariaLabelString = `x Value, ${xValue}`;
14 | if(data0Point) {
15 | ariaLabelString += `, data0 y Value ${data0Point.y}`;
16 | }
17 | if(data1Point) {
18 | ariaLabelString += `, data1 y Value ${data1Point.y}`;
19 | }
20 | return ariaLabelString;
21 | }
22 |
23 |
24 | return
25 |
26 |
27 | d.x}
30 | y={d => d.y}
31 | lineStyle={{stroke: '#ff7f0e', strokeWidth: 3}}
32 | />
33 | d.x}
36 | y={d => d.y}
37 | lineStyle={{stroke: '#2ca02c', strokeWidth: 3}}
38 | />
39 | d.x,
45 | },
46 | {
47 | data: data1,
48 | accessor: d => d.x,
49 | }
50 | ]}
51 | />
52 | ;
53 | };
54 |
55 | ReactDOM.render( , mountNode);
56 |
--------------------------------------------------------------------------------
/docs/src/docs/AriaLabelContainer/examples/WithActions.js.example:
--------------------------------------------------------------------------------
1 | const AriaLabelContainerExample = (props) => {
2 | const [selectedValue, setSelectedValue] = React.useState();
3 |
4 | const data = _.range(10).map(d => ({
5 | x: d,
6 | y: d * 50,
7 | }))
8 |
9 | const onMouseMove = ({xValue, yValue}) => {
10 | setSelectedValue({ x: xValue, y: yValue });
11 | }
12 |
13 | const onMouseLeave = () => setSelectedValue();
14 |
15 | const onKeyDown = (event, xValue, datasets) => {
16 | const dataPoint = datasets[0];
17 | switch (event.keyCode) {
18 | // enter key code
19 | case 13:
20 | setSelectedValue(dataPoint);
21 | break;
22 | default:
23 | break;
24 | }
25 | }
26 |
27 |
28 | return (
29 |
35 |
36 |
37 | d.x}
40 | y={d => d.y}
41 | lineStyle={{stroke: '#ff7f0e', strokeWidth: 3}}
42 | />
43 | {
45 | const dataPoint = datasets[0];
46 | if(dataPoint) {
47 | return `x Value, ${dataPoint.x}; y Value: ${dataPoint.y}`
48 | }
49 | }}
50 | onKeyDown={onKeyDown}
51 | datasetWithAccessor={[
52 | {
53 | data,
54 | accessor: d => d.x
55 | }
56 | ]}
57 | />
58 |
59 | {selectedValue &&
{`(${selectedValue.x}, ${selectedValue.y})`} }
60 |
);
61 | };
62 |
63 | ReactDOM.render( , mountNode);
64 |
--------------------------------------------------------------------------------
/docs/src/docs/Bar/BarDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic Bar',
11 | codeText: require('./examples/Bar.js.example').default,
12 | },
13 | ];
14 |
15 | export default class BarExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/Bar/examples/Bar.js.example:
--------------------------------------------------------------------------------
1 | const BarExample = (props) => {
2 | return
3 |
7 |
8 |
13 |
19 |
20 |
;
21 | };
22 |
23 | ReactDOM.render( , mountNode);
24 |
--------------------------------------------------------------------------------
/docs/src/docs/BarChart/BarChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic BarChart',
11 | codeText: require('./examples/BarChart.js.example').default,
12 | },
13 | {
14 | id: 'gradient',
15 | label: 'BarChart with Linear Gradient',
16 | codeText: require('./examples/BarChartLinearGradient.js.example').default,
17 | },
18 | ];
19 |
20 | export default class BarChartExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/BarChart/examples/BarChart.js.example:
--------------------------------------------------------------------------------
1 | const BarChartExample = (props) => {
2 | const count = 30;
3 | const startDate = new Date(1992, 0, 1);
4 |
5 | const numbers = _.range(count);
6 | const letters = _.times(count, n => String.fromCharCode(97 + n));
7 | const dates = _.times(count, n => new Date(+(startDate) + (n * 1000 * 60 * 60 * 24 * 100)));
8 |
9 | const getNumberValue = (d) => 1.97 + Math.cos(d / 10);
10 | const getDateValue = (d) => getNumberValue(d.getFullYear() + (d.getMonth() / 12));
11 | const getLetterValue = (d) => getNumberValue(d.charCodeAt(0));
12 |
13 | const chartDefs = _.zip([numbers, letters, dates], [getNumberValue, getLetterValue, getDateValue]);
14 |
15 | return
16 | {([true, false]).map((horizontal, index) => {
17 | return
18 |
{horizontal ? "Horizontal" : "Vertical"}
19 |
20 | {chartDefs.map(([data, getValue], index2) => {
21 | return
22 |
23 | d}
27 | y={horizontal ? d => d : getValue}
28 | />
29 | ;
30 | })}
31 | ;
32 | })}
33 |
34 | };
35 |
36 | ReactDOM.render( , mountNode);
37 |
--------------------------------------------------------------------------------
/docs/src/docs/BarChart/examples/BarChartLinearGradient.js.example:
--------------------------------------------------------------------------------
1 | const BarChartWithDefs = (props) => {
2 | const data = [
3 | {x: 0, y: 80},
4 | {x: 5, y: 60},
5 | {x: 10, y: 90},
6 | {x: 15, y: 30},
7 | ];
8 | return
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | d.x}
25 | y={d => d.y}
26 | barThickness={40}
27 | />
28 |
29 |
30 | };
31 |
32 | ReactDOM.render( , mountNode);
33 |
--------------------------------------------------------------------------------
/docs/src/docs/ColorHeatmap/ColorHeatmapDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic ColorHeatmap',
11 | codeText: require('./examples/ColorHeatmap.js.example').default,
12 | },
13 | {
14 | id: 'categorical',
15 | label: 'Categorical ColorHeatmap',
16 | codeText: require('./examples/CategoricalColorHeatmap.js.example').default,
17 | },
18 | ];
19 |
20 | export default class ColorHeatmapExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/ColorHeatmap/examples/CategoricalColorHeatmap.js.example:
--------------------------------------------------------------------------------
1 | const CategoricalColorHeatmapExample = (props) => {
2 | // sorry, kinda hacky currently!
3 | // working on a better solution... -d
4 | const playTypes = ['www', 'open', 'play', 'other'];
5 | const platforms = ['desktop', 'mobile', 'webplayer', 'other'];
6 |
7 | const gridData = playTypes.map(function(n, i) {
8 | return platforms.map(function(m, j) {
9 | return {
10 | x: i,
11 | xEnd: i + 1,
12 | y: j,
13 | yEnd: j+1,
14 | value: Math.sin(i * j * 0.1)
15 | };
16 | })
17 | });
18 | const data = _.flatten(gridData);
19 |
20 | return
21 |
22 | d.value}
25 | x={d => d.x}
26 | xEnd={d => d.xEnd}
27 | y={d => d.y}
28 | yEnd={d => d.yEnd}
29 | colors={['rebeccapurple', 'goldenrod']}
30 | interpolator={'lab'}
31 | />
32 | i + 0.5)}
35 | labelFormat={d => playTypes[Math.round(d - 0.5)]}
36 | />
37 | i + 0.5)}
40 | labelFormat={d => platforms[Math.round(d - 0.5)]}
41 | />
42 |
43 |
44 |
45 |
46 | };
47 |
48 | ReactDOM.render( , mountNode);
49 |
--------------------------------------------------------------------------------
/docs/src/docs/ColorHeatmap/examples/ColorHeatmap.js.example:
--------------------------------------------------------------------------------
1 | const ColorHeatMapExample = (props) => {
2 | const gridData = _.range(30).map(m => {
3 | return _.range(30).map(n => {
4 | return {
5 | x: n,
6 | xEnd: n + 1,
7 | y: m,
8 | yEnd: m + 1,
9 | value: Math.sin(m * n * 0.01)
10 | };
11 | });
12 | });
13 |
14 | const data = _.flatten(gridData);
15 |
16 | return
17 |
18 | d.value}
21 | x={d => d.x}
22 | xEnd={d => d.xEnd}
23 | y={d => d.y}
24 | yEnd={d => d.yEnd}
25 | colors={['rebeccapurple', 'goldenrod']}
26 | interpolator={'lab'}
27 | />
28 |
29 |
30 |
31 |
32 |
33 | d.value}
36 | x={d => d.x}
37 | xEnd={d => d.xEnd}
38 | y={d => d.y}
39 | yEnd={d => d.yEnd}
40 | valueDomain={[-1, 0, 1]}
41 | colors={['Crimson', '#eee', 'ForestGreen']}
42 | interpolator={'lab'}
43 | />
44 |
45 |
46 |
47 |
;
48 | };
49 |
50 | ReactDOM.render( , mountNode);
51 |
--------------------------------------------------------------------------------
/docs/src/docs/FunnelChart/FunnelChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic FunnelChart',
11 | codeText: require('./examples/FunnelChart.js.example').default,
12 | },
13 | ];
14 |
15 | export default class FunnelChartExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/FunnelChart/examples/FunnelChart.js.example:
--------------------------------------------------------------------------------
1 | const FunnelChartExample = (props) => {
2 | const funnelData = [
3 | {observation: 1, value: 100},
4 | {observation: 2, value: 85},
5 | {observation: 3, value: 42},
6 | {observation: 4, value: 37},
7 | {observation: 5, value: 12}
8 | ];
9 |
10 | return
11 |
12 |
13 |
14 | d.observation}
17 | y={d => d.value}
18 | />
19 |
20 |
21 |
22 |
23 |
24 | d.value}
28 | y={d => d.observation}
29 | />
30 |
31 |
32 | };
33 |
34 | ReactDOM.render( , mountNode);
35 |
--------------------------------------------------------------------------------
/docs/src/docs/Histogram/HistogramDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic Histogram',
11 | codeText: require('./examples/Histogram.js.example').default,
12 | },
13 | ];
14 |
15 | export default class HistogramExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/Histogram/examples/Histogram.js.example:
--------------------------------------------------------------------------------
1 | const HistogramExample = (props) => {
2 | const randomNormalArr = _.times(1000, d3.randomNormal(0, 1)).concat(_.times(1000, d3.randomNormal(3, 0.5)));
3 |
4 | return
5 |
6 |
10 |
11 | d}
14 | />
15 |
16 |
17 |
18 |
With nicing applied
19 |
23 |
24 | d}
27 | nice={true}
28 | thresholds={10}
29 | />
30 |
31 |
32 |
33 |
With specified binDomain
34 |
38 |
39 | d}
42 | binDomain={[-6, 6]}
43 | />
44 |
45 |
46 |
;
47 | };
48 |
49 | ReactDOM.render( , mountNode);
50 |
--------------------------------------------------------------------------------
/docs/src/docs/KernelDensityEstimation/KernelDensityEstimationDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic KernelDensityEstimation',
11 | codeText: require('./examples/KernelDensityEstimation.js.example').default,
12 | },
13 | ];
14 |
15 | export default class KernelDensityEstimationExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/KernelDensityEstimation/examples/KernelDensityEstimation.js.example:
--------------------------------------------------------------------------------
1 | const KernelDensityEstimationExample = (props) => {
2 | const randomNormalArr = _.times(1000, d3.randomNormal(0, 1)).concat(_.times(1000, d3.randomNormal(3, 0.5)));
3 |
4 | return
5 |
6 |
7 |
8 | d}
10 | />
11 | d} bandwidth={0.5}
13 | />
14 | d} bandwidth={0.1}
16 | />
17 | d} bandwidth={2}
19 | />
20 |
21 |
22 | {/*
*/}
23 | {/**/}
30 | {/* Math.random()}*/}
34 | {/*pointRadius={1}*/}
35 | {/*/>*/}
36 | {/* */}
37 | {/*
*/}
38 |
;
39 | };
40 |
41 | ReactDOM.render( , mountNode);
42 |
--------------------------------------------------------------------------------
/docs/src/docs/LineChart/LineChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic LineChart',
11 | codeText: require('./examples/LineChart.js.example').default,
12 | },
13 | {
14 | id: 'interactive',
15 | label: 'Interactive LineChart',
16 | codeText: require('./examples/InteractiveLineChart.js.example').default,
17 | },
18 | ];
19 |
20 | export default class LineChartExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/LineChart/examples/InteractiveLineChart.js.example:
--------------------------------------------------------------------------------
1 | const line1 = d => Math.sin(d*.1);
2 | const line2 = d => Math.cos(d*.1);
3 | const line3 = d => Math.sin(d*.2) * 1.5;
4 |
5 | const dPlusOne = d => d + 1;
6 |
7 | const gridData = _.range(30).map(m => {
8 | return _.range(30).map(n => {
9 | return {
10 | x: n,
11 | xEnd: n + 1,
12 | y: m,
13 | yEnd: m + 1,
14 | value: Math.sin(m * n * 0.01)
15 | };
16 | });
17 | });
18 |
19 | const randomNormalArr = _.times(1000, d3.randomNormal(0, 1)).concat(_.times(1000, d3.randomNormal(3, 0.5)));
20 |
21 | class InteractiveLineChartExample extends React.Component {
22 | state = {
23 | activeX: null
24 | };
25 |
26 | _onMouseMove = ({xValue, yValue}) => {
27 | this.setState({activeX: xValue});
28 | };
29 |
30 | render() {
31 | const {activeX} = this.state;
32 | const colors = d3.scaleOrdinal(d3.schemeCategory10);
33 |
34 | return
35 |
36 |
37 |
38 |
39 | {/* */}
45 |
51 |
57 |
63 |
64 |
70 |
71 | {activeX ?
72 | :
73 | null
74 | }
75 |
76 | {/*{activeX ?*/}
77 | {/* [activeX, lineFunc(activeX)])}*/}
79 | {/*getX={0}*/}
80 | {/*getY={1}*/}
81 | {/*pointRadius={5}*/}
82 | {/*/> :*/}
83 | {/*null*/}
84 | {/*}*/}
85 |
86 |
87 | {activeX ?
88 |
{this.state.activeX.toFixed(3)} :
89 | null
90 | }
91 |
92 | }
93 | }
94 |
95 | ReactDOM.render( , mountNode);
96 |
--------------------------------------------------------------------------------
/docs/src/docs/LineChart/examples/LineChart.js.example:
--------------------------------------------------------------------------------
1 | const LineChartExample = (props) => {
2 | return
3 |
4 |
5 |
6 | d}
9 | y={d => Math.sin(d*.1)}
10 | lineStyle={{stroke: '#ff7f0e', strokeWidth: 3}}
11 | />
12 | d}
15 | y={d => Math.cos(d*.1)}
16 | lineStyle={{stroke: '#1f77b4', strokeWidth: 2}}
17 | />
18 | d}
21 | y={d => Math.sin(d*.2) * 1.5}
22 | lineStyle={{stroke: '#2ca02c', strokeWidth: 1}}
23 | />
24 |
25 |
26 | };
27 |
28 | ReactDOM.render( , mountNode);
29 |
--------------------------------------------------------------------------------
/docs/src/docs/LineChart/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "`LineChart` displays a series of points connected by straight line segments.\nEach `LineChart` renders one line.",
3 | "displayName": "LineChart",
4 | "methods": [
5 | {
6 | "name": "getBisectorState",
7 | "docblock": null,
8 | "modifiers": ["static"],
9 | "params": [
10 | {
11 | "name": "props",
12 | "type": null
13 | }
14 | ],
15 | "returns": null
16 | },
17 | {
18 | "name": "getHovered",
19 | "docblock": null,
20 | "modifiers": [],
21 | "params": [
22 | {
23 | "name": "x",
24 | "type": null
25 | }
26 | ],
27 | "returns": null
28 | }
29 | ],
30 | "props": {
31 | "data": {
32 | "type": {
33 | "name": "array"
34 | },
35 | "required": true,
36 | "description": "Array of data objects"
37 | },
38 | "x": {
39 | "type": {
40 | "name": "custom",
41 | "raw": "CustomPropTypes.valueOrAccessor"
42 | },
43 | "required": false,
44 | "description": "Accessor function for line X values, called once per datum, or a single value to be used for the entire line."
45 | },
46 | "y": {
47 | "type": {
48 | "name": "custom",
49 | "raw": "CustomPropTypes.valueOrAccessor"
50 | },
51 | "required": false,
52 | "description": "Accessor function for line Y values, called once per datum, or a single value to be used for the entire line."
53 | },
54 | "lineStyle": {
55 | "type": {
56 | "name": "object"
57 | },
58 | "required": false,
59 | "description": "Inline style object to be applied to the line path.",
60 | "defaultValue": {
61 | "value": "{}",
62 | "computed": false
63 | }
64 | },
65 | "lineClassName": {
66 | "type": {
67 | "name": "string"
68 | },
69 | "required": false,
70 | "description": "Class attribute to be applied to the line path.",
71 | "defaultValue": {
72 | "value": "''",
73 | "computed": false
74 | }
75 | },
76 | "xScale": {
77 | "type": {
78 | "name": "func"
79 | },
80 | "required": false,
81 | "description": "D3 scale for X axis - provided by XYPlot."
82 | },
83 | "yScale": {
84 | "type": {
85 | "name": "func"
86 | },
87 | "required": false,
88 | "description": "D3 scale for Y axis - provided by XYPlot."
89 | },
90 | "curve": {
91 | "type": {
92 | "name": "func"
93 | },
94 | "required": false,
95 | "description": "D3 curve for path generation",
96 | "defaultValue": {
97 | "value": "curveLinear",
98 | "computed": true
99 | }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/docs/src/docs/MarkerLineChart/MarkerLineChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic MarkerLineChart',
11 | codeText: require('./examples/MarkerLineChart.js.example').default,
12 | },
13 | {
14 | id: 'withBar',
15 | label: 'MarkerLineChart with BarChart',
16 | codeText: require('./examples/MarkerLineWithBarChart.js.example').default,
17 | },
18 | ];
19 |
20 | export default class MarkerLineChartExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/MarkerLineChart/examples/MarkerLineChart.js.example:
--------------------------------------------------------------------------------
1 | const MarkerLineChartExample = (props) => {
2 | return
3 |
4 |
5 |
6 |
7 | d}
10 | y={d => Math.sin(d / (Math.PI))}
11 | />
12 |
13 |
14 |
15 |
16 |
17 | d}
21 | y={d => Math.sin(d / (Math.PI))}
22 | />
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Math.sin(d / 10) * 10}
33 | xEnd={d => Math.sin((d + 1) / 10) * 10}
34 | y={d => Math.sin(d / (Math.PI))}
35 | />
36 |
37 |
38 |
39 |
40 |
41 | Math.sin(d / (Math.PI))}
45 | y={d => Math.sin(d / 10) * 10}
46 | yEnd={d => Math.sin((d + 1) / 10) * 10}
47 | />
48 |
49 |
50 |
;
51 | };
52 |
53 | ReactDOM.render( , mountNode);
54 |
--------------------------------------------------------------------------------
/docs/src/docs/MarkerLineChart/examples/MarkerLineWithBarChart.js.example:
--------------------------------------------------------------------------------
1 | const MarkerLineWithBarChartExample = (props) => {
2 | const data1 = [[1, 12], [2, 23], [3, 14], [4, 17], [5, 29], [6, 21]];
3 | const data2 = [[1, 14], [2, 21], [3, 19], [4, 11], [5, 27], [6, 11]];
4 |
5 | return
6 |
7 |
8 |
9 | d[0]}
12 | y={d => d[1]}
13 | />
14 | d[0]}
17 | y={d => d[1]}
18 | lineLength={15}
19 | />
20 |
21 |
;
22 | };
23 |
24 | ReactDOM.render( , mountNode);
25 |
--------------------------------------------------------------------------------
/docs/src/docs/MeasuredValueLabel/MeasuredValueLabelDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic MeasuredValueLabel',
11 | codeText: require('./examples/MeasuredValueLabel.js.example').default,
12 | },
13 | ];
14 |
15 | export default class MeasuredValueLabelExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/MeasuredValueLabel/examples/MeasuredValueLabel.js.example:
--------------------------------------------------------------------------------
1 | const MeasuredValueLabelExample = (props) => {
2 | return insert example here
;
3 | };
4 |
5 | ReactDOM.render( , mountNode);
6 |
--------------------------------------------------------------------------------
/docs/src/docs/MeasuredValueLabel/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "",
3 | "displayName": "MeasuredValueLabel",
4 | "methods": [
5 | {
6 | "name": "getLabel",
7 | "docblock": null,
8 | "modifiers": ["static"],
9 | "params": [
10 | {
11 | "name": "props",
12 | "type": null
13 | }
14 | ],
15 | "returns": null
16 | }
17 | ],
18 | "props": {
19 | "value": {
20 | "type": {
21 | "name": "any"
22 | },
23 | "required": false,
24 | "description": ""
25 | },
26 | "format": {
27 | "type": {
28 | "name": "func"
29 | },
30 | "required": false,
31 | "description": "",
32 | "defaultValue": {
33 | "value": "identity",
34 | "computed": true
35 | }
36 | },
37 | "children": {
38 | "type": {
39 | "name": "any"
40 | },
41 | "required": false,
42 | "description": ""
43 | },
44 | "style": {
45 | "defaultValue": {
46 | "value": "{\n fontFamily: 'Helvetica, sans-serif',\n fontSize: '20px',\n lineHeight: 1,\n textAnchor: 'middle',\n}",
47 | "computed": false
48 | },
49 | "required": false
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/docs/src/docs/PieChart/PieChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic PieChart',
11 | codeText: require('./examples/PieChart.js.example').default,
12 | },
13 | ];
14 |
15 | export default class PieChartExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/PieChart/examples/PieChart.js.example:
--------------------------------------------------------------------------------
1 | class PieChartExample extends React.Component {
2 | state = { sinVal: 0 };
3 |
4 | _animateValue = () => {
5 | const sinVal = Math.min(
6 | Math.abs(
7 | Math.cos(new Date() * 0.001) * Math.sin(new Date() * 0.0011) + 1,
8 | ),
9 | 2,
10 | );
11 | this.setState({ sinVal });
12 | };
13 |
14 | componentDidMount() {
15 | this._interval = setInterval(this._animateValue, 20);
16 | }
17 | componentWillUnmount() {
18 | clearInterval(this._interval);
19 | }
20 |
21 | getPieSliceFill = datum => {
22 | const color = d3.interpolateSinebow(datum / 100);
23 | return {
24 | fill: color,
25 | };
26 | };
27 |
28 | render() {
29 | const slice = d => d;
30 | return (
31 |
32 |
37 |
45 |
53 |
61 |
`${val}%`}
65 | pieSliceLabelDistance={20}
66 | holeRadius={75}
67 | radius={100}
68 | marginTop={50}
69 | marginBottom={50}
70 | marginLeft={50}
71 | marginRight={50}
72 | />
73 |
74 | );
75 | }
76 | }
77 |
78 | ReactDOM.render( , mountNode);
79 |
--------------------------------------------------------------------------------
/docs/src/docs/RangeBarChart/RangeBarChartDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic RangeBarChart',
11 | codeText: require('./examples/RangeBarChart.js.example').default,
12 | },
13 | ];
14 |
15 | export default class RangeBarChartExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/RangeRect/RangeRectDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic RangeRect',
11 | codeText: require('./examples/RangeRect.js.example').default,
12 | },
13 | ];
14 |
15 | export default class RangeRectExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/RangeRect/examples/RangeRect.js.example:
--------------------------------------------------------------------------------
1 | const RangeRectExample = (props) => {
2 | return
3 |
7 |
8 |
13 |
18 |
19 |
;
20 | };
21 |
22 | ReactDOM.render( , mountNode);
23 |
--------------------------------------------------------------------------------
/docs/src/docs/SankeyDiagram/SankeyDiagramDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic SankeyDiagram',
11 | codeText: require('./examples/SankeyDiagram.js.example').default,
12 | },
13 | {
14 | id: 'interactive',
15 | label: 'Interactive Sankey Diagram',
16 | codeText: require('./examples/SankeyInteractive.js.example').default,
17 | },
18 | ];
19 |
20 | export default class SankeyDiagramExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/ScatterPlot/ScatterPlotDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic ScatterPlot',
11 | codeText: require('./examples/ScatterPlot.js.example').default,
12 | },
13 | ];
14 |
15 | export default class ScatterPlotExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/ScatterPlot/examples/ScatterPlot.js.example:
--------------------------------------------------------------------------------
1 | const randomScatter = [
2 | _.zip(randomWalk(20, 100), randomWalk(20, 100)),
3 | _.zip(randomWalk(3000, 10000), randomWalk(3000, 10000)),
4 | _.zip(randomWalk(50, 100), randomWalk(50, 100)),
5 | _.zip(randomWalk(100, 100), randomWalk(100, 100)),
6 | _.zip(randomWalk(200, 100), randomWalk(200, 100))
7 | ];
8 |
9 | const emojis = ["😀", "😁", "😂", "😅", "😆", "😇", "😈", "👿", "😉", "😊", "😐", "😑", "😒", "😓", "😔", "😕", "😖", "😗", "😘", "😙", "😚", "😛", "😜", "😝", "👻", "👹", "👺", "💩", "💀", "👽", "👾", "🙇", "💁", "🙅", "🙆", "🙋", "🙎", "🙍", "💆", "💇"];
10 |
11 | const ScatterPlotExample = () => {
12 | const rectangleSymbol = ;
13 | const triangleSymbol = ;
14 | const randomEmoji = (d, i) => _.sample(emojis);
15 |
16 | return
17 |
18 |
19 |
20 |
21 | d[0]}
24 | y={d => d[1]}
25 | pointSymbol={rectangleSymbol}
26 | />
27 | d[0]}
30 | y={d => d[1]}
31 | pointSymbol={randomEmoji}
32 | pointOffset={[0, 2]}
33 | />
34 |
35 | d[0]}
38 | y={d => d[1]}
39 | pointSymbol={(d, i) => i}
40 | />
41 | d[0]}
44 | y={d => d[1]}
45 | pointSymbol={triangleSymbol}
46 | pointOffset={[-4, -3]}
47 | />
48 |
49 |
50 | };
51 |
52 | ReactDOM.render( , mountNode);
53 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMap/TreeMapDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic TreeMap',
11 | codeText: require('./examples/TreeMap.js.example').default,
12 | },
13 | {
14 | id: 'animated',
15 | label: 'Animated TreeMap',
16 | codeText: require('./examples/AnimatedTreeMap.js.example').default,
17 | },
18 | ];
19 |
20 | export default class TreeMapExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMap/examples/AnimatedTreeMap.js.example:
--------------------------------------------------------------------------------
1 | class AnimatedTreeMapExample extends React.Component {
2 | constructor(props) {
3 | super(props);
4 |
5 | const data = {
6 | children: _.range(1, 5).map(n => ({
7 | children: _.times(n * n, m => ({
8 | size: (n +1) * (m + 1) + (100 * Math.random()),
9 | size2: (n +1) * (m + 1) + (100 * Math.random())
10 | }))
11 | }))
12 | };
13 |
14 | this.state = { getValue: "size", data };
15 | }
16 |
17 | _animateValue = () => {
18 | if(this.state.getValue === "size")
19 | this.setState({getValue: "size2"});
20 | else
21 | this.setState({getValue: "size"});
22 | };
23 |
24 | componentDidMount() {
25 | this._interval = setInterval(this._animateValue, 1000);
26 | }
27 |
28 | componentWillUnmount() {
29 | clearInterval(this._interval);
30 | }
31 |
32 | render() {
33 | const {getValue, data} = this.state;
34 |
35 | const colorScale = d3.scaleLinear()
36 | .domain([0, 65])
37 | .range(['#6b6ecf', '#8ca252'])
38 | .interpolate(d3.interpolateHcl);
39 |
40 | return
41 | ({
46 | backgroundColor: colorScale(parseInt(node.data.size)),
47 | border: '1px solid #333'
48 | })}
49 | sticky
50 | width={400}
51 | height={500}
52 | />
53 |
54 | }
55 | }
56 |
57 | ReactDOM.render( , mountNode);
58 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMap/examples/TreeMap.js.example:
--------------------------------------------------------------------------------
1 | const TreeMapExample = props => {
2 | const data = {
3 | children: _.range(1, 5).map(n => ({
4 | children: _.times(n * n, m => ({
5 | size: n * (m + 1)
6 | }))
7 | }))
8 | };
9 |
10 | const colorScale = d3
11 | .scaleLinear()
12 | .domain([0, 65])
13 | .range(["#6b6ecf", "#8ca252"])
14 | .interpolate(d3.interpolateHcl);
15 |
16 | return (
17 |
18 | d.size}
21 | getLabel={d => d.value}
22 | nodeStyle={node => ({
23 | backgroundColor: colorScale(parseInt(node.data.size)),
24 | border: "1px solid #333"
25 | })}
26 | width={400}
27 | height={500}
28 | />
29 |
30 | );
31 | };
32 |
33 | ReactDOM.render( , mountNode);
34 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMapNode/TreeMapNodeDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic TreeMapNode',
11 | codeText: require('./examples/TreeMapNode.js.example').default,
12 | },
13 | ];
14 |
15 | export default class TreeMapNodeExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMapNode/examples/TreeMapNode.js.example:
--------------------------------------------------------------------------------
1 | const TreeMapNodeExample = (props) => {
2 | return insert example here
;
3 | };
4 |
5 | ReactDOM.render( , mountNode);
6 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMapNode/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "",
3 | "methods": [],
4 | "props": {
5 | "node": {
6 | "type": {
7 | "name": "shape",
8 | "value": {
9 | "parent": {
10 | "name": "object",
11 | "required": false
12 | },
13 | "children": {
14 | "name": "array",
15 | "required": false
16 | },
17 | "value": {
18 | "name": "number",
19 | "required": false
20 | },
21 | "depth": {
22 | "name": "number",
23 | "required": false
24 | },
25 | "x": {
26 | "name": "number",
27 | "required": false
28 | },
29 | "y": {
30 | "name": "number",
31 | "required": false
32 | },
33 | "dx": {
34 | "name": "number",
35 | "required": false
36 | },
37 | "dy": {
38 | "name": "number",
39 | "required": false
40 | }
41 | }
42 | },
43 | "required": false,
44 | "description": ""
45 | },
46 | "nodeStyle": {
47 | "type": {
48 | "name": "union",
49 | "value": [
50 | {
51 | "name": "func"
52 | },
53 | {
54 | "name": "object"
55 | }
56 | ]
57 | },
58 | "required": false,
59 | "description": ""
60 | },
61 | "minLabelWidth": {
62 | "type": {
63 | "name": "number"
64 | },
65 | "required": false,
66 | "description": "",
67 | "defaultValue": {
68 | "value": "0",
69 | "computed": false
70 | }
71 | },
72 | "minLabelHeight": {
73 | "type": {
74 | "name": "number"
75 | },
76 | "required": false,
77 | "description": "",
78 | "defaultValue": {
79 | "value": "0",
80 | "computed": false
81 | }
82 | },
83 | "getLabel": {
84 | "type": {
85 | "name": "custom",
86 | "raw": "CustomPropTypes.getter"
87 | },
88 | "required": false,
89 | "description": ""
90 | },
91 | "labelStyle": {
92 | "type": {
93 | "name": "union",
94 | "value": [
95 | {
96 | "name": "func"
97 | },
98 | {
99 | "name": "object"
100 | }
101 | ]
102 | },
103 | "required": false,
104 | "description": ""
105 | },
106 | "NodeLabelComponent": {
107 | "type": {
108 | "name": "func"
109 | },
110 | "required": false,
111 | "description": ""
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/docs/src/docs/TreeMapNodeLabel/TreeMapNodeLabelDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic TreeMapNodeLabel',
11 | codeText: require('./examples/TreeMapNodeLabel.js.example').default,
12 | },
13 | ];
14 |
15 | export default class TreeMapNodeLabelExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMapNodeLabel/examples/TreeMapNodeLabel.js.example:
--------------------------------------------------------------------------------
1 | const TreeMapNodeLabelExample = (props) => {
2 | return insert example here
;
3 | };
4 |
5 | ReactDOM.render( , mountNode);
6 |
--------------------------------------------------------------------------------
/docs/src/docs/TreeMapNodeLabel/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "",
3 | "methods": [],
4 | "props": {
5 | "node": {
6 | "type": {
7 | "name": "object"
8 | },
9 | "required": false,
10 | "description": ""
11 | },
12 | "getLabel": {
13 | "type": {
14 | "name": "custom",
15 | "raw": "CustomPropTypes.getter"
16 | },
17 | "required": false,
18 | "description": ""
19 | },
20 | "labelStyle": {
21 | "type": {
22 | "name": "union",
23 | "value": [
24 | {
25 | "name": "func"
26 | },
27 | {
28 | "name": "object"
29 | }
30 | ]
31 | },
32 | "required": false,
33 | "description": ""
34 | },
35 | "minLabelWidth": {
36 | "type": {
37 | "name": "number"
38 | },
39 | "required": false,
40 | "description": ""
41 | },
42 | "minLabelHeight": {
43 | "type": {
44 | "name": "number"
45 | },
46 | "required": false,
47 | "description": ""
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/docs/src/docs/XAxis/XAxisDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XAxis',
11 | codeText: require('./examples/XAxis.js.example').default,
12 | },
13 | {
14 | id: 'customTicks',
15 | label: 'XAxis with custom ticks',
16 | codeText: require('./examples/XAxisCustomTicks.js.example').default,
17 | },
18 | ];
19 |
20 | export default class XAxisExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxis/examples/XAxis.js.example:
--------------------------------------------------------------------------------
1 | const XAxisExample = (props) => {
2 | const dateDomain = [new Date(2008, 0, 1), new Date(2017, 0, 1)];
3 | const numberDomain = [-20, 20];
4 | const categoricalDomain = ['puppies', 'kitties', 'ponies'];
5 | const smallSize = {width: 300, height: 100};
6 |
7 | return
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | };
25 |
26 | ReactDOM.render( , mountNode);
27 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxis/examples/XAxisCustomTicks.js.example:
--------------------------------------------------------------------------------
1 | const XAxisExample = (props) => {
2 | const size = {width: 350, height: 100};
3 |
4 | return
5 |
6 |
7 |
8 |
9 | };
10 |
11 | ReactDOM.render( , mountNode);
12 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxisLabels/XAxisLabelsDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XAxisLabels',
11 | codeText: require('./examples/XAxisLabels.js.example').default,
12 | },
13 | ];
14 |
15 | export default class XAxisLabelsExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxisLabels/examples/XAxisLabels.js.example:
--------------------------------------------------------------------------------
1 | const XAxisLabelsExample = (props) => {
2 | const chartStyle = {marginBottom: '10px'};
3 |
4 | return
5 |
6 |
10 |
13 | label + "%"}
15 | position="top"
16 | distance={2}
17 | tickCount={5}
18 | labelStyle={(label) => {
19 | return {
20 | fontSize: '10px',
21 | fill: label.text === "20%" ? "red" : "black"
22 | };
23 | }
24 | } />
25 |
26 |
27 |
28 | };
29 |
30 | ReactDOM.render( , mountNode);
31 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxisTitle/XAxisTitleDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XAxisTitle',
11 | codeText: require('./examples/XAxisTitle.js.example').default,
12 | },
13 | {
14 | id: 'all',
15 | label: 'All XAxisTitle Options',
16 | codeText: require('./examples/XAxisTitleAll.js.example').default,
17 | },
18 | ];
19 |
20 | export default class XAxisTitleExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxisTitle/examples/XAxisTitle.js.example:
--------------------------------------------------------------------------------
1 | const XAxisTitleExample = (props) => {
2 | const xyProps = {
3 | width: 500, height: 200,
4 | xDomain: [0, 100], yDomain: [0, 100]
5 | };
6 |
7 | return
8 |
9 | ;
10 | };
11 |
12 | ReactDOM.render( , mountNode);
13 |
--------------------------------------------------------------------------------
/docs/src/docs/XAxisTitle/examples/XAxisTitleAll.js.example:
--------------------------------------------------------------------------------
1 | const XAxisTitleExample = (props) => {
2 | const xyProps = {
3 | width: 500, height: 360,
4 | xDomain: [0, 100], yDomain: [0, 100]
5 | };
6 |
7 | return
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | ;
43 | };
44 |
45 | ReactDOM.render( , mountNode);
46 |
--------------------------------------------------------------------------------
/docs/src/docs/XGrid/XGridDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XGrid',
11 | codeText: require('./examples/XGrid.js.example').default,
12 | },
13 | ];
14 |
15 | export default class XGridExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/XGrid/examples/XGrid.js.example:
--------------------------------------------------------------------------------
1 | const XGridExample = (props) => {
2 | const size = {width: 400, height: 300};
3 |
4 | return
5 |
6 |
7 |
8 |
9 |
10 | };
11 |
12 | ReactDOM.render( , mountNode);
13 |
--------------------------------------------------------------------------------
/docs/src/docs/XGrid/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "",
3 | "displayName": "XGrid",
4 | "methods": [
5 | {
6 | "name": "getTickDomain",
7 | "docblock": null,
8 | "modifiers": ["static"],
9 | "params": [
10 | {
11 | "name": "props",
12 | "type": null
13 | }
14 | ],
15 | "returns": null
16 | }
17 | ],
18 | "props": {
19 | "width": {
20 | "type": {
21 | "name": "number"
22 | },
23 | "required": false,
24 | "description": ""
25 | },
26 | "height": {
27 | "type": {
28 | "name": "number"
29 | },
30 | "required": false,
31 | "description": ""
32 | },
33 | "xScale": {
34 | "type": {
35 | "name": "func"
36 | },
37 | "required": false,
38 | "description": ""
39 | },
40 | "spacingTop": {
41 | "type": {
42 | "name": "number"
43 | },
44 | "required": false,
45 | "description": ""
46 | },
47 | "spacingBottom": {
48 | "type": {
49 | "name": "number"
50 | },
51 | "required": false,
52 | "description": ""
53 | },
54 | "spacingLeft": {
55 | "type": {
56 | "name": "number"
57 | },
58 | "required": false,
59 | "description": ""
60 | },
61 | "spacingRight": {
62 | "type": {
63 | "name": "number"
64 | },
65 | "required": false,
66 | "description": ""
67 | },
68 | "nice": {
69 | "type": {
70 | "name": "bool"
71 | },
72 | "required": false,
73 | "description": "",
74 | "defaultValue": {
75 | "value": "true",
76 | "computed": false
77 | }
78 | },
79 | "ticks": {
80 | "type": {
81 | "name": "array"
82 | },
83 | "required": false,
84 | "description": ""
85 | },
86 | "tickCount": {
87 | "type": {
88 | "name": "number"
89 | },
90 | "required": false,
91 | "description": ""
92 | },
93 | "lineClassName": {
94 | "type": {
95 | "name": "string"
96 | },
97 | "required": false,
98 | "description": ""
99 | },
100 | "lineStyle": {
101 | "type": {
102 | "name": "object"
103 | },
104 | "required": false,
105 | "description": "",
106 | "defaultValue": {
107 | "value": "{}",
108 | "computed": false
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/docs/src/docs/XLine/XLineDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XLine',
11 | codeText: require('./examples/XLine.js.example').default,
12 | },
13 | ];
14 |
15 | export default class XLineExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/XLine/examples/XLine.js.example:
--------------------------------------------------------------------------------
1 | const XLineExample = (props) => {
2 | return
3 |
4 |
5 |
6 |
7 |
8 |
9 | };
10 |
11 | ReactDOM.render( , mountNode);
12 |
--------------------------------------------------------------------------------
/docs/src/docs/XLine/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "`XLine` is a vertical line rendered on the x axis",
3 | "displayName": "XLine",
4 | "methods": [],
5 | "props": {
6 | "height": {
7 | "type": {
8 | "name": "number"
9 | },
10 | "required": false,
11 | "description": "Height of chart - provided by XYPlot"
12 | },
13 | "xScale": {
14 | "type": {
15 | "name": "func"
16 | },
17 | "required": false,
18 | "description": "D3 scale for X axis - provided by XYPlot"
19 | },
20 | "value": {
21 | "type": {
22 | "name": "union",
23 | "value": [
24 | {
25 | "name": "number"
26 | },
27 | {
28 | "name": "string"
29 | },
30 | {
31 | "name": "instanceOf",
32 | "value": "Date"
33 | }
34 | ]
35 | },
36 | "required": true,
37 | "description": ""
38 | },
39 | "yScale": {
40 | "type": {
41 | "name": "func"
42 | },
43 | "required": false,
44 | "description": "D3 scale for Y axis - provided by XYPlot"
45 | },
46 | "yLimit": {
47 | "type": {
48 | "name": "union",
49 | "value": [
50 | {
51 | "name": "number"
52 | },
53 | {
54 | "name": "string"
55 | },
56 | {
57 | "name": "instanceOf",
58 | "value": "Date"
59 | }
60 | ]
61 | },
62 | "required": false,
63 | "description": ""
64 | },
65 | "yDomain": {
66 | "type": {
67 | "name": "array"
68 | },
69 | "required": false,
70 | "description": "The Y domain of the data as an array - provided by XYPlot"
71 | },
72 | "spacingTop": {
73 | "type": {
74 | "name": "number"
75 | },
76 | "required": false,
77 | "description": "Spacing top - provided by XYPlot",
78 | "defaultValue": {
79 | "value": "0",
80 | "computed": false
81 | }
82 | },
83 | "spacingBottom": {
84 | "type": {
85 | "name": "number"
86 | },
87 | "required": false,
88 | "description": "Spacing bottom - provided by XYPlot",
89 | "defaultValue": {
90 | "value": "0",
91 | "computed": false
92 | }
93 | },
94 | "style": {
95 | "type": {
96 | "name": "object"
97 | },
98 | "required": false,
99 | "description": "Inline style object to be applied to the line",
100 | "defaultValue": {
101 | "value": "{}",
102 | "computed": false
103 | }
104 | },
105 | "className": {
106 | "type": {
107 | "name": "string"
108 | },
109 | "required": false,
110 | "description": "Class attribute to be applied to the line",
111 | "defaultValue": {
112 | "value": "''",
113 | "computed": false
114 | }
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/docs/src/docs/XTicks/XTicksDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XTicks',
11 | codeText: require('./examples/XTicks.js.example').default,
12 | },
13 | ];
14 |
15 | export default class XTicksExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/XTicks/examples/XTicks.js.example:
--------------------------------------------------------------------------------
1 | const XTicksExample = (props) => {
2 | const size = {width: 300, height: 100};
3 | const chartStyle = {marginBottom: '10px'};
4 |
5 | return
6 |
7 | Default:
8 |
9 |
10 |
11 |
12 |
13 | Multiple sets of ticks, with options:
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | };
22 |
23 |
24 | ReactDOM.render( , mountNode);
25 |
--------------------------------------------------------------------------------
/docs/src/docs/XYPlot/XYPlotDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic XYPlot',
11 | codeText: require('./examples/XYPlot.js.example').default,
12 | },
13 | {
14 | id: 'spacing',
15 | label: 'Custom Spacing',
16 | codeText: require('./examples/CustomSpacing.js.example').default,
17 | },
18 | ];
19 |
20 | export default class XYPlotExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/XYPlot/examples/CustomSpacing.js.example:
--------------------------------------------------------------------------------
1 | const SpacingExample = (props) => {
2 | const spacing = {spacingLeft: 10, spacingTop: 53, spacingRight: 16, spacingBottom: 9};
3 |
4 | return
5 |
6 |
7 |
8 | d}
11 | y={d => Math.sin(d*.1)}
12 | />
13 |
14 |
15 | };
16 |
17 | ReactDOM.render( , mountNode);
18 |
--------------------------------------------------------------------------------
/docs/src/docs/XYPlot/examples/XYPlot.js.example:
--------------------------------------------------------------------------------
1 | const MultipleXYExample = (props) => {
2 | return
3 |
4 |
5 |
6 |
7 | d}
10 | y={d => (Math.sin(d*3) * .7) + 1.2}
11 | yEnd={d => (Math.sin(d*3) * Math.cos(d*3) * .7) + 1.2}
12 | barThickness={2}
13 | barStyle={{fill: '#3690c0'}}
14 | />
15 |
16 | d}
19 | y={d => Math.pow(Math.abs(Math.sin(d*5)), Math.abs(Math.sin(d*.25))) * 1.8}
20 | lineStyle={{stroke: '#02818a', strokeWidth: 3}}
21 | />
22 |
23 | d}
26 | y={d => Math.pow(2, (d + 2) * 1.8) * 0.1}
27 | pointSymbol={ }
28 | />
29 |
30 | d}
33 | y={d => -Math.abs(Math.sin(d*4) * Math.cos(d*3))}
34 | barThickness={3}
35 | barStyle={{fill: '#67a9cf'}}
36 | />
37 |
38 | d}
41 | y={d => Math.cos(d)}
42 | lineStyle={{stroke: '#ec7014', strokeWidth: 3}}
43 | />
44 |
45 | _.range(-2, 0, .1).map(j => [i, j])))}
47 | value={([i, j]) => Math.sin(i * j * 5)}
48 | x={([i, j]) => i}
49 | xEnd={([i, j]) => i + .1}
50 | y={([i, j]) => j}
51 | yEnd={([i, j]) => j + .1}
52 | colors={['#d0d1e6', '#016450']}
53 | interpolator={'lab'}
54 | />
55 |
56 | _.range(-2, -1, .1).map(j => [i, j])))}
58 | area={([i, j]) => -Math.sin(i * j * 5)}
59 | x={([i, j]) => i}
60 | xEnd={([i, j]) => i + .1}
61 | y={([i, j]) => j}
62 | yEnd={([i, j]) => j + .1}
63 | rectStyle={{fill: '#016450'}}
64 | />
65 |
66 |
;
67 | };
68 |
69 | ReactDOM.render( , mountNode);
70 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxis/YAxisDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic YAxis',
11 | codeText: require('./examples/YAxis.js.example').default,
12 | },
13 | {
14 | id: 'customTicks',
15 | label: 'YAxis with custom ticks',
16 | codeText: require('./examples/YAxisCustomTicks.js.example').default,
17 | },
18 | ];
19 |
20 | export default class YAxisExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxis/examples/YAxis.js.example:
--------------------------------------------------------------------------------
1 | const YAxisExample = (props) => {
2 | const dateDomain = [new Date(2008, 0, 1), new Date(2017, 0, 1)];
3 | const numberDomain = [-20, 20];
4 | const categoricalDomain = ['puppies', 'kitties', 'ponies'];
5 | const size = {width: 100, height: 300};
6 | const chartStyle = {display: 'inline-block', marginRight: '10px'};
7 |
8 | return
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | };
26 |
27 |
28 | ReactDOM.render( , mountNode);
29 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxis/examples/YAxisCustomTicks.js.example:
--------------------------------------------------------------------------------
1 | const YAxisCustomTicksExample = (props) => {
2 | const size = {width: 150, height: 300};
3 |
4 | return
5 |
6 |
7 |
8 |
9 | };
10 |
11 | ReactDOM.render( , mountNode);
12 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxisLabels/YAxisLabelsDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic YAxisLabels',
11 | codeText: require('./examples/YAxisLabels.js.example').default,
12 | },
13 | ];
14 |
15 | export default class YAxisLabelsExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxisLabels/examples/YAxisLabels.js.example:
--------------------------------------------------------------------------------
1 | const YAxisLabelsExample = (props) => {
2 | const chartStyle = {marginBottom: '10px'};
3 |
4 | return
5 |
6 |
10 |
13 | label + "%"}
15 | position="right"
16 | tickCount={5}
17 | labelStyle={(label) => {
18 | const is20 = Math.abs(label.value) === 20;
19 | return {
20 | fill: is20 ? "green" : "black",
21 | fontWeight: is20 ? 900 : 400
22 | };
23 | }}
24 | />
25 |
26 |
27 |
28 | };
29 |
30 | ReactDOM.render( , mountNode);
31 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxisTitle/YAxisTitleDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic YAxisTitle',
11 | codeText: require('./examples/YAxisTitle.js.example').default,
12 | },
13 | {
14 | id: 'all',
15 | label: 'YAxisTitle Positions and Placements',
16 | codeText: require('./examples/YAxisTitleAll.js.example').default,
17 | },
18 | ];
19 |
20 | export default class YAxisTitleExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxisTitle/examples/YAxisTitle.js.example:
--------------------------------------------------------------------------------
1 | const YAxisTitleExample = (props) => {
2 | const xyProps = {
3 | width: 400, height: 300,
4 | xDomain: [0, 100], yDomain: [0, 100]
5 | };
6 |
7 | return
8 |
9 | ;
10 | };
11 |
12 | ReactDOM.render( , mountNode);
13 |
--------------------------------------------------------------------------------
/docs/src/docs/YAxisTitle/examples/YAxisTitleAll.js.example:
--------------------------------------------------------------------------------
1 | const YAxisTitleExample = (props) => {
2 | const xyProps = {
3 | width: 500, height: 360,
4 | xDomain: [0, 100], yDomain: [0, 100]
5 | };
6 |
7 | return
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | ;
43 | };
44 |
45 | ReactDOM.render( , mountNode);
46 |
--------------------------------------------------------------------------------
/docs/src/docs/YGrid/YGridDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic YGrid',
11 | codeText: require('./examples/YGrid.js.example').default,
12 | },
13 | ];
14 |
15 | export default class YGridExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/YGrid/examples/YGrid.js.example:
--------------------------------------------------------------------------------
1 | const YGridExample = (props) => {
2 | const size = {width: 400, height: 300};
3 |
4 | return
5 |
6 |
7 |
8 |
9 |
10 | };
11 |
12 | ReactDOM.render( , mountNode);
13 |
--------------------------------------------------------------------------------
/docs/src/docs/YGrid/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "",
3 | "displayName": "YGrid",
4 | "methods": [
5 | {
6 | "name": "getTickDomain",
7 | "docblock": null,
8 | "modifiers": ["static"],
9 | "params": [
10 | {
11 | "name": "props",
12 | "type": null
13 | }
14 | ],
15 | "returns": null
16 | }
17 | ],
18 | "props": {
19 | "width": {
20 | "type": {
21 | "name": "number"
22 | },
23 | "required": false,
24 | "description": ""
25 | },
26 | "height": {
27 | "type": {
28 | "name": "number"
29 | },
30 | "required": false,
31 | "description": ""
32 | },
33 | "yScale": {
34 | "type": {
35 | "name": "func"
36 | },
37 | "required": false,
38 | "description": ""
39 | },
40 | "spacingTop": {
41 | "type": {
42 | "name": "number"
43 | },
44 | "required": false,
45 | "description": ""
46 | },
47 | "spacingBottom": {
48 | "type": {
49 | "name": "number"
50 | },
51 | "required": false,
52 | "description": ""
53 | },
54 | "spacingLeft": {
55 | "type": {
56 | "name": "number"
57 | },
58 | "required": false,
59 | "description": ""
60 | },
61 | "spacingRight": {
62 | "type": {
63 | "name": "number"
64 | },
65 | "required": false,
66 | "description": ""
67 | },
68 | "nice": {
69 | "type": {
70 | "name": "bool"
71 | },
72 | "required": false,
73 | "description": "",
74 | "defaultValue": {
75 | "value": "true",
76 | "computed": false
77 | }
78 | },
79 | "ticks": {
80 | "type": {
81 | "name": "array"
82 | },
83 | "required": false,
84 | "description": ""
85 | },
86 | "tickCount": {
87 | "type": {
88 | "name": "number"
89 | },
90 | "required": false,
91 | "description": ""
92 | },
93 | "lineClassName": {
94 | "type": {
95 | "name": "string"
96 | },
97 | "required": false,
98 | "description": ""
99 | },
100 | "lineStyle": {
101 | "type": {
102 | "name": "object"
103 | },
104 | "required": false,
105 | "description": "",
106 | "defaultValue": {
107 | "value": "{}",
108 | "computed": false
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/docs/src/docs/YLine/YLineDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic YLine',
11 | codeText: require('./examples/YLine.js.example').default,
12 | },
13 | ];
14 |
15 | export default class YLineExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/YLine/examples/YLine.js.example:
--------------------------------------------------------------------------------
1 | const YLineExample = (props) => {
2 | return
3 |
4 |
5 |
6 |
7 |
8 |
9 | };
10 |
11 | ReactDOM.render( , mountNode);
12 |
--------------------------------------------------------------------------------
/docs/src/docs/YLine/propDocs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "`YLine` is a horizontal line rendered on the y axis",
3 | "displayName": "YLine",
4 | "methods": [],
5 | "props": {
6 | "yScale": {
7 | "type": {
8 | "name": "func"
9 | },
10 | "required": false,
11 | "description": "D3 scale for Y axis - provided by XYPlot"
12 | },
13 | "width": {
14 | "type": {
15 | "name": "number"
16 | },
17 | "required": false,
18 | "description": "Width of chart - provided by XYPlot."
19 | },
20 | "value": {
21 | "type": {
22 | "name": "union",
23 | "value": [
24 | {
25 | "name": "number"
26 | },
27 | {
28 | "name": "string"
29 | },
30 | {
31 | "name": "instanceOf",
32 | "value": "Date"
33 | }
34 | ]
35 | },
36 | "required": true,
37 | "description": ""
38 | },
39 | "xScale": {
40 | "type": {
41 | "name": "func"
42 | },
43 | "required": false,
44 | "description": "D3 scale for X axis - provided by XYPlot"
45 | },
46 | "xLimit": {
47 | "type": {
48 | "name": "union",
49 | "value": [
50 | {
51 | "name": "number"
52 | },
53 | {
54 | "name": "string"
55 | },
56 | {
57 | "name": "instanceOf",
58 | "value": "Date"
59 | }
60 | ]
61 | },
62 | "required": false,
63 | "description": ""
64 | },
65 | "spacingLeft": {
66 | "type": {
67 | "name": "number"
68 | },
69 | "required": false,
70 | "description": "Spacing left - provided by XYPlot",
71 | "defaultValue": {
72 | "value": "0",
73 | "computed": false
74 | }
75 | },
76 | "spacingRight": {
77 | "type": {
78 | "name": "number"
79 | },
80 | "required": false,
81 | "description": "Spacing right - provided by XYPlot",
82 | "defaultValue": {
83 | "value": "0",
84 | "computed": false
85 | }
86 | },
87 | "style": {
88 | "type": {
89 | "name": "object"
90 | },
91 | "required": false,
92 | "description": "Inline style object to be applied to the line",
93 | "defaultValue": {
94 | "value": "{}",
95 | "computed": false
96 | }
97 | },
98 | "className": {
99 | "type": {
100 | "name": "string"
101 | },
102 | "required": false,
103 | "description": "Class attribute to be applied to the line",
104 | "defaultValue": {
105 | "value": "''",
106 | "computed": false
107 | }
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/docs/src/docs/YTicks/YTicksDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic YTicks',
11 | codeText: require('./examples/YTicks.js.example').default,
12 | },
13 | ];
14 |
15 | export default class YTicksExamples extends React.Component {
16 | render() {
17 | return (
18 |
19 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
20 |
21 | {examples.map(example => {
22 | return ;
23 | })}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/docs/YTicks/examples/YTicks.js.example:
--------------------------------------------------------------------------------
1 | const YTicksExample = (props) => {
2 | const size = {width: 100, height: 300};
3 | const chartStyle = {display: 'inline-block', marginRight: '10px'};
4 |
5 | return
6 |
7 | Left: default params
8 | Right: Multiple sets of ticks, with options
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | };
24 |
25 |
26 | ReactDOM.render( , mountNode);
27 |
--------------------------------------------------------------------------------
/docs/src/docs/ZoomContainer/ZoomContainerDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ComponentDocs from '../../ComponentDocs';
3 | import ExampleSection from '../../ExampleSection';
4 | // autogenerated docs data containing descriptions of this component's props
5 | import propDocs from './propDocs.json';
6 |
7 | const examples = [
8 | {
9 | id: 'basic',
10 | label: 'Basic ZoomContainer',
11 | codeText: require('./examples/ZoomContainer.js.example').default,
12 | },
13 | {
14 | id: 'controlled',
15 | label: 'Controlled ZoomContainer',
16 | codeText: require('./examples/ZoomContainerControlled.js.example').default,
17 | },
18 | ];
19 |
20 | export default class ZoomContainerExamples extends React.Component {
21 | render() {
22 | return (
23 |
24 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
25 |
26 | {examples.map(example => {
27 | return ;
28 | })}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/docs/ZoomContainer/examples/ZoomContainer.js.example:
--------------------------------------------------------------------------------
1 | const ZoomContainerExample = (props) => {
2 | return
3 |
4 |
5 |
6 |
7 | d}
10 | y={d => Math.sin(d*.1)}
11 | />
12 |
13 |
14 |
15 | };
16 |
17 | ReactDOM.render( , mountNode);
18 |
--------------------------------------------------------------------------------
/docs/src/docs/ZoomContainer/examples/ZoomContainerControlled.js.example:
--------------------------------------------------------------------------------
1 | const width = 600;
2 | const height = 350;
3 |
4 | function getNewZoomProps(newZoomScale, oldZoomScale, oldZoomX, oldZoomY, width, height) {
5 | // Some math is required here in order to ensure that whatever is in the center of the viewport
6 | // remains in the center of the viewport after zooming in/out.
7 | // It's possible to only update zoomScale (and not zoomX & zoomY), but doing so will zoom relative to the
8 | // top left corner of the chart, rather than viewport center.
9 |
10 | return {
11 | zoomX: width / 2 - newZoomScale / oldZoomScale * (width / 2 - oldZoomX),
12 | zoomY: height / 2 - newZoomScale / oldZoomScale * (height / 2 - oldZoomY),
13 | zoomScale: newZoomScale
14 | };
15 | }
16 |
17 | class ZoomControlledExample extends React.Component {
18 | state = {
19 | zoomTransform: {k: 1, x: 0, y: 0},
20 | zoomX: 0,
21 | zoomY: 0,
22 | zoomScale: 1
23 | };
24 |
25 | handleZoom = nextZoomTransform => {
26 | // callback called when user has zoomed (or panned)
27 | // pass the new zoom transform from callback back down as props
28 | if (!nextZoomTransform) return;
29 | this.setState({
30 | zoomX: nextZoomTransform.x,
31 | zoomY: nextZoomTransform.y,
32 | zoomScale: nextZoomTransform.k
33 | });
34 | };
35 | handleClickZoomIn = () => {
36 | const {zoomScale, zoomX, zoomY} = this.state;
37 | const newZoomScale = this.state.zoomScale * 1.25;
38 | this.setState(getNewZoomProps(newZoomScale, zoomScale, zoomX, zoomY, width, height));
39 | };
40 | handleClickZoomOut = () => {
41 | const {zoomScale, zoomX, zoomY} = this.state;
42 | const newZoomScale = this.state.zoomScale / 1.25;
43 | this.setState(getNewZoomProps(newZoomScale, zoomScale, zoomX, zoomY, width, height));
44 | };
45 |
46 | render() {
47 | return (
48 |
49 |
59 |
60 |
61 |
62 | d} y={d => Math.sin(d * 0.1)} />
63 |
64 |
65 |
66 | [+] Zoom In
67 | [-] Zoom Out
68 |
69 |
70 | );
71 | }
72 | }
73 |
74 | ReactDOM.render( , mountNode);
75 |
--------------------------------------------------------------------------------
/docs/src/docs/index.js:
--------------------------------------------------------------------------------
1 | export { default as AreaBarChartDocs } from './AreaBarChart/AreaBarChartDocs';
2 | export { default as AreaChartDocs } from './AreaChart/AreaChartDocs';
3 | export { default as AreaHeatmapDocs } from './AreaHeatmap/AreaHeatmapDocs';
4 | export {
5 | default as AriaLabelContainerDocs,
6 | } from './AriaLabelContainer/AriaLabelContainerDocs';
7 | export { default as BarDocs } from './Bar/BarDocs';
8 | export { default as BarChartDocs } from './BarChart/BarChartDocs';
9 | export { default as ColorHeatmapDocs } from './ColorHeatmap/ColorHeatmapDocs';
10 | export { default as FunnelChartDocs } from './FunnelChart/FunnelChartDocs';
11 | export { default as HistogramDocs } from './Histogram/HistogramDocs';
12 | export {
13 | default as KernelDensityEstimationDocs,
14 | } from './KernelDensityEstimation/KernelDensityEstimationDocs';
15 | export { default as LineChartDocs } from './LineChart/LineChartDocs';
16 | export {
17 | default as MarkerLineChartDocs,
18 | } from './MarkerLineChart/MarkerLineChartDocs';
19 | export {
20 | default as MeasuredValueLabelDocs,
21 | } from './MeasuredValueLabel/MeasuredValueLabelDocs';
22 | export { default as PieChartDocs } from './PieChart/PieChartDocs';
23 | export {
24 | default as RangeBarChartDocs,
25 | } from './RangeBarChart/RangeBarChartDocs';
26 | export { default as RangeRectDocs } from './RangeRect/RangeRectDocs';
27 | export {
28 | default as SankeyDiagramDocs,
29 | } from './SankeyDiagram/SankeyDiagramDocs';
30 | export { default as ScatterPlotDocs } from './ScatterPlot/ScatterPlotDocs';
31 | export { default as TreeMapDocs } from './TreeMap/TreeMapDocs';
32 | export { default as XAxisDocs } from './XAxis/XAxisDocs';
33 | export { default as XAxisLabelsDocs } from './XAxisLabels/XAxisLabelsDocs';
34 | export { default as XAxisTitleDocs } from './XAxisTitle/XAxisTitleDocs';
35 | export { default as XGridDocs } from './XGrid/XGridDocs';
36 | export { default as XLineDocs } from './XLine/XLineDocs';
37 | export { default as XTicksDocs } from './XTicks/XTicksDocs';
38 | export { default as XYPlotDocs } from './XYPlot/XYPlotDocs';
39 | export { default as YAxisDocs } from './YAxis/YAxisDocs';
40 | export { default as YAxisLabelsDocs } from './YAxisLabels/YAxisLabelsDocs';
41 | export { default as YAxisTitleDocs } from './YAxisTitle/YAxisTitleDocs';
42 | export { default as YGridDocs } from './YGrid/YGridDocs';
43 | export { default as YLineDocs } from './YLine/YLineDocs';
44 | export { default as YTicksDocs } from './YTicks/YTicksDocs';
45 | export {
46 | default as ZoomContainerDocs,
47 | } from './ZoomContainer/ZoomContainerDocs';
48 |
--------------------------------------------------------------------------------
/docs/src/index_html.ejs:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | <%= htmlWebpackPlugin.options.title %>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
32 |
33 | Loading...
34 |
35 |
--------------------------------------------------------------------------------
/docs/src/lessons/GettersAndAccessors/examples/GettersAndAccessors.js.example:
--------------------------------------------------------------------------------
1 | const GettersAndAccessorsExample = (props) => {
2 | // sample data in a few different shapes
3 | const arrData = [
4 | [0, 4], [5, 20], [10, 13], [15, 19]
5 | ];
6 | const objData = [
7 | {count: 4, friends: [{id: 'a', age: 24}, {id: 'b', age: 19}]},
8 | {count: 7, friends: [{id: 'a', age: 28}, {id: 'b', age: 29}]},
9 | {count: 19, friends: [{id: 'a', age: 22}, {id: 'b', age: 44}]},
10 | {count: 22, friends: [{id: 'a', age: 41}, {id: 'b', age: 22}]},
11 | ];
12 |
13 | return
14 |
15 |
16 | {/* array getters: line X is d[0] and line Y is d[1] */}
17 |
22 | {/* use strings for deep object access */}
23 |
29 | {/* or use functions if you prefer */}
30 | d.count}
33 | getY={(d) => d.friends[1].age}
34 | lineStyle={{stroke: 'purple'}}
35 | />
36 |
37 | };
38 |
39 |
40 | ReactDOM.render( , mountNode);
41 |
--------------------------------------------------------------------------------
/docs/src/lessons/GettersAndAccessors/examples/GraphingCalculator.js.example:
--------------------------------------------------------------------------------
1 | const GraphingCalculatorExample = (props) => {
2 | // generate an array of numbers using _.range
3 | // returns [0, 1, 2, 3, ..., 99]
4 | const data = _.range(100);
5 |
6 | return
7 |
8 |
9 | Math.sin(d*0.1)}
15 | />
16 |
17 | };
18 |
19 |
20 | ReactDOM.render( , mountNode);
21 |
--------------------------------------------------------------------------------
/docs/src/lessons/Interaction/InteractionLesson.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Lesson from '../../Lesson';
3 | import ExampleSection from '../../ExampleSection';
4 |
5 | const examples = [
6 | {
7 | id: 'basic',
8 | label: 'Interaction Example',
9 | codeText: require('./examples/Interaction.js.example').default,
10 | },
11 | ];
12 |
13 | export default class InteractionLesson extends React.Component {
14 | render() {
15 | return (
16 |
17 | {/* Interaction lesson goes here. intersperse with examples or leave examples loop below */}
18 |
19 | {examples.map(example => {
20 | return ;
21 | })}
22 |
23 | );
24 | }
25 | }
26 |
27 | // todo: flesh out this lesson and re-do this example:
28 |
29 | const CustomSelectionRect = () => {
30 | const { scale, hoveredYVal } = this.props;
31 | return hoveredYVal ? (
32 |
39 | ) : null;
40 | };
41 |
42 | class CustomChildExample extends React.Component {
43 | state = {
44 | hoveredYVal: null,
45 | };
46 |
47 | onMouseMoveChart = ({ yValue }) => {
48 | this.setState({ hoveredYVal: yValue });
49 | };
50 |
51 | render() {
52 | return (
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/docs/src/lessons/Interaction/examples/Interaction.js.example:
--------------------------------------------------------------------------------
1 | // const InteractionExample = React.createClass({
2 | class InteractionExample extends React.Component {
3 | getInitialState() {
4 | return {
5 | activeValue: null
6 | }
7 | }
8 | onEnterBar(e, d) {
9 | this.setState({activeValue: d});
10 | }
11 | onLeaveBar(e, d) {
12 | this.setState({activeValue: null})
13 | }
14 | render() {
15 | const {activeValue} = this.state;
16 |
17 | return
18 | {_.isNumber(activeValue) ?
19 |
20 | {activeValue.toFixed(2)}
21 |
:
22 |
Hover over the chart to show values
23 | }
24 |
25 |
26 | Math.sin(d / 10) * 10}
29 | getXEnd={d => Math.sin((d + 1) / 10) * 10}
30 | getY={d => Math.cos(d / (Math.PI))}
31 | onMouseEnterBar={this.onEnterBar}
32 | onMouseLeaveBar={this.onLeaveBar}
33 | />
34 | ;
35 |
36 | }
37 | }
38 |
39 | ReactDOM.render( , mountNode);
40 |
--------------------------------------------------------------------------------
/docs/src/lessons/QuickStart/QuickStartLesson.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Lesson from '../../Lesson';
3 | import ExampleSection from '../../ExampleSection';
4 |
5 | const examples = [
6 | {
7 | id: 'basic',
8 | label: 'Quick Start Example',
9 | codeText: require('./examples/QuickStart.js.example').default,
10 | },
11 | ];
12 |
13 | export default class QuickStartLesson extends React.Component {
14 | render() {
15 | return (
16 |
17 |
18 | To get started using Reactochart, first install it using{' '}
19 | npm
:
20 |
21 | npm install --save reactochart
22 |
23 | Then you can import
individual Reactochart components:
24 |
25 | import LineChart from 'reactochart/LineChart'
26 |
27 | The examples in this documentation will omit these imports to save
28 | space, so make sure you remember to include them in your code to get
29 | things working. For example, the example below requires importing the
30 | following components:
31 |
32 |
33 | import XYPlot from 'reactochart/XYPlot';
34 |
35 | import XAxis from 'reactochart/XAxis';
36 |
37 | import YAxis from 'reactochart/YAxis';
38 |
39 | import LineChart from 'reactochart/LineChart';
40 |
41 |
42 | If you prefer, you can import all of Reactochart at once, though this
43 | may hinder some optimizations, such as webpack
{' '}
44 | tree-shaking:
45 |
46 |
47 | import {'{'}XYPlot, XAxis, YAxis, LineChart{'}'} from 'reactochart';
48 |
49 | // or
50 | import * as Reactochart from 'reactochart';
51 |
52 |
53 | And now, here's our first line chart showing the basic usage of these
54 | components. In this and all future examples, the code on the left side
55 | is editable and will update the preview on the right - so experiment
56 | and see for yourself how things work!
57 |
58 |
59 | {examples.map(example => {
60 | return ;
61 | })}
62 |
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/docs/src/lessons/QuickStart/examples/QuickStart.js.example:
--------------------------------------------------------------------------------
1 | const QuickStartExample = (props) => {
2 | return
3 |
4 |
5 | d.x}
13 | y={d => d.y}
14 | />
15 |
16 | };
17 |
18 | ReactDOM.render( , mountNode);
19 |
--------------------------------------------------------------------------------
/docs/src/lessons/XYPlots/examples/LineChart.js.example:
--------------------------------------------------------------------------------
1 | const XYLineChartExample = (props) => {
2 | const data = [
3 | {x: 0, y: 20},
4 | {x: 5, y: 30},
5 | {x: 10, y: 35},
6 | {x: 15, y: 30},
7 | ];
8 | return
9 | d.x}
12 | y={d => d.y}
13 | />
14 |
15 | };
16 |
17 | ReactDOM.render( , mountNode);
18 |
--------------------------------------------------------------------------------
/docs/src/lessons/XYPlots/examples/LineChartWithAxis.js.example:
--------------------------------------------------------------------------------
1 | const XYLineChartExample = (props) => {
2 | const data = [
3 | {x: 0, y: 2},
4 | {x: 5, y: 22},
5 | {x: 10, y: 32},
6 | {x: 15, y: 36},
7 | ];
8 | return
9 |
10 |
11 | d.x}
14 | y={d => d.y}
15 | />
16 |
17 | };
18 |
19 | ReactDOM.render( , mountNode);
20 |
--------------------------------------------------------------------------------
/docs/src/lessons/XYPlots/examples/MultiChart.js.example:
--------------------------------------------------------------------------------
1 | const MultiChartExample = (props) => {
2 | const data = [
3 | {x: 0, y: 2, z: 3},
4 | {x: 5, y: 22, z: 12},
5 | {x: 10, y: 32, z: 15},
6 | {x: 15, y: 36, z: 25},
7 | ];
8 | return
9 |
10 |
11 | d.x}
14 | y={d => d.y}
15 | barThickness={35}
16 | barStyle={{fill: '#888'}}
17 | />
18 | d.x}
21 | y={d => d.y}
22 | lineStyle={{stroke: 'royalblue', strokeWidth: 5}}
23 | />
24 | d.x}
27 | y={d => d.z}
28 | lineStyle={{stroke: 'coral', strokeWidth: 3}}
29 | />
30 |
31 | };
32 |
33 | ReactDOM.render( , mountNode);
34 |
--------------------------------------------------------------------------------
/docs/src/lessons/index.js:
--------------------------------------------------------------------------------
1 | export { default as QuickStartLesson } from "./QuickStart/QuickStartLesson";
2 | export { default as XYPlotsLesson } from "./XYPlots/XYPlotsLesson";
3 | export {
4 | default as GettersAndAccessorsLesson
5 | } from "./GettersAndAccessors/GettersAndAccessorsLesson";
6 | export { default as InteractionLesson } from "./Interaction/InteractionLesson";
7 |
--------------------------------------------------------------------------------
/docs/src/main.js:
--------------------------------------------------------------------------------
1 | import '../styles/main.less';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import { App } from './App';
5 |
6 | ReactDOM.render( , document.getElementById('container'));
7 |
--------------------------------------------------------------------------------
/docs/src/templates/ComponentDocsPage.js.template:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ComponentDocs from '../../ComponentDocs';
4 | import ExampleSection from '../../ExampleSection';
5 | // autogenerated docs data containing descriptions of this component's props
6 | import propDocs from './propDocs.json';
7 |
8 | const examples = [
9 | {
10 | id: "basic",
11 | label: "Basic ${componentName}",
12 | codeText: require('./examples/${componentName}.js.example').default,
13 | },
14 | ];
15 |
16 | export default class ${componentName}Examples extends React.Component {
17 | render() {
18 | return
19 |
20 | {/* documentation goes here. intersperse docs with examples or leave examples loop below */}
21 |
22 | {examples.map(example => {
23 | return ;
24 | })}
25 | ;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/templates/ComponentExample.js.template:
--------------------------------------------------------------------------------
1 | const ${componentName}Example = (props) => {
2 | return insert example here
;
3 | };
4 |
5 | ReactDOM.render(<${componentName}Example />, mountNode);
6 |
--------------------------------------------------------------------------------
/docs/src/templates/Lesson.js.template:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Lesson from '../../Lesson';
4 | import ExampleSection from '../../ExampleSection';
5 |
6 | const examples = [
7 | {
8 | id: "basic",
9 | label: "${name} Example",
10 | codeText: require('./examples/${componentName}.js.example').default,
11 | },
12 | ];
13 |
14 | export default class ${componentName}Lesson extends React.Component {
15 | render() {
16 | return
17 |
18 | {/* ${name} lesson goes here. intersperse with examples or leave examples loop below */}
19 |
20 | {examples.map(example => {
21 | return ;
22 | })}
23 | ;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/docs/styles/main.less:
--------------------------------------------------------------------------------
1 | @import "../../styles/charts.less";
2 |
3 | body {
4 | //font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
5 | //margin: 0;
6 | //padding: 0;
7 | //background: #f0f0f0;
8 | //color: #0f0f0f;
9 |
10 | #container {
11 | //margin: 10px;
12 | }
13 | }
14 |
15 | .sidebar-nav {
16 | h1,
17 | h2,
18 | h3,
19 | h4,
20 | h5,
21 | h6 {
22 | color: #f8f8f8;
23 | text-transform: uppercase;
24 | }
25 | h3 {
26 | font-size: 16px;
27 | }
28 | h4 {
29 | font-size: 14px;
30 | }
31 | }
32 |
33 | .example {
34 | margin-bottom: 2em;
35 | }
36 |
37 | .component-docs {
38 | padding: 0 30px;
39 | }
40 | .prop-docs {
41 | background-color: #efefef;
42 | padding: 15px;
43 |
44 | .prop-description,
45 | .prop-default {
46 | display: block;
47 | margin-left: 2em;
48 | font-size: 0.85em;
49 | }
50 | }
51 |
52 | .example-section {
53 | display: inline-block;
54 | margin: 10px;
55 |
56 | &.example-section-visible {
57 | display: block;
58 | }
59 |
60 | .example-section-button {
61 | display: inline-block;
62 | //margin: 10px;
63 | padding: 10px 20px;
64 | font-size: 20pt;
65 | font-weight: bold;
66 | background: #cccccc;
67 | cursor: pointer;
68 | border-radius: 5px;
69 |
70 | .example-arrow {
71 | color: #888;
72 | }
73 | &.active {
74 | background-color: #4cba6f;
75 | .example-arrow {
76 | color: #0f0f0f;
77 | }
78 | }
79 | }
80 |
81 | .example-section-content {
82 | margin: 10px 20px;
83 | }
84 | }
85 |
86 | .playground {
87 | display: flex;
88 | flex-wrap: wrap;
89 |
90 | .playgroundCode,
91 | .playgroundPreview {
92 | border: 1px solid #efefef;
93 | border-radius: 3px;
94 | flex-basis: 150px;
95 |
96 | &:before {
97 | display: block;
98 | text-align: center;
99 | color: #616467;
100 | background-color: #f8f8f8;
101 | border-bottom: 1px solid #efefef;
102 | text-transform: uppercase;
103 | letter-spacing: 1px;
104 | font-size: 14px;
105 | line-height: 28px;
106 | }
107 | }
108 |
109 | .playgroundCode {
110 | margin-right: 8px;
111 | flex-grow: 0.6;
112 |
113 | &:before {
114 | content: "Editable Source";
115 | }
116 | .CodeMirror {
117 | font-size: 10pt;
118 | font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
119 | }
120 | }
121 |
122 | .playgroundPreview {
123 | margin-left: 8px;
124 | //text-align: center;
125 | flex-grow: 0.4;
126 |
127 | &:before {
128 | content: "Live Preview";
129 | }
130 | .previewArea {
131 | padding: 8px 6px;
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Redirect
4 |
5 |
6 |
7 | Redirecting to docs...
8 |
9 |
10 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const dontTranspiledThese = ['internmap', 'delaunator', 'robust-predicates'];
2 | const dontTranspile = dontTranspiledThese.join('|');
3 |
4 | const config = {
5 | collectCoverage: true,
6 | collectCoverageFrom: ['src/**/*.js'],
7 | setupFiles: ['/tests/jsdom/setup.js'],
8 | setupFilesAfterEnv: ['./node_modules/jest-enzyme/lib/index.js'],
9 | transformIgnorePatterns: [
10 | `[/\\\\]node_modules[/\\\\]((?!(?<=[/\\\\])(d3-?|${dontTranspile})).)+\\.(js|jsx|ts|tsx)$`,
11 | ],
12 | };
13 |
14 | module.exports = config;
15 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@spotify/web-scripts/config/prettier.config');
2 |
--------------------------------------------------------------------------------
/scripts/clean.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const sh = require('shelljs');
3 |
4 | const { fileExists, dirExists } = require('./utils');
5 |
6 | const srcContents = sh.ls('src');
7 |
8 | // We don't want to commit built files, so it is useful to have a `clean` script which deletes them if they exist.
9 | // However, Reactochart is built in the root directory
10 | // (so that modules may be required with eg. `require('reactochart/LineChart')`).
11 | // This makes cleanup harder than simply deleting a `build` directory.
12 | // Instead this looks for any files in the root directory which match the name of a file in the `src` directory,
13 | // and deletes them if they exist.
14 | // Sounds dangerous, but any files in root which share a name with src would have been overwritten by the build anyway.
15 |
16 | srcContents.forEach(fileOrDir => {
17 | if (fileExists(`src/${fileOrDir}`) && fileExists(`./${fileOrDir}`)) {
18 | console.log(`deleting file ./${fileOrDir}`);
19 | sh.rm(`./${fileOrDir}`);
20 | } else if (dirExists(`src/${fileOrDir}`) && dirExists(fileOrDir)) {
21 | console.log(`deleting directory ./${fileOrDir}`);
22 | sh.rm('-rf', `./${fileOrDir}`);
23 | }
24 | // check for source maps too
25 | if (fileExists(`./${fileOrDir}.map`)) {
26 | console.log(`deleting file ./${fileOrDir}.map`);
27 | sh.rm(`./${fileOrDir}.map`);
28 | }
29 | });
30 |
31 | // Clean compiled css file
32 | if (fileExists('./styles.css')) {
33 | sh.rm('./styles.css');
34 | }
35 |
--------------------------------------------------------------------------------
/scripts/makeLesson.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const sh = require('shelljs');
3 | const _ = require('lodash');
4 |
5 | const {
6 | isUpperCase,
7 | fileExists,
8 | dirExists,
9 | ensureDir,
10 | fileNameFromPath,
11 | stripFileExtension,
12 | } = require('./utils');
13 |
14 | const lessonsDirPath = `${__dirname}/../docs/src/lessons`;
15 | const lessonTemplatePath = `${__dirname}/../docs/src/templates/Lesson.js.template`;
16 | const exampleTemplatePath = `${__dirname}/../docs/src/templates/ComponentExample.js.template`;
17 |
18 | if (process.argv.length <= 2) {
19 | console.log(`Usage: ${__filename} LESSON_NAME`);
20 | process.exit(-1);
21 | }
22 |
23 | const lessonName = process.argv[2];
24 | console.log(lessonName);
25 |
26 | const componentName = lessonName
27 | .split(' ')
28 | .map(_.capitalize)
29 | .join('');
30 | console.log('componentName', componentName);
31 | const lessonDirPath = `${lessonsDirPath}/${componentName}`;
32 | const lessonComponentPath = `${lessonDirPath}/${componentName}Lesson.js`;
33 |
34 | ensureDir(lessonsDirPath);
35 | ensureDir(lessonDirPath);
36 | if (!fileExists(lessonComponentPath)) {
37 | // use template file to generate a stub example page for this component
38 | const lessonTemplate = _.template(sh.cat(lessonTemplatePath).toString());
39 | const lessonStub = lessonTemplate({ name: lessonName, componentName });
40 | fs.writeFile(lessonComponentPath, lessonStub, err => {
41 | if (err) throw err;
42 | console.log('created stub lesson component:', lessonComponentPath);
43 | });
44 |
45 | const examplesDirPath = `${lessonDirPath}/examples`;
46 | const examplePath = `${examplesDirPath}/${componentName}.js.example`;
47 |
48 | // use template to generate stub example file, to be used for live preview (using component-playground)
49 | const exampleTemplate = _.template(sh.cat(exampleTemplatePath).toString());
50 | const exampleStub = exampleTemplate({ componentName });
51 | ensureDir(examplesDirPath);
52 | fs.writeFile(examplePath, exampleStub, err => {
53 | if (err) throw err;
54 | console.log('created stub example:', examplePath);
55 | });
56 | }
57 |
--------------------------------------------------------------------------------
/scripts/utils.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const sh = require('shelljs');
3 | const _ = require('lodash');
4 |
5 | function isUpperCase(letter) {
6 | return letter.toUpperCase() === letter;
7 | }
8 | function fileExists(path) {
9 | return sh.test('-f', path);
10 | }
11 | function dirExists(path) {
12 | return sh.test('-d', path);
13 | }
14 | function ensureDir(path) {
15 | if (!dirExists(path)) sh.mkdir('-p', path);
16 | }
17 | function fileNameFromPath(path) {
18 | return _.last(path.split('/'));
19 | }
20 | function stripFileExtension(fileName) {
21 | return _.dropRight(fileName.split('.')).join('.');
22 | }
23 |
24 | module.exports = {
25 | isUpperCase,
26 | fileExists,
27 | dirExists,
28 | ensureDir,
29 | fileNameFromPath,
30 | stripFileExtension,
31 | };
32 |
--------------------------------------------------------------------------------
/src/MeasuredValueLabel.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaults from 'lodash/defaults';
3 | import omit from 'lodash/omit';
4 | import identity from 'lodash/identity';
5 | import measureText from './utils/measureText';
6 | import PropTypes from 'prop-types';
7 |
8 | export default class MeasuredValueLabel extends React.Component {
9 | static propTypes = {
10 | value: PropTypes.any,
11 | format: PropTypes.func,
12 | children: PropTypes.any,
13 | };
14 |
15 | static defaultProps = {
16 | format: identity,
17 | style: {
18 | fontFamily: 'Helvetica, sans-serif',
19 | fontSize: '20px',
20 | lineHeight: 1,
21 | textAnchor: 'middle',
22 | },
23 | };
24 |
25 | static getLabel(props) {
26 | const { value, format } = props;
27 | const style = defaults(props.style, MeasuredValueLabel.defaultProps.style);
28 | const labelStr = format(value);
29 | const labelWithStyle = Object.assign({ text: labelStr }, style);
30 | const measured = measureText(labelWithStyle);
31 |
32 | return {
33 | value: props.value,
34 | text: measured.text,
35 | height: measured.height.value,
36 | width: measured.width.value,
37 | };
38 | }
39 |
40 | render() {
41 | const { value, format } = this.props;
42 | const passedProps = omit(this.props, ['value', 'format']);
43 |
44 | return (
45 |
46 | {React.Children.count(this.props.children)
47 | ? this.props.children
48 | : format(value)}
49 |
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/TreeMapNode.js:
--------------------------------------------------------------------------------
1 | import get from 'lodash/get';
2 | import kebabCase from 'lodash/kebabCase';
3 | import isFunction from 'lodash/isFunction';
4 | import isObject from 'lodash/isObject';
5 |
6 | import PropTypes from 'prop-types';
7 | import React from 'react';
8 | import * as CustomPropTypes from './utils/CustomPropTypes';
9 |
10 | const TreeMapNode = props => {
11 | const {
12 | node,
13 | getLabel,
14 | nodeStyle,
15 | labelStyle,
16 | minLabelWidth,
17 | minLabelHeight,
18 | NodeLabelComponent,
19 | parentNames,
20 | } = props;
21 | const { depth, parent, x0, y0, x1, y1 } = node;
22 |
23 | const parentName = get(parent, 'data.name');
24 | const nodeGroupClass = parent
25 | ? `node-group-${kebabCase(parentName)} node-group-i-${parentNames.indexOf(
26 | parentName,
27 | )}`
28 | : '';
29 | const className = `rct-tree-map-node node-depth-${depth} ${nodeGroupClass}`;
30 |
31 | const style = {
32 | position: 'absolute',
33 | width: x1 - x0,
34 | height: y1 - y0,
35 | top: y0,
36 | left: x0,
37 | transition: 'all .2s',
38 | };
39 | const customStyle = isFunction(nodeStyle)
40 | ? nodeStyle(node)
41 | : isObject(nodeStyle)
42 | ? nodeStyle
43 | : {};
44 | Object.assign(style, customStyle);
45 |
46 | const handlers = [
47 | 'onClick',
48 | 'onMouseEnter',
49 | 'onMouseLeave',
50 | 'onMouseMove',
51 | ].reduce((acc, eventName) => {
52 | const handler = props[`${eventName}Node`];
53 | if (handler) acc[eventName] = handler.bind(null, node);
54 | return acc;
55 | }, {});
56 |
57 | return (
58 |
59 | {x1 - x0 > minLabelWidth && y1 - y0 > minLabelHeight ? ( // show label if node is big enough
60 |
61 | ) : null}
62 |
63 | );
64 | };
65 |
66 | TreeMapNode.propTypes = {
67 | node: PropTypes.shape({
68 | parent: PropTypes.object,
69 | children: PropTypes.array,
70 | value: PropTypes.number,
71 | depth: PropTypes.number,
72 | x: PropTypes.number,
73 | y: PropTypes.number,
74 | dx: PropTypes.number,
75 | dy: PropTypes.number,
76 | x0: PropTypes.number,
77 | y0: PropTypes.number,
78 | x1: PropTypes.number,
79 | y1: PropTypes.number,
80 | }),
81 | nodeStyle: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
82 | minLabelWidth: PropTypes.number,
83 | minLabelHeight: PropTypes.number,
84 | getLabel: CustomPropTypes.getter,
85 | labelStyle: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
86 | NodeLabelComponent: PropTypes.func,
87 | parentNames: PropTypes.arrayOf(PropTypes.string),
88 | };
89 |
90 | TreeMapNode.defaultProps = {
91 | minLabelWidth: 0,
92 | minLabelHeight: 0,
93 | };
94 |
95 | export default TreeMapNode;
96 |
--------------------------------------------------------------------------------
/src/TreeMapNodeLabel.js:
--------------------------------------------------------------------------------
1 | import isFunction from 'lodash/isFunction';
2 | import isObject from 'lodash/isObject';
3 | import PropTypes from 'prop-types';
4 | import React from 'react';
5 | import * as CustomPropTypes from './utils/CustomPropTypes';
6 | import { makeAccessor } from './utils/Data';
7 |
8 | const TreeMapNodeLabel = props => {
9 | const { node, getLabel, labelStyle } = props;
10 | const { x1, x0 } = node;
11 | const style = { width: x1 - x0 };
12 | const customStyle = isFunction(labelStyle)
13 | ? labelStyle(node)
14 | : isObject(labelStyle)
15 | ? labelStyle
16 | : {};
17 | Object.assign(style, customStyle);
18 |
19 | return (
20 |
21 | {makeAccessor(getLabel)(node)}
22 |
23 | );
24 | };
25 |
26 | TreeMapNodeLabel.propTypes = {
27 | node: PropTypes.object,
28 | getLabel: CustomPropTypes.getter,
29 | labelStyle: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
30 | minLabelWidth: PropTypes.number,
31 | minLabelHeight: PropTypes.number,
32 | };
33 |
34 | export default TreeMapNodeLabel;
35 |
--------------------------------------------------------------------------------
/src/XGrid.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaults from 'lodash/defaults';
3 | import PropTypes from 'prop-types';
4 |
5 | import { getScaleTicks, getTickDomain } from './utils/Scale';
6 | import XLine from './XLine';
7 |
8 | export default class XGrid extends React.Component {
9 | static propTypes = {
10 | width: PropTypes.number,
11 | height: PropTypes.number,
12 | xScale: PropTypes.func,
13 | spacingTop: PropTypes.number,
14 | spacingBottom: PropTypes.number,
15 | spacingLeft: PropTypes.number,
16 | spacingRight: PropTypes.number,
17 | nice: PropTypes.bool,
18 | ticks: PropTypes.array,
19 | tickCount: PropTypes.number,
20 | lineClassName: PropTypes.string,
21 | lineStyle: PropTypes.object,
22 | };
23 | static defaultProps = {
24 | nice: true,
25 | lineStyle: {},
26 | };
27 |
28 | static getTickDomain(props) {
29 | if (!props.xScale) return;
30 | const propsWithDefaults = defaults({}, props, XGrid.defaultProps);
31 | return {
32 | xTickDomain: getTickDomain(propsWithDefaults.xScale, propsWithDefaults),
33 | };
34 | }
35 |
36 | render() {
37 | const {
38 | height,
39 | xScale,
40 | tickCount,
41 | lineClassName,
42 | lineStyle,
43 | spacingTop,
44 | spacingBottom,
45 | spacingLeft,
46 | spacingRight,
47 | } = this.props;
48 | const ticks = this.props.ticks || getScaleTicks(xScale, null, tickCount);
49 | const className = `rct-chart-grid-line ${lineClassName || ''}`;
50 |
51 | return (
52 |
53 | {ticks.map((tick, i) => {
54 | return (
55 |
69 | );
70 | })}
71 |
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/XLine.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | /**
5 | * `XLine` is a vertical line rendered on the x axis
6 | */
7 | export default class XLine extends React.Component {
8 | static propTypes = {
9 | /**
10 | * Height of chart - provided by XYPlot
11 | */
12 | height: PropTypes.number,
13 | /**
14 | * D3 scale for X axis - provided by XYPlot
15 | */
16 | xScale: PropTypes.func,
17 | value: PropTypes.oneOfType([
18 | PropTypes.number,
19 | PropTypes.string,
20 | PropTypes.instanceOf(Date),
21 | ]).isRequired,
22 | /**
23 | * D3 scale for Y axis - provided by XYPlot
24 | */
25 | yScale: PropTypes.func,
26 | yLimit: PropTypes.oneOfType([
27 | PropTypes.number,
28 | PropTypes.string,
29 | PropTypes.instanceOf(Date),
30 | ]),
31 | /**
32 | * The Y domain of the data as an array - provided by XYPlot
33 | */
34 | yDomain: PropTypes.array,
35 | /**
36 | * Spacing top - provided by XYPlot
37 | */
38 | spacingTop: PropTypes.number,
39 | /**
40 | * Spacing bottom - provided by XYPlot
41 | */
42 | spacingBottom: PropTypes.number,
43 | /**
44 | * Inline style object to be applied to the line
45 | */
46 | style: PropTypes.object,
47 | /**
48 | * Class attribute to be applied to the line
49 | */
50 | className: PropTypes.string,
51 | };
52 | static defaultProps = {
53 | style: {},
54 | className: '',
55 | spacingTop: 0,
56 | spacingBottom: 0,
57 | };
58 |
59 | render() {
60 | const {
61 | xScale,
62 | value,
63 | yScale,
64 | yLimit,
65 | yDomain,
66 | height,
67 | style,
68 | spacingTop,
69 | spacingBottom,
70 | } = this.props;
71 | const className = `rct-chart-line-x ${this.props.className}`;
72 | const lineX = xScale(value);
73 |
74 | let y1 = -spacingTop;
75 | let y2 = height + spacingBottom;
76 |
77 | if (typeof yLimit !== 'undefined') {
78 | y1 = yScale(yDomain[0]) + spacingBottom;
79 | y2 = yScale(yLimit);
80 | }
81 |
82 | return (
83 |
94 | );
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/YGrid.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaults from 'lodash/defaults';
3 | import PropTypes from 'prop-types';
4 |
5 | import YLine from './YLine';
6 | import { getScaleTicks, getTickDomain } from './utils/Scale';
7 |
8 | export default class YGrid extends React.Component {
9 | static propTypes = {
10 | width: PropTypes.number,
11 | height: PropTypes.number,
12 | yScale: PropTypes.func,
13 | spacingTop: PropTypes.number,
14 | spacingBottom: PropTypes.number,
15 | spacingLeft: PropTypes.number,
16 | spacingRight: PropTypes.number,
17 | nice: PropTypes.bool,
18 | ticks: PropTypes.array,
19 | tickCount: PropTypes.number,
20 | lineClassName: PropTypes.string,
21 | lineStyle: PropTypes.object,
22 | };
23 | static defaultProps = {
24 | nice: true,
25 | lineStyle: {},
26 | };
27 |
28 | static getTickDomain(props) {
29 | if (!props.yScale) return;
30 | const propsWithDefaults = defaults({}, props, YGrid.defaultProps);
31 | return { yTickDomain: getTickDomain(props.yScale, propsWithDefaults) };
32 | }
33 |
34 | render() {
35 | const {
36 | width,
37 | yScale,
38 | tickCount,
39 | lineClassName,
40 | lineStyle,
41 | spacingTop,
42 | spacingBottom,
43 | spacingLeft,
44 | spacingRight,
45 | } = this.props;
46 | const ticks = this.props.ticks || getScaleTicks(yScale, null, tickCount);
47 | const className = `rct-chart-grid-line ${lineClassName || ''}`;
48 |
49 | return (
50 |
51 | {ticks.map((tick, i) => {
52 | return (
53 |
67 | );
68 | })}
69 |
70 | );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/YLine.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | /**
5 | * `YLine` is a horizontal line rendered on the y axis
6 | */
7 | export default class YLine extends React.Component {
8 | static propTypes = {
9 | /**
10 | * D3 scale for Y axis - provided by XYPlot
11 | */
12 | yScale: PropTypes.func,
13 | /**
14 | * Width of chart - provided by XYPlot.
15 | */
16 | width: PropTypes.number,
17 | value: PropTypes.oneOfType([
18 | PropTypes.number,
19 | PropTypes.string,
20 | PropTypes.instanceOf(Date),
21 | ]).isRequired,
22 | /**
23 | * D3 scale for X axis - provided by XYPlot
24 | */
25 | xScale: PropTypes.func,
26 | xLimit: PropTypes.oneOfType([
27 | PropTypes.number,
28 | PropTypes.string,
29 | PropTypes.instanceOf(Date),
30 | ]),
31 | /**
32 | * Spacing left - provided by XYPlot
33 | */
34 | spacingLeft: PropTypes.number,
35 | /**
36 | * Spacing right - provided by XYPlot
37 | */
38 | spacingRight: PropTypes.number,
39 | /**
40 | * Inline style object to be applied to the line
41 | */
42 | style: PropTypes.object,
43 | /**
44 | * Class attribute to be applied to the line
45 | */
46 | className: PropTypes.string,
47 | };
48 | static defaultProps = {
49 | style: {},
50 | className: '',
51 | spacingLeft: 0,
52 | spacingRight: 0,
53 | };
54 |
55 | render() {
56 | const {
57 | width,
58 | yScale,
59 | value,
60 | xScale,
61 | xLimit,
62 | spacingLeft,
63 | spacingRight,
64 | style,
65 | } = this.props;
66 | const className = `rct-chart-line-y ${this.props.className || ''}`;
67 | const lineY = yScale(value);
68 | const lineX =
69 | typeof xLimit === 'undefined' ? width + spacingRight : xScale(xLimit);
70 |
71 | return (
72 |
83 | );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // Non-XY charts
2 | export { default as PieChart } from './PieChart';
3 | export { default as SankeyDiagram } from './SankeyDiagram';
4 | export { default as TreeMap } from './TreeMap';
5 |
6 | // XYPlot & XY charts
7 | export { default as XYPlot } from './XYPlot';
8 | export { default as LineChart } from './LineChart';
9 | export { default as ScatterPlot } from './ScatterPlot';
10 | export { default as BarChart } from './BarChart';
11 | export { default as RangeBarChart } from './RangeBarChart';
12 | export { default as AreaBarChart } from './AreaBarChart';
13 | export { default as MarkerLineChart } from './MarkerLineChart';
14 | export { default as AreaChart } from './AreaChart';
15 | export { default as ColorHeatmap } from './ColorHeatmap';
16 | export { default as AreaHeatmap } from './AreaHeatmap';
17 | export { default as Histogram } from './Histogram';
18 | export { default as KernelDensityEstimation } from './KernelDensityEstimation';
19 | export { default as FunnelChart } from './FunnelChart';
20 | export { default as AriaLabelContainer } from './AriaLabelContainer';
21 |
22 | // XY datum components (used by charts & axes)
23 | export { default as Bar } from './Bar';
24 | export { default as RangeRect } from './RangeRect';
25 | export { default as XLine } from './XLine';
26 | export { default as YLine } from './YLine';
27 |
28 | // XY Axis Components
29 | export { default as XAxis } from './XAxis';
30 | export { default as XAxisLabels } from './XAxisLabels';
31 | export { default as XAxisTitle } from './XAxisTitle';
32 | export { default as XGrid } from './XGrid';
33 | export { default as XTicks } from './XTicks';
34 |
35 | export { default as YAxis } from './YAxis';
36 | export { default as YAxisLabels } from './YAxisLabels';
37 | export { default as YAxisTitle } from './YAxisTitle';
38 | export { default as YGrid } from './YGrid';
39 | export { default as YTicks } from './YTicks';
40 |
41 | // Higher-order components
42 | export { default as resolveXYScales } from './utils/resolveXYScales';
43 |
44 | // Containers
45 | export { default as ZoomContainer } from './ZoomContainer';
46 |
47 | import * as Data from './utils/Data';
48 | export const utils = { Data };
49 | // export {utils};
50 |
51 | // ### Utilities
52 | // * Data
53 | // * Scale
54 | // * Axis
55 | // * Label
56 | // * Margin
57 | // * depthEqual
58 |
--------------------------------------------------------------------------------
/src/util.js:
--------------------------------------------------------------------------------
1 | import isFunction from 'lodash/isFunction';
2 | import isUndefined from 'lodash/isUndefined';
3 |
4 | /**
5 | * Convenience function for event callbacks... we often want to say
6 | * "if this.props.onThing is a function, call this.onThing(e), which will do stuff, then call this.props.onThing"
7 | * @param {String} propName - name of prop (func name)
8 | * @param {Object} props - props from component
9 | * @param {Function} context - component context
10 | * @param
11 | */
12 | export function methodIfFuncProp(propName, props, context) {
13 | return isFunction(props[propName]) && isFunction(context[propName])
14 | ? context[propName]
15 | : null;
16 | }
17 |
18 | /**
19 | * Binds arguments to given fn after arguments provided to the fn
20 | * @param {Function} fn - function to be called
21 | * @param {...any} args - arguments to be appended to the function
22 | */
23 | export function bindTrailingArgs(fn, ...boundArgs) {
24 | return (...args) => {
25 | return fn(...args, ...boundArgs);
26 | };
27 | }
28 |
29 | export function hasOneOfTwo(a, b) {
30 | return [a, b].some(isUndefined) && [a, b].some(v => !isUndefined(v));
31 | }
32 |
--------------------------------------------------------------------------------
/src/utils/CustomPropTypes.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | export const xyObjectOf = type => PropTypes.shape({ x: type, y: type });
4 |
5 | export const fourDirectionsOf = type =>
6 | PropTypes.shape({
7 | top: type,
8 | bottom: type,
9 | left: type,
10 | right: type,
11 | });
12 |
13 | export const getter = PropTypes.oneOfType([
14 | PropTypes.string,
15 | PropTypes.number,
16 | PropTypes.array,
17 | PropTypes.func,
18 | ]);
19 |
20 | export const scaleType = PropTypes.oneOf([
21 | 'linear',
22 | 'time',
23 | 'ordinal',
24 | 'log',
25 | 'pow',
26 | ]);
27 |
28 | export const valueOrAccessor = PropTypes.oneOfType([
29 | PropTypes.number,
30 | PropTypes.string,
31 | PropTypes.instanceOf(Date),
32 | PropTypes.func,
33 | ]);
34 |
35 | export const accessorOrType = type => {
36 | if (Array.isArray(type))
37 | return PropTypes.oneOfType([PropTypes.func, ...type]);
38 | return PropTypes.oneOfType([PropTypes.func, type]);
39 | };
40 |
--------------------------------------------------------------------------------
/src/utils/Margin.js:
--------------------------------------------------------------------------------
1 | import mapKeys from 'lodash/mapKeys';
2 | import upperFirst from 'lodash/upperFirst';
3 | import mapValues from 'lodash/mapValues';
4 | import clone from 'lodash/clone';
5 |
6 | export const zeroMargin = { top: 0, bottom: 0, left: 0, right: 0 };
7 |
8 | // find a fuzzy match for key in object and return the value
9 | // eg getFuzzy({marginLeft: 10}, 'left') returns 10
10 | function getFuzzy(obj = {}, fuzzyKey) {
11 | const keyMatch = Object.keys(obj).find(key => {
12 | if (!!key.match(new RegExp(fuzzyKey, 'i'))) {
13 | return true;
14 | }
15 | return false;
16 | });
17 |
18 | if (keyMatch === undefined) {
19 | return;
20 | }
21 |
22 | return obj[keyMatch];
23 | }
24 |
25 | export function innerWidth(width, margin = {}) {
26 | return Math.max(
27 | width -
28 | ((getFuzzy(margin, 'left') || 0) + (getFuzzy(margin, 'right') || 0)),
29 | 0,
30 | );
31 | }
32 |
33 | export function innerHeight(height, margin = {}) {
34 | return Math.max(
35 | height -
36 | ((getFuzzy(margin, 'top') || 0) + (getFuzzy(margin, 'bottom') || 0)),
37 | 0,
38 | );
39 | }
40 |
41 | export function innerSize({ width, height } = {}, margin = {}) {
42 | return {
43 | width: innerWidth(width, margin),
44 | height: innerHeight(height, margin),
45 | };
46 | }
47 |
48 | export function innerRangeX(outerWidth, margin = {}) {
49 | const left = getFuzzy(margin, 'left') || 0;
50 | return [
51 | Math.min(left, outerWidth),
52 | Math.min(left + innerWidth(outerWidth, margin), outerWidth),
53 | ];
54 | }
55 | export function innerRangeY(outerHeight, margin = {}) {
56 | const top = getFuzzy(margin, 'top') || 0;
57 | return [
58 | Math.min(top + innerHeight(outerHeight, margin), outerHeight),
59 | Math.min(top, outerHeight),
60 | ];
61 | }
62 |
63 | export function prefixKeys(obj, prefix) {
64 | if (!prefix) return obj;
65 | return mapKeys(obj, (value, key) => prefix + upperFirst(key));
66 | }
67 |
68 | // TODO this isn't used anywhere, deprecate?
69 | export function maxMargins(margins = [], keyPrefix) {
70 | return margins.reduce((result, margin) => {
71 | return mapValues(result, (value, key) => {
72 | return Math.max(margin[key] || 0, result[key] || 0);
73 | });
74 | }, clone(prefixKeys(zeroMargin, keyPrefix)));
75 | }
76 |
77 | export function sumMargins(margins = [], keyPrefix) {
78 | return margins.reduce((result, margin) => {
79 | return mapValues(result, (value, key) => {
80 | return (result[key] || 0) + (margin[key] || 0);
81 | });
82 | }, clone(prefixKeys(zeroMargin, keyPrefix)));
83 | }
84 |
--------------------------------------------------------------------------------
/src/utils/depthEqual.js:
--------------------------------------------------------------------------------
1 | // Based on https://github.com/acdlite/recompose/blob/master/src/packages/recompose/shallowEqual.js
2 |
3 | const hasOwnProperty = Object.prototype.hasOwnProperty;
4 |
5 | export default function depthEqual(objA, objB, depth = 1) {
6 | if (objA === objB) {
7 | return true;
8 | }
9 |
10 | if (
11 | depth === 0 ||
12 | typeof objA !== 'object' ||
13 | objA === null ||
14 | typeof objB !== 'object' ||
15 | objB === null
16 | ) {
17 | // console.log('different obj', objA, objB);
18 | return false;
19 | }
20 |
21 | const keysA = Object.keys(objA);
22 | const keysB = Object.keys(objB);
23 |
24 | if (keysA.length !== keysB.length) {
25 | return false;
26 | }
27 |
28 | // Test for A's keys different from B.
29 | const bHasOwnProperty = hasOwnProperty.bind(objB);
30 | for (let i = 0; i < keysA.length; i++) {
31 | const aKey = keysA[i];
32 | if (
33 | !bHasOwnProperty(aKey) ||
34 | // recursively call depthEqual at the next level; depth 0 is === check
35 | !depthEqual(objA[aKey], objB[aKey], depth - 1)
36 | ) {
37 | // console.log('different key', aKey, objA, objB);
38 | return false;
39 | }
40 | }
41 |
42 | return true;
43 | }
44 |
--------------------------------------------------------------------------------
/src/utils/shallowEqual.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2013-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | *
9 | * @providesModule shallowEqual
10 | * @typechecks
11 | * @flow
12 | */
13 |
14 | // TODO Recreate shallow equals to not use flow
15 | // we currently use "@babel/preset-flow" just to parse this file
16 |
17 | /* eslint-disable no-self-compare */
18 |
19 | 'use strict';
20 |
21 | const hasOwnProperty = Object.prototype.hasOwnProperty;
22 |
23 | /**
24 | * inlined Object.is polyfill to avoid requiring consumers ship their own
25 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
26 | */
27 | function is(x: mixed, y: mixed): boolean {
28 | // SameValue algorithm
29 | if (x === y) {
30 | // Steps 1-5, 7-10
31 | // Steps 6.b-6.e: +0 != -0
32 | return x !== 0 || 1 / (x: $FlowIssue) === 1 / (y: $FlowIssue);
33 | }
34 | // Step 6.a: NaN == NaN
35 | return x !== x && y !== y;
36 | }
37 |
38 | /**
39 | * Performs equality by iterating through keys on an object and returning false
40 | * when any key has values which are not strictly equal between the arguments.
41 | * Returns true when the values of all keys are strictly equal.
42 | */
43 | function shallowEqual(objA: mixed, objB: mixed): boolean {
44 | if (is(objA, objB)) {
45 | return true;
46 | }
47 |
48 | if (
49 | typeof objA !== 'object' ||
50 | objA === null ||
51 | typeof objB !== 'object' ||
52 | objB === null
53 | ) {
54 | // console.log('shallowEqual: not object??');
55 | return false;
56 | }
57 |
58 | const keysA = Object.keys(objA);
59 | const keysB = Object.keys(objB);
60 |
61 | if (keysA.length !== keysB.length) {
62 | // console.log('!shallowEqual: different keys length');
63 | return false;
64 | }
65 |
66 | // Test for A's keys different from B.
67 | for (let i = 0; i < keysA.length; i++) {
68 | if (
69 | !hasOwnProperty.call(objB, keysA[i]) ||
70 | !is(objA[keysA[i]], objB[keysA[i]])
71 | ) {
72 | // console.log(`!shallowEqual: different ${keysA[i]} - ${objA[keysA[i]]} vs. ${objB[keysA[i]]}`);
73 | return false;
74 | }
75 | }
76 |
77 | return true;
78 | }
79 |
80 | module.exports = shallowEqual;
81 |
--------------------------------------------------------------------------------
/styles/charts.less:
--------------------------------------------------------------------------------
1 | .rct-xy-plot {
2 | * {
3 | user-select: none;
4 | -webkit-user-select: none;
5 | -moz-user-select: none;
6 | }
7 |
8 | .rct-chart-tick {
9 | fill: none;
10 | stroke: #666;
11 | stroke-width: 1px;
12 | }
13 |
14 | .rct-chart-background {
15 | fill: none;
16 | }
17 |
18 | .rct-plot-background {
19 | fill: #e0e0e0;
20 | }
21 |
22 | .rct-chart-grid-line {
23 | stroke: #b9b9b9;
24 | stroke-width: 1px;
25 | }
26 | }
27 |
28 | .rct-chart-line-x,
29 | .rct-chart-line-y {
30 | stroke: #090909;
31 | }
32 |
33 | .rct-chart-bar,
34 | .rct-chart-area-bar {
35 | fill: steelblue;
36 | }
37 |
38 | .rct-marker-line-chart {
39 | line {
40 | stroke: black;
41 | stroke-width: 2px;
42 | }
43 | }
44 |
45 | .rct-pie-chart {
46 | .rct-pie-slice {
47 | stroke: none;
48 | }
49 | .rct-pie-slice-0 {
50 | fill: steelblue;
51 | }
52 | .rct-pie-slice-1 {
53 | fill: darkred;
54 | }
55 | .rct-pie-slice-2 {
56 | fill: orange;
57 | }
58 | .rct-pie-slice-empty {
59 | fill: #ddd;
60 | }
61 | .rct-pie-label-center {
62 | font-size: 26pt;
63 | }
64 | .rct-marker-line {
65 | stroke: black;
66 | stroke-width: 2px;
67 | }
68 | }
69 |
70 | .rct-line-chart {
71 | .rct-line-path {
72 | fill: none;
73 | stroke: #0a0a0a;
74 | stroke-width: 1.5px;
75 | stroke-linejoin: bevel;
76 | }
77 | }
78 |
79 | .rct-area-chart {
80 | .rct-area-chart-path {
81 | stroke-width: 0;
82 | fill: steelblue;
83 | }
84 | }
85 |
86 | .rct-area-chart--difference {
87 | .rct-area-chart-path {
88 | stroke: #0a0a0a;
89 | stroke-width: 1.5px;
90 | stroke-linejoin: bevel;
91 | }
92 | }
93 |
94 | .rct-sankey-diagram {
95 | .rct-sankey-nodes .rct-sankey-node {
96 | fill: #000;
97 | }
98 | .rct-sankey-links .rct-sankey-link {
99 | stroke: rgba(0, 0, 0, 0.16);
100 | fill: none;
101 | }
102 | .rct-sankey-node-label {
103 | pointer-events: none;
104 | font-size: 10pt;
105 | }
106 | .rct-sankey-link-label {
107 | pointer-events: none;
108 | alignment-baseline: middle;
109 | dominant-baseline: central;
110 | font-size: 8.5pt;
111 | color: #333;
112 | }
113 | .rct-sankey-node-terminal {
114 | fill: steelblue;
115 | }
116 | }
117 |
118 | .rct-chart-axis-line-y,
119 | .rct-chart-axis-line-x {
120 | stroke: #b9b9b9;
121 | }
122 |
123 | .rct-chart-visually-hidden-rect {
124 | fill: transparent;
125 | pointer-events: none;
126 |
127 | &:focus {
128 | outline: 3px inset #181818;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/tests/browser/index.js:
--------------------------------------------------------------------------------
1 | require('./spec/XAxis.spec');
2 | require('./spec/YAxis.spec');
3 | require('./spec/YAxisLabels.spec');
4 | require('./spec/XAxisLabels.spec');
5 | require('./spec/XAxisTitle.spec');
6 | require('./spec/YAxisTitle.spec');
7 | const enzyme = require('enzyme');
8 | const adapter = require('enzyme-adapter-react-16');
9 |
10 | // some tests must be run in a browser environment
11 | // also it can be easier to debug tests in browser thanks to chrome debugger
12 | // place browser tests in tests/browser/spec and run `npm run test-browser`
13 |
14 | // run mocha
15 | (function() {
16 | enzyme.configure({ adapter: new adapter() });
17 |
18 | if (window.mochaPhantomJS) {
19 | mochaPhantomJS.run();
20 | } else {
21 | mocha.run();
22 | }
23 | })();
24 |
--------------------------------------------------------------------------------
/tests/browser/index_html.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Mocha Spec Runner
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/browser/spec/XAxisTitle.spec.js:
--------------------------------------------------------------------------------
1 | import chai, { expect } from 'chai';
2 | import { mount } from 'enzyme';
3 | import React from 'react';
4 | import sinonChai from 'sinon-chai';
5 | import { XAxisTitle, XYPlot } from 'src/index.js';
6 | chai.use(sinonChai);
7 |
8 | // XAxisTitle tests must run in browser since XAxisLabels uses measureText
9 |
10 | describe('XAxisTitle', () => {
11 | it('Check how many labels are created and where', () => {
12 | const xyProps = {
13 | width: 500,
14 | height: 360,
15 | xDomain: [0, 100],
16 | yDomain: [0, 100],
17 | };
18 |
19 | const tree = (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
37 |
38 |
39 | );
40 | const rendered = mount(tree).find(XAxisTitle);
41 | expect(rendered.at(0).props().alignment).to.equal('right');
42 | expect(
43 | rendered
44 | .at(0)
45 | .getDOMNode()
46 | .getAttribute('transform'),
47 | ).to.equal('translate(500,220)');
48 | expect(rendered.at(1).props().placement).to.equal('above');
49 | expect(
50 | rendered
51 | .at(1)
52 | .getDOMNode()
53 | .getAttribute('transform'),
54 | ).to.equal('translate(0,210)');
55 | expect(rendered.at(2).props().rotate).to.equal(true);
56 | expect(
57 | rendered
58 | .at(2)
59 | .getDOMNode()
60 | .getAttribute('transform'),
61 | ).to.equal('translate(250,220)');
62 | expect(rendered.at(3).props().rotate).to.equal(true);
63 | expect(
64 | rendered
65 | .at(3)
66 | .find('text')
67 | .first()
68 | .getDOMNode()
69 | .getAttribute('transform'),
70 | ).to.equal('rotate(-90)');
71 | expect(
72 | rendered
73 | .at(4)
74 | .getDOMNode()
75 | .getAttribute('transform'),
76 | ).to.equal('translate(0,-5)');
77 | expect(
78 | rendered
79 | .at(5)
80 | .getDOMNode()
81 | .getAttribute('transform'),
82 | ).to.equal('translate(0,5)');
83 | expect(
84 | rendered
85 | .at(6)
86 | .getDOMNode()
87 | .getAttribute('transform'),
88 | ).to.equal('translate(0,-5)');
89 | expect(
90 | rendered
91 | .at(6)
92 | .find('text')
93 | .first()
94 | .getDOMNode()
95 | .getAttribute('transform'),
96 | ).to.equal('rotate(-90)');
97 | });
98 | });
99 |
--------------------------------------------------------------------------------
/tests/browser/webpack.config.test.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const HtmlPlugin = require('html-webpack-plugin');
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5 |
6 | module.exports = {
7 | mode: 'development',
8 | context: __dirname,
9 | entry: [path.join(__dirname, 'index.js')],
10 | output: {
11 | path: path.join(__dirname, 'build'),
12 | filename: 'bundle.[hash].js',
13 | },
14 | devtool: 'source-map',
15 | plugins: [
16 | new webpack.NoEmitOnErrorsPlugin(),
17 | new HtmlPlugin({
18 | title: 'Reactochart Tests',
19 | template: path.join(__dirname, 'index_html.ejs'),
20 | }),
21 | new CleanWebpackPlugin(),
22 | ],
23 | resolve: {
24 | extensions: ['.js', '.jsx'],
25 | modules: ['node_modules', path.resolve(__dirname, '../..')],
26 | },
27 | module: {
28 | rules: [
29 | {
30 | test: /\.jsx?$/,
31 | exclude: /node_modules/,
32 | use: 'babel-loader',
33 | },
34 | {
35 | test: /\.less?$/,
36 | use: [
37 | { loader: 'style-loader' },
38 | { loader: 'css-loader' },
39 | { loader: 'less-loader' },
40 | ],
41 | }
42 | ],
43 | },
44 | // https://github.com/airbnb/enzyme/issues/503
45 | externals: {
46 | jsdom: 'window',
47 | cheerio: 'window',
48 | 'react/lib/ExecutionEnvironment': true,
49 | 'react/addons': true,
50 | 'react/lib/ReactContext': 'window',
51 | },
52 | };
53 |
--------------------------------------------------------------------------------
/tests/jsdom/setup.js:
--------------------------------------------------------------------------------
1 | import "jest-canvas-mock";
2 |
3 | // see https://github.com/airbnb/enzyme/blob/master/docs/guides/jsdom.md
4 | const { JSDOM } = require('jsdom');
5 |
6 | const jsdom = new JSDOM('', {
7 | url: 'http://localhost',
8 | });
9 | const { window } = jsdom;
10 |
11 | function copyProps(src, target) {
12 | Object.defineProperties(target, {
13 | ...Object.getOwnPropertyDescriptors(src),
14 | ...Object.getOwnPropertyDescriptors(target),
15 | });
16 | }
17 |
18 | global.window = window;
19 | global.document = window.document;
20 | global.navigator = {
21 | userAgent: 'node.js',
22 | };
23 | global.requestAnimationFrame = function(callback) {
24 | return setTimeout(callback, 0);
25 | };
26 | global.cancelAnimationFrame = function(id) {
27 | clearTimeout(id);
28 | };
29 | copyProps(window, global);
30 |
31 | // hack to deal with https://github.com/airbnb/enzyme/issues/888
32 | // see also https://github.com/chaijs/type-detect/issues/98
33 | global.HTMLElement = window.HTMLElement;
34 | global.SVGElement = function() {};
35 |
36 | const enzyme = require('enzyme');
37 | const adapter = require('enzyme-adapter-react-16');
38 |
39 | enzyme.configure({ adapter: new adapter() });
40 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/AreaHeatmap.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import _ from 'lodash';
4 | import { mount } from 'enzyme';
5 |
6 | import { AreaHeatmap } from '../../../src';
7 |
8 | describe('AreaHeatmap', () => {
9 | const gridData = _.range(30).map(m => {
10 | return _.range(30).map(n => {
11 | return {
12 | x: n,
13 | xEnd: n + 1,
14 | y: m,
15 | yEnd: m + 1,
16 | value: Math.sin(m * n * 0.01),
17 | };
18 | });
19 | });
20 | const data = _.flatten(gridData);
21 | const props = {
22 | data,
23 | area: d => d.value,
24 | x: d => d.x,
25 | xEnd: d => d.xEnd,
26 | y: d => d.y,
27 | yEnd: d => d.yEnd,
28 | rectClassName: 'rect-class',
29 | xScale: scaleLinear()
30 | .domain([-1, 0, 1])
31 | .range([0, 30]),
32 | yScale: scaleLinear()
33 | .domain([0, 10])
34 | .range([0, 30]),
35 | onMouseMove: jest.fn(),
36 | onMouseEnter: jest.fn(),
37 | onMouseLeave: jest.fn(),
38 | rectStyle: { fill: 'rebeccapurple' },
39 | };
40 |
41 | it('renders a color heatmap', () => {
42 | const chart = mount( );
43 | const group = chart.find('g.rct-area-heatmap-chart');
44 | expect(group).toHaveLength(1);
45 | expect(group.find('rect').length).toBeGreaterThan(1);
46 | });
47 |
48 | it('passes props correctly', () => {
49 | const chart = mount( );
50 | const lastRect = chart.find('rect').last();
51 |
52 | expect(typeof chart.props().onMouseMove).toBe('function');
53 | expect(typeof chart.props().onMouseEnter).toBe('function');
54 | expect(typeof chart.props().onMouseLeave).toBe('function');
55 |
56 | expect(typeof lastRect.props().x).toBe('number');
57 | expect(typeof lastRect.props().y).toBe('number');
58 | expect(typeof lastRect.props().width).toBe('number');
59 | expect(typeof lastRect.props().height).toBe('number');
60 | expect(lastRect.props().className).toContain(props.rectClassName);
61 | expect(lastRect.props().style).toEqual(props.rectStyle);
62 | });
63 |
64 | it('triggers event handlers', () => {
65 | const chart = mount( );
66 | expect(chart.props().onMouseMove).not.toHaveBeenCalled();
67 | chart.simulate('mousemove');
68 | expect(chart.props().onMouseMove).toHaveBeenCalled();
69 | expect(chart.props().onMouseEnter).not.toHaveBeenCalled();
70 | chart.simulate('mouseenter');
71 | expect(chart.props().onMouseEnter).toHaveBeenCalled();
72 | expect(chart.props().onMouseLeave).not.toHaveBeenCalled();
73 | chart.simulate('mouseleave');
74 | expect(chart.props().onMouseLeave).toHaveBeenCalled();
75 | });
76 | });
77 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/AriaLabelContainer.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { mount } from 'enzyme';
3 | import { scaleLinear } from 'd3-scale';
4 |
5 | import { AriaLabelContainer } from '../../../src';
6 |
7 | const onKeyDown = jest.fn();
8 | const ariaLabelGenerator = xValue => `xValue: ${xValue}`;
9 | const data0 = [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }, { x: 4, y: 0 }];
10 | const data1 = [{ val: 0, y: 0 }, { val: 1, y: 0 }, { val: 2, y: 0 }];
11 | const props = {
12 | ariaLabelGenerator,
13 | onKeyDown,
14 | height: 50,
15 | width: 100,
16 | xScale: scaleLinear()
17 | .domain([0, 4])
18 | .range([0, 100]),
19 | datasetWithAccessor: [
20 | {
21 | data: data0,
22 | accessor: d => d.x,
23 | },
24 | ],
25 | };
26 |
27 | const numFrames = data0.length;
28 |
29 | describe('AriaLabelContainer', () => {
30 | beforeEach(() => {
31 | jest.clearAllMocks();
32 | });
33 |
34 | it('renders and passes props correctly to AriaLabelContainer', () => {
35 | const chart = mount( );
36 | const group = chart.find('g');
37 | const rects = chart.find('rect');
38 |
39 | expect(group).toHaveLength(1);
40 | expect(rects).toHaveLength(numFrames);
41 |
42 | expect(rects.at(0).props().height).toEqual(props.height);
43 | expect(rects.at(0).props().width).toEqual(props.width / (numFrames - 1));
44 | expect(rects.at(0).props()['aria-label']).toEqual(
45 | ariaLabelGenerator(data0[0].x),
46 | );
47 | });
48 |
49 | it('renders the last rect at the same position as the second-to-last if last value is end of domain', () => {
50 | const chart = mount( );
51 | const rects = chart.find('rect');
52 |
53 | expect(rects.at(numFrames - 1).props().x).toEqual(
54 | rects.at(numFrames - 2).props().x,
55 | );
56 | });
57 |
58 | it('renders the last rect at a different location if before the end of the domain', () => {
59 | const chart = mount(
60 | d.val }]}
63 | />,
64 | );
65 | const rects = chart.find('rect');
66 |
67 | expect(rects.at(data1.length - 1).props().x).not.toEqual(
68 | rects.at(data1.length - 2).props().x,
69 | );
70 | });
71 |
72 | it('renders the proper amount of rectangles given two datasets', () => {
73 | const chart = mount(
74 | d.val },
79 | ]}
80 | />,
81 | );
82 | const rects = chart.find('rect');
83 |
84 | expect(rects).toHaveLength(5);
85 | });
86 |
87 | it('triggers an action on key press', () => {
88 | const chart = mount( );
89 | const rects = chart.find('rect');
90 | expect(onKeyDown).not.toHaveBeenCalled();
91 | rects.at(0).simulate('keydown');
92 | expect(onKeyDown).toHaveBeenCalled();
93 | });
94 | });
95 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/ColorHeatmap.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import _ from 'lodash';
4 | import { mount } from 'enzyme';
5 |
6 | import { ColorHeatmap, RangeRect } from '../../../src';
7 | import { getValue } from '../../../src/utils/Data.js';
8 |
9 | describe('ColorHeatmap', () => {
10 | const gridData = _.range(30).map(m => {
11 | return _.range(30).map(n => {
12 | return {
13 | x: n,
14 | xEnd: n + 1,
15 | y: m,
16 | yEnd: m + 1,
17 | value: Math.sin(m * n * 0.01),
18 | };
19 | });
20 | });
21 | const data = _.flatten(gridData);
22 | const props = {
23 | data,
24 | value: d => d.value,
25 | x: d => d.x,
26 | xEnd: d => d.xEnd,
27 | y: d => d.y,
28 | yEnd: d => d.yEnd,
29 | xScale: scaleLinear()
30 | .domain([-1, 0, 1])
31 | .range([0, 30]),
32 | yScale: scaleLinear()
33 | .domain([0, 10])
34 | .range([0, 30]),
35 | colors: ['rebeccapurple', 'goldenrod'],
36 | interpolator: 'lab',
37 | rectClassName: 'rect-class',
38 | };
39 |
40 | it('renders a color heatmap', () => {
41 | const chart = mount( );
42 | const rangeRects = chart.find(RangeRect);
43 | expect(rangeRects).toHaveLength(props.data.length);
44 | });
45 |
46 | it('passes props correctly', () => {
47 | const chart = mount( );
48 |
49 | expect(
50 | chart
51 | .find(RangeRect)
52 | .first()
53 | .props().x,
54 | ).toEqual(getValue(props.x, props.data[0]));
55 | expect(
56 | chart
57 | .find(RangeRect)
58 | .first()
59 | .props().xEnd,
60 | ).toEqual(getValue(props.xEnd, props.data[0]));
61 | expect(
62 | chart
63 | .find(RangeRect)
64 | .first()
65 | .props().y,
66 | ).toEqual(getValue(props.y, props.data[0]));
67 | expect(
68 | chart
69 | .find(RangeRect)
70 | .first()
71 | .props().yEnd,
72 | ).toEqual(getValue(props.yEnd, props.data[0]));
73 | expect(
74 | chart
75 | .find(RangeRect)
76 | .first()
77 | .props().xScale,
78 | ).toEqual(props.xScale);
79 | expect(
80 | chart
81 | .find(RangeRect)
82 | .first()
83 | .props().yScale,
84 | ).toEqual(props.yScale);
85 | expect(
86 | chart
87 | .find(RangeRect)
88 | .first()
89 | .props().className,
90 | ).toEqual(props.rectClassName);
91 | });
92 |
93 | it('sets the color scale to the prop value when colorScale prop is passed', () => {
94 | const propsWithColorScale = { ...props, colorScale: () => 'rgb' };
95 | const updatedChart = mount( );
96 |
97 | expect(
98 | updatedChart
99 | .find(RangeRect)
100 | .first()
101 | .props().style,
102 | ).toHaveProperty('fill', 'rgb');
103 | });
104 | });
105 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/FunnelChart.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import { mount } from 'enzyme';
4 |
5 | import { FunnelChart } from '../../../src';
6 |
7 | describe('FunnelChart', () => {
8 | const funnelData = [
9 | { observation: 1, value: 100 },
10 | { observation: 2, value: 85 },
11 | { observation: 3, value: 42 },
12 | { observation: 4, value: 37 },
13 | { observation: 5, value: 12 },
14 | ];
15 |
16 | const props = {
17 | data: funnelData,
18 | x: d => d.value,
19 | y: d => d.observation,
20 | pathClassName: 'path-class',
21 | horizontal: true,
22 | xScale: scaleLinear()
23 | .domain([-1, 0, 1])
24 | .range([0, 30]),
25 | yScale: scaleLinear()
26 | .domain([0, 10])
27 | .range([0, 30]),
28 | pathStyle: { fill: 'yellow' },
29 | };
30 |
31 | it('renders a funnel chart', () => {
32 | const chart = mount( );
33 | const group = chart.find('g.rct-funnel-chart');
34 | expect(group).toHaveLength(1);
35 | expect(group.find('path')).toHaveLength(props.data.length - 1);
36 |
37 | group.find('path').forEach(path => {
38 | const pathD = path.instance().getAttribute('d');
39 |
40 | expect(pathD).not.toContain('NaN');
41 | });
42 |
43 | const lastPath = group.find('path').last();
44 | const pathData = lastPath.instance().getAttribute('d');
45 | expect(pathData).toEqual('M1140,12L390,15L-330,15L-1080,12Z');
46 | });
47 |
48 | it('passes props correctly', () => {
49 | const chart = mount( );
50 | const lastPath = chart.find('path').last();
51 | expect(lastPath.props().className).toContain(props.pathClassName);
52 | expect(lastPath.props().style).toHaveProperty('fill', props.pathStyle.fill);
53 | expect(typeof lastPath.props().d).toBe('string');
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/Histogram.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import _ from 'lodash';
4 | import { mount } from 'enzyme';
5 |
6 | import { expectProps } from '../utils';
7 | import { Histogram, AreaBarChart } from '../../../src';
8 |
9 | describe('Histogram', () => {
10 | it('it passes most props through to AreaBarChart', () => {
11 | // histogram is a wrapper around AreaBarChart
12 | const props = {
13 | xScale: scaleLinear()
14 | .domain([-1, 0, 1])
15 | .range([0, 100]),
16 | yScale: scaleLinear()
17 | .domain([0, 10])
18 | .range([100, 0]),
19 | data: [-1, 0, 1, -1, 0, 1, 1, 1],
20 | value: x => {
21 | return x;
22 | },
23 | thresholds: 3,
24 | nice: true,
25 | barClassName: 'test-bar-class-name',
26 | barStyle: { fill: 'red' },
27 | onMouseEnterBar: () => 'onMouseEnterBar',
28 | onMouseMoveBar: () => 'onMouseMoveBar',
29 | onMouseLeaveBar: () => 'onMouseLeaveBar',
30 | };
31 |
32 | const histogram = mount( );
33 | const areaBarChart = histogram.find(AreaBarChart);
34 |
35 | const parsedProps = {
36 | ...props,
37 | data: Histogram.computeHistogram(
38 | props.data,
39 | props.thresholds,
40 | props.value,
41 | null,
42 | props.nice,
43 | ),
44 | };
45 |
46 | // Omit data since expectProps will check for reference equality on the data instead of
47 | expectProps(areaBarChart, _.omit(parsedProps, ['data']));
48 | // Check value of data prop is equal
49 | expect(areaBarChart.props().data).toEqual(parsedProps.data);
50 | });
51 |
52 | it('renders histogram', () => {
53 | // histogram is a wrapper around AreaBarChart
54 | const props = {
55 | xScale: scaleLinear()
56 | .domain([-1, 0, 1])
57 | .range([0, 100]),
58 | yScale: scaleLinear()
59 | .domain([0, 10])
60 | .range([100, 0]),
61 | data: [-1, 0, 1, -1, 0, 1, 1, 1],
62 | value: x => {
63 | return x;
64 | },
65 | nice: true,
66 | thresholds: 3,
67 | barClassName: 'test-bar-class-name',
68 | barStyle: { fill: 'red' },
69 | onMouseEnterBar: () => 'onMouseEnterBar',
70 | onMouseMoveBar: () => 'onMouseMoveBar',
71 | onMouseLeaveBar: () => 'onMouseLeaveBar',
72 | };
73 |
74 | const histogram = mount( );
75 | const group = histogram.find('g');
76 | const bars = group.find('rect');
77 |
78 | // histogram creates 4 bars
79 | expect(bars).toHaveLength(4);
80 | });
81 | });
82 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/RangeBarChart.spec.js:
--------------------------------------------------------------------------------
1 | import { scaleLinear, scalePoint } from 'd3-scale';
2 | import { mount } from 'enzyme';
3 | import React from 'react';
4 | import { Bar, RangeBarChart } from '../../../src';
5 |
6 | describe('RangeBarChart', () => {
7 | const props = {
8 | xScale: scalePoint()
9 | .domain(['a', 'b', 'c'])
10 | .range([0, 100]),
11 | yScale: scaleLinear()
12 | .domain([0, 1])
13 | .range([100, 0]),
14 | data: [['a', [0.3, 0.5]], ['b', [0.6, 0.9]]],
15 | x: d => d[0],
16 | y: d => d[1][0],
17 | yEnd: d => d[1][1],
18 | barThickness: 10,
19 | barClassName: 'my-bar',
20 | barStyle: { fill: 'blue' },
21 | onMouseEnterBar: jest.fn(),
22 | onMouseMoveBar: jest.fn(),
23 | onMouseLeaveBar: jest.fn(),
24 | onClick: jest.fn(),
25 | };
26 |
27 | it('passes props to Bar elements', () => {
28 | const chart = mount( );
29 | const bars = chart.find('rect');
30 |
31 | bars.forEach(bar => {
32 | expect(bar.props().className).toContain(props.barClassName);
33 | expect(bar.props().style).toEqual(props.barStyle);
34 | });
35 | });
36 |
37 | it('renders a bar chart with categorical X data & numerical Y data', () => {
38 | // make simple bar chart with 3 datapoints to make sure it renders correctly
39 | // this is more of an integration test/sanity check;
40 | // most tests for render correctness are in RangeRect and Bar specs
41 | const chart = mount( );
42 | const group = chart.find('g');
43 | const bars = chart.find('rect');
44 | expect(group).toHaveLength(1);
45 | expect(bars).toHaveLength(2);
46 |
47 | expect(bars.at(0).props().x).toEqual(0 - props.barThickness / 2);
48 | expect(bars.at(0).props().width).toEqual(props.barThickness);
49 | expect(bars.at(0).props().y).toEqual(50);
50 | expect(bars.at(0).props().height).toEqual(20);
51 |
52 | expect(bars.at(1).props().x).toEqual(50 - props.barThickness / 2);
53 | expect(bars.at(1).props().width).toEqual(props.barThickness);
54 | expect(Math.round(bars.at(1).props().y)).toEqual(10);
55 | expect(bars.at(1).props().height).toEqual(30);
56 | });
57 |
58 | it('triggers event handlers', () => {
59 | const chart = mount( );
60 | const bars = chart.find(Bar);
61 |
62 | expect(props.onMouseMoveBar).not.toHaveBeenCalled();
63 | bars.at(1).simulate('mousemove');
64 | expect(props.onMouseMoveBar).toHaveBeenCalled();
65 |
66 | expect(props.onMouseEnterBar).not.toHaveBeenCalled();
67 | bars.at(1).simulate('mouseenter');
68 | expect(props.onMouseEnterBar).toHaveBeenCalled();
69 |
70 | expect(props.onMouseLeaveBar).not.toHaveBeenCalled();
71 | bars.at(1).simulate('mouseleave');
72 | expect(props.onMouseLeaveBar).toHaveBeenCalled();
73 |
74 | expect(props.onClick).not.toHaveBeenCalled();
75 | bars.at(1).simulate('click');
76 | expect(props.onClick).toHaveBeenCalled();
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/ScatterPlot.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import { mount } from 'enzyme';
4 | import { ScatterPlot } from '../../../src';
5 |
6 | describe('ScatterPlot', () => {
7 | const props = {
8 | data: [[0, 0], [2, 1], [5, 1], [3, 5], [4, 2], [5, 5], [1, 4]],
9 | x: d => d[0],
10 | y: d => d[1],
11 | pointClassName: 'my-point',
12 | pointStyle: { fill: 'blue' },
13 | xScale: scaleLinear().domain([0, 5]),
14 | yScale: scaleLinear().domain([0, 5]),
15 | onMouseEnterPoint: jest.fn(),
16 | onMouseMovePoint: jest.fn(),
17 | onMouseLeavePoint: jest.fn(),
18 | pointOffset: [2, 2],
19 | };
20 |
21 | it('passes props correctly to points', () => {
22 | let chart = mount( );
23 | let points = chart.find('circle');
24 |
25 | points.forEach(point => {
26 | expect(point.props().className).toContain(props.pointClassName);
27 | expect(point.props().style).toEqual(props.pointStyle);
28 | });
29 |
30 | chart = mount( 'a'} />);
31 | points = chart.find('text');
32 |
33 | points.forEach(point => {
34 | expect(point.props().className).toContain(props.pointClassName);
35 | expect(point.props().style).toEqual({
36 | textAnchor: 'middle',
37 | dominantBaseline: 'central',
38 | ...props.pointStyle,
39 | });
40 | });
41 | });
42 |
43 | it('renders correct amount of points in correct area', () => {
44 | const chart = mount( );
45 | const points = chart.find('circle');
46 |
47 | expect(points).toHaveLength(props.data.length);
48 |
49 | points.forEach((point, idx) => {
50 | const { xScale, yScale, data, x, y, pointOffset } = props;
51 | const xPos = xScale(x(data[idx])) + pointOffset[0];
52 | const yPos = yScale(y(data[idx])) + pointOffset[1];
53 |
54 | expect(point.props().cx).toEqual(xPos);
55 | expect(point.props().cy).toEqual(yPos);
56 | });
57 | });
58 |
59 | it('triggers event handlers', () => {
60 | const chart = mount( );
61 | const points = chart.find('circle');
62 |
63 | expect(props.onMouseMovePoint).not.toHaveBeenCalled();
64 | points.at(1).simulate('mousemove');
65 | expect(props.onMouseMovePoint).toHaveBeenCalled();
66 | expect(props.onMouseEnterPoint).not.toHaveBeenCalled();
67 | points.at(1).simulate('mouseenter');
68 | expect(props.onMouseEnterPoint).toHaveBeenCalled();
69 | expect(props.onMouseLeavePoint).not.toHaveBeenCalled();
70 | points.at(1).simulate('mouseleave');
71 | expect(props.onMouseLeavePoint).toHaveBeenCalled();
72 | });
73 | });
74 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/TreeMap.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import { mount } from 'enzyme';
4 |
5 | import { TreeMap } from '../../../src';
6 | import TreeMapNode from '../../../src/TreeMapNode.js';
7 | import TreeMapNodeLabel from '../../../src/TreeMapNodeLabel.js';
8 |
9 | describe('TreeMap', () => {
10 | const data = {
11 | children: _.range(1, 5).map(n => ({
12 | size: n * 5,
13 | name: `Name: ${n}`,
14 | })),
15 | };
16 |
17 | const props = {
18 | data,
19 | nodeStyle: { border: '1px solid #333' },
20 | getLabel: d => d.name,
21 | getValue: d => d.size,
22 | onClickNode: jest.fn(),
23 | onMouseEnterNode: jest.fn(),
24 | onMouseLeaveNode: jest.fn(),
25 | onMouseMoveNode: jest.fn(),
26 | width: 400,
27 | height: 500,
28 | };
29 |
30 | it('passes props correctly to nodes', () => {
31 | const chart = mount( );
32 | const nodes = chart.find(TreeMapNode);
33 |
34 | nodes.forEach(node => {
35 | expect(node.props().nodeStyle.border).toEqual(props.nodeStyle.border);
36 | });
37 | });
38 |
39 | it('renders correct amount of nodes and labels', () => {
40 | const chart = mount( );
41 | const nodes = chart.find(TreeMapNode);
42 |
43 | expect(nodes).toHaveLength(5);
44 |
45 | nodes.forEach(node => {
46 | expect(node.find(TreeMapNodeLabel)).toHaveLength(1);
47 | });
48 | });
49 |
50 | it('recreates tree when sticky is false, and keeps tree when true', () => {
51 | let chart = mount( );
52 | let tree = chart.instance().state.tree;
53 |
54 | chart.setProps({ data });
55 | expect(tree).not.toEqual(chart.instance().state.tree);
56 |
57 | chart = mount( );
58 | tree = chart.instance().state.tree;
59 | chart.setProps({ data });
60 | expect(tree).toEqual(chart.instance().state.tree);
61 | });
62 |
63 | it('triggers event handlers', () => {
64 | const chart = mount( );
65 | const nodes = chart.find(TreeMapNode);
66 |
67 | expect(props.onMouseMoveNode).not.toHaveBeenCalled();
68 | nodes.at(1).simulate('mousemove');
69 | expect(props.onMouseMoveNode).toHaveBeenCalled();
70 | expect(props.onMouseEnterNode).not.toHaveBeenCalled();
71 | nodes.at(1).simulate('mouseenter');
72 | expect(props.onMouseEnterNode).toHaveBeenCalled();
73 | expect(props.onMouseLeaveNode).not.toHaveBeenCalled();
74 | nodes.at(1).simulate('mouseleave');
75 | expect(props.onMouseLeaveNode).toHaveBeenCalled();
76 | });
77 | });
78 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/XGrid.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import { mount } from 'enzyme';
4 |
5 | import { XGrid, XLine } from '../../../src';
6 | import { getScaleTicks, getTickDomain } from '../../../src/utils/Scale';
7 |
8 | describe('XGrid', () => {
9 | const props = {
10 | height: 10,
11 | spacingTop: 10,
12 | spacingBottom: 10,
13 | spacingLeft: 10,
14 | spacingRight: 10,
15 | lineClassName: 'xgrid-line-class',
16 | lineStyle: { stroke: 'blue' },
17 | xScale: scaleLinear().domain([0, 100]),
18 | };
19 |
20 | it('passes props correctly to XLine', () => {
21 | const xGrid = mount( );
22 | const xLines = xGrid.find(XLine);
23 | const group = xGrid.find('g');
24 |
25 | expect(group).toHaveLength(1);
26 | expect(group.getDOMNode().className).toEqual('rct-chart-grid-x');
27 |
28 | xLines.forEach(xLine => {
29 | const xLineProps = xLine.props();
30 |
31 | expect(xLineProps.className).toContain(props.lineClassName);
32 | expect(xLineProps.style).toEqual(props.lineStyle);
33 | expect(xLineProps.spacingTop).toEqual(props.spacingTop);
34 | expect(xLineProps.spacingBottom).toEqual(props.spacingBottom);
35 | expect(xLineProps.spacingLeft).toEqual(props.spacingLeft);
36 | expect(xLineProps.spacingRight).toEqual(props.spacingRight);
37 | expect(xLineProps.xScale).toEqual(props.xScale);
38 | expect(xLineProps.height).toEqual(props.height);
39 | });
40 | });
41 |
42 | it('renders the correct amount of XLines given tickCount', () => {
43 | const tickCount = 50;
44 | const xGrid = mount( );
45 | const group = xGrid.find('g');
46 |
47 | expect(group).toHaveLength(1);
48 | expect(group.getDOMNode().className).toEqual('rct-chart-grid-x');
49 |
50 | const xLines = xGrid.find(XLine);
51 | const numTicksMade = getScaleTicks(props.xScale, null, tickCount);
52 |
53 | expect(xLines).toHaveLength(numTicksMade.length);
54 | });
55 |
56 | it('renders the correct amount of XLines given ticks', () => {
57 | const ticks = [0, 25, 50, 100];
58 | const xGrid = mount( );
59 | const group = xGrid.find('g');
60 |
61 | expect(group).toHaveLength(1);
62 | expect(group.getDOMNode().className).toEqual('rct-chart-grid-x');
63 |
64 | const xLines = xGrid.find(XLine);
65 | expect(xLines).toHaveLength(ticks.length);
66 | });
67 |
68 | it('getTickDomain works as expected', () => {
69 | const ticks = [0, 25, 50, 100];
70 |
71 | const result = getTickDomain(props.xScale, { ...props, ticks });
72 |
73 | expect(XGrid.getTickDomain({ ...props, ticks })).toEqual({
74 | xTickDomain: result,
75 | });
76 | });
77 | });
78 |
--------------------------------------------------------------------------------
/tests/jsdom/spec/YGrid.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { scaleLinear } from 'd3-scale';
3 | import { mount } from 'enzyme';
4 |
5 | import { YGrid, YLine } from '../../../src/index.js';
6 | import { getScaleTicks, getTickDomain } from '../../../src/utils/Scale';
7 |
8 | describe('YGrid', () => {
9 | const props = {
10 | width: 10,
11 | spacingTop: 10,
12 | spacingBottom: 10,
13 | spacingLeft: 10,
14 | spacingRight: 10,
15 | lineClassName: 'ygrid-line-class',
16 | lineStyle: { stroke: 'blue' },
17 | yScale: scaleLinear().domain([0, 100]),
18 | };
19 |
20 | it('passes props correctly to YLine', () => {
21 | const yGrid = mount( );
22 | const yLines = yGrid.find(YLine);
23 |
24 | yLines.forEach(yLine => {
25 | const yLineProps = yLine.props();
26 |
27 | expect(yLineProps.className).toContain(props.lineClassName);
28 | expect(yLineProps.style).toEqual(props.lineStyle);
29 | expect(yLineProps.spacingTop).toEqual(props.spacingTop);
30 | expect(yLineProps.spacingBottom).toEqual(props.spacingBottom);
31 | expect(yLineProps.spacingLeft).toEqual(props.spacingLeft);
32 | expect(yLineProps.spacingRight).toEqual(props.spacingRight);
33 | expect(yLineProps.yScale).toEqual(props.yScale);
34 | expect(yLineProps.width).toEqual(props.width);
35 | });
36 | });
37 |
38 | it('renders the correct amount of YLines given tickCount', () => {
39 | const tickCount = 50;
40 | const yGrid = mount( );
41 | const group = yGrid.find('g');
42 |
43 | expect(group).toHaveLength(1);
44 | expect(group.getDOMNode().className).toEqual('rct-chart-grid-y');
45 |
46 | const yLines = yGrid.find(YLine);
47 | const numTicksMade = getScaleTicks(props.yScale, null, tickCount);
48 |
49 | expect(yLines).toHaveLength(numTicksMade.length);
50 | });
51 |
52 | it('renders the correct amount of YLines given ticks', () => {
53 | const ticks = [0, 25, 50, 100];
54 | const yGrid = mount( );
55 | const group = yGrid.find('g');
56 |
57 | expect(group).toHaveLength(1);
58 | expect(group.getDOMNode().className).toEqual('rct-chart-grid-y');
59 |
60 | const yLines = yGrid.find(YLine);
61 | expect(yLines).toHaveLength(ticks.length);
62 | });
63 |
64 | it('getTickDomain works as expected', () => {
65 | const ticks = [0, 25, 50, 100];
66 |
67 | const result = getTickDomain(props.yScale, { ...props, ticks });
68 |
69 | expect(YGrid.getTickDomain({ ...props, ticks })).toEqual({
70 | yTickDomain: result,
71 | });
72 | });
73 | });
74 |
--------------------------------------------------------------------------------
/tests/jsdom/utils.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import { scaleLinear, scalePoint } from 'd3-scale';
3 |
4 | export function expectProps(el, expectedProps) {
5 | const props = el.props();
6 | _.forEach(expectedProps, (expectedValue, key) => {
7 | expect(props[key]).toEqual(expectedValue);
8 | });
9 | }
10 |
11 | export function testWithScales(scaleTypes, callback) {
12 | const testScales = {
13 | linear: {
14 | scale: scaleLinear()
15 | .domain([-3, 3])
16 | .range([20, 100]),
17 | testValues: [-1.4, 1.7, 2.8],
18 | },
19 | // time: {},
20 | ordinal: {
21 | scale: scalePoint()
22 | .domain(['a', 'b', 'c', 'd', 'e'])
23 | .range([0, 100]),
24 | testValues: ['a', 'c', 'e'],
25 | },
26 | };
27 |
28 | scaleTypes.forEach(scaleType => {
29 | if (!_.has(testScales, scaleType))
30 | throw new Error(
31 | `${scaleType} is not a valid scaleType for testWithScales`,
32 | );
33 | });
34 |
35 | const scalesToTest = _.compact(
36 | scaleTypes.map(scaleType => testScales[scaleType]),
37 | );
38 | scalesToTest.forEach((scaleInfo, scaleType) => {
39 | callback({ ...scaleInfo, scaleType });
40 | });
41 | }
42 |
--------------------------------------------------------------------------------
/webpack.config.base.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlPlugin = require('html-webpack-plugin');
3 | const CopyPlugin = require('copy-webpack-plugin');
4 |
5 | module.exports = {
6 | mode: 'development',
7 | context: __dirname,
8 | entry: ['./docs/src/main.js'],
9 | output: {
10 | path: path.join(__dirname, 'docs/build'),
11 | filename: 'bundle.[hash].js',
12 | },
13 | devServer: {
14 | port: 9876,
15 | static: {
16 | directory: path.join(__dirname, 'docs/build'),
17 | },
18 | },
19 | devtool: 'source-map',
20 | module: {
21 | rules: [
22 | {
23 | use: 'babel-loader',
24 | test: /\.jsx?$/,
25 | exclude: /node_modules/,
26 | },
27 | {
28 | test: /\.less?$/,
29 | use: [
30 | { loader: 'style-loader' },
31 | { loader: 'css-loader' },
32 | { loader: 'less-loader' },
33 | ],
34 | },
35 | {
36 | test: /\.js.example/,
37 | use: 'raw-loader',
38 | },
39 | ],
40 | },
41 | optimization: {
42 | emitOnErrors: false,
43 | },
44 | plugins: [
45 | new HtmlPlugin({
46 | // put built html file in /docs/index.html ('../' because relative to /docs/build)
47 | // filename: path.join(__dirname, 'docs/index.html'),
48 | title: 'Reactochart Docs',
49 | template: 'docs/src/index_html.ejs',
50 | }),
51 | new CopyPlugin({
52 | patterns: [{ from: path.join(__dirname, 'docs/assets'), to: 'assets' }],
53 | }),
54 | ],
55 | resolve: {
56 | extensions: ['.js', '.jsx'],
57 | },
58 | };
59 |
--------------------------------------------------------------------------------
/webpack.config.build.js:
--------------------------------------------------------------------------------
1 | // This webpack file is used for the documentation build
2 |
3 | const _ = require('lodash');
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5 |
6 | let config = require('./webpack.config.base');
7 |
8 | config = _.merge(config, {
9 | mode: 'production',
10 | plugins: config.plugins.concat([new CleanWebpackPlugin()]),
11 | });
12 |
13 | module.exports = config;
14 |
--------------------------------------------------------------------------------