├── .gitignore
├── Gruntfile.js
├── README.md
├── docs
├── assets
│ └── main.js
└── index.html
├── package.json
├── src
├── components
│ ├── VisExample1.js
│ ├── VisExample2.js
│ ├── VisExample3.js
│ ├── VisExample4.js
│ ├── VisExample5.js
│ ├── VisExample6.js
│ ├── VisExample7.js
│ ├── VisExample8.js
│ └── VisExampleApp.js
├── index.html
└── styles
│ └── main.css
├── webpack.config.js
└── webpack.dist.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | ### SublimeText ###
2 | *.sublime-workspace
3 |
4 | ### OSX ###
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 |
10 | # Thumbnails
11 | ._*
12 |
13 | # Files that might appear on external disk
14 | .Spotlight-V100
15 | .Trashes
16 |
17 | ### Windows ###
18 | # Windows image file caches
19 | Thumbs.db
20 | ehthumbs.db
21 |
22 | # Folder config file
23 | Desktop.ini
24 |
25 | # Recycle Bin used on file shares
26 | $RECYCLE.BIN/
27 |
28 | # App specific
29 |
30 | node_modules/
31 | .tmp
32 | dist
33 | /src/main.js
34 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var mountFolder = function (connect, dir) {
4 | return connect.static(require('path').resolve(dir));
5 | };
6 |
7 | var webpackDistConfig = require('./webpack.dist.config.js'),
8 | webpackDevConfig = require('./webpack.config.js');
9 |
10 | module.exports = function (grunt) {
11 | // Let *load-grunt-tasks* require everything
12 | require('load-grunt-tasks')(grunt);
13 |
14 | // Read configuration from package.json
15 | var pkgConfig = grunt.file.readJSON('package.json');
16 |
17 | grunt.initConfig({
18 | pkg: pkgConfig,
19 |
20 | webpack: {
21 | options: webpackDistConfig,
22 | dist: {
23 | cache: false
24 | }
25 | },
26 |
27 | 'webpack-dev-server': {
28 | options: {
29 | hot: true,
30 | port: 8000,
31 | webpack: webpackDevConfig,
32 | publicPath: '/assets/',
33 | contentBase: './<%= pkg.src %>/'
34 | },
35 |
36 | start: {
37 | keepAlive: true
38 | }
39 | },
40 |
41 | connect: {
42 | options: {
43 | port: 8000
44 | },
45 |
46 | dist: {
47 | options: {
48 | keepalive: true,
49 | middleware: function (connect) {
50 | return [
51 | mountFolder(connect, pkgConfig.dist)
52 | ];
53 | }
54 | }
55 | }
56 | },
57 |
58 | open: {
59 | options: {
60 | delay: 500
61 | },
62 | dev: {
63 | path: 'http://localhost:<%= connect.options.port %>/webpack-dev-server/'
64 | },
65 | dist: {
66 | path: 'http://localhost:<%= connect.options.port %>/'
67 | }
68 | },
69 |
70 | copy: {
71 | dist: {
72 | files: [
73 | // includes files within path
74 | {
75 | flatten: true,
76 | expand: true,
77 | src: ['<%= pkg.src %>/*'],
78 | dest: '<%= pkg.dist %>/',
79 | filter: 'isFile'
80 | },
81 | {
82 | flatten: true,
83 | expand: true,
84 | src: ['<%= pkg.src %>/images/*'],
85 | dest: '<%= pkg.dist %>/images/'
86 | }
87 | ]
88 | }
89 | },
90 |
91 | clean: {
92 | dist: {
93 | files: [{
94 | dot: true,
95 | src: [
96 | '<%= pkg.dist %>'
97 | ]
98 | }]
99 | }
100 | }
101 | });
102 |
103 | grunt.registerTask('serve', function (target) {
104 | if (target === 'dist') {
105 | return grunt.task.run(['build', 'open:dist', 'connect:dist']);
106 | }
107 |
108 | grunt.task.run([
109 | 'open:dev',
110 | 'webpack-dev-server'
111 | ]);
112 | });
113 |
114 |
115 | grunt.registerTask('build', ['clean', 'copy', 'webpack']);
116 |
117 | grunt.registerTask('default', []);
118 | };
119 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-basic-vis-examples
2 | A few basic visualization examples that build on each other,
3 | using [React](https://facebook.github.io/react/) and
4 | [D3.js](http://d3js.org/). The project base
5 | was generated using [Yeoman](http://yeoman.io/)'s [react-webpack generator](https://github.com/newtriks/generator-react-webpack).
6 |
7 | **Demo** http://pbeshai.github.io/react-basic-vis-examples/
8 |
9 | ## Installation
10 |
11 | Install npm packages
12 |
13 | ```npm install```
14 |
15 |
16 | ## Usage
17 |
18 | Use grunt to start the web server
19 |
20 | ```grunt serve```
21 |
22 | This will start the `webpack-dev-server` and open a browser to the locally running connect server.
23 |
24 |
25 | ## Author
26 |
27 | By Peter Beshai [@pbesh](http://twitter.com/pbesh)
28 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Basic Vis Examples with React
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-basic-vis-examples",
3 | "version": "0.1.0",
4 | "description": "A few basic visualization examples using React and D3",
5 | "author": {
6 | "name": "Peter Beshai",
7 | "email": "peter.beshai@gmail.com"
8 | },
9 | "repository": "",
10 | "private": true,
11 | "src": "src",
12 | "dist": "dist",
13 | "mainInput": "VisExampleApp",
14 | "mainOutput": "main",
15 | "dependencies": {
16 | "normalize.css": "~3.0.3",
17 | "react": "^0.14.6",
18 | "react-addons-pure-render-mixin": "^0.14.6",
19 | "react-dom": "^0.14.6"
20 | },
21 | "devDependencies": {
22 | "babel": "^4.0.0",
23 | "babel-loader": "^4.0.0",
24 | "css-loader": "~0.9.0",
25 | "d3": "^3.5.5",
26 | "grunt": "~0.4.5",
27 | "grunt-contrib-clean": "~0.6.0",
28 | "grunt-contrib-connect": "~0.8.0",
29 | "grunt-contrib-copy": "~0.5.0",
30 | "grunt-open": "~0.2.3",
31 | "grunt-webpack": "~1.0.8",
32 | "jshint-loader": "~0.8.0",
33 | "jsxhint-loader": "~0.2.0",
34 | "load-grunt-tasks": "~0.6.0",
35 | "react-auto-width": "^0.1.0",
36 | "react-hot-loader": "^1.0.7",
37 | "style-loader": "~0.8.0",
38 | "url-loader": "~0.5.5",
39 | "webpack": "~1.4.3",
40 | "webpack-dev-server": "~1.6.5"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/VisExample1.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const VisExample1 = React.createClass({
4 | propTypes: {
5 | height: React.PropTypes.number.isRequired,
6 | width: React.PropTypes.number.isRequired
7 | },
8 |
9 | render() {
10 | const { width, height } = this.props;
11 |
12 | return (
13 |
18 | );
19 | }
20 | });
21 |
22 | export default VisExample1;
23 |
--------------------------------------------------------------------------------
/src/components/VisExample2.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const VisExample2 = React.createClass({
4 | propTypes: {
5 | height: React.PropTypes.number.isRequired,
6 | width: React.PropTypes.number.isRequired
7 | },
8 |
9 | render() {
10 | const { width, height } = this.props;
11 |
12 | const data = [
13 | { x: 30, y: 80, r: 25, color: 'red' },
14 | { x: 130, y: 80, r: 60, color: 'green' },
15 | { x: 260, y: 80, r: 40, color: 'blue' }
16 | ];
17 |
18 | return (
19 |
25 | );
26 | }
27 | });
28 |
29 | export default VisExample2;
30 |
--------------------------------------------------------------------------------
/src/components/VisExample3.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const VisExample3 = React.createClass({
4 | propTypes: {
5 | data: React.PropTypes.array.isRequired,
6 | height: React.PropTypes.number.isRequired,
7 | width: React.PropTypes.number.isRequired
8 | },
9 |
10 | _chartComponents() {
11 | /* data is of format:
12 | data = [{ locationX, locationY, frequency, accuracy, rank }, ...] */
13 | const { data } = this.props;
14 |
15 | // convert data points into chart points
16 | const points = data.map(d => {
17 | return {
18 | x: d.locationX * 10,
19 | y: d.locationY * 10,
20 | r: d.frequency / 5,
21 | color: d.accuracy > 0.5 ? 'red' : 'blue',
22 | datum: d
23 | };
24 | });
25 |
26 | return {
27 | points
28 | };
29 | },
30 |
31 | render() {
32 | const { width, height } = this.props;
33 | const { points } = this._chartComponents();
34 |
35 | return (
36 |
42 | );
43 | }
44 | });
45 |
46 | export default VisExample3;
47 |
--------------------------------------------------------------------------------
/src/components/VisExample4.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 |
4 | const VisExample4 = React.createClass({
5 | propTypes: {
6 | data: React.PropTypes.array.isRequired,
7 | height: React.PropTypes.number.isRequired,
8 | width: React.PropTypes.number.isRequired
9 | },
10 |
11 | _chartComponents() {
12 | /* data is of format:
13 | data = [{ locationX, locationY, frequency, accuracy, rank }, ...] */
14 | const { width, height, data } = this.props;
15 |
16 | // convert data points into chart points
17 | const points = data.map(d => {
18 | return {
19 | x: d.locationX,
20 | y: d.locationY,
21 | r: d.frequency,
22 | color: d.accuracy,
23 | datum: d
24 | };
25 | });
26 |
27 | // get the range of values from the x and y attributes in the data
28 | const xDomain = d3.extent(points, d => d.x);
29 | const yDomain = d3.extent(points, d => d.y);
30 |
31 | // use d3 to create scales based on the dimensions and domains
32 | const x = d3.scale.linear().domain(xDomain).range([0, width]);
33 | const y = d3.scale.linear().domain(yDomain).range([0, height]);
34 |
35 | // create radius scale based on data
36 | const rDomain = d3.extent(points, d => d.r);
37 | const numCols = xDomain[1];
38 | const r = d3.scale.linear().domain(rDomain)
39 | .range([0, (width / numCols) / 2 ]);
40 |
41 | // create color scale (colors from http://colorbrewer2.org)
42 | const color = d3.scale.linear().domain([0.3, 0.45, 0.6])
43 | .range(['#0571b0', '#f7f7f7', '#ca0020']).clamp(true);
44 |
45 | return {
46 | points,
47 | width,
48 | height,
49 | x,
50 | y,
51 | r,
52 | color
53 | };
54 | },
55 |
56 | render() {
57 | const { points, width, height, x, y, r, color } = this._chartComponents();
58 |
59 | return (
60 |
66 | );
67 | }
68 | });
69 |
70 | export default VisExample4;
71 |
--------------------------------------------------------------------------------
/src/components/VisExample5.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 |
4 | const VisExample5 = React.createClass({
5 | propTypes: {
6 | data: React.PropTypes.array.isRequired,
7 | height: React.PropTypes.number.isRequired,
8 | width: React.PropTypes.number.isRequired
9 | },
10 |
11 | _chartComponents() {
12 | /* data is of format:
13 | data = [{ locationX, locationY, frequency, accuracy, rank }, ...] */
14 | const { width, height, data } = this.props;
15 |
16 | // convert data points into chart points
17 | const points = data.map(d => {
18 | return {
19 | x: d.locationX,
20 | y: d.locationY,
21 | r: d.frequency,
22 | color: d.accuracy,
23 | datum: d
24 | };
25 | });
26 |
27 | // define the inner margins of the chart
28 | const innerMargin = { top: 10, bottom: 25, left: 10, right: 10 };
29 | const innerWidth = width - innerMargin.left - innerMargin.right;
30 | const innerHeight = height - innerMargin.top - innerMargin.bottom;
31 |
32 | // get the range of values from the x and y attributes in the data
33 | const xDomain = d3.extent(points, d => d.x);
34 | const yDomain = d3.extent(points, d => d.y);
35 |
36 | // use d3 to create scales based on the dimensions and domains
37 | const x = d3.scale.linear().domain(xDomain)
38 | .range([innerMargin.left, innerMargin.left + innerWidth]);
39 |
40 | const y = d3.scale.linear().domain(yDomain)
41 | .range([innerMargin.top, innerMargin.top + innerHeight]);
42 |
43 | // create radius scale based on data
44 | const rDomain = d3.extent(points, d => d.r);
45 | const numCols = xDomain[1];
46 | const r = d3.scale.linear().domain(rDomain)
47 | .range([0, (innerWidth / numCols) / 2]);
48 |
49 | // create color scale (colors from http://colorbrewer2.org)
50 | const color = d3.scale.linear().domain([0.3, 0.45, 0.6])
51 | .range(['#0571b0', '#f7f7f7', '#ca0020']).clamp(true);
52 |
53 | return {
54 | points,
55 | width,
56 | height,
57 | innerMargin,
58 | x,
59 | y,
60 | r,
61 | color
62 | };
63 | },
64 |
65 | render() {
66 | const { points, width, height, x, y, r, color } = this._chartComponents();
67 |
68 | return (
69 |
75 | );
76 | }
77 | });
78 |
79 | export default VisExample5;
80 |
--------------------------------------------------------------------------------
/src/components/VisExample6.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 |
4 | const VisExample6 = React.createClass({
5 | propTypes: {
6 | data: React.PropTypes.array.isRequired,
7 | height: React.PropTypes.number.isRequired,
8 | width: React.PropTypes.number.isRequired
9 | },
10 |
11 | getInitialState() {
12 | return {};
13 | },
14 |
15 | _chartComponents() {
16 | /* data is of format:
17 | data = [{ locationX, locationY, frequency, accuracy, rank }, ...] */
18 | const { width, height, data } = this.props;
19 |
20 | // convert data points into chart points
21 | const points = data.map(d => {
22 | return {
23 | x: d.locationX,
24 | y: d.locationY,
25 | r: d.frequency,
26 | color: d.accuracy,
27 | datum: d
28 | };
29 | });
30 |
31 | // define the inner margins of the chart
32 | const innerMargin = { top: 10, bottom: 25, left: 10, right: 10 };
33 | const innerWidth = width - innerMargin.left - innerMargin.right;
34 | const innerHeight = height - innerMargin.top - innerMargin.bottom;
35 |
36 | // get the range of values from the x and y attributes in the data
37 | const xDomain = d3.extent(points, d => d.x);
38 | const yDomain = d3.extent(points, d => d.y);
39 |
40 | // use d3 to create scales based on the dimensions and domains
41 | const x = d3.scale.linear().domain(xDomain)
42 | .range([innerMargin.left, innerMargin.left + innerWidth]);
43 |
44 | const y = d3.scale.linear().domain(yDomain)
45 | .range([innerMargin.top, innerMargin.top + innerHeight]);
46 |
47 | // create radius scale based on data
48 | const rDomain = d3.extent(points, d => d.r);
49 | const numCols = xDomain[1];
50 | const r = d3.scale.linear().domain(rDomain)
51 | .range([0, (innerWidth / numCols) / 2]);
52 |
53 | // create color scale (colors from http://colorbrewer2.org)
54 | const color = d3.scale.linear().domain([0.3, 0.45, 0.6])
55 | .range(['#0571b0', '#f7f7f7', '#ca0020']).clamp(true);
56 |
57 | return {
58 | points,
59 | width,
60 | height,
61 | innerMargin,
62 | x,
63 | y,
64 | r,
65 | color
66 | };
67 | },
68 |
69 | _handleHighlight(d) {
70 | this.setState({ highlight: d });
71 | },
72 |
73 | _renderHighlight(chartComponents) {
74 | const { highlight } = this.state;
75 | const { innerMargin, height, x, y, r, color } = chartComponents;
76 |
77 | // no highlight, so don't show anything
78 | if (!highlight) {
79 | return null;
80 | }
81 |
82 | // show a circle around the point and the text details of the point
83 | return (
84 |
85 |
88 |
89 | {`Rank #${highlight.datum.rank},
90 | Frequency ${d3.format('0.1f')(highlight.datum.frequency)},
91 | Accuracy ${d3.format('0.1%')(highlight.datum.accuracy)}`}
92 |
93 |
94 | );
95 | },
96 |
97 | render() {
98 | const chartComponents = this._chartComponents();
99 | const { points, width, height, x, y, r, color } = chartComponents;
100 | return (
101 |
112 | );
113 | }
114 | });
115 |
116 | export default VisExample6;
117 |
--------------------------------------------------------------------------------
/src/components/VisExample7.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import d3 from 'd3';
3 |
4 | const VisExample7 = React.createClass({
5 | propTypes: {
6 | data: React.PropTypes.array.isRequired,
7 | height: React.PropTypes.number.isRequired,
8 | width: React.PropTypes.number.isRequired
9 | },
10 |
11 | getInitialState() {
12 | return {};
13 | },
14 |
15 | _chartComponents() {
16 | /* data is of format:
17 | data = [{ locationX, locationY, frequency, accuracy, rank }, ...] */
18 | const { width, height, data } = this.props;
19 |
20 | // convert data points into chart points
21 | const points = data.map(d => {
22 | return {
23 | x: d.locationX,
24 | y: d.locationY,
25 | r: d.frequency,
26 | color: d.accuracy,
27 | datum: d
28 | };
29 | });
30 |
31 | // define the inner margins of the chart
32 | const innerMargin = { top: 10, bottom: 25, left: 10, right: 10 };
33 | const innerWidth = width - innerMargin.left - innerMargin.right;
34 | const innerHeight = height - innerMargin.top - innerMargin.bottom;
35 |
36 | // get the range of values from the x and y attributes in the data
37 | const xDomain = d3.extent(points, d => d.x);
38 | const yDomain = d3.extent(points, d => d.y);
39 |
40 | // use d3 to create scales based on the dimensions and domains
41 | const x = d3.scale.linear().domain(xDomain)
42 | .range([innerMargin.left, innerMargin.left + innerWidth]);
43 |
44 | const y = d3.scale.linear().domain(yDomain)
45 | .range([innerMargin.top, innerMargin.top + innerHeight]);
46 |
47 | // create radius scale based on data
48 | const rDomain = d3.extent(points, d => d.r);
49 | const numCols = xDomain[1];
50 | const r = d3.scale.linear().domain(rDomain)
51 | .range([0, (innerWidth / numCols) / 2]);
52 |
53 | // create color scale (colors from http://colorbrewer2.org)
54 | const color = d3.scale.linear().domain([0.3, 0.45, 0.6])
55 | .range(['#0571b0', '#f7f7f7', '#ca0020']).clamp(true);
56 |
57 | return {
58 | points,
59 | width,
60 | height,
61 | innerMargin,
62 | x,
63 | y,
64 | r,
65 | color
66 | };
67 | },
68 |
69 | _handleHighlight(d) {
70 | this.setState({ highlight: d });
71 | },
72 |
73 | _renderHighlight(chartComponents) {
74 | const { highlight } = this.state;
75 | const { innerMargin, height, x, y, r, color } = chartComponents;
76 |
77 | // no highlight, so don't show anything
78 | if (!highlight) {
79 | return null;
80 | }
81 |
82 | // show a circle around the point and the text details of the point
83 | return (
84 |
85 |
88 |
89 | {`Rank #${highlight.datum.rank},
90 | Frequency ${d3.format('0.1f')(highlight.datum.frequency)},
91 | Accuracy ${d3.format('0.1%')(highlight.datum.accuracy)}`}
92 |
93 |
94 | );
95 | },
96 |
97 | render() {
98 | const chartComponents = this._chartComponents();
99 | const { points, width, height, x, y, r, color } = chartComponents;
100 | const maxRadius = r.range()[1];
101 | return (
102 |
121 | );
122 | }
123 | });
124 |
125 | export default VisExample7;
126 |
--------------------------------------------------------------------------------
/src/components/VisExample8.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PureRenderMixin from 'react-addons-pure-render-mixin';
3 | import d3 from 'd3';
4 |
5 | const VisExample8Points = React.createClass({
6 | mixins: [PureRenderMixin],
7 |
8 | propTypes: {
9 | chartComponents: React.PropTypes.object.isRequired,
10 | onHighlight: React.PropTypes.func
11 | },
12 |
13 | _handleHighlight(d) {
14 | if (this.props.onHighlight) {
15 | this.props.onHighlight(d);
16 | }
17 | },
18 |
19 | render() {
20 | const { points, x, y, r, color } = this.props.chartComponents;
21 | const maxRadius = r.range()[1];
22 |
23 | return (
24 |
25 | {points.map((d, i) => {
26 | return (
27 |
28 |
30 |
36 |
37 | );
38 | })}
39 |
40 | );
41 | }
42 | });
43 |
44 | const VisExample8Highlight = React.createClass({
45 | mixins: [PureRenderMixin],
46 |
47 | propTypes: {
48 | chartComponents: React.PropTypes.object.isRequired,
49 | highlight: React.PropTypes.object
50 | },
51 |
52 | render() {
53 | const { highlight, chartComponents } = this.props;
54 | const { innerMargin, height, x, y, r, color } = chartComponents;
55 |
56 | // no highlight, so don't show anything
57 | if (!highlight) {
58 | return null;
59 | }
60 |
61 | // show a circle around the point and the text details of the point
62 | return (
63 |
64 |
67 |
68 | {`Rank #${highlight.datum.rank},
69 | Frequency ${d3.format('0.1f')(highlight.datum.frequency)},
70 | Accuracy ${d3.format('0.1%')(highlight.datum.accuracy)}`}
71 |
72 |
73 | );
74 | }
75 | });
76 |
77 |
78 | const VisExample8 = React.createClass({
79 | propTypes: {
80 | data: React.PropTypes.array.isRequired,
81 | height: React.PropTypes.number.isRequired,
82 | width: React.PropTypes.number // do not put isRequired to prevent render on null
83 | },
84 |
85 | getInitialState() {
86 | return {
87 | chartComponents: this._chartComponents()
88 | };
89 | },
90 |
91 | componentWillReceiveProps(nextProps) {
92 | this.setState({
93 | chartComponents: this._chartComponents(nextProps)
94 | });
95 | },
96 |
97 | _chartComponents(props = this.props) {
98 | /* data is of format:
99 | data = [{ locationX, locationY, frequency, accuracy, rank }, ...] */
100 | const { width, height, data } = props;
101 |
102 | // convert data points into chart points
103 | const points = data.map(d => {
104 | return {
105 | x: d.locationX,
106 | y: d.locationY,
107 | r: d.frequency,
108 | color: d.accuracy,
109 | datum: d
110 | };
111 | });
112 |
113 | // define the inner margins of the chart
114 | const innerMargin = { top: 10, bottom: 25, left: 10, right: 10 };
115 | const innerWidth = width - innerMargin.left - innerMargin.right;
116 | const innerHeight = height - innerMargin.top - innerMargin.bottom;
117 |
118 | // get the range of values from the x and y attributes in the data
119 | const xDomain = d3.extent(points, d => d.x);
120 | const yDomain = d3.extent(points, d => d.y);
121 |
122 | // use d3 to create scales based on the dimensions and domains
123 | const x = d3.scale.linear().domain(xDomain)
124 | .range([innerMargin.left, innerMargin.left + innerWidth]);
125 |
126 | const y = d3.scale.linear().domain(yDomain)
127 | .range([innerMargin.top, innerMargin.top + innerHeight]);
128 |
129 | // create radius scale based on data
130 | const rDomain = d3.extent(points, d => d.r);
131 | const numCols = xDomain[1];
132 | const r = d3.scale.linear().domain(rDomain)
133 | .range([0, (innerWidth / numCols) / 2]);
134 |
135 | // create color scale (colors from http://colorbrewer2.org)
136 | const color = d3.scale.linear().domain([0.3, 0.45, 0.6])
137 | .range(['#0571b0', '#f7f7f7', '#ca0020']).clamp(true);
138 |
139 | return {
140 | points,
141 | width,
142 | height,
143 | innerMargin,
144 | x,
145 | y,
146 | r,
147 | color
148 | };
149 | },
150 |
151 | _handleHighlight(d) {
152 | this.setState({ highlight: d });
153 | },
154 |
155 | _renderHighlight() {
156 | const { highlight, chartComponents } = this.state;
157 |
158 | // no highlight, so don't show anything
159 | if (!highlight) {
160 | return null;
161 | }
162 |
163 | // show a circle around the point and the text details of the point
164 | return ;
166 | },
167 |
168 | render() {
169 | const { chartComponents } = this.state;
170 | const { width, height } = chartComponents;
171 |
172 | if (!width) {
173 | return null;
174 | }
175 |
176 | return (
177 |
182 | );
183 | }
184 | });
185 |
186 | export default VisExample8;
187 |
--------------------------------------------------------------------------------
/src/components/VisExampleApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import d3 from 'd3';
4 |
5 | import VisExample1 from './VisExample1';
6 | import VisExample2 from './VisExample2';
7 | import VisExample3 from './VisExample3';
8 | import VisExample4 from './VisExample4';
9 | import VisExample5 from './VisExample5';
10 | import VisExample6 from './VisExample6';
11 | import VisExample7 from './VisExample7';
12 | import VisExample8 from './VisExample8';
13 | import AutoWidth from 'react-auto-width';
14 |
15 | // CSS via webpack
16 | require('normalize.css');
17 | require('../styles/main.css');
18 |
19 | const VisExampleApp = React.createClass({
20 | getInitialState() {
21 | // make up some data
22 | const data = [];
23 | const numRows = 30;
24 | const numCols = 50;
25 | const freqRng = d3.random.normal(15, 15);
26 | const accRng = d3.random.normal(0.45, 0.1);
27 | const rankRng = () => Math.ceil(Math.random() * 300);
28 |
29 | for (let x = 0; x < numCols; x++) {
30 | for (let y = 0; y < numRows; y++) {
31 | const freq = freqRng();
32 | data.push({ locationX: x, locationY: y, frequency: freq < 0 ? 0 : freq, accuracy: accRng(), rank: rankRng() });
33 | }
34 | }
35 |
36 | return {
37 | data: data
38 | };
39 | },
40 |
41 | // render the line chart and radial heatmap
42 | render() {
43 | const { data } = this.state;
44 |
45 | return (
46 |
47 |
48 |
Example 1 - Basic SVG Drawing
49 |
50 |
51 |
52 |
Example 2 - SVG Drawing from Data Array
53 |
54 |
55 |
56 |
Example 3 - External Data Points
57 |
58 |
59 |
60 |
Example 4 - D3 Scales
61 |
62 |
63 |
64 |
Example 5 - Inner Margin
65 |
66 |
67 |
68 |
Example 6 - Highlight Behaviour (flickers)
69 |
70 |
71 |
72 |
Example 7 - Highlight Behaviour (slow)
73 |
74 |
75 |
76 |
Example 8 - Highlight Behaviour (optimized)
77 |
78 |
79 |
80 |
Example 9 - Highlight Behaviour (optimized, auto width)
81 |
82 |
83 |
84 |
85 |
86 | );
87 | }
88 | });
89 |
90 | ReactDOM.render(, document.getElementById('content'));
91 |
92 | export default VisExampleApp;
93 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Basic Vis Examples with React
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/styles/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #fff;
3 | color: #333;
4 | padding: 10px;
5 | }
6 |
7 | h4 {
8 | margin: 0;
9 | }
10 |
11 | .chart {
12 | margin: 10px 0;
13 | border: 1px solid #aaa;
14 | }
15 |
16 | text {
17 | dominant-baseline: hanging;
18 | }
19 |
20 | .highlight {
21 | pointer-events: none;
22 | }
23 |
24 | .example {
25 | margin-bottom: 50px;
26 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Webpack development server configuration
3 | *
4 | * This file is set up for serving the webpack-dev-server, which will watch for changes and recompile as required if
5 | * the subfolder /webpack-dev-server/ is visited. Visiting the root will not automatically reload.
6 | */
7 | 'use strict';
8 | var webpack = require('webpack');
9 |
10 | module.exports = {
11 |
12 | output: {
13 | filename: 'main.js',
14 | publicPath: '/assets/'
15 | },
16 |
17 | cache: true,
18 | debug: true,
19 | devtool: false,
20 | entry: [
21 | 'webpack/hot/only-dev-server',
22 | './src/components/VisExampleApp.js'
23 | ],
24 |
25 | stats: {
26 | colors: true,
27 | reasons: true
28 | },
29 |
30 | resolve: {
31 | extensions: ['', '.js'],
32 | alias: {
33 | 'styles': __dirname + '/src/styles',
34 | 'mixins': __dirname + '/src/mixins',
35 | 'components': __dirname + '/src/components/',
36 | 'stores': __dirname + '/src/stores/',
37 | 'actions': __dirname + '/src/actions/'
38 | }
39 | },
40 | module: {
41 | loaders: [{
42 | test: /\.js$/,
43 | exclude: /node_modules/,
44 | loader: 'react-hot!babel-loader'
45 | }, {
46 | test: /\.css$/,
47 | loader: 'style-loader!css-loader'
48 | }, {
49 | test: /\.(png|jpg)$/,
50 | loader: 'url-loader?limit=8192'
51 | }]
52 | },
53 |
54 | plugins: [
55 | new webpack.HotModuleReplacementPlugin(),
56 | new webpack.NoErrorsPlugin()
57 | ]
58 |
59 | };
60 |
--------------------------------------------------------------------------------
/webpack.dist.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Webpack distribution configuration
3 | *
4 | * This file is set up for serving the distribution version. It will be compiled to dist/ by default
5 | */
6 |
7 | 'use strict';
8 |
9 | var webpack = require('webpack');
10 |
11 | module.exports = {
12 |
13 | output: {
14 | publicPath: '/assets/',
15 | path: 'dist/assets/',
16 | filename: 'main.js'
17 | },
18 |
19 | debug: false,
20 | devtool: false,
21 | entry: './src/components/VisExampleApp.js',
22 |
23 | stats: {
24 | colors: true,
25 | reasons: false
26 | },
27 |
28 | plugins: [
29 | new webpack.optimize.DedupePlugin(),
30 | new webpack.optimize.UglifyJsPlugin(),
31 | new webpack.optimize.OccurenceOrderPlugin(),
32 | new webpack.optimize.AggressiveMergingPlugin()
33 | ],
34 |
35 | resolve: {
36 | extensions: ['', '.js'],
37 | alias: {
38 | 'styles': __dirname + '/src/styles',
39 | 'mixins': __dirname + '/src/mixins',
40 | 'components': __dirname + '/src/components/',
41 | 'stores': __dirname + '/src/stores/',
42 | 'actions': __dirname + '/src/actions/'
43 | }
44 | },
45 |
46 | module: {
47 | preLoaders: [{
48 | test: /\.js$/,
49 | exclude: /node_modules/,
50 | loader: 'jsxhint'
51 | }],
52 |
53 | loaders: [{
54 | test: /\.js$/,
55 | exclude: /node_modules/,
56 | loader: 'babel-loader'
57 | }, {
58 | test: /\.css$/,
59 | loader: 'style-loader!css-loader'
60 | }, {
61 | test: /\.(png|jpg)$/,
62 | loader: 'url-loader?limit=8192'
63 | }]
64 | }
65 | };
66 |
--------------------------------------------------------------------------------