├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── build ├── bundle.js └── index.html ├── examples ├── actions │ └── DataActions.js ├── assets │ └── stylesheet.css ├── components │ ├── C3Chart.jsx │ ├── C3Index.jsx │ └── DocIndex.jsx ├── constants.js ├── index.jsx └── stores │ └── DataStore.js ├── index.js ├── lib └── C3Chart.js ├── package.json ├── src ├── C3Chart.jsx └── assets │ └── c3.css └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | webpack.config.js 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "es6": true, 6 | "mocha": true, 7 | "node": true 8 | }, 9 | "ecmaFeatures": { 10 | "arrowFunctions": true, 11 | "blockBindings": true, 12 | "classes": true, 13 | "defaultParams": true, 14 | "destructuring": true, 15 | "forOf": true, 16 | "generators": true, 17 | "modules": true, 18 | "spread": true, 19 | "templateStrings": true, 20 | "jsx": true 21 | }, 22 | "rules": { 23 | "no-unused-expressions": 0, 24 | "consistent-return": [0], 25 | "comma-dangle": "always", 26 | "eol-last": [0], 27 | "key-spacing": [0], 28 | "new-cap": [0], 29 | "no-comma-dangle": [0], 30 | "no-mixed-requires": [0], 31 | "no-multi-spaces": [0], 32 | "no-shadow": [0], 33 | "no-unused-vars": [1], 34 | "no-use-before-define": [2, "nofunc"], 35 | "no-underscore-dangle": [0], 36 | "quotes": [1, "double"], 37 | "space-before-function-parentheses": "always", 38 | "no-var": [2], 39 | "curly": [2], 40 | 41 | // Stylistic 42 | "brace-style": [2], 43 | "comma-spacing": [2], 44 | "new-cap": [0], 45 | "space-infix-ops": [2], 46 | 47 | // React 48 | "react/display-name": 1, 49 | "react/jsx-boolean-value": 1, 50 | "react/jsx-quotes": 1, 51 | "react/jsx-no-undef": 1, 52 | "react/jsx-uses-react": 1, 53 | "react/jsx-uses-vars": 1, 54 | "react/no-did-mount-set-state": 1, 55 | "react/no-did-update-set-state": 1, 56 | "react/no-multi-comp": 1, 57 | "react/no-unknown-property": 1, 58 | "react/prop-types": 1, 59 | "react/react-in-jsx-scope": 1, 60 | "react/self-closing-comp": 1, 61 | "react/wrap-multilines": 1 62 | }, 63 | "globals": { 64 | "process": true 65 | }, 66 | "plugins": [ 67 | "react" 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | # Ignore bundler config. 7 | /.bundle 8 | # Ignore all logfiles and tempfiles. 9 | /log/*.log 10 | /tmp 11 | 12 | .DS_Store 13 | 14 | # Ignore npm related files 15 | node_modules 16 | .npm-debug.log 17 | npm-debug.log 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ming-Hsun Tsai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # c3-react 2 | 3 | c3-react is a reusable react component for [c3](https://github.com/masayuki0812/c3) charts 4 | [demo](http://terry81811.github.io/c3-react/build/#/c3) 5 | 6 | ## How to install 7 | 8 | ``` 9 | npm install c3-react 10 | ``` 11 | 12 | ## How to use 13 | 14 | ``` 15 | const C3Chart = require("./C3Chart.jsx"); 16 | ``` 17 | 18 | * In parnet component 19 | ``` 20 | 21 | ``` 22 | 23 | * data example: 24 | ``` 25 | let data = [ 26 | { 27 | key: "dataSource1" 28 | values: [ 29 | {label: "A", value: 3}, 30 | {label: "B", value: 4} 31 | ] 32 | }, 33 | { 34 | key: "dataSource2" 35 | values: [ 36 | {label: "X", value: 7}, 37 | {label: "Y", value: 8} 38 | ] 39 | } 40 | ] 41 | ``` 42 | 43 | * supported types 44 | ``` 45 | let type = "bar" // {"line","bar","pie", "multiBar","lineBar"} 46 | ``` 47 | 48 | * options example 49 | ``` 50 | let options = { 51 | padding: { 52 | top: 20, 53 | bottom: 20, 54 | left: 40, 55 | right: 10 56 | }, 57 | size: { 58 | width: 800, 59 | height: 600 60 | }, 61 | subchart: true, 62 | zoom: true, 63 | grid: { 64 | x: false, 65 | y: true 66 | }, 67 | labels: true, 68 | axisLabel: { 69 | x: "product", 70 | y: "quantity" 71 | }, 72 | onClick: function(d) { 73 | let categories = this.categories(); //c3 function, get categorical labels 74 | console.log(d); 75 | console.log("you clicked {" + d.name + ": " + categories[d.x] + ": " + d.value + "}"); 76 | } 77 | }; 78 | ``` 79 | 80 | 81 | ## How to run examples 82 | 83 | ``` 84 | $ cd c3-react 85 | $ npm install 86 | $ npm run dev 87 | ``` 88 | 89 | ## Release Note 90 | 91 | + 0.1.6 - provide compiled es5 module 92 | 93 | 94 | ## Dependency 95 | + [C3.js](https://github.com/masayuki0812/c3) `<=0.4.10` 96 | + [D3.js](https://github.com/mbostock/d3) `<=3.5.0` 97 | 98 | ## License 99 | MIT 100 | -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | c3-react 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/actions/DataActions.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Const = require("../constants"); 4 | const DataActTypes = Const.ActTypes.Data; 5 | 6 | const DataActions = exports; 7 | 8 | DataActions.newData = function () { 9 | this.dispatch( 10 | DataActTypes.NEW_DATA, {} 11 | ); 12 | }; 13 | 14 | DataActions.addEntry = function () { 15 | this.dispatch( 16 | DataActTypes.ADD_ENTRY, {} 17 | ); 18 | }; 19 | 20 | DataActions.removeEntry = function () { 21 | this.dispatch( 22 | DataActTypes.REMOVE_ENTRY, {} 23 | ); 24 | }; 25 | 26 | DataActions.removeData = function () { 27 | this.dispatch( 28 | DataActTypes.REMOVE_DATA, {} 29 | ); 30 | }; 31 | 32 | DataActions.changeChartType = function (type) { 33 | this.dispatch( 34 | DataActTypes.CHANGE_CHART_TYPE, 35 | {type: type} 36 | ); 37 | }; -------------------------------------------------------------------------------- /examples/assets/stylesheet.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | 5 | .wrapper { 6 | height: 100%; 7 | width: 100%; 8 | position: relative; 9 | padding-top: 60px; 10 | } 11 | -------------------------------------------------------------------------------- /examples/components/C3Chart.jsx: -------------------------------------------------------------------------------- 1 | const React = require("react"); 2 | const _ = require("lodash"); 3 | 4 | const c3 = require("c3"); 5 | const d3 = require("d3"); 6 | 7 | let C3Chart = React.createClass({ 8 | displayName: "C3Chart", 9 | propTypes: { 10 | type: React.PropTypes.string.isRequired, 11 | data: React.PropTypes.array.isRequired, 12 | options: React.PropTypes.shape({ 13 | padding: React.PropTypes.shape({ 14 | top: React.PropTypes.number, 15 | bottom: React.PropTypes.number, 16 | left: React.PropTypes.number, 17 | right: React.PropTypes.number 18 | }), 19 | size: React.PropTypes.shape({ 20 | width: React.PropTypes.number, 21 | height: React.PropTypes.number, 22 | }), 23 | labels: React.PropTypes.bool, 24 | onclick: React.PropTypes.func, 25 | axisLabel: React.PropTypes.shape({ 26 | x: React.PropTypes.string, 27 | y: React.PropTypes.string 28 | }), 29 | subchart: React.PropTypes.bool, 30 | zoom: React.PropTypes.bool, 31 | grid: React.PropTypes.shape({ 32 | x: React.PropTypes.bool, 33 | y: React.PropTypes.bool 34 | }) 35 | }) 36 | }, 37 | 38 | //color theme 39 | colors: function(count) { 40 | let colors = []; 41 | let color = d3.scale.category10(); 42 | for(let i = 0; i < count; i++){ 43 | colors.push(color(i)); 44 | } 45 | return colors; 46 | }, 47 | 48 | //apply props.options to graph json 49 | graphObject: function() { 50 | let graphObject = { 51 | data: {}, 52 | axis: {}, 53 | bindto: "#chartContainer", 54 | color: { 55 | pattern: this.colors(20) 56 | } 57 | }; 58 | let options = this.props.options; 59 | if(options.padding){ 60 | graphObject.padding = { 61 | top: options.padding.top, 62 | left: options.padding.left, 63 | right: options.padding.right, 64 | bottom: options.padding.bottom 65 | }; 66 | } 67 | if(options.size){ 68 | graphObject.size = { 69 | width: options.size.width, 70 | height: options.size.height 71 | }; 72 | } 73 | if(options.labels){ 74 | graphObject.data.labels = options.labels; 75 | } 76 | if(options.onClick){ 77 | graphObject.data.onclick = options.onClick; 78 | } 79 | if(options.axisLabel){ 80 | graphObject.axis.x = {label: options.axisLabel.x}; 81 | graphObject.axis.y = {label: options.axisLabel.y}; 82 | } 83 | if(options.subchart){ 84 | graphObject.subchart = {show: options.subchart}; 85 | } 86 | if(options.zoom){ 87 | graphObject.zoom = {enabled: options.zoom}; 88 | } 89 | if(options.grid){ 90 | graphObject.grid = { 91 | x:{show: options.grid.x}, 92 | y:{show: options.grid.y} 93 | }; 94 | } 95 | return graphObject; 96 | }, 97 | 98 | //c3.js 99 | drawGraph: function() { 100 | switch(this.props.type){ 101 | case "line": 102 | this.drawGraphLine(); 103 | break; 104 | case "bar": 105 | this.drawGraphBar(); 106 | break; 107 | case "pie": 108 | this.drawGraphPie(); 109 | break; 110 | case "multiBar": 111 | this.drawGraphMultiBar(); 112 | break; 113 | case "lineBar": 114 | this.drawGraphlLineBar(); 115 | break; 116 | } 117 | }, 118 | 119 | drawGraphLine: function() { 120 | console.log("drawing line"); 121 | let graphObject = this.graphObject(); 122 | let graphObjectData = { 123 | json: this.props.data[0].values, 124 | keys: { x: "label", value: ["value"] }, 125 | names: { value: this.props.data[0].key } 126 | }; 127 | let graphObjectAxis = { 128 | x: { type: "category" } // this needed to load string x value 129 | }; 130 | 131 | graphObject.data = _.merge(graphObjectData, graphObject.data); 132 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 133 | 134 | let chart = c3.generate(graphObject); 135 | return chart; 136 | }, 137 | 138 | drawGraphBar: function() { 139 | console.log("drawing bar"); 140 | let graphObject = this.graphObject(); 141 | let graphObjectData = { 142 | x: "x", 143 | json: this.props.data[0].values, 144 | keys: { x: "label", value: ["value"] }, 145 | names: { value: this.props.data[0].key }, 146 | type: "bar", 147 | labels: true 148 | }; 149 | let graphObjectAxis = { 150 | x: { type: "category" } // this needed to load string x value 151 | }; 152 | 153 | graphObject.data = _.merge(graphObjectData, graphObject.data); 154 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 155 | 156 | let chart = c3.generate(graphObject); 157 | return chart; 158 | }, 159 | 160 | pieChartDataPreparator: function(rawData) { 161 | let data; 162 | data = _.map(rawData, (d) => { 163 | return [d.label, d.value]; 164 | }); 165 | return data; 166 | }, 167 | 168 | drawGraphPie: function() { 169 | console.log("drawing pie"); 170 | let graphObject = this.graphObject(); 171 | let graphObjectData = { 172 | columns: this.pieChartDataPreparator(this.props.data[0].values), 173 | type : "pie" 174 | }; 175 | 176 | graphObject.data = _.merge(graphObjectData, graphObject.data); 177 | 178 | let chart = c3.generate(graphObject); 179 | return chart; 180 | }, 181 | 182 | multiDmsDataPreparator: function(rawData) { 183 | let xLabels = ["x"]; // to make ['x', 'a', 'b', 'c' ...] for labels 184 | _.map(rawData[0].values, (d) => { 185 | xLabels.push(d.label); 186 | }); 187 | 188 | let data; 189 | data = _.map(rawData, (datum) => { 190 | let row = [datum.key]; // to make ['key', 30, 200, 100, 400 ...] for each row 191 | _.map(datum.values, (d) => { 192 | row.push(d.value); 193 | }); 194 | return row; 195 | }); 196 | data.push(xLabels); 197 | return data; 198 | }, 199 | 200 | drawGraphMultiBar: function() { 201 | console.log("drawing multiBar"); 202 | let graphObject = this.graphObject(); 203 | let graphObjectData = { 204 | x: "x", 205 | columns: this.multiDmsDataPreparator(this.props.data), 206 | type: "bar", 207 | labels: true, 208 | }; 209 | let graphObjectAxis = { 210 | x: { type: "category" } // this needed to load string x value 211 | }; 212 | 213 | graphObject.data = _.merge(graphObjectData, graphObject.data); 214 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 215 | 216 | let chart = c3.generate(graphObject); 217 | return chart; 218 | }, 219 | 220 | drawGraphlLineBar: function() { 221 | console.log("drawing LineBar"); 222 | let graphObject = this.graphObject(); 223 | let graphObjectData = { 224 | x: "x", 225 | columns: this.multiDmsDataPreparator(this.props.data), 226 | types: {dataSource1: "bar"}, 227 | }; 228 | let graphObjectAxis = { 229 | x: { type: "category" } // this needed to load string x value 230 | }; 231 | 232 | graphObject.data = _.merge(graphObjectData, graphObject.data); 233 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 234 | 235 | let chart = c3.generate(graphObject); 236 | return chart; 237 | }, 238 | 239 | componentDidMount: function() { 240 | this.drawGraph(); 241 | }, 242 | 243 | componentDidUpdate: function () { 244 | this.drawGraph(); 245 | }, 246 | 247 | render: function() { 248 | return ( 249 |
250 |
251 |
); 252 | } 253 | }); 254 | 255 | module.exports = C3Chart; 256 | -------------------------------------------------------------------------------- /examples/components/C3Index.jsx: -------------------------------------------------------------------------------- 1 | const React = require("react"); 2 | const { 3 | ButtonToolbar, 4 | MenuItem, 5 | SplitButton 6 | } = require("react-bootstrap"); 7 | 8 | const Fluxxor = require("fluxxor"); 9 | const FluxMixin = Fluxxor.FluxMixin(React), 10 | StoreWatchMixin = Fluxxor.StoreWatchMixin; 11 | 12 | const C3Chart = require("./C3Chart.jsx"); 13 | 14 | let C3Index = React.createClass({ 15 | displayName: "C3Component", 16 | mixins: [FluxMixin, StoreWatchMixin("DataStore")], 17 | 18 | getInitialState: function() { 19 | return {}; 20 | }, 21 | 22 | getStateFromFlux: function() { 23 | let flux = this.getFlux(); 24 | return { 25 | DataStore: flux.store("DataStore").getState(), 26 | }; 27 | }, 28 | 29 | handleNewDataClick: function() { 30 | this.getFlux().actions.DataActions.newData(); 31 | }, 32 | 33 | handleAddEntryClick: function() { 34 | this.getFlux().actions.DataActions.addEntry(); 35 | }, 36 | 37 | handleRemoveEntryClick: function() { 38 | this.getFlux().actions.DataActions.removeEntry(); 39 | }, 40 | 41 | handleRemoveDataClick: function() { 42 | this.getFlux().actions.DataActions.removeData(); 43 | }, 44 | 45 | handleChartTypeChange: function(type) { 46 | this.getFlux().actions.DataActions.changeChartType(type); 47 | }, 48 | 49 | render: function () { 50 | //sample options 51 | let options = { 52 | padding: { 53 | top: 20, 54 | bottom: 20, 55 | left: 40, 56 | right: 10 57 | }, 58 | size: { 59 | width: 640, 60 | height: 480 61 | }, 62 | subchart: true, 63 | zoom: true, 64 | grid: { 65 | y: true 66 | }, 67 | labels: true, 68 | axisLabel: { 69 | x: "x軸", 70 | y: "y軸" 71 | }, 72 | onClick: function(d) { 73 | let categories = this.categories(); 74 | console.log(d); 75 | console.log("you clicked {" + d.name + ": " + categories[d.x] + ": " + d.value + "}"); 76 | } 77 | }; 78 | return ( 79 |
80 |

C3-React-Component

81 |

{this.state.DataStore.type}

82 | 83 | 84 | Line 85 | Bar 86 | Pie 87 | MultiBar 88 | Line+Bar 89 | Other 90 | 91 | 92 | New Data 93 | Add Entry 94 | Remove Entry 95 | Remove Data 96 | 97 | 98 |
99 | 102 |
103 |
104 | ); 105 | } 106 | }); 107 | module.exports = C3Index; 108 | -------------------------------------------------------------------------------- /examples/components/DocIndex.jsx: -------------------------------------------------------------------------------- 1 | const React = require("react"); 2 | let DocIndex = React.createClass({ 3 | displayName: "DocComponent", 4 | render: function () { 5 | //sample options 6 | return ( 7 |
8 |

Documentations

9 |

will be available soon. For now, please check source

10 |
11 | ); 12 | } 13 | }); 14 | module.exports = DocIndex; 15 | -------------------------------------------------------------------------------- /examples/constants.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let scopedKeyMirror = function(scope, obj) { 4 | let rtn = {}; 5 | let key; 6 | 7 | for (key in obj) { 8 | let scopedKey = `${scope.toUpperCase()}_${key}`; 9 | if (!obj.hasOwnProperty(key)) { 10 | continue; 11 | } 12 | rtn[key] = scopedKey; 13 | } 14 | 15 | return rtn; 16 | }; 17 | 18 | module.exports = { 19 | ActTypes: { 20 | Data: scopedKeyMirror("DATA", { 21 | NEW_DATA: null, 22 | ADD_ENTRY: null, 23 | REMOVE_ENTRY: null, 24 | REMOVE_DATA: null, 25 | CHANGE_CHART_TYPE: null 26 | }), 27 | }, 28 | 29 | CHANGE_EVENT: "change" 30 | }; 31 | -------------------------------------------------------------------------------- /examples/index.jsx: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | require("./assets/stylesheet.css"); 4 | //c3.js 5 | require("c3/c3.min.css"); 6 | 7 | const React = require("react"); 8 | 9 | let Fluxxor = require("fluxxor"); 10 | let FluxMixin = Fluxxor.FluxMixin(React), 11 | StoreWatchMixin = Fluxxor.StoreWatchMixin; 12 | 13 | let Router = require("react-router"); 14 | let { Route, DefaultRoute, RouteHandler } = Router; 15 | 16 | let { Navbar, Nav, NavItem, 17 | MenuItem, DropdownButton 18 | } = require("react-bootstrap"); 19 | 20 | const C3Index = require("./components/C3Index.jsx"); 21 | const DocIndex = require("./components/DocIndex.jsx"); 22 | 23 | // Initialize Fluxxor 24 | // Stores 25 | let DataStore = require("./stores/DataStore"); 26 | let stores = { 27 | DataStore: new DataStore() 28 | }; 29 | 30 | // Actions 31 | let DataActions = require("./actions/DataActions"); 32 | let actions = { 33 | DataActions: DataActions 34 | }; 35 | 36 | // Flux 37 | let flux = new Fluxxor.Flux(stores, actions); 38 | flux.on("dispatch", function(type, payload) { 39 | if (console && console.log) { 40 | console.log("[Dispatch]", type, payload); 41 | } 42 | }); 43 | 44 | let Index = React.createClass({ 45 | displayName: "Index", 46 | mixins: [FluxMixin], 47 | 48 | render: function() { 49 | return ( 50 |
51 | C3-React}> 52 | 59 | 60 |
61 | 62 |
63 |
64 | ); 65 | } 66 | }); 67 | 68 | let routes = ( 69 | 70 | 71 | 72 | 73 | 74 | ); 75 | 76 | Router.run(routes, function(Handler) { 77 | React.render(, document.getElementById("container")); 78 | }); 79 | 80 | 81 | -------------------------------------------------------------------------------- /examples/stores/DataStore.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const _ = require("lodash"); 4 | const Fluxxor = require("fluxxor"); 5 | const Const = require("../constants"); 6 | const DataActTypes = Const.ActTypes.Data; 7 | 8 | // Keeping these variables outside the PageStore makes them private. 9 | // We surely don"t want others use these variables directly -- this 10 | // makes sure we have proper consistency. 11 | let _data; 12 | let _type; 13 | let _charGenerator = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 14 | 15 | let DataStore = Fluxxor.createStore({ 16 | dataGenerator: function() { 17 | let data = []; 18 | for(let i = 0; i < 10; i++){ 19 | data.push({label: _charGenerator.charAt(i), value: Math.floor((Math.random() * 100) + 1)}); 20 | } 21 | return data; 22 | }, 23 | 24 | initialize: function() { 25 | _data = [{ 26 | key: "dataSource1", 27 | values: this.dataGenerator() 28 | }, 29 | { 30 | key: "dataSource2", 31 | values: this.dataGenerator() 32 | }]; 33 | _type = "bar"; 34 | 35 | this.bindActions( 36 | DataActTypes.NEW_DATA, this.onNewData, 37 | DataActTypes.ADD_ENTRY, this.onAddEntry, 38 | DataActTypes.REMOVE_ENTRY, this.onRemoveEntry, 39 | DataActTypes.REMOVE_DATA, this.onRemoveData, 40 | DataActTypes.CHANGE_CHART_TYPE, this.onChangeChartType 41 | ); 42 | }, 43 | 44 | getState: function() { 45 | return { 46 | data: _data, 47 | type: _type 48 | }; 49 | }, 50 | 51 | onNewData: function() { 52 | _.map(_data, (d) => { 53 | d.values = this.dataGenerator(); 54 | }); 55 | this.emit(Const.CHANGE_EVENT); 56 | }, 57 | 58 | onAddEntry: function() { 59 | console.log("add entry"); 60 | _.map(_data, (d) => { 61 | d.values.push({label: _charGenerator.charAt(d.values.length), value: Math.floor((Math.random() * 100) + 1)}); 62 | }); 63 | this.emit(Const.CHANGE_EVENT); 64 | }, 65 | 66 | onRemoveEntry: function() { 67 | console.log("remove entry"); 68 | _.map(_data, (d) => { 69 | d.values.pop(); 70 | }); 71 | this.emit(Const.CHANGE_EVENT); 72 | }, 73 | 74 | onRemoveData: function() { 75 | console.log("remove data"); 76 | _data = [{ 77 | key: "dataSource1", 78 | values: [] 79 | }, 80 | { 81 | key: "dataSource2", 82 | values: [] 83 | }]; 84 | this.emit(Const.CHANGE_EVENT); 85 | }, 86 | 87 | onChangeChartType: function(payload) { 88 | console.log(payload); 89 | _type = payload.type; 90 | this.emit(Const.CHANGE_EVENT); 91 | } 92 | 93 | }); 94 | module.exports = DataStore; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./lib/C3Chart.js"); 2 | -------------------------------------------------------------------------------- /lib/C3Chart.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var React = require("react"); 4 | var _ = require("lodash"); 5 | 6 | var c3 = require("c3"); 7 | var d3 = require("d3"); 8 | 9 | var C3Chart = React.createClass({ 10 | displayName: "C3Chart", 11 | propTypes: { 12 | type: React.PropTypes.string.isRequired, 13 | data: React.PropTypes.array.isRequired, 14 | options: React.PropTypes.shape({ 15 | padding: React.PropTypes.shape({ 16 | top: React.PropTypes.number, 17 | bottom: React.PropTypes.number, 18 | left: React.PropTypes.number, 19 | right: React.PropTypes.number 20 | }), 21 | size: React.PropTypes.shape({ 22 | width: React.PropTypes.number, 23 | height: React.PropTypes.number 24 | }), 25 | labels: React.PropTypes.bool, 26 | onclick: React.PropTypes.func, 27 | axisLabel: React.PropTypes.shape({ 28 | x: React.PropTypes.string, 29 | y: React.PropTypes.string 30 | }), 31 | subchart: React.PropTypes.bool, 32 | zoom: React.PropTypes.bool, 33 | grid: React.PropTypes.shape({ 34 | x: React.PropTypes.bool, 35 | y: React.PropTypes.bool 36 | }) 37 | }) 38 | }, 39 | 40 | //color theme 41 | colors: function colors(count) { 42 | var colors = []; 43 | var color = d3.scale.category10(); 44 | for (var i = 0; i < count; i++) { 45 | colors.push(color(i)); 46 | } 47 | return colors; 48 | }, 49 | 50 | //apply props.options to graph json 51 | graphObject: function graphObject() { 52 | var graphObject = { 53 | data: {}, 54 | axis: {}, 55 | bindto: "#chartContainer", 56 | color: { 57 | pattern: this.colors(20) 58 | } 59 | }; 60 | var options = this.props.options; 61 | if (options.padding) { 62 | graphObject.padding = { 63 | top: options.padding.top, 64 | left: options.padding.left, 65 | right: options.padding.right, 66 | bottom: options.padding.bottom 67 | }; 68 | } 69 | if (options.size) { 70 | graphObject.size = { 71 | width: options.size.width, 72 | height: options.size.height 73 | }; 74 | } 75 | if (options.labels) { 76 | graphObject.data.labels = options.labels; 77 | } 78 | if (options.onClick) { 79 | graphObject.data.onclick = options.onClick; 80 | } 81 | if (options.axisLabel) { 82 | graphObject.axis.x = { label: options.axisLabel.x }; 83 | graphObject.axis.y = { label: options.axisLabel.y }; 84 | } 85 | if (options.subchart) { 86 | graphObject.subchart = { show: options.subchart }; 87 | } 88 | if (options.zoom) { 89 | graphObject.zoom = { enabled: options.zoom }; 90 | } 91 | if (options.grid) { 92 | graphObject.grid = { 93 | x: { show: options.grid.x }, 94 | y: { show: options.grid.y } 95 | }; 96 | } 97 | return graphObject; 98 | }, 99 | 100 | //c3.js 101 | drawGraph: function drawGraph() { 102 | switch (this.props.type) { 103 | case "line": 104 | this.drawGraphLine(); 105 | break; 106 | case "bar": 107 | this.drawGraphBar(); 108 | break; 109 | case "pie": 110 | this.drawGraphPie(); 111 | break; 112 | case "multiBar": 113 | this.drawGraphMultiBar(); 114 | break; 115 | case "lineBar": 116 | this.drawGraphlLineBar(); 117 | break; 118 | } 119 | }, 120 | 121 | drawGraphLine: function drawGraphLine() { 122 | console.log("drawing line"); 123 | var graphObject = this.graphObject(); 124 | var graphObjectData = { 125 | json: this.props.data[0].values, 126 | keys: { x: "label", value: ["value"] }, 127 | names: { value: this.props.data[0].key } 128 | }; 129 | var graphObjectAxis = { 130 | x: { type: "category" } // this needed to load string x value 131 | }; 132 | 133 | graphObject.data = _.merge(graphObjectData, graphObject.data); 134 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 135 | 136 | var chart = c3.generate(graphObject); 137 | return chart; 138 | }, 139 | 140 | drawGraphBar: function drawGraphBar() { 141 | console.log("drawing bar"); 142 | var graphObject = this.graphObject(); 143 | var graphObjectData = { 144 | x: "x", 145 | json: this.props.data[0].values, 146 | keys: { x: "label", value: ["value"] }, 147 | names: { value: this.props.data[0].key }, 148 | type: "bar", 149 | labels: true 150 | }; 151 | var graphObjectAxis = { 152 | x: { type: "category" } // this needed to load string x value 153 | }; 154 | 155 | graphObject.data = _.merge(graphObjectData, graphObject.data); 156 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 157 | 158 | var chart = c3.generate(graphObject); 159 | return chart; 160 | }, 161 | 162 | pieChartDataPreparator: function pieChartDataPreparator(rawData) { 163 | var data = undefined; 164 | data = _.map(rawData, function (d) { 165 | return [d.label, d.value]; 166 | }); 167 | return data; 168 | }, 169 | 170 | drawGraphPie: function drawGraphPie() { 171 | console.log("drawing pie"); 172 | var graphObject = this.graphObject(); 173 | var graphObjectData = { 174 | columns: this.pieChartDataPreparator(this.props.data[0].values), 175 | type: "pie" 176 | }; 177 | 178 | graphObject.data = _.merge(graphObjectData, graphObject.data); 179 | 180 | var chart = c3.generate(graphObject); 181 | return chart; 182 | }, 183 | 184 | multiDmsDataPreparator: function multiDmsDataPreparator(rawData) { 185 | var xLabels = ["x"]; // to make ['x', 'a', 'b', 'c' ...] for labels 186 | _.map(rawData[0].values, function (d) { 187 | xLabels.push(d.label); 188 | }); 189 | 190 | var data = undefined; 191 | data = _.map(rawData, function (datum) { 192 | var row = [datum.key]; // to make ['key', 30, 200, 100, 400 ...] for each row 193 | _.map(datum.values, function (d) { 194 | row.push(d.value); 195 | }); 196 | return row; 197 | }); 198 | data.push(xLabels); 199 | return data; 200 | }, 201 | 202 | drawGraphMultiBar: function drawGraphMultiBar() { 203 | console.log("drawing multiBar"); 204 | var graphObject = this.graphObject(); 205 | var graphObjectData = { 206 | x: "x", 207 | columns: this.multiDmsDataPreparator(this.props.data), 208 | type: "bar", 209 | labels: true 210 | }; 211 | var graphObjectAxis = { 212 | x: { type: "category" } // this needed to load string x value 213 | }; 214 | 215 | graphObject.data = _.merge(graphObjectData, graphObject.data); 216 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 217 | 218 | var chart = c3.generate(graphObject); 219 | return chart; 220 | }, 221 | 222 | drawGraphlLineBar: function drawGraphlLineBar() { 223 | console.log("drawing LineBar"); 224 | var graphObject = this.graphObject(); 225 | var graphObjectData = { 226 | x: "x", 227 | columns: this.multiDmsDataPreparator(this.props.data), 228 | types: { dataSource1: "bar" } 229 | }; 230 | var graphObjectAxis = { 231 | x: { type: "category" } // this needed to load string x value 232 | }; 233 | 234 | graphObject.data = _.merge(graphObjectData, graphObject.data); 235 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 236 | 237 | var chart = c3.generate(graphObject); 238 | return chart; 239 | }, 240 | 241 | componentDidMount: function componentDidMount() { 242 | this.drawGraph(); 243 | }, 244 | 245 | componentDidUpdate: function componentDidUpdate() { 246 | this.drawGraph(); 247 | }, 248 | 249 | render: function render() { 250 | return React.createElement( 251 | "div", 252 | null, 253 | React.createElement("div", { id: "chartContainer" }) 254 | ); 255 | } 256 | }); 257 | 258 | module.exports = C3Chart; 259 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "c3-react", 3 | "version": "0.1.6", 4 | "author": "Ming-Hsun Tsai", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "keywords": [ 8 | "react", 9 | "component", 10 | "c3", 11 | "d3", 12 | "chart", 13 | "graph" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/terry81811/c3-react" 18 | }, 19 | "readmeFilename": "README.md", 20 | "scripts": { 21 | "dev": "webpack-dev-server --port 3002 --devtool eval --progress --hot --colors --content-base build" 22 | }, 23 | "peerDependencies": { 24 | "react": ">=0.13" 25 | }, 26 | "dependencies": { 27 | "c3": "^0.4.10", 28 | "d3": "^3.5.5", 29 | "lodash": "^3.9.3" 30 | }, 31 | "devDependency": { 32 | "react-bootstrap": "^0.23.0", 33 | "babel-core": "^5.4.7", 34 | "babel-loader": "^5.1.3", 35 | "css-loader": "^0.14.4", 36 | "file-loader": "^0.8.4", 37 | "fluxxor": "^1.5.4", 38 | "jsx-loader": "^0.13.2", 39 | "react-hot-loader": "^1.2.7", 40 | "react-router": "^0.13.3", 41 | "style-loader": "^0.12.3", 42 | "url-loader": "^0.5.6", 43 | "webpack": "^1.8.10", 44 | "webpack-dev-server": "^1.9.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/C3Chart.jsx: -------------------------------------------------------------------------------- 1 | const React = require("react"); 2 | const _ = require("lodash"); 3 | 4 | const c3 = require("c3"); 5 | const d3 = require("d3"); 6 | 7 | let C3Chart = React.createClass({ 8 | displayName: "C3Chart", 9 | propTypes: { 10 | type: React.PropTypes.string.isRequired, 11 | data: React.PropTypes.array.isRequired, 12 | options: React.PropTypes.shape({ 13 | padding: React.PropTypes.shape({ 14 | top: React.PropTypes.number, 15 | bottom: React.PropTypes.number, 16 | left: React.PropTypes.number, 17 | right: React.PropTypes.number 18 | }), 19 | size: React.PropTypes.shape({ 20 | width: React.PropTypes.number, 21 | height: React.PropTypes.number, 22 | }), 23 | labels: React.PropTypes.bool, 24 | onclick: React.PropTypes.func, 25 | axisLabel: React.PropTypes.shape({ 26 | x: React.PropTypes.string, 27 | y: React.PropTypes.string 28 | }), 29 | subchart: React.PropTypes.bool, 30 | zoom: React.PropTypes.bool, 31 | grid: React.PropTypes.shape({ 32 | x: React.PropTypes.bool, 33 | y: React.PropTypes.bool 34 | }) 35 | }) 36 | }, 37 | 38 | //color theme 39 | colors: function(count) { 40 | let colors = []; 41 | let color = d3.scale.category10(); 42 | for(let i = 0; i < count; i++){ 43 | colors.push(color(i)); 44 | } 45 | return colors; 46 | }, 47 | 48 | //apply props.options to graph json 49 | graphObject: function() { 50 | let graphObject = { 51 | data: {}, 52 | axis: {}, 53 | bindto: "#chartContainer", 54 | color: { 55 | pattern: this.colors(20) 56 | } 57 | }; 58 | let options = this.props.options; 59 | if(options.padding){ 60 | graphObject.padding = { 61 | top: options.padding.top, 62 | left: options.padding.left, 63 | right: options.padding.right, 64 | bottom: options.padding.bottom 65 | }; 66 | } 67 | if(options.size){ 68 | graphObject.size = { 69 | width: options.size.width, 70 | height: options.size.height 71 | }; 72 | } 73 | if(options.labels){ 74 | graphObject.data.labels = options.labels; 75 | } 76 | if(options.onClick){ 77 | graphObject.data.onclick = options.onClick; 78 | } 79 | if(options.axisLabel){ 80 | graphObject.axis.x = {label: options.axisLabel.x}; 81 | graphObject.axis.y = {label: options.axisLabel.y}; 82 | } 83 | if(options.subchart){ 84 | graphObject.subchart = {show: options.subchart}; 85 | } 86 | if(options.zoom){ 87 | graphObject.zoom = {enabled: options.zoom}; 88 | } 89 | if(options.grid){ 90 | graphObject.grid = { 91 | x:{show: options.grid.x}, 92 | y:{show: options.grid.y} 93 | }; 94 | } 95 | return graphObject; 96 | }, 97 | 98 | //c3.js 99 | drawGraph: function() { 100 | switch(this.props.type){ 101 | case "line": 102 | this.drawGraphLine(); 103 | break; 104 | case "bar": 105 | this.drawGraphBar(); 106 | break; 107 | case "pie": 108 | this.drawGraphPie(); 109 | break; 110 | case "multiBar": 111 | this.drawGraphMultiBar(); 112 | break; 113 | case "lineBar": 114 | this.drawGraphlLineBar(); 115 | break; 116 | } 117 | }, 118 | 119 | drawGraphLine: function() { 120 | console.log("drawing line"); 121 | let graphObject = this.graphObject(); 122 | let graphObjectData = { 123 | json: this.props.data[0].values, 124 | keys: { x: "label", value: ["value"] }, 125 | names: { value: this.props.data[0].key } 126 | }; 127 | let graphObjectAxis = { 128 | x: { type: "category" } // this needed to load string x value 129 | }; 130 | 131 | graphObject.data = _.merge(graphObjectData, graphObject.data); 132 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 133 | 134 | let chart = c3.generate(graphObject); 135 | return chart; 136 | }, 137 | 138 | drawGraphBar: function() { 139 | console.log("drawing bar"); 140 | let graphObject = this.graphObject(); 141 | let graphObjectData = { 142 | x: "x", 143 | json: this.props.data[0].values, 144 | keys: { x: "label", value: ["value"] }, 145 | names: { value: this.props.data[0].key }, 146 | type: "bar", 147 | labels: true 148 | }; 149 | let graphObjectAxis = { 150 | x: { type: "category" } // this needed to load string x value 151 | }; 152 | 153 | graphObject.data = _.merge(graphObjectData, graphObject.data); 154 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 155 | 156 | let chart = c3.generate(graphObject); 157 | return chart; 158 | }, 159 | 160 | pieChartDataPreparator: function(rawData) { 161 | let data; 162 | data = _.map(rawData, (d) => { 163 | return [d.label, d.value]; 164 | }); 165 | return data; 166 | }, 167 | 168 | drawGraphPie: function() { 169 | console.log("drawing pie"); 170 | let graphObject = this.graphObject(); 171 | let graphObjectData = { 172 | columns: this.pieChartDataPreparator(this.props.data[0].values), 173 | type : "pie" 174 | }; 175 | 176 | graphObject.data = _.merge(graphObjectData, graphObject.data); 177 | 178 | let chart = c3.generate(graphObject); 179 | return chart; 180 | }, 181 | 182 | multiDmsDataPreparator: function(rawData) { 183 | let xLabels = ["x"]; // to make ['x', 'a', 'b', 'c' ...] for labels 184 | _.map(rawData[0].values, (d) => { 185 | xLabels.push(d.label); 186 | }); 187 | 188 | let data; 189 | data = _.map(rawData, (datum) => { 190 | let row = [datum.key]; // to make ['key', 30, 200, 100, 400 ...] for each row 191 | _.map(datum.values, (d) => { 192 | row.push(d.value); 193 | }); 194 | return row; 195 | }); 196 | data.push(xLabels); 197 | return data; 198 | }, 199 | 200 | drawGraphMultiBar: function() { 201 | console.log("drawing multiBar"); 202 | let graphObject = this.graphObject(); 203 | let graphObjectData = { 204 | x: "x", 205 | columns: this.multiDmsDataPreparator(this.props.data), 206 | type: "bar", 207 | labels: true, 208 | }; 209 | let graphObjectAxis = { 210 | x: { type: "category" } // this needed to load string x value 211 | }; 212 | 213 | graphObject.data = _.merge(graphObjectData, graphObject.data); 214 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 215 | 216 | let chart = c3.generate(graphObject); 217 | return chart; 218 | }, 219 | 220 | drawGraphlLineBar: function() { 221 | console.log("drawing LineBar"); 222 | let graphObject = this.graphObject(); 223 | let graphObjectData = { 224 | x: "x", 225 | columns: this.multiDmsDataPreparator(this.props.data), 226 | types: {dataSource1: "bar"}, 227 | }; 228 | let graphObjectAxis = { 229 | x: { type: "category" } // this needed to load string x value 230 | }; 231 | 232 | graphObject.data = _.merge(graphObjectData, graphObject.data); 233 | graphObject.axis = _.merge(graphObjectAxis, graphObject.axis); 234 | 235 | let chart = c3.generate(graphObject); 236 | return chart; 237 | }, 238 | 239 | componentDidMount: function() { 240 | this.drawGraph(); 241 | }, 242 | 243 | componentDidUpdate: function () { 244 | this.drawGraph(); 245 | }, 246 | 247 | render: function() { 248 | return ( 249 |
250 |
251 |
); 252 | } 253 | }); 254 | 255 | module.exports = C3Chart; 256 | -------------------------------------------------------------------------------- /src/assets/c3.css: -------------------------------------------------------------------------------- 1 | /*-- Chart --*/ 2 | .c3 svg { 3 | font: 10px sans-serif; } 4 | 5 | .c3 path, .c3 line { 6 | fill: none; 7 | stroke: #000; } 8 | 9 | .c3 text { 10 | -webkit-user-select: none; 11 | -moz-user-select: none; 12 | user-select: none; } 13 | 14 | .c3-legend-item-tile, .c3-xgrid-focus, .c3-ygrid, .c3-event-rect, .c3-bars path { 15 | shape-rendering: crispEdges; } 16 | 17 | .c3-chart-arc path { 18 | stroke: #fff; } 19 | 20 | .c3-chart-arc text { 21 | fill: #fff; 22 | font-size: 13px; } 23 | 24 | /*-- Axis --*/ 25 | /*-- Grid --*/ 26 | .c3-grid line { 27 | stroke: #aaa; } 28 | 29 | .c3-grid text { 30 | fill: #aaa; } 31 | 32 | .c3-xgrid, .c3-ygrid { 33 | stroke-dasharray: 3 3; } 34 | 35 | /*-- Text on Chart --*/ 36 | .c3-text.c3-empty { 37 | fill: #808080; 38 | font-size: 2em; } 39 | 40 | /*-- Line --*/ 41 | .c3-line { 42 | stroke-width: 1px; } 43 | 44 | /*-- Point --*/ 45 | .c3-circle._expanded_ { 46 | stroke-width: 1px; 47 | stroke: white; } 48 | 49 | .c3-selected-circle { 50 | fill: white; 51 | stroke-width: 2px; } 52 | 53 | /*-- Bar --*/ 54 | .c3-bar { 55 | stroke-width: 0; } 56 | 57 | .c3-bar._expanded_ { 58 | fill-opacity: 0.75; } 59 | 60 | /*-- Focus --*/ 61 | .c3-target.c3-focused { 62 | opacity: 1; } 63 | 64 | .c3-target.c3-focused path.c3-line, .c3-target.c3-focused path.c3-step { 65 | stroke-width: 2px; } 66 | 67 | .c3-target.c3-defocused { 68 | opacity: 0.3 !important; } 69 | 70 | /*-- Region --*/ 71 | .c3-region { 72 | fill: steelblue; 73 | fill-opacity: 0.1; } 74 | 75 | /*-- Brush --*/ 76 | .c3-brush .extent { 77 | fill-opacity: 0.1; } 78 | 79 | /*-- Select - Drag --*/ 80 | /*-- Legend --*/ 81 | .c3-legend-item { 82 | font-size: 12px; } 83 | 84 | .c3-legend-item-hidden { 85 | opacity: 0.15; } 86 | 87 | .c3-legend-background { 88 | opacity: 0.75; 89 | fill: white; 90 | stroke: lightgray; 91 | stroke-width: 1; } 92 | 93 | /*-- Tooltip --*/ 94 | .c3-tooltip-container { 95 | z-index: 10; } 96 | 97 | .c3-tooltip { 98 | border-collapse: collapse; 99 | border-spacing: 0; 100 | background-color: #fff; 101 | empty-cells: show; 102 | -webkit-box-shadow: 7px 7px 12px -9px #777777; 103 | -moz-box-shadow: 7px 7px 12px -9px #777777; 104 | box-shadow: 7px 7px 12px -9px #777777; 105 | opacity: 0.9; } 106 | 107 | .c3-tooltip tr { 108 | border: 1px solid #CCC; } 109 | 110 | .c3-tooltip th { 111 | background-color: #aaa; 112 | font-size: 14px; 113 | padding: 2px 5px; 114 | text-align: left; 115 | color: #FFF; } 116 | 117 | .c3-tooltip td { 118 | font-size: 13px; 119 | padding: 3px 6px; 120 | background-color: #fff; 121 | border-left: 1px dotted #999; } 122 | 123 | .c3-tooltip td > span { 124 | display: inline-block; 125 | width: 10px; 126 | height: 10px; 127 | margin-right: 6px; } 128 | 129 | .c3-tooltip td.value { 130 | text-align: right; } 131 | 132 | /*-- Area --*/ 133 | .c3-area { 134 | stroke-width: 0; 135 | opacity: 0.2; } 136 | 137 | /*-- Arc --*/ 138 | .c3-chart-arcs-title { 139 | dominant-baseline: middle; 140 | font-size: 1.3em; } 141 | 142 | .c3-chart-arcs .c3-chart-arcs-background { 143 | fill: #e0e0e0; 144 | stroke: none; } 145 | 146 | .c3-chart-arcs .c3-chart-arcs-gauge-unit { 147 | fill: #000; 148 | font-size: 16px; } 149 | 150 | .c3-chart-arcs .c3-chart-arcs-gauge-max { 151 | fill: #777; } 152 | 153 | .c3-chart-arcs .c3-chart-arcs-gauge-min { 154 | fill: #777; } 155 | 156 | .c3-chart-arc .c3-gauge-value { 157 | fill: #000; 158 | /* font-size: 28px !important;*/ } 159 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var env = process.env.WEBPACK_ENV || "index"; 2 | var entry; 3 | 4 | if (env === "dev") { 5 | entry = [ 6 | "webpack-dev-server/client?http://localhost:3002", 7 | "webpack/hot/dev-server", 8 | "./examples/index.jsx" 9 | ]; 10 | } else { 11 | entry = [ 12 | "./examples/index.jsx" 13 | ]; 14 | } 15 | 16 | var config = { 17 | entry: entry, 18 | output: { 19 | path: "./build", 20 | filename: "bundle.js" 21 | }, 22 | module: { 23 | loaders: [ 24 | { test: /\.css$/, loader: "style-loader!css-loader" }, // use ! to chain loaders 25 | { test: /\.less$/, loader: "style-loader!css-loader!less-loader" }, // use ! to chain loaders 26 | { test: /\.(ttf|eot|png|jpg|woff2|woff|svg)($|\?)/, loader: "url-loader?limit=100000" }, 27 | { test: /\.jsx?$/, exclude: /node_modules/, loaders: ["react-hot", "babel-loader?stage=0&optional=runtime"] }, 28 | ] 29 | } 30 | }; 31 | 32 | module.exports = config; 33 | --------------------------------------------------------------------------------