Compare commits

..

36 Commits

Author SHA1 Message Date
4f3a6ac0a3 fix: fix event types and bump to 7.0.0 2024-08-03 16:17:46 +08:00
e967bfc1fe docs: update migration part in readme 2024-07-25 23:54:58 +08:00
a9c54e1dc5 docs: update readme 2024-07-25 23:21:49 +08:00
d941e35a61 docs: update csp usage docs 2024-07-24 18:21:56 +08:00
3c063ed21e chore: update changelog and lint config 2024-07-24 18:21:56 +08:00
c0b0d2d0be chore: update changelog 2024-07-24 18:21:56 +08:00
2d310a3891 chore: update linter config 2024-07-24 18:21:56 +08:00
9fe76efa93 chore: update lock file 2024-07-24 18:21:56 +08:00
24ed18e439 docs: use local wasm file 2024-07-24 18:21:56 +08:00
6b98318504 build: add back umd, drop csp, share type between vue2/3 2024-07-24 18:21:56 +08:00
27c79b9012 feat!: move to esm and drop support for vue 2.6 2024-07-24 18:21:56 +08:00
861674352b docs: improve demo 2024-07-24 18:21:56 +08:00
fc53aee8a7 feat!: drop extra wrapper 2024-07-24 18:21:56 +08:00
da0109b07a refactor: improve import statements 2024-07-24 18:21:56 +08:00
7e5c06225c chore: update echarts deps 2024-07-24 18:21:56 +08:00
3c7ff95331 refactor!: remove resize-detector and update vue deps to 2.7+ 2024-07-24 18:21:56 +08:00
d774558f3e chore: fix disappeared logo in demo 2024-06-13 20:25:38 +08:00
5d23006866 chore: update demo 2024-06-11 20:05:05 +08:00
443eaa0367 chore: update readme 2024-06-04 23:14:19 +08:00
16f3f4b419 fix: fix padding style 2024-06-04 23:11:22 +08:00
e651d32334 fix(#783): chart should display after activation in <keep-alive> 2024-05-07 17:43:19 +08:00
a8e30b137a chore: update changelog and version 2024-04-23 19:49:16 +08:00
09808a47d2 fix: move events collecting from init to setup 2024-04-23 18:20:38 +08:00
898195c770 fix: fix esbuild wasm url in demo 2024-04-23 15:59:10 +08:00
07e0d067d5 chore: update deps 2024-04-23 10:55:48 +08:00
185940aecb docs: update changelog and version 2024-04-22 21:15:38 +08:00
def674bc6c refactor: improve readability and add more comments to explain native event handling 2024-04-22 21:08:02 +08:00
feb4f03587 fix: remove native: events from realListeners 2024-04-22 19:22:14 +08:00
5cdff0b4f9 feat: also supports native: in Vue 2 2024-04-22 19:22:14 +08:00
29ff9bc52a feat: support native listener in Vue 3 2024-04-22 19:22:14 +08:00
54d196c9d5 chore: update deps and fix ts error 2024-04-22 12:30:41 +08:00
34defec669 docs: update readme 2024-04-22 11:03:46 +08:00
e189abd9c2 fix(#777): autoresize does not work when reducing height 2024-04-22 11:00:56 +08:00
f07855df08 docs: add sample rate to reduce analytics data points 2024-04-16 13:18:23 +08:00
ae3102a86c chore: add asf notice to readme (#769) 2024-03-12 10:56:23 +08:00
48a2507ef8 chore: add asf notice to readme cn (#770) 2024-03-12 10:55:44 +08:00
41 changed files with 7514 additions and 6071 deletions

View File

@ -1,25 +0,0 @@
module.exports = {
root: true,
env: {
node: true
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
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",
"vue/multi-word-component-names": "off"
},
overrides: [
{
files: ["*.ts"],
extends: [
"@vue/typescript/recommended",
"@vue/prettier/@typescript-eslint"
]
}
]
};

20
.eslintrc.json Normal file
View File

@ -0,0 +1,20 @@
{
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
"@vue/eslint-config-prettier/skip-formatting"
],
"parserOptions": {
"ecmaVersion": 2020,
"parser": "@typescript-eslint/parser"
},
"rules": {
"no-console": "off",
"vue/multi-word-component-names": "off"
}
}

View File

@ -1,3 +1,44 @@
## 7.0.0
> Other prerelease changes:
> * [7.0.0-beta.0](#700-beta0)
* Fixed types for events.
## 7.0.0-beta.0
* Upgraded to ESM.
* Removed the `postinstall` script.
* API remains the same.
### Breaking changes
* Dropped support for browsers without `ResizeObserver`. Can work with [resize-observer-polyfill](https://www.npmjs.com/package/resize-observer-polyfill).
* Dropped support for Vue < 2.7.
* Dropped CJS outputs.
* Dropped extra wrapper element so that you should no longer set `padding` on the component root.
* For strict CSP usage, `vue-echarts/csp` should now be used as the entry point and `vue-echarts/csp/style.css` should be included manually.
## 6.7.3
* Fixed that `padding` on the component root doesn't work.
## 6.7.2
* Fixed that charts inside `<keep-alive>` failed to display after activation.
## 6.7.1
* Fixed that native events won't actually trigger.
## 6.7.0
* Added supports for native DOM events binding with the `native:` prefix.
## 6.6.10
* Fixed that `autoresize` doesn't work when reducing the height or the root element.
## 6.6.9 ## 6.6.9
* Fixed that the chart may not be the same size as the component root element ([#761](https://github.com/ecomfe/vue-echarts/issues/761)). * Fixed that the chart may not be the same size as the component root element ([#761](https://github.com/ecomfe/vue-echarts/issues/761)).

223
README.md
View File

@ -1,47 +1,21 @@
<h1 align="center">Vue-ECharts</h1> <h1 align="center">Vue-ECharts</h1>
<p align="center">Vue.js <sup>(v2/v3)</sup> component for Apache ECharts™ <sup>(v5)</sup>.</p> <p align="center">Vue.js component for Apache ECharts™.</p>
<p align="center"><a href="https://vue-echarts.dev/">View Demo →</a></p> <p align="center"><a href="https://npmjs.com/package/vue-echarts"><img alt="npm version" src="https://img.shields.io/npm/v/vue-echarts"></a> <a href="https://vue-echarts.dev/"><img src="https://img.shields.io/badge/Demo%20%C2%BB-20c3aa" alt="View demo"></a> <a href="./README.zh-Hans.md"><img src="https://img.shields.io/badge/%E4%B8%AD%E6%96%87%E7%89%88%20%C2%BB-000" alt="前往中文版"></a></p>
<p align="center"><a href="https:///pr.new/ecomfe/vue-echarts"><img alt="Open in Codeflow" src="https://developer.stackblitz.com/img/open_in_codeflow.svg" height="28"/></a> <a href="https://codesandbox.io/p/github/ecomfe/vue-echarts"><img alt="Edit in CodeSandbox" src="https://assets.codesandbox.io/github/button-edit-lime.svg" height="28"/></a></p> <p align="center"><a href="https:///pr.new/ecomfe/vue-echarts"><img alt="Open in Codeflow" src="https://developer.stackblitz.com/img/open_in_codeflow.svg" height="28"></a> <a href="https://codesandbox.io/p/github/ecomfe/vue-echarts"><img alt="Edit in CodeSandbox" src="https://assets.codesandbox.io/github/button-edit-lime.svg" height="28"></a></p>
> [!IMPORTANT]
> We have released an [import code generator](https://vue-echarts.dev/#codegen) that can generate precise import code by pasting the `option` code.
>
> ![](https://github.com/ecomfe/vue-echarts/assets/1726061/f9c38a06-3422-4f0e-ab8c-f242d9aea9aa)
>
> [Try it →](https://vue-echarts.dev/#codegen)
--- ---
<h2>💡 Heads up 💡 <a href="./README.zh-Hans.md"><img src="https://img.shields.io/badge/%F0%9F%87%A8%F0%9F%87%B3-%E4%B8%AD%E6%96%87%E7%89%88-white?labelColor=white" alt="前往中文版" align="right" height="24"/></a></h2> > Still using v6? Read v6 docs [here →](https://github.com/ecomfe/vue-echarts/tree/6.x)
If you are migrating from `vue-echarts` ≤ 5, you should read the _[Migration to v6](#migration-to-v6)_ section before you update to v6.
Not ready yet? Read documentation for older versions [here →](https://github.com/ecomfe/vue-echarts/tree/5.x)
## Installation & Usage ## Installation & Usage
### npm & ESM ### npm
```sh ```sh
npm i echarts vue-echarts npm add echarts vue-echarts
``` ```
To make `vue-echarts` work for _Vue 2_ (<2.7.0), you need to have `@vue/composition-api` installed (`@vue/runtime-core` for TypeScript support):
```sh
npm i @vue/composition-api
npm i @vue/runtime-core # for TypeScript support
```
If you are using _NuxtJS_ on top of _Vue 2_, you'll need `@nuxtjs/composition-api`:
```sh
npm i @nuxtjs/composition-api
```
And then add `'@nuxtjs/composition-api/module'` in the `buildModules` option in your `nuxt.config.js`.
#### Example #### Example
<details> <details>
@ -219,6 +193,8 @@ export default {
> [!IMPORTANT] > [!IMPORTANT]
> We encourage manually importing components and charts from ECharts for smaller bundle size. We've built an [import code generator](https://vue-echarts.dev/#codegen) to help you with that. You can just paste in your `option` code and we'll generate the precise import code for you. > We encourage manually importing components and charts from ECharts for smaller bundle size. We've built an [import code generator](https://vue-echarts.dev/#codegen) to help you with that. You can just paste in your `option` code and we'll generate the precise import code for you.
> >
> ![](https://github.com/ecomfe/vue-echarts/assets/1726061/f9c38a06-3422-4f0e-ab8c-f242d9aea9aa)
>
> [Try it →](https://vue-echarts.dev/#codegen) > [Try it →](https://vue-echarts.dev/#codegen)
But if you really want to import the whole ECharts bundle without having to import modules manually, just add this in your code: But if you really want to import the whole ECharts bundle without having to import modules manually, just add this in your code:
@ -227,7 +203,7 @@ But if you really want to import the whole ECharts bundle without having to impo
import "echarts"; import "echarts";
``` ```
### CDN & Global variable ### CDN
Drop `<script>` inside your HTML file and access the component via `window.VueECharts`. Drop `<script>` inside your HTML file and access the component via `window.VueECharts`.
@ -236,9 +212,9 @@ Drop `<script>` inside your HTML file and access the component via `window.VueEC
<!-- vue3Scripts:start --> <!-- vue3Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.19"></script> <script src="https://cdn.jsdelivr.net/npm/vue@3.4.33"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@7.0.0"></script>
``` ```
<!-- vue3Scripts:end --> <!-- vue3Scripts:end -->
@ -257,8 +233,8 @@ app.component('v-chart', VueECharts)
<!-- vue2Scripts:start --> <!-- vue2Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@7.0.0"></script>
``` ```
<!-- vue2Scripts:end --> <!-- vue2Scripts:end -->
@ -319,6 +295,78 @@ See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/src/dem
For performance critical scenarios (having a large dataset) we'd better bypass Vue's reactivity system for `option` prop. By specifying `manual-update` prop with `true` and not providing `option` prop, the dataset won't be watched any more. After doing so, you need to retrieve the component instance with `ref` and manually call `setOption` method to update the chart. For performance critical scenarios (having a large dataset) we'd better bypass Vue's reactivity system for `option` prop. By specifying `manual-update` prop with `true` and not providing `option` prop, the dataset won't be watched any more. After doing so, you need to retrieve the component instance with `ref` and manually call `setOption` method to update the chart.
### 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)
- `downplay` [](https://echarts.apache.org/en/api.html#events.downplay)
- `selectchanged` [](https://echarts.apache.org/en/api.html#events.selectchanged)
- `legendselectchanged` [](https://echarts.apache.org/en/api.html#events.legendselectchanged)
- `legendselected` [](https://echarts.apache.org/en/api.html#events.legendselected)
- `legendunselected` [](https://echarts.apache.org/en/api.html#events.legendunselected)
- `legendselectall` [](https://echarts.apache.org/en/api.html#events.legendselectall)
- `legendinverseselect` [](https://echarts.apache.org/en/api.html#events.legendinverseselect)
- `legendscroll` [](https://echarts.apache.org/en/api.html#events.legendscroll)
- `datazoom` [](https://echarts.apache.org/en/api.html#events.datazoom)
- `datarangeselected` [](https://echarts.apache.org/en/api.html#events.datarangeselected)
- `timelinechanged` [](https://echarts.apache.org/en/api.html#events.timelinechanged)
- `timelineplaychanged` [](https://echarts.apache.org/en/api.html#events.timelineplaychanged)
- `restore` [](https://echarts.apache.org/en/api.html#events.restore)
- `dataviewchanged` [](https://echarts.apache.org/en/api.html#events.dataviewchanged)
- `magictypechanged` [](https://echarts.apache.org/en/api.html#events.magictypechanged)
- `geoselectchanged` [](https://echarts.apache.org/en/api.html#events.geoselectchanged)
- `geoselected` [](https://echarts.apache.org/en/api.html#events.geoselected)
- `geounselected` [](https://echarts.apache.org/en/api.html#events.geounselected)
- `axisareaselected` [](https://echarts.apache.org/en/api.html#events.axisareaselected)
- `brush` [](https://echarts.apache.org/en/api.html#events.brush)
- `brushEnd` [](https://echarts.apache.org/en/api.html#events.brushEnd)
- `brushselected` [](https://echarts.apache.org/en/api.html#events.brushselected)
- `globalcursortaken` [](https://echarts.apache.org/en/api.html#events.globalcursortaken)
- `rendered` [](https://echarts.apache.org/en/api.html#events.rendered)
- `finished` [](https://echarts.apache.org/en/api.html#events.finished)
- Mouse events
- `click` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.click)
- `dblclick` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.dblclick)
- `mouseover` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseover)
- `mouseout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseout)
- `mousemove` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousemove)
- `mousedown` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousedown)
- `mouseup` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseup)
- `globalout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.globalout)
- `contextmenu` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.contextmenu)
- ZRender events
- `zr:click`
- `zr:mousedown`
- `zr:mouseup`
- `zr:mousewheel`
- `zr:dblclick`
- `zr:contextmenu`
See supported events [here →](https://echarts.apache.org/en/api.html#events)
#### Native DOM Events
As Vue-ECharts binds events to the ECharts instance by default, there is some caveat when using native DOM events. You need to prefix the event name with `native:` to bind native DOM events (or you can use the `.native` modifier in Vue 2, which is dropped in Vue 3).
```vue
<template>
<v-chart @native:click="handleClick" />
</template>
```
### Provide / Inject ### Provide / Inject
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: 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:
@ -402,102 +450,13 @@ import { THEME_KEY } from 'vue-echarts'
Static methods can be accessed from [`echarts` itself](https://echarts.apache.org/en/api.html#echarts). Static methods can be accessed from [`echarts` itself](https://echarts.apache.org/en/api.html#echarts).
### 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)
- `downplay` [](https://echarts.apache.org/en/api.html#events.downplay)
- `selectchanged` [](https://echarts.apache.org/en/api.html#events.selectchanged)
- `legendselectchanged` [](https://echarts.apache.org/en/api.html#events.legendselectchanged)
- `legendselected` [](https://echarts.apache.org/en/api.html#events.legendselected)
- `legendunselected` [](https://echarts.apache.org/en/api.html#events.legendunselected)
- `legendselectall` [](https://echarts.apache.org/en/api.html#events.legendselectall)
- `legendinverseselect` [](https://echarts.apache.org/en/api.html#events.legendinverseselect)
- `legendscroll` [](https://echarts.apache.org/en/api.html#events.legendscroll)
- `datazoom` [](https://echarts.apache.org/en/api.html#events.datazoom)
- `datarangeselected` [](https://echarts.apache.org/en/api.html#events.datarangeselected)
- `timelinechanged` [](https://echarts.apache.org/en/api.html#events.timelinechanged)
- `timelineplaychanged` [](https://echarts.apache.org/en/api.html#events.timelineplaychanged)
- `restore` [](https://echarts.apache.org/en/api.html#events.restore)
- `dataviewchanged` [](https://echarts.apache.org/en/api.html#events.dataviewchanged)
- `magictypechanged` [](https://echarts.apache.org/en/api.html#events.magictypechanged)
- `geoselectchanged` [](https://echarts.apache.org/en/api.html#events.geoselectchanged)
- `geoselected` [](https://echarts.apache.org/en/api.html#events.geoselected)
- `geounselected` [](https://echarts.apache.org/en/api.html#events.geounselected)
- `axisareaselected` [](https://echarts.apache.org/en/api.html#events.axisareaselected)
- `brush` [](https://echarts.apache.org/en/api.html#events.brush)
- `brushEnd` [](https://echarts.apache.org/en/api.html#events.brushEnd)
- `brushselected` [](https://echarts.apache.org/en/api.html#events.brushselected)
- `globalcursortaken` [](https://echarts.apache.org/en/api.html#events.globalcursortaken)
- `rendered` [](https://echarts.apache.org/en/api.html#events.rendered)
- `finished` [](https://echarts.apache.org/en/api.html#events.finished)
- Mouse events
- `click` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.click)
- `dblclick` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.dblclick)
- `mouseover` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseover)
- `mouseout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseout)
- `mousemove` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousemove)
- `mousedown` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousedown)
- `mouseup` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseup)
- `globalout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.globalout)
- `contextmenu` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.contextmenu)
- ZRender events
- `zr:click`
- `zr:mousedown`
- `zr:mouseup`
- `zr:mousewheel`
- `zr:dblclick`
- `zr:contextmenu`
See supported events [here →](https://echarts.apache.org/en/api.html#events)
## CSP: `style-src` or `style-src-elem` ## CSP: `style-src` or `style-src-elem`
If you are applying a CSP to prevent inline `<style>` injection, you need to use files from `dist/csp` directory and include `dist/csp/style.css` into your app manually. If you are applying a CSP to prevent inline `<style>` injection, you need to use `vue-echarts/csp` instead of `vue-echarts` and include `vue-echarts/csp/style.css` manually.
## Migration to v6 ## Migration to v7
> 💡 Please make sure to read the [migration guide](https://echarts.apache.org/en/tutorial.html#ECharts%205%20Upgrade%20Guide) for ECharts 5 as well. Read the breaking changes document in the [release log](https://github.com/ecomfe/vue-echarts/releases/tag/v7.0.0-beta.0) and the migration shoud be straightforward.
The following breaking changes are introduced in `vue-echarts@6`:
### Vue 2 support
- 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 (and also `@vue/runtime-core` for TypeScript support).
### Props
- `options` is renamed to **`option`** to align with ECharts itself.
- Updating `option` will respect **`update-options`** configs instead of checking reference change.
- `watch-shallow` is removed. Use **`manual-update`** for performance critical scenarios.
### Methods
- `mergeOptions` is renamed to **`setOption`** to align with ECharts itself.
- `showLoading` and `hideLoading` is removed. Use the **`loading` and `loading-options`** props instead.
- `appendData` is removed. (Due to ECharts 5's breaking change.)
- All static methods are removed from `vue-echarts`. Use those methods from `echarts` directly.
### Computed getters
- Computed getters (`width`, `height`, `isDisposed` and `computedOptions`) are removed. Use the **`getWidth`, `getHeight`, `isDisposed` and `getOption`** methods instead.
### Styles
- Now the root element of the component have **`100%×100%`** size by default, instead of `600×400`.
## Local development ## Local development
@ -507,3 +466,7 @@ pnpm serve
``` ```
Open `http://localhost:8080` to see the demo. Open `http://localhost:8080` to see the demo.
## Notice
The Apache Software Foundation [Apache ECharts, ECharts](https://echarts.apache.org/), Apache, the Apache feather, and the Apache ECharts project logo are either registered trademarks or trademarks of the [Apache Software Foundation](https://www.apache.org/).

View File

@ -1,47 +1,21 @@
<h1 align="center">Vue-ECharts</h1> <h1 align="center">Vue-ECharts</h1>
<p align="center">Apache ECharts™ <sup>(v5)</sup> 的 Vue.js <sup>(v2/v3)</sup> 组件。</p> <p align="center">Apache ECharts™ 的 Vue.js 组件。</p>
<p align="center"><a href="https://vue-echarts.dev/">查看 Demo →</a></p> <p align="center"><a href="https://npmjs.com/package/vue-echarts"><img alt="npm 版本" src="https://img.shields.io/npm/v/vue-echarts"></a> <a href="https://vue-echarts.dev/"><img src="https://img.shields.io/badge/%E6%BC%94%E7%A4%BA%20%C2%BB-20c3aa" alt="查看演示"></a> <a href="./README.zh-Hans.md"></p>
<p align="center"><a href="https:///pr.new/ecomfe/vue-echarts"><img alt="Open in Codeflow" src="https://developer.stackblitz.com/img/open_in_codeflow.svg" height="28"/></a> <a href="https://codesandbox.io/p/github/ecomfe/vue-echarts"><img alt="Edit in CodeSandbox" src="https://assets.codesandbox.io/github/button-edit-lime.svg" height="28"/></a></p> <p align="center"><a href="https:///pr.new/ecomfe/vue-echarts"><img alt="Open in Codeflow" src="https://developer.stackblitz.com/img/open_in_codeflow.svg" height="28"></a> <a href="https://codesandbox.io/p/github/ecomfe/vue-echarts"><img alt="Edit in CodeSandbox" src="https://assets.codesandbox.io/github/button-edit-lime.svg" height="28"></a></p>
> [!IMPORTANT]
> 我们新发布了一个[导入代码生成器](https://vue-echarts.dev/#codegen),只需要把`option` 代码粘贴进去,就可以得到精确的导入代码。
>
> ![](https://github.com/ecomfe/vue-echarts/assets/1726061/f9c38a06-3422-4f0e-ab8c-f242d9aea9aa)
>
> [试一试 →](https://vue-echarts.dev/#codegen)
--- ---
## 💡 注意 💡 > 还在使用 v6可以继续阅读老版本的文档。[前往 →](https://github.com/ecomfe/vue-echarts/blob/6.x/README.zh_CN.md)
若您准备从 `vue-echarts` ≤ 5 的版本迁移到新版本,请在升级 v6 前阅读 _[迁移到 v6](#迁移到-v6)_ 部分文档。
没准备好的话,可以继续阅读老版本的文档。[前往 →](https://github.com/ecomfe/vue-echarts/blob/5.x/README.zh_CN.md)
## 安装 & 使用 ## 安装 & 使用
### npm & ESM ### npm
```sh ```sh
npm i echarts vue-echarts npm add echarts vue-echarts
``` ```
要在 _Vue 2_<2.7.0下使用 `vue-echarts`需要确保 `@vue/composition-api` 已经安装TypeScript 支持还需要 `@vue/runtime-core`
```sh
npm i @vue/composition-api
npm i @vue/runtime-core # TypeScript 支持
```
如果你在使用基于 _Vue 2_ _NuxtJS_则需要安装 `@nuxtjs/composition-api`
```sh
npm i @nuxtjs/composition-api
```
然后在 `nuxt.config.js` `buildModules` 选项中添加 `'@nuxtjs/composition-api/module'`
#### 示例 #### 示例
<details> <details>
@ -219,6 +193,8 @@ export default {
> [!IMPORTANT] > [!IMPORTANT]
> 我们鼓励手动从 ECharts 中引入组件和图表,以减小打包体积。我们已经为此构建了一个[导入代码生成器](https://vue-echarts.dev/#codegen)。你只需要把`option` 代码粘贴进去,就可以得到精确的导入代码。 > 我们鼓励手动从 ECharts 中引入组件和图表,以减小打包体积。我们已经为此构建了一个[导入代码生成器](https://vue-echarts.dev/#codegen)。你只需要把`option` 代码粘贴进去,就可以得到精确的导入代码。
> >
> ![](https://github.com/ecomfe/vue-echarts/assets/1726061/f9c38a06-3422-4f0e-ab8c-f242d9aea9aa)
>
> [试一试 →](https://vue-echarts.dev/#codegen) > [试一试 →](https://vue-echarts.dev/#codegen)
但如果你实在需要全量引入 ECharts 从而无需手动引入模块,只需要在代码中添加: 但如果你实在需要全量引入 ECharts 从而无需手动引入模块,只需要在代码中添加:
@ -227,7 +203,7 @@ export default {
import "echarts"; import "echarts";
``` ```
### CDN & 全局变量 ### CDN
用如下方式在 HTML 中插入 `<script>` 标签,并且通过 `window.VueECharts` 来访问组件接口: 用如下方式在 HTML 中插入 `<script>` 标签,并且通过 `window.VueECharts` 来访问组件接口:
@ -236,9 +212,9 @@ import "echarts";
<!-- vue3Scripts:start --> <!-- vue3Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.19"></script> <script src="https://cdn.jsdelivr.net/npm/vue@3.4.33"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@7.0.0"></script>
``` ```
<!-- vue3Scripts:end --> <!-- vue3Scripts:end -->
@ -257,8 +233,8 @@ app.component('v-chart', VueECharts)
<!-- vue2Scripts:start --> <!-- vue2Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@7.0.0"></script>
``` ```
<!-- vue2Scripts:end --> <!-- vue2Scripts:end -->
@ -381,6 +357,16 @@ Vue-ECharts 支持如下事件:
请参考支持的事件列表。[前往 →](https://echarts.apache.org/zh/api.html#events) 请参考支持的事件列表。[前往 →](https://echarts.apache.org/zh/api.html#events)
#### 原生 DOM 事件
由于 Vue-ECharts 默认将事件绑定到 ECharts 实例,因此在使用原生 DOM 事件时需要做一些特殊处理。你需要在事件名称前加上 `native:` 前缀来绑定原生 DOM 事件(可以在 Vue 2 中也可以使用 `.native` 修饰符,但这在 Vue 3 中已被废弃)。
```vue
<template>
<v-chart @native:click="handleClick" />
</template>
```
### Provide / Inject ### Provide / Inject
Vue-ECharts 为 `theme``init-options``update-options``loading-options` 提供了 provide/inject API以通过上下文配置选项。例如可以通过如下方式来使用 provide API 为 `init-options` 提供上下文配置: Vue-ECharts 为 `theme``init-options``update-options``loading-options` 提供了 provide/inject API以通过上下文配置选项。例如可以通过如下方式来使用 provide API 为 `init-options` 提供上下文配置:
@ -464,40 +450,18 @@ import { THEME_KEY } from 'vue-echarts'
静态方法请直接通过 [`echarts` 本身](https://echarts.apache.org/zh/api.html#echarts)进行调用。 静态方法请直接通过 [`echarts` 本身](https://echarts.apache.org/zh/api.html#echarts)进行调用。
## CSP: `style-src` 或 `style-src-elem` ## CSP: `style-src` 或 `style-src-elem`
如果你正在应用 CSP 来防止内联 `<style>` 注入,则需要使用 `dist/csp` 目录中的文件,并手动引入 `dist/csp/style.css` 如果你正在应用 CSP 来防止内联 `<style>` 注入,则需要使用 `vue-echarts/csp` 代替 `vue-echarts`,并手动引入 `vue-echarts/csp/style.css`
## 迁移到 v6 ## 迁移到 v7
> 💡 请确保同时查阅 ECharts 5 的[升级指南](https://echarts.apache.org/zh/tutorial.html#ECharts%205%20%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97)。 Translate:
Read the breaking changes document in the [release log](https://github.com/ecomfe/vue-echarts/releases/tag/v7.0.0-beta.0) and the migration shoud be straightforward.
`vue-echarts@6` 引入了如下破坏性变更: 请阅读[发布日志](https://github.com/ecomfe/vue-echarts/releases/tag/v7.0.0-beta.0)中的变更记录,之后迁移过程应该会相对简单。
### Vue 2 支持
- 要在 `vue@2.7.0` 之前的版本中使用 Vue-ECharts必须安装 `@vue/composition-api`(还需要安装 `@vue/runtime-core` 来支持 TypeScript
### Prop
- `options` 重命名为 **`option`**,以和 ECharts 本身保持一致。
- 更新 `option` 将采用 **`update-options`** 中的配置,不再检查是否发生引用变化。
- `watch-shallow` 被移除。在性能关键场景请使用 **`manual-update`**。
### 方法
- `mergeOptions` 重命名为 **`setOption`**,以和 ECharts 本身保持一致。
- `showLoading``hideLoading` 被移除。请使用 **`loading``loading-options`** prop。
- `appendData` 被移除。(由于 ECharts 5 引入的破坏性变更。)
- 所有静态方法被从 `vue-echarts` 移除。可以直接使用 `echarts` 本身的这些方法。
### 计算 Getter
- 计算 getter`width``height``isDisposed``computedOptions`)被移除。请分别使用 **`getWidth``getHeight``isDisposed``getOption`** 方法代替。
### 样式
- 现在组件根元素尺寸默认为 **`100%×100%`**,而非原来的 `600×400`
## 本地开发 ## 本地开发
@ -507,3 +471,7 @@ pnpm serve
``` ```
打开 `http://localhost:8080` 来查看 demo。 打开 `http://localhost:8080` 来查看 demo。
## 声明
The Apache Software Foundation [Apache ECharts, ECharts](https://echarts.apache.org/), Apache, the Apache feather, and the Apache ECharts project logo are either registered trademarks or trademarks of the [Apache Software Foundation](https://www.apache.org/).

View File

@ -1,3 +0,0 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"]
};

3
babel.config.json Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@vue/cli-plugin-babel/preset"]
}

View File

@ -1,92 +1,90 @@
{ {
"name": "vue-echarts", "name": "vue-echarts",
"version": "6.6.9", "version": "7.0.0",
"description": "Vue.js component for Apache ECharts™.", "description": "Vue.js component for Apache ECharts™.",
"license": "MIT",
"repository": "https://github.com/ecomfe/vue-echarts.git",
"author": "GU Yiling <justice360@gmail.com>", "author": "GU Yiling <justice360@gmail.com>",
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "pnpm run docs && rimraf dist && pnpm run build:2 && pnpm run build:3 && vue-demi-switch 3", "build": "pnpm run docs && rimraf dist && pnpm run build:rollup",
"build:2": "vue-demi-switch 2 vue2 && rollup -c rollup.vue2.config.js", "build:rollup": "vue-demi-switch 3 && rollup -c rollup.config.js",
"build:3": "vue-demi-switch 3 && rollup -c rollup.config.js",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
"publint": "publint",
"build:demo": "vue-cli-service build", "build:demo": "vue-cli-service build",
"docs": "node ./scripts/docs.js", "docs": "node ./scripts/docs.mjs",
"postinstall": "node ./scripts/postinstall.js", "prepublishOnly": "pnpm run build && publint"
"prepublishOnly": "pnpm run build" },
"type": "module",
"main": "dist/index.js",
"unpkg": "dist/index.min.js",
"jsdelivr": "dist/index.min.js",
"types": "dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./csp": "./dist/csp/index.js",
"./csp/style.css": "./dist/csp/style.css"
}, },
"main": "dist/index.cjs.min.js",
"module": "dist/index.esm.min.js",
"unpkg": "dist/index.umd.min.js",
"files": [ "files": [
"dist", "dist",
"scripts/postinstall.js" "scripts/postinstall.js"
], ],
"dependencies": { "dependencies": {
"resize-detector": "^0.3.0",
"vue-demi": "^0.13.11" "vue-demi": "^0.13.11"
}, },
"devDependencies": {
"@babel/core": "^7.23.2",
"@highlightjs/vue-plugin": "^2.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-terser": "^0.4.4",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"@vercel/analytics": "^1.1.1",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-typescript": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.3.7",
"@vue/composition-api": "^1.7.2",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"@vueuse/core": "^10.5.0",
"comment-mark": "^1.1.1",
"core-js": "^3.33.2",
"echarts": "^5.4.3",
"echarts-gl": "^2.0.9",
"echarts-liquidfill": "^3.1.0",
"esbuild-wasm": "^0.19.2",
"eslint": "^7.32.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^8.7.1",
"highlight.js": "^11.9.0",
"pinia": "^2.1.7",
"postcss": "^8.4.31",
"postcss-loader": "^5.3.0",
"postcss-nested": "^5.0.6",
"prettier": "^2.8.8",
"raw-loader": "^4.0.2",
"resize-detector": "^0.3.0",
"rimraf": "^3.0.2",
"rollup": "^2.79.1",
"rollup-plugin-dts": "^4.2.3",
"rollup-plugin-styles": "^4.0.0",
"rollup-plugin-ts": "^2.0.7",
"tslib": "^2.6.2",
"typescript": "4.6.4",
"vue": "^3.3.7",
"vue2": "npm:vue@^2.7.15",
"webpack": "^5.89.0"
},
"peerDependencies": { "peerDependencies": {
"@vue/composition-api": "^1.0.5",
"@vue/runtime-core": "^3.0.0", "@vue/runtime-core": "^3.0.0",
"echarts": "^5.4.1", "echarts": "^5.5.1",
"vue": "^2.6.12 || ^3.1.1" "vue": "^2.7.0 || ^3.1.1"
}, },
"jsdelivr": "dist/index.umd.min.js",
"license": "MIT",
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"@vue/runtime-core": { "@vue/runtime-core": {
"optional": true "optional": true
} }
}, },
"repository": "https://github.com/ecomfe/vue-echarts.git", "devDependencies": {
"types": "dist/index.d.ts" "@babel/core": "^7.24.9",
"@highlightjs/vue-plugin": "^2.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.7",
"@typescript-eslint/eslint-plugin": "^7.17.0",
"@typescript-eslint/parser": "^7.17.0",
"@vercel/analytics": "^1.3.1",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-typescript": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.4.33",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vueuse/core": "^10.11.0",
"comment-mark": "^1.1.1",
"core-js": "^3.37.1",
"echarts": "^5.5.1",
"echarts-gl": "^2.0.9",
"echarts-liquidfill": "^3.1.0",
"esbuild-wasm": "^0.23.0",
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^9.27.0",
"highlight.js": "^11.10.0",
"pinia": "^2.1.7",
"postcss": "^8.4.39",
"postcss-loader": "^8.1.1",
"postcss-nested": "^6.2.0",
"prettier": "^3.3.3",
"publint": "^0.2.9",
"raw-loader": "^4.0.2",
"resize-detector": "^0.3.0",
"rimraf": "^6.0.1",
"rollup": "^4.19.0",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-import-css": "^3.5.0",
"tslib": "^2.6.3",
"typescript": "5.5.4",
"vue": "^3.4.33",
"vue2": "npm:vue@^2.7.16",
"webpack": "^5.93.0"
}
} }

12244
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
import typescript from "rollup-plugin-ts";
import terser from "@rollup/plugin-terser";
import resolve from "@rollup/plugin-node-resolve";
import replace from "@rollup/plugin-replace"; import replace from "@rollup/plugin-replace";
import styles from "rollup-plugin-styles"; import esbuild from "rollup-plugin-esbuild";
import { injectVueDemi } from "./scripts/rollup"; import { dts } from "rollup-plugin-dts";
import css from "rollup-plugin-import-css";
import { injectVueDemi } from "./scripts/rollup.mjs";
/** /**
* Modifies the Rollup options for a build to support strict CSP * Modifies the Rollup options for a build to support strict CSP
@ -18,7 +17,7 @@ function configBuild(options, csp) {
result.plugins = [ result.plugins = [
...(csp ? [replace({ __CSP__: `${csp}`, preventAssignment: true })] : []), ...(csp ? [replace({ __CSP__: `${csp}`, preventAssignment: true })] : []),
...plugins, ...plugins,
csp ? styles({ mode: ["extract", "style.css"] }) : styles() csp ? css({ output: "style.css" }) : css({ inject: true })
]; ];
// modify output file names // modify output file names
@ -39,67 +38,23 @@ function configBuild(options, csp) {
const builds = [ const builds = [
{ {
input: "src/index.ts", input: "src/index.ts",
plugins: [ plugins: [esbuild()],
typescript({ external: ["vue-demi", /^echarts/],
tsconfig: resolvedConfig => ({ ...resolvedConfig, declaration: true }),
hook: {
outputPath: (path, kind) =>
kind === "declaration" ? "dist/index.d.ts" : path
}
})
],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: {
file: "dist/index.esm.js",
format: "esm",
sourcemap: true
}
},
{
input: "src/index.ts",
plugins: [typescript()],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: [ output: [
{ {
file: "dist/index.esm.min.js", file: "dist/index.js",
format: "esm", format: "esm",
sourcemap: true,
plugins: [
terser({
format: {
comments: false
}
})
]
},
{
file: "dist/index.cjs.js",
format: "cjs",
exports: "named",
sourcemap: true sourcemap: true
},
{
file: "dist/index.cjs.min.js",
format: "cjs",
exports: "named",
sourcemap: true,
plugins: [
terser({
format: {
comments: false
}
})
]
} }
] ]
}, },
{ {
input: "src/global.ts", input: "src/global.ts",
plugins: [resolve(), typescript()], plugins: [esbuild({ minify: true })],
external: ["vue-demi", "echarts", "echarts/core"], external: ["vue-demi", /^echarts/],
output: [ output: [
{ {
file: "dist/index.umd.js", file: "dist/index.min.js", // for unpkg/jsdelivr
format: "umd", format: "umd",
name: "VueECharts", name: "VueECharts",
exports: "default", exports: "default",
@ -110,26 +65,6 @@ const builds = [
"echarts/core": "echarts" "echarts/core": "echarts"
}, },
plugins: [injectVueDemi] plugins: [injectVueDemi]
},
{
file: "dist/index.umd.min.js",
format: "umd",
name: "VueECharts",
exports: "default",
sourcemap: true,
globals: {
"vue-demi": "VueDemi",
echarts: "echarts",
"echarts/core": "echarts"
},
plugins: [
injectVueDemi,
terser({
format: {
comments: false
}
})
]
} }
] ]
} }
@ -137,5 +72,19 @@ const builds = [
export default [ export default [
...builds.map(options => configBuild(options, false)), ...builds.map(options => configBuild(options, false)),
...builds.map(options => configBuild(options, true)) ...builds.map(options => configBuild(options, true)),
{
input: "src/index.d.ts",
plugins: [dts()],
output: [
{
file: "dist/index.d.ts",
format: "esm"
},
{
file: "dist/csp/index.d.ts",
format: "esm"
}
]
}
]; ];

View File

@ -1,23 +0,0 @@
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"
}
},
{
input: "src/index.vue2_7.d.ts",
plugins: [dts()],
output: {
file: "dist/index.vue2_7.d.ts",
format: "esm"
}
}
];
export default options;

View File

@ -1,18 +1,15 @@
const { readFileSync, writeFileSync } = require("fs"); import { readFileSync, writeFileSync } from "node:fs";
const { resolve } = require("path"); import commentMark from "comment-mark";
const commentMark = require("comment-mark"); import { getPackageMeta, resolvePath } from "./utils.mjs";
const { name, version } = require("../package.json");
function resolvePath(...parts) { const { name, version } = getPackageMeta();
return resolve(__dirname, ...parts);
}
const CDN_PREFIX = "https://cdn.jsdelivr.net/npm/"; const CDN_PREFIX = "https://cdn.jsdelivr.net/npm/";
const DEP_VERSIONS = { const DEP_VERSIONS = {
"vue@3": "3.4.19", "vue@3": "3.4.33",
"vue@2": "2.7.16", "vue@2": "2.7.16",
echarts: "5.4.3", echarts: "5.5.1",
[name]: version [name]: version
}; };
@ -41,7 +38,7 @@ const scripts = {
}; };
const README_FILES = ["README.md", "README.zh-Hans.md"].map(name => const README_FILES = ["README.md", "README.zh-Hans.md"].map(name =>
resolvePath("..", name) resolvePath(import.meta.url, "..", name)
); );
README_FILES.forEach(file => { README_FILES.forEach(file => {

View File

@ -1,46 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require("path");
const fs = require("fs");
const packageFile = path.resolve(__dirname, "../package.json");
const typesPaths = {
3: "dist/index.d.ts",
2.7: "dist/index.vue2_7.d.ts",
2: "dist/index.vue2.d.ts"
};
function switchVersion(version) {
const typesPath = typesPaths[version];
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.`);
}
function loadVue() {
try {
return require("vue");
} catch (e) {
return null;
}
}
const Vue = loadVue();
// Align the process with vue-demi
if (!Vue || typeof Vue.version !== "string") {
console.warn(
'[vue-echarts] Vue is not found. Please run "npm install vue" to install.'
);
} else if (Vue.version.startsWith("3.")) {
switchVersion(3);
} else if (Vue.version.startsWith("2.7.")) {
switchVersion(2.7);
} else if (Vue.version.startsWith("2.")) {
switchVersion(2);
} else {
console.warn(`[vue-echarts] Vue version v${Vue.version} is not supported.`);
}

View File

@ -1,30 +0,0 @@
import { readFileSync } from "fs";
const VUE_DEMI_IIFE = readFileSync(
require.resolve("vue-demi/lib/index.iife.js"),
"utf8"
);
/** @type {import('rollup').Plugin} */
export const injectVueDemi = {
name: "inject-vue-demi",
banner() {
return `${VUE_DEMI_IIFE};\n;`;
}
};
const EMPTY_FILE_ID = "__rollup_empty__";
/** @type {import('rollup').Plugin} */
export const ingoreCss = {
name: "ignore-css",
resolveId(source) {
if (source.endsWith(".css")) {
return EMPTY_FILE_ID;
}
return null;
},
load(id) {
return id === EMPTY_FILE_ID ? "" : null;
}
};

17
scripts/rollup.mjs Normal file
View File

@ -0,0 +1,17 @@
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const VUE_DEMI_IIFE = readFileSync(
require.resolve("vue-demi/lib/index.iife.js"),
"utf8"
);
/** @type {import('rollup').Plugin} */
export const injectVueDemi = {
name: "inject-vue-demi",
banner() {
return `${VUE_DEMI_IIFE};\n;`;
}
};

13
scripts/utils.mjs Normal file
View File

@ -0,0 +1,13 @@
import { readFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
export function resolvePath(url, ...parts) {
return resolve(dirname(fileURLToPath(url)), ...parts);
}
export function getPackageMeta() {
return JSON.parse(
readFileSync(resolvePath(import.meta.url, "../package.json"), "utf8")
);
}

View File

@ -13,11 +13,21 @@ import {
nextTick, nextTick,
watchEffect, watchEffect,
getCurrentInstance, getCurrentInstance,
Vue2, Vue2
type PropType,
type InjectionKey
} from "vue-demi"; } from "vue-demi";
import { init as initChart } from "echarts/core"; import { init as initChart } from "echarts/core";
import {
usePublicAPI,
useAutoresize,
autoresizeProps,
useLoading,
loadingProps
} from "./composables";
import { isOn, omitOn, unwrapInjected } from "./utils";
import { register, TAG_NAME } from "./wc";
import type { PropType, InjectionKey } from "vue-demi";
import type { import type {
EChartsType, EChartsType,
EventTarget, EventTarget,
@ -30,15 +40,8 @@ import type {
UpdateOptionsInjection, UpdateOptionsInjection,
Emits Emits
} from "./types"; } from "./types";
import { import type { EChartsElement } from "./wc";
usePublicAPI,
useAutoresize,
autoresizeProps,
useLoading,
loadingProps
} from "./composables";
import { omitOn, unwrapInjected } from "./utils";
import { register, TAG_NAME, type EChartsElement } from "./wc";
import "./style.css"; import "./style.css";
const __CSP__ = false; const __CSP__ = false;
@ -55,6 +58,8 @@ export const UPDATE_OPTIONS_KEY =
"ecUpdateOptions" as unknown as InjectionKey<UpdateOptionsInjection>; "ecUpdateOptions" as unknown as InjectionKey<UpdateOptionsInjection>;
export { LOADING_OPTIONS_KEY } from "./composables"; export { LOADING_OPTIONS_KEY } from "./composables";
const NATIVE_EVENT_RE = /(^&?~?!?)native:/;
export default defineComponent({ export default defineComponent({
name: "echarts", name: "echarts",
props: { props: {
@ -73,7 +78,6 @@ export default defineComponent({
inheritAttrs: false, inheritAttrs: false,
setup(props, { attrs }) { setup(props, { attrs }) {
const root = shallowRef<EChartsElement>(); const root = shallowRef<EChartsElement>();
const inner = shallowRef<HTMLElement>();
const chart = shallowRef<EChartsType>(); const chart = shallowRef<EChartsType>();
const manualOption = shallowRef<Option>(); const manualOption = shallowRef<Option>();
const defaultTheme = inject(THEME_KEY, null); const defaultTheme = inject(THEME_KEY, null);
@ -95,17 +99,70 @@ export default defineComponent({
() => props.updateOptions || unwrapInjected(defaultUpdateOptions, {}) () => props.updateOptions || unwrapInjected(defaultUpdateOptions, {})
); );
const nonEventAttrs = computed(() => omitOn(attrs)); const nonEventAttrs = computed(() => omitOn(attrs));
const nativeListeners: Record<string, unknown> = {};
// @ts-expect-error listeners for Vue 2 compatibility // @ts-expect-error listeners for Vue 2 compatibility
const listeners = getCurrentInstance().proxy.$listeners; const listeners = getCurrentInstance().proxy.$listeners;
const realListeners: Record<string, any> = {};
if (!listeners) {
// This is for Vue 3.
// We are converting all `on<Event>` props to event listeners compatible with Vue 2
// and collect them into `realListeners` so that we can bind them to the chart instance
// later in the same way.
// For `onNative:<event>` props, we just strip the `Native:` part and collect them into
// `nativeListeners` so that we can bind them to the root element directly.
Object.keys(attrs)
.filter(key => isOn(key))
.forEach(key => {
// onClick -> c + lick
// onZr:click -> z + r:click
let event = key.charAt(2).toLowerCase() + key.slice(3);
// Collect native DOM events
if (event.indexOf("native:") === 0) {
// native:click -> onClick
const nativeKey = `on${event.charAt(7).toUpperCase()}${event.slice(
8
)}`;
nativeListeners[nativeKey] = attrs[key];
return;
}
// clickOnce -> ~click
// zr:clickOnce -> ~zr:click
if (event.substring(event.length - 4) === "Once") {
event = `~${event.substring(0, event.length - 4)}`;
}
realListeners[event] = attrs[key];
});
} else {
// This is for Vue 2.
// We just need to distinguish normal events and `native:<event>` events and
// collect them into `realListeners` and `nativeListeners` respectively.
// For `native:<event>` events, we just strip the `native:` part and collect them
// into `nativeListeners` so that we can bind them to the root element directly.
// native:click -> click
// ~native:click -> ~click
// &~!native:click -> &~!click
Object.keys(listeners).forEach(key => {
if (NATIVE_EVENT_RE.test(key)) {
nativeListeners[key.replace(NATIVE_EVENT_RE, "$1")] = listeners[key];
} else {
realListeners[key] = listeners[key];
}
});
}
function init(option?: Option) { function init(option?: Option) {
if (!inner.value) { if (!root.value) {
return; return;
} }
const instance = (chart.value = initChart( const instance = (chart.value = initChart(
inner.value, root.value,
realTheme.value, realTheme.value,
realInitOptions.value realInitOptions.value
)); ));
@ -114,27 +171,6 @@ export default defineComponent({
instance.group = props.group; instance.group = props.group;
} }
let realListeners = listeners;
if (!realListeners) {
realListeners = {};
Object.keys(attrs)
.filter(key => key.indexOf("on") === 0 && key.length > 2)
.forEach(key => {
// onClick -> c + lick
// onZr:click -> z + r:click
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 => { Object.keys(realListeners).forEach(key => {
let handler = realListeners[key]; let handler = realListeners[key];
@ -272,7 +308,7 @@ export default defineComponent({
useLoading(chart, loading, loadingOptions); useLoading(chart, loading, loadingOptions);
useAutoresize(chart, autoresize, inner); useAutoresize(chart, autoresize, root);
onMounted(() => { onMounted(() => {
init(); init();
@ -293,9 +329,9 @@ export default defineComponent({
return { return {
chart, chart,
root, root,
inner,
setOption, setOption,
nonEventAttrs, nonEventAttrs,
nativeListeners,
...publicApi ...publicApi
}; };
}, },
@ -303,12 +339,12 @@ export default defineComponent({
// Vue 3 and Vue 2 have different vnode props format: // 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 // See https://v3-migration.vuejs.org/breaking-changes/render-function-api.html#vnode-props-format
const attrs = ( const attrs = (
Vue2 ? { attrs: this.nonEventAttrs } : { ...this.nonEventAttrs } Vue2
? { attrs: this.nonEventAttrs, on: this.nativeListeners }
: { ...this.nonEventAttrs, ...this.nativeListeners }
) as any; ) as any;
attrs.ref = "root"; attrs.ref = "root";
attrs.class = attrs.class ? ["echarts"].concat(attrs.class) : "echarts"; attrs.class = attrs.class ? ["echarts"].concat(attrs.class) : "echarts";
return h(TAG_NAME, attrs, [ return h(TAG_NAME, attrs);
h("div", { ref: "inner", class: "vue-echarts-inner" })
]);
} }
}); });

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Ref } from "vue-demi"; import type { Ref } from "vue-demi";
import { EChartsType } from "../types"; import type { EChartsType } from "../types";
const METHOD_NAMES = [ const METHOD_NAMES = [
"getWidth", "getWidth",

View File

@ -1,11 +1,8 @@
import { watch, type Ref, type PropType } from "vue-demi"; import { watch } from "vue-demi";
import { throttle } from "echarts/core"; import { throttle } from "echarts/core";
import {
addListener, import type { Ref, PropType } from "vue-demi";
removeListener, import type { EChartsType } from "../types";
type ResizeCallback
} from "resize-detector";
import { type EChartsType } from "../types";
type AutoresizeProp = type AutoresizeProp =
| boolean | boolean
@ -19,28 +16,50 @@ export function useAutoresize(
autoresize: Ref<AutoresizeProp | undefined>, autoresize: Ref<AutoresizeProp | undefined>,
root: Ref<HTMLElement | undefined> root: Ref<HTMLElement | undefined>
): void { ): void {
let resizeListener: ResizeCallback | null = null; watch(
[root, chart, autoresize],
([root, chart, autoresize], _, onCleanup) => {
let ro: ResizeObserver | null = null;
watch([root, chart, autoresize], ([root, chart, autoresize], _, cleanup) => { if (root && chart && autoresize) {
if (root && chart && autoresize) { const { offsetWidth, offsetHeight } = root;
const autoresizeOptions = autoresize === true ? {} : autoresize; const autoresizeOptions = autoresize === true ? {} : autoresize;
const { throttle: wait = 100, onResize } = autoresizeOptions; const { throttle: wait = 100, onResize } = autoresizeOptions;
const callback = () => { let initialResizeTriggered = false;
chart.resize();
onResize?.();
};
resizeListener = wait ? throttle(callback, wait) : callback; const callback = () => {
addListener(root, resizeListener); chart.resize();
} onResize?.();
};
cleanup(() => { const resizeCallback = wait ? throttle(callback, wait) : callback;
if (root && resizeListener) {
removeListener(root, resizeListener); ro = new ResizeObserver(() => {
// We just skip ResizeObserver's initial resize callback if the
// size has not changed since the chart is rendered.
if (!initialResizeTriggered) {
initialResizeTriggered = true;
if (
root.offsetWidth === offsetWidth &&
root.offsetHeight === offsetHeight
) {
return;
}
}
resizeCallback();
});
ro.observe(root);
} }
});
}); onCleanup(() => {
if (ro) {
ro.disconnect();
ro = null;
}
});
}
);
} }
export const autoresizeProps = { export const autoresizeProps = {

View File

@ -1,12 +1,7 @@
import { unwrapInjected } from "../utils"; import { unwrapInjected } from "../utils";
import { import { inject, computed, watchEffect } from "vue-demi";
inject,
computed, import type { Ref, InjectionKey, PropType } from "vue-demi";
watchEffect,
type Ref,
type InjectionKey,
type PropType
} from "vue-demi";
import type { EChartsType, LoadingOptions } from "../types"; import type { EChartsType, LoadingOptions } from "../types";
export const LOADING_OPTIONS_KEY = export const LOADING_OPTIONS_KEY =

View File

@ -16,6 +16,7 @@ import javascript from "highlight.js/lib/languages/javascript";
import typescript from "highlight.js/lib/languages/typescript"; import typescript from "highlight.js/lib/languages/typescript";
import hljsVuePlugin from "@highlightjs/vue-plugin"; import hljsVuePlugin from "@highlightjs/vue-plugin";
import { initialize, transform } from "esbuild-wasm"; import { initialize, transform } from "esbuild-wasm";
import wasmURL from "esbuild-wasm/esbuild.wasm";
import { track } from "@vercel/analytics"; import { track } from "@vercel/analytics";
import { getImportsFromOption } from "./utils/codegen"; import { getImportsFromOption } from "./utils/codegen";
@ -75,9 +76,7 @@ const transformedCode = ref("");
const transformErrors = ref([]); const transformErrors = ref([]);
onMounted(async () => { onMounted(async () => {
await initialize({ await initialize({ wasmURL });
wasmURL: "https://cdn.jsdelivr.net/npm/esbuild-wasm@0.19.2/esbuild.wasm"
});
initializing.value = false; initializing.value = false;
@ -414,7 +413,9 @@ input[type="number"] {
transform: translate(-50%, 200%); transform: translate(-50%, 200%);
border-radius: 4px; border-radius: 4px;
opacity: 0; opacity: 0;
transition: transform 0.2s, opacity 0.2s; transition:
transform 0.2s,
opacity 0.2s;
} }
.message.open { .message.open {

View File

@ -111,9 +111,7 @@ watch(codeOpen, open => {
</aside> </aside>
<aside class="codegen"> <aside class="codegen">
<button @click="openCodegen"> <button @click="openCodegen"> <code>import</code> Codegen</button>
<code>import</code> Codegen <span class="badge">beta</span>
</button>
</aside> </aside>
<code-gen v-model:open="codeOpen" :renderer="initOptions.renderer" /> <code-gen v-model:open="codeOpen" :renderer="initOptions.renderer" />
@ -297,7 +295,7 @@ input {
} }
label { label {
display: flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
@ -311,7 +309,7 @@ select {
} }
#logo { #logo {
display: inline-block; display: inline-flex;
width: 128px; width: 128px;
height: 128px; height: 128px;
pointer-events: none; pointer-events: none;
@ -381,11 +379,13 @@ select {
} }
} }
} }
}
.actions { .actions {
display: flex; display: flex;
justify-content: center; justify-content: center;
} align-items: center;
gap: 8px;
} }
.renderer, .renderer,
@ -445,15 +445,6 @@ select {
align-items: center; align-items: center;
padding: 0 4px; padding: 0 4px;
gap: 4px; gap: 4px;
.badge {
display: block;
padding: 2px 3px;
font-size: 10px;
background: #36485e54;
color: #fff;
border-radius: 4px;
}
} }
} }

View File

@ -15,15 +15,16 @@ const c1 = {
fontWeight: 300 fontWeight: 300
}, },
legend: { legend: {
top: 20, top: "3%",
data: ["scatter"] data: ["scatter"]
}, },
tooltip: { tooltip: {
formatter: "{c}" formatter: "{c}"
}, },
grid: { grid: {
top: "26%", top: "30%",
bottom: "26%" right: "18%",
bottom: "20%"
}, },
xAxis: { xAxis: {
type: "value", type: "value",
@ -40,7 +41,8 @@ const c1 = {
visualMap: [ visualMap: [
{ {
realtime: false, realtime: false,
left: "right", right: "2%",
bottom: "3%",
selectedMode: "multiple", selectedMode: "multiple",
dimension: 2, dimension: 2,
selected: [], selected: [],
@ -67,15 +69,16 @@ const c2 = {
fontWeight: 300 fontWeight: 300
}, },
legend: { legend: {
top: 20, top: "3%",
data: ["scatter"] data: ["scatter"]
}, },
tooltip: { tooltip: {
formatter: "{c}" formatter: "{c}"
}, },
grid: { grid: {
top: "26%", top: "30%",
bottom: "26%" right: "18%",
bottom: "20%"
}, },
xAxis: { xAxis: {
type: "value", type: "value",
@ -91,7 +94,8 @@ const c2 = {
}, },
visualMap: [ visualMap: [
{ {
left: "right", right: "2%",
bottom: "3%",
selectedMode: "multiple", selectedMode: "multiple",
dimension: 2, dimension: 2,
selected: [], selected: [],

View File

@ -408,6 +408,7 @@ export default function getData() {
text: "Air quality of major cities in China", text: "Air quality of major cities in China",
subtext: "data from PM25.in", subtext: "data from PM25.in",
sublink: "http://www.pm25.in", sublink: "http://www.pm25.in",
top: "5%",
left: "center", left: "center",
textStyle: { textStyle: {
color: "#fff" color: "#fff"
@ -418,9 +419,9 @@ export default function getData() {
}, },
legend: { legend: {
orient: "vertical", orient: "vertical",
y: "bottom", right: "5%",
x: "right", bottom: "5%",
data: ["pm2.5"], data: ["PM2.5"],
textStyle: { textStyle: {
color: "#fff" color: "#fff"
} }
@ -438,11 +439,13 @@ export default function getData() {
itemStyle: { itemStyle: {
areaColor: "#323c48", areaColor: "#323c48",
borderColor: "#111" borderColor: "#111"
} },
top: "20%",
bottom: "7%"
}, },
series: [ series: [
{ {
name: "pm2.5", name: "PM2.5",
type: "scatter", type: "scatter",
coordinateSystem: "geo", coordinateSystem: "geo",
data: convertData(data), data: convertData(data),

View File

@ -6,6 +6,7 @@ export default function getData() {
}, },
title: { title: {
text: "Traffic Sources", text: "Traffic Sources",
top: "5%",
left: "center" left: "center"
}, },
tooltip: { tooltip: {
@ -14,7 +15,8 @@ export default function getData() {
}, },
legend: { legend: {
orient: "vertical", orient: "vertical",
left: "left", top: "5%",
left: "5%",
data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"] data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
}, },
series: [ series: [

View File

@ -13,13 +13,17 @@ export default function getData() {
fontWeight: 300 fontWeight: 300
}, },
title: { title: {
text: "Dual Numeric Axis" text: "Dual Numeric Axis",
top: "5%",
left: "5%"
}, },
legend: { legend: {
data: ["line"] data: ["line"],
top: "6%"
}, },
polar: { polar: {
center: ["50%", "54%"] radius: "65%",
center: ["50%", "56%"]
}, },
tooltip: { tooltip: {
trigger: "axis", trigger: "axis",

View File

@ -15,37 +15,17 @@ export const useScoreStore = defineStore("store", () => {
return scores.value.map(({ name }) => name); return scores.value.map(({ name }) => name);
}); });
const scoreRadar = computed(() => { function getRadarData(activeIndex: number) {
return { return {
title: { title: {
text: "Player Ability" text: "Player Ability",
top: "5%",
left: "5%"
}, },
textStyle: { textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif', fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300 fontWeight: 300
}, },
radar: {
indicator: scores.value.map(({ name, max }) => {
return { name, max };
})
},
series: [
{
name: "Value",
type: "radar",
data: [{ value: scores.value.map(({ value }) => value) }]
}
]
};
});
function getRadarData(activeIndex: number) {
return {
animation: false,
title: {
text: "Player Ability"
},
tooltip: {},
radar: { radar: {
indicator: scores.value.map(({ name, max }, index) => { indicator: scores.value.map(({ name, max }, index) => {
if (index === activeIndex) { if (index === activeIndex) {
@ -81,7 +61,6 @@ export const useScoreStore = defineStore("store", () => {
return { return {
scores, scores,
metrics, metrics,
scoreRadar,
getRadarData, getRadarData,
increase, increase,
isMax, isMax,

View File

@ -47,15 +47,21 @@ const data = [
export default function getData() { export default function getData() {
return { return {
grid: {
top: "25%"
},
textStyle: { textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif', fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300 fontWeight: 300
}, },
title: { title: {
text: "Life Expectancy vs. GDP by country" text: "Life Expectancy vs. GDP by country",
top: "5%",
left: "5%"
}, },
legend: { legend: {
right: 10, top: "6%",
right: "5%",
data: ["1990", "2015"] data: ["1990", "2015"]
}, },
xAxis: { xAxis: {

View File

@ -46,10 +46,8 @@ watch(
</template> </template>
<template #extra> <template #extra>
<p class="actions"> <p class="actions">
<label> <input id="connected-check" type="checkbox" v-model="connected" />
<input type="checkbox" v-model="connected" /> <label for="connected-check">Connected</label>
Connected
</label>
</p> </p>
</template> </template>
</v-example> </v-example>

View File

@ -49,7 +49,6 @@ defineProps({
width: calc(60vw + 4em); width: calc(60vw + 4em);
height: 360px; height: 360px;
max-width: 720px; max-width: 720px;
padding: 1.5em 2em;
border: 1px solid rgba(0, 0, 0, 0.1); border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px; border-radius: 8px;
box-shadow: 0 0 45px rgba(0, 0, 0, 0.2); box-shadow: 0 0 45px rgba(0, 0, 0, 0.2);
@ -75,7 +74,6 @@ defineProps({
width: 100%; width: 100%;
min-width: 0; min-width: 0;
height: 60vw; height: 60vw;
padding: 1em 0;
border: none; border: none;
border-radius: 0; border-radius: 0;
box-shadow: none; box-shadow: none;
@ -88,7 +86,6 @@ defineProps({
.echarts { .echarts {
width: 28vw; width: 28vw;
min-width: 240px; min-width: 240px;
padding: 1em 1.5em;
height: 180px; height: 180px;
} }

View File

@ -50,6 +50,8 @@ onMounted(() => {
} }
}, },
visualMap: { visualMap: {
bottom: "3%",
left: "3%",
max: 40, max: 40,
calculable: true, calculable: true,
realtime: false, realtime: false,

View File

@ -46,6 +46,7 @@ function load() {
}, },
title: { title: {
text: "World Flights", text: "World Flights",
top: "5%",
left: "center", left: "center",
textStyle: { textStyle: {
color: "#eee" color: "#eee"
@ -62,8 +63,10 @@ function load() {
}, },
geo: { geo: {
map: "world", map: "world",
left: 0, top: "15%",
right: 0, right: "5%",
bottom: "5%",
left: "5%",
silent: true, silent: true,
itemStyle: { itemStyle: {
borderColor: "#003", borderColor: "#003",

View File

@ -7,7 +7,7 @@ import {
LegendComponent, LegendComponent,
TooltipComponent TooltipComponent
} from "echarts/components"; } from "echarts/components";
import { shallowRef } from "vue"; import { computed, shallowRef } from "vue";
import VChart from "../../ECharts"; import VChart from "../../ECharts";
import VExample from "./Example"; import VExample from "./Example";
import getData from "../data/polar"; import getData from "../data/polar";
@ -22,6 +22,23 @@ use([
const option = shallowRef(getData()); const option = shallowRef(getData());
const theme = shallowRef("dark"); const theme = shallowRef("dark");
const loading = shallowRef(false);
const loadingOptions = computed(() =>
theme.value === "dark"
? {
color: "#fff",
textColor: "#fff",
maskColor: "rgba(0, 0, 0, 0.7)"
}
: null
);
const style = computed(() => {
return theme.value === "dark"
? loading.value
? "background-color: #05040d"
: "background-color: #100c2a"
: "";
});
</script> </script>
<template> <template>
@ -29,8 +46,10 @@ const theme = shallowRef("dark");
<v-chart <v-chart
:option="option" :option="option"
autoresize autoresize
:loading="loading"
:loading-options="loadingOptions"
:theme="theme" :theme="theme"
:style="theme === 'dark' ? 'background-color: #100c2a' : ''" :style="style"
/> />
<template #extra> <template #extra>
<p class="actions"> <p class="actions">
@ -39,6 +58,8 @@ const theme = shallowRef("dark");
<option :value="null">Default</option> <option :value="null">Default</option>
<option value="dark">Dark</option> <option value="dark">Dark</option>
</select> </select>
<input id="loading-check" type="checkbox" v-model="loading" />
<label for="loading-check">Loading</label>
</p> </p>
</template> </template>
</v-example> </v-example>

View File

@ -3,7 +3,17 @@ import { createApp } from "vue";
import { createPinia } from "pinia"; import { createPinia } from "pinia";
import Demo from "./Demo.vue"; import Demo from "./Demo.vue";
inject(); const SAMPLE_RATE = 0.5;
inject({
beforeSend: event => {
if (Math.random() > SAMPLE_RATE) {
return null;
}
return event;
}
});
const pinia = createPinia(); const pinia = createPinia();
const app = createApp(Demo); const app = createApp(Demo);

View File

@ -1,31 +1,44 @@
/* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/ban-types */
import type { DefineComponent } from "@vue/runtime-core"; import type { Ref, DefineComponent, InjectionKey } from "vue-demi";
import type { Ref } from "vue-demi";
import type { import type {
Option, Option,
Theme,
InitOptions, InitOptions,
UpdateOptions, UpdateOptions,
LoadingOptions,
EChartsType, EChartsType,
Emits Emits,
ThemeInjection,
InitOptionsInjection,
UpdateOptionsInjection,
LoadingOptionsInjection
} from "./types"; } from "./types";
declare const LOADING_OPTIONS_KEY = "ecLoadingOptions"; declare const THEME_KEY: InjectionKey<ThemeInjection>;
declare const THEME_KEY = "ecTheme"; declare const INIT_OPTIONS_KEY: InjectionKey<InitOptionsInjection>;
declare const INIT_OPTIONS_KEY = "ecInitOptions"; declare const UPDATE_OPTIONS_KEY: InjectionKey<UpdateOptionsInjection>;
declare const UPDATE_OPTIONS_KEY = "ecUpdateOptions"; declare const LOADING_OPTIONS_KEY: InjectionKey<LoadingOptionsInjection>;
declare type ChartProps = { declare type ChartProps = {
loading?: boolean; theme?: Theme;
loadingOptions?: Record<string, unknown>;
autoresize?: boolean;
option?: Option;
theme?: string | Record<string, unknown>;
initOptions?: InitOptions; initOptions?: InitOptions;
updateOptions?: UpdateOptions; updateOptions?: UpdateOptions;
loadingOptions?: LoadingOptions;
option?: Option;
autoresize?: boolean;
loading?: boolean;
group?: string; group?: string;
manualUpdate?: boolean; manualUpdate?: boolean;
}; };
// convert Emits to Props
// click => onClick
declare type ChartEventProps = {
[key in keyof Emits as key extends string
? `on${Capitalize<key>}`
: never]?: Emits[key];
};
type MethodNames = type MethodNames =
| "getWidth" | "getWidth"
| "getHeight" | "getHeight"
@ -47,18 +60,15 @@ type MethodNames =
declare type ChartMethods = Pick<EChartsType, MethodNames>; declare type ChartMethods = Pick<EChartsType, MethodNames>;
declare const Chart: DefineComponent< declare const Chart: DefineComponent<
ChartProps, ChartProps & ChartEventProps,
{ {
root: Ref<HTMLElement | undefined>; root: Ref<HTMLElement | undefined>;
chart: Ref<EChartsType | undefined>; chart: Ref<EChartsType | undefined>;
}, },
{}, {},
{}, {},
ChartMethods, ChartMethods
{},
{},
Emits
>; >;
export default Chart; export default Chart;
export { INIT_OPTIONS_KEY, LOADING_OPTIONS_KEY, THEME_KEY, UPDATE_OPTIONS_KEY }; export { THEME_KEY, INIT_OPTIONS_KEY, UPDATE_OPTIONS_KEY, LOADING_OPTIONS_KEY };

63
src/index.vue2_7.d.ts vendored
View File

@ -1,63 +0,0 @@
/* 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 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;
};
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,2 +1 @@
x-vue-echarts{display:flex;flex-direction:column;width:100%;height:100%;min-width:0} x-vue-echarts{display:block;width:100%;height:100%;min-width:0}
.vue-echarts-inner{flex-grow:1;min-width:0}

View File

@ -1,6 +1,7 @@
import { init } from "echarts/core"; import { init } from "echarts/core";
import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts";
import type { Ref } from "vue"; import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts/core";
import type { Ref } from "vue-demi";
export type Injection<T> = T | null | Ref<T | null> | { value: T | null }; export type Injection<T> = T | null | Ref<T | null> | { value: T | null };
@ -36,6 +37,7 @@ export type LoadingOptions = {
lineWidth?: number; lineWidth?: number;
zlevel?: number; zlevel?: number;
}; };
export type LoadingOptionsInjection = Injection<LoadingOptions>;
type MouseEventName = type MouseEventName =
| "click" | "click"
@ -91,19 +93,19 @@ type OtherEventName =
| "globalcursortaken"; | "globalcursortaken";
type MouseEmits = { type MouseEmits = {
[key in MouseEventName]: (params: ECElementEvent) => boolean; [key in MouseEventName]: (params: ECElementEvent) => void;
}; };
type ZRenderEmits = { type ZRenderEmits = {
[key in ZRenderEventName]: (params: ElementEvent) => boolean; [key in ZRenderEventName]: (params: ElementEvent) => void;
}; };
type OtherEmits = { type OtherEmits = {
[key in OtherEventName]: null; [key in OtherEventName]: (params: any) => void;
}; };
export type Emits = MouseEmits & export type Emits = MouseEmits &
OtherEmits & { OtherEmits & {
rendered: (params: { elapsedTime: number }) => boolean; rendered: (params: { elapsedTime: number }) => void;
finished: () => boolean; finished: () => void;
} & ZRenderEmits; } & ZRenderEmits;

View File

@ -1,4 +1,5 @@
import { unref } from "vue-demi"; import { unref, isRef } from "vue-demi";
import type { Injection } from "./types"; import type { Injection } from "./types";
type Attrs = { type Attrs = {
@ -26,7 +27,7 @@ export function unwrapInjected<T, V>(
injection: Injection<T>, injection: Injection<T>,
defaultValue: V defaultValue: V
): T | V { ): T | V {
const value = unref(injection); const value = isRef(injection) ? unref(injection) : injection;
if (value && typeof value === "object" && "value" in value) { if (value && typeof value === "object" && "value" in value) {
return value.value || defaultValue; return value.value || defaultValue;

View File

@ -26,21 +26,9 @@ export function register(): boolean {
// if the browser doesn't support native classes. // if the browser doesn't support native classes.
const reg = new Function( const reg = new Function(
"tag", "tag",
`class EChartsElement extends HTMLElement { // Use esbuild repl to keep build process simple
__dispose = null; // https://esbuild.github.io/try/#dAAwLjIzLjAALS1taW5pZnkAY2xhc3MgRUNoYXJ0c0VsZW1lbnQgZXh0ZW5kcyBIVE1MRWxlbWVudCB7CiAgX19kaXNwb3NlID0gbnVsbDsKCiAgZGlzY29ubmVjdGVkQ2FsbGJhY2soKSB7CiAgICBpZiAodGhpcy5fX2Rpc3Bvc2UpIHsKICAgICAgdGhpcy5fX2Rpc3Bvc2UoKTsKICAgICAgdGhpcy5fX2Rpc3Bvc2UgPSBudWxsOwogICAgfQogIH0KfQoKaWYgKGN1c3RvbUVsZW1lbnRzLmdldCh0YWcpID09IG51bGwpIHsKICBjdXN0b21FbGVtZW50cy5kZWZpbmUodGFnLCBFQ2hhcnRzRWxlbWVudCk7Cn0K
"class EChartsElement extends HTMLElement{__dispose=null;disconnectedCallback(){this.__dispose&&(this.__dispose(),this.__dispose=null)}}customElements.get(tag)==null&&customElements.define(tag,EChartsElement);"
disconnectedCallback() {
if (this.__dispose) {
this.__dispose();
this.__dispose = null;
}
}
}
if (customElements.get(tag) == null) {
customElements.define(tag, EChartsElement);
}
`
); );
reg(TAG_NAME); reg(TAG_NAME);
} catch (e) { } catch (e) {

View File

@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */ import nested from "postcss-nested";
const nested = require("postcss-nested");
module.exports = { export default {
outputDir: "demo", outputDir: "demo",
css: { css: {
loaderOptions: { loaderOptions: {
@ -21,6 +20,14 @@ module.exports = {
.test(/\.svg$/) .test(/\.svg$/)
.type("asset/source"); .type("asset/source");
config.module
.rule("wasm")
.test(/\.wasm$/)
.type("asset/resource")
.set("generator", {
filename: "[name].[hash:8][ext]"
});
config.plugin("define").tap(([options]) => [ config.plugin("define").tap(([options]) => [
{ {
...options, ...options,