├── examples ├── index.cjsx ├── index.html └── examples.cjsx ├── .npmignore ├── .gitignore ├── Makefile ├── README.md ├── webpack.production.config.js ├── webpack.config.js ├── LICENSE ├── package.json └── src └── index.cjsx /examples/index.cjsx: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | ReactDOM = require('react-dom'); 3 | Examples = require './examples' 4 | 5 | ReactDOM.render(, document.body) 6 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Deployed apps should consider commenting this line out: 24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 25 | node_modules 26 | src/ 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Deployed apps should consider commenting this line out: 24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 25 | node_modules 26 | dist/ 27 | examples/bundle.js 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN = ./node_modules/.bin 2 | 3 | release-patch: 4 | @$(call release,patch) 5 | 6 | release-minor: 7 | @$(call release,minor) 8 | 9 | release-major: 10 | @$(call release,major) 11 | 12 | build: 13 | @$(BIN)/cjsx -cb -o dist src/index.cjsx 14 | webpack 15 | 16 | publish: 17 | git push --tags origin HEAD:master 18 | @$(BIN)/cjsx -cb -o dist src/index.cjsx 19 | npm publish 20 | 21 | publish-gh-pages: 22 | git checkout gh-pages 23 | git merge master 24 | webpack --config webpack.production.config.js 25 | cp examples/* . 26 | git add --all . 27 | git commit -m "New release" 28 | git push origin gh-pages 29 | git checkout master 30 | 31 | define release 32 | npm version $(1) 33 | endef 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | react-sparkline 2 | =============== 3 | 4 | React component for rendering simple sparklines. Companion to [react-micro-bar-chart](https://github.com/KyleAMathews/react-micro-bar-chart). 5 | 6 | ## Install 7 | `npm install react-sparkline` 8 | 9 | ## Usage 10 | ````javascript 11 | var Sparkline = require('react-sparkline'); 12 | 13 | // Pass in an array of values. 14 | 15 | 16 | // Sparkline of dates + values 17 | // Pass in an array of objects something like 18 | values = [ 19 | { 20 | date: "2014-06-23T00:21:59.271Z" 21 | value: 2 22 | }, 23 | { 24 | date: "2014-06-24T00:21:59.271Z" 25 | value: 4 26 | } 27 | ] 28 | 29 | 30 | ```` 31 | 32 | ## Demo 33 | http://kyleamathews.github.io/react-sparkline/ 34 | -------------------------------------------------------------------------------- /webpack.production.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | 5 | module.exports = { 6 | entry: [ 7 | './examples/index' 8 | ], 9 | output: { 10 | path: path.join(__dirname, 'examples'), 11 | filename: 'bundle.js', 12 | }, 13 | resolveLoader: { 14 | modulesDirectories: ['node_modules'] 15 | }, 16 | plugins: [ 17 | new webpack.DefinePlugin({ 18 | "process.env": { 19 | NODE_ENV: JSON.stringify("production") 20 | } 21 | }), 22 | new webpack.optimize.DedupePlugin(), 23 | new webpack.optimize.UglifyJsPlugin() 24 | ], 25 | resolve: { 26 | extensions: ['', '.js', '.cjsx', '.coffee'] 27 | }, 28 | module: { 29 | loaders: [ 30 | { test: /\.css$/, loaders: ['style', 'css']}, 31 | { test: /\.cjsx$/, loaders: ['coffee', 'cjsx']}, 32 | { test: /\.coffee$/, loader: 'coffee' } 33 | ] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: [ 6 | "webpack-dev-server/client?http://0.0.0.0:8080", 7 | 'webpack/hot/only-dev-server', 8 | './examples/index' 9 | ], 10 | devServer: { 11 | contentBase: './examples/' 12 | }, 13 | devtool: "eval", 14 | debug: true, 15 | output: { 16 | path: path.join(__dirname, 'examples'), 17 | filename: 'bundle.js', 18 | }, 19 | resolveLoader: { 20 | modulesDirectories: ['node_modules'] 21 | }, 22 | plugins: [ 23 | new webpack.HotModuleReplacementPlugin(), 24 | new webpack.NoErrorsPlugin(), 25 | new webpack.IgnorePlugin(/un~$/) 26 | ], 27 | resolve: { 28 | extensions: ['', '.js', '.cjsx', '.coffee'] 29 | }, 30 | module: { 31 | loaders: [ 32 | { test: /\.css$/, loaders: ['style', 'css']}, 33 | { test: /\.cjsx$/, loaders: ['react-hot', 'coffee', 'cjsx']}, 34 | { test: /\.coffee$/, loader: 'coffee' } 35 | ] 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Kyle Mathews 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-sparkline", 3 | "description": "React component for rendering simple sparklines with D3", 4 | "version": "2.0.0", 5 | "author": "Kyle Mathews ", 6 | "bugs": { 7 | "url": "https://github.com/KyleAMathews/react-sparkline/issues" 8 | }, 9 | "dependencies": { 10 | "d3": "^3.5.6" 11 | }, 12 | "devDependencies": { 13 | "cjsx-loader": "^2.0.1", 14 | "coffee-loader": "^0.7.2", 15 | "coffee-react": "^4.0.0", 16 | "coffee-script": "^1.10.0", 17 | "css-loader": "^0.19.0", 18 | "faker": "^3.0.1", 19 | "react": "^0.14.0", 20 | "react-dom": "^0.14.0", 21 | "react-hot-loader": "^1.3.0", 22 | "react-simple-table": "^0.6.1", 23 | "style-loader": "^0.12.4", 24 | "underscore": "^1.8.3", 25 | "webpack": "^1.12.2", 26 | "webpack-dev-server": "^1.12.0" 27 | }, 28 | "homepage": "https://github.com/KyleAMathews/react-sparkline", 29 | "keywords": [ 30 | "react", 31 | "react-component", 32 | "sparkline", 33 | "d3" 34 | ], 35 | "license": "MIT", 36 | "main": "dist/index.js", 37 | "peerDependencies": { 38 | "react": "*", 39 | "react-dom": "*" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "https://github.com/KyleAMathews/react-sparkline.git" 44 | }, 45 | "scripts": { 46 | "test": "echo \"Error: no test specified\" && exit 1", 47 | "watch": "./node_modules/.bin/webpack-dev-server --hot" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/index.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | ReactDOM = require 'react-dom' 3 | d3 = require 'd3' 4 | 5 | module.exports = React.createClass 6 | 7 | getDefaultProps: -> 8 | return { 9 | width: 100 10 | height: 16 11 | strokeColor: 'black' 12 | strokeWidth: '0.5px' 13 | interpolate: 'basis' 14 | circleDiameter: 1.5 15 | data: [1,23,5,5,23,0,0,0,4,32,3,12,3,1,24,1,5,5,24,23] # Some semi-random data. 16 | } 17 | 18 | componentDidMount: -> 19 | @renderSparkline() 20 | 21 | componentDidUpdate: -> 22 | @renderSparkline() 23 | 24 | render: -> 25 |
26 | 27 | renderSparkline: () -> 28 | # If the sparkline has already been rendered, remove it. 29 | el = ReactDOM.findDOMNode(@) 30 | while (el.firstChild) 31 | el.removeChild(el.firstChild) 32 | 33 | data = @props.data.slice() 34 | 35 | # Do nothing if no data is passed in. 36 | if data.length is 0 37 | return 38 | 39 | x = d3.scale.linear().range([2, @props.width - 2]) 40 | y = d3.scale.linear().range([@props.height - 2, 2]) 41 | 42 | # react-sparkline allows you to pass in two types of data. 43 | # Data tied to dates and linear data. We need to change our line and x/y 44 | # functions depending on the type of data. 45 | 46 | # These are objects with a date key 47 | if data[0]?.date? 48 | # Convert dates into D3 dates 49 | data.forEach (d) -> d.date = d3.time.format.iso.parse(d.date) 50 | 51 | line = d3.svg.line() 52 | .interpolate(@props.interpolate) 53 | .x((d,i) -> x(d.date)) 54 | .y((d) -> y(d.value)) 55 | 56 | x.domain(d3.extent(data, (d) -> d.date)) 57 | y.domain(d3.extent(data, (d) -> d.value)) 58 | 59 | lastX = x(data[data.length - 1].date) 60 | lastY = y(data[data.length - 1].value) 61 | 62 | else 63 | line = d3.svg.line() 64 | .interpolate(@props.interpolate) 65 | .x((d,i) -> x(i)) 66 | .y((d) -> y(d)) 67 | 68 | x.domain([0, data.length]) 69 | y.domain(d3.extent(data)) 70 | 71 | lastX = x(data.length - 1) 72 | lastY = y(data[data.length - 1]) 73 | 74 | svg = d3.select(ReactDOM.findDOMNode(@)) 75 | .append('svg') 76 | .attr('width', @props.width) 77 | .attr('height', @props.height) 78 | .append('g') 79 | 80 | svg.append('path') 81 | .datum(data) 82 | .attr('class', 'sparkline') 83 | .style('fill', 'none') 84 | .style('stroke', @props.strokeColor) 85 | .style('stroke-width', @props.strokeWidth) 86 | .attr('d', line) 87 | 88 | svg.append('circle') 89 | .attr('class', 'sparkcircle') 90 | .attr('cx', lastX) 91 | .attr('cy', lastY) 92 | .attr('fill', 'red') 93 | .attr('stroke', 'none') 94 | .attr('r', @props.circleDiameter) 95 | -------------------------------------------------------------------------------- /examples/examples.cjsx: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | Table = require 'react-simple-table' 3 | faker = require 'faker' 4 | Sparkline = require('../src/index') 5 | _ = require 'underscore' 6 | 7 | columns = ['apple', 'peach', { 8 | displayName: 'activity' 9 | function: (data) -> 10 | }] 11 | 12 | data = for i in [0..5] 13 | { 14 | apple: faker.lorem.words(1) 15 | peach: faker.lorem.words(1) 16 | data: for i in [0..50] 17 | faker.random.number(20) 18 | } 19 | 20 | dateData = for i in [0..100] 21 | { 22 | date: faker.date.between("2014-06-23T00:21:59.271Z", "2014-07-23T00:21:59.271Z") 23 | value: faker.random.number(100) 24 | } 25 | 26 | dateData = _.sortBy dateData, (datum) -> return datum.date 27 | 28 | UpdatingSparkline = React.createClass 29 | displayName: 'UpdatingSparkline' 30 | 31 | getInitialState: -> 32 | data: [1,2,1] 33 | 34 | componentDidMount: -> 35 | setInterval((=> 36 | data = @state.data.slice() 37 | data.push faker.random.number(10) 38 | if data.length > 50 39 | data = _.last data, 50 40 | @setState data: data 41 | ),500) 42 | 43 | render: -> 44 | 49 | 50 | module.exports = React.createClass 51 | render: -> 52 |
53 |

React-Sparkline

54 | Code on Github 55 |
56 |
57 |

Default look

58 |

 59 |       {"""
 60 |       
 61 |         """}
 62 |       
63 | 64 | 65 |

Override all defaults

66 |

 67 |       {"""
 68 |       
 75 |         """}
 76 |       
77 | 84 |
85 | 86 |

Updating data

87 | 88 |
89 | 90 |

Pass in non-date data

91 |

 92 |       {"""
 93 |       
 98 |         """}
 99 |       
100 | 105 |
106 | 107 |

Pass in date data

108 |

109 |       {"""
110 |       dateData = for i in [0..100]
111 |         {
112 |           date: faker.date.between("2014-06-23T00:21:59.271Z", "2014-07-23T00:21:59.271Z")
113 |           value: faker.random.number(100)
114 |         }
115 | 
116 |       dateData = _.sortBy dateData, (datum) -> return datum.date
117 | 
118 |       
123 |         """}
124 |       
125 | 130 |
131 | 132 |

Use in table

133 | 134 |
135 |
136 |
137 |
138 | 139 |

If no data is passed in, an empty div is returned

140 |

141 |         {""}
142 |       
143 | 144 | 145 | 146 | --------------------------------------------------------------------------------