├── src ├── index.css ├── App.test.js ├── index.js ├── App.css ├── EchartsDemo │ ├── RadarReact.js │ ├── BarReact.js │ ├── PieReact.js │ ├── LineReact.js │ ├── ScatterReact.js │ ├── CandlestickReact.js │ └── MapReact.js ├── AsyncComponent.js ├── App.js ├── logo.svg ├── registerServiceWorker.js └── optionConfig │ └── options.js ├── public ├── favicon.ico ├── manifest.json └── index.html ├── package.json ├── LICENSE ├── .gitignore └── README.md /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-love/react-echarts-modules/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-echarts-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "echarts": "4.1.0", 7 | "react": "16.5.0", 8 | "react-dom": "16.5.0" 9 | }, 10 | "devDependencies": { 11 | "react-scripts": "1.1.5" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/EchartsDemo/RadarReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/chart/radar' //引入雷达图 7 | 8 | export default class RadarReact extends React.Component { 9 | 10 | constructor(props) { 11 | super(props) 12 | this.initPie = this.initPie.bind(this) 13 | } 14 | 15 | initPie() { 16 | const { option={} } = this.props //外部传入的data数据 17 | let myChart = echarts.init(this.ID) //初始化echarts 18 | 19 | //设置options 20 | myChart.setOption(option) 21 | window.onresize = function() { 22 | myChart.resize() 23 | } 24 | } 25 | 26 | componentDidMount() { 27 | this.initPie() 28 | } 29 | 30 | componentDidUpdate() { 31 | this.initPie() 32 | } 33 | 34 | render() { 35 | const { width="100%", height="400px" } = this.props 36 | return
this.ID = ID} style={{width, height}}>
37 | } 38 | } -------------------------------------------------------------------------------- /src/AsyncComponent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | const asyncComponent = loadComponent => ( 6 | class AsyncComponent extends React.Component { 7 | state = { 8 | Component: null, 9 | } 10 | 11 | componentWillMount() { 12 | if (this.hasLoadedComponent()) { 13 | return; 14 | } 15 | 16 | loadComponent() 17 | .then(module => module.default) 18 | .then((Component) => { 19 | this.setState({ Component }); 20 | }) 21 | .catch((err) => { 22 | console.error(`Cannot load component in `); 23 | throw err; 24 | }); 25 | } 26 | 27 | hasLoadedComponent() { 28 | return this.state.Component != null; 29 | } 30 | 31 | render() { 32 | const { Component } = this.state; 33 | return (Component) ? : null; 34 | } 35 | } 36 | ); 37 | 38 | export default asyncComponent 39 | -------------------------------------------------------------------------------- /src/EchartsDemo/BarReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/component/tooltip' 7 | import 'echarts/lib/component/grid' 8 | import 'echarts/lib/chart/bar' 9 | 10 | export default class BarReact extends React.Component { 11 | 12 | constructor(props) { 13 | super(props) 14 | this.initPie = this.initPie.bind(this) 15 | } 16 | 17 | initPie() { 18 | const { option={} } = this.props //外部传入的data数据 19 | let myChart = echarts.init(this.ID) //初始化echarts 20 | 21 | //设置options 22 | myChart.setOption(option) 23 | window.onresize = function() { 24 | myChart.resize() 25 | } 26 | } 27 | 28 | componentDidMount() { 29 | this.initPie() 30 | } 31 | 32 | componentDidUpdate() { 33 | this.initPie() 34 | } 35 | 36 | render() { 37 | const { width="100%", height="200px"} = this.props 38 | return
this.ID = ID} style={{width, height}}>
39 | } 40 | } -------------------------------------------------------------------------------- /src/EchartsDemo/PieReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/component/tooltip' 7 | import 'echarts/lib/component/legend' 8 | import 'echarts/lib/chart/pie' 9 | 10 | export default class PieReact extends React.Component { 11 | 12 | constructor(props) { 13 | super(props) 14 | this.initPie = this.initPie.bind(this) 15 | } 16 | 17 | initPie() { 18 | const { option={} } = this.props //外部传入的data数据 19 | let myChart = echarts.init(this.ID) //初始化echarts 20 | 21 | //设置options 22 | myChart.setOption(option) 23 | window.onresize = function() { 24 | myChart.resize() 25 | } 26 | } 27 | 28 | componentDidMount() { 29 | this.initPie() 30 | } 31 | 32 | componentDidUpdate() { 33 | this.initPie() 34 | } 35 | 36 | render() { 37 | const { width="100%", height = '200px' } = this.props 38 | return
this.ID = ID} style={{width, height}}>
39 | } 40 | } -------------------------------------------------------------------------------- /src/EchartsDemo/LineReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/component/tooltip' 7 | import 'echarts/lib/component/grid' 8 | import 'echarts/lib/chart/line' 9 | 10 | export default class LineReact extends React.Component { 11 | 12 | constructor(props) { 13 | super(props) 14 | this.initPie = this.initPie.bind(this) 15 | } 16 | 17 | initPie() { 18 | const { option={} } = this.props //外部传入的data数据 19 | let myChart = echarts.init(this.ID) //初始化echarts 20 | 21 | //设置options 22 | myChart.setOption(option) 23 | window.onresize = function() { 24 | myChart.resize() 25 | } 26 | } 27 | 28 | componentDidMount() { 29 | this.initPie() 30 | } 31 | 32 | componentDidUpdate() { 33 | this.initPie() 34 | } 35 | 36 | render() { 37 | const { width="100%", height="300px" } = this.props 38 | return
this.ID = ID} style={{width, height}}>
39 | } 40 | } -------------------------------------------------------------------------------- /src/EchartsDemo/ScatterReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/component/tooltip' 7 | import 'echarts/lib/component/legend' 8 | import 'echarts/lib/component/grid' 9 | import 'echarts/lib/chart/scatter' 10 | 11 | export default class ScatterReact extends React.Component { 12 | 13 | constructor(props) { 14 | super(props) 15 | this.initPie = this.initPie.bind(this) 16 | } 17 | 18 | initPie() { 19 | const { option={} } = this.props //外部传入的data数据 20 | let myChart = echarts.init(this.ID) //初始化echarts 21 | 22 | //设置options 23 | myChart.setOption(option) 24 | window.onresize = function() { 25 | myChart.resize() 26 | } 27 | } 28 | 29 | componentDidMount() { 30 | this.initPie() 31 | } 32 | 33 | componentDidUpdate() { 34 | this.initPie() 35 | } 36 | 37 | render() { 38 | const { width="100%", height="200px" } = this.props 39 | return
this.ID = ID} style={{width, height}}>
40 | } 41 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 二月 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .idea 61 | build -------------------------------------------------------------------------------- /src/EchartsDemo/CandlestickReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/chart/candlestick' //引入雷达图 7 | import 'echarts/lib/component/tooltip' 8 | import 'echarts/lib/component/legend' 9 | import 'echarts/lib/component/grid' 10 | import 'echarts/lib/component/markLine' 11 | 12 | export default class CandlestickReact extends React.Component { 13 | 14 | constructor(props) { 15 | super(props) 16 | this.initPie = this.initPie.bind(this) 17 | } 18 | 19 | initPie() { 20 | const { option={} } = this.props //外部传入的data数据 21 | let myChart = echarts.init(this.ID) //初始化echarts 22 | 23 | //设置options 24 | myChart.setOption(option) 25 | window.onresize = function() { 26 | myChart.resize() 27 | } 28 | } 29 | 30 | componentDidMount() { 31 | this.initPie() 32 | } 33 | 34 | componentDidUpdate() { 35 | this.initPie() 36 | } 37 | 38 | render() { 39 | const { width="100%", height="400px" } = this.props 40 | return
this.ID = ID} style={{width, height}}>
41 | } 42 | } -------------------------------------------------------------------------------- /src/EchartsDemo/MapReact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | import React from 'react' 5 | import echarts from 'echarts/lib/echarts' //必须 6 | import 'echarts/lib/component/tooltip' 7 | import 'echarts/lib/component/legend' 8 | import 'echarts/lib/component/geo' 9 | import 'echarts/lib/chart/map' //引入地图 10 | import 'echarts/lib/chart/lines' 11 | import 'echarts/lib/chart/effectScatter' 12 | import 'echarts/map/js/china' // 引入中国地图 13 | 14 | export default class MapReact extends React.Component { 15 | 16 | constructor(props) { 17 | super(props) 18 | this.initPie = this.initPie.bind(this) 19 | } 20 | 21 | initPie() { 22 | const { option={} } = this.props //外部传入的data数据 23 | let myChart = echarts.init(this.ID) //初始化echarts 24 | 25 | //设置options 26 | myChart.setOption(option) 27 | window.onresize = function() { 28 | myChart.resize() 29 | } 30 | } 31 | 32 | componentDidMount() { 33 | this.initPie() 34 | } 35 | 36 | componentDidUpdate() { 37 | this.initPie() 38 | } 39 | 40 | render() { 41 | const { width="100%", height="200px" } = this.props 42 | return
this.ID = ID} style={{width, height}}>
43 | } 44 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import asyncComponent from './AsyncComponent' 3 | import { pieOption, barOption, lineOption, scatterOption, mapOption, radarOption, candlestickOption } from './optionConfig/options' 4 | const PieReact = asyncComponent(() => import(/* webpackChunkName: "Pie" */'./EchartsDemo/PieReact')) //饼图组件 5 | const BarReact = asyncComponent(() => import(/* webpackChunkName: "Bar" */'./EchartsDemo/BarReact')) //柱状图组件 6 | const LineReact = asyncComponent(() => import(/* webpackChunkName: "Line" */'./EchartsDemo/LineReact')) //折线图组件 7 | const ScatterReact = asyncComponent(() => import(/* webpackChunkName: "Scatter" */'./EchartsDemo/ScatterReact')) //散点图组件 8 | const MapReact = asyncComponent(() => import(/* webpackChunkName: "Map" */'./EchartsDemo/MapReact')) //地图组件 9 | const RadarReact = asyncComponent(() => import(/* webpackChunkName: "Radar" */'./EchartsDemo/RadarReact')) //雷达图组件 10 | const CandlestickReact = asyncComponent(() => import(/* webpackChunkName: "Candlestick" */'./EchartsDemo/CandlestickReact')) //k线图组件 11 | 12 | class App extends Component { 13 | render() { 14 | return ( 15 |
16 |

