├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── etc
├── bar_graph_1.gif
└── donut.gif
├── example
├── .eslintrc
├── .gitignore
├── README.md
├── demo.jsx
├── index.html
└── package.json
├── gulpfile.babel.js
├── package.json
└── src
├── BarChart.jsx
├── Chart.jsx
├── Colors.js
├── DataSeries.jsx
├── Group.jsx
├── Pie.jsx
├── Stack.jsx
├── XAxis.jsx
├── YAxis.jsx
├── constants.js
├── helpers
├── axes.js
└── scales.js
├── index.js
├── styles.js
└── util.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "react",
5 | "stage-1"
6 | ],
7 | "plugins": [
8 |
9 | ],
10 | "ignore": [
11 | "build"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 4
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # Transpiled javascript
2 | build/
3 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "browser": true,
5 | "node": true
6 | },
7 | "parserOptions": {
8 | "ecmaVersion": 6,
9 | "sourceType": "module",
10 | "ecmaFeatures": {
11 | "arrowFunctions": true,
12 | "binaryLiterals": true,
13 | "blockBindings": true,
14 | "classes": true,
15 | "defaultParams": true,
16 | "destructuring": true,
17 | "forOf": true,
18 | "generators": true,
19 | "modules": true,
20 | "objectLiteralComputedProperties": true,
21 | "objectLiteralDuplicateProperties": true,
22 | "objectLiteralShorthandMethods": true,
23 | "objectLiteralShorthandProperties": true,
24 | "octalLiterals": true,
25 | "regexUFlag": false,
26 | "regexYFlag": false,
27 | "restParams": true,
28 | "spread": true,
29 | "superInFunctions": true,
30 | "templateStrings": true,
31 | "unicodeCodePointEscapes": true,
32 | "globalReturn": true,
33 | "jsx": true,
34 | "experimentalObjectRestSpread": true
35 | }
36 | },
37 | "rules": {
38 | "no-mixed-requires": [
39 | 0,
40 | false
41 | ],
42 | "strict": [
43 | 1,
44 | "never"
45 | ],
46 | "no-undef": 2,
47 | "no-delete-var": 2,
48 | "no-shadow": 2,
49 | "no-shadow-restricted-names": 2,
50 | "no-unused-vars": [
51 | 2,
52 | {
53 | "vars": "all",
54 | "args": "after-used"
55 | }
56 | ],
57 | "no-undefined": 2,
58 | "no-use-before-define": 2,
59 | "no-unneeded-ternary": 1,
60 | "no-obj-calls": 2,
61 | "no-negated-in-lhs": 2,
62 | "no-inner-declarations": 2,
63 | "curly": 1,
64 | "camelcase": 2,
65 | "max-len": [
66 | 1,
67 | 100,
68 | 4,
69 | {
70 | "ignoreComments": true,
71 | "ignoreUrls": true,
72 | "ignorePattern": "^\\s*import\\s+"
73 | }
74 | ],
75 | "padded-blocks": [
76 | 0,
77 | "always"
78 | ],
79 | "no-invalid-regexp": 2,
80 | "vars-on-top": 0,
81 | "guard-for-in": 1,
82 | "no-underscore-dangle": 0,
83 | "no-func-assign": 2,
84 | "no-extra-parens": 0,
85 | "no-loop-func": 1,
86 | "no-multi-spaces": 1,
87 | "comma-dangle": [
88 | 1,
89 | "never"
90 | ],
91 | "indent": [
92 | 2,
93 | 4,
94 | {
95 | "SwitchCase": 1,
96 | "VariableDeclarator": 1
97 | }
98 | ],
99 | "quotes": [
100 | 2,
101 | "single"
102 | ],
103 | "semi": [
104 | 2,
105 | "always"
106 | ],
107 | "semi-spacing": [
108 | 2,
109 | {
110 | "before": false,
111 | "after": true
112 | }
113 | ],
114 | "brace-style": [
115 | 2,
116 | "1tbs",
117 | {
118 | "allowSingleLine": true
119 | }
120 | ],
121 | "key-spacing": [
122 | 2,
123 | {
124 | "beforeColon": false,
125 | "afterColon": true
126 | }
127 | ],
128 | "new-cap": [
129 | 2,
130 | {
131 | "newIsCap": true,
132 | "capIsNew": true,
133 | "capIsNewExceptions": [
134 | "Immutable",
135 | "Set"
136 | ]
137 | }
138 | ],
139 | "keyword-spacing": [
140 | 2,
141 | {
142 | "before": true,
143 | "after": true
144 | }
145 | ],
146 | "space-before-blocks": [
147 | 1,
148 | "always"
149 | ],
150 | "array-bracket-spacing": [
151 | 2,
152 | "never"
153 | ],
154 | "object-curly-spacing": [
155 | 2,
156 | "never",
157 | {
158 | "objectsInObjects": false,
159 | "arraysInObjects": false
160 | }
161 | ],
162 | "computed-property-spacing": [
163 | 1,
164 | "never"
165 | ],
166 | "space-in-parens": [
167 | 1,
168 | "never"
169 | ],
170 | "space-before-function-paren": [
171 | 1,
172 | "never"
173 | ],
174 | "space-infix-ops": [
175 | 2,
176 | {
177 | "int32Hint": false
178 | }
179 | ],
180 | "max-nested-callbacks": [
181 | 2,
182 | 3
183 | ],
184 | "one-var": [
185 | 0,
186 | "always"
187 | ],
188 | "eqeqeq": [
189 | 2,
190 | "smart"
191 | ],
192 | "accessor-pairs": [
193 | 1,
194 | {
195 | "getWithoutSet": true
196 | }
197 | ],
198 | "no-cond-assign": [
199 | 2,
200 | "except-parens"
201 | ],
202 | "valid-typeof": 1,
203 | "no-div-regex": 2,
204 | "no-control-regex": 2,
205 | "no-caller": 2,
206 | "no-alert": 2,
207 | "no-with": 2,
208 | "no-duplicate-case": 2,
209 | "no-dupe-args": 2,
210 | "no-dupe-keys": 2,
211 | "no-unreachable": 2,
212 | "use-isnan": 2,
213 | "no-redeclare": [
214 | 2,
215 | {
216 | "builtinGlobals": true
217 | }
218 | ],
219 | "no-useless-call": 2,
220 | "no-void": 2,
221 | "no-new-wrappers": 2,
222 | "no-new-require": 2,
223 | "no-path-concat": 2,
224 | "no-lonely-if": 1,
225 | "no-array-constructor": 1,
226 | "no-unexpected-multiline": 2,
227 | "linebreak-style": [
228 | 2,
229 | "unix"
230 | ],
231 | "no-trailing-spaces": [
232 | 1,
233 | {
234 | "skipBlankLines": false
235 | }
236 | ],
237 | "eol-last": 2,
238 | "prefer-spread": 1,
239 | "no-this-before-super": 2,
240 | "constructor-super": 2,
241 | "prefer-const": 1,
242 | "no-bitwise": 1,
243 | "babel/generator-star-spacing": 1,
244 | "babel/new-cap": 0,
245 | "babel/object-curly-spacing": 1,
246 | "babel/object-shorthand": 1,
247 | "babel/arrow-parens": 0,
248 |
249 | "react/display-name": 2,
250 | "react/forbid-prop-types": 0,
251 | "react/jsx-boolean-value": 1,
252 | "react/jsx-closing-bracket-location": [
253 | 1,
254 | {
255 | "selfClosing": "after-props",
256 | "nonEmpty": "after-props"
257 | }
258 | ],
259 | "react/jsx-curly-spacing": 1,
260 | "react/jsx-indent-props": 1,
261 | "react/jsx-max-props-per-line": [
262 | 1,
263 | {
264 | "maximum": 3
265 | }
266 | ],
267 | "react/jsx-no-duplicate-props": 2,
268 | "react/jsx-no-literals": 1,
269 | "react/jsx-no-undef": 2,
270 | "jsx-quotes": [
271 | 1,
272 | "prefer-double"
273 | ],
274 | "react/sort-prop-types": 0,
275 | "react/jsx-sort-props": [
276 | 0,
277 | {
278 | "callbacksLast": true
279 | }
280 | ],
281 | "react/jsx-uses-react": 1,
282 | "react/jsx-uses-vars": 1,
283 | "react/no-danger": 1,
284 | "react/jsx-pascal-case": 1,
285 | "react/no-did-mount-set-state": 2,
286 | "react/no-did-update-set-state": 2,
287 | "react/no-direct-mutation-state": 2,
288 | "react/no-multi-comp": 0,
289 | "react/no-set-state": 0,
290 | "react/no-unknown-property": 2,
291 | "react/prop-types": 0,
292 | "react/react-in-jsx-scope": 2,
293 | "react/require-extension": 0,
294 | "react/self-closing-comp": 1,
295 | "react/sort-comp": 1,
296 | "react/wrap-multilines": 1
297 | },
298 | "plugins": [
299 | "babel",
300 | "react"
301 | ]
302 | }
303 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | build
4 | diffract-*.tgz
5 | # jsx Transform Disk Cache
6 | .module-cache
7 | .tmp
8 |
9 | # Exclude compiled files
10 | lib
11 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | docs
2 | example
3 | src
4 | node_modules
5 | etc
6 | lib
7 | *.tgz
8 | .*
9 | .*
10 | # jsx Transform Disk Cache
11 | .module-cache
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Amey Sakhadeo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # diffract
2 | [](http://badge.fury.io/js/diffract)
3 | [](https://david-dm.org/ameyms/diffract#info=devDependencies)
4 | [](https://david-dm.org/ameyms/diffract#info=peerDependencies)
5 |
6 | A set of d3 based visualization components with **cool animations** built for React
7 |
8 | Installation
9 | ---
10 | Diffract is available via npm and can be used along with [browserify](http://browserify.org/)
11 |
12 | ```shell
13 | npm install diffract
14 |
15 | ```
16 |
17 | ## Usage
18 |
19 | After installing diffract via NPM, you may use the components in your code as follows:
20 |
21 | ```js
22 | /** DeathStar.jsx */
23 |
24 | import React from 'react';
25 | import {Chart, DataSeries, Pie} from 'diffract';
26 |
27 | // ...And use it in your code
28 | class DeathStar extends Component {
29 |
30 | render: function() {
31 | return (
32 |
33 |
34 | ({fill: this.getColors(i)})}>
36 |
38 | {'Hello'}
39 |
40 |
42 | {'diffract'}
43 |
44 |
45 |
46 |
47 | );
48 | }
49 |
50 | }
51 |
52 | ```
53 |
54 | ## More Examples
55 | See [examples](https://github.com/ameyms/diffract/blob/master/example/demo.jsx) for more
56 | examples including Donuts, BarChart, stacked bar chart, grouped bar chart etc.
57 | ## Demo
58 | ### Donut
59 | 
60 |
61 | ### Bar Graph
62 | 
63 |
64 |
65 |
66 |
67 | ----
68 |
69 |
70 | License: MIT
71 |
--------------------------------------------------------------------------------
/etc/bar_graph_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ameyms/diffract/6b9805819abb7818f9dcb9c69446ec9c2e36e09c/etc/bar_graph_1.gif
--------------------------------------------------------------------------------
/etc/donut.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ameyms/diffract/6b9805819abb7818f9dcb9c69446ec9c2e36e09c/etc/donut.gif
--------------------------------------------------------------------------------
/example/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "node": true,
5 | "es6": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Demo JS files
2 | demo.bundle.js
3 |
4 | node_modules
5 | build
6 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # [diffract](http://github.com/ameyms/diffract) - Example Project
2 |
3 | This is an example project that uses [Diffract](http://github.com/ameyms/diffract).
4 |
5 | ## Installation
6 | After cloning the repository, install dependencies:
7 |
8 | ```shell
9 | npm install # Install diffract`s dependencies
10 | cd example # CD to example project
11 | npm install # Install example project`s dependencies
12 | ```
13 |
14 | ## Run demos
15 | Now you can run your local server:
16 |
17 | ```shell
18 | grunt demo
19 | ```
20 |
21 | You can now point your browser to http://localhost:9001 to view the demos
22 |
--------------------------------------------------------------------------------
/example/demo.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import ReactDom from 'react-dom';
3 | import {
4 | util, Chart, DataSeries, BarChart, Pie, XAxis, YAxis, Stack, Group
5 | } from 'diffract';
6 |
7 | const colors = ['#E91E63', '#2196F3', '#FF9800', '#4CAF50', '#673AB7'];
8 | const width = 640;
9 | const height = 240;
10 | let cnt = 1;
11 |
12 | const getRandomValuesArray = () => ([
13 | Math.random() * 10000, Math.random() * 10000,
14 | Math.random() * 10000, Math.random() * 10000,
15 | Math.random() * 10000
16 | ]);
17 |
18 | const margins = {
19 | left: 50,
20 | bottom: 20,
21 | top: 0,
22 | right: 0
23 | };
24 |
25 | const xScale = util.scale.ordinal().rangeRoundBands([0, width - margins.left - margins.right], 0.2);
26 | const yScale = util.scale.linear().rangeRound([height - margins.top - margins.bottom, 0]);
27 |
28 | class App extends Component {
29 |
30 | constructor() {
31 | super();
32 | this.state = {
33 | values: [Math.random() * 10000, Math.random() * 10000,
34 | Math.random() * 10000, Math.random() * 10000,
35 | Math.random() * 10000],
36 |
37 | multiValues: [
38 | getRandomValuesArray(), getRandomValuesArray(),
39 | getRandomValuesArray(), getRandomValuesArray(),
40 | getRandomValuesArray()
41 | ],
42 |
43 | labels: ['Elves', 'Dwarves',
44 | 'Hobbitses', 'Men', 'Wizards']
45 | };
46 | }
47 |
48 | componentDidMount() {
49 | this._updater = setInterval(this.updateData.bind(this), 5000);
50 | }
51 |
52 | componentWillUnmount() {
53 | clearInterval(this._updater);
54 | }
55 |
56 | getColors(d, i) {
57 | if (arguments.length === 2) {
58 | return colors[i];
59 | } else {
60 | return colors[d];
61 | }
62 |
63 | }
64 |
65 | getPieChart() {
66 | return (
67 |
68 |
69 | console.log(this.state.labels[i] + ' clicked')}
71 | style={(d, i) => ({fill: this.getColors(i)})}>
72 |
74 | {'Hello'}
75 |
76 |
78 | {'diffract'}
79 |
80 |
81 |
82 |
83 | );
84 | }
85 |
86 | updateData() {
87 |
88 | if (cnt++ % 3) {
89 | this.setState({
90 |
91 | values: getRandomValuesArray(),
92 |
93 | multiValues: [
94 | getRandomValuesArray(), getRandomValuesArray(),
95 | getRandomValuesArray(), getRandomValuesArray(),
96 | getRandomValuesArray()
97 | ],
98 | labels: ['Elves', 'Dwarves',
99 | 'Hobbitses', 'Men', 'Some really long label']});
100 | } else {
101 | this.setState({
102 | values: [
103 | Math.random() * 10000, Math.random() * 10000,
104 | Math.random() * 10000, Math.random() * 10000
105 | ],
106 | multiValues: [
107 | getRandomValuesArray(), getRandomValuesArray(),
108 | getRandomValuesArray(), getRandomValuesArray()
109 | ],
110 |
111 | labels: ['Elves', 'Dwarves',
112 | 'Hobbitses', 'Men']});
113 | }
114 | }
115 |
116 | getBarChart() {
117 | return (
118 |
120 |
122 | console.log(this.state.labels[i] + ' clicked')}
123 | style={(d, i) => ({fill: this.getColors(i)})}/>
124 | this.state.labels[i]} debug/>
125 | {
127 | return d;
128 | }}/>
129 |
130 |
131 | );
132 | }
133 |
134 | getStackedBarChart() {
135 | return (
136 |
138 |
140 |
141 | ({fill: this.getColors(i)})}/>
142 | this.state.labels[i]}/>
143 | {
145 | return d;
146 | }}/>
147 |
148 |
149 |
150 | );
151 | }
152 |
153 | getGroupedBarChart() {
154 | return (
155 |
158 |
160 |
161 | ({fill: this.getColors(i)})}/>
162 | this.state.labels[i]}/>
163 | {
165 | return d;
166 | }}/>
167 |
168 |
169 |
170 | );
171 | }
172 |
173 | render() {
174 |
175 | const donut = this.getPieChart();
176 | const barGraph = this.getBarChart();
177 | const stackedBarGraph = this.getStackedBarChart();
178 | const groupedBarGraph = this.getGroupedBarChart();
179 | const padding = {padding: '50px'};
180 |
181 | return (
182 |
183 |
{'Diffract demos'}
184 |
185 |
{'Donut'}
186 | {donut}
187 |
188 |
189 |
{'Bar Graph'}
190 | {barGraph}
191 |
192 |
193 |
{'Stacked Chart'}
194 | {stackedBarGraph}
195 |
196 |
197 |
{'Grouped Chart'}
198 | {groupedBarGraph}
199 |
200 |
201 |
202 | );
203 | }
204 | }
205 |
206 | App.displayName = 'App';
207 |
208 | ReactDom.render(
209 | ,
210 | document.getElementById('appRoot')
211 | );
212 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | diffract Demo
6 |
8 |
9 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffract-example",
3 | "version": "0.0.2",
4 | "description": "Showcase of diffract d3 widgets",
5 | "dependencies": {
6 | "d3": "^3.5.6",
7 | "react": "^0.14.7",
8 | "react-addons-transition-group": "^0.14.7",
9 | "react-dom": "^0.14.1"
10 | },
11 | "author": "Amey Sakhadeo",
12 | "license": "ISC",
13 | "devDependencies": {}
14 | }
15 |
--------------------------------------------------------------------------------
/gulpfile.babel.js:
--------------------------------------------------------------------------------
1 | require('babel-register')();
2 |
3 | import gulp from 'gulp';
4 | import {exec} from 'child_process';
5 | import fs from 'fs';
6 | import path from 'path';
7 |
8 | import gulpLoadPlugins from 'gulp-load-plugins';
9 | import browserify from 'browserify';
10 | import babelify from 'babelify';
11 | import del from 'del';
12 | import opn from 'opn';
13 | import Promise from 'bluebird';
14 | import srcStream from 'vinyl-source-stream';
15 | const $ = gulpLoadPlugins();
16 | const pkg = JSON.parse(fs.readFileSync('./package.json'));
17 |
18 | function lint(files, options) {
19 | return () => {
20 | return gulp.src(files)
21 | .pipe($.eslint(options))
22 | .pipe($.eslint.format());
23 | };
24 | }
25 |
26 | gulp.task('clean', del.bind(null, ['build', `${pkg.name}-*.tgz`]));
27 |
28 | gulp.task('lint', lint(['src/{,*/}*.js{,x}']));
29 |
30 | gulp.task('npmpack', ['build'], () => {
31 |
32 | return new Promise((resolve, reject) => {
33 | exec('npm pack', (err, stdout) => {
34 |
35 | if (err) {
36 | reject(err);
37 | } else {
38 | resolve(stdout.toString());
39 | }
40 | });
41 | });
42 | });
43 |
44 | gulp.task('demoInstall', ['npmpack'], () => {
45 |
46 | return new Promise((resolve, reject) => {
47 | exec(`npm install ../${pkg.name}-${pkg.version}.tgz`, {
48 | cwd: path.join(__dirname, 'example')
49 | }, (err, stdout) => {
50 | if (err) {
51 | reject(err);
52 | } else {
53 | resolve(stdout.toString());
54 | }
55 | });
56 | });
57 | });
58 |
59 | gulp.task('demoBuild', ['demoInstall'], () => {
60 | return browserify({
61 | entries: 'example/demo.jsx',
62 | debug: true,
63 | transform: [babelify]
64 | }).bundle()
65 | .pipe(srcStream('demo.bundle.js'))
66 | .pipe(gulp.dest('example'));
67 |
68 | });
69 |
70 | gulp.task('server', ['demoBuild'], () => {
71 | return $.connect.server({
72 | port: 9000,
73 | root: 'example',
74 | livereload: true
75 | });
76 | });
77 | gulp.task('demo', ['server', 'watch'], () => {
78 | opn('http://localhost:9000');
79 | });
80 |
81 | gulp.task('watch', () => {
82 | gulp.watch(['src/{,*/}*.js{,x}', 'example/demo.jsx'], ['demoBuild']);
83 | gulp.watch(['example/*.html', 'example/demo.bundle.js']).
84 | on('change', (file) => {
85 | gulp.src(file.path)
86 | .pipe($.connect.reload());
87 | });
88 | });
89 |
90 | gulp.task('build', ['clean', 'lint'], () => {
91 |
92 | return gulp.src('src/{,*/}*.js{,x}')
93 | .pipe($.plumber())
94 | .pipe($.babel())
95 | .pipe(gulp.dest('build/'));
96 | });
97 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffract",
3 | "author": "Amey Sakhadeo",
4 | "version": "0.3.2",
5 | "description": "A set of d3 based visualization components built for React",
6 | "main": "build/index.js",
7 | "files": [
8 | "build",
9 | "package.json"
10 | ],
11 | "scripts": {},
12 | "keywords": [
13 | "react",
14 | "react-component",
15 | "d3",
16 | "visualization",
17 | "graphs"
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/ameyms/diffract.git"
22 | },
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/ameyms/diffract/issues"
26 | },
27 | "dependencies": {
28 | "d3": "^3.5.16",
29 | "react-motion": "^0.4.2",
30 | "react-addons-transition-group": "^0.14.0 || ^15.0.2"
31 | },
32 | "peerDependencies": {
33 | "react": "^0.14.0 || ^15.0.2",
34 | "react-dom": "^0.14.0 || ^15.0.2"
35 | },
36 | "devDependencies": {
37 | "babel": "6.5.2",
38 | "babel-core": "^6.8.0",
39 | "babel-eslint": "^6.0.4",
40 | "babel-plugin-constant-folding": "^1.0.1",
41 | "babel-plugin-dead-code-elimination": "^1.0.2",
42 | "babel-plugin-react-transform": "^2.0.0",
43 | "babel-plugin-uglify": "^1.0.2",
44 | "babel-preset-es2015": "^6.0.11",
45 | "babel-preset-react": "^6.0.2",
46 | "babel-preset-stage-0": "^6.5.0",
47 | "babel-preset-stage-1": "^6.5.0",
48 | "babel-preset-stage-2": "^6.5.0",
49 | "babel-register": "^6.8.0",
50 | "babel-runtime": "6.6.1",
51 | "babelify": "^7.2.0",
52 | "bluebird": "^3.3.4",
53 | "browserify": "^13.0.0",
54 | "del": "^2.2.0",
55 | "eslint": "^2.9.0",
56 | "eslint-plugin-babel": "^3.1.0",
57 | "eslint-plugin-react": "^5.0.1",
58 | "gulp": "^3.9.1",
59 | "gulp-babel": "^6.1.1",
60 | "gulp-cache": "^0.4.2",
61 | "gulp-connect": "^4.0.0",
62 | "gulp-eslint": "^2.0.0",
63 | "gulp-if": "^2.0.0",
64 | "gulp-load-plugins": "^1.2.0",
65 | "gulp-nodemon": "^2.0.6",
66 | "gulp-plumber": "^1.0.1",
67 | "gulp-size": "^2.0.0",
68 | "gulp-util": "^3.0.7",
69 | "opn": "^4.0.1",
70 | "vinyl-source-stream": "^1.1.0"
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/BarChart.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component, PropTypes} from 'react';
2 | import d3 from 'd3';
3 | import {TransitionMotion, Motion, spring} from 'react-motion';
4 |
5 | export default class BarChart extends Component {
6 |
7 | static displayName = 'BarChart'
8 |
9 | static propTypes = {
10 | style: PropTypes.func,
11 | onClick: PropTypes.func
12 | }
13 |
14 | static contextTypes = {
15 | data: PropTypes.oneOfType([
16 | PropTypes.arrayOf(PropTypes.number),
17 | PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number))
18 | ]),
19 | height: PropTypes.number.isRequired,
20 | width: PropTypes.number.isRequired,
21 | margin: PropTypes.shape({
22 | top: PropTypes.number,
23 | bottom: PropTypes.number,
24 | left: PropTypes.number,
25 | right: PropTypes.number
26 | }),
27 | xScale: PropTypes.func.isRequired,
28 | yScale: PropTypes.func.isRequired,
29 | dataTransform: PropTypes.func,
30 | groupWidth: PropTypes.number
31 | }
32 |
33 | static defaultProps = {
34 | style: () => ({}),
35 | onClick: () => {}
36 | }
37 |
38 | willLeave({style}) {
39 |
40 | return {
41 | ...style,
42 | width: 0,
43 | x: style.x + style.width
44 | };
45 | }
46 |
47 | willEnter({style}) {
48 | return {
49 | ...style,
50 | width: 0,
51 | x: style.x + style.width
52 | };
53 | }
54 |
55 | render() {
56 |
57 | const {
58 | xScale, yScale, data,
59 | dataTransform = arr => arr.map((d, i) => ({
60 | x: i,
61 | dx: 0,
62 | y0: 0,
63 | y: d,
64 | z: 0,
65 | index: i
66 | })),
67 | groupWidth = 1
68 |
69 | } = this.context;
70 |
71 | const {style, onClick} = this.props;
72 |
73 | const txData = dataTransform(data);
74 |
75 | const xScaleFn = xScale.
76 | domain(d3.range(data.length));
77 |
78 |
79 | const yScaleFn = yScale.
80 | domain([0, d3.max(txData, d => d.y0 + d.y)]);
81 |
82 | const motionStyles = txData.map(d => ({
83 | key: d.index + '-' + d.z,
84 | data: {...d, index: d.index},
85 | style: {
86 | width: xScaleFn.rangeBand() / groupWidth,
87 | height: yScaleFn(d.y0) - yScaleFn(d.y0 + d.y),
88 | y0: yScaleFn(d.y0),
89 | y: yScaleFn(d.y0 + d.y),
90 | x: xScaleFn(d.x) + xScaleFn.rangeBand() / groupWidth * d.dx
91 |
92 | }
93 | }));
94 |
95 | const defaultStyles = txData.map(d => ({
96 | key: d.index + '-' + d.z,
97 | data: {...d, index: d.index},
98 | style: {
99 | width: xScaleFn.rangeBand() / groupWidth,
100 | height: 0,
101 | y0: yScaleFn(d.y0),
102 | y: yScaleFn(d.y0),
103 | x: xScaleFn(d.x) + xScaleFn.rangeBand() / groupWidth * d.dx
104 | }
105 | }));
106 |
107 | return (
108 |
109 |
111 | {interStyles => (
112 |
113 | {interStyles.map(config => (
114 |
127 | {interStyle => {
128 |
129 | return (
130 | {
133 | onClick(
134 | e,
135 | config.data.y,
136 | config.data.index
137 | );
138 | }}
139 | x={interStyle.x} y={interStyle.y}
140 | style={style(
141 | config.data.y,
142 | config.data.index
143 | )}/>
144 | );
145 | }
146 | }
147 |
148 | ))}
149 |
150 | )}
151 |
152 | {this.props.children}
153 |
154 | );
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/Chart.jsx:
--------------------------------------------------------------------------------
1 | // "transform-remove-console"
2 | import React, {Component, PropTypes} from 'react';
3 |
4 | export default class Chart extends Component {
5 |
6 | static displayName = 'Chart'
7 |
8 | static childContextTypes = {
9 | height: PropTypes.number,
10 | width: PropTypes.number,
11 | margin: PropTypes.shape({
12 | top: PropTypes.number,
13 | bottom: PropTypes.number,
14 | left: PropTypes.number,
15 | right: PropTypes.number
16 | })
17 | };
18 |
19 | static propTypes = {
20 | height: PropTypes.number,
21 | width: PropTypes.number,
22 | margin: PropTypes.shape({
23 | top: PropTypes.number,
24 | bottom: PropTypes.number,
25 | left: PropTypes.number,
26 | right: PropTypes.number
27 | })
28 | };
29 |
30 | static defaultProps = {
31 | height: 0,
32 | width: 0,
33 | margin: {
34 | top: 0,
35 | bottom: 0,
36 | left: 0,
37 | right: 0
38 | }
39 | };
40 |
41 |
42 | getChildContext() {
43 | const {width, height} = this.props;
44 | let {margin} = this.props;
45 |
46 | margin = {
47 | top: 0,
48 | bottom: 0,
49 | left: 0,
50 | right: 0,
51 | ...margin
52 | };
53 |
54 | return {width, height, margin};
55 | }
56 | render(): () => any {
57 |
58 | const {width, height} = this.props;
59 | let {margin} = this.props;
60 |
61 | margin = {
62 | top: 0,
63 | bottom: 0,
64 | left: 0,
65 | right: 0,
66 | ...margin
67 | };
68 |
69 | const insetString = `translate(${margin.left}, ${margin.top})`;
70 | return (
71 |
77 |
82 |
83 |
86 |
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Colors.js:
--------------------------------------------------------------------------------
1 | export const AXIS_LINES = '#999';
2 |
--------------------------------------------------------------------------------
/src/DataSeries.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component, PropTypes} from 'react';
2 |
3 | export default class DataSeries extends Component {
4 |
5 | static displayName = 'DataSeries'
6 |
7 | static propTypes = {
8 | xScale: PropTypes.func,
9 | yScale: PropTypes.func,
10 | data: PropTypes.oneOfType([
11 | PropTypes.arrayOf(PropTypes.number),
12 | PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number))
13 | ]).isRequired
14 | }
15 |
16 | static childContextTypes = {
17 | xScale: PropTypes.func,
18 | yScale: PropTypes.func,
19 | data: PropTypes.oneOfType([
20 | PropTypes.arrayOf(PropTypes.number),
21 | PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number))
22 | ])
23 | }
24 |
25 | getChildContext() {
26 | const {xScale, yScale, data} = this.props;
27 | return {xScale, yScale, data};
28 | }
29 |
30 | render() {
31 | return (
32 |
33 | {this.props.children}
34 |
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Group.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component, PropTypes} from 'react';
2 |
3 | export default class Group extends Component {
4 |
5 | static displayName = 'Group'
6 |
7 | static contextTypes = {
8 | data: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)).isRequired,
9 | height: PropTypes.number.isRequired,
10 | width: PropTypes.number.isRequired,
11 | margin: PropTypes.shape({
12 | top: PropTypes.number,
13 | bottom: PropTypes.number,
14 | left: PropTypes.number,
15 | right: PropTypes.number
16 | }),
17 | xScale: PropTypes.func.isRequired,
18 | yScale: PropTypes.func.isRequired
19 | }
20 |
21 | static childContextTypes = {
22 | data: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
23 | height: PropTypes.number,
24 | width: PropTypes.number,
25 | margin: PropTypes.shape({
26 | top: PropTypes.number,
27 | bottom: PropTypes.number,
28 | left: PropTypes.number,
29 | right: PropTypes.number
30 | }),
31 | xScale: PropTypes.func.isRequired,
32 | yScale: PropTypes.func.isRequired,
33 | dataTransform: PropTypes.func,
34 | groupWidth: PropTypes.number
35 | }
36 |
37 | getChildContext() {
38 |
39 | const {data} = this.context;
40 |
41 | return {
42 | ...this.context,
43 | groupWidth: data[0].length,
44 | dataTransform: this.dataTransform
45 | };
46 | }
47 |
48 | dataTransform(arr2d) {
49 |
50 | const txData = [];
51 |
52 | arr2d.forEach((samples, i) => {
53 | txData.push(samples.map((sample, j) => ({
54 | x: i,
55 | dx: j,
56 | y: sample,
57 | z: i,
58 | y0: 0,
59 | index: j
60 | })));
61 | });
62 |
63 | return Array.prototype.concat.apply([], txData);
64 | }
65 |
66 | render() {
67 | return (
68 |
69 | {this.props.children}
70 |
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Pie.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component, PropTypes} from 'react';
2 | import d3 from 'd3';
3 | import {TransitionMotion, Motion, spring} from 'react-motion';
4 |
5 | export default class Pie extends Component {
6 |
7 | static displayName = 'Pie'
8 |
9 | static propTypes = {
10 | innerRadius: PropTypes.number,
11 | outerRadius: PropTypes.number,
12 | style: PropTypes.func,
13 | onClick: PropTypes.func
14 | }
15 |
16 | static contextTypes = {
17 | data: PropTypes.arrayOf(PropTypes.number),
18 | height: PropTypes.number,
19 | width: PropTypes.number,
20 | margin: PropTypes.shape({
21 | top: PropTypes.number,
22 | bottom: PropTypes.number,
23 | left: PropTypes.number,
24 | right: PropTypes.number
25 | })
26 | }
27 |
28 | static defaultProps = {
29 | style: () => ({}),
30 | onClick: () => {}
31 | }
32 |
33 | willLeave({style}) {
34 | return {
35 | ...style,
36 | startAngle: style.endAngle
37 | };
38 | }
39 |
40 | willEnter({style}) {
41 | return {
42 | ...style,
43 | endAngle: style.startAngle
44 | };
45 | }
46 |
47 | render() {
48 | const {width, height, data} = this.context;
49 | const pieFn = d3.layout.pie().sort(null);
50 | const {style, onClick} = this.props;
51 |
52 | const arcFn = d3.svg.arc().
53 | outerRadius(this.props.outerRadius).
54 | innerRadius(this.props.innerRadius);
55 |
56 | const pieData = pieFn(data);
57 | const motionStyles = pieData.map((d, i) => ({
58 | key: i + '',
59 | data: {...d, index: i},
60 | style: d
61 | }));
62 |
63 | const defaultStyles = pieData.map((d, i) => ({
64 | key: i + '',
65 | data: {...d, index: i},
66 | style: {...d, endAngle: d.startAngle}
67 | }));
68 |
69 | const centerTransform = `translate(${width / 2}, ${height / 2})`;
70 |
71 |
72 | return (
73 |
74 |
76 | {interStyles => (
77 |
78 | {interStyles.map(config => (
79 |
89 | {interStyle =>
90 | {
96 | onClick(
97 | e, config.data.value,
98 | config.data.index
99 | );
100 | }
101 | }/>
102 | }
103 |
104 | ))}
105 |
106 | )}
107 |
108 | {this.props.children}
109 |
110 | );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/Stack.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component, PropTypes} from 'react';
2 | import d3 from 'd3';
3 |
4 | export default class Stack extends Component {
5 | static contextTypes = {
6 | data: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)).isRequired,
7 | height: PropTypes.number.isRequired,
8 | width: PropTypes.number.isRequired,
9 | margin: PropTypes.shape({
10 | top: PropTypes.number,
11 | bottom: PropTypes.number,
12 | left: PropTypes.number,
13 | right: PropTypes.number
14 | }),
15 | xScale: PropTypes.func.isRequired,
16 | yScale: PropTypes.func.isRequired
17 | }
18 |
19 | static childContextTypes = {
20 | data: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
21 | height: PropTypes.number,
22 | width: PropTypes.number,
23 | margin: PropTypes.shape({
24 | top: PropTypes.number,
25 | bottom: PropTypes.number,
26 | left: PropTypes.number,
27 | right: PropTypes.number
28 | }),
29 | xScale: PropTypes.func.isRequired,
30 | yScale: PropTypes.func.isRequired,
31 | dataTransform: PropTypes.func
32 | }
33 |
34 | getChildContext() {
35 |
36 | return {
37 | ...this.context,
38 | dataTransform: this.dataTransform
39 | };
40 | }
41 |
42 | dataTransform(arr2d) {
43 |
44 | const txData = [];
45 |
46 | arr2d[0].forEach(() => {
47 | txData.push([]);
48 | });
49 |
50 | arr2d.forEach((samples, i) => {
51 | samples.forEach((s, j) => {
52 | txData[j].push({
53 | x: i,
54 | y: s,
55 | z: i,
56 | y0: 0,
57 | dx: 0,
58 | index: j
59 | });
60 | });
61 | });
62 |
63 | return Array.prototype.concat.apply([], d3.layout.stack()(txData));
64 | }
65 |
66 | render() {
67 | return (
68 |
69 | {this.props.children}
70 |
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/XAxis.jsx:
--------------------------------------------------------------------------------
1 | import React, {PropTypes, Component} from 'react';
2 | import {Axis as Styles} from './styles';
3 | import d3 from 'd3';
4 | import {scaleRange} from './helpers/scales';
5 | import {getTicks} from './helpers/axes';
6 | import {TransitionMotion, Motion, spring} from 'react-motion';
7 |
8 | export default class XAxis extends Component {
9 |
10 | static displayName = 'XAxis'
11 |
12 | static contextTypes = {
13 | xScale: PropTypes.func.isRequired,
14 | dataTransform: PropTypes.func,
15 | data: PropTypes.oneOfType([
16 | PropTypes.arrayOf(PropTypes.number),
17 | PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number))
18 | ]),
19 | height: PropTypes.number,
20 | width: PropTypes.number,
21 | margin: PropTypes.shape({
22 | top: PropTypes.number,
23 | bottom: PropTypes.number,
24 | left: PropTypes.number,
25 | right: PropTypes.number
26 | })
27 | }
28 |
29 | static propTypes = {
30 |
31 | labels: PropTypes.func,
32 | orientation: PropTypes.oneOf(['top', 'bottom']),
33 | tickFormat: PropTypes.func,
34 | outerTickSize: PropTypes.number,
35 | innerTickSize: PropTypes.number,
36 | tickPadding: PropTypes.number,
37 | tickValues: PropTypes.arrayOf(PropTypes.any),
38 | ticks: PropTypes.arrayOf(PropTypes.any),
39 | tickTextStyle: PropTypes.object,
40 | tickLineStyle: PropTypes.object,
41 | textRotation: PropTypes.number,
42 | debug: PropTypes.bool
43 | }
44 |
45 | static defaultProps = {
46 | tickFormat: v => v,
47 | labels: v => (v),
48 | orientation: 'bottom',
49 | outerTickSize: 6,
50 | innerTickSize: 6,
51 | tickPadding: 3,
52 | tickValues: null,
53 | ticks: [10],
54 | tickTextStyle: {},
55 | tickLineStyle: {},
56 | textRotation: 0
57 | }
58 |
59 | constructor(props) {
60 | super(props);
61 | this.state = {};
62 | }
63 |
64 | willEnter({style}) {
65 | return {
66 | ...style,
67 | opacity: 0
68 | };
69 | }
70 |
71 | willLeave({style}) {
72 | return {
73 | ...style,
74 | opacity: 0
75 | };
76 | }
77 |
78 | render() {
79 |
80 | const {
81 | orientation,
82 | outerTickSize,
83 | innerTickSize,
84 | tickValues,
85 | tickPadding,
86 | ticks,
87 | tickFormat,
88 | tickTextStyle,
89 | tickLineStyle,
90 | textRotation,
91 | /*eslint-disable no-unused-vars*/
92 | debug
93 | /*eslint-enable unused*/
94 | } = this.props;
95 |
96 | const {xScale, data, width, height, margin} = this.context;
97 |
98 | const tickSpacing = Math.max(innerTickSize, 0) + tickPadding;
99 | const wMax = width - margin.left - margin.right;
100 | const hMax = height - margin.top - margin.bottom;
101 |
102 | const scale = xScale.domain(d3.range(data.length)).copy();
103 |
104 | const ticksArr = getTicks(scale, tickValues, ticks);
105 |
106 |
107 | const displacement = orientation === 'bottom' ?
108 | `translate(0, ${hMax})` : 'translate(0, 0)';
109 |
110 | const sign = orientation === 'top' ? -1 : 1;
111 |
112 | const range = scaleRange(scale);
113 | const pathD = `M${range[0]},${sign * outerTickSize}V0H${range[1]}V${sign * outerTickSize}`;
114 |
115 | let dx = 0;
116 | if (scale.rangeBand) {
117 | dx = scale.rangeBand() / 2;
118 | }
119 |
120 |
121 | const defaultStyles = ticksArr.map((t, i) => ({
122 | key: i + '',
123 | data: {
124 | text: tickFormat(t, i)
125 | },
126 | style: {
127 | tx: scale(t) + dx,
128 | ty: 0,
129 | textRotation,
130 | opacity: 1
131 | }
132 | }));
133 |
134 | const motionStyles = ticksArr.map((t, i) => ({
135 | key: i + '',
136 | data: {
137 | text: tickFormat(t, i)
138 | },
139 | style: {
140 | tx: scale(t) + dx,
141 | ty: 0,
142 | textRotation,
143 | opacity: 1
144 | }
145 | }));
146 |
147 |
148 | return (
149 |
150 |
152 | {interStyles => (
153 |
154 | {interStyles.map(config => (
155 |
167 | {interStyle => {
168 | return (
169 |
176 |
181 |
194 | {config.data.text}
195 |
196 |
197 | );
198 | }
199 | }
200 |
201 | ))}
202 |
203 | )}
204 |
205 |
206 |
207 | );
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/YAxis.jsx:
--------------------------------------------------------------------------------
1 | import React, {PropTypes, Component} from 'react';
2 | import {Axis as Styles} from './styles';
3 | import d3 from 'd3';
4 | import {scaleRange} from './helpers/scales';
5 | import {getTicks} from './helpers/axes';
6 | import {TransitionMotion, Motion, spring} from 'react-motion';
7 |
8 | export default class YAxis extends Component {
9 |
10 | static displayName = 'YAxis'
11 |
12 | static contextTypes = {
13 | yScale: PropTypes.func.isRequired,
14 | dataTransform: PropTypes.func,
15 | data: PropTypes.oneOfType([
16 | PropTypes.arrayOf(PropTypes.number),
17 | PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number))
18 | ]),
19 | height: PropTypes.number,
20 | width: PropTypes.number,
21 | margin: PropTypes.shape({
22 | top: PropTypes.number,
23 | bottom: PropTypes.number,
24 | left: PropTypes.number,
25 | right: PropTypes.number
26 | })
27 | }
28 |
29 | static propTypes = {
30 |
31 | labels: PropTypes.func,
32 | orientation: PropTypes.oneOf(['left', 'right']),
33 | tickFormat: PropTypes.func,
34 | outerTickSize: PropTypes.number,
35 | innerTickSize: PropTypes.number,
36 | tickPadding: PropTypes.number,
37 | tickValues: PropTypes.arrayOf(PropTypes.any),
38 | ticks: PropTypes.arrayOf(PropTypes.any),
39 | tickTextStyle: PropTypes.object,
40 | tickLineStyle: PropTypes.object,
41 | textRotation: PropTypes.number,
42 | debug: PropTypes.bool
43 | }
44 |
45 | static defaultProps = {
46 | tickFormat: v => v,
47 | labels: v => (v),
48 | orientation: 'left',
49 | outerTickSize: 6,
50 | innerTickSize: 6,
51 | tickPadding: 3,
52 | tickValues: null,
53 | ticks: [10],
54 | tickTextStyle: {},
55 | tickLineStyle: {},
56 | textRotation: 0
57 | }
58 |
59 | constructor(props) {
60 | super(props);
61 | this.state = {};
62 | }
63 |
64 | willEnter({style}) {
65 | return {
66 | ...style,
67 | opacity: 0
68 | };
69 | }
70 |
71 | willLeave({style}) {
72 | return {
73 | ...style,
74 | opacity: 0
75 | };
76 | }
77 |
78 | render() {
79 |
80 | const {
81 | orientation,
82 | outerTickSize,
83 | innerTickSize,
84 | tickValues,
85 | tickPadding,
86 | ticks,
87 | tickFormat,
88 | tickTextStyle,
89 | tickLineStyle,
90 | textRotation,
91 | /*eslint-disable no-unused-vars*/
92 | debug
93 | /*eslint-enable unused*/
94 | } = this.props;
95 |
96 | const {
97 | yScale, data, width, height, margin,
98 | dataTransform = arr => arr.map((d, i) => ({
99 | x: i,
100 | y0: 0,
101 | y: d,
102 | z: 0
103 | }))
104 | } = this.context;
105 |
106 | const txData = dataTransform(data);
107 | const tickSpacing = Math.max(innerTickSize, 0) + tickPadding;
108 | const wMax = width - margin.left - margin.right;
109 | const hMax = height - margin.top - margin.bottom;
110 |
111 | const scale = yScale.domain([0, d3.max(txData, d => d.y0 + d.y)]).copy();
112 |
113 | const ticksArr = getTicks(scale, tickValues, ticks);
114 |
115 |
116 | const displacement = orientation === 'right' ?
117 | `translate(${wMax},0)` : 'translate(0, 0)';
118 |
119 | const sign = orientation === 'left' ? -1 : 1;
120 |
121 | const range = scaleRange(scale);
122 | const pathD = `M${sign * outerTickSize},${range[0]}H0V${range[1]}H${sign * outerTickSize}`;
123 |
124 | let dx = 0;
125 | if (scale.rangeBand) {
126 | dx = scale.rangeBand() / 2;
127 | }
128 |
129 |
130 | const defaultStyles = ticksArr.map((t, i) => ({
131 | key: i + '',
132 | data: {
133 | text: tickFormat(t, i)
134 | },
135 | style: {
136 | ty: scale(t) + dx,
137 | tx: 0,
138 | textRotation,
139 | opacity: 1
140 | }
141 | }));
142 |
143 | const motionStyles = ticksArr.map((t, i) => ({
144 | key: i + '',
145 | data: {
146 | text: tickFormat(t, i)
147 | },
148 | style: {
149 | ty: scale(t) + dx,
150 | tx: 0,
151 | textRotation,
152 | opacity: 1
153 | }
154 | }));
155 |
156 |
157 | return (
158 |
159 |
161 | {interStyles => (
162 |
163 | {interStyles.map(config => (
164 |
176 | {interStyle => {
177 | return (
178 |
185 |
190 |
202 | {config.data.text}
203 |
204 |
205 | );
206 | }
207 | }
208 |
209 | ))}
210 |
211 | )}
212 |
213 |
214 |
215 | );
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | export const TRANSITION_DURATION = 800;
2 |
--------------------------------------------------------------------------------
/src/helpers/axes.js:
--------------------------------------------------------------------------------
1 | export function getTicks(scale, tickValues, ticks) {
2 | if (tickValues === null) {
3 | return (scale.ticks ? scale.ticks(...ticks) : scale.domain());
4 | } else {
5 | return tickValues;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/helpers/scales.js:
--------------------------------------------------------------------------------
1 |
2 | export function scaleExtent(domain) {
3 | var start = domain[0], stop = domain[domain.length - 1];
4 | return start < stop ? [start, stop] : [stop, start];
5 | }
6 |
7 | export function scaleRange(scale) {
8 | return scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range());
9 | }
10 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Chart from './Chart';
2 | import DataSeries from './DataSeries';
3 | import Pie from './Pie';
4 | import BarChart from './BarChart';
5 | import Stack from './Stack';
6 | import Group from './Group';
7 | import XAxis from './XAxis';
8 | import YAxis from './YAxis';
9 | import util from './util';
10 |
11 | module.exports = {
12 | Chart,
13 | DataSeries,
14 | Pie,
15 | BarChart,
16 | Stack,
17 | Group,
18 | XAxis,
19 | YAxis,
20 | util
21 | };
22 |
--------------------------------------------------------------------------------
/src/styles.js:
--------------------------------------------------------------------------------
1 | import * as Colors from './Colors';
2 |
3 | export const Axis = {
4 | text: {
5 | fontSize: '0.8em'
6 | },
7 | paths: {
8 | fill: 'none',
9 | stroke: Colors.AXIS_LINES,
10 | shapeRendering: 'crispEdges'
11 | },
12 | lines: {
13 | fill: 'none',
14 | stroke: Colors.AXIS_LINES,
15 | shapeRendering: 'crispEdges'
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/src/util.js:
--------------------------------------------------------------------------------
1 | import d3 from 'd3';
2 |
3 | const {scale} = d3;
4 |
5 | export default {scale};
6 |
--------------------------------------------------------------------------------