Compare commits

...

65 Commits
next ... v6.4.0

Author SHA1 Message Date
0a4601bc1a feat: delay disposal to disconnection if possible 2022-12-29 18:13:51 +08:00
3b2f2b547b docs: update readme version 2022-12-19 02:19:14 +08:00
977db3d415 fix: autoresize now works for grid layout by default (#675) 2022-12-19 02:03:25 +08:00
0bb1839392 feat: add basic types for events 2022-12-18 19:38:04 +08:00
5f57d3fb1c docs: update readme version 2022-12-17 01:46:23 +08:00
0470d69bba fix: revert overflow hidden 2022-12-17 01:44:00 +08:00
05111f5b6f fix: fix relative path 2022-12-17 01:36:31 +08:00
f1ca32d3a4 docs: update readme 2022-12-17 01:27:20 +08:00
669ba1cbbb fix: refine style and remove unused import 2022-12-17 01:26:08 +08:00
ec124f4bf7 feat: make it possible to dynamically change provide values for Vue 2 2022-12-17 01:23:29 +08:00
9491a904a0 docs: update readme [skip ci] 2022-12-07 20:00:09 +08:00
d773416b71 chore: bump version and update changelog 2022-12-07 19:46:46 +08:00
20858a6ed0 chore: bring logo back for demo site 2022-12-07 19:44:58 +08:00
6304a1b15a fix: attributes should fall onto the root for Vue 2 (#670) 2022-12-07 19:44:29 +08:00
e44c9dfd40 docs: use stackblitz for demos 2022-07-13 18:22:45 +08:00
6d2d3baa5d chore: improve readme demo link [skip ci] 2022-07-12 14:40:17 +08:00
0e27be6165 chore: update readme [skip ci] 2022-07-12 12:40:46 +08:00
0ddc499755 fix: v-on not working in 2.7 (fix #636) 2022-07-12 12:25:57 +08:00
4aaca62b89 chore: update version and changelog [skip ci] 2022-07-07 15:21:32 +08:00
bbac925b03 fix: UpdateOptions types omit notMerge 2022-07-07 12:21:05 +08:00
49563d3d52 chore: update readme [skip ci] 2022-07-06 16:55:29 +08:00
98a2fec975 chore: update changelog and version [skip ci] 2022-07-06 16:18:54 +08:00
1d4d0d0302 feat: provide better types for injection keys 2022-07-06 15:46:28 +08:00
948d522cf7 feat: add 2.7 support, fix #633 2022-07-06 15:08:35 +08:00
b11f1efc76 chore: fix readme 2022-06-15 22:55:43 +08:00
9f5106092b docs: refine docs 2022-06-15 19:27:21 +08:00
33feda71c0 fix: fix dev deps 2022-06-15 19:03:59 +08:00
eaceae607d feat: support .once modifier 2022-06-15 19:03:59 +08:00
57cd2e6a16 chore: move to pnpm and refine build 2022-05-11 22:38:00 +08:00
e51adb12d0 chore: refine demo 2022-05-11 01:22:43 +08:00
b05f072eb1 chore: update deps 2022-05-11 01:18:28 +08:00
259665c4c0 types: improve typings for vue 2 2022-05-11 00:20:20 +08:00
5e51ab1ac6 fix(docs): align with en docs 2022-03-16 14:43:38 +08:00
3256c3d833 fix: removed duplicated method signature in docs (#610) 2022-03-16 14:42:44 +08:00
2ab85972c9 chore: fix issue form [skip ci] 2022-01-24 14:51:51 +08:00
0dfe4f314a docs: update readme [skip ci] 2022-01-19 17:07:52 +08:00
01460d543d chore: update version and readme 2022-01-18 18:19:50 +08:00
899ef4b8d5 fix: chart instance should always be initialized 2022-01-18 16:55:13 +08:00
677f100b07 fix: make notMerge still respect to update-options 2022-01-18 14:24:17 +08:00
c1838efb45 fix: use ref change to apply notMerge: true for setOption 2022-01-18 14:22:41 +08:00
cdc6ed54d6 chore: update deps version and changelog 2022-01-14 19:02:25 +08:00
89be965939 chore: allowJs for demo 2022-01-14 19:02:25 +08:00
54ac383b6f refactor(types): use SetOptionOpts from echarts 2022-01-14 19:02:24 +08:00
7aa9edca96 fix: update should always have notMerge: true 2022-01-14 19:02:24 +08:00
157a66b75f docs: fix broken links in README (#586) 2021-12-16 14:10:16 +08:00
d9722d133b chore: refine issue form and readme 2021-08-11 12:08:09 +08:00
bb9540bf4a chore: update deps and version 2021-08-02 20:31:04 +08:00
f7f8e4a757 chore: fix issue form dropdown options 2021-06-29 13:58:23 +08:00
454e9056fa chore: add issue forms 2021-06-29 13:45:21 +08:00
86c22186cc types: fix rollup config type 2021-06-29 10:45:26 +08:00
a77ecc726d fix: delay first setOption until initial resize, update deps 2021-06-10 01:16:58 +08:00
87d9f843ac fix: provided theme changing won't trigger effect 2021-05-06 10:28:22 +08:00
6e25406cb9 docs: update demo version 2021-04-30 18:45:55 +08:00
dd71918d10 fix: make the .chart getter work with Vue 2 2021-04-30 18:45:05 +08:00
c7fd5110f7 fix: update default value for updateOption.lazyUpdate and no longer call resize in a task 2021-04-30 10:37:46 +08:00
9ecb954a9f chore: refine readme format 2021-03-29 20:16:27 +08:00
4d715e5378 docs: update readme 2021-03-29 20:15:02 +08:00
be2968cc1b chore: update version 2021-03-29 20:15:02 +08:00
23eba11c8f fix: fix updateOptions 2021-03-29 20:15:02 +08:00
289a0b59dc docs: update changelog 2021-03-29 20:15:02 +08:00
80710aa0fa fix: update vue-demi and fix type error for Vue2 reference, closes #534 2021-03-29 20:15:02 +08:00
accab93ea1 docs: update examples in readme (#524) 2021-03-11 14:55:46 +08:00
e10e588d99 docs: update readme 2021-03-09 10:53:05 +08:00
14520cb6a5 fix: add .d.ts for vue2 2021-03-09 10:52:39 +08:00
e543866b4d fix: fix postinstall script 2021-03-09 10:36:48 +08:00
36 changed files with 8918 additions and 17174 deletions

View File

@ -3,18 +3,22 @@ module.exports = {
env: {
node: true
},
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint"
],
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
ecmaVersion: 2020
ecmaVersion: 2020,
parser: "@typescript-eslint/parser"
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
}
},
overrides: [
{
files: ["*.ts"],
extends: [
"@vue/typescript/recommended",
"@vue/prettier/@typescript-eslint"
]
}
]
};

View File

@ -0,0 +1,46 @@
name: "🐞 Bug Report"
description: Create a bug report for Vue-ECharts
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to report this issue!
- type: checkboxes
id: confirmation
attributes:
label: Confirmation
description: Before submitting this issue, please make sure that the problem only occurs in Vue-ECharts and is not related to ECharts itself.
options:
- label: I can confirm this problem is not reproducible with ECharts itself.
required: true
- type: dropdown
id: integration
attributes:
label: How are you introducing Vue-ECharts into your project?
options:
- ES Module imports
- "<script> tag"
validations:
required: true
- type: textarea
id: versions
attributes:
label: Versions
description: The output of `npm ls vue echarts vue-echarts`.
render: sh
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: A clear description about the bug.
validations:
required: true
- type: input
id: repro
attributes:
label: Reproduction
description: "A link to a boiled-down reproduction (a minimal but runnable demo with unnecessary dependencies pruned). If the issue isn't reproducible within an online playground, please create a GitHub repo to reflect the problem. Please paste the link to your CodeSandbox demo or GitHub repo below: ([Vue 3 template](https://codesandbox.io/s/charming-night-2y6m6?file=/src/App.vue) / [Vue 2 template](https://codesandbox.io/s/suspicious-glitter-mk66j?file=/src/App.vue))"
validations:
required: true

View File

@ -0,0 +1,46 @@
name: "🐞 Bug 报告"
description: 给 Vue-ECharts 报告 bug
body:
- type: markdown
attributes:
value: |
感谢您花时间报告这个问题!
- type: checkboxes
id: confirmation
attributes:
label: 请确认
description: 在提交此问题前,请确认问题仅在 Vue-ECharts 中发生,而与 ECharts 本身无关。
options:
- label: 我可以确认这个问题无法在 ECharts 项目本身中复现。
required: true
- type: dropdown
id: integration
attributes:
label: 您是如何将 Vue-ECharts 引入项目的?
options:
- 通过 ES 模块 import
- "<script> 标签"
validations:
required: true
- type: textarea
id: versions
attributes:
label: 版本信息
description: 在命令行执行 `npm ls vue echarts vue-echarts` 的输出。
render: sh
validations:
required: true
- type: textarea
id: details
attributes:
label: 问题详情
description: 请清晰地描述您遇到的问题。
validations:
required: true
- type: input
id: repro
attributes:
label: 问题复现
description: "请提供一个精炼的问题复现(去除无关依赖的最小化可运行 demo。如果在线环境无法复现可以创建对应的 GitHub repo 来提供复现环境。请在下方贴入在 CodeSandbox 上 demo 的链接或 GitHub repo 链接:([Vue 3 模板](https://codesandbox.io/s/charming-night-2y6m6?file=/src/App.vue) / [Vue 2 模板](https://codesandbox.io/s/suspicious-glitter-mk66j?file=/src/App.vue)"
validations:
required: true

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -0,0 +1,22 @@
name: "✨ Feature Request"
description: Create a feature request for Vue-ECharts
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to report this issue!
- type: checkboxes
id: confirmation
attributes:
label: Confirmation
description: Before submitting the issue, please make sure you did the following check.
options:
- label: I can confirm this is a feature request for the Vue component instead of ECharts itself.
required: true
- type: textarea
id: desc
attributes:
label: Details
description: A clear description about the use case of the new feature and its potential API.
validations:
required: true

View File

@ -0,0 +1,22 @@
name: "✨ 新功能建议"
description: 给 Vue-ECharts 提交新功能建议
body:
- type: markdown
attributes:
value: |
感谢您花时间报告这个问题!
- type: checkboxes
id: confirmation
attributes:
label: 提前确认
description: 在提交此建议前,请确认下述情况。
options:
- label: 我可以确认这个新功能建议是提交给此 Vue 组件的,而不应该提交到 ECharts 项目本身。
required: true
- type: textarea
id: details
attributes:
label: 新功能详情
description: 请清晰地描述此功能的适用场景,以及可能的相关 API 的设想。
validations:
required: true

1
.npmrc Normal file
View File

@ -0,0 +1 @@
strict-peer-dependencies = false

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"trailingComma": "none",
"arrowParens": "avoid"
}

View File

@ -1,3 +1,89 @@
## 6.4.0
* Delay the disposal of the ECharts instance to the moment the element is disconnected from the DOM if possible (#433).
## 6.3.3
* Make autoresize work for grid layout by default (#675).
## 6.3.2
* Added basic types for events (only event names).
## 6.3.1
* Revert the style change to prevent tooltips from being clipped.
## 6.3.0
* Injected values can now be wrapped in an object so that they can be reactive in Vue 2.
## 6.2.4
* Fixed that attributes were not outputted onto the chart root element for Vue 2 (#670).
## 6.2.3
* Fixed the problem that `v-on` stops working after upgrading to `vue@2.7.x`.
## 6.2.2
* Improve types for `update-options`.
## 6.2.1
* Improved types for provide/inject API.
## 6.2.0
* Added support for Vue 2.7+.
## 6.1.0
* Added support for `.once` event modifier.
## 6.0.3
* Improved typings for Vue 2 version.
## 6.0.2
* Make `notMerge` option still respect `update-options`.
* The default behavior of `notMerge` now revert to checking if there is a reference change for the `option` prop.
## 6.0.1
* Update should always be `notMerge: true`.
* Update dependency version for vue-demi.
## 6.0.0
* Update dependency versions.
## 6.0.0-rc.6
* Revert the change of `updateOptions.lazyUpdate`. It defaults to `false` again.
* Fixed the occasional error caused by the internal implementation of ECharts.
* Removed unexpected `console.log` call.
## 6.0.0-rc.5
* Changed `updateOptions.lazyUpdate` to `true` by default. ([#533](https://github.com/ecomfe/vue-echarts/issues/533#issuecomment-809883909))
* Only perform an additional `resize` call after init within a task. ([#533](https://github.com/ecomfe/vue-echarts/issues/533#issuecomment-809883909))
* The `.chart` getter API now works for Vue 2. (#542)
## 6.0.0-rc.4
* Fix type error for `Vue2` reference.
## 6.0.0-rc.3
* Add missing types file for Vue 2.
## 6.0.0-rc.2
* Fix postinstall script.
## 6.0.0-rc.1
* Move inital resize timing earlier into microtasks so that minimize visual layout shift.

257
README.md
View File

@ -4,7 +4,7 @@
> [🇨🇳 中文版](./README.zh-Hans.md)
Uses [Apache ECharts](http://echarts.baidu.com/index.html) 5 and works for both [Vue.js](https://vuejs.org/) 2/3.
Uses [Apache ECharts](https://echarts.apache.org/en/index.html) 5 and works for both [Vue.js](https://vuejs.org/) 2/3.
## 💡 Heads up 💡
@ -20,87 +20,31 @@ Not ready yet? Read documentation for older versions [here →](https://github.c
$ npm install echarts vue-echarts
```
To make `vue-echarts` work for Vue 2, you need to have `@vue/composition-api` installed:
To make `vue-echarts` work for _Vue 2_ (<2.7.0), you need to have `@vue/composition-api` installed:
```sh
npm i -D @vue/composition-api
```
<details open>
<summary>Vue 3</summary>
If you are using _NuxtJS_ on top of _Vue 2_ (<2.7.0), you'll also need `@nuxtjs/composition-api`:
```js
import { createApp } from 'vue'
import ECharts from 'vue-echarts'
// import ECharts modules manually to reduce bundle size
import {
CanvasRenderer
} from 'echarts/renderers'
import {
BarChart
} from 'echarts/charts'
import {
GridComponent,
TooltipComponent
} from 'echarts/components'
const app = createApp(...)
// register globally (or you can do it locally)
app.component('v-chart', ECharts)
app.mount(...)
```sh
npm i -D @nuxtjs/composition-api
```
</details>
And then add `'@nuxtjs/composition-api/module'` in the `buildModules` option in your `nuxt.config.js`.
#### Example
<details>
<summary>Vue 2</summary>
```js
import Vue from 'vue'
import ECharts from 'vue-echarts'
// import ECharts modules manually to reduce bundle size
import {
CanvasRenderer
} from 'echarts/renderers'
import {
BarChart
} from 'echarts/charts'
import {
GridComponent,
TooltipComponent
} from 'echarts/components'
// register globally (or you can do it locally)
Vue.component('v-chart', ECharts)
new Vue(...)
```
</details>
We encourage manually importing components and charts from ECharts for smaller bundle size. See all supported renderers/charts/components [here →](https://github.com/apache/echarts/blob/master/src/echarts.all.ts)
But if you really want to import the whole ECharts bundle without having to import modules manually, just add this in your code:
```js
import "echarts";
```
#### SFC example
<details open>
<summary>Vue 3</summary>
<summary>Vue 3 <a href="https://stackblitz.com/edit/vue-echarts-vue-3?file=src%2FApp.vue">Demo →</a></summary>
```vue
<template>
<v-chart class="chart" :option="option" />
</template>
<script>
<script setup>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
@ -110,7 +54,7 @@ import {
LegendComponent
} from "echarts/components";
import VChart, { THEME_KEY } from "vue-echarts";
import { ref, defineComponent } from "vue";
import { ref, provide } from "vue";
use([
CanvasRenderer,
@ -120,55 +64,44 @@ use([
LegendComponent
]);
export default defineComponent({
name: "HelloWorld",
components: {
VChart
},
provide: {
[THEME_KEY]: "dark"
},
setup: () => {
const option = ref({
title: {
text: "Traffic Sources",
left: "center"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: "vertical",
left: "left",
data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
},
series: [
{
name: "Traffic Sources",
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
});
provide(THEME_KEY, "dark");
return { option };
}
const option = ref({
title: {
text: "Traffic Sources",
left: "center"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: "vertical",
left: "left",
data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
},
series: [
{
name: "Traffic Sources",
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
});
</script>
@ -179,12 +112,10 @@ export default defineComponent({
</style>
```
[Demo →](https://codesandbox.io/s/charming-night-2y6m6?file=/src/App.vue)
</details>
<details>
<summary>Vue 2</summary>
<summary>Vue 2 <a href="https://stackblitz.com/edit/vue-echarts-vue-2?file=src%2FApp.vue">Demo →</a></summary>
```vue
<template>
@ -275,22 +206,28 @@ export default {
</style>
```
[Demo →](https://codesandbox.io/s/suspicious-glitter-mk66j?file=/src/App.vue)
</details>
We encourage manually importing components and charts from ECharts for smaller bundle size. See all supported renderers/charts/components [here →](https://github.com/apache/echarts/blob/master/src/echarts.all.ts)
But if you really want to import the whole ECharts bundle without having to import modules manually, just add this in your code:
```js
import "echarts";
```
### CDN & Global variable
Drop `<script>` inside your HTML file and access the component via `window.VueECharts`.
<details open>
<summary>Vue 3</summary>
<details>
<summary>Vue 3 <a href="https://stackblitz.com/edit/vue-echarts-vue-3-global?file=index.html">Demo →</a></summary>
<!-- vue3Scripts:start -->
```html
<script src="https://cdn.jsdelivr.net/npm/vue@3.0.7"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.0.0-rc.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.37"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.4.0"></script>
```
<!-- vue3Scripts:end -->
@ -301,23 +238,16 @@ const app = Vue.createApp(...)
app.component('v-chart', VueECharts)
```
<!-- vue3Demo:start -->
[Demo →](https://codesandbox.io/api/v1/sandboxes/define?parameters=N4IgZglgNgpgziAXKCA7AJjAHgOgBYAuAtlEqAMYD2qBMNSIAPAIQAiA8gMIAqAmgAoBRAASESAPgA6qRmKhSZeGAEN0CxnAIBPWAoDEygA6HhwacNEwIAc0KJhAFgAMTw1gDc0gL7TGAek0dGHU_JVV1ACNKdC11dAgAN2EIdABeSRAjQwyFC0YEgFpyPGUAJwJhZQBXAkpS-AgALxhhREpDAghqdJB2zuoMvxD4hPU4clKIDuE4UvIewgJDOEQ_P3J0VBwAKzhMKETSnFQYAj9UQyI_BKqYAAEAZhwnHAB2HP9xyY6xiamK2bzDKLZardabHZ7GAHBJHE5nC5XGDFMoEOB3ACszxwACYPgE_j9fF9_jM5gsCEsVmsNltdvtDsdTudLtdbgVkSVyuiAGzYpwFOY4ACM-JJRJk4oICgAarccBMVLQAILGAAUZlQFnQygIyjVAEpTOYLMJ6gQqqUtZrTaa-l1UPYbbbTbQsAQAMraWBOk0u01gagEABiyiI0C09gA5ABJGgwUoAGmEGQAEtCEqcIORlMIAHIwW4ZZPKybKKDJuDKVBwApwBMQMBRv0uryJlu2zoEH3GrX-13YAj2DLcUrKMCQcjCD2US3keDFjsu2BgIcpkDz-OlDJLixt3fCWqUKCdQy-vv9w-TazWBPDkAQWhERcX_uB0pEXW0Ur34DKLzCIwESlEMwARABTrkABGroF4ACkBo7q-tr7shpqwLeGDnpeFh1BAdBrhkmblNm5YvjhwgroRIBUeROE6nq9gANoHraGSsBA9TkAQdEURkgiftAvE4RkyroPmpwAO51AA1nAwmXhkMopDAlDCGJ8kgO2aH-hkHoqHMeDCIIqDWGgC4gKxwgALoHqhl71pM8DMVZzoUagYYwPeo7jpO06znMFnaRRFjaIYXnroY-EKf2Y7xFUKzrhiGJwTF_qbt-LkgBiTipVp648rlGTWcFIUMcoLk6f2wDCAk5a3PYDwPBiyYeUQEXsZxyI8SAwj2SFFg1XVUANcIDzCk4rWefeAnKEJvX9QNQ31RFOIPA4U3tfeYkSQQ0mlHJGR9aVS21St9jCs1m0dSAymYGpGlHYtIXLSNEXChiDgABzXfe-llMUxmmeZml9VZFgleDwgwEQhglHAECJW5IWPjDXpBNhA2mnAJToJQkkAEIjT-wgTSdWM46o-PsBO9YEAAGvYk1Q7alN45JnDHnU96lNYET6pNwiC8LOAYohllVf6PiS6a0sUXL_a2WhCt7p4fbS14iF9gqlCw9QBFqkRRRcj1yZyjAgicCbcBaxYOBELONCGyABjGBkBpq58hLSr4fhRDEIRyOIIBeKHQA)
<!-- vue3Demo:end -->
</details>
<details>
<summary>Vue 2</summary>
<summary>Vue 2 <a href="https://stackblitz.com/edit/vue-echarts-vue-2-global?file=index.html">Demo →</a></summary>
<!-- vue2Scripts:start -->
```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.0.0-rc.3"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.0.0-rc.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.5"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.4.0"></script>
```
<!-- vue2Scripts:end -->
@ -326,12 +256,6 @@ app.component('v-chart', VueECharts)
Vue.component("v-chart", VueECharts);
```
<!-- vue2Demo:start -->
[Demo →](https://codesandbox.io/api/v1/sandboxes/define?parameters=N4IgZglgNgpgziAXKCA7AJjAHgOgBYAuAtlEqAMYD2qBMNSIAPAIQAiA8gMIAqAmgAoBRAASESAPgA6qRmKhSZeGAEN0CxnAIBPWAoDEygA6HhwacNEwIAc0KJhAFgAMTw1gDc0gL7TGAek0dGHU_JVV1ACNKdC11dAgAN2EIdABeSRAjQwyFC0YEgFpyPGUAJwJhZQBXAkpS-AgALxhhREpDAghqdJB2zuoMvxD4hPU4clKIDuE4UvIewgJDOEQ_P3J0VBwAKzhMKETSnFQYAj9UQyI_BKqYAAEAJhwANhwARgec_3HJjrGJqYVWbzDKLZardabHZ7GAHBJHE5nC5XO43GDrShEQyUOAQfqoApGCB3N44JxkgpzHAAZi-AQBf18P0BMzmCwISxWaw2W12-0Ox1O50ufhgxTKBDgdwArGScJ8QOJvgyCP9fkC2aCOeDuVC-bCBYjhVc0QUxSVylLXuSnJTyO86czGTInarpAA1W44KhY6h0AgACgyhXF5QyABphJ6YIJOBbJQBKTyoaQnADuUduAbMqAssPsGQMxgj5mE6GUBGUAYTplLFnqBCqpVzOYsbeEfS6qHsrfbbdoWAIAGVtLAe3W-xYwNQCAAxZREaBaewAcgAkjQYKVIxkABKwhKnCDkZTCAByMFuEeEAEFJsooJG4MpUHACnAtxAwCuJ-2vOHf37PEx1rXNJ37bACALEBuFKZQwEgchhCHSgm3IeASzA8DhFgMAoOEDJ0M3UoMkAix_zI4RakoKBOkMccsPAghJmsawt2gvEYCITDsKnOoiArWhSmg4BlC8YRGAiUohmACJxJ7chxOzdAvAAUgTUjGL_ACtLbWA2IwBjeI7SZ_Wgw9ymPB8eN43D8IyOybOw8tK3sABtSj2wyVgIHqcgCCc3iMkEAToEC7CMhvdBz1ONM6gAazgcLwIyd0UhgShb3QJKQB04yLAyIcVDmPBhEEVBrDQDCQE84QAF1KIo3SLA_UyVmEDzmrbXtjNQBcYGg2D4MQ5DULmaq8vy7RDAGgiQEMCAYGSyc4PiKp2oyaVpVU5a-yIoT3M2pwdtyubnmOjI6sm4yXOUQ6usnYBhASB9bnsalqWlSM-qIWbvN8sUApAYQmvy7rnte2bqTeJxvv66CQuUMLgdBsHTAhqA3uEB5qQcOHfugqKYoIOLSkSjIQeu_KnpezHZreT78b-kA0swTKopyynavbGnIfsN5pQcAAOJnoKKspijKiqqs5nwHrbK7ueELjDBKXF2p6_LOKIEcgiMtGWpKdBKDTAAhTHhOEGGqbBuAjZN9gEI_AgAA17FhpX2zt1QTc4Gi6mg0prAiKtYeEMOI5waUNJq-W_yVuXjMT8CGt05PyOTcjvCTXx6XVEIohiEI5HEEAvHLoA)
<!-- vue2Demo:end -->
</details>
See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/src/demo).
@ -354,6 +278,8 @@ See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/src/dem
ECharts' universal interface. Modifying this prop will trigger ECharts' `setOption` method. Read more [here →](https://echarts.apache.org/en/option.html)
> 💡 When `update-options` is not specified, `notMerge: false` will be specified by default when the `setOption` method is called if the `option` object is modified directly and the reference remains unchanged; otherwise, if a new reference is bound to `option`, ` notMerge: true` will be specified.
- `update-options: object`
Options for updating chart option. See `echartsInstance.setOption`'s `opts` parameter [here →](https://echarts.apache.org/en/api.html#echartsInstance.setOption)
@ -386,20 +312,20 @@ See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/src/dem
Vue-ECharts provides provide/inject API for `theme`, `init-options`, `update-options` and `loading-options` to help configuring contextual options. eg. for `init-options` you can use the provide API like this:
<details open>
<details>
<summary>Vue 3</summary>
```js
import { INIT_OPTIONS_KEY } from 'vue-echarts'
import { THEME_KEY } from 'vue-echarts'
import { provide } from 'vue'
// composition API
provide(INIT_OPTIONS_KEY, ...)
provide(THEME_KEY, 'dark')
// options API
{
provide: {
[INIT_OPTIONS_KEY]: { ... }
[THEME_KEY]: 'dark'
}
}
```
@ -410,16 +336,36 @@ provide(INIT_OPTIONS_KEY, ...)
<summary>Vue 2</summary>
```js
import { INIT_OPTIONS_KEY } from 'vue-echarts'
import { THEME_KEY } from 'vue-echarts'
// in component options
{
provide: {
[INIT_OPTIONS_KEY]: { ... }
[THEME_KEY]: 'dark'
}
}
```
> **Note**
>
> You need to provide an object for Vue 2 if you want to change it dynamically.
>
> ```js
> // in component options
> {
> data () {
> return {
> theme: { value: 'dark' }
> }
> },
> provide () {
> return {
> [THEME_KEY]: this.theme
> }
> }
> }
> ```
</details>
### Methods
@ -436,7 +382,6 @@ import { INIT_OPTIONS_KEY } from 'vue-echarts'
- `containPixel` [](https://echarts.apache.org/en/api.html#echartsInstance.containPixel)
- `showLoading` [](https://echarts.apache.org/en/api.html#echartsInstance.showLoading)
- `hideLoading` [](https://echarts.apache.org/en/api.html#echartsInstance.hideLoading)
- `containPixel` [](https://echarts.apache.org/en/api.html#echartsInstance.containPixel)
- `getDataURL` [](https://echarts.apache.org/en/api.html#echartsInstance.getDataURL)
- `getConnectedDataURL` [](https://echarts.apache.org/en/api.html#echartsInstance.getConnectedDataURL)
- `clear` [](https://echarts.apache.org/en/api.html#echartsInstance.clear)
@ -448,6 +393,18 @@ Static methods can be accessed from [`echarts` itself](https://echarts.apache.or
### Events
You can bind events with Vue's `v-on` directive.
```vue
<template>
<v-chart :option="option" @highlight="handleHighlight" />
</template>
```
> **Note**
>
> Only the `.once` event modifier is supported as other modifiers are tightly coupled with the DOM event system.
Vue-ECharts support the following events:
- `highlight` [](https://echarts.apache.org/en/api.html#events.highlight)
@ -504,7 +461,7 @@ The following breaking changes are introduced in `vue-echarts@6`:
### Vue 2 support
- Now `@vue/composition-api` is required to be installed to use Vue-ECharts with Vue 2.
- If you are using version prior to `vue@2.7.0`, `@vue/composition-api` is required to be installed to use Vue-ECharts with Vue 2.
### Props

View File

@ -2,7 +2,7 @@
> Apache ECharts 的 Vue.js 组件。
使用 [Apache ECharts](http://echarts.baidu.com/index.html) 5同时支持 [Vue.js](https://vuejs.org/) 2/3。
使用 [Apache ECharts](https://echarts.apache.org/zh/index.html) 5同时支持 [Vue.js](https://vuejs.org/) 2/3。
## 💡 注意 💡
@ -18,87 +18,31 @@
$ npm install echarts vue-echarts
```
要在 Vue 2 下使用 `vue-echarts`需要确保 `@vue/composition-api` 已经安装
要在 _Vue 2_<2.7.0下使用 `vue-echarts`需要确保 `@vue/composition-api` 已经安装
```sh
npm i -D @vue/composition-api
```
<details open>
<summary>Vue 3</summary>
如果你在使用基于 _Vue 2_<2.7.0 _NuxtJS_那么还需要安装 `@nuxtjs/composition-api`
```js
import { createApp } from 'vue'
import ECharts from 'vue-echarts'
// 手动引入 ECharts 各模块来减小打包体积
import {
CanvasRenderer
} from 'echarts/renderers'
import {
BarChart
} from 'echarts/charts'
import {
GridComponent,
TooltipComponent
} from 'echarts/components'
const app = createApp(...)
// 全局注册组件(也可以使用局部注册)
app.component('v-chart', ECharts)
app.mount(...)
```sh
npm i -D @nuxtjs/composition-api
```
</details>
然后在 `nuxt.config.js` `buildModules` 选项中添加 `'@nuxtjs/composition-api/module'`
#### 示例
<details>
<summary>Vue 2</summary>
```js
import Vue from 'vue'
import ECharts from 'vue-echarts'
// 手动引入 ECharts 各模块来减小打包体积
import {
CanvasRenderer
} from 'echarts/renderers'
import {
BarChart
} from 'echarts/charts'
import {
GridComponent,
TooltipComponent
} from 'echarts/components'
// 全局注册组件(也可以使用局部注册)
Vue.component('v-chart', ECharts)
new Vue(...)
```
</details>
为了更小的打包体积,我们建议手动从 ECharts 引入单个图表和组件。请参考所有支持的渲染器/图表/组件。[前往 →](https://github.com/apache/echarts/blob/master/src/echarts.all.ts)
但如果你实在需要全量引入 ECharts 从而无需手动引入模块,只需要在代码中添加:
```js
import "echarts";
```
#### 单文件组件示例
<details open>
<summary>Vue 3</summary>
<summary>Vue 3 <a href="https://stackblitz.com/edit/vue-echarts-vue-3?file=src%2FApp.vue">Demo →</a></summary>
```vue
<template>
<v-chart class="chart" :option="option" />
</template>
<script>
<script setup>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
@ -108,7 +52,7 @@ import {
LegendComponent
} from "echarts/components";
import VChart, { THEME_KEY } from "vue-echarts";
import { ref, defineComponent } from "vue";
import { ref, provide } from "vue";
use([
CanvasRenderer,
@ -118,55 +62,44 @@ use([
LegendComponent
]);
export default defineComponent({
name: "HelloWorld",
components: {
VChart
},
provide: {
[THEME_KEY]: "dark"
},
setup: () => {
const option = ref({
title: {
text: "Traffic Sources",
left: "center"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: "vertical",
left: "left",
data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
},
series: [
{
name: "Traffic Sources",
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
});
provide(THEME_KEY, "dark");
return { option };
}
const option = ref({
title: {
text: "Traffic Sources",
left: "center"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: "vertical",
left: "left",
data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
},
series: [
{
name: "Traffic Sources",
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
});
</script>
@ -180,7 +113,7 @@ export default defineComponent({
</details>
<details>
<summary>Vue 2</summary>
<summary>Vue 2 <a href="https://stackblitz.com/edit/vue-echarts-vue-2?file=src%2FApp.vue">Demo →</a></summary>
```vue
<template>
@ -273,18 +206,26 @@ export default {
</details>
为了更小的打包体积,我们建议手动从 ECharts 引入单个图表和组件。请参考所有支持的渲染器/图表/组件。[前往 →](https://github.com/apache/echarts/blob/master/src/echarts.all.ts)
但如果你实在需要全量引入 ECharts 从而无需手动引入模块,只需要在代码中添加:
```js
import "echarts";
```
### CDN & 全局变量
用如下方式在 HTML 中插入 `<script>` 标签,并且通过 `window.VueECharts` 来访问组件接口:
<details open>
<summary>Vue 3</summary>
<details>
<summary>Vue 3 <a href="https://stackblitz.com/edit/vue-echarts-vue-3-global?file=index.html">Demo →</a></summary>
<!-- vue3Scripts:start -->
```html
<script src="https://cdn.jsdelivr.net/npm/vue@3.0.7"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.0.0-rc.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.37"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.4.0"></script>
```
<!-- vue3Scripts:end -->
@ -295,23 +236,16 @@ const app = Vue.createApp(...)
app.component('v-chart', VueECharts)
```
<!-- vue3Demo:start -->
[Demo →](https://codesandbox.io/api/v1/sandboxes/define?parameters=N4IgZglgNgpgziAXKCA7AJjAHgOgBYAuAtlEqAMYD2qBMNSIAPAIQAiA8gMIAqAmgAoBRAASESAPgA6qRmKhSZeGAEN0CxnAIBPWAoDEygA6HhwacNEwIAc0KJhAFgAMTw1gDc0gL7TGAek0dGHU_JVV1ACNKdC11dAgAN2EIdABeSRAjQwyFC0YEgFpyPGUAJwJhZQBXAkpS-AgALxhhREpDAghqdJB2zuoMvxD4hPU4clKIDuE4UvIewgJDOEQ_P3J0VBwAKzhMKETSnFQYAj9UQyI_BKqYAAEAZhwnHAB2HP9xyY6xiamK2bzDKLZardabHZ7GAHBJHE5nC5XGDFMoEOB3ACszxwACYPgE_j9fF9_jM5gsCEsVmsNltdvtDsdTudLtdbgVkSVyuiAGzYpwFOY4ACM-JJRJk4oICgAarccBMVLQAILGAAUZlQFnQygIyjVAEpTOYLMJ6gQqqUtZrTaa-l1UPYbbbTbQsAQAMraWBOk0u01gagEABiyiI0C09gA5ABJGgwUoAGmEGQAEtCEqcIORlMIAHIwW4ZZPKybKKDJuDKVBwApwBMQMBRv0uryJlu2zoEH3GrX-13YAj2DLcUrKMCQcjCD2US3keDFjsu2BgIcpkDz-OlDJLixt3fCWqUKCdQy-vv9w-TazWBPDkAQWhERcX_uB0pEXW0Ur34DKLzCIwESlEMwARABTrkABGroF4ACkBo7q-tr7shpqwLeGDnpeFh1BAdBrhkmblNm5YvjhwgroRIBUeROE6nq9gANoHraGSsBA9TkAQdEURkgiftAvE4RkyroPmpwAO51AA1nAwmXhkMopDAlDCGJ8kgO2aH-hkHoqHMeDCIIqDWGgC4gKxwgALoHqhl71pM8DMVZzoUagYYwPeo7jpO06znMFnaRRFjaIYXnroY-EKf2Y7xFUKzrhiGJwTF_qbt-LkgBiTipVp648rlGTWcFIUMcoLk6f2wDCAk5a3PYDwPBiyYeUQEXsZxyI8SAwj2SFFg1XVUANcIDzCk4rWefeAnKEJvX9QNQ31RFOIPA4U3tfeYkSQQ0mlHJGR9aVS21St9jCs1m0dSAymYGpGlHYtIXLSNEXChiDgABzXfe-llMUxmmeZml9VZFgleDwgwEQhglHAECJW5IWPjDXpBNhA2mnAJToJQkkAEIjT-wgTSdWM46o-PsBO9YEAAGvYk1Q7alN45JnDHnU96lNYET6pNwiC8LOAYohllVf6PiS6a0sUXL_a2WhCt7p4fbS14iF9gqlCw9QBFqkRRRcj1yZyjAgicCbcBaxYOBELONCGyABjGBkBpq58hLSr4fhRDEIRyOIIBeKHQA)
<!-- vue3Demo:end -->
</details>
<details>
<summary>Vue 2</summary>
<summary>Vue 2 <a href="https://stackblitz.com/edit/vue-echarts-vue-2-global?file=index.html">Demo →</a></summary>
<!-- vue2Scripts:start -->
```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.0.0-rc.3"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.0.0-rc.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.5"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.4.0"></script>
```
<!-- vue2Scripts:end -->
@ -320,8 +254,6 @@ app.component('v-chart', VueECharts)
Vue.component("v-chart", VueECharts);
```
[Demo →](https://codepen.io/Justineo/pen/gOLGxJR)
</details>
可以在[这里](https://github.com/ecomfe/vue-echarts/tree/main/src/demo)查看更多例子。
@ -344,6 +276,8 @@ Vue.component("v-chart", VueECharts);
ECharts 的万能接口。修改这个 prop 会触发 ECharts 实例的 `setOption` 方法。查看[详情 →](https://echarts.apache.org/zh/option.html)
> 💡 在没有指定 `update-options` 时,如果直接修改 `option` 对象而引用保持不变,`setOption` 方法调用时将默认指定 `notMerge: false`;否则,如果为 `option` 绑定一个新的引用,将指定 `notMerge: true`。
- `update-options: object`
图表更新的配置项。请参考 `echartsInstance.setOption``opts` 参数。[前往 →](https://echarts.apache.org/zh/api.html#echartsInstance.setOption)
@ -372,72 +306,20 @@ Vue.component("v-chart", VueECharts);
在性能敏感(数据量很大)的场景下,我们最好对于 `option` prop 绕过 Vue 的响应式系统。当将 `manual-update` prop 指定为 `true` 且不传入 `option` prop 时,数据将不会被监听。然后,需要用 `ref` 获取组件实例以后手动调用 `setOption` 方法来更新图表。
### Provide / Inject
Vue-ECharts 为 `theme``init-options``update-options``loading-options` 提供了 provide/inject API以通过上下文配置选项。例如可以通过如下方式来使用 provide API 为 `init-options` 提供上下文配置:
<details open>
<summary>Vue 3</summary>
```js
import { INIT_OPTIONS_KEY } from 'vue-echarts'
import { provide } from 'vue'
// composition API
provide(INIT_OPTIONS_KEY, ...)
// options API
{
provide: {
[INIT_OPTIONS_KEY]: { ... }
}
}
```
</details>
<details>
<summary>Vue 2</summary>
```js
import { INIT_OPTIONS_KEY } from 'vue-echarts'
// in component options
{
provide: {
[INIT_OPTIONS_KEY]: { ... }
}
}
```
</details>
### 方法
- `setOption` [](https://echarts.apache.org/zh/api.html#echartsInstance.setOption)
- `getWidth` [](https://echarts.apache.org/zh/api.html#echartsInstance.getWidth)
- `getHeight` [](https://echarts.apache.org/zh/api.html#echartsInstance.getHeight)
- `getDom` [](https://echarts.apache.org/zh/api.html#echartsInstance.getDom)
- `getOption` [](https://echarts.apache.org/zh/api.html#echartsInstance.getOption)
- `resize` [](https://echarts.apache.org/zh/api.html#echartsInstance.resize)
- `dispatchAction` [](https://echarts.apache.org/zh/api.html#echartsInstance.dispatchAction)
- `convertToPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.convertToPixel)
- `convertFromPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.convertFromPixel)
- `containPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.containPixel)
- `showLoading` [](https://echarts.apache.org/zh/api.html#echartsInstance.showLoading)
- `hideLoading` [](https://echarts.apache.org/zh/api.html#echartsInstance.hideLoading)
- `containPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.containPixel)
- `getDataURL` [](https://echarts.apache.org/zh/api.html#echartsInstance.getDataURL)
- `getConnectedDataURL` [](https://echarts.apache.org/zh/api.html#echartsInstance.getConnectedDataURL)
- `clear` [](https://echarts.apache.org/zh/api.html#echartsInstance.clear)
- `dispose` [](https://echarts.apache.org/zh/api.html#echartsInstance.dispose)
### 静态方法
静态方法请直接通过 [`echarts` 本身](https://echarts.apache.org/zh/api.html#echarts)进行调用。
### 事件
可以使用 Vue 的 `v-on` 指令绑定事件。
```vue
<template>
<v-chart :option="option" @highlight="handleHighlight" />
</template>
```
> **Note**
>
> 仅支持 `.once` 修饰符,因为其它修饰符都与 DOM 事件机制强耦合。
Vue-ECharts 支持如下事件:
- `highlight` [](https://echarts.apache.org/zh/api.html#events.highlight)
@ -486,6 +368,89 @@ Vue-ECharts 支持如下事件:
请参考支持的事件列表。[前往 →](https://echarts.apache.org/zh/api.html#events)
### Provide / Inject
Vue-ECharts 为 `theme``init-options``update-options``loading-options` 提供了 provide/inject API以通过上下文配置选项。例如可以通过如下方式来使用 provide API 为 `init-options` 提供上下文配置:
<details>
<summary>Vue 3</summary>
```js
import { THEME_KEY } from 'vue-echarts'
import { provide } from 'vue'
// 组合式 API
provide(THEME_KEY, 'dark')
// 选项式 API
{
provide: {
[THEME_KEY]: 'dark'
}
}
```
</details>
<details>
<summary>Vue 2</summary>
```js
import { THEME_KEY } from 'vue-echarts'
// 组件选项中
{
provide: {
[THEME_KEY]: 'dark'
}
}
```
> **Note**
>
> 在 Vue 2 中,如果你想动态地改变这些选项,那么你需要提供一个对象。
>
> ```js
> // 组件选项中
> {
> data () {
> return {
> theme: { value: 'dark' }
> }
> },
> provide () {
> return {
> [THEME_KEY]: this.theme
> }
> }
> }
> ```
</details>
### 方法
- `setOption` [](https://echarts.apache.org/zh/api.html#echartsInstance.setOption)
- `getWidth` [](https://echarts.apache.org/zh/api.html#echartsInstance.getWidth)
- `getHeight` [](https://echarts.apache.org/zh/api.html#echartsInstance.getHeight)
- `getDom` [](https://echarts.apache.org/zh/api.html#echartsInstance.getDom)
- `getOption` [](https://echarts.apache.org/zh/api.html#echartsInstance.getOption)
- `resize` [](https://echarts.apache.org/zh/api.html#echartsInstance.resize)
- `dispatchAction` [](https://echarts.apache.org/zh/api.html#echartsInstance.dispatchAction)
- `convertToPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.convertToPixel)
- `convertFromPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.convertFromPixel)
- `containPixel` [](https://echarts.apache.org/zh/api.html#echartsInstance.containPixel)
- `showLoading` [](https://echarts.apache.org/zh/api.html#echartsInstance.showLoading)
- `hideLoading` [](https://echarts.apache.org/zh/api.html#echartsInstance.hideLoading)
- `getDataURL` [](https://echarts.apache.org/zh/api.html#echartsInstance.getDataURL)
- `getConnectedDataURL` [](https://echarts.apache.org/zh/api.html#echartsInstance.getConnectedDataURL)
- `clear` [](https://echarts.apache.org/zh/api.html#echartsInstance.clear)
- `dispose` [](https://echarts.apache.org/zh/api.html#echartsInstance.dispose)
### 静态方法
静态方法请直接通过 [`echarts` 本身](https://echarts.apache.org/zh/api.html#echarts)进行调用。
## 迁移到 v6
> 💡 请确保同时查阅 ECharts 5 的[升级指南](https://echarts.apache.org/zh/tutorial.html#ECharts%205%20%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97)。
@ -494,7 +459,7 @@ Vue-ECharts 支持如下事件:
### Vue 2 支持
- 要在 Vue 2 中使用 Vue-ECharts现在必须安装 `@vue/composition-api`
- 要在 `vue@2.7.0` 之前的版本中使用 Vue-ECharts必须安装 `@vue/composition-api`
### Prop

16381
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +1,82 @@
{
"name": "vue-echarts",
"version": "6.4.0",
"description": "Vue.js component for Apache ECharts.",
"version": "6.0.0-rc.1",
"repository": "https://github.com/ecomfe/vue-echarts.git",
"license": "MIT",
"author": "GU Yiling <justice360@gmail.com>",
"scripts": {
"serve": "vue-cli-service serve",
"build:demo": "vue-cli-service build",
"build": "npm run readme && rimraf dist && rollup -c rollup.config.js",
"build": "pnpm run docs && rimraf dist && pnpm run build:2 && pnpm run build:3 && vue-demi-switch 3",
"build:2": "vue-demi-switch 2 vue2 && rollup -c rollup.vue2.config.js",
"build:3": "vue-demi-switch 3 && rollup -c rollup.config.js",
"lint": "vue-cli-service lint",
"prepare": "npm run build",
"build:demo": "vue-cli-service build",
"docs": "node -r esm ./scripts/docs.js",
"postinstall": "node ./scripts/postinstall.js",
"readme": "node -r esm ./scripts/readme.js"
"prepare": "pnpm run build"
},
"main": "dist/index.cjs.min.js",
"module": "dist/index.esm.min.js",
"unpkg": "dist/index.umd.min.js",
"jsdelivr": "dist/index.umd.min.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"scripts/postinstall.js"
],
"dependencies": {
"resize-detector": "^0.3.0",
"vue-demi": "^0.7.1"
"vue-demi": "^0.13.2"
},
"devDependencies": {
"@babel/core": "^7.17.10",
"@rollup/plugin-node-resolve": "^11.1.1",
"@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"@vue/composition-api": "^1.0.0-rc.1",
"@typescript-eslint/eslint-plugin": "^4.15.1",
"@typescript-eslint/parser": "^4.15.1",
"@vue/cli-plugin-babel": "^5.0.4",
"@vue/cli-plugin-eslint": "^5.0.4",
"@vue/cli-plugin-typescript": "^5.0.4",
"@vue/cli-service": "^5.0.4",
"@vue/compiler-sfc": "^3.2.33",
"@vue/composition-api": "^1.7.0",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^5.0.2",
"codesandbox": "^2.2.1",
"@vue/eslint-config-typescript": "^10.0.0",
"comment-mark": "^1.0.0",
"echarts": "^5.0.2",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^7.0.0-0",
"core-js": "^3.23.0",
"echarts": "^5.3.2",
"echarts-liquidfill": "^3.1.0",
"eslint": "^7.20.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^8.7.1",
"esm": "^3.2.25",
"postcss": "^8.2.5",
"postcss": "^8.3.0",
"postcss-loader": "^5.0.0",
"postcss-nested": "^4.2.3",
"prettier": "^1.19.1",
"postcss-nested": "^5.0.5",
"prettier": "^2.6.2",
"qs": "^6.10.5",
"raw-loader": "^4.0.2",
"resize-detector": "^0.3.0",
"rimraf": "^3.0.2",
"rollup": "^2.38.5",
"rollup-plugin-dts": "^2.0.1",
"rollup-plugin-postcss": "^4.0.0",
"rollup": "^2.72.1",
"rollup-plugin-dts": "^4.2.1",
"rollup-plugin-styles": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.29.0",
"typescript": "^4.1.3",
"vue": "^3.0.5"
"rollup-plugin-ts": "^2.0.7",
"tslib": "^2.4.0",
"typescript": "4.6.4",
"vue": "^3.2.33",
"vue2": "npm:vue@^2.7.14",
"webpack": "^5.72.1"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.2",
"echarts": "^5.0.2",
"vue": "^2.6.12 || ^3.0.0"
"@vue/composition-api": "^1.0.5",
"echarts": "^5.1.2",
"vue": "^2.6.12 || ^3.1.1"
},
"jsdelivr": "dist/index.umd.min.js",
"license": "MIT",
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"repository": "https://github.com/ecomfe/vue-echarts.git",
"types": "dist/index.d.ts"
}

7838
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,38 @@
import typescript from "rollup-plugin-typescript2";
import typescript from "rollup-plugin-ts";
import { terser } from "rollup-plugin-terser";
import resolve from "@rollup/plugin-node-resolve";
import postcss from "rollup-plugin-postcss";
import dts from "rollup-plugin-dts";
import { injectVueDemi, ingoreCss } from "./scripts/rollup";
import styles from "rollup-plugin-styles";
import { injectVueDemi } from "./scripts/rollup";
/** @type {import('rollup').RollupOptions} */
/** @type {import('rollup').RollupOptions[]} */
const options = [
{
input: "src/index.ts",
plugins: [typescript(), postcss()],
plugins: [
typescript({
tsconfig: resolvedConfig => ({ ...resolvedConfig, declaration: true }),
hook: {
outputPath: (path, kind) =>
kind === "declaration" ? "dist/index.d.ts" : path
}
}),
styles()
],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: {
file: "dist/index.esm.js",
format: "esm",
sourcemap: true
}
},
{
input: "src/index.ts",
plugins: [typescript(), styles()],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: [
{
file: "dist/index.esm.js",
format: "es",
sourcemap: true
},
{
file: "dist/index.esm.min.js",
format: "es",
format: "esm",
sourcemap: true,
plugins: [
terser({
@ -52,7 +65,7 @@ const options = [
},
{
input: "src/global.ts",
plugins: [resolve(), typescript(), postcss()],
plugins: [resolve(), typescript(), styles()],
external: ["vue-demi", "echarts", "echarts/core"],
output: [
{
@ -89,14 +102,6 @@ const options = [
]
}
]
},
{
input: "src/index.ts",
plugins: [ingoreCss, dts()],
output: {
file: "dist/index.d.ts",
format: "es"
}
}
];

15
rollup.vue2.config.js Normal file
View File

@ -0,0 +1,15 @@
import dts from "rollup-plugin-dts";
/** @type {import('rollup').RollupOptions[]} */
const options = [
{
input: "src/index.vue2.d.ts",
plugins: [dts()],
output: {
file: "dist/index.vue2.d.ts",
format: "esm"
}
}
];
export default options;

View File

@ -1,7 +1,6 @@
import fs from "fs";
import { resolve } from "path";
import commentMark from "comment-mark";
import { getParameters } from "codesandbox/lib/api/define";
import { name, version } from "../package.json";
const { readFile, writeFile } = fs.promises;
@ -9,16 +8,15 @@ const { readFile, writeFile } = fs.promises;
const CDN_PREFIX = "https://cdn.jsdelivr.net/npm/";
const DEP_VERSIONS = {
"vue@3": "3.0.7",
"vue@2": "2.6.12",
"@vue/composition-api": "1.0.0-rc.3",
echarts: "5.0.2",
"vue@3": "3.2.37",
"vue@2": "2.7.5",
echarts: "5.3.3",
[name]: version
};
const markConfig = {
vue3Scripts: ["vue@3", "echarts", name],
vue2Scripts: ["vue@2", "@vue/composition-api", "echarts", name]
vue2Scripts: ["vue@2", "echarts", name]
};
function getScripts(version) {
@ -40,38 +38,6 @@ const scripts = {
3: getScripts(3)
};
async function getSandboxParams(version) {
const [html, js, css] = await Promise.all(
["index.html", `vue${version}.js`, "index.css"].map(async name => {
const file = resolve(__dirname, `./sandbox/${name}`);
return readFile(file, "utf-8");
})
);
return {
files: {
"index.html": {
content: `<!DOCTYPE html>
<html>
<head>
<style>
${css}</style>
</head>
<body>
${html}${scripts[version]}
<script>
${js}</script>
</body>
</html>`
}
}
};
}
async function getDemoLink(version) {
const parameters = getParameters(await getSandboxParams(version));
return `[Demo →](${`https://codesandbox.io/api/v1/sandboxes/define?parameters=${parameters}`})`;
}
const README_FILES = ["README.md", "README.zh-Hans.md"].map(name =>
resolve(__dirname, "..", name)
);
@ -79,19 +45,15 @@ const README_FILES = ["README.md", "README.zh-Hans.md"].map(name =>
function exec() {
return Promise.all(
README_FILES.map(async file => {
const content = await readFile(file, "utf-8");
const [link2, link3] = await Promise.all([2, 3].map(getDemoLink));
const content = await readFile(file, "utf8");
return writeFile(
file,
commentMark(content, {
vue2Scripts: getCodeBlock(scripts[2]),
vue3Scripts: getCodeBlock(scripts[3]),
vue2Demo: `\n${link2}\n`,
vue3Demo: `\n${link3}\n`
vue3Scripts: getCodeBlock(scripts[3])
}),
"utf-8"
"utf8"
);
})
);

View File

@ -11,10 +11,10 @@ const typesPaths = {
function switchVersion(version) {
const typesPath = typesPaths[version];
const package = JSON.parse(fs.readFileSync(packageFile, "utf-8"));
const current = package.types || package.typings;
if (typesPath !== current) {
fs.writeFileSync(JSON.stringify(package, null, " "));
const package = JSON.parse(fs.readFileSync(packageFile, "utf8"));
if (typesPath !== package.types) {
package.types = typesPath;
fs.writeFileSync(packageFile, JSON.stringify(package, null, " "), "utf8");
}
console.log(`[vue-echarts] Switched to Vue ${version} environment.`);
}

View File

@ -2,7 +2,7 @@ import { readFileSync } from "fs";
const VUE_DEMI_IIFE = readFileSync(
require.resolve("vue-demi/lib/index.iife.js"),
"utf-8"
"utf8"
);
/** @type {import('rollup').Plugin} */

View File

@ -1,55 +0,0 @@
Vue.component("v-chart", VueECharts);
new Vue({
el: "#app",
data() {
return {
option: {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif'
},
title: {
text: "Traffic Sources",
left: "center"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: "vertical",
left: "left",
data: [
"Direct",
"Email",
"Ad Networks",
"Video Ads",
"Search Engines"
]
},
series: [
{
name: "Traffic Sources",
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
}
};
}
});

View File

@ -1,54 +0,0 @@
Vue.createApp({
data() {
return {
option: {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif'
},
title: {
text: "Traffic Sources",
left: "center"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: "vertical",
left: "left",
data: [
"Direct",
"Email",
"Ad Networks",
"Video Ads",
"Search Engines"
]
},
series: [
{
name: "Traffic Sources",
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
}
};
}
})
.component("v-chart", VueECharts)
.mount("#app");

View File

@ -1,32 +1,34 @@
/* eslint-disable vue/multi-word-component-names */
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
defineComponent,
ref,
unref,
shallowRef,
toRef,
toRefs,
watch,
computed,
inject,
onMounted,
onUnmounted,
onBeforeUnmount,
h,
nextTick,
PropType,
watchEffect,
Vue2
getCurrentInstance,
Vue2,
type PropType,
type InjectionKey
} from "vue-demi";
import { init as initChart } from "echarts/core";
import {
import type {
EChartsType,
EventTarget,
Option,
Theme,
ThemeInjection,
InitOptions,
InitOptionsInjection,
UpdateOptions,
UpdateOptionsInjection
UpdateOptionsInjection,
Emits
} from "./types";
import {
usePublicAPI,
@ -35,18 +37,21 @@ import {
useLoading,
loadingProps
} from "./composables";
import { omitOn, unwrapInjected } from "./utils";
import { register, TAG_NAME, type EChartsElement } from "./wc";
import "./style.css";
import { omitOn } from "./utils";
const TAG_NAME = "x-vue-echarts";
const wcRegistered = register();
if (Vue2) {
Vue2.config.ignoredElements.push(TAG_NAME);
}
export const THEME_KEY = "ecTheme";
export const INIT_OPTIONS_KEY = "ecInitOptions";
export const UPDATE_OPTIONS_KEY = "ecUpdateOptions";
export const THEME_KEY = "ecTheme" as unknown as InjectionKey<ThemeInjection>;
export const INIT_OPTIONS_KEY =
"ecInitOptions" as unknown as InjectionKey<InitOptionsInjection>;
export const UPDATE_OPTIONS_KEY =
"ecUpdateOptions" as unknown as InjectionKey<UpdateOptionsInjection>;
export { LOADING_OPTIONS_KEY } from "./composables";
export default defineComponent({
@ -63,42 +68,37 @@ export default defineComponent({
...autoresizeProps,
...loadingProps
},
emits: [] as unknown as Emits,
inheritAttrs: false,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// @ts-expect-error
setup(props, { attrs, listeners }) {
const root = ref<HTMLElement>();
setup(props, { attrs }) {
const root = shallowRef<EChartsElement>();
const chart = shallowRef<EChartsType>();
const manualOption = shallowRef<Option>();
const defaultTheme = inject(THEME_KEY, null) as ThemeInjection;
const defaultInitOptions = inject(
INIT_OPTIONS_KEY,
null
) as InitOptionsInjection;
const defaultUpdateOptions = inject(
UPDATE_OPTIONS_KEY,
null
) as UpdateOptionsInjection;
const defaultTheme = inject(THEME_KEY, null);
const defaultInitOptions = inject(INIT_OPTIONS_KEY, null);
const defaultUpdateOptions = inject(UPDATE_OPTIONS_KEY, null);
const { autoresize, manualUpdate, loading, loadingOptions } = toRefs(props);
const realOption = computed(
() => manualOption.value || props.option || Object.create(null)
() => manualOption.value || props.option || null
);
const realTheme = computed(
() => props.theme || unwrapInjected(defaultTheme, {})
);
const realTheme = computed(() => props.theme || unref(defaultTheme) || {});
const realInitOptions = computed(
() => props.initOptions || unref(defaultInitOptions) || {}
() => props.initOptions || unwrapInjected(defaultInitOptions, {})
);
const realUpdateOptions = computed(
() => props.updateOptions || unref(defaultUpdateOptions) || {}
() => props.updateOptions || unwrapInjected(defaultUpdateOptions, {})
);
const { autoresize, manualUpdate, loading } = toRefs(props);
const theme = toRef(props, "theme");
const initOptions = toRef(props, "initOptions");
const loadingOptions = toRef(props, "loadingOptions");
const nonEventAttrs = computed(() => omitOn(attrs));
// @ts-expect-error listeners for Vue 2 compatibility
const listeners = getCurrentInstance().proxy.$listeners;
function init(option?: Option) {
if (chart.value || !root.value) {
if (!root.value) {
return;
}
@ -121,35 +121,77 @@ export default defineComponent({
.forEach(key => {
// onClick -> c + lick
// onZr:click -> z + r:click
const event = key.charAt(2).toLowerCase() + key.slice(3);
let event = key.charAt(2).toLowerCase() + key.slice(3);
// clickOnce -> ~click
// zr:clickOnce -> ~zr:click
if (event.substring(event.length - 4) === "Once") {
event = `~${event.substring(0, event.length - 4)}`;
}
realListeners[event] = attrs[key];
});
}
Object.keys(realListeners).forEach(key => {
const handler = realListeners[key] as any;
let handler = realListeners[key];
if (!handler) {
return;
}
if (key.indexOf("zr:") === 0) {
instance.getZr().on(key.slice(3).toLowerCase(), handler);
} else {
instance.on(key.toLowerCase(), handler);
let event = key.toLowerCase();
if (event.charAt(0) === "~") {
event = event.substring(1);
handler.__once__ = true;
}
});
instance.setOption(option || realOption.value, realUpdateOptions.value);
let target: EventTarget = instance;
if (event.indexOf("zr:") === 0) {
target = instance.getZr();
event = event.substring(3);
}
if (handler.__once__) {
delete handler.__once__;
const raw = handler;
handler = (...args: any[]) => {
raw(...args);
target.off(event, handler);
};
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore EChartsType["on"] is not compatible with ZRenderType["on"]
// but it's okay here
target.on(event, handler);
});
function resize() {
if (instance && !instance.isDisposed()) {
instance.resize();
}
}
// Make sure the chart fits the container in next UI render (after current task)
nextTick(resize);
setTimeout(resize);
function commit() {
const opt = option || realOption.value;
if (opt) {
instance.setOption(opt, realUpdateOptions.value);
}
}
if (autoresize.value) {
// Try to make chart fit to container in case container size
// is changed synchronously or in already queued microtasks
nextTick(() => {
resize();
commit();
});
} else {
commit();
}
}
function setOption(option: Option, updateOptions?: UpdateOptions) {
@ -160,10 +202,7 @@ export default defineComponent({
if (!chart.value) {
init(option);
} else {
chart.value.setOption(option, {
...realUpdateOptions.value,
...updateOptions
});
chart.value.setOption(option, updateOptions || {});
}
}
@ -186,14 +225,17 @@ export default defineComponent({
if (!manualUpdate) {
unwatchOption = watch(
() => props.option,
option => {
(option, oldOption) => {
if (!option) {
return;
}
if (!chart.value) {
init();
} else {
chart.value.setOption(option, props.updateOptions);
chart.value.setOption(option, {
notMerge: option.value !== oldOption?.value,
...realUpdateOptions.value
});
}
},
{ deep: true }
@ -206,7 +248,7 @@ export default defineComponent({
);
watch(
[theme, initOptions],
[realTheme, realInitOptions],
() => {
cleanup();
init();
@ -222,36 +264,42 @@ export default defineComponent({
}
});
const publicApi = usePublicAPI(chart, init);
const publicApi = usePublicAPI(chart);
useLoading(chart, loading, loadingOptions);
useAutoresize(chart, autoresize, root, realOption);
useAutoresize(chart, autoresize, root);
onMounted(() => {
if (props.option) {
init();
init();
});
onBeforeUnmount(() => {
if (wcRegistered && root.value) {
// For registered web component, we can leverage the
// `disconnectedCallback` to dispose the chart instance
// so that we can delay the cleanup after exsiting leaving
// transition.
root.value.__dispose = cleanup;
} else {
cleanup();
}
});
onUnmounted(cleanup);
const exposed = {
return {
chart,
root,
setOption,
nonEventAttrs,
...publicApi
};
Object.defineProperty(exposed, "chart", {
get() {
return unref(chart);
}
});
return exposed;
},
render() {
const attrs = { ...this.nonEventAttrs };
// Vue 3 and Vue 2 have different vnode props format:
// See https://v3-migration.vuejs.org/breaking-changes/render-function-api.html#vnode-props-format
const attrs = (
Vue2 ? { attrs: this.nonEventAttrs } : { ...this.nonEventAttrs }
) as any;
attrs.ref = "root";
attrs.class = attrs.class ? ["echarts"].concat(attrs.class) : "echarts";
return h(TAG_NAME, attrs);

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Ref } from "vue-demi";
import { EChartsType, Option } from "../types";
import { EChartsType } from "../types";
const METHOD_NAMES = [
"getWidth",
@ -19,22 +19,18 @@ const METHOD_NAMES = [
"isDisposed",
"dispose"
] as const;
type MethodName = typeof METHOD_NAMES[number];
type PublicMethods = Pick<EChartsType, MethodName>;
export function usePublicAPI(
chart: Ref<EChartsType | undefined>,
init: (option?: Option) => void
) {
chart: Ref<EChartsType | undefined>
): PublicMethods {
function makePublicMethod<T extends MethodName>(
name: T
): (...args: Parameters<EChartsType[T]>) => ReturnType<EChartsType[T]> {
return (...args) => {
if (!chart.value) {
init();
}
if (!chart.value) {
throw new Error("ECharts is not initialized yet.");
}
@ -42,12 +38,6 @@ export function usePublicAPI(
};
}
function makeAnyMethod<T extends MethodName>(
name: T
): (...args: any[]) => ReturnType<EChartsType[T]> {
return makePublicMethod(name) as any;
}
function makePublicMethods(): PublicMethods {
const methods = Object.create(null);
METHOD_NAMES.forEach(name => {
@ -57,10 +47,5 @@ export function usePublicAPI(
return methods as PublicMethods;
}
return {
...makePublicMethods(),
dispatchAction: makeAnyMethod("dispatchAction"),
getDataURL: makeAnyMethod("getDataURL"),
getConnectedDataURL: makeAnyMethod("getConnectedDataURL")
};
return makePublicMethods();
}

View File

@ -1,37 +1,19 @@
import { Ref, watch } from "vue-demi";
import { throttle } from "echarts/core";
import { addListener, removeListener, ResizeCallback } from "resize-detector";
import { EChartsType, Option } from "../types";
import { EChartsType } from "../types";
export function useAutoresize(
chart: Ref<EChartsType | undefined>,
autoresize: Ref<boolean>,
root: Ref<HTMLElement | undefined>,
option: Ref<Option>
root: Ref<HTMLElement | undefined>
): void {
let resizeListener: ResizeCallback | null = null;
let lastArea = 0;
function getArea() {
const el = root.value;
if (!el) {
return 0;
}
return el.offsetWidth * el.offsetHeight;
}
watch([root, chart, autoresize], ([root, chart, autoresize], _, cleanup) => {
if (root && chart && autoresize) {
lastArea = getArea();
resizeListener = throttle(() => {
if (lastArea === 0) {
chart.setOption(Object.create(null), true);
chart.resize();
chart.setOption(option.value, true);
} else {
chart.resize();
}
lastArea = getArea();
chart.resize();
}, 100);
addListener(root, resizeListener);
@ -39,7 +21,6 @@ export function useAutoresize(
cleanup(() => {
if (resizeListener && root) {
lastArea = 0;
removeListener(root, resizeListener);
}
});

View File

@ -1,18 +1,28 @@
import { inject, unref, computed, Ref, watchEffect } from "vue-demi";
import { unwrapInjected } from "../utils";
import {
inject,
computed,
watchEffect,
type Ref,
type InjectionKey
} from "vue-demi";
import { EChartsType } from "../types";
export const LOADING_OPTIONS_KEY = "ecLoadingOptions";
export const LOADING_OPTIONS_KEY =
"ecLoadingOptions" as unknown as InjectionKey<
UnknownRecord | Ref<UnknownRecord>
>;
type UnknownRecord = Record<string, unknown>;
export function useLoading(
chart: Ref<EChartsType | undefined>,
loading: Ref<boolean>,
loadingOptions: Ref<object | undefined>
loadingOptions: Ref<UnknownRecord | undefined>
): void {
const defaultLoadingOptions = inject(LOADING_OPTIONS_KEY, {}) as
| object
| Ref<object>;
const defaultLoadingOptions = inject(LOADING_OPTIONS_KEY, {});
const realLoadingOptions = computed(() => ({
...unref(defaultLoadingOptions),
...unwrapInjected(defaultLoadingOptions, {}),
...loadingOptions?.value
}));

View File

@ -1,8 +1,15 @@
<template>
<main>
<!-- <v-chart
class="echarts" id="logo" :option="logo" :init-options="initOptions" autoresize /> -->
<h1><a href="https://github.com/ecomfe/vue-echarts">Vue-ECharts</a></h1>
<v-chart
class="echarts"
id="logo"
:option="logo"
:init-options="initOptions"
autoresize
/>
<h1>
<a href="https://github.com/ecomfe/vue-echarts">Vue-ECharts</a>
</h1>
<p class="desc">
Vue.js component for Apache ECharts. (<a
href="https://github.com/ecomfe/vue-echarts#readme"
@ -11,9 +18,10 @@
</p>
<h2 id="bar">
<a href="#bar"
>Bar chart <small>(with async data &amp; custom theme)</small></a
>
<a href="#bar">
Bar chart
<small>(with async data &amp; custom theme)</small>
</a>
<button
:class="{
round: true,
@ -37,19 +45,26 @@
@click="handleClick"
/>
</figure>
<p v-if="seconds <= 0"><small>Loaded.</small></p>
<p v-else>
<small
>Data coming in <b>{{ seconds }}</b> second{{
seconds > 1 ? "s" : ""
}}...</small
>
<p v-if="seconds <= 0">
<small>Loaded.</small>
</p>
<p v-else>
<small>
Data coming in
<b>{{ seconds }}</b>
second{{ seconds > 1 ? "s" : "" }}...
</small>
</p>
<p>
<button @click="refresh" :disabled="seconds > 0">Refresh</button>
</p>
<p><button @click="refresh" :disabled="seconds > 0">Refresh</button></p>
</section>
<h2 id="pie">
<a href="#pie">Pie chart <small>(with action dispatch)</small></a>
<a href="#pie">
Pie chart
<small>(with action dispatch)</small>
</a>
<button
:class="{
round: true,
@ -71,7 +86,10 @@
</section>
<h2 id="polar">
<a href="#polar">Polar plot <small>(with built-in theme)</small></a>
<a href="#polar">
Polar plot
<small>(with built-in theme)</small>
</a>
<button
:class="{
round: true,
@ -100,7 +118,10 @@
</section>
<h2 id="scatter">
<a href="#scatter">Scatter plot <small>(with gradient)</small></a>
<a href="#scatter">
Scatter plot
<small>(with gradient)</small>
</a>
<button
:class="{
round: true,
@ -117,7 +138,10 @@
</section>
<h2 id="map">
<a href="#map">Map <small>(with GeoJSON &amp; image converter)</small></a>
<a href="#map">
Map
<small>(with GeoJSON &amp; image converter)</small>
</a>
<button
:class="{
round: true,
@ -128,7 +152,7 @@
></button>
</h2>
<section v-if="expand.map">
<figure style="background-color: #404a59;">
<figure style="background-color: #404a59">
<v-chart
:option="map"
:init-options="initOptions"
@ -136,7 +160,9 @@
autoresize
/>
</figure>
<p><button @click="convert">Convert to image</button></p>
<p>
<button @click="convert">Convert to image</button>
</p>
</section>
<!-- <h2 id="radar">
@ -166,7 +192,7 @@
<input id="async" type="checkbox" v-model="asyncCount" />
<label for="async">Async</label>
</p>
</section> -->
</section>-->
<h2 id="connect">
<a href="#connect">Connectable charts</a>
@ -219,13 +245,15 @@
</h2>
<section v-if="expand.flight">
<p>
<small
>You may use <code>manual-update</code> prop for performance critical
use cases.</small
>
<small>
You may use
<code>manual-update</code> prop for performance critical use cases.
</small>
</p>
<p><button :disabled="flightLoaded" @click="loadFlights">Load</button></p>
<figure style="background-color: #003;">
<p>
<button :disabled="flightLoaded" @click="loadFlights">Load</button>
</p>
<figure style="background-color: #003">
<v-chart
ref="flight"
:init-options="initOptions"
@ -238,10 +266,11 @@
</section>
<footer>
<a href="//github.com/Justineo">@Justineo</a>|<a
href="//github.com/ecomfe/vue-echarts/blob/master/LICENSE"
<a href="//github.com/Justineo">@Justineo</a>|
<a href="//github.com/ecomfe/vue-echarts/blob/master/LICENSE"
>MIT License</a
>|<a href="//github.com/ecomfe/vue-echarts">View on GitHub</a>
>|
<a href="//github.com/ecomfe/vue-echarts">View on GitHub</a>
</footer>
<aside :class="{ modal: true, open }" @click="open = false">
@ -274,7 +303,13 @@
import qs from "qs";
import VChart from "../ECharts";
import * as echarts from "echarts/core";
import {
use,
registerMap,
registerTheme,
connect,
disconnect
} from "echarts/core";
import {
BarChart,
LineChart,
@ -293,11 +328,26 @@ import {
LegendComponent,
TitleComponent,
VisualMapComponent,
DatasetComponent
DatasetComponent,
ToolboxComponent,
DataZoomComponent
} from "echarts/components";
import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
import "echarts-liquidfill";
import logo from "./data/logo";
import getBar from "./data/bar";
import pie from "./data/pie";
import polar from "./data/polar";
import scatter from "./data/scatter";
import map from "./data/map";
import { c1, c2 } from "./data/connect";
const { use, registerMap, registerTheme } = echarts;
// custom theme
import theme from "./theme.json";
// Map of China
import chinaMap from "./china.json";
import worldMap from "./world.json";
use([
BarChart,
@ -317,25 +367,11 @@ use([
VisualMapComponent,
DatasetComponent,
CanvasRenderer,
SVGRenderer
SVGRenderer,
ToolboxComponent,
DataZoomComponent
]);
// import "echarts-liquidfill";
// import logo from "./data/logo";
import getBar from "./data/bar";
import pie from "./data/pie";
import polar from "./data/polar";
import scatter from "./data/scatter";
import map from "./data/map";
import { c1, c2 } from "./data/connect";
// custom theme
import theme from "./theme.json";
// Map of China
import chinaMap from "./china.json";
import worldMap from "./world.json";
// registering map data
registerMap("china", chinaMap);
registerMap("world", worldMap);
@ -344,6 +380,7 @@ registerMap("world", worldMap);
registerTheme("ovilia-green", theme);
export default {
name: "vue-echarts-demo",
components: {
VChart
},
@ -351,6 +388,7 @@ export default {
const options = qs.parse(location.search, { ignoreQueryPrefix: true });
return {
options,
logo,
bar: getBar(),
pie,
polar,
@ -444,7 +482,7 @@ export default {
function getAirportCoord(idx) {
return [data.airports[idx][3], data.airports[idx][4]];
}
const routes = data.routes.map(function(airline) {
const routes = data.routes.map(airline => {
return [getAirportCoord(airline[1]), getAirportCoord(airline[2])];
});
@ -533,7 +571,11 @@ export default {
watch: {
connected: {
handler(value) {
echarts[value ? "connect" : "disconnect"]("radiance");
if (value) {
connect("radiance");
} else {
disconnect("radiance");
}
},
immediate: true
},
@ -557,6 +599,9 @@ export default {
},
mounted() {
this.startActions();
},
beforeUnmount() {
this.stopActions();
}
};
</script>
@ -680,7 +725,6 @@ select {
font: inherit;
padding: 0 0.5em;
transition: opacity 0.3s;
-webkit-appearance: none;
transition: all 0.2s;
&:focus {
@ -851,10 +895,6 @@ figure {
font-size: 0.8em;
}
select {
-webkit-appearance: none;
}
input[type="checkbox"] {
display: none;

View File

@ -12,27 +12,27 @@ export default function getData() {
source: [
{
Product: "Matcha Latte",
"2015": random(),
"2016": random(),
"2017": random()
2015: random(),
2016: random(),
2017: random()
},
{
Product: "Milk Tea",
"2015": random(),
"2016": random(),
"2017": random()
2015: random(),
2016: random(),
2017: random()
},
{
Product: "Cheese Cocoa",
"2015": random(),
"2016": random(),
"2017": random()
2015: random(),
2016: random(),
2017: random()
},
{
Product: "Walnut Brownie",
"2015": random(),
"2016": random(),
"2017": random()
2015: random(),
2016: random(),
2017: random()
}
]
},

View File

@ -446,7 +446,7 @@ export default {
data: convertData(data),
symbolSize: val => val[2] / 10,
tooltip: {
formatter: function(val) {
formatter: function (val) {
return val.name + ": " + val.value[2];
}
},
@ -468,7 +468,7 @@ export default {
scale: true
},
tooltip: {
formatter: function(val) {
formatter: function (val) {
return val.name + ": " + val.value[2];
}
},

5
src/demo/jsconfig.json Normal file
View File

@ -0,0 +1,5 @@
{
"files": [
"./Demo.vue"
],
}

58
src/index.vue2.d.ts vendored
View File

@ -1,9 +1,63 @@
/* eslint-disable @typescript-eslint/ban-types */
import type { Ref, DefineComponent } from "vue-demi";
import type {
Option,
InitOptions,
UpdateOptions,
EChartsType,
Emits
} from "./types";
declare const LOADING_OPTIONS_KEY = "ecLoadingOptions";
declare const THEME_KEY = "ecTheme";
declare const INIT_OPTIONS_KEY = "ecInitOptions";
declare const UPDATE_OPTIONS_KEY = "ecUpdateOptions";
declare const _default: any;
declare type ChartProps = {
loading?: boolean;
loadingOptions?: Record<string, unknown>;
autoresize?: boolean;
option?: Option;
theme?: string | Record<string, unknown>;
initOptions?: InitOptions;
updateOptions?: UpdateOptions;
group?: string;
manualUpdate?: boolean;
};
export default _default;
type MethodNames =
| "getWidth"
| "getHeight"
| "getDom"
| "getOption"
| "resize"
| "dispatchAction"
| "convertToPixel"
| "convertFromPixel"
| "containPixel"
| "getDataURL"
| "getConnectedDataURL"
| "appendData"
| "clear"
| "isDisposed"
| "dispose"
| "setOption";
declare type ChartMethods = Pick<EChartsType, MethodNames>;
declare const Chart: DefineComponent<
ChartProps,
{
root: Ref<HTMLElement | undefined>;
chart: Ref<EChartsType | undefined>;
},
{},
{},
ChartMethods,
{},
{},
Emits
>;
export default Chart;
export { INIT_OPTIONS_KEY, LOADING_OPTIONS_KEY, THEME_KEY, UPDATE_OPTIONS_KEY };

View File

@ -1 +1 @@
x-vue-echarts{display:block;width:100%;height:100%}
x-vue-echarts{display:block;width:100%;height:100%;min-width:0}

View File

@ -1,28 +1,83 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { init } from "echarts/core";
import { Ref } from "vue";
import { init, type SetOptionOpts } from "echarts/core";
import type { Ref } from "vue";
export type Injection<T> = T | null | Ref<T | null> | { value: T | null };
type InitType = typeof init;
export type InitParameters = Parameters<InitType>;
export type Theme = NonNullable<InitParameters[1]>;
export type ThemeInjection = Theme | null | Ref<Theme | null>;
export type ThemeInjection = Injection<Theme>;
export type InitOptions = NonNullable<InitParameters[2]>;
export type InitOptionsInjection = InitOptions | null | Ref<InitOptions | null>;
export type InitOptionsInjection = Injection<InitOptions>;
export type UpdateOptions = SetOptionOpts;
export type UpdateOptionsInjection = Injection<UpdateOptions>;
export type EChartsType = ReturnType<InitType>;
type ZRenderType = ReturnType<EChartsType["getZr"]>;
export type EventTarget = EChartsType | ZRenderType;
type SetOptionType = EChartsType["setOption"];
export type Option = Parameters<SetOptionType>[0];
// TODO: Wait for apache/echarts#14289 to ship in v5.1,
// so that we can use SetOptionOpts directly
export interface UpdateOptions {
notMerge?: boolean;
lazyUpdate?: boolean;
silent?: boolean;
replaceMerge?: any;
transition?: any;
}
export type UpdateOptionsInjection =
| UpdateOptions
| null
| Ref<UpdateOptions | null>;
type EChartsEventName =
| "click"
| "dblclick"
| "mousedown"
| "mousemove"
| "mouseup"
| "mouseover"
| "mouseout"
| "globalout"
| "contextmenu"
| "highlight"
| "downplay"
| "selectchanged"
| "legendselectchanged"
| "legendselected"
| "legendunselected"
| "legendselectall"
| "legendinverseselect"
| "legendscroll"
| "datazoom"
| "datarangeselected"
| "graphroam"
| "georoam"
| "treeroam"
| "timelinechanged"
| "timelineplaychanged"
| "restore"
| "dataviewchanged"
| "magictypechanged"
| "geoselectchanged"
| "geoselected"
| "geounselected"
| "axisareaselected"
| "brush"
| "brushEnd"
| "brushselected"
| "globalcursortaken"
| "rendered"
| "finished";
type ZRenderEventName =
| "click"
| "dblclick"
| "mousewheel"
| "mouseout"
| "mouseover"
| "mouseup"
| "mousedown"
| "mousemove"
| "contextmenu"
| "drag"
| "dragstart"
| "dragend"
| "dragenter"
| "dragleave"
| "dragover"
| "drop"
| "globalout";
type EventName = EChartsEventName | `zr:${ZRenderEventName}`;
export type Emits = {
[key in EventName]: null;
};

View File

@ -1,3 +1,6 @@
import { unref } from "vue-demi";
import type { Injection } from "./types";
type Attrs = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
@ -6,9 +9,9 @@ type Attrs = {
// Copied from
// https://github.com/vuejs/vue-next/blob/5a7a1b8293822219283d6e267496bec02234b0bc/packages/shared/src/index.ts#L40-L41
const onRE = /^on[^a-z]/;
export const isOn = (key: string) => onRE.test(key);
export const isOn = (key: string): boolean => onRE.test(key);
export function omitOn(attrs: Attrs) {
export function omitOn(attrs: Attrs): Attrs {
const result: Attrs = {};
for (const key in attrs) {
if (!isOn(key)) {
@ -18,3 +21,16 @@ export function omitOn(attrs: Attrs) {
return result;
}
export function unwrapInjected<T, V>(
injection: Injection<T>,
defaultValue: V
): T | V {
const value = unref(injection);
if (value && typeof value === "object" && "value" in value) {
return value.value || defaultValue;
}
return value || defaultValue;
}

51
src/wc.ts Normal file
View File

@ -0,0 +1,51 @@
let registered: boolean | null = null;
export const TAG_NAME = "x-vue-echarts";
export interface EChartsElement extends HTMLElement {
__dispose: (() => void) | null;
}
export function register(): boolean {
if (registered != null) {
return registered;
}
if (
typeof HTMLElement === "undefined" ||
typeof customElements === "undefined"
) {
return (registered = false);
}
try {
// Class definitions cannot be transpiled to ES5
// so we are doing a little trick here to ensure
// we are using native classes. As we use this as
// a progressive enhancement, it will be fine even
// if the browser doesn't support native classes.
const reg = new Function(
"tag",
`class EChartsElement extends HTMLElement {
__dispose = null;
disconnectedCallback() {
if (this.__dispose) {
this.__dispose();
this.__dispose = null;
}
}
}
if (customElements.get(tag) == null) {
customElements.define(tag, EChartsElement);
}
`
);
reg(TAG_NAME);
} catch (e) {
return (registered = false);
}
return (registered = true);
}

View File

@ -1,4 +1,5 @@
{
"allowJs": true,
"compilerOptions": {
"target": "ES5",
"module": "ESNext",
@ -12,7 +13,6 @@
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": ["webpack-env"],
"lib": ["ESNext", "DOM", "DOM.Iterable", "ScriptHost"]
},
"include": [

View File

@ -6,14 +6,20 @@ module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [nested()]
postcssOptions: {
plugins: [nested()]
}
}
}
},
chainWebpack: config => {
config
.entry("app")
config.entry("app").clear().add("./src/demo/main.ts");
config.module
.rule("svg")
.clear()
.add("./src/demo/main.ts");
.test(/\.svg$/)
.use("raw-loader")
.loader("raw-loader");
}
};