饼图react组件实现

17 | 18 |
19 | 20 |

柱状图react组件实现

21 | 22 |
23 | 24 |

折线图react组件实现

25 | 26 |
27 | 28 |

散点图react组件实现

29 | 30 |
31 | 32 |

地图react组件实现

33 | 34 |
35 | 36 |

雷达图react组件实现

37 | 38 |
39 | 40 |

k线图react组件实现

41 | 42 |
43 |
44 | ); 45 | } 46 | } 47 | 48 | export default App; 49 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### react16.5.0实现echarts4模块化加载 2 | 3 | **我们真的需要react-echarts插件吗?** 4 | 5 | ## NO 6 | 7 | **注意:该项目仅作为源码学习使用,不能采取npm install --save react-echarts-modules的方式导入你的项目,因为这不是一个插件!!** 8 | 9 | **在这里,我使用echarts提供的模块化加载方式,实现了几个react-echarts图表组件** 10 | 11 | **你可以打开控制台,观察每个图表组件的加载情况。** 12 | 13 | #### 插件版本号 14 | 15 | ```json 16 | "echarts": "4.1.0", 17 | "react": "16.5.0", 18 | "react-dom": "16.5.0" 19 | ``` 20 | 21 | #### 实现了哪些图表组件 22 | 23 | 1、饼图 24 | 25 | 2、柱状图 26 | 27 | 3、折线图 28 | 29 | 4、散点图 30 | 31 | 5、地图 32 | 33 | 6、雷达图 34 | 35 | 7、k线图 36 | 37 | 38 | #### echarts体积太大,使用模块化加载 39 | 40 | 以柱状图为例子,我们根据需要渲染的插件采取模块导入,不渲染的组件不导入,最大程度减小js。 41 | 42 | ```javascript 43 | import echarts from 'echarts/lib/echarts' //必须 44 | import 'echarts/lib/component/tooltip' 45 | import 'echarts/lib/component/grid' 46 | import 'echarts/lib/chart/bar' 47 | ``` 48 | 49 | #### 组件化开发的福音,react组件模块化加载 50 | 51 | demo中采用单个echarts组件异步打包加载的模式,因为echarts组件普遍偏大,即使压缩也效果不明显,所以异步加载是最好的方式。 52 | 53 | ```javascript 54 | import { pieOption, barOption, lineOption, scatterOption, mapOption, radarOption, candlestickOption } from './optionConfig/options' 55 | const PieReact = asyncComponent(() => import(/* webpackChunkName: "Pie" */'./EchartsDemo/PieReact')) //饼图组件 56 | const BarReact = asyncComponent(() => import(/* webpackChunkName: "Bar" */'./EchartsDemo/BarReact')) //柱状图组件 57 | const LineReact = asyncComponent(() => import(/* webpackChunkName: "Line" */'./EchartsDemo/LineReact')) //折线图组件 58 | const ScatterReact = asyncComponent(() => import(/* webpackChunkName: "Scatter" */'./EchartsDemo/ScatterReact')) //散点图组件 59 | const MapReact = asyncComponent(() => import(/* webpackChunkName: "Map" */'./EchartsDemo/MapReact')) //地图组件 60 | const RadarReact = asyncComponent(() => import(/* webpackChunkName: "Radar" */'./EchartsDemo/RadarReact')) //雷达图组件 61 | const CandlestickReact = asyncComponent(() => import(/* webpackChunkName: "Candlestick" */'./EchartsDemo/CandlestickReact')) //k线图组件 62 | ``` 63 | 64 | ### 启动项目 65 | 66 | ```npm 67 | npm install 68 | ``` 69 | 70 | ```npm 71 | npm start 72 | ``` 73 | 74 | ### 打包项目 75 | 76 | ```npm 77 | npm run build 78 | ``` 79 | 80 | ### 实现方案介绍 81 | 82 | 1、每个图表单独封装成一个组件,通过参数传递数据,你会发现,图表内部代码几乎完全一样,只有import的类型不同。 83 | 84 | 2、异步加载是提高图表加载性能的最佳方式,不管是服务端还是客户端渲染。 85 | 86 | 3、在这些demo中,我认为对你来说最有价值的是react组件异步加载模式,很多人异步加载组件是通过拆分路由的方式,而非路由组件的异步加载,并不多人去尝试。但我想告诉你的是, 87 | 非路由组件的异步加载会将你的庞大的父组件拆分的更细,体积更小,加载的更加流畅。 88 | 89 | 4、有时候,我会看到有些人把echarts打包到公共js文件里面,如果你的首屏不需要用到它,完全没有必要这样做。 90 | 91 | ### 附echarts各个模块导出路径 92 | 93 | ```javascript 94 | /** 95 | * 导出echarts主模块 96 | */ 97 | module.exports = require('./lib/echarts'); 98 | 99 | // 各子模块路径 100 | require('./lib/chart/line'); 101 | require('./lib/chart/bar'); 102 | require('./lib/chart/pie'); 103 | require('./lib/chart/scatter'); 104 | require('./lib/chart/radar'); 105 | 106 | require('./lib/chart/map'); 107 | require('./lib/chart/treemap'); 108 | require('./lib/chart/graph'); 109 | require('./lib/chart/gauge'); 110 | require('./lib/chart/funnel'); 111 | require('./lib/chart/parallel'); 112 | require('./lib/chart/sankey'); 113 | require('./lib/chart/boxplot'); 114 | require('./lib/chart/candlestick'); 115 | require('./lib/chart/effectScatter'); 116 | require('./lib/chart/lines'); 117 | require('./lib/chart/heatmap'); 118 | require('./lib/chart/pictorialBar'); 119 | require('./lib/chart/themeRiver'); 120 | require('./lib/chart/custom'); 121 | 122 | require('./lib/component/graphic'); 123 | require('./lib/component/grid'); 124 | require('./lib/component/legend'); 125 | require('./lib/component/tooltip'); 126 | require('./lib/component/axisPointer'); 127 | require('./lib/component/polar'); 128 | require('./lib/component/geo'); 129 | require('./lib/component/parallel'); 130 | require('./lib/component/singleAxis'); 131 | require('./lib/component/brush'); 132 | require('./lib/component/calendar'); 133 | 134 | require('./lib/component/title'); 135 | 136 | require('./lib/component/dataZoom'); 137 | require('./lib/component/visualMap'); 138 | 139 | require('./lib/component/markPoint'); 140 | require('./lib/component/markLine'); 141 | require('./lib/component/markArea'); 142 | 143 | require('./lib/component/timeline'); 144 | require('./lib/component/toolbox'); 145 | 146 | require('zrender/lib/vml/vml'); 147 | 148 | ``` 149 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/optionConfig/options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yongyuehuang on 2017/8/5. 3 | */ 4 | //饼图数据 5 | export const pieOption = { 6 | tooltip: { 7 | trigger: 'item', 8 | formatter: "{a}
{b}: {c} ({d}%)" 9 | }, 10 | legend: { 11 | orient: 'vertical', 12 | x: 'left', 13 | data:['直接访问','邮件营销','联盟广告','视频广告','搜索引擎'] 14 | }, 15 | series: [ 16 | { 17 | name:'访问来源', 18 | type:'pie', 19 | radius: ['100%', '70%'], 20 | avoidLabelOverlap: false, 21 | label: { 22 | normal: { 23 | show: false, 24 | position: 'center' 25 | }, 26 | emphasis: { 27 | show: true, 28 | textStyle: { 29 | fontSize: '30', 30 | fontWeight: 'bold' 31 | } 32 | } 33 | }, 34 | labelLine: { 35 | normal: { 36 | show: false 37 | } 38 | }, 39 | data:[ 40 | {value:335, name:'直接访问'}, 41 | {value:310, name:'邮件营销'}, 42 | {value:234, name:'联盟广告'}, 43 | {value:135, name:'视频广告'}, 44 | {value:1548, name:'搜索引擎'} 45 | ] 46 | } 47 | ] 48 | }; 49 | 50 | //柱状图数据 51 | export const barOption = { 52 | color: ['#3398DB'], 53 | tooltip : { 54 | trigger: 'axis', 55 | axisPointer : { // 坐标轴指示器,坐标轴触发有效 56 | type : 'shadow' // 默认为直线,可选为:'line' | 'shadow' 57 | } 58 | }, 59 | grid: { 60 | left: '3%', 61 | right: '4%', 62 | bottom: '3%', 63 | containLabel: true 64 | }, 65 | xAxis : [ 66 | { 67 | type : 'category', 68 | data : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], 69 | axisTick: { 70 | alignWithLabel: true 71 | } 72 | } 73 | ], 74 | yAxis : [ 75 | { 76 | type : 'value' 77 | } 78 | ], 79 | series : [ 80 | { 81 | name:'直接访问', 82 | type:'bar', 83 | barWidth: '60%', 84 | data:[10, 52, 200, 334, 390, 330, 220] 85 | } 86 | ] 87 | }; 88 | 89 | //折线图数据 90 | export const lineOption = { 91 | title: { 92 | text: '堆叠区域图' 93 | }, 94 | tooltip : { 95 | trigger: 'axis', 96 | axisPointer: { 97 | type: 'cross', 98 | label: { 99 | backgroundColor: '#6a7985' 100 | } 101 | } 102 | }, 103 | legend: { 104 | data:['邮件营销','联盟广告','视频广告','直接访问','搜索引擎'] 105 | }, 106 | toolbox: { 107 | feature: { 108 | saveAsImage: {} 109 | } 110 | }, 111 | grid: { 112 | left: '3%', 113 | right: '4%', 114 | bottom: '3%', 115 | containLabel: true 116 | }, 117 | xAxis : [ 118 | { 119 | type : 'category', 120 | boundaryGap : false, 121 | data : ['周一','周二','周三','周四','周五','周六','周日'] 122 | } 123 | ], 124 | yAxis : [ 125 | { 126 | type : 'value' 127 | } 128 | ], 129 | series : [ 130 | { 131 | name:'邮件营销', 132 | type:'line', 133 | stack: '总量', 134 | areaStyle: {normal: {}}, 135 | data:[120, 132, 101, 134, 90, 230, 210] 136 | }, 137 | { 138 | name:'联盟广告', 139 | type:'line', 140 | stack: '总量', 141 | areaStyle: {normal: {}}, 142 | data:[220, 182, 191, 234, 290, 330, 310] 143 | }, 144 | { 145 | name:'视频广告', 146 | type:'line', 147 | stack: '总量', 148 | areaStyle: {normal: {}}, 149 | data:[150, 232, 201, 154, 190, 330, 410] 150 | }, 151 | { 152 | name:'直接访问', 153 | type:'line', 154 | stack: '总量', 155 | areaStyle: {normal: {}}, 156 | data:[320, 332, 301, 334, 390, 330, 320] 157 | }, 158 | { 159 | name:'搜索引擎', 160 | type:'line', 161 | stack: '总量', 162 | label: { 163 | normal: { 164 | show: true, 165 | position: 'top' 166 | } 167 | }, 168 | areaStyle: {normal: {}}, 169 | data:[820, 932, 901, 934, 1290, 1330, 1320] 170 | } 171 | ] 172 | }; 173 | 174 | //散点图数据 175 | export const scatterOption = { 176 | tooltip : { 177 | trigger: 'axis', 178 | showDelay : 0, 179 | axisPointer:{ 180 | show: true, 181 | type : 'cross', 182 | lineStyle: { 183 | type : 'dashed', 184 | width : 1 185 | } 186 | }, 187 | zlevel: 1 188 | }, 189 | legend: { 190 | data:['sin','cos'] 191 | }, 192 | toolbox: { 193 | show : true, 194 | feature : { 195 | mark : {show: true}, 196 | dataZoom : {show: true}, 197 | dataView : {show: true, readOnly: false}, 198 | restore : {show: true}, 199 | saveAsImage : {show: true} 200 | } 201 | }, 202 | xAxis : [ 203 | { 204 | type : 'value', 205 | scale:true 206 | } 207 | ], 208 | yAxis : [ 209 | { 210 | type : 'value', 211 | scale:true 212 | } 213 | ], 214 | series : [ 215 | { 216 | name:'sin', 217 | type:'scatter', 218 | large: true, 219 | symbolSize: 3, 220 | data: (function () { 221 | var d = []; 222 | var len = 10000; 223 | var x = 0; 224 | while (len--) { 225 | x = (Math.random() * 10).toFixed(3) - 0; 226 | d.push([ 227 | x, 228 | //Math.random() * 10 229 | (Math.sin(x) - x * (len % 2 ? 0.1 : -0.1) * Math.random()).toFixed(3) - 0 230 | ]); 231 | } 232 | //console.log(d) 233 | return d; 234 | })() 235 | }, 236 | { 237 | name:'cos', 238 | type:'scatter', 239 | large: true, 240 | symbolSize: 2, 241 | data: (function () { 242 | var d = []; 243 | var len = 20000; 244 | var x = 0; 245 | while (len--) { 246 | x = (Math.random() * 10).toFixed(3) - 0; 247 | d.push([ 248 | x, 249 | //Math.random() * 10 250 | (Math.cos(x) - x * (len % 2 ? 0.1 : -0.1) * Math.random()).toFixed(3) - 0 251 | ]); 252 | } 253 | //console.log(d) 254 | return d; 255 | })() 256 | } 257 | ] 258 | }; 259 | 260 | //地图数据 261 | var geoCoordMap = { 262 | '上海': [121.4648,31.2891], 263 | '东莞': [113.8953,22.901], 264 | '东营': [118.7073,37.5513], 265 | '中山': [113.4229,22.478], 266 | '临汾': [111.4783,36.1615], 267 | '临沂': [118.3118,35.2936], 268 | '丹东': [124.541,40.4242], 269 | '丽水': [119.5642,28.1854], 270 | '乌鲁木齐': [87.9236,43.5883], 271 | '佛山': [112.8955,23.1097], 272 | '保定': [115.0488,39.0948], 273 | '兰州': [103.5901,36.3043], 274 | '包头': [110.3467,41.4899], 275 | '北京': [116.4551,40.2539], 276 | '北海': [109.314,21.6211], 277 | '南京': [118.8062,31.9208], 278 | '南宁': [108.479,23.1152], 279 | '南昌': [116.0046,28.6633], 280 | '南通': [121.1023,32.1625], 281 | '厦门': [118.1689,24.6478], 282 | '台州': [121.1353,28.6688], 283 | '合肥': [117.29,32.0581], 284 | '呼和浩特': [111.4124,40.4901], 285 | '咸阳': [108.4131,34.8706], 286 | '哈尔滨': [127.9688,45.368], 287 | '唐山': [118.4766,39.6826], 288 | '嘉兴': [120.9155,30.6354], 289 | '大同': [113.7854,39.8035], 290 | '大连': [122.2229,39.4409], 291 | '天津': [117.4219,39.4189], 292 | '太原': [112.3352,37.9413], 293 | '威海': [121.9482,37.1393], 294 | '宁波': [121.5967,29.6466], 295 | '宝鸡': [107.1826,34.3433], 296 | '宿迁': [118.5535,33.7775], 297 | '常州': [119.4543,31.5582], 298 | '广州': [113.5107,23.2196], 299 | '廊坊': [116.521,39.0509], 300 | '延安': [109.1052,36.4252], 301 | '张家口': [115.1477,40.8527], 302 | '徐州': [117.5208,34.3268], 303 | '德州': [116.6858,37.2107], 304 | '惠州': [114.6204,23.1647], 305 | '成都': [103.9526,30.7617], 306 | '扬州': [119.4653,32.8162], 307 | '承德': [117.5757,41.4075], 308 | '拉萨': [91.1865,30.1465], 309 | '无锡': [120.3442,31.5527], 310 | '日照': [119.2786,35.5023], 311 | '昆明': [102.9199,25.4663], 312 | '杭州': [119.5313,29.8773], 313 | '枣庄': [117.323,34.8926], 314 | '柳州': [109.3799,24.9774], 315 | '株洲': [113.5327,27.0319], 316 | '武汉': [114.3896,30.6628], 317 | '汕头': [117.1692,23.3405], 318 | '江门': [112.6318,22.1484], 319 | '沈阳': [123.1238,42.1216], 320 | '沧州': [116.8286,38.2104], 321 | '河源': [114.917,23.9722], 322 | '泉州': [118.3228,25.1147], 323 | '泰安': [117.0264,36.0516], 324 | '泰州': [120.0586,32.5525], 325 | '济南': [117.1582,36.8701], 326 | '济宁': [116.8286,35.3375], 327 | '海口': [110.3893,19.8516], 328 | '淄博': [118.0371,36.6064], 329 | '淮安': [118.927,33.4039], 330 | '深圳': [114.5435,22.5439], 331 | '清远': [112.9175,24.3292], 332 | '温州': [120.498,27.8119], 333 | '渭南': [109.7864,35.0299], 334 | '湖州': [119.8608,30.7782], 335 | '湘潭': [112.5439,27.7075], 336 | '滨州': [117.8174,37.4963], 337 | '潍坊': [119.0918,36.524], 338 | '烟台': [120.7397,37.5128], 339 | '玉溪': [101.9312,23.8898], 340 | '珠海': [113.7305,22.1155], 341 | '盐城': [120.2234,33.5577], 342 | '盘锦': [121.9482,41.0449], 343 | '石家庄': [114.4995,38.1006], 344 | '福州': [119.4543,25.9222], 345 | '秦皇岛': [119.2126,40.0232], 346 | '绍兴': [120.564,29.7565], 347 | '聊城': [115.9167,36.4032], 348 | '肇庆': [112.1265,23.5822], 349 | '舟山': [122.2559,30.2234], 350 | '苏州': [120.6519,31.3989], 351 | '莱芜': [117.6526,36.2714], 352 | '菏泽': [115.6201,35.2057], 353 | '营口': [122.4316,40.4297], 354 | '葫芦岛': [120.1575,40.578], 355 | '衡水': [115.8838,37.7161], 356 | '衢州': [118.6853,28.8666], 357 | '西宁': [101.4038,36.8207], 358 | '西安': [109.1162,34.2004], 359 | '贵阳': [106.6992,26.7682], 360 | '连云港': [119.1248,34.552], 361 | '邢台': [114.8071,37.2821], 362 | '邯郸': [114.4775,36.535], 363 | '郑州': [113.4668,34.6234], 364 | '鄂尔多斯': [108.9734,39.2487], 365 | '重庆': [107.7539,30.1904], 366 | '金华': [120.0037,29.1028], 367 | '铜川': [109.0393,35.1947], 368 | '银川': [106.3586,38.1775], 369 | '镇江': [119.4763,31.9702], 370 | '长春': [125.8154,44.2584], 371 | '长沙': [113.0823,28.2568], 372 | '长治': [112.8625,36.4746], 373 | '阳泉': [113.4778,38.0951], 374 | '青岛': [120.4651,36.3373], 375 | '韶关': [113.7964,24.7028] 376 | }; 377 | 378 | var BJData = [ 379 | [{name:'北京'}, {name:'上海',value:95}], 380 | [{name:'北京'}, {name:'广州',value:90}], 381 | [{name:'北京'}, {name:'大连',value:80}], 382 | [{name:'北京'}, {name:'南宁',value:70}], 383 | [{name:'北京'}, {name:'南昌',value:60}], 384 | [{name:'北京'}, {name:'拉萨',value:50}], 385 | [{name:'北京'}, {name:'长春',value:40}], 386 | [{name:'北京'}, {name:'包头',value:30}], 387 | [{name:'北京'}, {name:'重庆',value:20}], 388 | [{name:'北京'}, {name:'常州',value:10}] 389 | ]; 390 | 391 | var SHData = [ 392 | [{name:'上海'},{name:'包头',value:95}], 393 | [{name:'上海'},{name:'昆明',value:90}], 394 | [{name:'上海'},{name:'广州',value:80}], 395 | [{name:'上海'},{name:'郑州',value:70}], 396 | [{name:'上海'},{name:'长春',value:60}], 397 | [{name:'上海'},{name:'重庆',value:50}], 398 | [{name:'上海'},{name:'长沙',value:40}], 399 | [{name:'上海'},{name:'北京',value:30}], 400 | [{name:'上海'},{name:'丹东',value:20}], 401 | [{name:'上海'},{name:'大连',value:10}] 402 | ]; 403 | 404 | var GZData = [ 405 | [{name:'广州'},{name:'福州',value:95}], 406 | [{name:'广州'},{name:'太原',value:90}], 407 | [{name:'广州'},{name:'长春',value:80}], 408 | [{name:'广州'},{name:'重庆',value:70}], 409 | [{name:'广州'},{name:'西安',value:60}], 410 | [{name:'广州'},{name:'成都',value:50}], 411 | [{name:'广州'},{name:'常州',value:40}], 412 | [{name:'广州'},{name:'北京',value:30}], 413 | [{name:'广州'},{name:'北海',value:20}], 414 | [{name:'广州'},{name:'海口',value:10}] 415 | ]; 416 | 417 | var planePath = 'path://M1705.06,1318.313v-89.254l-319.9-221.799l0.073-208.063c0.521-84.662-26.629-121.796-63.961-121.491c-37.332-0.305-64.482,36.829-63.961,121.491l0.073,208.063l-319.9,221.799v89.254l330.343-157.288l12.238,241.308l-134.449,92.931l0.531,42.034l175.125-42.917l175.125,42.917l0.531-42.034l-134.449-92.931l12.238-241.308L1705.06,1318.313z'; 418 | 419 | var convertData = function (data) { 420 | var res = []; 421 | for (var i = 0; i < data.length; i++) { 422 | var dataItem = data[i]; 423 | var fromCoord = geoCoordMap[dataItem[0].name]; 424 | var toCoord = geoCoordMap[dataItem[1].name]; 425 | if (fromCoord && toCoord) { 426 | res.push({ 427 | fromName: dataItem[0].name, 428 | toName: dataItem[1].name, 429 | coords: [fromCoord, toCoord] 430 | }); 431 | } 432 | } 433 | return res; 434 | }; 435 | 436 | var color = ['#a6c84c', '#ffa022', '#46bee9']; 437 | var series = []; 438 | [['北京', BJData], ['上海', SHData], ['广州', GZData]].forEach(function (item, i) { 439 | series.push({ 440 | name: item[0] + ' Top10', 441 | type: 'lines', 442 | zlevel: 1, 443 | effect: { 444 | show: true, 445 | period: 6, 446 | trailLength: 0.7, 447 | color: '#fff', 448 | symbolSize: 3 449 | }, 450 | lineStyle: { 451 | normal: { 452 | color: color[i], 453 | width: 0, 454 | curveness: 0.2 455 | } 456 | }, 457 | data: convertData(item[1]) 458 | }, 459 | { 460 | name: item[0] + ' Top10', 461 | type: 'lines', 462 | zlevel: 2, 463 | symbol: ['none', 'arrow'], 464 | symbolSize: 10, 465 | effect: { 466 | show: true, 467 | period: 6, 468 | trailLength: 0, 469 | symbol: planePath, 470 | symbolSize: 15 471 | }, 472 | lineStyle: { 473 | normal: { 474 | color: color[i], 475 | width: 1, 476 | opacity: 0.6, 477 | curveness: 0.2 478 | } 479 | }, 480 | data: convertData(item[1]) 481 | }, 482 | { 483 | name: item[0] + ' Top10', 484 | type: 'effectScatter', 485 | coordinateSystem: 'geo', 486 | zlevel: 2, 487 | rippleEffect: { 488 | brushType: 'stroke' 489 | }, 490 | label: { 491 | normal: { 492 | show: true, 493 | position: 'right', 494 | formatter: '{b}' 495 | } 496 | }, 497 | symbolSize: function (val) { 498 | return val[2] / 8; 499 | }, 500 | itemStyle: { 501 | normal: { 502 | color: color[i] 503 | } 504 | }, 505 | data: item[1].map(function (dataItem) { 506 | return { 507 | name: dataItem[1].name, 508 | value: geoCoordMap[dataItem[1].name].concat([dataItem[1].value]) 509 | }; 510 | }) 511 | }); 512 | }); 513 | 514 | export const mapOption = { 515 | backgroundColor: '#404a59', 516 | tooltip : { 517 | trigger: 'item' 518 | }, 519 | legend: { 520 | orient: 'vertical', 521 | top: 'bottom', 522 | left: 'right', 523 | data:['北京 Top10', '上海 Top10', '广州 Top10'], 524 | textStyle: { 525 | color: '#fff' 526 | }, 527 | selectedMode: 'single' 528 | }, 529 | geo: { 530 | map: 'china', 531 | label: { 532 | emphasis: { 533 | show: false 534 | } 535 | }, 536 | roam: true, 537 | itemStyle: { 538 | normal: { 539 | areaColor: '#323c48', 540 | borderColor: '#404a59' 541 | }, 542 | emphasis: { 543 | areaColor: '#2a333d' 544 | } 545 | } 546 | }, 547 | series: series 548 | }; 549 | 550 | //雷达图数据 551 | export const radarOption = { 552 | legend: { 553 | data: ['预算分配(Allocated Budget)', '实际开销(Actual Spending)'] 554 | }, 555 | radar: { 556 | // shape: 'circle', 557 | indicator: [ 558 | { name: '销售(sales)', max: 6500}, 559 | { name: '管理(Administration)', max: 16000}, 560 | { name: '信息技术(Information Techology)', max: 30000}, 561 | { name: '客服(Customer Support)', max: 38000}, 562 | { name: '研发(Development)', max: 52000}, 563 | { name: '市场(Marketing)', max: 25000} 564 | ] 565 | }, 566 | series: [{ 567 | name: '预算 vs 开销(Budget vs spending)', 568 | type: 'radar', 569 | // areaStyle: {normal: {}}, 570 | data : [ 571 | { 572 | value : [4300, 10000, 28000, 35000, 50000, 19000], 573 | name : '预算分配(Allocated Budget)' 574 | }, 575 | { 576 | value : [5000, 14000, 28000, 31000, 42000, 21000], 577 | name : '实际开销(Actual Spending)' 578 | } 579 | ] 580 | }] 581 | }; 582 | 583 | //k线图数据 584 | // 数据意义:开盘(open),收盘(close),最低(lowest),最高(highest) 585 | var data0 = splitData([ 586 | ['2013/1/24', 2320.26,2320.26,2287.3,2362.94], 587 | ['2013/1/25', 2300,2291.3,2288.26,2308.38], 588 | ['2013/1/28', 2295.35,2346.5,2295.35,2346.92], 589 | ['2013/1/29', 2347.22,2358.98,2337.35,2363.8], 590 | ['2013/1/30', 2360.75,2382.48,2347.89,2383.76], 591 | ['2013/1/31', 2383.43,2385.42,2371.23,2391.82], 592 | ['2013/2/1', 2377.41,2419.02,2369.57,2421.15], 593 | ['2013/2/4', 2425.92,2428.15,2417.58,2440.38], 594 | ['2013/2/5', 2411,2433.13,2403.3,2437.42], 595 | ['2013/2/6', 2432.68,2434.48,2427.7,2441.73], 596 | ['2013/2/7', 2430.69,2418.53,2394.22,2433.89], 597 | ['2013/2/8', 2416.62,2432.4,2414.4,2443.03], 598 | ['2013/2/18', 2441.91,2421.56,2415.43,2444.8], 599 | ['2013/2/19', 2420.26,2382.91,2373.53,2427.07], 600 | ['2013/2/20', 2383.49,2397.18,2370.61,2397.94], 601 | ['2013/2/21', 2378.82,2325.95,2309.17,2378.82], 602 | ['2013/2/22', 2322.94,2314.16,2308.76,2330.88], 603 | ['2013/2/25', 2320.62,2325.82,2315.01,2338.78], 604 | ['2013/2/26', 2313.74,2293.34,2289.89,2340.71], 605 | ['2013/2/27', 2297.77,2313.22,2292.03,2324.63], 606 | ['2013/2/28', 2322.32,2365.59,2308.92,2366.16], 607 | ['2013/3/1', 2364.54,2359.51,2330.86,2369.65], 608 | ['2013/3/4', 2332.08,2273.4,2259.25,2333.54], 609 | ['2013/3/5', 2274.81,2326.31,2270.1,2328.14], 610 | ['2013/3/6', 2333.61,2347.18,2321.6,2351.44], 611 | ['2013/3/7', 2340.44,2324.29,2304.27,2352.02], 612 | ['2013/3/8', 2326.42,2318.61,2314.59,2333.67], 613 | ['2013/3/11', 2314.68,2310.59,2296.58,2320.96], 614 | ['2013/3/12', 2309.16,2286.6,2264.83,2333.29], 615 | ['2013/3/13', 2282.17,2263.97,2253.25,2286.33], 616 | ['2013/3/14', 2255.77,2270.28,2253.31,2276.22], 617 | ['2013/3/15', 2269.31,2278.4,2250,2312.08], 618 | ['2013/3/18', 2267.29,2240.02,2239.21,2276.05], 619 | ['2013/3/19', 2244.26,2257.43,2232.02,2261.31], 620 | ['2013/3/20', 2257.74,2317.37,2257.42,2317.86], 621 | ['2013/3/21', 2318.21,2324.24,2311.6,2330.81], 622 | ['2013/3/22', 2321.4,2328.28,2314.97,2332], 623 | ['2013/3/25', 2334.74,2326.72,2319.91,2344.89], 624 | ['2013/3/26', 2318.58,2297.67,2281.12,2319.99], 625 | ['2013/3/27', 2299.38,2301.26,2289,2323.48], 626 | ['2013/3/28', 2273.55,2236.3,2232.91,2273.55], 627 | ['2013/3/29', 2238.49,2236.62,2228.81,2246.87], 628 | ['2013/4/1', 2229.46,2234.4,2227.31,2243.95], 629 | ['2013/4/2', 2234.9,2227.74,2220.44,2253.42], 630 | ['2013/4/3', 2232.69,2225.29,2217.25,2241.34], 631 | ['2013/4/8', 2196.24,2211.59,2180.67,2212.59], 632 | ['2013/4/9', 2215.47,2225.77,2215.47,2234.73], 633 | ['2013/4/10', 2224.93,2226.13,2212.56,2233.04], 634 | ['2013/4/11', 2236.98,2219.55,2217.26,2242.48], 635 | ['2013/4/12', 2218.09,2206.78,2204.44,2226.26], 636 | ['2013/4/15', 2199.91,2181.94,2177.39,2204.99], 637 | ['2013/4/16', 2169.63,2194.85,2165.78,2196.43], 638 | ['2013/4/17', 2195.03,2193.8,2178.47,2197.51], 639 | ['2013/4/18', 2181.82,2197.6,2175.44,2206.03], 640 | ['2013/4/19', 2201.12,2244.64,2200.58,2250.11], 641 | ['2013/4/22', 2236.4,2242.17,2232.26,2245.12], 642 | ['2013/4/23', 2242.62,2184.54,2182.81,2242.62], 643 | ['2013/4/24', 2187.35,2218.32,2184.11,2226.12], 644 | ['2013/4/25', 2213.19,2199.31,2191.85,2224.63], 645 | ['2013/4/26', 2203.89,2177.91,2173.86,2210.58], 646 | ['2013/5/2', 2170.78,2174.12,2161.14,2179.65], 647 | ['2013/5/3', 2179.05,2205.5,2179.05,2222.81], 648 | ['2013/5/6', 2212.5,2231.17,2212.5,2236.07], 649 | ['2013/5/7', 2227.86,2235.57,2219.44,2240.26], 650 | ['2013/5/8', 2242.39,2246.3,2235.42,2255.21], 651 | ['2013/5/9', 2246.96,2232.97,2221.38,2247.86], 652 | ['2013/5/10', 2228.82,2246.83,2225.81,2247.67], 653 | ['2013/5/13', 2247.68,2241.92,2231.36,2250.85], 654 | ['2013/5/14', 2238.9,2217.01,2205.87,2239.93], 655 | ['2013/5/15', 2217.09,2224.8,2213.58,2225.19], 656 | ['2013/5/16', 2221.34,2251.81,2210.77,2252.87], 657 | ['2013/5/17', 2249.81,2282.87,2248.41,2288.09], 658 | ['2013/5/20', 2286.33,2299.99,2281.9,2309.39], 659 | ['2013/5/21', 2297.11,2305.11,2290.12,2305.3], 660 | ['2013/5/22', 2303.75,2302.4,2292.43,2314.18], 661 | ['2013/5/23', 2293.81,2275.67,2274.1,2304.95], 662 | ['2013/5/24', 2281.45,2288.53,2270.25,2292.59], 663 | ['2013/5/27', 2286.66,2293.08,2283.94,2301.7], 664 | ['2013/5/28', 2293.4,2321.32,2281.47,2322.1], 665 | ['2013/5/29', 2323.54,2324.02,2321.17,2334.33], 666 | ['2013/5/30', 2316.25,2317.75,2310.49,2325.72], 667 | ['2013/5/31', 2320.74,2300.59,2299.37,2325.53], 668 | ['2013/6/3', 2300.21,2299.25,2294.11,2313.43], 669 | ['2013/6/4', 2297.1,2272.42,2264.76,2297.1], 670 | ['2013/6/5', 2270.71,2270.93,2260.87,2276.86], 671 | ['2013/6/6', 2264.43,2242.11,2240.07,2266.69], 672 | ['2013/6/7', 2242.26,2210.9,2205.07,2250.63], 673 | ['2013/6/13', 2190.1,2148.35,2126.22,2190.1] 674 | ]); 675 | 676 | 677 | function splitData(rawData) { 678 | var categoryData = []; 679 | var values = [] 680 | for (var i = 0; i < rawData.length; i++) { 681 | categoryData.push(rawData[i].splice(0, 1)[0]); 682 | values.push(rawData[i]) 683 | } 684 | return { 685 | categoryData: categoryData, 686 | values: values 687 | }; 688 | } 689 | 690 | function calculateMA(dayCount) { 691 | var result = []; 692 | for (var i = 0, len = data0.values.length; i < len; i++) { 693 | if (i < dayCount) { 694 | result.push('-'); 695 | continue; 696 | } 697 | var sum = 0; 698 | for (var j = 0; j < dayCount; j++) { 699 | sum += data0.values[i - j][1]; 700 | } 701 | result.push(sum / dayCount); 702 | } 703 | return result; 704 | } 705 | 706 | 707 | 708 | export const candlestickOption = { 709 | tooltip: { 710 | trigger: 'axis', 711 | axisPointer: { 712 | type: 'cross' 713 | } 714 | }, 715 | legend: { 716 | data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30'] 717 | }, 718 | grid: { 719 | left: '10%', 720 | right: '10%', 721 | bottom: '15%' 722 | }, 723 | xAxis: { 724 | type: 'category', 725 | data: data0.categoryData, 726 | scale: true, 727 | boundaryGap : false, 728 | axisLine: {onZero: false}, 729 | splitLine: {show: false}, 730 | splitNumber: 20, 731 | min: 'dataMin', 732 | max: 'dataMax' 733 | }, 734 | yAxis: { 735 | scale: true, 736 | splitArea: { 737 | show: true 738 | } 739 | }, 740 | series: [ 741 | { 742 | name: '日K', 743 | type: 'candlestick', 744 | data: data0.values, 745 | markPoint: { 746 | label: { 747 | normal: { 748 | formatter: function (param) { 749 | return param != null ? Math.round(param.value) : ''; 750 | } 751 | } 752 | }, 753 | data: [ 754 | { 755 | name: 'XX标点', 756 | coord: ['2013/5/31', 2300], 757 | value: 2300, 758 | itemStyle: { 759 | normal: {color: 'rgb(41,60,85)'} 760 | } 761 | }, 762 | { 763 | name: 'highest value', 764 | type: 'max', 765 | valueDim: 'highest' 766 | }, 767 | { 768 | name: 'lowest value', 769 | type: 'min', 770 | valueDim: 'lowest' 771 | }, 772 | { 773 | name: 'average value on close', 774 | type: 'average', 775 | valueDim: 'close' 776 | } 777 | ], 778 | tooltip: { 779 | formatter: function (param) { 780 | return param.name + '
' + (param.data.coord || ''); 781 | } 782 | } 783 | }, 784 | markLine: { 785 | symbol: ['none', 'none'], 786 | data: [ 787 | [ 788 | { 789 | name: 'from lowest to highest', 790 | type: 'min', 791 | valueDim: 'lowest', 792 | symbol: 'circle', 793 | symbolSize: 10, 794 | label: { 795 | normal: {show: false}, 796 | emphasis: {show: false} 797 | } 798 | }, 799 | { 800 | type: 'max', 801 | valueDim: 'highest', 802 | symbol: 'circle', 803 | symbolSize: 10, 804 | label: { 805 | normal: {show: false}, 806 | emphasis: {show: false} 807 | } 808 | } 809 | ], 810 | { 811 | name: 'min line on close', 812 | type: 'min', 813 | valueDim: 'close' 814 | }, 815 | { 816 | name: 'max line on close', 817 | type: 'max', 818 | valueDim: 'close' 819 | } 820 | ] 821 | } 822 | }, 823 | { 824 | name: 'MA5', 825 | type: 'line', 826 | data: calculateMA(5), 827 | smooth: true, 828 | lineStyle: { 829 | normal: {opacity: 0.5} 830 | } 831 | }, 832 | { 833 | name: 'MA10', 834 | type: 'line', 835 | data: calculateMA(10), 836 | smooth: true, 837 | lineStyle: { 838 | normal: {opacity: 0.5} 839 | } 840 | }, 841 | { 842 | name: 'MA20', 843 | type: 'line', 844 | data: calculateMA(20), 845 | smooth: true, 846 | lineStyle: { 847 | normal: {opacity: 0.5} 848 | } 849 | }, 850 | { 851 | name: 'MA30', 852 | type: 'line', 853 | data: calculateMA(30), 854 | smooth: true, 855 | lineStyle: { 856 | normal: {opacity: 0.5} 857 | } 858 | }, 859 | 860 | ] 861 | }; 862 | 863 | --------------------------------------------------------------------------------