├── .npmignore ├── .babelrc ├── docs ├── favicon.ico └── index.html ├── .eslintignore ├── samples ├── resources │ ├── thumbnails │ │ └── banner_1.png │ └── gettingstarted.css ├── public │ └── index.html ├── styles │ ├── style.css │ └── snippet-highlight.css ├── ScrollReset.jsx ├── chart-docs │ ├── PlayGround.jsx │ ├── util │ │ ├── SyntaxHighLight.js │ │ └── MakeData.js │ ├── SimpleChart.jsx │ ├── TableChartServerSidePagination.jsx │ ├── NumberChartSample.jsx │ ├── GeographicalChartsSample.jsx │ ├── PieChartSamples.jsx │ └── ScatterPlotSample.jsx ├── components │ ├── LightBulbFill.jsx │ ├── LightBulbOutline.jsx │ ├── GitHub.jsx │ └── Header.jsx ├── ChartWrapper.jsx ├── GettingStarted.jsx ├── GettingStarted.md └── index.jsx ├── src ├── components │ ├── resources │ │ ├── css │ │ │ └── map-chart.css │ │ ├── MapData.js │ │ └── themes │ │ │ ├── victoryLightTheme.js │ │ │ └── victoryDarkTheme.js │ ├── util │ │ └── Constants.js │ ├── helper.js │ ├── LegendComponent.jsx │ ├── ComposedChart.jsx │ ├── NumberChart.jsx │ ├── InlineChart.jsx │ ├── LineChart.jsx │ ├── ArcCharts.jsx │ ├── ScatterPlot.jsx │ ├── AreaChart.jsx │ └── BaseChart.jsx ├── index.js ├── VizGError.js ├── ErrorBoundary.jsx └── VizG.jsx ├── dist └── components │ └── resources │ └── css │ └── map-chart.css ├── index.js ├── issue_template.md ├── .gitignore ├── webpack.config.js ├── package.json ├── pull_request_template.md ├── .eslintrc.js ├── README.md └── LICENSE /.npmignore: -------------------------------------------------------------------------------- 1 | samples/ 2 | docs/ 3 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react","env","stage-2"] 3 | } 4 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/this/react-vizgrammar/master/docs/favicon.ico -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist/** 2 | /node_modules/** 3 | /lib/** 4 | /public/** 5 | /js/tests/resources/** 6 | -------------------------------------------------------------------------------- /samples/resources/thumbnails/banner_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/this/react-vizgrammar/master/samples/resources/thumbnails/banner_1.png -------------------------------------------------------------------------------- /src/components/resources/css/map-chart.css: -------------------------------------------------------------------------------- 1 | .fontClass { 2 | font-family: 'Gill Sans', 'Gill Sans MT', 'Seravek', 'Trebuchet MS', sans-serif !important; 3 | } -------------------------------------------------------------------------------- /dist/components/resources/css/map-chart.css: -------------------------------------------------------------------------------- 1 | .fontClass { 2 | font-family: 'Gill Sans', 'Gill Sans MT', 'Seravek', 'Trebuchet MS', sans-serif !important; 3 | } 4 | -------------------------------------------------------------------------------- /samples/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-VizGrammar Charting Made Easy 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import VizG from './dist/VizG'; 18 | 19 | export default VizG; 20 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import VizG from './VizG'; 20 | 21 | export default VizG; 22 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | **Description:** 2 | 3 | 4 | **Suggested Labels:** 5 | 6 | 7 | **Suggested Assignees:** 8 | 9 | 10 | **Affected Product Version:** 11 | 12 | **OS, DB, other environment details and versions:** 13 | 14 | **Steps to reproduce:** 15 | 16 | 17 | **Related Issues:** 18 | -------------------------------------------------------------------------------- /samples/styles/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | .lightTheme { 20 | background: #fff; 21 | } 22 | 23 | .darkTheme { 24 | background: #2c2c2c; 25 | } 26 | 27 | .darkTheme .json-structure { 28 | color: #ccc; 29 | } 30 | -------------------------------------------------------------------------------- /samples/resources/gettingstarted.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | .thumbnails { 20 | text-align:center; 21 | } 22 | 23 | .thumbnails > li { 24 | display: inline-block; 25 | *display:inline; /* ie7 fix */ 26 | float: none; /* this is the part that makes it work */ 27 | } -------------------------------------------------------------------------------- /src/components/resources/MapData.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export { default as WorldMap } from './world.json'; 20 | export { default as EuropeMap } from './europe.json'; 21 | export { default as USAMap } from './usa2.json'; 22 | export { default as CountryInfo } from './countryInfo.json'; 23 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-VizGrammar Charting Made Easy 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/components/util/Constants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | const Constants = { 20 | MILLISECONDS_FOR_DAY: 86400000, 21 | MILLISECONDS_FOR_MONTH: 2592000000, 22 | MILLISECONDS_FOR_YEAR: 31104000000, 23 | MILLISECONDS_FOR_HOUR: 3600000, 24 | MILLISECONDS_FOR_MINUTE: 60000, 25 | MILLISECONDS_FOR_SECOND: 1000, 26 | }; 27 | 28 | export default Constants; 29 | -------------------------------------------------------------------------------- /src/VizGError.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export default class VizGError extends Error { 20 | constructor(context, ...params) { 21 | super(...params); 22 | 23 | // supported only in the V8 engine 24 | if (Error.captureStackTrace) { 25 | Error.captureStackTrace(this, VizGError); 26 | } 27 | 28 | this.context = context; 29 | this.date = new Date(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/helper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | /** 20 | * Returns an array of default color set to be used in the visualizations 21 | * @returns {} 22 | */ 23 | export function getDefaultColorScale() { 24 | return ['#1565C0', '#4DB6AC', '#FF9800', '#9C27B0', '#3F51B5', '#F44336', '#673AB7', 25 | '#E91E63', '#4CAF50', '#00BCD4', '#FFEB3B', '#FF5722', '#8BC34A', '#03A9F4', 26 | '#FFC107', '#80CBC4', '#EF9A9A', '#CE93D8', '#B39DDB', '#C5E1A5', 27 | ]; 28 | } 29 | -------------------------------------------------------------------------------- /samples/ScrollReset.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React, { Component } from 'react'; 20 | import { withRouter } from 'react-router-dom'; 21 | 22 | class ScrollToTop extends Component { 23 | componentDidUpdate(prevProps) { 24 | if (this.props.location !== prevProps.location) { 25 | window.scrollTo(0, 0); 26 | } 27 | } 28 | 29 | render() { 30 | return this.props.children; 31 | } 32 | } 33 | 34 | export default withRouter(ScrollToTop); 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | #vscode 9 | .vscode/ 10 | 11 | #idea stuff 12 | .idea/ 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (http://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Typescript v1 declaration files 46 | typings/ 47 | 48 | # Optional npm cache directory 49 | .npm 50 | 51 | # Optional eslint cache 52 | .eslintcache 53 | 54 | # Optional REPL history 55 | .node_repl_history 56 | 57 | # Output of 'npm pack' 58 | *.tgz 59 | 60 | # Yarn Integrity file 61 | .yarn-integrity 62 | 63 | # dotenv environment variables file 64 | .env 65 | -------------------------------------------------------------------------------- /samples/chart-docs/PlayGround.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | 21 | export default class PlayGround extends React.Component { 22 | render() { 23 | return ( 24 |
25 | 30 |
31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/styles/snippet-highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | pre { 20 | outline: 1px solid #ccc; 21 | padding: 5px; margin: 5px; 22 | background-color: #d3d3d3; 23 | } 24 | .string { color: #66BB6A; } 25 | .number { color: #ff6501; } 26 | .boolean { color: #42A5F5; } 27 | .null { color: #EC407A; } 28 | .key { color: #EF5350; } 29 | 30 | /*Dark theme styles*/ 31 | 32 | .darkTheme pre { 33 | outline: 1px solid #1c1c1c; 34 | background-color: #3a3a3a; 35 | color: #ccc; 36 | } 37 | 38 | .darkTheme .hljs-keyword, .darkTheme .hljs-selector-tag, .darkTheme .hljs-subst { 39 | color: #ccc; 40 | } 41 | -------------------------------------------------------------------------------- /samples/components/LightBulbFill.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import React, { Component } from 'react'; 19 | import SvgIcon from 'material-ui/SvgIcon'; 20 | 21 | class LightBulbFill extends Component { 22 | render() { 23 | return ( 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | 31 | LightBulbFill.muiName = 'SvgIcon'; 32 | 33 | export default LightBulbFill; 34 | -------------------------------------------------------------------------------- /src/ErrorBoundary.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | 21 | export default class ErrorBoundary extends React.Component { 22 | constructor(props) { 23 | super(props); 24 | this.state = { hasError: false }; 25 | } 26 | 27 | componentDidCatch(error, info) { 28 | // Display fallback UI 29 | this.setState({ hasError: true }); 30 | // You can also log the error to an error reporting service 31 | } 32 | 33 | render() { 34 | if (this.state.hasError) { 35 | // You can render any custom fallback UI 36 | return

Something went wrong.

; 37 | } 38 | return this.props.children; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/components/LightBulbOutline.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import React, { Component } from 'react'; 19 | import SvgIcon from 'material-ui/SvgIcon'; 20 | 21 | class LightBulbOutline extends Component { 22 | render() { 23 | return ( 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | 31 | LightBulbOutline.muiName = 'SvgIcon'; 32 | 33 | export default LightBulbOutline; 34 | -------------------------------------------------------------------------------- /samples/components/GitHub.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import React, { Component } from 'react'; 19 | import SvgIcon from 'material-ui/SvgIcon'; 20 | 21 | class GitHub extends Component { 22 | render() { 23 | return ( 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | 31 | GitHub.muiName = 'SvgIcon'; 32 | 33 | export default GitHub; 34 | -------------------------------------------------------------------------------- /samples/chart-docs/util/SyntaxHighLight.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | export function syntaxHighlight(json) { 20 | json = json.replace(/&/g, '&').replace(//g, '>'); 21 | return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, (match) => { 22 | let cls = 'number'; 23 | if (/^"/.test(match)) { 24 | if (/:$/.test(match)) { 25 | cls = 'key'; 26 | } else { 27 | cls = 'string'; 28 | } 29 | } else if (/true|false/.test(match)) { 30 | cls = 'boolean'; 31 | } else if (/null/.test(match)) { 32 | cls = 'null'; 33 | } 34 | return '' + match + ''; 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /samples/chart-docs/util/MakeData.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import Namor from 'namor'; 20 | 21 | const range = (len) => { 22 | const arr = []; 23 | for (let i = 0; i < len; i++) { 24 | arr.push(i); 25 | } 26 | return arr; 27 | }; 28 | 29 | const newPerson = () => { 30 | const statusChance = Math.random(); 31 | return [ 32 | Namor.generate({ words: 1, numbers: 0 }), 33 | Namor.generate({ words: 1, numbers: 0 }), 34 | Math.floor(Math.random() * 30), 35 | Math.floor(Math.random() * 100), 36 | Math.floor(Math.random() * 100), 37 | statusChance > 0.66 38 | ? 'relationship' 39 | : statusChance > 0.33 ? 'complicated' : 'single', 40 | ]; 41 | }; 42 | 43 | export function makeData() { 44 | const dataSet = []; 45 | 46 | for (let i = 0; i < 100; i++) { 47 | dataSet.push(newPerson()); 48 | } 49 | 50 | return dataSet; 51 | } 52 | 53 | export function makeDataWithSize(size) { 54 | const dataSet = []; 55 | 56 | for (let i = 0; i < size; i++) { 57 | dataSet.push(newPerson()); 58 | } 59 | 60 | return dataSet; 61 | } 62 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | const path = require('path'); 20 | 21 | module.exports = { 22 | devtool: 'source-map', 23 | entry: './samples/index', 24 | output: { 25 | path: path.resolve(__dirname, './docs'), 26 | filename: 'app.js', 27 | }, 28 | module: { 29 | loaders: [ 30 | { 31 | test: /\.json$/, 32 | loader: 'json-loader', 33 | }, 34 | { 35 | exclude: [path.resolve(__dirname, './node_modules')], 36 | test: /\.(js|jsx)$/, 37 | loader: 'babel-loader', 38 | }, 39 | 40 | { 41 | test: /\.css$/, 42 | loader: 'style-loader!css-loader', 43 | }, 44 | { 45 | test: /\.scss$/, 46 | loaders: ['style-loader', 'css-loader', 'sass-loader'], 47 | }, 48 | { 49 | test: /\.md$/, 50 | loader: 'raw-loader', 51 | }, 52 | { 53 | test: /\.(jpg|png)$/, 54 | loader: 'url-loader', 55 | }, 56 | ], 57 | }, 58 | devServer: { 59 | contentBase: './docs', 60 | historyApiFallback: true, 61 | inline: true, 62 | port: 8080, 63 | }, 64 | resolve: { 65 | extensions: ['.js', '.json', '.jsx', '.scss'], 66 | }, 67 | }; 68 | -------------------------------------------------------------------------------- /samples/chart-docs/SimpleChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import React from 'react'; 19 | import VizG from '../../src/VizG'; 20 | 21 | export default class SimpleChart extends React.Component { 22 | 23 | constructor(props) { 24 | super(props); 25 | 26 | this.lineChartConfig = { 27 | x: 'rpm', 28 | charts: [{ type: 'line', y: 'torque' }], 29 | maxLength: 30, 30 | width: 800, 31 | height: 400, 32 | interactiveLegend: true, 33 | legend: true, 34 | tipTimeFormat: '%A', 35 | }; 36 | 37 | this.metadata = { 38 | names: ['rpm', 'torque', 'horsepower', 'EngineType'], 39 | types: ['linear', 'linear', 'ordinal', 'ordinal'], 40 | }; 41 | 42 | this.staticDataSet = [ 43 | [10, 11, 12, 'piston'], 44 | [11, 15, 12, 'rotary'], 45 | [12, 14, 12, 'piston'], 46 | [13, 24, 12, 'rotary'], 47 | [15, 11, 12, 'rotary'], 48 | [16, 15, 12, 'piston'], 49 | [17, 14, 12, 'rotary'], 50 | ]; 51 | } 52 | 53 | 54 | render() { 55 | return ( 56 |
57 | 59 |
60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /samples/components/Header.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { AppBar, Toolbar, Typography, IconButton } from 'material-ui'; 21 | import BackIcon from 'material-ui-icons/ArrowBack'; 22 | import GitHub from '../components/GitHub'; 23 | import { Link } from 'react-router-dom'; 24 | import PropTypes from 'prop-types'; 25 | 26 | const style = { 27 | background: '#2196f3', 28 | }; 29 | 30 | export default class Header extends React.Component { 31 | render() { 32 | return ( 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | {this.props.title} 42 | 43 | { 46 | window.location.href = 'https://github.com/wso2/react-vizgrammar'; 47 | }} 48 | title="See the source on GitHub" 49 | > 50 | 51 | 52 | 53 | 54 | ) 55 | }; 56 | } 57 | 58 | Header.propTypes = { 59 | url: PropTypes.string.isRequired, 60 | title: PropTypes.string.isRequired, 61 | }; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-vizgrammar", 3 | "version": "0.7.24", 4 | "description": "React-VizGrammar is a charting library that makes charting easy by adding required boilerplate code so that developers/designers can get started in few minutes.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "npx babel src -d dist", 9 | "samples": "webpack-dev-server --progress", 10 | "generate-docs": "webpack -p --progress" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/wso2/react-vizgrammar.git" 15 | }, 16 | "license": "Apache-2.0", 17 | "dependencies": { 18 | "d3": "^4.12.0", 19 | "lodash": "^4.17.4", 20 | "prop-types": "^15.6.0", 21 | "rc-slider": "^8.3.4", 22 | "react": "^16.0.0", 23 | "react-dom": "^16.0.0", 24 | "react-simple-maps": "^0.9.0", 25 | "react-table": "^6.6.0", 26 | "react-tooltip": "^3.4.0", 27 | "topojson-client": "^3.0.0", 28 | "victory": "^0.22.2", 29 | "victory-core": "^20.2.0" 30 | }, 31 | "devDependencies": { 32 | "babel-cli": "^6.26.0", 33 | "babel-eslint": "^8.0.1", 34 | "namor": "^1.0.1", 35 | "babel-loader": "^7.1.2", 36 | "babel-preset-env": "^1.6.1", 37 | "babel-preset-es2015": "^6.24.1", 38 | "babel-preset-react": "^6.24.1", 39 | "babel-preset-stage-2": "^6.24.1", 40 | "bootstrap": "^4.0.0", 41 | "css-loader": "^0.28.7", 42 | "eslint": "^3.19.0", 43 | "eslint-config-airbnb": "^15.0.1", 44 | "eslint-plugin-import": "^2.3.0", 45 | "eslint-plugin-jsx-a11y": "^5.0.3", 46 | "eslint-plugin-react": "^7.0.1", 47 | "highlight.js": "^9.12.0", 48 | "html-loader": "^0.5.5", 49 | "json-loader": "^0.5.7", 50 | "markdown-loader": "^2.0.2", 51 | "material-ui": "^1.0.0-beta.29", 52 | "material-ui-icons": "^1.0.0-beta.17", 53 | "node-sass": "^4.5.3", 54 | "nodemon": "^1.12.1", 55 | "raw-loader": "^0.5.1", 56 | "react-addons-perf": "^15.4.2", 57 | "react-router-dom": "^4.2.2", 58 | "reactstrap": "^4.8.0", 59 | "remarkable": "^1.7.1", 60 | "sass-loader": "^6.0.6", 61 | "style-loader": "^0.19.0", 62 | "url-loader": "^0.6.2", 63 | "webpack": "^3.8.1", 64 | "webpack-cli": "^2.0.14", 65 | "webpack-dev-server": "^2.9.3" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /samples/ChartWrapper.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { Card, CardActions, CardHeader, Button, CardContent } from 'material-ui'; 21 | import { Link } from 'react-router-dom'; 22 | import PropTypes from 'prop-types'; 23 | 24 | export default class ChartWrapper extends React.Component { 25 | render() { 26 | return ( 27 | 28 | 29 | 30 | 31 | {this.props.children} 32 | 33 | 34 | { 35 | this.props.actionBar ? 36 | 37 | 41 | 42 | 43 | : null 44 | } 45 | 46 | ); 47 | } 48 | } 49 | 50 | ChartWrapper.defaultProps = { 51 | media: false, 52 | actionBar: false, 53 | subtitle: '', 54 | children: null, 55 | height: 450, 56 | }; 57 | 58 | ChartWrapper.propTypes = { 59 | title: PropTypes.string.isRequired, 60 | subtitle: PropTypes.string, 61 | children: PropTypes.object, 62 | chart: PropTypes.string.isRequired, 63 | actionBar: PropTypes.bool.isRequired, 64 | height: PropTypes.number, 65 | }; 66 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | > Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc. 3 | 4 | ## Goals 5 | > Describe the solutions that this feature/fix will introduce to resolve the problems described above 6 | 7 | ## Approach 8 | > Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here. 9 | 10 | ## User stories 11 | > Summary of user stories addressed by this change> 12 | 13 | ## Release note 14 | > Brief description of the new feature or bug fix as it will appear in the release notes 15 | 16 | ## Documentation 17 | > Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact 18 | 19 | ## Training 20 | > Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable 21 | 22 | ## Certification 23 | > Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why. 24 | 25 | ## Marketing 26 | > Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable 27 | 28 | ## Automation tests 29 | - Unit tests 30 | > Code coverage information 31 | - Integration tests 32 | > Details about the test cases and coverage 33 | 34 | ## Security checks 35 | - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no 36 | - Ran FindSecurityBugs plugin and verified report? yes/no 37 | - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no 38 | 39 | ## Samples 40 | > Provide high-level details about the samples related to this feature 41 | 42 | ## Related PRs 43 | > List any other related PRs 44 | 45 | ## Migrations (if applicable) 46 | > Describe migration steps and platforms on which migration has been tested 47 | 48 | ## Test environment 49 | > List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested 50 | 51 | ## Learning 52 | > Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem. -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | module.exports = { 19 | "parserOptions": { 20 | "ecmaVersion": 6, 21 | "sourceType": "module", 22 | "ecmaFeatures": { 23 | "jsx": true, 24 | } 25 | }, 26 | "env": { 27 | "browser": true, 28 | "commonjs": true, 29 | "es6": true 30 | }, 31 | "extends": "airbnb", 32 | "rules": { 33 | "max-len": ["error", 120], 34 | "require-jsdoc": ["warn", { 35 | "require": { 36 | "FunctionDeclaration": true, 37 | "MethodDefinition": true, 38 | "ClassDeclaration": true 39 | } 40 | }], 41 | "valid-jsdoc": ["warn", { 42 | "requireReturn": false 43 | }], 44 | "indent": ["error", 4, {"SwitchCase": 1}], 45 | "import/no-extraneous-dependencies": ["off", { 46 | "devDependencies": false, 47 | "optionalDependencies": false, 48 | "peerDependencies": false 49 | }], 50 | "import/no-unresolved": ["off"], 51 | "import/extensions": ["off"], 52 | "import/no-named-as-default": ["off"], 53 | "import/no-named-as-default-member": ["off"], 54 | "no-underscore-dangle": ["error", { 55 | "allowAfterThis": true 56 | }], 57 | "no-param-reassign": ["off"], 58 | "no-restricted-syntax": ["off"], 59 | "no-plusplus": ["off"], 60 | "func-names": ["off"], 61 | "class-methods-use-this": ["off"], 62 | "arrow-body-style": "off", 63 | "prefer-template": "off", 64 | "jsx-a11y/no-static-element-interactions": "off", 65 | "jsx-a11y/no-noninteractive-element-interactions": "off", 66 | "react/jsx-indent": ["error", 4], 67 | "react/jsx-indent-props": ["error", 4], 68 | "react/prefer-stateless-function": ["off"], 69 | "no-mixed-operators": ["error", {"allowSamePrecedence": true}], 70 | "jsx-quotes": ["off"], 71 | "no-else-return": "off", 72 | }, 73 | "plugins": [ 74 | "react" 75 | ] 76 | }; 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React-VizGrammar 2 | 3 | React VizGrammar is a wrapper around Victory JS and it makes charting easier by adding boilerplate code so that 4 | designers and developers can get started and set it up in a few minutes. 5 | 6 | A chart can be embedded in a React environment simply by using the VizG react component. 7 | ```jsx 8 | import VizG from 'react-vizgrammar'; 9 | 10 | 11 | ``` 12 | Where the props? 13 | - `config` is the widget configurations specified as a JSON object. 14 | - `data` is the array of data sets fed to the charts. 15 | - `metadata` is the JSON object that contains information about the provided dataset. 16 | 17 | checkout the [samples and documentation](https://wso2.github.io/react-vizgrammar) 18 | 19 | ### Chart `config` prop 20 | Users have to provide parameters for the widget using config object inorder to create the chart type they require. It is a JSON object that has a well defined configuration attributes to customize the chart. 21 | 22 | Following is a basic configuration to plot a line chart, 23 | ```javascript 24 | let config = { 25 | x : "rpm", 26 | charts : [{type: "line", y : "torque", color: "EngineType"}], 27 | maxLength: 10, 28 | width: 400, 29 | height: 200 30 | } 31 | ``` 32 | ### `metadata` prop and `data` prop 33 | Once the `config` is provided. User can provide a dataset to visualize the chart. For easy interpretation React-VizGrammar require this dataset to be arranged in a tabular way similar to the way explained below. 34 | ```javascript 35 | metadata = { 36 | "names": ["Column1", "Column2",...], 37 | "types": ['ordinal', 'linear',...] 38 | }; 39 | ``` 40 | 41 | `metadata.names` is an array consists of column names/fields of the table and `metadata.types` contains their types 42 | (ordinal, time or linear), `names` and `types` are aligned together in a way that "Column1" => 'ordinal' and "Column2" => 'linear' and so on. 43 | 44 | ```javascript 45 | data = [ 46 | ["value1", numericValue1,...], 47 | ["value2", numericValue2,...], 48 | ]; 49 | ``` 50 | `data` collection of arrays of data rows. Single row is stored as an array and their element order follows the order of `metadata.names`. 51 | 52 | Sample data table would be like following: 53 | ```javascript 54 | metadata = { 55 | "names" : ["rpm","torque","horsepower", "EngineType"], 56 | "types" : ["linear","linear", "ordinal","ordinal"] 57 | }; 58 | 59 | data = [ 60 | [8000, 75, 120, "Piston"], [9000, 81, 130, "Rotary"] 61 | ]; 62 | ``` 63 | 64 | ## Build Process 65 | 66 | #### Prerequisites 67 | - NPM 68 | - Node 69 | 70 | These prerequisites must be installed before proceeding with the build process. 71 | 72 | #### Build the Library 73 | In order build React-VizGrammar from the sources, Get a clone from this repository and then run the following commands in the terminal from the react-vizgrammar directory. 74 | ```bash 75 | npm install 76 | npm run build 77 | ``` 78 | 79 | #### Build and run samples 80 | To build and start the dev-server and view the samples, inside the main directory run the following command afer installing the npm dependencies. 81 | ```bash 82 | npm run samples 83 | ``` 84 | -------------------------------------------------------------------------------- /samples/chart-docs/TableChartServerSidePagination.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import VizG from '../../src/VizG'; 21 | import { makeDataWithSize } from './util/MakeData'; 22 | 23 | const totalPages = (Math.random() * 100).toFixed(0); 24 | 25 | const requestData = (pageSize, page) => { 26 | // This is a mock service to emulate an endpoint you can use any kind of endpoint to fetch data. 27 | return new Promise((resolve, reject) => { 28 | const res = { 29 | data: makeDataWithSize(pageSize), 30 | pages: totalPages, 31 | }; 32 | 33 | setTimeout(() => resolve(res), 500); 34 | }); 35 | } 36 | 37 | export default class ServerSidePaginationTableChart extends React.Component { 38 | constructor(props) { 39 | super(props); 40 | 41 | this.state = { 42 | data: [], 43 | pageSize: -1, 44 | }; 45 | 46 | this.normalTableConfig = { 47 | charts: [ 48 | { 49 | type: 'table', 50 | columns: [ 51 | { 52 | name: 'firstName', 53 | title: 'First Name', 54 | }, 55 | { 56 | name: 'lastName', 57 | title: 'Last Name', 58 | }, 59 | { 60 | name: 'age', 61 | title: 'Age', 62 | }, 63 | { 64 | name: 'visits', 65 | title: 'Visits', 66 | }, 67 | { 68 | name: 'status', 69 | title: 'status', 70 | }, 71 | ], 72 | }, 73 | ], 74 | pagination: true, 75 | filterable: true, 76 | append: false, 77 | }; 78 | 79 | this.normalDataSetMetadata = { 80 | names: ['firstName', 'lastName', 'age', 'visits', 'status'], 81 | types: ['ordinal', 'ordinal', 'linear', 'linear', 'linear'], 82 | }; 83 | } 84 | 85 | render() { 86 | return ( 87 | { 94 | requestData(state.pageSize, state.page) 95 | .then((res) => { 96 | this.setState({ 97 | data: res.data, 98 | pageSize: res.pages, 99 | }); 100 | }); 101 | }} 102 | /> 103 | ); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /samples/GettingStarted.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import React from 'react'; 19 | import { Card, CardContent } from 'material-ui'; 20 | import Remarkable from 'remarkable'; 21 | import hljs from 'highlight.js'; 22 | import { Link } from 'react-router-dom'; 23 | import { Jumbotron, Button } from 'reactstrap'; 24 | import 'bootstrap/dist/css/bootstrap.css'; 25 | import ReadMe from './GettingStarted.md'; 26 | import SimpleChart from './chart-docs/SimpleChart'; 27 | import './resources/gettingstarted.css'; 28 | 29 | export default class GettingStarted extends React.Component { 30 | constructor(props) { 31 | super(props); 32 | this.divRef = null; 33 | } 34 | 35 | render() { 36 | const md = new Remarkable('full', { 37 | html: false, // Enable HTML tags in source 38 | xhtmlOut: false, // Use '/' to close single tags (
) 39 | breaks: false, // Convert '\n' in paragraphs into
40 | langPrefix: 'language-', // CSS language prefix for fenced blocks 41 | linkify: true, // autoconvert URL-like texts to links 42 | linkTarget: '', // set target to open link in 43 | 44 | // Enable some language-neutral replacements + quotes beautification 45 | typographer: false, 46 | 47 | // Double + single quotes replacement pairs, when typographer enabled, 48 | // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. 49 | quotes: '“”‘’', 50 | 51 | // Highlighter function. Should return escaped HTML, 52 | // or '' if input not changed 53 | highlight(str, lang) { 54 | if (lang && hljs.getLanguage(lang)) { 55 | try { 56 | return hljs.highlight(lang, str).value; 57 | } catch (__) { } 58 | } 59 | 60 | try { 61 | return hljs.highlightAuto(str).value; 62 | } catch (__) { } 63 | 64 | return ''; // use external default escaping 65 | }, 66 | }); 67 | return ( 68 |
69 | 70 | 71 |
72 |

React-VizGrammar

73 |

A charting library based on React.JS, written with simplicity and flexibility in mind.

74 |
75 | thumbnail 76 |

77 | {' '} 78 | {' '} 79 |

80 |
81 |
82 | 83 | 84 | 85 |
86 | 87 | 88 | 89 | 90 |
91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/components/LegendComponent.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { VictoryLegend, VictoryPortal, VictoryContainer } from 'victory'; 21 | 22 | /** 23 | * Class to handle the visualization of legends. 24 | */ 25 | export default class LegendComponent extends React.Component { 26 | render() { 27 | const { config, height, width, legendItems, interaction, theme } = this.props; 28 | return ( 29 | 30 | { 33 | if (!config.legendOrientation) return (width - 150); 34 | else if (config.legendOrientation === 'right') { 35 | return (width - 100); 36 | } else if (config.legendOrientation === 'left') { 37 | return 0; 38 | } else return 100; 39 | })() 40 | } 41 | y={ 42 | (() => { 43 | if (!config.legendOrientation) return 0; 44 | else if (config.legendOrientation === 'top') { 45 | return 0; 46 | } else if (config.legendOrientation === 'bottom') { 47 | return height - 100; 48 | } else return 0; 49 | })() 50 | } 51 | standalone 52 | containerComponent={} 53 | centerTitle 54 | height={height} 55 | width={width} 56 | orientation={ 57 | !config.legendOrientation ? 58 | 'vertical' : 59 | (() => { 60 | if (config.legendOrientation === 'left' || config.legendOrientation === 'right') { 61 | return 'vertical'; 62 | } else { 63 | return 'horizontal'; 64 | } 65 | })() 66 | } 67 | style={{ 68 | title: { 69 | fontSize: (config.style ? (config.style.legendTitleSize || 70 | theme.legend.style.title.fontSize) : theme.legend.style.title.fontSize), 71 | fill: config.style ? config.style.legendTitleColor : theme.legend.style.title.fill, 72 | }, 73 | labels: { 74 | fontSize: config.style ? (config.style.legendTextSize || 75 | theme.legend.style.labels.fontSize) : theme.legend.style.labels.fontSize, 76 | fill: config.style ? config.style.legendTextColor : theme.legend.style.labels.fill, 77 | }, 78 | }} 79 | data={legendItems.length > 0 ? legendItems : [{ 80 | name: 'undefined', 81 | symbol: { fill: '#333' }, 82 | }]} 83 | itemsPerRow={config.legendOrientation === 'top' || config.legendOrientation === 'bottom' ? 10 84 | : null} 85 | events={[ 86 | { 87 | target: 'data', 88 | eventHandlers: { 89 | onClick: () => { 90 | return [{ target: 'data', mutation: interaction }]; 91 | }, 92 | }, 93 | }, 94 | ]} 95 | /> 96 | 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/components/ComposedChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { VictoryGroup, VictoryStack } from 'victory'; 21 | import _ from 'lodash'; 22 | import BaseChart from './BaseChart'; 23 | import LineChart from './LineChart'; 24 | import AreaChart from './AreaChart'; 25 | import BarChart from './BarChart'; 26 | import ChartContainer from './ChartContainer'; 27 | import LegendComponent from './LegendComponent'; 28 | import darkTheme from './resources/themes/victoryDarkTheme'; 29 | import lightTheme from './resources/themes/victoryLightTheme'; 30 | 31 | /** 32 | * Class to handle visualization of Charts consisting of Area, Bar and Line Charts. 33 | */ 34 | export default class ComposedChart extends BaseChart { 35 | 36 | constructor(props) { 37 | super(props); 38 | this.handleMouseEvent = this.handleMouseEvent.bind(this); 39 | this.handleLegendInteraction = this.handleLegendInteraction.bind(this); 40 | } 41 | 42 | render() { 43 | const finalLegend = []; 44 | const chartComponents = []; 45 | const { config, height, width, theme } = this.props; 46 | const { chartArray, dataSets, xScale, ignoreArray } = this.state; 47 | const currentTheme = theme === 'light' ? lightTheme : darkTheme; 48 | 49 | chartArray.forEach((chart, chartIndex) => { 50 | const localChartSet = []; 51 | let dataSetLength = 1; 52 | _.keys(chart.dataSetNames).forEach((dsName) => { 53 | finalLegend.push({ 54 | name: dsName, 55 | symbol: { fill: _.indexOf(ignoreArray, dsName) > -1 ? '#d3d3d3' : chart.dataSetNames[dsName] }, 56 | chartIndex, 57 | }); 58 | if (dataSetLength < dataSets[dsName].length) dataSetLength = dataSets[dsName].length; 59 | const component = { 60 | line: () => { 61 | return LineChart 62 | .getComponent(config, chartIndex, xScale, dataSets[dsName], chart.dataSetNames[dsName], 63 | null, currentTheme); 64 | }, 65 | area: () => { 66 | return AreaChart 67 | .getComponent(config, chartIndex, xScale, dataSets[dsName], chart.dataSetNames[dsName], 68 | null, currentTheme); 69 | }, 70 | bar: () => { 71 | return BarChart 72 | .getComponent(config, chartIndex, xScale, dataSets[dsName], chart.dataSetNames[dsName], 73 | null, currentTheme); 74 | }, 75 | }; 76 | 77 | if (_.indexOf(ignoreArray, dsName) === -1) { 78 | localChartSet.push(component[chart.type]()); 79 | } 80 | }); 81 | 82 | if (chart.mode === 'stacked') { 83 | chartComponents.push( 84 | ( 85 | {localChartSet} 86 | )); 87 | } else if (chart.type === 'bar') { 88 | const barWidth = 89 | ((BarChart.isHorizontal(config) ? 90 | (height - 80) : (width - 280)) / (dataSetLength * localChartSet.length)) - 1; 91 | 92 | chartComponents.push(( 93 | 98 | {localChartSet} 99 | 100 | )); 101 | } else { 102 | chartComponents.push(...localChartSet); 103 | } 104 | }); 105 | 106 | return ( 107 | 109 | { 110 | config.legend === true ? 111 | : null 118 | 119 | } 120 | {chartComponents} 121 | 122 | ); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /samples/GettingStarted.md: -------------------------------------------------------------------------------- 1 | # Getting started.... 2 | 3 | React VizGrammar is a wrapper around Victory JS and it makes charting easier by adding boilerplate code so that 4 | designers and developers can get started and set it up in a few minutes. 5 | 6 | First start by installing the react-vizgrammar dependency into your project by running the command, 7 | 8 | ```bash 9 | npm i -S react-vizgrammar 10 | ``` 11 | 12 | A chart can be embedded in a React environment simply by importing the VizG component and embedding it in the render 13 | method of a component. 14 | ```jsx 15 | import VizG from 'react-vizgrammar'; 16 | 17 | class RandomComponent extends React.Component { 18 | // component logic 19 | 20 | render() { 21 | return ( 22 | 23 | ); 24 | } 25 | } 26 | ``` 27 | where the props 28 | - `config` is the widget configurations specified as a JSON object. 29 | - `data` is the array of data sets fed to the charts. 30 | - `metadata` is the JSON object that contains information about the provided dataset. 31 | 32 | ### Chart `config` prop 33 | Users have to provide parameters for the widget using config object inorder to create the chart type they require. It is a JSON object that has a well defined configuration attributes to customize the chart. 34 | 35 | Following is a basic configuration to plot a line chart, 36 | ```javascript 37 | let config = { 38 | x : "rpm", 39 | charts : [{type: "line", y : "torque", color: "EngineType"}], 40 | maxLength: 10, 41 | width: 400, 42 | height: 200 43 | } 44 | ``` 45 | These configuration and how it varies for different charts can be found in the charting samples [here](/#/samples). 46 | ### `metadata` prop and `data` prop 47 | Once the `config` is provided. User can provide a dataset to visualize the chart. For easy interpretation React-VizGrammar require this dataset to be arranged in a tabular way similar to the way explained below. 48 | ```javascript 49 | metadata = { 50 | "names": ["Column1", "Column2",...], 51 | "types": ['ordinal', 'linear',...] 52 | }; 53 | ``` 54 | 55 | `metadata.names` is an array consists of column names/fields of the table and `metadata.types` contains their types 56 | (ordinal, time or linear), `names` and `types` are aligned together in a way that "Column1" => 'ordinal' and "Column2" => 'linear' and so on. 57 | 58 | ```javascript 59 | data = [ 60 | ["value1", numericValue1,...], 61 | ["value2", numericValue2,...], 62 | ]; 63 | ``` 64 | `data` collection of arrays of data rows. Single row is stored as an array and their element order follows the order of `metadata.names`. 65 | 66 | Sample data table would be like following: 67 | ```javascript 68 | metadata = { 69 | "names" : ["rpm","torque","horsepower", "EngineType"], 70 | "types" : ["linear","linear", "ordinal","ordinal"] 71 | }; 72 | 73 | data = [ 74 | [8000, 75, 120, "Piston"], 75 | [9000, 81, 130, "Rotary"] 76 | ]; 77 | ``` 78 | 79 | ### Events 80 | React VizGrammar supports `onClick` events, to use the onClick events user has to submit a function to the `onClick` prop of the react component. 81 | 82 | ```jsx 83 | { /* function to perform */ }} /> 84 | ``` 85 | 86 | The submitted function should have a parameter if user wishes to retrieve the data related to the data point. 87 | 88 | ### Themes 89 | 90 | React VizGrammar has light and dark theme types to choose from. By default, charts use the light theme type. 91 | 92 | ```jsx 93 | 94 | 95 | 96 | ``` 97 | 98 | - `theme` prop accepts 'light' and 'dark' strings as type and change the theme accordingly. 99 | 100 | ## Sample in action 101 | 102 | Code : 103 | ```jsx 104 | import React from 'react'; 105 | import VizG from 'react-vizgrammar'; 106 | 107 | export default class SimpleChart extends React.Component { 108 | 109 | constructor(props) { 110 | super(props); 111 | 112 | this.lineChartConfig = { 113 | x: 'rpm', 114 | charts: [{ type: 'line', y: 'torque' }], 115 | maxLength: 30, 116 | width: 800, 117 | height: 400, 118 | interactiveLegend: true, 119 | legend: true, 120 | }; 121 | 122 | this.metadata = { 123 | names: ['rpm', 'torque', 'horsepower', 'EngineType'], 124 | types: ['linear', 'linear', 'ordinal', 'ordinal'], 125 | }; 126 | 127 | this.staticDataSet = [ 128 | [10, 11, 12, 'piston'], 129 | [11, 15, 12, 'rotary'], 130 | [12, 14, 12, 'piston'], 131 | [13, 24, 12, 'rotary'], 132 | [15, 11, 12, 'rotary'], 133 | [16, 15, 12, 'piston'], 134 | [17, 14, 12, 'rotary'], 135 | ]; 136 | } 137 | 138 | 139 | render() { 140 | return ( 141 | 142 | ); 143 | } 144 | } 145 | 146 | ``` 147 | 148 | Output : 149 | -------------------------------------------------------------------------------- /src/VizG.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import React, { Component } from 'react'; 19 | import PropTypes from 'prop-types'; 20 | import _ from 'lodash'; 21 | import MapGenerator from './components/MapChart'; 22 | import TableCharts from './components/TableChart'; 23 | import NumberCharts from './components/NumberChart'; 24 | import InlineCharts from './components/InlineChart'; 25 | import VizGError from './VizGError'; 26 | import LineChart from './components/LineChart'; 27 | import AreaChart from './components/AreaChart'; 28 | import BarChart from './components/BarChart'; 29 | import ComposedChart from './components/ComposedChart'; 30 | import ArcCharts from './components/ArcCharts'; 31 | import ScatterPlot from './components/ScatterPlot'; 32 | 33 | class VizG extends Component { 34 | /** 35 | * Function will render a chart based on the given chart. 36 | * @param {String} chartType Chart type of the chart. 37 | * @param {Object} config Chart configuration provided by the user 38 | * @param {Array} data Data provided by the user 39 | * @param {Object} metadata Metadata related to the data provided 40 | * @param {Function} onClick OnClick function provided by the user 41 | * @param {Boolean} manual indicates if the user handle data manually 42 | * @param {Function} onFetchData function to be executed when fetching data(only for table charts with 43 | * server-side pagination) 44 | * @param {Number} pages Total number of pages(only for table charts) 45 | * @private 46 | */ 47 | _getChartComponent(chartType, config, data, metadata, onClick, manual, onFetchData, pages) { 48 | if (chartType === 'spark-line' || chartType === 'spark-area' || chartType === 'spark-bar') chartType = 'inline'; 49 | 50 | const component = { 51 | line: LineChart, 52 | area: AreaChart, 53 | bar: BarChart, 54 | composed: ComposedChart, 55 | arc: ArcCharts, 56 | scatter: ScatterPlot, 57 | table: TableCharts, 58 | number: NumberCharts, 59 | inline: InlineCharts, 60 | map: MapGenerator, 61 | }; 62 | 63 | if (!component[chartType]) throw new VizGError('VizG', 'Invalid chart type defined in the configuration.'); 64 | 65 | const ChartComponent = component[chartType]; 66 | 67 | return ( 68 | 84 | ); 85 | } 86 | 87 | /** 88 | * Check if the chart contains configuration of a mixed chart. 89 | * @param config 90 | * @returns {string} 91 | * @private 92 | */ 93 | _isComposed(config) { 94 | const chartType = config.charts[0].type; 95 | if ((chartType === 'line' || chartType === 'area' || chartType === 'bar') && config.charts.length > 1) { 96 | const areaChart = _.find(config.charts, { type: 'area' }); 97 | const barChart = _.find(config.charts, { type: 'bar' }); 98 | const lineChart = _.find(config.charts, { type: 'line' }); 99 | 100 | if ((!areaChart && !barChart) || (!lineChart && !areaChart) || (!barChart && !lineChart)) { 101 | return chartType; 102 | } else { 103 | return 'composed'; 104 | } 105 | } else { 106 | return chartType; 107 | } 108 | } 109 | 110 | render() { 111 | const { config, data, metadata, onClick, manual, onFetchData, pages } = this.props; 112 | return ( 113 |
114 | { 115 | !config || !metadata ? 116 | null : 117 | this._getChartComponent(this._isComposed(config), config, data, metadata, onClick, manual, 118 | onFetchData, pages) 119 | } 120 |
121 | ); 122 | } 123 | } 124 | 125 | VizG.defaultProps = { 126 | append: true, 127 | theme: 'light', 128 | width: 800, 129 | height: 450, 130 | manual: false, 131 | pages: -1, 132 | }; 133 | 134 | VizG.propTypes = { 135 | config: PropTypes.object.isRequired, 136 | data: PropTypes.array, 137 | metadata: PropTypes.object.isRequired, 138 | onClick: PropTypes.func, 139 | append: PropTypes.bool, 140 | theme: PropTypes.string, 141 | height: PropTypes.number, 142 | width: PropTypes.number, 143 | manual: PropTypes.bool, 144 | onFetchData: PropTypes.func, 145 | pages: PropTypes.number, 146 | }; 147 | 148 | export default VizG; 149 | -------------------------------------------------------------------------------- /samples/chart-docs/NumberChartSample.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { Grid } from 'material-ui'; 21 | import ChartWrapper from '../ChartWrapper'; 22 | import VizG from '../../src/VizG'; 23 | import { syntaxHighlight } from './util/SyntaxHighLight'; 24 | import Header from '../components/Header'; 25 | 26 | export default class NumberChartSample extends React.Component { 27 | constructor(props) { 28 | super(props); 29 | this.state = { 30 | data: [ 31 | [10], 32 | ], 33 | timer: 1, 34 | }; 35 | 36 | this.numConfig = { 37 | x: 'torque', 38 | title: 'Torque of Engine', 39 | charts: [{ type: 'number' }], 40 | showDifference: true, 41 | showPercentage: true, 42 | showDecimal: false, 43 | }; 44 | 45 | this.metadata = { 46 | names: ['torque'], 47 | types: ['linear'], 48 | }; 49 | 50 | this.intervalObj = null; 51 | } 52 | 53 | componentDidMount() { 54 | this.intervalObj = setInterval(() => { 55 | this.setState({ 56 | data: [[Math.round(Math.random() * 100)], [Math.round(Math.random() * 100)]], 57 | }); 58 | }, 1000); 59 | } 60 | 61 | componentWillUnmount() { 62 | clearInterval(this.intervalObj); 63 | } 64 | 65 | render() { 66 | return ( 67 |
68 |
69 | 70 | 71 | 77 |
78 | 80 |
81 |
82 |

83 |
 91 |                             
92 |
93 |
94 | 95 | 101 |
102 | metadata: 103 |
109 |                                 data:
110 |                                 
116 |                                 

117 |

Chart Configuration JSON structure

118 |
    119 |
  • x - Datafield that should be shown in the number chart
  • 120 |
  • title - Title that should be displayed in the chart
  • 121 |
  • 122 | charts - Array of chart objects that should be visualized 123 |
      124 |
    • type - Type of the chart to be displayed
    • 125 |
    126 |
  • 127 |
  • showDifference - Show difference between current value and the 128 | previous value
  • 129 |
  • showPercentage - Show difference with the previous value as a 130 | percentage
  • 131 |
  • showDifference - Show Decimal places in the Number
  • 132 |
133 |
134 |
135 |

Style

136 | Number Chart scales to available outer wrapper width/height, preserving aspect ratio. 137 | Set outer wrapper width and height to scale Number Chart accordingly. 138 |
139 |
140 |
141 |
142 |
143 | ); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /samples/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import ReactDOM from 'react-dom'; 21 | import { MuiThemeProvider, createMuiTheme, IconButton } from 'material-ui'; 22 | import LightBulbFill from './components/LightBulbFill' 23 | import LightBulbOutline from './components/LightBulbOutline'; 24 | import { HashRouter as Router, Route, Switch as RouterSwitch } from 'react-router-dom'; 25 | import ScrollReset from './ScrollReset'; 26 | import App from './App'; 27 | import LineCharts from './chart-docs/LineChartSamples'; 28 | import AreaCharts from './chart-docs/AreaChartSamples'; 29 | import BarCharts from './chart-docs/BarChartSamples'; 30 | import ScatterChart from './chart-docs/ScatterPlotSample'; 31 | import Maps from './chart-docs/GeographicalChartsSample'; 32 | import Arcs from './chart-docs/PieChartSamples'; 33 | import NumChart from './chart-docs/NumberChartSample'; 34 | import Table from './chart-docs/TableChartSamples'; 35 | import GettingStarted from './GettingStarted'; 36 | import './styles/style.css'; 37 | 38 | const darkTheme = createMuiTheme({ 39 | palette: { 40 | type: 'dark', 41 | }, 42 | }); 43 | 44 | const lightTheme = createMuiTheme({ 45 | palette: { 46 | type: 'light', 47 | }, 48 | }); 49 | 50 | class AppRoute extends React.Component { 51 | 52 | constructor() { 53 | super(); 54 | this.state = { 55 | theme: `light`, 56 | check: false, 57 | }; 58 | } 59 | 60 | handleChange = (evt) => { 61 | 62 | evt.preventDefault(); 63 | this.setState({ 64 | check: !this.state.check, 65 | theme: !this.state.check ? `dark` : `light` 66 | }); 67 | 68 | }; 69 | 70 | render() { 71 | return ( 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | ( 81 |
82 | 87 | {this.state.theme === `dark` ? : } 88 | 89 |
90 | )} /> 91 |
92 | 93 | { 94 | return ( 95 | 96 | ) 97 | }} /> 98 | 99 | 100 | { 101 | return ( 102 | 103 | ) 104 | }} /> 105 | 106 | 107 | { 108 | return ( 109 | 110 | ) 111 | }} /> 112 | 113 | 114 | { 115 | return ( 116 | 117 | ) 118 | }} /> 119 | 120 | 121 | { 122 | return ( 123 | 124 | ) 125 | }} /> 126 | 127 | 128 | { 129 | return ( 130 | 131 | ) 132 | }} /> 133 | 134 | 135 | { 136 | return ( 137 | 138 | ) 139 | }} /> 140 | 141 | 142 | { 143 | return ( 144 | 145 | ) 146 | }} /> 147 | 148 | 149 | { 150 | return ( 151 | 152 | ) 153 | }} /> 154 | 155 | 156 | 157 | 158 | ); 159 | } 160 | } 161 | 162 | ReactDOM.render( 163 | , 164 | document.getElementById('samples') 165 | ); 166 | -------------------------------------------------------------------------------- /src/components/NumberChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import PropTypes from 'prop-types'; 21 | import { VictoryLabel } from 'victory'; 22 | import VizGError from '../VizGError'; 23 | import lightTheme from './resources/themes/victoryLightTheme'; 24 | import darkTheme from './resources/themes/victoryDarkTheme'; 25 | 26 | /** 27 | * Class to handle visualization of Number Charts. 28 | */ 29 | export default class NumberCharts extends React.Component { 30 | constructor(props) { 31 | super(props); 32 | this.state = { 33 | value: null, 34 | prevValue: null, 35 | }; 36 | } 37 | 38 | componentDidMount() { 39 | if (this.props.metadata !== null) { 40 | this._handleData(this.props); 41 | } 42 | } 43 | 44 | componentWillReceiveProps(nextProps) { 45 | if (this.props.metadata !== null) { 46 | this._handleData(nextProps); 47 | } 48 | } 49 | 50 | /** 51 | * handles data received by the props 52 | * @param props 53 | * @private 54 | */ 55 | _handleData(props) { 56 | const { config, data, metadata } = props; 57 | let { prevValue, value } = this.state; 58 | const xIndex = metadata.names.indexOf(config.x); 59 | 60 | if (xIndex === -1) { 61 | throw new VizGError('MapChart', "Unknown 'x' field defined in the Number Chart config."); 62 | } 63 | 64 | if (data.length > 0) { 65 | prevValue = value; 66 | value = data[data.length - 1][xIndex]; 67 | } 68 | 69 | this.setState({ value, prevValue }); 70 | } 71 | 72 | render() { 73 | const { config, width, height, theme } = this.props; 74 | const currentTheme = theme === 'light' ? lightTheme : darkTheme; 75 | const { prevValue, value } = this.state; 76 | const highValueColor = config.highValueColor || currentTheme.number.style.labels.highValue.fill; 77 | const lowValueColor = config.lowValueColor || currentTheme.number.style.labels.lowValue.fill; 78 | const viewBoxWidth = config.title.length * 20; 79 | 80 | return ( 81 | 82 | 90 | 98 | { 99 | config.showDifference ? [ 100 | ( { 106 | if (prevValue < value) { 107 | return '+'; 108 | } else if (prevValue === value) { 109 | return ''; 110 | } else { 111 | return '-'; 112 | } 113 | })()} 114 | style={{ fill: currentTheme.number.style.labels.difference.fill, fontSize: 26 }} 115 | />), 116 | ( 117 | 129 | )] : null 130 | } 131 | { 132 | config.showPercentage ? [ 133 | (), 142 | ( { 149 | if (prevValue < value) { 150 | return '↑'; 151 | } else if (prevValue === value) { 152 | return ''; 153 | } else { 154 | return '↓'; 155 | } 156 | })()} 157 | style={{ fill: prevValue < value ? highValueColor : lowValueColor, fontSize: 26 }} 158 | />)] : null 159 | } 160 | 161 | 162 | ); 163 | } 164 | } 165 | 166 | NumberCharts.propTypes = { 167 | config: PropTypes.shape({ 168 | x: PropTypes.string, 169 | title: PropTypes.string, 170 | charts: PropTypes.arrayOf(PropTypes.shape({ 171 | type: PropTypes.string, 172 | })), 173 | showDifference: PropTypes.bool, 174 | showPercentage: PropTypes.bool, 175 | }).isRequired, 176 | metadata: PropTypes.shape({ 177 | names: PropTypes.arrayOf(PropTypes.string), 178 | types: PropTypes.arrayOf(PropTypes.string), 179 | }).isRequired, 180 | data: PropTypes.array, 181 | height: PropTypes.number, 182 | width: PropTypes.number, 183 | }; 184 | 185 | NumberCharts.defaultProps = { 186 | height: 450, 187 | width: 800, 188 | data: [], 189 | }; 190 | -------------------------------------------------------------------------------- /src/components/InlineChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { VictoryLine, VictoryArea, VictoryGroup, VictoryBar, VictoryTooltip, VictoryStack } from 'victory'; 21 | import VizGError from '../VizGError'; 22 | import BaseChart from './BaseChart'; 23 | 24 | /** 25 | * Class to handle visualization of spark charts. 26 | */ 27 | export default class InlineChart extends BaseChart { 28 | 29 | constructor(props) { 30 | super(props); 31 | this.sortDataBasedOnConfig = this.sortDataBasedOnConfig.bind(this); 32 | } 33 | 34 | render() { 35 | const { config, height, width } = this.props; 36 | const { chartArray, dataSets } = this.state; 37 | let chartComponents = []; 38 | let horizontal = false; 39 | const lineCharts = []; 40 | let areaCharts = []; 41 | let barCharts = []; 42 | 43 | chartArray.map((chart, chartIndex) => { 44 | switch (chart.type) { 45 | case 'spark-line': 46 | Object.keys(chart.dataSetNames).map((dataSetName) => { 47 | lineCharts.push(( 48 | 62 | 65 | 66 | )); 67 | return null; 68 | }); 69 | break; 70 | case 'spark-area': { 71 | const areaLocal = []; 72 | Object.keys(chart.dataSetNames).map((dataSetName) => { 73 | areaLocal.push(( 74 | 89 | 92 | 93 | )); 94 | return null; 95 | }); 96 | 97 | if (chart.mode === 'stacked') { 98 | areaCharts.push(( 99 | 104 | {areaLocal} 105 | 106 | )); 107 | } else { 108 | areaCharts = areaCharts.concat(areaLocal); 109 | } 110 | break; 111 | } 112 | case 'spark-bar': { 113 | const localBar = []; 114 | 115 | horizontal = horizontal || chart.orientation === 'left'; 116 | 117 | Object.keys(chart.dataSetNames).map((dataSetName) => { 118 | localBar.push(( 119 | `${config.x}:${d.x}\n${config.charts[chartIndex].y}:${d.y}`} 121 | labelComponent={ 122 | 125 | } 126 | data={dataSets[dataSetName]} 127 | color={chart.dataSetNames[dataSetName]} 128 | height={height} 129 | width={width} 130 | padding={0} 131 | /> 132 | )); 133 | return null; 134 | }); 135 | 136 | if (chart.mode === 'stacked') { 137 | barCharts.push(( 138 | 143 | {localBar} 144 | 145 | )); 146 | } else { 147 | barCharts = barCharts.concat(localBar); 148 | } 149 | break; 150 | } 151 | default: 152 | throw new VizGError('InlineChart', 'Unsupported chart type defined in the config.'); 153 | } 154 | return null; 155 | }); 156 | 157 | if (areaCharts.length > 0) chartComponents = chartComponents.concat(areaCharts); 158 | if (lineCharts.length > 0) chartComponents = chartComponents.concat(lineCharts); 159 | if (barCharts.length > 0) { 160 | const barWidth = 161 | ((horizontal ? height : width) / (config.maxLength * (barCharts.length > 1 ? barCharts.length : 2))) - 3; 162 | chartComponents.push(( 163 | 171 | {barCharts} 172 | 173 | )); 174 | } 175 | 176 | return ( 177 |
{chartComponents}
178 | ); 179 | } 180 | } 181 | 182 | InlineChart.defaultProps = { 183 | height: 100, 184 | width: 200, 185 | }; 186 | -------------------------------------------------------------------------------- /src/components/LineChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { VictoryLine, VictoryTooltip, VictoryScatter } from 'victory'; 21 | import _ from 'lodash'; 22 | import { timeFormat } from 'd3'; 23 | import BaseChart from './BaseChart'; 24 | import ChartContainer from './ChartContainer'; 25 | import BarChart from './BarChart'; 26 | import LegendComponent from './LegendComponent'; 27 | import lightTheme from './resources/themes/victoryLightTheme'; 28 | import darkTheme from './resources/themes/victoryDarkTheme'; 29 | 30 | /** 31 | * Class to handle the visualization of line charts. 32 | */ 33 | export default class LineChart extends BaseChart { 34 | constructor(props) { 35 | super(props); 36 | this.sortDataBasedOnConfig = this.sortDataBasedOnConfig.bind(this); 37 | this.handleMouseEvent = this.handleMouseEvent.bind(this); 38 | this.handleLegendInteraction = this.handleLegendInteraction.bind(this); 39 | } 40 | 41 | /** 42 | * Generate the chart components in the case where there's only Line charts defined in the chart config. 43 | * @param {Array} chartArray - Array containing objects that has the information to visualize each area chart. 44 | * @param {String} xScale - xAxis scale to be used in the charts. 45 | * @param {Object} dataSets - object containing arrays of data after classification. 46 | * @param {Object} config - object containing user provided chart configuration 47 | * @param {Function} onClick - function to be executed on click event 48 | * @param {Array} ignoreArray - array that contains dataSets to be ignored in rendering the components. 49 | * @returns {{chartComponents: Array, legendComponents: Array}} 50 | */ 51 | static getLineChartComponent(chartArray, xScale, dataSets, config, onClick, ignoreArray, currentTheme) { 52 | const chartComponents = []; 53 | const legendComponents = []; 54 | 55 | chartArray.forEach((chart, chartIndex) => { 56 | _.keys(chart.dataSetNames).forEach((dsName) => { 57 | legendComponents.push({ 58 | name: dsName, 59 | symbol: { fill: _.indexOf(ignoreArray, dsName) > -1 ? '#d3d3d3' : chart.dataSetNames[dsName] }, 60 | chartIndex, 61 | }); 62 | if (_.indexOf(ignoreArray, dsName) === -1) { 63 | chartComponents.push(...LineChart 64 | .getComponent(config, chartIndex, xScale, dataSets[dsName], chart.dataSetNames[dsName], 65 | onClick, currentTheme)); 66 | } 67 | }); 68 | }); 69 | 70 | return { chartComponents, legendComponents }; 71 | } 72 | 73 | /** 74 | * Generate a single Line chart component to be visualized. 75 | * @param {Object} config - Chart configuration provided by the user. 76 | * @param {Number} chartIndex - Index of the chart definition in the chart Array. 77 | * @param {String} xScale - Scale to be used in the xAxis when plotting the chart. 78 | * @param {Array} data - Array of objects that containing the dataset to be plotted using this chart component. 79 | * @param {String} color - Color the chart should be plotted in. 80 | * @param {Function} onClick - Function to be executed in the case of an click event. 81 | * @returns {Element} 82 | */ 83 | static getComponent(config, chartIndex, xScale, data, color, onClick, currentTheme) { 84 | return [ 85 | (), 99 | ( { 109 | if (xScale === 'time' && config.tipTimeFormat) { 110 | return (d) => { 111 | return `${config.x} : ${timeFormat(config.tipTimeFormat)(new Date(d.x))}\n` + 112 | `${config.charts[chartIndex].y} : ${Number(d.y).toFixed(2)}`; 113 | }; 114 | } else { 115 | return (d) => { 116 | if (isNaN(d.x)) { 117 | return `${config.x} : ${d.x}\n${config.charts[chartIndex].y} : ${Number(d.y) 118 | .toFixed(2)}`; 119 | } else { 120 | return `${config.x} : ${Number(d.x).toFixed(2)}\n` + 121 | `${config.charts[chartIndex].y} : ${Number(d.y).toFixed(2)}`; 122 | } 123 | }; 124 | } 125 | })() 126 | } 127 | labelComponent={ 128 | 138 | } 139 | size={( 140 | config.charts[chartIndex].style ? 141 | config.charts[chartIndex].style.markRadius || currentTheme.scatter.style.data.markRadius 142 | : currentTheme.scatter.style.data.markRadius 143 | )} 144 | events={[{ 145 | target: 'data', 146 | eventHandlers: { 147 | onClick: () => { 148 | return [{ target: 'data', mutation: onClick }]; 149 | }, 150 | }, 151 | }]} 152 | />), 153 | ]; 154 | } 155 | 156 | render() { 157 | const { config, height, width, yDomain, theme } = this.props; 158 | const { chartArray, dataSets, xScale, ignoreArray } = this.state; 159 | const currentTheme = theme === 'light' ? lightTheme : darkTheme; 160 | 161 | const { chartComponents, legendComponents } = 162 | LineChart.getLineChartComponent(chartArray, xScale, dataSets, config, this.handleMouseEvent, ignoreArray, 163 | currentTheme); 164 | 165 | return ( 166 | 175 | { 176 | config.legend === true ? 177 | : null 185 | 186 | } 187 | {chartComponents} 188 | 189 | ); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/components/resources/themes/victoryLightTheme.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import assign from 'lodash/assign'; 20 | 21 | // Colors 22 | const yellow200 = '#FFF59D'; 23 | const deepOrange600 = '#F4511E'; 24 | const lime300 = '#DCE775'; 25 | const lightGreen500 = '#8BC34A'; 26 | const teal700 = '#00796B'; 27 | const cyan900 = '#006064'; 28 | const blueGrey50 = '#ECEFF1'; 29 | const blueGrey300 = '#90A4AE'; 30 | const blueGrey700 = '#455A64'; 31 | const grey900 = '#212121'; 32 | const colors = [ 33 | deepOrange600, 34 | yellow200, 35 | lime300, 36 | lightGreen500, 37 | teal700, 38 | cyan900, 39 | ]; 40 | 41 | // Typography 42 | const sansSerif = "'Roboto', 'Helvetica Neue', Helvetica, sans-serif"; 43 | const letterSpacing = 'normal'; 44 | const fontSize = 14; 45 | const fontSizeSmall = 12; 46 | 47 | // Layout 48 | const padding = 10; 49 | const axisLabelPadding = 30; 50 | const tickLabelpadding = 0; 51 | const baseProps = { 52 | width: 800, 53 | height: 450, 54 | padding: 50, 55 | colorScale: colors, 56 | }; 57 | 58 | // Labels 59 | const baseLabelStyles = { 60 | fontFamily: sansSerif, 61 | fontSize, 62 | letterSpacing, 63 | padding, 64 | fill: blueGrey700, 65 | stroke: 'transparent', 66 | }; 67 | 68 | const centeredLabelStyles = assign({ textAnchor: 'middle' }, baseLabelStyles); 69 | 70 | // Strokes 71 | const strokeDasharray = 'none'; 72 | const strokeLinecap = 'round'; 73 | const strokeLinejoin = 'round'; 74 | const strokeOpacity = '.15'; 75 | const markRadius = '4'; 76 | 77 | const victoryLightTheme = { 78 | area: assign({ 79 | style: { 80 | data: { 81 | fill: grey900, 82 | fillOpacity: '0.1', 83 | markRadius: markRadius, 84 | }, 85 | labels: centeredLabelStyles, 86 | }, 87 | }, baseProps), 88 | axis: assign({ 89 | style: { 90 | axis: { 91 | fill: 'transparent', 92 | stroke: blueGrey300, 93 | strokeWidth: 1, 94 | strokeLinecap, 95 | strokeLinejoin, 96 | }, 97 | axisLabel: assign({}, centeredLabelStyles, { 98 | padding: axisLabelPadding, 99 | stroke: 'transparent', 100 | }), 101 | grid: { 102 | fill: 'transparent', 103 | stroke: '#000', 104 | strokeDasharray, 105 | strokeLinecap, 106 | strokeLinejoin, 107 | strokeOpacity, 108 | }, 109 | ticks: { 110 | fill: 'transparent', 111 | size: 10, 112 | stroke: blueGrey300, 113 | strokeWidth: 1, 114 | strokeLinecap, 115 | strokeLinejoin, 116 | strokeOpacity, 117 | }, 118 | tickLabels: assign({}, baseLabelStyles, { 119 | fontSize: fontSizeSmall, 120 | fill: blueGrey300, 121 | stroke: 'transparent', 122 | padding: tickLabelpadding, 123 | }), 124 | }, 125 | }, baseProps), 126 | bar: assign({ 127 | style: { 128 | data: { 129 | fill: blueGrey700, 130 | padding, 131 | stroke: 'transparent', 132 | strokeWidth: 0, 133 | width: 5, 134 | }, 135 | labels: baseLabelStyles, 136 | }, 137 | }, baseProps), 138 | candlestick: assign({ 139 | style: { 140 | data: { 141 | stroke: blueGrey700, 142 | strokeWidth: 1, 143 | }, 144 | labels: centeredLabelStyles, 145 | }, 146 | candleColors: { 147 | positive: blueGrey50, 148 | negative: blueGrey700, 149 | }, 150 | }, baseProps), 151 | chart: baseProps, 152 | errorbar: assign({ 153 | style: { 154 | data: { 155 | fill: 'transparent', 156 | opacity: 1, 157 | stroke: blueGrey700, 158 | strokeWidth: 2, 159 | }, 160 | labels: assign({}, centeredLabelStyles, { 161 | stroke: 'transparent', 162 | strokeWidth: 0, 163 | }), 164 | }, 165 | }, baseProps), 166 | group: assign({ 167 | colorScale: colors, 168 | }, baseProps), 169 | line: assign({ 170 | style: { 171 | data: { 172 | fill: 'transparent', 173 | opacity: 1, 174 | stroke: blueGrey700, 175 | strokeWidth: 1, 176 | markRadius: markRadius, 177 | }, 178 | labels: assign({}, baseLabelStyles, { 179 | stroke: 'transparent', 180 | strokeWidth: 0, 181 | textAnchor: 'start', 182 | }), 183 | }, 184 | }, baseProps), 185 | pie: assign({ 186 | colorScale: colors, 187 | style: { 188 | data: { 189 | padding, 190 | stroke: blueGrey50, 191 | strokeWidth: 1, 192 | innerRadius: 0, 193 | }, 194 | labels: assign({}, baseLabelStyles, { 195 | padding: 20, 196 | stroke: 'transparent', 197 | strokeWidth: 0, 198 | }), 199 | presentage: { 200 | fontSize: '45', 201 | }, 202 | }, 203 | }, baseProps), 204 | scatter: assign({ 205 | style: { 206 | data: { 207 | fill: blueGrey700, 208 | opacity: 1, 209 | stroke: 'transparent', 210 | strokeWidth: 0, 211 | markRadius: markRadius, 212 | }, 213 | labels: assign({}, centeredLabelStyles, { 214 | stroke: 'transparent', 215 | }), 216 | }, 217 | }, baseProps), 218 | stack: assign({ 219 | colorScale: colors, 220 | }, baseProps), 221 | tooltip: assign({ 222 | style: { 223 | labels: { 224 | fill: blueGrey50, 225 | }, 226 | flyout: { 227 | fillOpacity: '0.8', 228 | strokeWidth: 1, 229 | fill: '#000', 230 | }, 231 | }, 232 | flyoutProps: { 233 | cornerRadius: 10, 234 | pointerLength: 10, 235 | }, 236 | }, baseProps), 237 | legend: assign({ 238 | style: { 239 | labels: assign({}, baseLabelStyles, { fontSize: 18 }), 240 | title: assign({}, baseLabelStyles, { fontSize: 25 }), 241 | }, 242 | }, baseProps), 243 | voronoi: assign({ 244 | style: { 245 | data: { 246 | fill: 'transparent', 247 | stroke: 'transparent', 248 | strokeWidth: 0, 249 | }, 250 | labels: centeredLabelStyles, 251 | }, 252 | }, baseProps), 253 | number: assign({ 254 | style: { 255 | labels: { 256 | title: { 257 | fill: blueGrey700, 258 | }, 259 | highValue: { 260 | fill: lightGreen500, 261 | }, 262 | lowValue: { 263 | fill: deepOrange600, 264 | }, 265 | mainValue: { 266 | fill: blueGrey700, 267 | }, 268 | difference: { 269 | fill: blueGrey300, 270 | }, 271 | }, 272 | }, 273 | }, baseProps), 274 | map: assign({ 275 | style: { 276 | labels: { 277 | title: { 278 | fill: blueGrey700, 279 | fontSize: fontSize, 280 | }, 281 | legend: { 282 | fill: blueGrey700, 283 | fontSize: fontSizeSmall, 284 | }, 285 | }, 286 | default: { 287 | fill: '#ddd', 288 | stroke: '#fff', 289 | strokeWidth: '0.5', 290 | outline: 'none', 291 | }, 292 | hover: { 293 | fill: '#ddd', 294 | opacity: '0.8', 295 | stroke: '#fff', 296 | strokeWidth: '0.5', 297 | outline: 'none', 298 | }, 299 | pressed: { 300 | fill: '#3a79ff', 301 | outline: 'none', 302 | }, 303 | }, 304 | }, baseProps), 305 | }; 306 | 307 | export default victoryLightTheme; 308 | -------------------------------------------------------------------------------- /src/components/resources/themes/victoryDarkTheme.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import assign from 'lodash/assign'; 20 | 21 | // Colors 22 | const yellow200 = '#FFF59D'; 23 | const deepOrange600 = '#F4511E'; 24 | const lime300 = '#DCE775'; 25 | const lightGreen500 = '#8BC34A'; 26 | const teal700 = '#00796B'; 27 | const cyan900 = '#006064'; 28 | const blueGrey50 = '#ECEFF1'; 29 | const blueGrey300 = '#90A4AE'; 30 | const grey700 = '#616161'; 31 | const grey500 = '#9E9E9E'; 32 | const grey50 = '#FAFAFA'; 33 | const grey900 = '#212121'; 34 | 35 | const colors = [ 36 | deepOrange600, 37 | yellow200, 38 | lime300, 39 | lightGreen500, 40 | teal700, 41 | cyan900, 42 | ]; 43 | 44 | // Typography 45 | const sansSerif = "'Roboto', 'Helvetica Neue', Helvetica, sans-serif"; 46 | const letterSpacing = 'normal'; 47 | const fontSize = 14; 48 | const fontSizeSmall = 12; 49 | 50 | // Layout 51 | const padding = 10; 52 | const axisLabelPadding = 30; 53 | const tickLabelpadding = 0; 54 | const baseProps = { 55 | width: 800, 56 | height: 450, 57 | padding: 50, 58 | colorScale: colors, 59 | }; 60 | 61 | // Labels 62 | const baseLabelStyles = { 63 | fontFamily: sansSerif, 64 | fontSize, 65 | letterSpacing, 66 | padding, 67 | fill: grey500, 68 | stroke: 'transparent', 69 | }; 70 | 71 | const centeredLabelStyles = assign({ textAnchor: 'middle' }, baseLabelStyles); 72 | 73 | // Strokes 74 | const strokeDasharray = 'none'; 75 | const strokeLinecap = 'round'; 76 | const strokeLinejoin = 'round'; 77 | const strokeOpacity = '.15'; 78 | const markRadius = '4'; 79 | 80 | const victoryDarkTheme = { 81 | area: assign({ 82 | style: { 83 | data: { 84 | fill: grey900, 85 | fillOpacity: '0.1', 86 | markRadius: markRadius, 87 | }, 88 | labels: centeredLabelStyles, 89 | }, 90 | }, baseProps), 91 | axis: assign({ 92 | style: { 93 | axis: { 94 | fill: 'transparent', 95 | stroke: grey500, 96 | strokeWidth: 1, 97 | strokeLinecap, 98 | strokeLinejoin, 99 | }, 100 | axisLabel: assign({}, centeredLabelStyles, { 101 | padding: axisLabelPadding, 102 | stroke: 'transparent', 103 | }), 104 | grid: { 105 | fill: 'transparent', 106 | stroke: blueGrey50, 107 | strokeDasharray, 108 | strokeLinecap, 109 | strokeLinejoin, 110 | strokeOpacity, 111 | }, 112 | ticks: { 113 | fill: 'transparent', 114 | size: 10, 115 | stroke: grey700, 116 | strokeWidth: 1, 117 | strokeLinecap, 118 | strokeLinejoin, 119 | strokeOpacity, 120 | }, 121 | tickLabels: assign({}, baseLabelStyles, { 122 | fontSize: fontSizeSmall, 123 | fill: grey500, 124 | stroke: 'transparent', 125 | padding: tickLabelpadding, 126 | }), 127 | }, 128 | }, baseProps), 129 | bar: assign({ 130 | style: { 131 | data: { 132 | fill: grey500, 133 | padding, 134 | stroke: 'transparent', 135 | strokeWidth: 0, 136 | width: 5, 137 | }, 138 | labels: baseLabelStyles, 139 | }, 140 | }, baseProps), 141 | candlestick: assign({ 142 | style: { 143 | data: { 144 | stroke: grey500, 145 | strokeWidth: 1, 146 | }, 147 | labels: centeredLabelStyles, 148 | }, 149 | candleColors: { 150 | positive: blueGrey50, 151 | negative: grey500, 152 | }, 153 | }, baseProps), 154 | chart: baseProps, 155 | errorbar: assign({ 156 | style: { 157 | data: { 158 | fill: 'transparent', 159 | opacity: 1, 160 | stroke: grey500, 161 | strokeWidth: 2, 162 | }, 163 | labels: assign({}, centeredLabelStyles, { 164 | stroke: 'transparent', 165 | strokeWidth: 0, 166 | }), 167 | }, 168 | }, baseProps), 169 | group: assign({ 170 | colorScale: colors, 171 | }, baseProps), 172 | line: assign({ 173 | style: { 174 | data: { 175 | fill: 'transparent', 176 | opacity: 1, 177 | stroke: grey500, 178 | strokeWidth: 1, 179 | markRadius: markRadius, 180 | }, 181 | labels: assign({}, baseLabelStyles, { 182 | stroke: 'transparent', 183 | strokeWidth: 0, 184 | textAnchor: 'start', 185 | }), 186 | }, 187 | }, baseProps), 188 | pie: assign({ 189 | colorScale: colors, 190 | style: { 191 | data: { 192 | padding, 193 | stroke: 'transparent', 194 | strokeWidth: 1, 195 | innerRadius: 0, 196 | }, 197 | labels: assign({}, baseLabelStyles, { 198 | padding: 20, 199 | stroke: 'transparent', 200 | strokeWidth: 0, 201 | }), 202 | presentage: { 203 | fontSize: '45', 204 | }, 205 | }, 206 | }, baseProps), 207 | scatter: assign({ 208 | style: { 209 | data: { 210 | fill: grey500, 211 | opacity: 1, 212 | stroke: 'transparent', 213 | strokeWidth: 0, 214 | markRadius: markRadius, 215 | }, 216 | labels: assign({}, centeredLabelStyles, { 217 | stroke: 'transparent', 218 | }), 219 | }, 220 | }, baseProps), 221 | stack: assign({ 222 | colorScale: colors, 223 | }, baseProps), 224 | tooltip: assign({ 225 | style: { 226 | labels: { 227 | fill: blueGrey50, 228 | }, 229 | flyout: { 230 | fillOpacity: '0.8', 231 | strokeWidth: 1, 232 | fill: '#000', 233 | }, 234 | }, 235 | flyoutProps: { 236 | cornerRadius: 10, 237 | pointerLength: 10, 238 | }, 239 | }, baseProps), 240 | legend: assign({ 241 | style: { 242 | labels: assign({}, baseLabelStyles, { fontSize: 18 }), 243 | title: assign({}, baseLabelStyles, { fontSize: 25 }), 244 | }, 245 | }, baseProps), 246 | voronoi: assign({ 247 | style: { 248 | data: { 249 | fill: 'transparent', 250 | stroke: 'transparent', 251 | strokeWidth: 0, 252 | }, 253 | labels: centeredLabelStyles, 254 | }, 255 | }, baseProps), 256 | number: assign({ 257 | style: { 258 | labels: { 259 | title: { 260 | fill: grey50, 261 | }, 262 | highValue: { 263 | fill: lightGreen500, 264 | }, 265 | lowValue: { 266 | fill: deepOrange600, 267 | }, 268 | mainValue: { 269 | fill: blueGrey300, 270 | }, 271 | difference: { 272 | fill: grey500, 273 | }, 274 | }, 275 | }, 276 | }, baseProps), 277 | map: assign({ 278 | style: { 279 | labels: { 280 | title: { 281 | fill: grey500, 282 | fontSize: fontSize, 283 | }, 284 | legend: { 285 | fill: grey500, 286 | fontSize: fontSizeSmall, 287 | }, 288 | }, 289 | default: { 290 | fill: '#ddd', 291 | stroke: '#fff', 292 | strokeWidth: '0.5', 293 | outline: 'none', 294 | }, 295 | hover: { 296 | fill: '#ddd', 297 | opacity: '0.8', 298 | stroke: '#fff', 299 | strokeWidth: '0.5', 300 | outline: 'none', 301 | }, 302 | pressed: { 303 | fill: '#3a79ff', 304 | outline: 'none', 305 | }, 306 | }, 307 | }, baseProps), 308 | }; 309 | 310 | export default victoryDarkTheme; 311 | -------------------------------------------------------------------------------- /src/components/ArcCharts.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import _ from 'lodash'; 21 | import { VictoryPie, VictoryTooltip, VictoryLabel } from 'victory'; 22 | import BaseChart from './BaseChart'; 23 | import VizGError from '../VizGError'; 24 | import ChartContainer from './ChartContainer'; 25 | import LegendComponent from './LegendComponent'; 26 | import lightTheme from './resources/themes/victoryLightTheme'; 27 | import darkTheme from './resources/themes/victoryDarkTheme'; 28 | 29 | /** 30 | * Class to handle Visualization of Arc Charts. 31 | */ 32 | export default class ArcChart extends BaseChart { 33 | 34 | constructor(props) { 35 | super(props); 36 | this.handleMouseEvent = this.handleMouseEvent.bind(this); 37 | this.chartMode = 'pie'; 38 | this.state = { 39 | chartInfo: [], 40 | pieChartData: [], 41 | random: 0, 42 | }; 43 | 44 | this.sortDataBasedOnConfig = this.sortDataBasedOnConfig.bind(this); 45 | } 46 | 47 | handleMouseEvent(props) { 48 | const { onClick } = this.props; 49 | 50 | const data = {}; 51 | data[props.datum.x] = props.datum.y; 52 | 53 | return onClick && onClick(data); 54 | } 55 | 56 | sortDataBasedOnConfig(props) { 57 | const { config, metadata, data } = props; 58 | let { chartInfo, pieChartData, random } = this.state; 59 | random++; 60 | // generate chart array from the config. 61 | if (chartInfo.length === 0) { 62 | chartInfo = BaseChart.generateChartArray(config.charts); 63 | } 64 | 65 | let dataSet = {}; 66 | 67 | chartInfo.forEach((chart) => { 68 | this.chartMode = chart.mode || this.chartMode; 69 | const xIndex = _.indexOf(metadata.names, chart.x); 70 | if (xIndex > -1) { 71 | if (!config.percentage) { 72 | const catIndex = _.indexOf(metadata.names, chart.colorCategoryName); 73 | 74 | if (catIndex > -1) { 75 | dataSet = _.groupBy(data.map( 76 | datum => ({ x: datum[xIndex], color: datum[catIndex] })), d => d.color); 77 | _.keys(dataSet).forEach((key) => { 78 | const datIndex = _.findIndex(pieChartData, d => d.x === key); 79 | if (datIndex > -1) { 80 | pieChartData[datIndex].y += _.sumBy(dataSet[key], d => d.x); 81 | } else { 82 | if (chart.colorIndex >= chart.colorScale.length) { 83 | chart.colorIndex = 0; 84 | } 85 | let color = chart.colorScale[chart.colorIndex++]; 86 | if (chart.colorDomain.length > 0) { 87 | const colorDomIn = _.indexOf(chart.colorDomain, key); 88 | if (colorDomIn > -1 && colorDomIn < chart.colorScale.length) { 89 | color = chart.colorScale[colorDomIn]; 90 | } 91 | } 92 | pieChartData.push({ 93 | x: key, 94 | y: _.sumBy(dataSet[key], d => d.x), 95 | fill: color, 96 | symbol: { fill: color }, 97 | }); 98 | } 99 | }); 100 | } else { 101 | throw new VizGError('ArcChart', 102 | 'color category of the chart not found among the metadata provided'); 103 | } 104 | } else { 105 | pieChartData = [ 106 | { y: data[data.length - 1][xIndex], fill: chart.colorScale[0] }, 107 | { y: (100 - data[data.length - 1][xIndex]), fill: chart.colorScale[1] }, 108 | ]; 109 | } 110 | } else { 111 | throw new VizGError('ArcChart', 112 | "'x' defined in the chart configuration not found among the metadata provided"); 113 | } 114 | }); 115 | 116 | this.setState({ chartInfo, pieChartData, random }); 117 | } 118 | 119 | componentWillReceiveProps(nextProps) { 120 | const { config } = nextProps; 121 | 122 | if (!this.chartConfig || !_.isEqual(this.chartConfig, config) || !this.chartConfig.append) { 123 | this.state.chartInfo = []; 124 | this.state.pieChartData = []; 125 | this.chartConfig = config; 126 | } 127 | 128 | this.sortDataBasedOnConfig(nextProps); 129 | } 130 | 131 | render() { 132 | const { config, theme, height, width } = this.props; 133 | const { pieChartData, random } = this.state; 134 | const currentTheme = theme === 'light' ? lightTheme : darkTheme; 135 | 136 | return ( 137 | 147 | : 155 | 166 | } 167 | innerRadius={ 168 | this.chartMode === 'donut' || config.percentage ? 169 | (height > width ? width : height / 4) + (config.innerRadius || 170 | currentTheme.pie.style.data.innerRadius) : currentTheme.pie.style.data.innerRadius 171 | } 172 | startAngle={ 173 | config.startAngle ? 174 | config.startAngle : 0 175 | } 176 | endAngle={ 177 | config.endAngle ? 178 | config.endAngle : 360 179 | } 180 | labels={ 181 | config.percentage === true ? 182 | '' : 183 | d => `${d.x} : ${((d.y / (_.sumBy(pieChartData, o => o.y))) * 100).toFixed(2)}%` 184 | } 185 | style={{ labels: { fontSize: 6 }, data: { strokeWidth: 0 } }} 186 | labelRadius={height / 3} 187 | events={[{ 188 | target: 'data', 189 | eventHandlers: { 190 | onClick: () => { 191 | return [{ target: 'data', mutation: this.handleMouseEvent }]; 192 | }, 193 | }, 194 | }]} 195 | animate={config.animate ? { onEnter: { duration: 100 } } : null} 196 | /> 197 | { 198 | config.percentage ? 199 | 0 ? pieChartData[0].y : 0)}%`} 204 | style={{ 205 | fontSize: config.labelFontSize || currentTheme.pie.style.presentage.fontSize, 206 | fill: config.labelColor || currentTheme.pie.style.labels.fill, 207 | }} 208 | /> : 209 | ({ name: data.x, symbol: data.symbol }))} 213 | interaction={() => { }} 214 | config={config} 215 | /> 216 | } 217 | 218 | ); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/components/ScatterPlot.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { VictoryScatter, VictoryTooltip } from 'victory'; 21 | import _ from 'lodash'; 22 | import { scaleLinear } from 'd3'; 23 | import BaseChart from './BaseChart'; 24 | import VizGError from '../VizGError'; 25 | import ChartContainer from './ChartContainer'; 26 | import LegendComponent from './LegendComponent'; 27 | import lightTheme from './resources/themes/victoryLightTheme'; 28 | import darkTheme from './resources/themes/victoryDarkTheme'; 29 | 30 | /** 31 | * Class to handle visualization of scatter plots. 32 | */ 33 | export default class ScatterPlot extends BaseChart { 34 | constructor(props) { 35 | super(props); 36 | this.state = { 37 | dataSets: {}, 38 | chartArray: [], 39 | xScale: 'linear', 40 | }; 41 | 42 | this.sortDataBasedOnConfig = this.sortDataBasedOnConfig.bind(this); 43 | this.handleMouseClickEvent = this.handleMouseClickEvent.bind(this); 44 | } 45 | 46 | sortDataBasedOnConfig(props) { 47 | const { config, data, metadata } = props; 48 | let { dataSets, chartArray, xScale } = this.state; 49 | 50 | if (chartArray.length === 0) chartArray = BaseChart.generateChartArray(config.charts); 51 | 52 | chartArray.forEach((chart, i) => { 53 | const xIndex = _.indexOf(metadata.names, chart.x); 54 | const yIndex = _.indexOf(metadata.names, chart.y); 55 | const sizeIndex = _.indexOf(metadata.names, chart.size); 56 | const colorIndex = _.indexOf(metadata.names, chart.colorCategoryName); 57 | 58 | xScale = BaseChart.getXScale(metadata.types[xIndex]); 59 | if (xIndex === -1) throw new VizGError('ScatterPlot', `x axis name '${chart.x}' is not found among metadata.`); 60 | if (yIndex === -1) throw new VizGError('ScatterPlot', `y axis name '${chart.y}' is not found among metadata.`); 61 | if (chart.colorCategoryName && colorIndex === -1) throw new VizGError('ScatterPlot', `color dimension name '${chart.colorCategoryName}' is not found among metadata.`); 62 | if (chart.size && sizeIndex === -1) throw new VizGError('ScatterPlot', `Size dimension name '${chart.size}' not found among metadata`); 63 | 64 | if (chart.colorCategoryName && metadata.types[colorIndex] === 'ordinal') { 65 | const dataSet = _.groupBy(data.map( 66 | datum => ({ x: datum[xIndex], y: datum[yIndex], color: datum[colorIndex], amount: datum[sizeIndex] })), d => d.color); 67 | 68 | _.difference(_.keys(dataSet), _.keys(chart.dataSetNames)).forEach((key) => { 69 | const colorDomIn = _.indexOf(chart.colorDomain, key); 70 | if (chart.colorIndex >= chart.colorScale.length) { 71 | chart.colorIndex = 0; 72 | } 73 | if (colorDomIn < 0) { 74 | chart.dataSetNames[key] = chart.colorScale[chart.colorIndex++]; 75 | } else if (colorDomIn > chart.colorScale.length) { 76 | chart.dataSetNames[key] = chart.colorScale[0]; 77 | } else { 78 | chart.dataSetNames[key] = chart.colorScale[colorDomIn]; 79 | } 80 | }); 81 | 82 | _.mergeWith(dataSets, dataSet, (objValue, srcValue) => { 83 | if (_.isArray(objValue)) { 84 | return objValue.concat(srcValue); 85 | } 86 | }); 87 | } else { 88 | chart.dataSetNames[chart.y] = chart.colorScale[0]; 89 | dataSets[chart.y] = dataSets[chart.y] || []; 90 | dataSets[chart.y] 91 | .push(...(data.map(datum => ({ 92 | x: datum[xIndex], 93 | y: datum[yIndex], 94 | color: datum[colorIndex], 95 | amount: datum[sizeIndex], 96 | chartIndex: i, 97 | })))); 98 | } 99 | if (config.charts[chart.id].maxLength) { 100 | const maxLength = config.charts[chart.id].maxLength; 101 | _.keys(chart.dataSetNames).forEach((key) => { 102 | const lengthDiff = dataSets[key].length - maxLength; 103 | dataSets[key].splice(0, lengthDiff); 104 | }); 105 | } 106 | }); 107 | 108 | this.setState({ chartArray, dataSets, xScale }); 109 | } 110 | 111 | handleMouseClickEvent(props) { 112 | const { onClick } = this.props; 113 | 114 | const chartInfo = this.state.chartArray[props.datum.chartIndex]; 115 | 116 | const data = {}; 117 | 118 | data[chartInfo.x] = props.datum.x; 119 | data[chartInfo.y] = props.datum.y; 120 | data.colorCategory = props.datum.color; 121 | data.size = props.datum.amount; 122 | 123 | return onClick && onClick(data); 124 | } 125 | 126 | render() { 127 | const { config, metadata, theme, width, height } = this.props; 128 | const { chartArray, dataSets, xScale } = this.state; 129 | const chartComponents = []; 130 | const legendComponents = []; 131 | const currentTheme = theme === 'light' ? lightTheme : darkTheme; 132 | 133 | chartArray.map((chart) => { 134 | const colorIndex = _.indexOf(metadata.names, chart.colorCategoryName); 135 | 136 | _.keys(chart.dataSetNames).forEach((key) => { 137 | legendComponents.push({ name: key, symbol: { fill: chart.dataSetNames[key] } }); 138 | chartComponents.push(( 139 | { 148 | if (colorIndex > -1 && metadata.types[colorIndex] === 'linear') { 149 | return (d) => { 150 | return scaleLinear() 151 | .range([chart.colorScale[0], chart.colorScale[1]]) 152 | .domain([ 153 | _.min(dataSets[key].map(obj => obj.color)), 154 | _.max(dataSets[key].map(obj => obj.color))])(d.color); 155 | }; 156 | } else if (colorIndex > -1) { 157 | return chart.dataSetNames[key]; 158 | } else { 159 | return null; 160 | } 161 | })(), 162 | }, 163 | }} 164 | labels={ 165 | (d) => { 166 | let text = `${config.charts[chart.id].x} : ${d.x}\n` + 167 | `${config.charts[chart.id].y} : ${d.y}\n`; 168 | if (config.charts[chart.id].size) { 169 | text += `${config.charts[chart.id].size} : ${d.amount}\n`; 170 | } 171 | 172 | if (config.charts[chart.id].color) { 173 | text += `${config.charts[chart.id].color} : ${d.color}`; 174 | } 175 | 176 | return text; 177 | } 178 | } 179 | labelComponent={ 180 | 191 | } 192 | events={[{ 193 | target: 'data', 194 | eventHandlers: { 195 | onClick: () => { 196 | return [{ target: 'data', mutation: this.handleMouseClickEvent }]; 197 | }, 198 | }, 199 | }]} 200 | animate={config.animate ? { onEnter: { duration: 100 } } : null} 201 | /> 202 | )); 203 | }); 204 | }); 205 | 206 | return ( 207 | 218 | {chartComponents} 219 | { 220 | config.legend ? 221 | { }} 226 | config={config} 227 | /> : null 228 | } 229 | 230 | ); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/components/AreaChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { VictoryArea, VictoryStack, VictoryTooltip, VictoryScatter, VictoryGroup } from 'victory'; 21 | import { timeFormat } from 'd3'; 22 | import _ from 'lodash'; 23 | import BaseChart from './BaseChart'; 24 | import ChartContainer from './ChartContainer'; 25 | import LegendComponent from './LegendComponent'; 26 | import darkTheme from './resources/themes/victoryDarkTheme'; 27 | import lightTheme from './resources/themes/victoryLightTheme'; 28 | 29 | /** 30 | * Class to handle visualization of Area Charts. 31 | */ 32 | export default class AreaChart extends BaseChart { 33 | 34 | constructor(props) { 35 | super(props); 36 | this.handleMouseEvent = this.handleMouseEvent.bind(this); 37 | this.handleLegendInteraction = this.handleLegendInteraction.bind(this); 38 | } 39 | 40 | /** 41 | * Generate the chart components in the case where there's only Area charts defined in the chart config. 42 | * @param {Array} chartArray - Array containing objects that has the information to visualize each area chart. 43 | * @param {String} xScale - xAxis scale to be used in the charts. 44 | * @param {Object} dataSets - object containing arrays of data after classification. 45 | * @param {Object} config - object containing user provided chart configuration 46 | * @param {Function} onClick - function to be executed on click event 47 | * @param {Array} ignoreArray - array that contains dataSets to be ignored in rendering the components. 48 | * @returns {{chartComponents: Array, legendComponents: Array}} 49 | */ 50 | static getAreaChartComponent(chartArray, xScale, dataSets, config, onClick, ignoreArray, currentTheme) { 51 | const chartComponents = []; 52 | const legendComponents = []; 53 | 54 | chartArray.forEach((chart, chartIndex) => { 55 | const localChartComp = []; 56 | _.keys(chart.dataSetNames).forEach((dsName) => { 57 | legendComponents.push({ 58 | name: dsName, 59 | symbol: { fill: _.indexOf(ignoreArray, dsName) > -1 ? '#d3d3d3' : chart.dataSetNames[dsName] }, 60 | chartIndex, 61 | }); 62 | if (_.indexOf(ignoreArray, dsName) === -1) { 63 | localChartComp.push( 64 | AreaChart 65 | .getComponent(config, chartIndex, xScale, dataSets[dsName], 66 | chart.dataSetNames[dsName], onClick, currentTheme)); 67 | } 68 | }); 69 | 70 | if (chart.mode === 'stacked') { 71 | chartComponents.push(( 72 | 73 | {localChartComp} 74 | 75 | )); 76 | } else { 77 | chartComponents.push(...localChartComp); 78 | } 79 | }); 80 | return { chartComponents, legendComponents }; 81 | } 82 | 83 | /** 84 | * Generate a single Area chart component to be visualized. 85 | * @param {Object} config - Chart configuration provided by the user. 86 | * @param {Number} chartIndex - Index of the chart definition in the chart Array. 87 | * @param {String} xScale - Scale to be used in the xAxis when plotting the chart. 88 | * @param {Array} data - Array of objects that containing the dataset to be plotted using this chart component. 89 | * @param {String} color - Color the chart should be plotted in. 90 | * @param {Function} onClick - Function to be executed in the case of an click event. 91 | * @returns {Element} 92 | */ 93 | static getComponent(config, chartIndex, xScale, data, color, onClick, currentTheme) { 94 | return ( 95 | 100 | 111 | { 114 | if (xScale === 'time' && config.tipTimeFormat) { 115 | return (d) => { 116 | if (Number(d.y) == Number(d.y).toFixed(2)) { 117 | return `${config.x} : ${timeFormat(config.tipTimeFormat)(new Date(d.x))}\n` + 118 | `${config.charts[chartIndex].y} : ${Number(d.y)}`; 119 | } 120 | else { 121 | return `${config.x} : ${timeFormat(config.tipTimeFormat)(new Date(d.x))}\n` + 122 | `${config.charts[chartIndex].y} : ${Number(d.y).toFixed(2)}`; 123 | } 124 | }; 125 | } else { 126 | return (d) => { 127 | if (isNaN(d.x)) { 128 | if (Number(d.y) == Number(d.y).toFixed(2)) { 129 | return `${config.x} : ${d.x}\n${config.charts[chartIndex].y} : ${Number(d.y)}`; 130 | } else { 131 | return `${config.x} : ${d.x}\n${config.charts[chartIndex].y} : ${Number(d.y) 132 | .toFixed(2)}`; 133 | } 134 | } else { 135 | if (Number(d.y) == Number(d.y).toFixed(2) && Number(d.x) == Number(d.x).toFixed(2)) { 136 | return `${config.x} : ${Number(d.x)}\n` + 137 | `${config.charts[chartIndex].y} : ${Number(d.y)}`; 138 | } else if (Number(d.y) == Number(d.y).toFixed(2)) { 139 | return `${config.x} : ${Number(d.x).toFixed(2)}\n` + 140 | `${config.charts[chartIndex].y} : ${Number(d.y)}`; 141 | } else if (Number(d.x) == Number(d.x).toFixed(2)) { 142 | return `${config.x} : ${Number(d.x)}\n` + 143 | `${config.charts[chartIndex].y} : ${Number(d.y).toFixed(2)}`; 144 | } else { 145 | return `${config.x} : ${Number(d.x).toFixed(2)}\n` + 146 | `${config.charts[chartIndex].y} : ${Number(d.y).toFixed(2)}`; 147 | } 148 | } 149 | }; 150 | } 151 | })() 152 | } 153 | labelComponent={ 154 | 164 | } 165 | size={( 166 | config.charts[chartIndex].style ? 167 | config.charts[chartIndex].style.markRadius || currentTheme.area.style.data.markRadius : 168 | currentTheme.area.style.data.markRadius 169 | )} 170 | animate={config.animate ? { onEnter: { duration: 50 } } : null} 171 | events={[{ 172 | target: 'data', 173 | eventHandlers: { 174 | onClick: () => { 175 | return [{ target: 'data', mutation: onClick }]; 176 | }, 177 | }, 178 | }]} 179 | /> 180 | 181 | ); 182 | } 183 | 184 | render() { 185 | const { config, height, width, yDomain, theme } = this.props; 186 | const { chartArray, dataSets, xScale, ignoreArray } = this.state; 187 | const currentTheme = theme === 'light' ? lightTheme : darkTheme; 188 | 189 | const { chartComponents, legendComponents } = 190 | AreaChart.getAreaChartComponent(chartArray, xScale, dataSets, config, this.handleMouseEvent, ignoreArray, 191 | currentTheme); 192 | 193 | return ( 194 | 202 | { 203 | config.legend === true ? 204 | : null 211 | 212 | } 213 | {chartComponents} 214 | 215 | ); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /samples/chart-docs/GeographicalChartsSample.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React, { Component } from 'react'; 20 | import { Grid } from 'material-ui'; 21 | import VizG from '../../src/VizG'; 22 | import ChartWrapper from '../ChartWrapper'; 23 | import { syntaxHighlight } from './util/SyntaxHighLight'; 24 | import Header from '../components/Header'; 25 | 26 | /** 27 | * This class will render a page that contains samples on how to use Geographical charts. 28 | */ 29 | class MapChartConfigSample extends Component { 30 | 31 | constructor(props) { 32 | super(props); 33 | 34 | this.data = [ 35 | ['Afghanistan', 4.23], 36 | ['EGY', 1.23], 37 | ['Afghanistan', 2.23], 38 | ['United States', 10.23], 39 | ['Albania', 3.23], 40 | ['United Kingdom', 7], 41 | ['Australia', 5], 42 | ['Ireland', 1], 43 | ['RUS', 15], 44 | ]; 45 | this.data2 = [ 46 | ['Alabama', 4.23], 47 | ['Michigan', 1.23], 48 | ['Georgia', 8.23], 49 | ['Texas', 3.23], 50 | ['Hawaii', 2.23], 51 | ]; 52 | 53 | this.lineChartConfig = { 54 | x: 'Country', 55 | charts: [{ type: 'map', y: 'Inflation', mapType: 'world', colorScale: ['#1565C0', '#4DB6AC'] }], 56 | }; 57 | 58 | this.europeConfig = { 59 | type: 'map', 60 | x: 'Country', 61 | charts: [{ type: 'map', y: 'Inflation', mapType: 'europe', colorScale: ['#1565C0', '#4DB6AC'] }], 62 | }; 63 | 64 | this.usaConfig = { 65 | type: 'map', 66 | x: 'Country', 67 | charts: [{ type: 'map', y: 'Inflation', mapType: 'usa', colorScale: ['#1565C0', '#4DB6AC'] }], 68 | }; 69 | 70 | this.metadata = { 71 | names: ['Country', 'Inflation'], 72 | types: ['ordinal', 'linear'], 73 | }; 74 | } 75 | 76 | render() { 77 | return ( 78 |
79 |
80 | 81 | 82 | 83 |
84 | 86 |
87 |
88 |

89 |
 97 |                             
98 |
99 |
100 | 101 | 102 |
103 | 105 |
106 |
107 |

108 |
116 |                             
117 |
118 |
119 | 120 | 121 |
122 | 124 |
125 |
126 |

127 |
135 |                             
136 |
137 |
138 | 139 | 141 |
142 | metadata : 143 |
148 |                                 
149 | data : 150 |
155 |                             
156 |

157 |
158 |
159 | 160 | 161 |
162 |
    163 |
  • type - Type of the chart in this case &qoute;map&qoute;
  • 164 |
  • x - Field containing Geographical data in metadata
  • 165 |
  • 166 | charts - Array of chart objects that needs to be visualized 167 |
      168 |
    • 169 | Chart Object 170 |
        171 |
      • type - type of the chart
      • 172 |
      • y - Data field that needs to be 173 | visualized on the Map.
      • 174 |
      • mapType - Type of the geography 175 | (world | europe | usa)
      • 176 |
      • colorScale - Array of colors in hex 177 | form that will be over-riding the default color set
      • 178 |
      179 |
    • 180 |
    181 |
  • 182 |
  • 183 | style - object containing style attributes of the chart. 184 |
      185 |
    • legendTitleColor - Color of the legend Title 186 | of the chart
    • 187 |
    • legendTextColor - Color of the legend text 188 | of the chart
    • 189 |
    190 |
  • 191 |
  • 192 | chloropethRangeUpperBound - If the range of values is known, user 193 | can define the upper bound of values that will be used for the colorScale of the 194 | chloropeth map as an array. if only upper bound is given library will calculate 195 | the lower bound based on input data. 196 |
  • 197 |
  • 198 | chloropethRangeLowerBound - If the range of values is known, user 199 | can define the lower bound of values that will be used for the colorScale of the 200 | chloropeth map as an array. if only lower bound is given library will calculate 201 | the upper bound based on input data. 202 |
  • 203 |
204 |
205 |
206 |
207 |
208 |
209 | ); 210 | } 211 | } 212 | 213 | export default MapChartConfigSample; 214 | -------------------------------------------------------------------------------- /samples/chart-docs/PieChartSamples.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { Grid } from 'material-ui'; 21 | import VizG from '../../src/VizG'; 22 | import ChartWrapper from '../ChartWrapper'; 23 | import { syntaxHighlight } from './util/SyntaxHighLight'; 24 | import Header from '../components/Header'; 25 | 26 | export default class PieChartSamples extends React.Component { 27 | constructor(props) { 28 | super(props); 29 | this.state = { 30 | data: [[1, 10, 23, 'piston'], [1, 20, 34, 'rotary']], 31 | data2: [[1, 10, 23, 'piston']], 32 | timer: 0, 33 | }; 34 | 35 | this.intervalId = null; 36 | 37 | this.metadata = { 38 | names: ['rpm', 'torque', 'horsepower', 'EngineType', 'weight'], 39 | types: ['linear', 'linear', 'linear', 'ordinal', 'linear'], 40 | }; 41 | 42 | this.donutChartConfig = { 43 | charts: [{ type: 'arc', x: 'torque', color: 'EngineType', mode: 'donut' }], 44 | legendOrientation: 'top', 45 | }; 46 | 47 | this.pieChartConfig = { 48 | charts: [{ type: 'arc', x: 'torque', color: 'EngineType', mode: 'pie' }], 49 | }; 50 | this.semiPieChartConfig = { 51 | charts: [{ type: 'arc', x: 'torque', color: 'EngineType', mode: 'pie' }], 52 | startAngle: -90, 53 | endAngle: 90, 54 | }; 55 | 56 | this.percentChartConfig = { 57 | charts: [{ type: 'arc', x: 'torque', color: 'EngineType', colorScale: ['#4DB6AC', '#E0E0E0'] }], 58 | percentage: true, 59 | width: 300, 60 | height: 300, 61 | }; 62 | } 63 | 64 | componentDidMount() { 65 | this.intervalId = setInterval(() => { 66 | this.setState({ 67 | data: [ 68 | [this.state.timer, this.state.timer === 20 ? null : Math.random() * 100, 10, 'piston'], 69 | [this.state.timer, Math.random() * 100, 10, 'rotary'], 70 | [this.state.timer, this.state.timer === 20 ? null : Math.random() * 100, 10, 'piston2'], 71 | [this.state.timer, Math.random() * 100, 10, 'rotary2'], 72 | ], 73 | data2: [ 74 | 75 | [this.state.timer, Math.random() * 100, Math.random() * 100, 'rotary'], 76 | ], 77 | timer: this.state.timer + 1, 78 | }); 79 | }, 500); 80 | } 81 | 82 | componentWillUnmount() { 83 | clearInterval(this.intervalId); 84 | } 85 | 86 | render() { 87 | return ( 88 |
89 |
90 | 91 | 92 | 93 |
94 | 96 |
97 |
98 |

99 |
107 |                             
108 | 109 |
110 |
111 | 112 | 113 |
114 | 116 |
117 |
118 |

119 |
127 |                             
128 | 129 |
130 |
131 | 132 | 133 |
134 | 136 |
137 |
138 |

139 |
147 |                             
148 | 149 |
150 |
151 | 152 | 153 |
154 | 156 |
157 |
158 |

159 |
167 |                             
168 | 169 |
170 |
171 | 172 | 174 |
175 | metadata : 176 |
184 |                                 data:
185 |                                 
193 |                                 

194 |

JSON structure of Chart Configuration

195 |
    196 |
  • 197 | charts - Array of chart objects that needs to be visualized. 198 |
      199 |
    • type - type of the chart.(&qoute;arc&qoute;)
    • 200 |
    • x - Data field that is used for the visualization
    • 201 |
    • color - Data field by which color 202 | categorization should be done.
    • 203 |
    • colorScale - - Array of colors in hex form 204 | that will be over-riding the default color set
    • 205 |
    • mode - Type of the chart ('donut' | 'pie')
    • 206 |
    207 |
  • 208 |
  • append - Append dataset to the current dataset
  • 209 |
  • legendOrientation - Orientation of the legend relative to 210 | the chart.
  • 211 |
  • percentage - Show the data field as a Gauge and the Value 212 | as a percent
  • 213 |
  • 214 | style - Object containing style attributes related to the chart 215 |
      216 |
    • legendTextColor - Text color of the 217 | legend component
    • 218 |
    219 |
  • 220 |
  • labelColor - Font color of percent chart
  • 221 |
222 |
223 |
224 |
225 | 226 | 227 |
228 | ); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /samples/chart-docs/ScatterPlotSample.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import { Grid } from 'material-ui'; 21 | import ChartWrapper from '../ChartWrapper'; 22 | import VizG from '../../src/VizG'; 23 | import { syntaxHighlight } from './util/SyntaxHighLight'; 24 | import Header from '../components/Header'; 25 | 26 | /** 27 | * This class will render a page that contains samples on how to use Scatter plots. 28 | */ 29 | export default class ScatterChartConfigSample extends React.Component { 30 | 31 | constructor(props) { 32 | super(props); 33 | this.state = { 34 | scatterPlot: [ 35 | [1, 4, 3.5, 79.91, 0.8, 0.03, 'piston'], 36 | [2, 3, 3.5, 79.65, 1.3, 0.06, 'rotary']], 37 | timer: 0, 38 | }; 39 | 40 | this.interval_id = null; 41 | 42 | this.metadata = { 43 | names: ['rpm', 'torque', 'horsepower', 'weight', 'EngineType'], 44 | types: ['linear', 'linear', 'linear', 'linear', 'ordinal'], 45 | }; 46 | 47 | this.scatterPlotConfig = { 48 | type: 'scatter', 49 | charts: [ 50 | { 51 | type: 'scatter', 52 | x: 'rpm', 53 | y: 'torque', 54 | color: 'horsepower', 55 | size: 'weight', 56 | maxLength: 30, 57 | colorScale: ['#1f77b4', '#ebff3b'], 58 | 59 | }], 60 | width: 800, 61 | height: 450, 62 | }; 63 | } 64 | 65 | componentDidMount() { 66 | this.interval_id = setInterval(() => { 67 | this.setState({ 68 | scatterPlot: [[this.state.timer, Math.random() * 100, Math.random() * 10, Math.random() * 100, 'piston'], 69 | [this.state.timer, Math.random() * 100, Math.random() * 10, Math.random() * 100, 'rotary']], 70 | timer: this.state.timer + 1, 71 | }); 72 | }, 500); 73 | } 74 | 75 | componentWillUnmount() { 76 | clearInterval(this.interval_id); 77 | } 78 | 79 | render() { 80 | return ( 81 |
82 |
83 | 84 | 85 | 86 |
87 | 89 |
90 |
91 |

92 |
100 |                             
101 |
102 |
103 | 104 | 106 |
107 | metadata : 108 |
113 |                                 
114 | data : 115 |
120 |                                 

121 |

Chart JSON Structure

122 |
    123 |
  • 124 | type - Type of the Chart in this case "scatter" 125 |
  • 126 |
  • 127 | charts - Array of chart objects to be visualized. 128 |
      129 |
    • 130 | Chart Object 131 |
        132 |
      • 133 | x - Data field representing x-axis 134 | in the metadata 135 |
      • 136 |
      • 137 | y - Data field representing y-axis 138 | in the metadata 139 |
      • 140 |
      • 141 | color - Data field representing color 142 | categorization data field of the metadata 143 |
      • 144 |
      • 145 | size - Data field representing size 146 | categorization data field of the metadata 147 |
      • 148 |
      • 149 | colorScale - Array of colors in hex 150 | form that will be over-riding the default color set 151 |
      • 152 |
      • 153 | colorDomain - If a certain color 154 | category needs to be plotted in a specific color. 155 |
      • 156 |
      157 |
    • 158 |
    • ....
    • 159 |
    160 |
  • 161 |
  • 162 | maxLength - Max length of data points to be 163 | visualized in the chart at time 164 |
  • 165 |
  • 166 | legend - enable or disable legend (boolean) value. 167 |
  • 168 |
  • 169 | Append - Append the incoming data to the existing dataset or 170 | replace the existing dataset boolean value. 171 |
  • 172 |
  • 173 | timeFormat - If the x-axis is a time series using this attribute 174 | user can format the tick values of the x axis using regex. refer  175 | 176 | d3 documentation 177 | for more info 178 |
  • 179 |
  • 180 | tipTimeFormat - If the x-axis is a time series using this 181 | attribute user can format the tick values of the x axis using regex. refer  182 | 183 | d3 documentation 184 | for more info 185 |
  • 186 |
  • animate - animate chart visualizations
  • 187 |
  • disableVerticleGrid - Disable verticle grid of the chart 188 | (boolean value)
  • 189 |
  • disableHorizontalGrid - Disable horizontal grid of the chart 190 | (boolean value)
  • 191 |
  • yAxisLabel - Change the label shown along the y-axis
  • 192 |
  • xAxisLabel - Change the label shown along the x-axis
  • 193 |
  • yAxisTickCount - Number of ticks shown in the y-axis
  • 194 |
  • xAxisTickCount - Number of ticks shown in the x-axis
  • 195 |
  • legendOrientaion - Orientaion of the legend relative 196 | to the chart (top | bottom | left | right)
  • 197 |
  • 198 | style - object that contain style attributes of the charts. 199 |
      200 |
    • axisColor - color of the axis lines
    • 201 |
    • axisLabelColor - color of the axis labels
    • 202 |
    • xAxisTickAngle - Tick angle of the x-axis ticks
    • 203 |
    • yAxisTickAngle - Tick angle of the y-axis ticks
    • 204 |
    • tickLabelColor - font color of the tickLabels
    • 205 |
    206 |
  • 207 |
208 |
209 |
210 |
211 | 212 | 213 |
214 | ); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/components/BaseChart.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import React from 'react'; 20 | import _ from 'lodash'; 21 | import PropTypes from 'prop-types'; 22 | import VizGError from '../VizGError'; 23 | import { getDefaultColorScale } from './helper'; 24 | 25 | /** 26 | * Base Chart that contain most common methods that requires for the charts. 27 | */ 28 | export default class BaseChart extends React.Component { 29 | /** 30 | * returns which x scale to be used for the current chart based on the metadata type. 31 | * @param {String} type - type defined in the metadata one of values 'linear', 'ordinal', or 'time' 32 | * @returns {string} type of the xScale that should be used in the chart. 33 | */ 34 | static getXScale(type) { 35 | if (type.toLowerCase() === 'linear' || type.toLowerCase() === 'ordinal') return 'linear'; 36 | else return 'time'; 37 | } 38 | 39 | /** 40 | * returns a dataSet object that contains arrays not longer than maxLength provided 41 | * @param {Object} dataSets 42 | * @param {number} maxLength 43 | * @returns {*} 44 | */ 45 | static trimDataSet(dataSets, maxLength) { 46 | _.keys(_.pickBy(dataSets, obj => obj.length > maxLength)).forEach((key) => { 47 | const lengthDiff = dataSets[key].length - maxLength; 48 | dataSets[key].splice(0, lengthDiff); 49 | }); 50 | 51 | return dataSets; 52 | } 53 | 54 | /** 55 | * Generates an array of objects containing chart information that needed to be plotted. 56 | * @param {Array} charts - Charts array provided in the config. 57 | * @returns {Array} - Array of objects containing chart information that needed to be plotted 58 | */ 59 | static generateChartArray(charts) { 60 | return charts.map((chart, chartIndex) => { 61 | return { 62 | type: chart.type, 63 | dataSetNames: {}, 64 | mode: chart.mode, 65 | orientation: chart.orientation || 'bottom', 66 | color: Object.prototype.hasOwnProperty.call(chart, 'color'), 67 | colorCategoryName: chart.color || '', 68 | colorScale: Array.isArray(chart.colorScale) ? chart.colorScale : getDefaultColorScale(), 69 | colorDomain: chart.colorDomain || [], 70 | colorIndex: chartIndex, 71 | id: chartIndex, 72 | y: chart.y, 73 | x: chart.x, 74 | size: chart.size, 75 | }; 76 | }); 77 | } 78 | 79 | constructor(props) { 80 | super(props); 81 | this.state = { 82 | chartArray: [], 83 | dataSets: {}, 84 | xScale: 'linear', 85 | ignoreArray: [], 86 | isOrdinal: false, 87 | stacked: false, 88 | xAxisRange: [null, null], 89 | xAxisType: 'linear', 90 | }; 91 | 92 | this.chartConfig = this.props.config; 93 | 94 | this.sortDataBasedOnConfig = this.sortDataBasedOnConfig.bind(this); 95 | } 96 | 97 | componentDidMount() { 98 | this.sortDataBasedOnConfig(this.props); 99 | } 100 | 101 | componentWillReceiveProps(nextProps) { 102 | const { config } = nextProps; 103 | 104 | if (!this.chartConfig || !(_.isEqual(config, this.chartConfig)) || !this.props.append) { 105 | this.state.chartArray = []; 106 | this.state.dataSets = {}; 107 | this.chartConfig = config; 108 | } 109 | 110 | this.sortDataBasedOnConfig(nextProps); 111 | } 112 | 113 | /** 114 | * Event handler for mouse events 115 | * @param evt - event associated with the interaction. 116 | * @returns {*} 117 | */ 118 | handleMouseEvent(props) { 119 | const { onClick } = this.props; 120 | const data = {}; 121 | 122 | data[this.chartConfig.x] = props.datum.x; 123 | data[props.datum.yName] = props.datum.y; 124 | data.colorCategory = props.datum.color; 125 | 126 | return onClick && onClick(data); 127 | } 128 | 129 | /** 130 | * Event handler for onClick events of names shown in the legend. 131 | * @param props 132 | */ 133 | handleLegendInteraction(props) { 134 | const { ignoreArray } = this.state; 135 | 136 | const ignoreIndex = _.indexOf(ignoreArray, props.datum.name); 137 | if (ignoreIndex < 0) { 138 | ignoreArray.push(props.datum.name); 139 | } else { 140 | ignoreArray.splice(ignoreIndex, 1); 141 | } 142 | 143 | this.state.ignoreArray = ignoreArray; 144 | 145 | this.forceUpdate(); 146 | } 147 | 148 | /** 149 | * Sort and set the state with data received from props. 150 | * @param props - props received by the component. 151 | */ 152 | sortDataBasedOnConfig(props) { 153 | const { config, metadata, data } = props; 154 | let { chartArray, dataSets, xScale, isOrdinal, xAxisType } = this.state; 155 | // generate chart array from the config. 156 | if (chartArray.length === 0) chartArray = BaseChart.generateChartArray(config.charts); 157 | 158 | const xIndex = metadata.names.indexOf(config.x); 159 | if (_.keys(dataSets).length === 0) { 160 | if (!isOrdinal) isOrdinal = metadata.types[xIndex].toLowerCase() === 'ordinal'; 161 | xScale = BaseChart.getXScale(metadata.types[xIndex]); 162 | xAxisType = metadata.types[xIndex]; 163 | } 164 | if (xScale !== BaseChart.getXScale(metadata.types[xIndex])) { 165 | throw VizGError('BasicChart', "Provided metadata doesn't match the previous metadata."); 166 | } 167 | 168 | let dataSet = {}; 169 | 170 | chartArray.forEach((chart) => { 171 | const yIndex = metadata.names.indexOf(chart.y); 172 | const colorIndex = metadata.names.indexOf(chart.colorCategoryName); 173 | 174 | if (xIndex < 0 || yIndex < 0) { 175 | throw new VizGError('BasicChart', 'Axis name not found in metadata'); 176 | } 177 | 178 | if (chart.color) { 179 | if (colorIndex < 0) { 180 | throw new VizGError('BasicChart', 'Color category not found in metadata.'); 181 | } 182 | dataSet = _.groupBy(data.map( 183 | datum => ({ 184 | x: datum[xIndex] instanceof Date ? datum[xIndex].getTime() : datum[xIndex], 185 | y: datum[yIndex], 186 | color: datum[colorIndex], 187 | yName: metadata.names[yIndex], 188 | })), d => d.color); 189 | 190 | _.difference(_.keys(dataSet), _.keys(chart.dataSetNames)).forEach((key) => { 191 | const colorDomIn = _.indexOf(chart.colorDomain, key); 192 | if (chart.colorIndex >= chart.colorScale.length) { 193 | chart.colorIndex = 0; 194 | } 195 | if (colorDomIn < 0) { 196 | chart.dataSetNames[key] = chart.colorScale[chart.colorIndex++]; 197 | } else if (colorDomIn > chart.colorScale.length) { 198 | chart.dataSetNames[key] = chart.colorScale[0]; 199 | } else { 200 | chart.dataSetNames[key] = chart.colorScale[colorDomIn]; 201 | } 202 | }); 203 | } else { 204 | dataSet[chart.y] = data.map(datum => ({ x: datum[xIndex], y: datum[yIndex], yName: chart.y })); 205 | chart.dataSetNames[chart.y] = config.charts[chart.id].fill || chart.colorScale[chart.colorIndex]; 206 | } 207 | }); 208 | 209 | this.setState((prevState) => { 210 | prevState.chartArray.push(...(_.differenceWith(chartArray, prevState.chartArray, _.isEqual))); 211 | if (!isOrdinal) { 212 | _.mergeWith(prevState.dataSets, dataSet, (objValue, srcValue) => { 213 | if (_.isArray(objValue)) { 214 | return objValue.concat(srcValue); 215 | } 216 | }); 217 | } else { 218 | _.keys(dataSet).forEach((key) => { 219 | prevState.dataSets[key] = prevState.dataSets[key] || []; 220 | dataSet[key].forEach((datum) => { 221 | const objIndex = _.findIndex(prevState.dataSets[key], obj => obj.x === datum.x); 222 | if (objIndex > -1) { 223 | prevState.dataSets[key][objIndex].y = datum.y; 224 | } else { 225 | prevState.dataSets[key].push(datum); 226 | } 227 | }); 228 | }); 229 | } 230 | 231 | _.keys(prevState.dataSets).forEach(key => _.sortBy(prevState.dataSets[key], o => o.x)); 232 | if (config.maxLength) BaseChart.trimDataSet(prevState.dataSets, config.maxLength); 233 | prevState.isOrdinal = isOrdinal; 234 | prevState.xScale = xScale; 235 | 236 | 237 | if (!isOrdinal) { 238 | let range = [null, null]; 239 | 240 | Object.keys(prevState.dataSets).forEach((key) => { 241 | let dataSetRange = []; 242 | dataSetRange[0] = _.minBy(prevState.dataSets[key], 'x'); 243 | dataSetRange[1] = _.maxBy(prevState.dataSets[key], 'x'); 244 | 245 | if (dataSetRange[0]) { 246 | dataSetRange[0] = dataSetRange[0].x; 247 | } 248 | if (dataSetRange[1]) { 249 | dataSetRange[1] = dataSetRange[1].x; 250 | } 251 | if (!range[0]) { 252 | range = dataSetRange; 253 | } else { 254 | if (dataSetRange[0] < range[0]) { 255 | range[0] = dataSetRange[0]; 256 | } 257 | 258 | if (dataSetRange[1] > range[1]) { 259 | range[1] = dataSetRange[1]; 260 | } 261 | } 262 | }); 263 | 264 | prevState.xAxisRange = range; 265 | } 266 | 267 | prevState.xAxisType = xAxisType; 268 | 269 | return prevState; 270 | }); 271 | } 272 | 273 | render() { 274 | return ( 275 |
276 | ); 277 | } 278 | } 279 | 280 | BaseChart.defaultProps = { 281 | width: 800, 282 | height: 400, 283 | onClick: null, 284 | yDomain: null, 285 | append: true, 286 | }; 287 | 288 | BaseChart.propTypes = { 289 | width: PropTypes.number, 290 | height: PropTypes.number, 291 | onClick: PropTypes.func, 292 | config: PropTypes.shape({ 293 | x: PropTypes.string, 294 | charts: PropTypes.arrayOf(PropTypes.shape({ 295 | type: PropTypes.string.isRequired, 296 | y: PropTypes.string, 297 | fill: PropTypes.string, 298 | color: PropTypes.string, 299 | colorScale: PropTypes.arrayOf(PropTypes.string), 300 | colorDomain: PropTypes.arrayOf(PropTypes.string), 301 | mode: PropTypes.string, 302 | })), 303 | legendOrientation: PropTypes.string, 304 | style: { 305 | tickLabelColor: PropTypes.string, 306 | legendTitleColor: PropTypes.string, 307 | legendTextColor: PropTypes.string, 308 | axisColor: PropTypes.string, 309 | axisLabelColor: PropTypes.string, 310 | gridColor: PropTypes.string, 311 | xAxisTickAngle: PropTypes.number, 312 | yAxisTickAngle: PropTypes.number, 313 | }, 314 | disableVerticalGrid: PropTypes.bool, 315 | disableHorizontalGrid: PropTypes.bool, 316 | xAxisLabel: PropTypes.string, 317 | yAxisLabel: PropTypes.string, 318 | yAxisTickCount: PropTypes.number, 319 | xAxisTickCount: PropTypes.number, 320 | height: PropTypes.number, 321 | width: PropTypes.number, 322 | maxLength: PropTypes.number, 323 | }).isRequired, 324 | yDomain: PropTypes.arrayOf(PropTypes.number), 325 | append: PropTypes.bool, 326 | }; 327 | --------------------------------------------------------------------------------