From 469acda80b900db4d5bc0e57a98ebb1026f87cd7 Mon Sep 17 00:00:00 2001 From: hustcc Date: Sun, 7 Feb 2021 18:03:59 +0800 Subject: [PATCH] chore: init 3.0.0-beta.1 --- .commitlintrc.js | 10 + .editorconfig | 20 ++ .eslintignore | 4 + .eslintrc | 40 ++++ .github/workflows/build.yml | 25 +++ .gitignore | 83 ++++++++ .lintmdrc | 5 + .prettierignore | 4 + .prettierrc | 9 + .umirc.js | 23 ++ LICENSE | 21 ++ README.md | 306 +++++++++++++++++++++++++++ __tests__/charts/simple-spec.tsx | 37 ++++ __tests__/helper/is-equal-spec.ts | 7 + __tests__/helper/is-fucntion-spec.ts | 10 + __tests__/helper/is-string-spec.ts | 10 + __tests__/helper/pick-spec.ts | 10 + __tests__/utils/index.ts | 44 ++++ docs/examples/api.md | 128 +++++++++++ docs/examples/dynamic.md | 178 ++++++++++++++++ docs/examples/event.md | 85 ++++++++ docs/examples/gl.md | 36 ++++ docs/examples/graph.md | 52 +++++ docs/examples/loading.md | 79 +++++++ docs/examples/simple.md | 78 +++++++ docs/examples/svg.md | 40 ++++ docs/examples/theme.md | 123 +++++++++++ docs/index.md | 86 ++++++++ package.json | 116 ++++++++++ src/core.tsx | 185 ++++++++++++++++ src/helper/is-equal.ts | 3 + src/helper/is-function.ts | 3 + src/helper/is-string.ts | 3 + src/helper/pick.ts | 12 ++ src/index.ts | 15 ++ src/types.ts | 69 ++++++ tsconfig.json | 20 ++ 37 files changed, 1979 insertions(+) create mode 100644 .commitlintrc.js create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 .lintmdrc create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 .umirc.js create mode 100644 LICENSE create mode 100644 README.md create mode 100644 __tests__/charts/simple-spec.tsx create mode 100644 __tests__/helper/is-equal-spec.ts create mode 100644 __tests__/helper/is-fucntion-spec.ts create mode 100644 __tests__/helper/is-string-spec.ts create mode 100644 __tests__/helper/pick-spec.ts create mode 100644 __tests__/utils/index.ts create mode 100644 docs/examples/api.md create mode 100644 docs/examples/dynamic.md create mode 100644 docs/examples/event.md create mode 100644 docs/examples/gl.md create mode 100644 docs/examples/graph.md create mode 100644 docs/examples/loading.md create mode 100644 docs/examples/simple.md create mode 100644 docs/examples/svg.md create mode 100644 docs/examples/theme.md create mode 100644 docs/index.md create mode 100644 package.json create mode 100644 src/core.tsx create mode 100644 src/helper/is-equal.ts create mode 100644 src/helper/is-function.ts create mode 100644 src/helper/is-string.ts create mode 100644 src/helper/pick.ts create mode 100644 src/index.ts create mode 100644 src/types.ts create mode 100644 tsconfig.json diff --git a/.commitlintrc.js b/.commitlintrc.js new file mode 100644 index 0000000..f8f4d21 --- /dev/null +++ b/.commitlintrc.js @@ -0,0 +1,10 @@ +module.exports = { + extends: ['@commitlint/config-angular'], + rules: { + 'type-enum': [ + 2, + 'always', + ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'wip'], + ], + }, +}; diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a2f217c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab +indent_size = 1 + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..b2f1269 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +node_modules +dist/ +test +build/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..e520023 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,40 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "prettier" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["prettier", "@typescript-eslint", "import"], + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "impliedStrict": true + }, + "rules": { + "no-sparse-arrays": 0, + "no-self-assign": 0, + "no-unused-vars": 0, // @typescript-eslint/no-unused-vars + "no-inner-declarations": 0, + "prettier/prettier": 2, + "@typescript-eslint/no-unused-vars": 1, + "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-use-before-define": [2, { "functions": false }], + "@typescript-eslint/ban-ts-ignore": 0, + "@typescript-eslint/interface-name-prefix": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/camelcase": 0, + "@typescript-eslint/no-inferrable-types": 0, + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/type-annotation-spacing": 0, + "@typescript-eslint/no-empty-function": 0, + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/ban-types": "off", + "no-undef": 0, + "@typescript-eslint/no-var-requires": 0, + "import/order": 0, + "import/no-default-export": 0 + } +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..54367ac --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,25 @@ +name: build + +on: ["push", "pull_request"] + +jobs: + build: + runs-on: macOS-latest + steps: + - uses: actions/checkout@v1 + - name: Use Node.js 12 + uses: actions/setup-node@v1 + with: + node-version: 12.10.0 + - name: npm install + run: | + npm install + - name: build + run: | + npm run build + env: + CI: true + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cb2439f --- /dev/null +++ b/.gitignore @@ -0,0 +1,83 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# lock +package-lock.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +yarn.lock + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +public +build +dist +temp +.DS_Store +.idea +.cache +demos/assets/screenshots +/lib +/esm +/dist + +*.sw* +*.un~ + +.vscode +/stats.json +.umi +.umi-production diff --git a/.lintmdrc b/.lintmdrc new file mode 100644 index 0000000..b153b89 --- /dev/null +++ b/.lintmdrc @@ -0,0 +1,5 @@ +{ + "rules": { + "no-long-code": 1 + } +} \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..5e199e6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +stats.json +.cache +dist +.umi diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a13afd8 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true, + "printWidth": 120, + "arrowParens": "always", + "endOfLine": "auto" +} diff --git a/.umirc.js b/.umirc.js new file mode 100644 index 0000000..d1dda6b --- /dev/null +++ b/.umirc.js @@ -0,0 +1,23 @@ +import { defineConfig } from 'dumi'; + +export default defineConfig({ + mode: 'site', + title: '\b', + base: '/', + publicPath: process.env.NODE_ENV === 'production' ? '/echarts-for-react/' : '/', + exportStatic: {}, + logo: 'https://cdn.jsdelivr.net/gh/apache/echarts-website@asf-site/zh/images/logo.png?_v_=20200710_1', + styles: [ + '.__dumi-default-navbar-logo:not([data-plaintext]) { padding-left: 200px!important; }', + '.echarts-for-react.class_1 { height: 400px!important; }', + '.echarts-for-react.class_2 { height: 500px!important; }', + ], + navs: [ + null, + { title: '在线文档', path: 'https://github.com/hustcc/echarts-for-react' }, + { title: 'GitHub', path: 'https://github.com/hustcc/echarts-for-react' }, + ], + analytics: { + }, + // more config: https://d.umijs.org/config +}); \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ef16fe9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 AntV team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do { so, subject } to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f64edc --- /dev/null +++ b/README.md @@ -0,0 +1,306 @@ +# echarts-for-react + +A very simple React wrapper for [Apache ECharts (incubating)](https://github.com/apache/incubator-echarts). + +[![Build Status](https://github.com/hustcc/echarts-for-react/workflows/build/badge.svg?branch=master)](https://github.com/hustcc/echarts-for-react/actions?query=workflow%3Abuild) +[![Coverage](https://img.shields.io/coveralls/hustcc/echarts-for-react/master.svg)](https://coveralls.io/github/hustcc/echarts-for-react) +[![npm](https://img.shields.io/npm/v/echarts-for-react.svg)](https://www.npmjs.com/package/echarts-for-react) +[![NPM downloads](https://img.shields.io/npm/dm/echarts-for-react.svg)](https://www.npmjs.com/package/echarts-for-react) +[![License](https://img.shields.io/npm/l/echarts-for-react.svg)](https://www.npmjs.com/package/echarts-for-react) +![ECharts Ver](https://img.shields.io/badge/echarts-%5E3.0.0%20%7C%7C%20%5E4.0.0%20%7C%7C%20%5E5.0.0-blue.svg) +![React Ver](https://img.shields.io/badge/React-%20%5E15.0.0%20%7C%7C%20%20%5E16.0.0%20%7C%7C%20%20%5E17.0.0-blue.svg) + + +# 1. install + +```sh +npm install --save echarts-for-react + +# `echarts` is the peerDependence of `echarts-for-react`, you can install echarts with your own version. +npm install --save echarts +``` + +Then use it. + +```js +import ReactEcharts from 'echarts-for-react'; + +// render echarts option. + +``` + +You can run demo by: + +```sh +git clone git@github.com:hustcc/echarts-for-react.git + +npm install + +npm start +``` + +then open [http://127.0.0.1:8080/](http://127.0.0.1:8080/) in your browser. or see [http://git.hust.cc/echarts-for-react/](http://git.hust.cc/echarts-for-react/) + +## GL + +Install and import [`echarts-gl`](https://www.npmjs.com/package/echarts-gl) module when you want to create a [GL instance](https://www.echartsjs.com/examples/zh/index.html#chart-type-globe) + + - **`Install`** + +```sh +npm install --save echarts-gl +``` + + - **`Import`** + +```js +import 'echarts-gl' +import ReactEcharts from "echarts-for-react"; + + + +``` + + +# 2. usage + +Code of a simple demo code showed below. For more example can see: [http://git.hust.cc/echarts-for-react/](http://git.hust.cc/echarts-for-react/) + +### javascript + +```js +import React from 'react'; +import ReactEcharts from 'echarts-for-react'; // or var ReactEcharts = require('echarts-for-react'); + + +``` + +### typescript + +```js +import * as React from "react"; +import ReactEcharts from "echarts-for-react"; + + +``` + +Import ECharts.js modules manually to reduce bundle size + +```js +import React from 'react'; +// import the core library. +import ReactEchartsCore from 'echarts-for-react/lib/core'; + +// then import echarts modules those you have used manually. +import echarts from 'echarts/lib/echarts'; +// import 'echarts/lib/chart/line'; +import 'echarts/lib/chart/bar'; +// import 'echarts/lib/chart/pie'; +// import 'echarts/lib/chart/scatter'; +// import 'echarts/lib/chart/radar'; + +// import 'echarts/lib/chart/map'; +// import 'echarts/lib/chart/treemap'; +// import 'echarts/lib/chart/graph'; +// import 'echarts/lib/chart/gauge'; +// import 'echarts/lib/chart/funnel'; +// import 'echarts/lib/chart/parallel'; +// import 'echarts/lib/chart/sankey'; +// import 'echarts/lib/chart/boxplot'; +// import 'echarts/lib/chart/candlestick'; +// import 'echarts/lib/chart/effectScatter'; +// import 'echarts/lib/chart/lines'; +// import 'echarts/lib/chart/heatmap'; + +// import 'echarts/lib/component/graphic'; +// import 'echarts/lib/component/grid'; +// import 'echarts/lib/component/legend'; +import 'echarts/lib/component/tooltip'; +// import 'echarts/lib/component/polar'; +// import 'echarts/lib/component/geo'; +// import 'echarts/lib/component/parallel'; +// import 'echarts/lib/component/singleAxis'; +// import 'echarts/lib/component/brush'; + +import 'echarts/lib/component/title'; + +// import 'echarts/lib/component/dataZoom'; +// import 'echarts/lib/component/visualMap'; + +// import 'echarts/lib/component/markPoint'; +// import 'echarts/lib/component/markLine'; +// import 'echarts/lib/component/markArea'; + +// import 'echarts/lib/component/timeline'; +// import 'echarts/lib/component/toolbox'; + +// import 'zrender/lib/vml/vml'; + +// The usage of ReactEchartsCore are same with above. + +``` + +# 3. component props + + - **`option`** (required, object) + +the echarts option config, can see [https://echarts.apache.org/option.html#title](https://echarts.apache.org/option.html#title). + + - **`notMerge`** (optional, object) + +when `setOption`, not merge the data, default is `false`. See [https://echarts.apache.org/api.html#echartsInstance.setOption](https://echarts.apache.org/api.html#echartsInstance.setOption). + + - **`lazyUpdate`** (optional, object) + +when `setOption`, lazy update the data, default is `false`. See [https://echarts.apache.org/api.html#echartsInstance.setOption](https://echarts.apache.org/api.html#echartsInstance.setOption). + + - **`style`** (optional, object) + +the `style` of echarts div. `object`, default is {height: '300px'}. + + - **`className`** (optional, string) + +the `class` of echarts div. you can setting the css style of charts by class name. + + - **`theme`** (optional, string) + +the `theme` of echarts. `string`, should `registerTheme` before use it (theme object format: [https://github.com/ecomfe/echarts/blob/master/theme/dark.js](https://github.com/ecomfe/echarts/blob/master/theme/dark.js)). e.g. + +```js +// import echarts +import echarts from 'echarts'; +... +// register theme object +echarts.registerTheme('my_theme', { + backgroundColor: '#f4cccc' +}); +... +// render the echarts use option `theme` + +``` + + - **`onChartReady`** (optional, function) + +when the chart is ready, will callback the function with the `echarts object` as it's paramter. + + - **`loadingOption`** (optional, object) + +the echarts loading option config, can see [https://echarts.apache.org/api.html#echartsInstance.showLoading](https://echarts.apache.org/api.html#echartsInstance.showLoading). + + - **`showLoading`** (optional, bool, default: false) + +`bool`, when the chart is rendering, show the loading mask. + + - **`onEvents`** (optional, array(string=>function) ) + +binding the echarts event, will callback with the `echarts event object`, and `the echart object` as it's paramters. e.g: + +```js +let onEvents = { + 'click': this.onChartClick, + 'legendselectchanged': this.onChartLegendselectchanged +} +... + +``` +for more event key name, see: [https://echarts.apache.org/api.html#events](https://echarts.apache.org/api.html#events) + + - **`opts`** (optional, object) + +the `opts` of echarts. `object`, will be used when initial echarts instance by `echarts.init`. Document [here](https://echarts.apache.org/api.html#echarts.init). + +```js + +``` + + +# 4. Component API & Echarts API + +the Component only has `one API` named `getEchartsInstance`. + + - **`getEchartsInstance()`** : get the echarts instance object, then you can use any `API of echarts`. + +for example: + +```js +// render the echarts component below with rel + { this.echarts_react = e; }} + option={this.getOption()} /> + +// then get the `ReactEcharts` use this.echarts_react + +let echarts_instance = this.echarts_react.getEchartsInstance(); +// then you can use any API of echarts. +let base64 = echarts_instance.getDataURL(); +``` + +**About API of echarts, can see** [https://echarts.apache.org/api.html#echartsInstance](https://echarts.apache.org/api.html#echartsInstance). + +You can use the API to do: + +1. `binding / unbinding` event. +2. `dynamic charts` with dynamic data. +3. get the echarts dom / dataURL / base64, save the chart to png. +4. `release` the charts. + + +# 5. Q & A + + - How to render the chart with svg when using echarts 4.x + +Use the props `opts` of component with `renderer = 'svg'`. For example: + + +```js + +``` + + - How to resolve Error `Component series.scatter3D not exists. Load it first.` + +[Install and import `echarts-gl` first](#GL) + + +# 6. LICENSE + +MIT@[hustcc](https://github.com/hustcc). + + diff --git a/__tests__/charts/simple-spec.tsx b/__tests__/charts/simple-spec.tsx new file mode 100644 index 0000000..fc5fbe1 --- /dev/null +++ b/__tests__/charts/simple-spec.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import ReactECharts from '../../src/'; +import { render, destroy, createDiv, removeDom } from '../utils'; + +const options = { + xAxis: { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + data: [820, 932, 901, 934, 1290, 1330, 1320], + type: 'line', + smooth: true, + }, + ], +}; + +describe('chart', () => { + it('simple', () => { + let instance; + const div = createDiv(); + const Comp = (instance = e)} option={options} />; + render(Comp, div); + + expect(instance).toBeDefined(); + expect(instance.getEchartsInstance()).toBeDefined(); + + destroy(div); + expect(div.querySelector('*')).toBe(null); + + removeDom(div); + }); +}); diff --git a/__tests__/helper/is-equal-spec.ts b/__tests__/helper/is-equal-spec.ts new file mode 100644 index 0000000..feddaac --- /dev/null +++ b/__tests__/helper/is-equal-spec.ts @@ -0,0 +1,7 @@ +import { isEqual } from '../../src/helper/is-equal'; + +describe('is-equal', () => { + it('isEqual', () => { + expect(isEqual({}, {})).toBe(true); + }); +}); diff --git a/__tests__/helper/is-fucntion-spec.ts b/__tests__/helper/is-fucntion-spec.ts new file mode 100644 index 0000000..0fac5f9 --- /dev/null +++ b/__tests__/helper/is-fucntion-spec.ts @@ -0,0 +1,10 @@ +import { isFunction } from '../../src/helper/is-function'; + +describe('is-function', () => { + it('isFunction', () => { + expect(isFunction(1)).toBe(false); + expect(isFunction('')).toBe(false); + expect(isFunction(true)).toBe(false); + expect(isFunction(() => {})).toBe(true); + }); +}); diff --git a/__tests__/helper/is-string-spec.ts b/__tests__/helper/is-string-spec.ts new file mode 100644 index 0000000..ec27c78 --- /dev/null +++ b/__tests__/helper/is-string-spec.ts @@ -0,0 +1,10 @@ +import { isString } from '../../src/helper/is-string'; + +describe('is-function', () => { + it('isFunction', () => { + expect(isString(1)).toBe(false); + expect(isString('')).toBe(true); + expect(isString(true)).toBe(false); + expect(isString(() => {})).toBe(false); + }); +}); diff --git a/__tests__/helper/pick-spec.ts b/__tests__/helper/pick-spec.ts new file mode 100644 index 0000000..57bf873 --- /dev/null +++ b/__tests__/helper/pick-spec.ts @@ -0,0 +1,10 @@ +import { pick } from '../../src/helper/pick'; + +describe('pick', () => { + it('pick', () => { + expect(pick({ a: 1 }, [])).toEqual({}); + expect(pick({ a: 1 }, ['b'])).toEqual({}); + expect(pick({ a: 1 }, ['a'])).toEqual({ a: 1 }); + expect(pick({ a: 1 }, ['a', 'b'])).toEqual({ a: 1 }); + }); +}); diff --git a/__tests__/utils/index.ts b/__tests__/utils/index.ts new file mode 100644 index 0000000..f458172 --- /dev/null +++ b/__tests__/utils/index.ts @@ -0,0 +1,44 @@ +import ReactDOM from 'react-dom'; + +/** + * 渲染组件 + * @param comp + * @param container + */ +export function render(comp: any, container: HTMLElement) { + ReactDOM.render(comp, container); +} + +/** + * 卸载组件 + * @param container + */ +export function destroy(container: HTMLElement) { + ReactDOM.unmountComponentAtNode(container); +} + +/** + * 创建一个 div 节点,并放到 container,默认放到 body 上 + * @param title + * @param container + * @param id 容器 id + */ +export function createDiv(container: HTMLElement = document.body): HTMLElement { + const div = document.createElement('div'); + + container.appendChild(div); + + return div; +} + +/** + * 移除 dom 元素 + * @param dom + */ +export function removeDom(dom: HTMLElement) { + const parent = dom.parentNode; + + if (parent) { + parent.removeChild(dom); + } +} diff --git a/docs/examples/api.md b/docs/examples/api.md new file mode 100644 index 0000000..725968e --- /dev/null +++ b/docs/examples/api.md @@ -0,0 +1,128 @@ +--- +title: ECharts API +order: 2 +--- + +## ECharts API + +```tsx +import React, { useRef } from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const option = { + title: { + text: '漏斗图', + subtext: '纯属虚构' + }, + tooltip: { + trigger: 'item', + formatter: "{a}
{b} : {c}%" + }, + toolbox: { + feature: { + dataView: {readOnly: false}, + restore: {}, + saveAsImage: {} + } + }, + legend: { + data: ['展现','点击','访问','咨询','订单'] + }, + series: [ + { + name: '预期', + type: 'funnel', + left: '10%', + width: '80%', + label: { + normal: { + formatter: '{b}预期' + }, + emphasis: { + position:'inside', + formatter: '{b}预期: {c}%' + } + }, + labelLine: { + normal: { + show: false + } + }, + itemStyle: { + normal: { + opacity: 0.7 + } + }, + data: [ + {value: 60, name: '访问'}, + {value: 40, name: '咨询'}, + {value: 20, name: '订单'}, + {value: 80, name: '点击'}, + {value: 100, name: '展现'} + ] + }, + { + name: '实际', + type: 'funnel', + left: '10%', + width: '80%', + maxSize: '80%', + label: { + normal: { + position: 'inside', + formatter: '{c}%', + textStyle: { + color: '#fff' + } + }, + emphasis: { + position:'inside', + formatter: '{b}实际: {c}%' + } + }, + itemStyle: { + normal: { + opacity: 0.5, + borderColor: '#fff', + borderWidth: 2 + } + }, + data: [ + {value: 30, name: '访问'}, + {value: 10, name: '咨询'}, + {value: 5, name: '订单'}, + {value: 50, name: '点击'}, + {value: 80, name: '展现'} + ] + } + ] + }; + + const instance = useRef(null); + + function clickBtn() { + const base64 = instance.current.getEchartsInstance().getDataURL(); + + const img = new Image(); + img.src = base64; + const newWin = window.open('', '_blank'); + newWin.document.write(img.outerHTML); + } + + return ( + <> + +
+ +
+ + ); +}; + +export default Page; +``` diff --git a/docs/examples/dynamic.md b/docs/examples/dynamic.md new file mode 100644 index 0000000..c462dea --- /dev/null +++ b/docs/examples/dynamic.md @@ -0,0 +1,178 @@ +--- +title: Dynamic +order: 6 +--- + +## Dynamic + +```tsx +import React, { useState, useEffect } from 'react'; +import ReactECharts from 'echarts-for-react'; +import cloneDeep from 'lodash.clonedeep'; + +const Page: React.FC = () => { + const DEFAULT_OPTION = { + title: { + text:'Hello Echarts-for-react.', + }, + tooltip: { + trigger: 'axis' + }, + legend: { + data:['最新成交价', '预购队列'] + }, + toolbox: { + show: true, + feature: { + dataView: {readOnly: false}, + restore: {}, + saveAsImage: {} + } + }, + grid: { + top: 60, + left: 30, + right: 60, + bottom:30 + }, + dataZoom: { + show: false, + start: 0, + end: 100 + }, + visualMap: { + show: false, + min: 0, + max: 1000, + color: ['#BE002F', '#F20C00', '#F00056', '#FF2D51', '#FF2121', '#FF4C00', '#FF7500', + '#FF8936', '#FFA400', '#F0C239', '#FFF143', '#FAFF72', '#C9DD22', '#AFDD22', + '#9ED900', '#00E500', '#0EB83A', '#0AA344', '#0C8918', '#057748', '#177CB0'] + }, + xAxis: [ + { + type: 'category', + boundaryGap: true, + data: (function (){ + let now = new Date(); + let res = []; + let len = 50; + while (len--) { + res.unshift(now.toLocaleTimeString().replace(/^\D*/,'')); + now = new Date(now - 2000); + } + return res; + })() + }, + { + type: 'category', + boundaryGap: true, + data: (function (){ + let res = []; + let len = 50; + while (len--) { + res.push(50 - len + 1); + } + return res; + })() + } + ], + yAxis: [ + { + type: 'value', + scale: true, + name: '价格', + max: 20, + min: 0, + boundaryGap: [0.2, 0.2] + }, + { + type: 'value', + scale: true, + name: '预购量', + max: 1200, + min: 0, + boundaryGap: [0.2, 0.2] + } + ], + series: [ + { + name:'预购队列', + type:'bar', + xAxisIndex: 1, + yAxisIndex: 1, + itemStyle: { + normal: { + barBorderRadius: 4, + } + }, + animationEasing: 'elasticOut', + animationDelay: function (idx) { + return idx * 10; + }, + animationDelayUpdate: function (idx) { + return idx * 10; + }, + data:(function (){ + let res = []; + let len = 50; + while (len--) { + res.push(Math.round(Math.random() * 1000)); + } + return res; + })() + }, + { + name:'最新成交价', + type:'line', + data:(function (){ + let res = []; + let len = 0; + while (len < 50) { + res.push((Math.random()*10 + 5).toFixed(1) - 0); + len++; + } + return res; + })() + } + ] + }; + + let count; + + const [option, setOption] = useState(DEFAULT_OPTION); + + function fetchNewData() { + const axisData = (new Date()).toLocaleTimeString().replace(/^\D*/,''); + const newOption = cloneDeep(option); // immutable + newOption.title.text = 'Hello Echarts-for-react.' + new Date().getSeconds(); + const data0 = newOption.series[0].data; + const data1 = newOption.series[1].data; + data0.shift(); + data0.push(Math.round(Math.random() * 1000)); + data1.shift(); + data1.push((Math.random() * 10 + 5).toFixed(1) - 0); + + newOption.xAxis[0].data.shift(); + newOption.xAxis[0].data.push(axisData); + newOption.xAxis[1].data.shift(); + newOption.xAxis[1].data.push(count++); + + setOption(newOption); + } + + useEffect(() => { + const timer = setInterval(() => { + fetchNewData(); + }, 1000); + + return () => clearInterval(timer); + }); + + return ; +}; + +export default Page; +``` diff --git a/docs/examples/event.md b/docs/examples/event.md new file mode 100644 index 0000000..110f0cc --- /dev/null +++ b/docs/examples/event.md @@ -0,0 +1,85 @@ +--- +title: Event +order: 4 +--- + +## Event + +```tsx +import React, { useState } from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const option = { + title : { + text: '某站点用户访问来源', + subtext: '纯属虚构', + x:'center' + }, + tooltip : { + trigger: 'item', + formatter: "{a}
{b} : {c} ({d}%)" + }, + legend: { + orient: 'vertical', + left: 'left', + data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎'] + }, + series : [ + { + name: '访问来源', + type: 'pie', + radius : '55%', + center: ['50%', '60%'], + data:[ + {value:335, name:'直接访问'}, + {value:310, name:'邮件营销'}, + {value:234, name:'联盟广告'}, + {value:135, name:'视频广告'}, + {value:1548, name:'搜索引擎'} + ], + itemStyle: { + emphasis: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] + }; + + const [count, setCount] = useState(0); + + function onChartReady(echarts) { + console.log('echarts is ready', echarts); + } + + function onChartClick(param, echarts) { + console.log(param, echarts); + setCount(count + 1); + }; + + function onChartLegendselectchanged(param, echarts) { + console.log(param, echarts); + }; + + return ( + <> + +
Click Count: {count}
+
Open console, see the log detail.
+ + ); +}; + +export default Page; +``` diff --git a/docs/examples/gl.md b/docs/examples/gl.md new file mode 100644 index 0000000..1b000da --- /dev/null +++ b/docs/examples/gl.md @@ -0,0 +1,36 @@ +--- +title: Web GL +order: 7 +--- + +## Web GL + +```tsx +import React from 'react'; +import ReactECharts from 'echarts-for-react'; +import 'echarts-gl'; + +const Page: React.FC = () => { + const option = { + grid3D: {}, + xAxis3D: {}, + yAxis3D: {}, + zAxis3D: {}, + series: [{ + type: 'scatter3D', + symbolSize: 50, + data: [[-1, -1, -1], [0, 0, 0], [1, 1, 1]], + itemStyle: { + opacity: 1 + } + }] + }; + + return ; +}; + +export default Page; +``` diff --git a/docs/examples/graph.md b/docs/examples/graph.md new file mode 100644 index 0000000..4c1639f --- /dev/null +++ b/docs/examples/graph.md @@ -0,0 +1,52 @@ +--- +title: Graph +order: 9 +--- + +## Graph + +```tsx +import React from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const webkitDep = {"type":"force","categories":[{"name":"HTMLElement","keyword":{},"base":"HTMLElement"},{"name":"WebGL","keyword":{},"base":"WebGLRenderingContext"},{"name":"SVG","keyword":{},"base":"SVGElement"},{"name":"CSS","keyword":{},"base":"CSSRule"},{"name":"Other","keyword":{}}],"nodes":[{"name":"AnalyserNode","value":1,"category":4},{"name":"AudioNode","value":1,"category":4},{"name":"Uint8Array","value":1,"category":4},{"name":"Float32Array","value":1,"category":4},{"name":"ArrayBuffer","value":1,"category":4},{"name":"ArrayBufferView","value":1,"category":4},{"name":"Attr","value":1,"category":4},{"name":"Node","value":1,"category":4},{"name":"Element","value":1,"category":4},{"name":"AudioBuffer","value":1,"category":4},{"name":"AudioBufferCallback","value":1,"category":4},{"name":"AudioBufferSourceNode","value":1,"category":4},{"name":"AudioSourceNode","value":1,"category":4},{"name":"AudioGain","value":1,"category":4},{"name":"AudioParam","value":1,"category":4},{"name":"AudioContext","value":1,"category":4},{"name":"AudioDestinationNode","value":1,"category":4},{"name":"AudioListener","value":1,"category":4},{"name":"BiquadFilterNode","value":1,"category":4},{"name":"ChannelMergerNode","value":1,"category":4},{"name":"ChannelSplitterNode","value":1,"category":4},{"name":"ConvolverNode","value":1,"category":4},{"name":"DelayNode","value":1,"category":4},{"name":"DynamicsCompressorNode","value":1,"category":4},{"name":"GainNode","value":1,"category":4},{"name":"MediaElementAudioSourceNode","value":1,"category":4},{"name":"MediaStreamAudioDestinationNode","value":1,"category":4},{"name":"MediaStreamAudioSourceNode","value":1,"category":4},{"name":"OscillatorNode","value":1,"category":4},{"name":"PannerNode","value":1,"category":4},{"name":"ScriptProcessorNode","value":1,"category":4},{"name":"WaveShaperNode","value":1,"category":4},{"name":"WaveTable","value":1,"category":4},{"name":"CanvasRenderingContext","value":1,"category":4},{"name":"HTMLCanvasElement","value":1,"category":0},{"name":"CanvasRenderingContext2D","value":1,"category":4},{"name":"ImageData","value":1,"category":4},{"name":"CanvasGradient","value":1,"category":4},{"name":"CanvasPattern","value":1,"category":4},{"name":"HTMLImageElement","value":1,"category":0},{"name":"HTMLVideoElement","value":1,"category":0},{"name":"TextMetrics","value":1,"category":4},{"name":"CDATASection","value":1,"category":4},{"name":"Text","value":1,"category":4},{"name":"CharacterData","value":1,"category":4},{"name":"ClientRectList","value":1,"category":4},{"name":"ClientRect","value":1,"category":4},{"name":"Clipboard","value":1,"category":4},{"name":"FileList","value":1,"category":4},{"name":"DataTransferItemList","value":1,"category":4},{"name":"Comment","value":1,"category":4},{"name":"Console","value":1,"category":4},{"name":"MemoryInfo","value":1,"category":4},{"name":"Crypto","value":1,"category":4},{"name":"CSSCharsetRule","value":1,"category":3},{"name":"CSSRule","value":3,"category":3},{"name":"CSSFontFaceRule","value":1,"category":3},{"name":"CSSStyleDeclaration","value":1,"category":3},{"name":"CSSImportRule","value":1,"category":3},{"name":"MediaList","value":1,"category":4},{"name":"CSSStyleSheet","value":1,"category":3},{"name":"CSSMediaRule","value":1,"category":3},{"name":"CSSRuleList","value":1,"category":3},{"name":"CSSPageRule","value":1,"category":3},{"name":"CSSPrimitiveValue","value":1,"category":3},{"name":"CSSValue","value":1,"category":3},{"name":"Counter","value":1,"category":4},{"name":"RGBColor","value":1,"category":4},{"name":"Rect","value":1,"category":4},{"name":"CSSStyleRule","value":1,"category":3},{"name":"StyleSheet","value":1,"category":4},{"name":"CSSUnknownRule","value":1,"category":3},{"name":"CSSValueList","value":1,"category":3},{"name":"Database","value":1,"category":4},{"name":"SQLTransactionCallback","value":1,"category":4},{"name":"DatabaseCallback","value":1,"category":4},{"name":"DatabaseSync","value":1,"category":4},{"name":"SQLTransactionSyncCallback","value":1,"category":4},{"name":"DataTransferItem","value":1,"category":4},{"name":"StringCallback","value":1,"category":4},{"name":"Entry","value":1,"category":4},{"name":"File","value":1,"category":4},{"name":"DataView","value":1,"category":4},{"name":"DedicatedWorkerContext","value":1,"category":4},{"name":"WorkerContext","value":1,"category":4},{"name":"DirectoryEntry","value":1,"category":4},{"name":"DirectoryReader","value":1,"category":4},{"name":"VoidCallback","value":1,"category":4},{"name":"DirectoryEntrySync","value":1,"category":4},{"name":"EntrySync","value":1,"category":4},{"name":"DirectoryReaderSync","value":1,"category":4},{"name":"FileEntrySync","value":1,"category":4},{"name":"EntriesCallback","value":1,"category":4},{"name":"EntryArraySync","value":1,"category":4},{"name":"DocumentFragment","value":1,"category":4},{"name":"NodeList","value":1,"category":4},{"name":"DocumentType","value":1,"category":4},{"name":"NamedNodeMap","value":1,"category":4},{"name":"DOMFileSystem","value":1,"category":4},{"name":"DOMFileSystemSync","value":1,"category":4},{"name":"DOMImplementation","value":1,"category":4},{"name":"HTMLDocument","value":1,"category":0},{"name":"DOMMimeType","value":1,"category":4},{"name":"DOMPlugin","value":1,"category":4},{"name":"DOMMimeTypeArray","value":1,"category":4},{"name":"DOMPluginArray","value":1,"category":4},{"name":"DOMSelection","value":1,"category":4},{"name":"Range","value":1,"category":4},{"name":"DOMSettableTokenList","value":1,"category":4},{"name":"DOMTokenList","value":1,"category":4},{"name":"DOMStringMap","value":1,"category":4},{"name":"ShadowRoot","value":1,"category":4},{"name":"Entity","value":1,"category":4},{"name":"EntityReference","value":1,"category":4},{"name":"EntryArray","value":1,"category":4},{"name":"MetadataCallback","value":1,"category":4},{"name":"EntryCallback","value":1,"category":4},{"name":"Metadata","value":1,"category":4},{"name":"ErrorCallback","value":1,"category":4},{"name":"FileError","value":1,"category":4},{"name":"FileCallback","value":1,"category":4},{"name":"FileEntry","value":1,"category":4},{"name":"FileWriterCallback","value":1,"category":4},{"name":"FileWriterSync","value":1,"category":4},{"name":"FileReader","value":1,"category":4},{"name":"FileReaderSync","value":1,"category":4},{"name":"FileSystemCallback","value":1,"category":4},{"name":"FileWriter","value":1,"category":4},{"name":"Float64Array","value":1,"category":4},{"name":"GamepadList","value":1,"category":4},{"name":"Gamepad","value":1,"category":4},{"name":"Geolocation","value":1,"category":4},{"name":"PositionCallback","value":1,"category":4},{"name":"Geoposition","value":1,"category":4},{"name":"Coordinates","value":1,"category":4},{"name":"HTMLAllCollection","value":1,"category":0},{"name":"HTMLAnchorElement","value":1,"category":0},{"name":"HTMLElement","value":3,"category":0},{"name":"HTMLAppletElement","value":1,"category":0},{"name":"HTMLAreaElement","value":1,"category":0},{"name":"HTMLAudioElement","value":1,"category":0},{"name":"HTMLMediaElement","value":1,"category":0},{"name":"HTMLBaseElement","value":1,"category":0},{"name":"HTMLBaseFontElement","value":1,"category":0},{"name":"HTMLBodyElement","value":1,"category":0},{"name":"HTMLBRElement","value":1,"category":0},{"name":"HTMLButtonElement","value":1,"category":0},{"name":"HTMLFormElement","value":1,"category":0},{"name":"ValidityState","value":1,"category":4},{"name":"HTMLCollection","value":1,"category":0},{"name":"HTMLContentElement","value":1,"category":0},{"name":"HTMLDataListElement","value":1,"category":0},{"name":"HTMLDetailsElement","value":1,"category":0},{"name":"HTMLDirectoryElement","value":1,"category":0},{"name":"HTMLDivElement","value":1,"category":0},{"name":"HTMLDListElement","value":1,"category":0},{"name":"HTMLEmbedElement","value":1,"category":0},{"name":"SVGDocument","value":1,"category":2},{"name":"HTMLFieldSetElement","value":1,"category":0},{"name":"HTMLFontElement","value":1,"category":0},{"name":"HTMLFormControlsCollection","value":1,"category":0},{"name":"HTMLFrameElement","value":1,"category":0},{"name":"HTMLFrameSetElement","value":1,"category":0},{"name":"HTMLHeadElement","value":1,"category":0},{"name":"HTMLHeadingElement","value":1,"category":0},{"name":"HTMLHRElement","value":1,"category":0},{"name":"HTMLHtmlElement","value":1,"category":0},{"name":"HTMLIFrameElement","value":1,"category":0},{"name":"HTMLInputElement","value":1,"category":0},{"name":"HTMLKeygenElement","value":1,"category":0},{"name":"HTMLLabelElement","value":1,"category":0},{"name":"HTMLLegendElement","value":1,"category":0},{"name":"HTMLLIElement","value":1,"category":0},{"name":"HTMLLinkElement","value":1,"category":0},{"name":"HTMLMapElement","value":1,"category":0},{"name":"HTMLMarqueeElement","value":1,"category":0},{"name":"TimeRanges","value":1,"category":4},{"name":"MediaController","value":1,"category":4},{"name":"MediaError","value":1,"category":4},{"name":"TextTrackList","value":1,"category":4},{"name":"TextTrack","value":1,"category":4},{"name":"HTMLMenuElement","value":1,"category":0},{"name":"HTMLMetaElement","value":1,"category":0},{"name":"HTMLMeterElement","value":1,"category":0},{"name":"HTMLModElement","value":1,"category":0},{"name":"HTMLObjectElement","value":1,"category":0},{"name":"HTMLOListElement","value":1,"category":0},{"name":"HTMLOptGroupElement","value":1,"category":0},{"name":"HTMLOptionElement","value":1,"category":0},{"name":"HTMLOptionsCollection","value":1,"category":0},{"name":"HTMLOutputElement","value":1,"category":0},{"name":"HTMLParagraphElement","value":1,"category":0},{"name":"HTMLParamElement","value":1,"category":0},{"name":"HTMLPreElement","value":1,"category":0},{"name":"HTMLProgressElement","value":1,"category":0},{"name":"HTMLQuoteElement","value":1,"category":0},{"name":"HTMLScriptElement","value":1,"category":0},{"name":"HTMLSelectElement","value":1,"category":0},{"name":"HTMLShadowElement","value":1,"category":0},{"name":"HTMLSourceElement","value":1,"category":0},{"name":"HTMLSpanElement","value":1,"category":0},{"name":"HTMLStyleElement","value":1,"category":0},{"name":"HTMLTableCaptionElement","value":1,"category":0},{"name":"HTMLTableCellElement","value":1,"category":0},{"name":"HTMLTableColElement","value":1,"category":0},{"name":"HTMLTableElement","value":1,"category":0},{"name":"HTMLTableSectionElement","value":1,"category":0},{"name":"HTMLTableRowElement","value":1,"category":0},{"name":"HTMLTextAreaElement","value":1,"category":0},{"name":"HTMLTitleElement","value":1,"category":0},{"name":"HTMLTrackElement","value":1,"category":0},{"name":"HTMLUListElement","value":1,"category":0},{"name":"HTMLUnknownElement","value":1,"category":0},{"name":"IDBCursor","value":1,"category":4},{"name":"IDBAny","value":1,"category":4},{"name":"IDBKey","value":1,"category":4},{"name":"IDBRequest","value":1,"category":4},{"name":"IDBCursorWithValue","value":1,"category":4},{"name":"IDBDatabase","value":1,"category":4},{"name":"DOMStringList","value":1,"category":4},{"name":"IDBObjectStore","value":1,"category":4},{"name":"IDBTransaction","value":1,"category":4},{"name":"IDBFactory","value":1,"category":4},{"name":"IDBVersionChangeRequest","value":1,"category":4},{"name":"IDBOpenDBRequest","value":1,"category":4},{"name":"IDBIndex","value":1,"category":4},{"name":"IDBKeyRange","value":1,"category":4},{"name":"DOMError","value":1,"category":4},{"name":"Int16Array","value":1,"category":4},{"name":"Int32Array","value":1,"category":4},{"name":"Int8Array","value":1,"category":4},{"name":"JavaScriptCallFrame","value":1,"category":4},{"name":"LocalMediaStream","value":1,"category":4},{"name":"MediaStream","value":1,"category":4},{"name":"Location","value":1,"category":4},{"name":"MediaQueryList","value":1,"category":4},{"name":"MediaQueryListListener","value":1,"category":4},{"name":"MediaSource","value":1,"category":4},{"name":"SourceBufferList","value":1,"category":4},{"name":"SourceBuffer","value":1,"category":4},{"name":"MediaStreamTrackList","value":1,"category":4},{"name":"MediaStreamList","value":1,"category":4},{"name":"MediaStreamTrack","value":1,"category":4},{"name":"MessageChannel","value":1,"category":4},{"name":"MessagePort","value":1,"category":4},{"name":"MutationObserver","value":1,"category":4},{"name":"MutationRecord","value":1,"category":4},{"name":"Navigator","value":1,"category":4},{"name":"BatteryManager","value":1,"category":4},{"name":"NavigatorUserMediaErrorCallback","value":1,"category":4},{"name":"NavigatorUserMediaError","value":1,"category":4},{"name":"NavigatorUserMediaSuccessCallback","value":1,"category":4},{"name":"NodeFilter","value":1,"category":4},{"name":"NodeIterator","value":1,"category":4},{"name":"Notation","value":1,"category":4},{"name":"Notification","value":1,"category":4},{"name":"NotificationPermissionCallback","value":1,"category":4},{"name":"NotificationCenter","value":1,"category":4},{"name":"OESVertexArrayObject","value":1,"category":4},{"name":"WebGLVertexArrayObjectOES","value":1,"category":1},{"name":"Performance","value":1,"category":4},{"name":"PerformanceNavigation","value":1,"category":4},{"name":"PerformanceTiming","value":1,"category":4},{"name":"PositionErrorCallback","value":1,"category":4},{"name":"PositionError","value":1,"category":4},{"name":"ProcessingInstruction","value":1,"category":4},{"name":"RadioNodeList","value":1,"category":4},{"name":"RTCDataChannel","value":1,"category":4},{"name":"RTCPeerConnection","value":1,"category":4},{"name":"RTCSessionDescription","value":1,"category":4},{"name":"RTCIceCandidate","value":1,"category":4},{"name":"RTCSessionDescriptionCallback","value":1,"category":4},{"name":"RTCStatsCallback","value":1,"category":4},{"name":"RTCStatsResponse","value":1,"category":4},{"name":"RTCStatsReport","value":1,"category":4},{"name":"RTCStatsElement","value":1,"category":4},{"name":"ScriptProfile","value":1,"category":4},{"name":"ScriptProfileNode","value":1,"category":4},{"name":"SharedWorker","value":1,"category":4},{"name":"AbstractWorker","value":1,"category":4},{"name":"SharedWorkerContext","value":1,"category":4},{"name":"SpeechGrammarList","value":1,"category":4},{"name":"SpeechGrammar","value":1,"category":4},{"name":"SpeechInputResultList","value":1,"category":4},{"name":"SpeechInputResult","value":1,"category":4},{"name":"SpeechRecognition","value":1,"category":4},{"name":"SpeechRecognitionResult","value":1,"category":4},{"name":"SpeechRecognitionAlternative","value":1,"category":4},{"name":"SpeechRecognitionResultList","value":1,"category":4},{"name":"SQLResultSet","value":1,"category":4},{"name":"SQLResultSetRowList","value":1,"category":4},{"name":"SQLStatementCallback","value":1,"category":4},{"name":"SQLTransaction","value":1,"category":4},{"name":"SQLStatementErrorCallback","value":1,"category":4},{"name":"SQLTransactionErrorCallback","value":1,"category":4},{"name":"SQLError","value":1,"category":4},{"name":"SQLTransactionSync","value":1,"category":4},{"name":"StorageInfo","value":1,"category":4},{"name":"StorageInfoUsageCallback","value":1,"category":4},{"name":"StorageInfoQuotaCallback","value":1,"category":4},{"name":"StorageInfoErrorCallback","value":1,"category":4},{"name":"DOMCoreException","value":1,"category":4},{"name":"StyleSheetList","value":1,"category":4},{"name":"SVGAElement","value":1,"category":2},{"name":"SVGTransformable","value":1,"category":2},{"name":"SVGAnimatedString","value":1,"category":2},{"name":"SVGAltGlyphDefElement","value":1,"category":2},{"name":"SVGElement","value":3,"category":2},{"name":"SVGAltGlyphElement","value":1,"category":2},{"name":"SVGURIReference","value":1,"category":2},{"name":"SVGAltGlyphItemElement","value":1,"category":2},{"name":"SVGAnimateColorElement","value":1,"category":2},{"name":"SVGAnimationElement","value":1,"category":2},{"name":"SVGAnimatedAngle","value":1,"category":2},{"name":"SVGAngle","value":1,"category":2},{"name":"SVGAnimatedLength","value":1,"category":2},{"name":"SVGLength","value":1,"category":2},{"name":"SVGAnimatedLengthList","value":1,"category":2},{"name":"SVGLengthList","value":1,"category":2},{"name":"SVGAnimatedNumberList","value":1,"category":2},{"name":"SVGNumberList","value":1,"category":2},{"name":"SVGAnimatedPreserveAspectRatio","value":1,"category":2},{"name":"SVGPreserveAspectRatio","value":1,"category":2},{"name":"SVGAnimatedRect","value":1,"category":2},{"name":"SVGRect","value":1,"category":2},{"name":"SVGAnimatedTransformList","value":1,"category":2},{"name":"SVGTransformList","value":1,"category":2},{"name":"SVGAnimateElement","value":1,"category":2},{"name":"SVGAnimateMotionElement","value":1,"category":2},{"name":"SVGAnimateTransformElement","value":1,"category":2},{"name":"ElementTimeControl","value":1,"category":4},{"name":"SVGCircleElement","value":1,"category":2},{"name":"SVGClipPathElement","value":1,"category":2},{"name":"SVGAnimatedEnumeration","value":1,"category":2},{"name":"SVGColor","value":1,"category":2},{"name":"SVGComponentTransferFunctionElement","value":1,"category":2},{"name":"SVGAnimatedNumber","value":1,"category":2},{"name":"SVGCursorElement","value":1,"category":2},{"name":"SVGExternalResourcesRequired","value":1,"category":2},{"name":"SVGDefsElement","value":1,"category":2},{"name":"SVGDescElement","value":1,"category":2},{"name":"SVGStylable","value":1,"category":2},{"name":"SVGSVGElement","value":1,"category":2},{"name":"SVGElementInstance","value":1,"category":2},{"name":"EventTarget","value":1,"category":4},{"name":"SVGElementInstanceList","value":1,"category":2},{"name":"SVGUseElement","value":1,"category":2},{"name":"SVGEllipseElement","value":1,"category":2},{"name":"SVGAnimatedBoolean","value":1,"category":2},{"name":"SVGFEBlendElement","value":1,"category":2},{"name":"SVGFilterPrimitiveStandardAttributes","value":1,"category":2},{"name":"SVGFEColorMatrixElement","value":1,"category":2},{"name":"SVGFEComponentTransferElement","value":1,"category":2},{"name":"SVGFECompositeElement","value":1,"category":2},{"name":"SVGFEConvolveMatrixElement","value":1,"category":2},{"name":"SVGAnimatedInteger","value":1,"category":2},{"name":"SVGFEDiffuseLightingElement","value":1,"category":2},{"name":"SVGFEDisplacementMapElement","value":1,"category":2},{"name":"SVGFEDistantLightElement","value":1,"category":2},{"name":"SVGFEDropShadowElement","value":1,"category":2},{"name":"SVGFEFloodElement","value":1,"category":2},{"name":"SVGFEFuncAElement","value":1,"category":2},{"name":"SVGFEFuncBElement","value":1,"category":2},{"name":"SVGFEFuncGElement","value":1,"category":2},{"name":"SVGFEFuncRElement","value":1,"category":2},{"name":"SVGFEGaussianBlurElement","value":1,"category":2},{"name":"SVGFEImageElement","value":1,"category":2},{"name":"SVGFEMergeElement","value":1,"category":2},{"name":"SVGFEMergeNodeElement","value":1,"category":2},{"name":"SVGFEMorphologyElement","value":1,"category":2},{"name":"SVGFEOffsetElement","value":1,"category":2},{"name":"SVGFEPointLightElement","value":1,"category":2},{"name":"SVGFESpecularLightingElement","value":1,"category":2},{"name":"SVGFESpotLightElement","value":1,"category":2},{"name":"SVGFETileElement","value":1,"category":2},{"name":"SVGFETurbulenceElement","value":1,"category":2},{"name":"SVGFilterElement","value":1,"category":2},{"name":"SVGFitToViewBox","value":1,"category":2},{"name":"SVGFontElement","value":1,"category":2},{"name":"SVGFontFaceElement","value":1,"category":2},{"name":"SVGFontFaceFormatElement","value":1,"category":2},{"name":"SVGFontFaceNameElement","value":1,"category":2},{"name":"SVGFontFaceSrcElement","value":1,"category":2},{"name":"SVGFontFaceUriElement","value":1,"category":2},{"name":"SVGForeignObjectElement","value":1,"category":2},{"name":"SVGGElement","value":1,"category":2},{"name":"SVGGlyphElement","value":1,"category":2},{"name":"SVGGlyphRefElement","value":1,"category":2},{"name":"SVGGradientElement","value":1,"category":2},{"name":"SVGHKernElement","value":1,"category":2},{"name":"SVGImageElement","value":1,"category":2},{"name":"SVGLinearGradientElement","value":1,"category":2},{"name":"SVGLineElement","value":1,"category":2},{"name":"SVGLocatable","value":1,"category":2},{"name":"SVGMatrix","value":1,"category":2},{"name":"SVGMarkerElement","value":1,"category":2},{"name":"SVGMaskElement","value":1,"category":2},{"name":"SVGMetadataElement","value":1,"category":2},{"name":"SVGMissingGlyphElement","value":1,"category":2},{"name":"SVGMPathElement","value":1,"category":2},{"name":"SVGNumber","value":1,"category":2},{"name":"SVGPaint","value":1,"category":2},{"name":"SVGPathElement","value":1,"category":2},{"name":"SVGPathSegList","value":1,"category":2},{"name":"SVGPathSegArcAbs","value":1,"category":2},{"name":"SVGPathSegArcRel","value":1,"category":2},{"name":"SVGPathSegClosePath","value":1,"category":2},{"name":"SVGPathSegCurvetoCubicAbs","value":1,"category":2},{"name":"SVGPathSegCurvetoCubicRel","value":1,"category":2},{"name":"SVGPathSegCurvetoCubicSmoothAbs","value":1,"category":2},{"name":"SVGPathSegCurvetoCubicSmoothRel","value":1,"category":2},{"name":"SVGPathSegCurvetoQuadraticAbs","value":1,"category":2},{"name":"SVGPathSegCurvetoQuadraticRel","value":1,"category":2},{"name":"SVGPathSegCurvetoQuadraticSmoothAbs","value":1,"category":2},{"name":"SVGPathSegCurvetoQuadraticSmoothRel","value":1,"category":2},{"name":"SVGPathSegLinetoAbs","value":1,"category":2},{"name":"SVGPathSegLinetoHorizontalAbs","value":1,"category":2},{"name":"SVGPathSegLinetoHorizontalRel","value":1,"category":2},{"name":"SVGPathSegLinetoRel","value":1,"category":2},{"name":"SVGPathSegLinetoVerticalAbs","value":1,"category":2},{"name":"SVGPathSegLinetoVerticalRel","value":1,"category":2},{"name":"SVGPathSegMovetoAbs","value":1,"category":2},{"name":"SVGPathSegMovetoRel","value":1,"category":2},{"name":"SVGPoint","value":1,"category":2},{"name":"SVGPathSeg","value":1,"category":2},{"name":"SVGPatternElement","value":1,"category":2},{"name":"SVGPointList","value":1,"category":2},{"name":"SVGPolygonElement","value":1,"category":2},{"name":"SVGPolylineElement","value":1,"category":2},{"name":"SVGRadialGradientElement","value":1,"category":2},{"name":"SVGRectElement","value":1,"category":2},{"name":"SVGScriptElement","value":1,"category":2},{"name":"SVGSetElement","value":1,"category":2},{"name":"SVGStopElement","value":1,"category":2},{"name":"SVGStyleElement","value":1,"category":2},{"name":"SVGLangSpace","value":1,"category":2},{"name":"SVGZoomAndPan","value":1,"category":2},{"name":"SVGViewSpec","value":1,"category":2},{"name":"SVGTransform","value":1,"category":2},{"name":"SVGSwitchElement","value":1,"category":2},{"name":"SVGSymbolElement","value":1,"category":2},{"name":"SVGTests","value":1,"category":2},{"name":"SVGStringList","value":1,"category":2},{"name":"SVGTextContentElement","value":1,"category":2},{"name":"SVGTextElement","value":1,"category":2},{"name":"SVGTextPathElement","value":1,"category":2},{"name":"SVGTextPositioningElement","value":1,"category":2},{"name":"SVGTitleElement","value":1,"category":2},{"name":"SVGTRefElement","value":1,"category":2},{"name":"SVGTSpanElement","value":1,"category":2},{"name":"SVGViewElement","value":1,"category":2},{"name":"SVGVKernElement","value":1,"category":2},{"name":"TextTrackCueList","value":1,"category":4},{"name":"TextTrackCue","value":1,"category":4},{"name":"Touch","value":1,"category":4},{"name":"TouchList","value":1,"category":4},{"name":"TreeWalker","value":1,"category":4},{"name":"Uint16Array","value":1,"category":4},{"name":"Uint32Array","value":1,"category":4},{"name":"Uint8ClampedArray","value":1,"category":4},{"name":"WebGLRenderingContext","value":3,"category":1},{"name":"WebGLProgram","value":1,"category":1},{"name":"WebGLBuffer","value":1,"category":1},{"name":"WebGLFramebuffer","value":1,"category":1},{"name":"WebGLRenderbuffer","value":1,"category":1},{"name":"WebGLTexture","value":1,"category":1},{"name":"WebGLShader","value":1,"category":1},{"name":"WebGLActiveInfo","value":1,"category":1},{"name":"WebGLContextAttributes","value":1,"category":1},{"name":"WebGLShaderPrecisionFormat","value":1,"category":1},{"name":"WebGLUniformLocation","value":1,"category":1},{"name":"WebKitAnimationList","value":1,"category":4},{"name":"WebKitAnimation","value":1,"category":4},{"name":"WebKitCSSFilterValue","value":1,"category":4},{"name":"WebKitCSSKeyframeRule","value":1,"category":4},{"name":"WebKitCSSKeyframesRule","value":1,"category":4},{"name":"WebKitCSSMatrix","value":1,"category":4},{"name":"WebKitCSSMixFunctionValue","value":1,"category":4},{"name":"WebKitCSSTransformValue","value":1,"category":4},{"name":"WebKitNamedFlow","value":1,"category":4},{"name":"WebSocket","value":1,"category":4},{"name":"Worker","value":1,"category":4},{"name":"WorkerLocation","value":1,"category":4},{"name":"WorkerNavigator","value":1,"category":4},{"name":"XMLHttpRequest","value":1,"category":4},{"name":"XMLHttpRequestUpload","value":1,"category":4},{"name":"DOMFormData","value":1,"category":4},{"name":"XPathEvaluator","value":1,"category":4},{"name":"XPathExpression","value":1,"category":4},{"name":"XPathNSResolver","value":1,"category":4},{"name":"XPathResult","value":1,"category":4},{"name":"XSLTProcessor","value":1,"category":4}],"links":[{"source":0,"target":1},{"source":0,"target":2},{"source":0,"target":3},{"source":4,"target":4},{"source":5,"target":4},{"source":6,"target":7},{"source":6,"target":8},{"source":9,"target":3},{"source":10,"target":9},{"source":11,"target":12},{"source":11,"target":9},{"source":11,"target":13},{"source":11,"target":14},{"source":15,"target":16},{"source":15,"target":17},{"source":15,"target":0},{"source":15,"target":18},{"source":15,"target":9},{"source":15,"target":11},{"source":15,"target":19},{"source":15,"target":20},{"source":15,"target":21},{"source":15,"target":22},{"source":15,"target":23},{"source":15,"target":24},{"source":15,"target":25},{"source":15,"target":26},{"source":15,"target":27},{"source":15,"target":28},{"source":15,"target":29},{"source":15,"target":30},{"source":15,"target":31},{"source":15,"target":32},{"source":15,"target":4},{"source":16,"target":1},{"source":13,"target":14},{"source":1,"target":15},{"source":1,"target":1},{"source":1,"target":14},{"source":14,"target":3},{"source":12,"target":1},{"source":18,"target":1},{"source":18,"target":14},{"source":18,"target":3},{"source":33,"target":34},{"source":35,"target":33},{"source":35,"target":36},{"source":35,"target":37},{"source":35,"target":38},{"source":35,"target":39},{"source":35,"target":34},{"source":35,"target":40},{"source":35,"target":41},{"source":42,"target":43},{"source":19,"target":1},{"source":20,"target":1},{"source":44,"target":7},{"source":45,"target":46},{"source":47,"target":48},{"source":47,"target":49},{"source":47,"target":39},{"source":50,"target":44},{"source":51,"target":52},{"source":21,"target":1},{"source":21,"target":9},{"source":53,"target":5},{"source":54,"target":55},{"source":56,"target":55},{"source":56,"target":57},{"source":58,"target":55},{"source":58,"target":59},{"source":58,"target":60},{"source":61,"target":55},{"source":61,"target":62},{"source":61,"target":59},{"source":63,"target":55},{"source":63,"target":57},{"source":64,"target":65},{"source":64,"target":66},{"source":64,"target":67},{"source":64,"target":68},{"source":55,"target":55},{"source":55,"target":60},{"source":62,"target":55},{"source":57,"target":55},{"source":57,"target":65},{"source":69,"target":55},{"source":69,"target":57},{"source":60,"target":70},{"source":60,"target":62},{"source":60,"target":55},{"source":71,"target":55},{"source":72,"target":65},{"source":73,"target":74},{"source":75,"target":73},{"source":75,"target":76},{"source":76,"target":77},{"source":78,"target":79},{"source":78,"target":80},{"source":49,"target":81},{"source":49,"target":78},{"source":82,"target":5},{"source":83,"target":84},{"source":22,"target":1},{"source":22,"target":14},{"source":85,"target":80},{"source":85,"target":86},{"source":85,"target":87},{"source":88,"target":89},{"source":88,"target":90},{"source":88,"target":88},{"source":88,"target":91},{"source":86,"target":92},{"source":90,"target":93},{"source":94,"target":7},{"source":94,"target":8},{"source":94,"target":95},{"source":96,"target":7},{"source":96,"target":97},{"source":98,"target":85},{"source":99,"target":88},{"source":100,"target":60},{"source":100,"target":96},{"source":100,"target":101},{"source":102,"target":103},{"source":104,"target":102},{"source":103,"target":102},{"source":105,"target":103},{"source":106,"target":7},{"source":106,"target":107},{"source":108,"target":109},{"source":23,"target":1},{"source":23,"target":14},{"source":8,"target":7},{"source":8,"target":109},{"source":8,"target":110},{"source":8,"target":8},{"source":8,"target":57},{"source":8,"target":6},{"source":8,"target":46},{"source":8,"target":45},{"source":8,"target":95},{"source":8,"target":111},{"source":112,"target":7},{"source":113,"target":7},{"source":92,"target":114},{"source":80,"target":98},{"source":80,"target":85},{"source":80,"target":115},{"source":80,"target":116},{"source":80,"target":87},{"source":114,"target":80},{"source":93,"target":89},{"source":116,"target":80},{"source":89,"target":99},{"source":89,"target":89},{"source":89,"target":117},{"source":89,"target":88},{"source":118,"target":119},{"source":120,"target":81},{"source":121,"target":80},{"source":121,"target":122},{"source":121,"target":120},{"source":91,"target":89},{"source":91,"target":123},{"source":91,"target":81},{"source":48,"target":81},{"source":124,"target":119},{"source":125,"target":4},{"source":126,"target":98},{"source":127,"target":119},{"source":122,"target":127},{"source":3,"target":5},{"source":3,"target":3},{"source":128,"target":5},{"source":128,"target":128},{"source":24,"target":1},{"source":24,"target":13},{"source":129,"target":130},{"source":131,"target":132},{"source":133,"target":134},{"source":135,"target":7},{"source":135,"target":95},{"source":136,"target":137},{"source":138,"target":137},{"source":139,"target":137},{"source":140,"target":141},{"source":142,"target":137},{"source":143,"target":137},{"source":144,"target":137},{"source":145,"target":137},{"source":146,"target":137},{"source":146,"target":147},{"source":146,"target":95},{"source":146,"target":148},{"source":34,"target":137},{"source":149,"target":7},{"source":150,"target":137},{"source":150,"target":95},{"source":151,"target":137},{"source":151,"target":149},{"source":152,"target":137},{"source":153,"target":137},{"source":154,"target":137},{"source":155,"target":137},{"source":101,"target":8},{"source":101,"target":135},{"source":101,"target":149},{"source":137,"target":8},{"source":137,"target":149},{"source":156,"target":137},{"source":156,"target":157},{"source":158,"target":137},{"source":158,"target":149},{"source":158,"target":147},{"source":158,"target":148},{"source":159,"target":137},{"source":160,"target":149},{"source":160,"target":7},{"source":147,"target":137},{"source":147,"target":149},{"source":161,"target":137},{"source":161,"target":157},{"source":162,"target":137},{"source":163,"target":137},{"source":164,"target":137},{"source":165,"target":137},{"source":166,"target":137},{"source":167,"target":137},{"source":167,"target":157},{"source":39,"target":137},{"source":168,"target":137},{"source":168,"target":48},{"source":168,"target":147},{"source":168,"target":95},{"source":168,"target":148},{"source":168,"target":114},{"source":169,"target":137},{"source":169,"target":147},{"source":169,"target":95},{"source":169,"target":148},{"source":170,"target":137},{"source":170,"target":147},{"source":171,"target":137},{"source":171,"target":147},{"source":172,"target":137},{"source":173,"target":137},{"source":173,"target":70},{"source":173,"target":108},{"source":174,"target":137},{"source":174,"target":149},{"source":175,"target":137},{"source":141,"target":137},{"source":141,"target":176},{"source":141,"target":177},{"source":141,"target":178},{"source":141,"target":179},{"source":141,"target":180},{"source":181,"target":137},{"source":182,"target":137},{"source":183,"target":137},{"source":183,"target":95},{"source":184,"target":137},{"source":185,"target":137},{"source":185,"target":147},{"source":185,"target":148},{"source":185,"target":157},{"source":186,"target":137},{"source":187,"target":137},{"source":188,"target":137},{"source":188,"target":147},{"source":189,"target":149},{"source":189,"target":188},{"source":189,"target":7},{"source":190,"target":137},{"source":190,"target":147},{"source":190,"target":108},{"source":190,"target":95},{"source":190,"target":148},{"source":191,"target":137},{"source":192,"target":137},{"source":193,"target":137},{"source":194,"target":137},{"source":194,"target":95},{"source":195,"target":137},{"source":196,"target":137},{"source":197,"target":137},{"source":197,"target":147},{"source":197,"target":95},{"source":197,"target":189},{"source":197,"target":149},{"source":197,"target":148},{"source":197,"target":7},{"source":198,"target":137},{"source":199,"target":137},{"source":200,"target":137},{"source":201,"target":137},{"source":201,"target":70},{"source":202,"target":137},{"source":203,"target":137},{"source":204,"target":137},{"source":205,"target":137},{"source":205,"target":202},{"source":205,"target":149},{"source":205,"target":206},{"source":207,"target":137},{"source":207,"target":149},{"source":206,"target":137},{"source":206,"target":149},{"source":208,"target":137},{"source":208,"target":147},{"source":208,"target":95},{"source":208,"target":148},{"source":209,"target":137},{"source":210,"target":137},{"source":210,"target":180},{"source":211,"target":137},{"source":212,"target":137},{"source":40,"target":141},{"source":213,"target":214},{"source":213,"target":215},{"source":213,"target":216},{"source":217,"target":213},{"source":218,"target":219},{"source":218,"target":214},{"source":218,"target":220},{"source":218,"target":221},{"source":222,"target":215},{"source":222,"target":223},{"source":222,"target":224},{"source":222,"target":216},{"source":225,"target":214},{"source":225,"target":220},{"source":225,"target":216},{"source":226,"target":215},{"source":226,"target":226},{"source":220,"target":219},{"source":220,"target":214},{"source":220,"target":221},{"source":220,"target":216},{"source":220,"target":225},{"source":224,"target":216},{"source":216,"target":227},{"source":216,"target":214},{"source":216,"target":221},{"source":221,"target":218},{"source":221,"target":227},{"source":221,"target":220},{"source":223,"target":216},{"source":228,"target":5},{"source":228,"target":228},{"source":229,"target":5},{"source":229,"target":229},{"source":230,"target":5},{"source":230,"target":230},{"source":231,"target":231},{"source":232,"target":233},{"source":234,"target":219},{"source":177,"target":176},{"source":25,"target":12},{"source":25,"target":141},{"source":235,"target":236},{"source":236,"target":235},{"source":237,"target":238},{"source":237,"target":239},{"source":233,"target":240},{"source":26,"target":12},{"source":26,"target":233},{"source":27,"target":12},{"source":27,"target":233},{"source":241,"target":233},{"source":240,"target":242},{"source":243,"target":244},{"source":115,"target":117},{"source":245,"target":7},{"source":246,"target":95},{"source":246,"target":7},{"source":97,"target":7},{"source":247,"target":131},{"source":247,"target":104},{"source":247,"target":105},{"source":247,"target":248},{"source":247,"target":129},{"source":249,"target":250},{"source":251,"target":232},{"source":7,"target":97},{"source":7,"target":95},{"source":7,"target":7},{"source":7,"target":8},{"source":252,"target":7},{"source":253,"target":252},{"source":253,"target":7},{"source":95,"target":7},{"source":254,"target":7},{"source":255,"target":256},{"source":257,"target":255},{"source":257,"target":87},{"source":258,"target":259},{"source":28,"target":12},{"source":28,"target":14},{"source":28,"target":32},{"source":29,"target":1},{"source":260,"target":52},{"source":260,"target":261},{"source":260,"target":262},{"source":132,"target":133},{"source":263,"target":264},{"source":265,"target":7},{"source":265,"target":70},{"source":266,"target":95},{"source":107,"target":7},{"source":107,"target":94},{"source":107,"target":107},{"source":107,"target":46},{"source":107,"target":45},{"source":68,"target":64},{"source":67,"target":64},{"source":267,"target":4},{"source":267,"target":5},{"source":268,"target":269},{"source":268,"target":241},{"source":268,"target":270},{"source":268,"target":233},{"source":268,"target":271},{"source":268,"target":267},{"source":268,"target":272},{"source":271,"target":269},{"source":272,"target":273},{"source":274,"target":275},{"source":30,"target":1},{"source":276,"target":277},{"source":111,"target":94},{"source":111,"target":8},{"source":111,"target":7},{"source":111,"target":95},{"source":111,"target":106},{"source":278,"target":279},{"source":278,"target":244},{"source":280,"target":84},{"source":239,"target":176},{"source":239,"target":2},{"source":238,"target":239},{"source":281,"target":282},{"source":283,"target":284},{"source":285,"target":281},{"source":286,"target":287},{"source":288,"target":286},{"source":289,"target":290},{"source":291,"target":292},{"source":293,"target":292},{"source":74,"target":292},{"source":294,"target":295},{"source":296,"target":289},{"source":77,"target":296},{"source":297,"target":298},{"source":297,"target":299},{"source":300,"target":301},{"source":70,"target":59},{"source":70,"target":7},{"source":70,"target":70},{"source":302,"target":70},{"source":303,"target":304},{"source":303,"target":305},{"source":306,"target":307},{"source":308,"target":309},{"source":310,"target":307},{"source":311,"target":312},{"source":313,"target":314},{"source":315,"target":316},{"source":317,"target":318},{"source":319,"target":320},{"source":321,"target":322},{"source":323,"target":324},{"source":325,"target":326},{"source":327,"target":312},{"source":328,"target":312},{"source":329,"target":312},{"source":312,"target":330},{"source":312,"target":307},{"source":331,"target":304},{"source":331,"target":315},{"source":332,"target":304},{"source":332,"target":333},{"source":334,"target":65},{"source":334,"target":67},{"source":335,"target":307},{"source":335,"target":336},{"source":335,"target":319},{"source":335,"target":333},{"source":337,"target":338},{"source":337,"target":315},{"source":339,"target":304},{"source":340,"target":341},{"source":157,"target":342},{"source":307,"target":8},{"source":307,"target":342},{"source":307,"target":307},{"source":343,"target":344},{"source":343,"target":345},{"source":343,"target":307},{"source":343,"target":346},{"source":343,"target":343},{"source":345,"target":343},{"source":347,"target":304},{"source":347,"target":315},{"source":338,"target":348},{"source":349,"target":350},{"source":349,"target":305},{"source":349,"target":333},{"source":351,"target":350},{"source":351,"target":305},{"source":351,"target":333},{"source":351,"target":319},{"source":352,"target":350},{"source":352,"target":305},{"source":353,"target":350},{"source":353,"target":305},{"source":353,"target":336},{"source":353,"target":333},{"source":354,"target":350},{"source":354,"target":336},{"source":354,"target":333},{"source":354,"target":305},{"source":354,"target":319},{"source":354,"target":355},{"source":354,"target":348},{"source":356,"target":350},{"source":356,"target":336},{"source":356,"target":305},{"source":357,"target":350},{"source":357,"target":305},{"source":357,"target":336},{"source":357,"target":333},{"source":358,"target":307},{"source":358,"target":336},{"source":359,"target":350},{"source":359,"target":336},{"source":359,"target":305},{"source":360,"target":350},{"source":361,"target":335},{"source":362,"target":335},{"source":363,"target":335},{"source":364,"target":335},{"source":365,"target":350},{"source":365,"target":305},{"source":365,"target":336},{"source":366,"target":350},{"source":366,"target":321},{"source":367,"target":350},{"source":368,"target":307},{"source":368,"target":305},{"source":369,"target":350},{"source":369,"target":305},{"source":369,"target":333},{"source":369,"target":336},{"source":370,"target":350},{"source":370,"target":336},{"source":370,"target":305},{"source":371,"target":307},{"source":371,"target":336},{"source":372,"target":350},{"source":372,"target":305},{"source":372,"target":336},{"source":373,"target":307},{"source":373,"target":336},{"source":374,"target":350},{"source":374,"target":305},{"source":375,"target":350},{"source":375,"target":336},{"source":375,"target":355},{"source":375,"target":333},{"source":376,"target":341},{"source":376,"target":355},{"source":376,"target":333},{"source":376,"target":315},{"source":350,"target":341},{"source":350,"target":315},{"source":350,"target":305},{"source":377,"target":321},{"source":377,"target":323},{"source":378,"target":307},{"source":379,"target":307},{"source":380,"target":307},{"source":381,"target":307},{"source":382,"target":307},{"source":383,"target":307},{"source":384,"target":304},{"source":384,"target":315},{"source":385,"target":304},{"source":386,"target":307},{"source":387,"target":341},{"source":388,"target":341},{"source":388,"target":325},{"source":388,"target":333},{"source":389,"target":307},{"source":390,"target":304},{"source":390,"target":315},{"source":390,"target":321},{"source":318,"target":316},{"source":391,"target":388},{"source":391,"target":315},{"source":392,"target":304},{"source":392,"target":315},{"source":393,"target":307},{"source":393,"target":324},{"source":393,"target":394},{"source":395,"target":377},{"source":395,"target":315},{"source":395,"target":333},{"source":395,"target":313},{"source":395,"target":314},{"source":396,"target":341},{"source":396,"target":315},{"source":396,"target":333},{"source":394,"target":394},{"source":397,"target":307},{"source":398,"target":307},{"source":399,"target":338},{"source":320,"target":400},{"source":401,"target":334},{"source":402,"target":304},{"source":402,"target":403},{"source":402,"target":336},{"source":402,"target":404},{"source":402,"target":405},{"source":402,"target":406},{"source":402,"target":407},{"source":402,"target":408},{"source":402,"target":409},{"source":402,"target":410},{"source":402,"target":411},{"source":402,"target":412},{"source":402,"target":413},{"source":402,"target":414},{"source":402,"target":415},{"source":402,"target":416},{"source":402,"target":417},{"source":402,"target":418},{"source":402,"target":419},{"source":402,"target":420},{"source":402,"target":421},{"source":402,"target":422},{"source":402,"target":423},{"source":404,"target":424},{"source":405,"target":424},{"source":406,"target":424},{"source":407,"target":424},{"source":408,"target":424},{"source":409,"target":424},{"source":410,"target":424},{"source":411,"target":424},{"source":412,"target":424},{"source":413,"target":424},{"source":414,"target":424},{"source":415,"target":424},{"source":416,"target":424},{"source":417,"target":424},{"source":418,"target":424},{"source":419,"target":424},{"source":420,"target":424},{"source":403,"target":424},{"source":421,"target":424},{"source":422,"target":424},{"source":425,"target":377},{"source":425,"target":315},{"source":425,"target":333},{"source":425,"target":325},{"source":423,"target":423},{"source":426,"target":423},{"source":427,"target":304},{"source":427,"target":426},{"source":428,"target":304},{"source":428,"target":426},{"source":429,"target":388},{"source":429,"target":315},{"source":430,"target":304},{"source":430,"target":315},{"source":431,"target":338},{"source":432,"target":312},{"source":433,"target":341},{"source":433,"target":336},{"source":341,"target":305},{"source":341,"target":57},{"source":341,"target":65},{"source":434,"target":435},{"source":342,"target":436},{"source":342,"target":423},{"source":342,"target":437},{"source":342,"target":315},{"source":342,"target":324},{"source":342,"target":307},{"source":342,"target":314},{"source":342,"target":316},{"source":342,"target":394},{"source":342,"target":400},{"source":342,"target":438},{"source":342,"target":8},{"source":342,"target":95},{"source":439,"target":304},{"source":440,"target":377},{"source":441,"target":442},{"source":443,"target":341},{"source":443,"target":333},{"source":443,"target":315},{"source":443,"target":423},{"source":443,"target":324},{"source":444,"target":304},{"source":445,"target":309},{"source":445,"target":333},{"source":445,"target":315},{"source":446,"target":443},{"source":446,"target":317},{"source":446,"target":319},{"source":447,"target":341},{"source":438,"target":394},{"source":304,"target":393},{"source":304,"target":325},{"source":326,"target":438},{"source":448,"target":309},{"source":449,"target":446},{"source":309,"target":305},{"source":346,"target":304},{"source":346,"target":343},{"source":346,"target":315},{"source":450,"target":436},{"source":450,"target":442},{"source":437,"target":321},{"source":437,"target":326},{"source":437,"target":323},{"source":437,"target":307},{"source":451,"target":307},{"source":43,"target":44},{"source":43,"target":43},{"source":180,"target":452},{"source":180,"target":453},{"source":453,"target":180},{"source":453,"target":94},{"source":452,"target":453},{"source":179,"target":180},{"source":454,"target":344},{"source":455,"target":454},{"source":456,"target":7},{"source":456,"target":252},{"source":457,"target":5},{"source":457,"target":457},{"source":458,"target":5},{"source":458,"target":458},{"source":2,"target":5},{"source":2,"target":2},{"source":459,"target":2},{"source":459,"target":459},{"source":31,"target":1},{"source":31,"target":3},{"source":460,"target":33},{"source":460,"target":461},{"source":460,"target":462},{"source":460,"target":463},{"source":460,"target":464},{"source":460,"target":465},{"source":460,"target":4},{"source":460,"target":5},{"source":460,"target":466},{"source":460,"target":467},{"source":460,"target":468},{"source":460,"target":469},{"source":460,"target":470},{"source":460,"target":36},{"source":460,"target":39},{"source":460,"target":34},{"source":460,"target":40},{"source":460,"target":3},{"source":471,"target":472},{"source":473,"target":72},{"source":474,"target":55},{"source":474,"target":57},{"source":475,"target":55},{"source":475,"target":62},{"source":475,"target":474},{"source":476,"target":476},{"source":477,"target":72},{"source":478,"target":72},{"source":479,"target":95},{"source":480,"target":4},{"source":480,"target":5},{"source":481,"target":279},{"source":84,"target":222},{"source":84,"target":482},{"source":84,"target":483},{"source":84,"target":84},{"source":84,"target":257},{"source":84,"target":73},{"source":84,"target":76},{"source":84,"target":126},{"source":84,"target":99},{"source":84,"target":89},{"source":484,"target":485},{"source":484,"target":4},{"source":484,"target":5},{"source":484,"target":486},{"source":487,"target":488},{"source":487,"target":489},{"source":487,"target":490},{"source":488,"target":490},{"source":490,"target":7},{"source":491,"target":7},{"source":491,"target":94}]}; + const option = { + legend: { + data: ['HTMLElement', 'WebGL', 'SVG', 'CSS', 'Other'] + }, + series: [{ + type: 'graph', + layout: 'force', + animation: false, + label: { + normal: { + position: 'right', + formatter: '{b}' + } + }, + draggable: true, + data: webkitDep.nodes.map(function (node, idx) { + node.id = idx; + return node; + }), + categories: webkitDep.categories, + force: { + // initLayout: 'circular' + // repulsion: 20, + edgeLength: 5, + repulsion: 20, + gravity: 0.2 + }, + edges: webkitDep.links + }] + }; + + return ; +}; + +export default Page; +``` diff --git a/docs/examples/loading.md b/docs/examples/loading.md new file mode 100644 index 0000000..fe31aa6 --- /dev/null +++ b/docs/examples/loading.md @@ -0,0 +1,79 @@ +--- +title: Loading +order: 5 +--- + +## Loading + +```tsx +import React, { useState, useEffect } from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const option = { + title: { + text: '基础雷达图' + }, + tooltip: {}, + legend: { + data: ['预算分配(Allocated Budget)', '实际开销(Actual Spending)'] + }, + radar: { + // shape: 'circle', + indicator: [ + { name: '销售(sales)', max: 6500}, + { name: '管理(Administration)', max: 16000}, + { name: '信息技术(Information Techology)', max: 30000}, + { name: '客服(Customer Support)', max: 38000}, + { name: '研发(Development)', max: 52000}, + { name: '市场(Marketing)', max: 25000} + ] + }, + series: [{ + name: '预算 vs 开销(Budget vs spending)', + type: 'radar', + // areaStyle: {normal: {}}, + data : [ + { + value : [4300, 10000, 28000, 35000, 50000, 19000], + name : '预算分配(Allocated Budget)' + }, + { + value : [5000, 14000, 28000, 31000, 42000, 21000], + name : '实际开销(Actual Spending)' + } + ] + }] + }; + + let timer; + + useEffect(() => { + return () => clearTimeout(timer); + }); + + const loadingOption = { + text: '加载中...', + color: '#4413c2', + textColor: '#270240', + maskColor: 'rgba(194, 88, 86, 0.3)', + zlevel: 0 + }; + + function onChartReady(echarts) { + timer = setTimeout(function() { + echarts.hideLoading(); + }, 3000); + } + + return ; +}; + +export default Page; +``` diff --git a/docs/examples/simple.md b/docs/examples/simple.md new file mode 100644 index 0000000..cf8bbf8 --- /dev/null +++ b/docs/examples/simple.md @@ -0,0 +1,78 @@ +--- +title: Simple +order: 1 +--- + +## 简单堆积面积图 + +```tsx +import React from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const option = { + title: { + text: '堆叠区域图' + }, + tooltip : { + trigger: 'axis' + }, + legend: { + data:['邮件营销','联盟广告','视频广告'] + }, + toolbox: { + feature: { + saveAsImage: {} + } + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis : [ + { + type : 'category', + boundaryGap : false, + data : ['周一','周二','周三','周四','周五','周六','周日'] + } + ], + yAxis : [ + { + type : 'value' + } + ], + series : [ + { + name:'邮件营销', + type:'line', + stack: '总量', + areaStyle: {normal: {}}, + data:[120, 132, 101, 134, 90, 230, 210] + }, + { + name:'联盟广告', + type:'line', + stack: '总量', + areaStyle: {normal: {}}, + data:[220, 182, 191, 234, 290, 330, 310] + }, + { + name:'视频广告', + type:'line', + stack: '总量', + areaStyle: {normal: {}}, + data:[150, 232, 201, 154, 190, 330, 410] + } + ] + }; + + return ; +}; + +export default Page; +``` diff --git a/docs/examples/svg.md b/docs/examples/svg.md new file mode 100644 index 0000000..c677301 --- /dev/null +++ b/docs/examples/svg.md @@ -0,0 +1,40 @@ +--- +title: SVG +order: 8 +--- + +## SVG + +```tsx +import React from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const option = { + title: { + text: 'ECharts 入门示例' + }, + tooltip: {}, + legend: { + data:['销量'] + }, + xAxis: { + data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'] + }, + yAxis: {}, + series: [{ + name: '销量', + type: 'bar', + data: [5, 20, 36, 10, 10, 20] + }] + }; + + return ; +}; + +export default Page; +``` diff --git a/docs/examples/theme.md b/docs/examples/theme.md new file mode 100644 index 0000000..082fa33 --- /dev/null +++ b/docs/examples/theme.md @@ -0,0 +1,123 @@ +--- +title: Theme +order: 3 +--- + +## Theme + +```tsx +import React, { useState } from 'react'; +import * as echarts from 'echarts'; +import ReactECharts from 'echarts-for-react'; + +echarts.registerTheme('my_theme', { + backgroundColor: '#f4cccc' +}); +echarts.registerTheme('another_theme', { + backgroundColor: '#eee' +}); + +const Page: React.FC = () => { + const option = { + title: { + text: '阶梯瀑布图', + subtext: 'From ExcelHome', + sublink: 'http://e.weibo.com/1341556070/Aj1J2x5a5' + }, + tooltip : { + trigger: 'axis', + axisPointer : { // 坐标轴指示器,坐标轴触发有效 + type : 'shadow' // 默认为直线,可选为:'line' | 'shadow' + } + }, + legend: { + data:['支出','收入'] + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: { + type : 'category', + splitLine: {show:false}, + data : ["11月1日", "11月2日", "11月3日", "11月4日", "11月5日", "11月6日", "11月7日", "11月8日", "11月9日", "11月10日", "11月11日"] + }, + yAxis: { + type : 'value' + }, + series: [ + { + name: '辅助', + type: 'bar', + stack: '总量', + itemStyle: { + normal: { + barBorderColor: 'rgba(0,0,0,0)', + color: 'rgba(0,0,0,0)' + }, + emphasis: { + barBorderColor: 'rgba(0,0,0,0)', + color: 'rgba(0,0,0,0)' + } + }, + data: [0, 900, 1245, 1530, 1376, 1376, 1511, 1689, 1856, 1495, 1292] + }, + { + name: '收入', + type: 'bar', + stack: '总量', + label: { + normal: { + show: true, + position: 'top' + } + }, + data: [900, 345, 393, '-', '-', 135, 178, 286, '-', '-', '-'] + }, + { + name: '支出', + type: 'bar', + stack: '总量', + label: { + normal: { + show: true, + position: 'bottom' + } + }, + data: ['-', '-', '-', 108, 154, '-', '-', '-', 119, 361, 203] + } + ] + }; + + const [theme, setTheme] = useState(); + const [className, setClassName] = useState('class_1'); + + function toggleTheme() { + setTheme(theme === 'my_theme' ? 'another_theme' : 'my_theme'); + } + + function toggleClassName() { + setClassName(className === 'class_1' ? 'class_2' : 'class_1'); + } + + return ( + <> + +
+
+ + +
+ + ); +}; + +export default Page; +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..debeb7d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,86 @@ +--- +title: ECharts for React - 全网最好用的 ECharts 的 React 组件封装 +order: 10 +hero: + title: ECharts for React + desc: 全网最好用的 ECharts 的 React 组件封装 + actions: + - text: 查看在线 DEMO + link: /examples/dynamic +footer: Open-source MIT Licensed | Copyright © 2021-present +--- + + +## 安装 + +```bash +$ npm install echarts-for-react +``` + + +## 使用 + +```tsx | pure +import React from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const options = { + grid: { top: 8, right: 8, bottom: 24, left: 36 }, + xAxis: { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + data: [820, 932, 901, 934, 1290, 1330, 1320], + type: 'line', + smooth: true, + }, + ], + }; + + return ; +}; + +export default Page; +``` + +最终结果: + +```tsx +import React from 'react'; +import ReactECharts from 'echarts-for-react'; + +const Page: React.FC = () => { + const options = { + grid: { top: 8, right: 8, bottom: 24, left: 36 }, + xAxis: { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + data: [820, 932, 901, 934, 1290, 1330, 1320], + type: 'line', + smooth: true, + }, + ], + }; + + return ; +}; + +export default Page; +``` + + +## 反馈 + +请访问 [GitHub](https://github.com/hustcc/echarts-for-react)。 diff --git a/package.json b/package.json new file mode 100644 index 0000000..74a275c --- /dev/null +++ b/package.json @@ -0,0 +1,116 @@ +{ + "name": "echarts-for-react", + "version": "3.0.0-beta.1", + "description": " Apache Echarts(v5) components for React.", + "main": "lib/index.js", + "module": "esm/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib", + "esm", + "src" + ], + "scripts": { + "docs:dev": "dumi dev", + "docs:build": "dumi build", + "docs:deploy": "rimraf dist && npm run docs:build && gh-pages -d dist", + "start": "webpack-dev-server --watch", + "lint": "eslint src __tests__ && prettier src __tests__ --check", + "fix": "eslint src __tests__ --fix && prettier src __tests__ --write", + "clean": "rimraf lib esm dist", + "test": "jest", + "lib": "run-p lib:*", + "lib:cjs": "tsc -p tsconfig.json --target ES5 --module commonjs --outDir lib", + "lib:esm": "tsc -p tsconfig.json --target ES5 --module ESNext --outDir esm", + "build": "npm run clean && npm run test && npm run lib" + }, + "repository": { + "type": "git", + "url": "https://github.com/hustcc/echarts-for-react.git" + }, + "keywords": [ + "react", + "component", + "echarts-react", + "echarts", + "react-echarts", + "chart", + "charts", + "graph", + "react-component" + ], + "author": "hustcc (http://github.com/hustcc)", + "license": "MIT", + "bugs": { + "url": "https://github.com/hustcc/echarts-for-react/issues" + }, + "homepage": "https://github.com/hustcc/echarts-for-react", + "devDependencies": { + "@commitlint/cli": "^11.0.0", + "@commitlint/config-angular": "^11.0.0", + "@types/jest": "^26.0.20", + "@types/node": "^14.14.14", + "@types/react": "^17.0.1", + "@typescript-eslint/eslint-plugin": "^4.14.2", + "@typescript-eslint/parser": "^4.11.0", + "cross-env": "^5.1.3", + "dumi": "^1.1.4", + "dumi-theme-default": "^1.0.4", + "echarts": "^5.0.2", + "echarts-gl": "^2.0.1", + "eslint": "^7.19.0", + "eslint-config-prettier": "^7.1.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-prettier": "^3.3.1", + "gh-pages": "^3.1.0", + "husky": "^4.3.8", + "jest": "^26.6.3", + "jest-canvas-mock": "^2.3.0", + "jest-electron": "^0.1.11", + "lint-md-cli": "^0.1.2", + "lint-staged": "^10.5.3", + "lodash.clonedeep": "^4.5.0", + "miz": "^1.0.1", + "npm-run-all": "^4.1.5", + "prettier": "^2.2.1", + "rimraf": "^2.6.2", + "ts-jest": "^26.5.0", + "ts-loader": "^8.0.15", + "typescript": "^4.1.3" + }, + "dependencies": { + "size-sensor": "^1.0.0", + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "react": ">=16.8.0", + "echarts": "^5.0.0" + }, + "jest": { + "runner": "jest-electron/runner", + "testEnvironment": "jest-electron/environment", + "preset": "ts-jest", + "collectCoverage": true, + "collectCoverageFrom": [ + "src/**/*.ts", + "!**/node_modules/**", + "!**/vendor/**" + ], + "testRegex": "/__tests__/.*-spec\\.tsx?$" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + }, + "lint-staged": { + "*.ts": [ + "eslint --fix", + "prettier --write" + ], + "*.md": [ + "lint-md --fix" + ] + } +} diff --git a/src/core.tsx b/src/core.tsx new file mode 100644 index 0000000..b7082a3 --- /dev/null +++ b/src/core.tsx @@ -0,0 +1,185 @@ +import React, { PureComponent } from 'react'; +import { bind, clear } from 'size-sensor'; +import { pick } from './helper/pick'; +import { isFunction } from './helper/is-function'; +import { isString } from './helper/is-string'; +import { isEqual } from './helper/is-equal'; +import { EChartsReactProps, EChartsInstance } from './types'; + +/** + * core component for echarts binding + */ +export default class EChartsReactCore extends PureComponent { + /** + * echarts render container + */ + public ele: HTMLElement; + + /** + * echarts library entry + */ + protected echarts: any; + + constructor(props: EChartsReactProps) { + super(props); + + this.echarts = props.echarts; + this.ele = null; + } + + componentDidMount() { + this.renderNewEcharts(); + } + + // update + componentDidUpdate(prevProps: EChartsReactProps) { + /** + * if shouldSetOption return false, then return, not update echarts options + * default is true + */ + const { shouldSetOption } = this.props; + if (isFunction(shouldSetOption) && !shouldSetOption(prevProps, this.props)) { + return; + } + + // 以下属性修改的时候,需要 dispose 之后再新建 + // 1. 切换 theme 的时候 + // 2. 修改 opts 的时候 + // 3. 修改 onEvents 的时候,这样可以取消所有之前绑定的事件 issue #151 + if ( + !isEqual(prevProps.theme, this.props.theme) || + !isEqual(prevProps.opts, this.props.opts) || + !isEqual(prevProps.onEvents, this.props.onEvents) + ) { + this.dispose(); + + this.renderNewEcharts(); // 重建 + return; + } + + // when thoes props isEqual, do not update echarts + const pickKeys = ['option', 'notMerge', 'lazyUpdate', 'showLoading', 'loadingOption']; + if (isEqual(pick(this.props, pickKeys), pick(prevProps, pickKeys))) { + return; + } + + const echartsInstance = this.updateEChartsOption(); + /** + * when style or class name updated, change size. + */ + if (!isEqual(prevProps.style, this.props.style) || !isEqual(prevProps.className, this.props.className)) { + try { + echartsInstance.resize(); + } catch (e) { + console.warn(e); + } + } + } + + componentWillUnmount() { + this.dispose(); + } + + /** + * return the echart object + * 1. if exist, return the existed instance + * 2. or new one instance + */ + public getEchartsInstance() { + return this.echarts.getInstanceByDom(this.ele) || this.echarts.init(this.ele, this.props.theme, this.props.opts); + } + + /** + * dispose echarts and clear size-sensor + */ + private dispose() { + if (this.ele) { + try { + clear(this.ele); + } catch (e) { + console.warn(e); + } + // dispose echarts instance + this.echarts.dispose(this.ele); + } + } + + /** + * render a new echarts instance + */ + private renderNewEcharts() { + const { onEvents, onChartReady } = this.props; + + // 1. new echarts instance + const echartsInstance = this.updateEChartsOption(); + + // 2. bind events + this.bindEvents(echartsInstance, onEvents || {}); + + // 3. on chart ready + if (isFunction(onChartReady)) onChartReady(echartsInstance); + + // 4. on resize + if (this.ele) { + bind(this.ele, () => { + try { + echartsInstance.resize(); + } catch (e) { + console.warn(e); + } + }); + } + } + + // bind the events + private bindEvents(instance, events: EChartsReactProps['onEvents']) { + function _bindEvent(eventName: string, func: Function) { + // ignore the event config which not satisfy + if (isString(eventName) && isFunction(func)) { + // binding event + instance.on(eventName, (param) => { + func(param, instance); + }); + } + } + + // loop and bind + for (const eventName in events) { + if (Object.prototype.hasOwnProperty.call(events, eventName)) { + _bindEvent(eventName, events[eventName]); + } + } + } + + /** + * render the echarts + */ + private updateEChartsOption(): EChartsInstance { + const { option, notMerge = false, lazyUpdate = false, showLoading, loadingOption = null } = this.props; + // 1. get or initial the echarts object + const echartInstance = this.getEchartsInstance(); + // 2. set the echarts option + echartInstance.setOption(option, notMerge, lazyUpdate); + // 3. set loading mask + if (showLoading) echartInstance.showLoading(loadingOption); + else echartInstance.hideLoading(); + + return echartInstance; + } + + render(): JSX.Element { + const { style, className = '' } = this.props; + // default height = 300 + const newStyle = { height: 300, ...style }; + + return ( +
{ + this.ele = e; + }} + style={newStyle} + className={`echarts-for-react ${className}`} + /> + ); + } +} diff --git a/src/helper/is-equal.ts b/src/helper/is-equal.ts new file mode 100644 index 0000000..7d7e552 --- /dev/null +++ b/src/helper/is-equal.ts @@ -0,0 +1,3 @@ +import isEqual from 'fast-deep-equal'; + +export { isEqual }; diff --git a/src/helper/is-function.ts b/src/helper/is-function.ts new file mode 100644 index 0000000..c254be4 --- /dev/null +++ b/src/helper/is-function.ts @@ -0,0 +1,3 @@ +export function isFunction(v: any): boolean { + return typeof v === 'function'; +} diff --git a/src/helper/is-string.ts b/src/helper/is-string.ts new file mode 100644 index 0000000..26e196d --- /dev/null +++ b/src/helper/is-string.ts @@ -0,0 +1,3 @@ +export function isString(v: any): boolean { + return typeof v === 'string'; +} diff --git a/src/helper/pick.ts b/src/helper/pick.ts new file mode 100644 index 0000000..ded83f8 --- /dev/null +++ b/src/helper/pick.ts @@ -0,0 +1,12 @@ +/** + * 保留 object 中的部分内容 + * @param obj + * @param keys + */ +export function pick(obj: Record, keys: string[]): Record { + const r = {}; + keys.forEach((key) => { + r[key] = obj[key]; + }); + return r; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e743d5a --- /dev/null +++ b/src/index.ts @@ -0,0 +1,15 @@ +import * as echarts from 'echarts'; +import { EChartsReactProps, EChartsOption, EChartsInstance } from './types'; +import EChartsReactCore from './core'; + +export { EChartsReactProps, EChartsOption, EChartsInstance }; + +// export the Component the echarts Object. +export default class EChartsReact extends EChartsReactCore { + constructor(props: EChartsReactProps) { + super(props); + + // 初始化为 echarts 整个包 + this.echarts = echarts; + } +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..7b8bd1a --- /dev/null +++ b/src/types.ts @@ -0,0 +1,69 @@ +import { CSSProperties } from 'react'; + +export type EChartsOption = any; + +export type EChartsInstance = any; + +export type Opts = { + readonly devicePixelRatio?: number; + readonly renderer?: 'canvas' | 'svg'; + readonly width?: number | null | undefined | 'auto'; + readonly height?: number | null | undefined | 'auto'; +}; + +export type EChartsReactProps = { + /** + * echarts library entry, use it for import necessary. + */ + readonly echarts?: any; + /** + * `className` for container + */ + readonly className?: string; + /** + * `style` for container + */ + readonly style?: CSSProperties; + /** + * echarts option + */ + readonly option: EChartsOption; + /** + * echarts theme config, can be: + * 1. theme name string + * 2. theme object + */ + readonly theme?: string | Record; + /** + * notMerge config for echarts, default is `false` + */ + readonly notMerge?: boolean; + /** + * lazyUpdate config for echarts, default is `false` + */ + readonly lazyUpdate?: boolean; + /** + * showLoading config for echarts, default is `false` + */ + readonly showLoading?: boolean; + /** + * loadingOption config for echarts, default is `null` + */ + readonly loadingOption?: any; + /** + * echarts opts config, default is `{}` + */ + readonly opts?: Opts; + /** + * when after chart reander, do the callback widht echarts instance + */ + readonly onChartReady?: (instance: EChartsInstance) => void; + /** + * bind events, default is `{}` + */ + readonly onEvents?: Record; + /** + * should update echarts options + */ + readonly shouldSetOption?: (prevProps: EChartsReactProps, props: EChartsReactProps) => boolean; +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..72042f4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "jsx": "react", + "module": "commonjs", + "sourceMap": true, + "inlineSources": true, + "target": "es5", + "outDir": "lib", + "declaration": true, + "importHelpers": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "lib": ["esnext", "dom"], + "types": ["jest", "react", "node"] + }, + "include": ["src"] +}