Compare commits

..

16 Commits

25 changed files with 6628 additions and 5537 deletions

25
.eslintrc.js Normal file
View File

@ -0,0 +1,25 @@
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"
]
}
]
};

View File

@ -1,24 +0,0 @@
{
"root": true,
"env": {
"node": true
},
"extends": ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
"parserOptions": {
"ecmaVersion": 2020,
"parser": "@typescript-eslint/parser"
},
"rules": {
"no-console": "off",
"vue/multi-word-component-names": "off"
},
"overrides": [
{
"files": ["*.ts"],
"extends": [
"@vue/typescript/recommended",
"@vue/prettier/@typescript-eslint"
]
}
]
}

View File

@ -1,3 +1,19 @@
## 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)).

144
README.md
View File

@ -236,9 +236,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.23"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.7.2"></script>
``` ```
<!-- vue3Scripts:end --> <!-- vue3Scripts:end -->
@ -258,7 +258,7 @@ app.component('v-chart', VueECharts)
```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.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.7.2"></script>
``` ```
<!-- vue2Scripts:end --> <!-- vue2Scripts:end -->
@ -319,6 +319,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,68 +474,6 @@ 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 files from `dist/csp` directory and include `dist/csp/style.css` into your app manually.
@ -507,3 +517,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

@ -236,9 +236,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.23"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.7.2"></script>
``` ```
<!-- vue3Scripts:end --> <!-- vue3Scripts:end -->
@ -258,7 +258,7 @@ app.component('v-chart', VueECharts)
```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.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.7.2"></script>
``` ```
<!-- vue2Scripts:end --> <!-- vue2Scripts:end -->
@ -381,6 +381,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,6 +474,8 @@ 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>` 注入,则需要使用 `dist/csp` 目录中的文件,并手动引入 `dist/csp/style.css`
@ -507,3 +519,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/).

3
babel.config.js Normal file
View File

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

View File

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

View File

@ -1,7 +1,6 @@
{ {
"name": "vue-echarts", "name": "vue-echarts",
"version": "6.6.9", "version": "6.7.2",
"type": "module",
"description": "Vue.js component for Apache ECharts™.", "description": "Vue.js component for Apache ECharts™.",
"author": "GU Yiling <justice360@gmail.com>", "author": "GU Yiling <justice360@gmail.com>",
"scripts": { "scripts": {
@ -27,48 +26,50 @@
"vue-demi": "^0.13.11" "vue-demi": "^0.13.11"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.2", "@babel/core": "^7.24.4",
"@highlightjs/vue-plugin": "^2.1.0", "@highlightjs/vue-plugin": "^2.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-terser": "^0.4.4",
"@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0", "@typescript-eslint/parser": "^4.33.0",
"@vercel/analytics": "^1.1.1", "@vercel/analytics": "^1.2.2",
"@vue/cli-plugin-babel": "^5.0.8", "@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8", "@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-typescript": "^5.0.8", "@vue/cli-plugin-typescript": "^5.0.8",
"@vue/cli-service": "^5.0.8", "@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.3.7", "@vue/compiler-sfc": "^3.4.24",
"@vue/composition-api": "^1.7.2", "@vue/composition-api": "^1.7.2",
"@vue/eslint-config-prettier": "^6.0.0", "@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^10.0.0", "@vue/eslint-config-typescript": "^10.0.0",
"@vueuse/core": "^10.5.0", "@vueuse/core": "^10.9.0",
"comment-mark": "^1.1.1", "comment-mark": "^1.1.1",
"core-js": "^3.33.2", "core-js": "^3.37.0",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"echarts-gl": "^2.0.9", "echarts-gl": "^2.0.9",
"echarts-liquidfill": "^3.1.0", "echarts-liquidfill": "^3.1.0",
"esbuild-wasm": "^0.19.2", "esbuild-wasm": "^0.19.12",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-prettier": "^3.4.1", "eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^8.7.1", "eslint-plugin-vue": "^8.7.1",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"postcss": "^8.4.31", "postcss": "^8.4.38",
"postcss-loader": "^5.3.0", "postcss-loader": "^5.3.0",
"postcss-nested": "^5.0.6", "postcss-nested": "^5.0.6",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
"resize-detector": "^0.3.0", "resize-detector": "^0.3.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^4.12.0", "rollup": "^2.79.1",
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^4.2.3",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-styles": "^4.0.0",
"rollup-plugin-import-css": "^3.5.0", "rollup-plugin-ts": "^2.0.7",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "4.6.4", "typescript": "4.6.4",
"vue": "^3.3.7", "vue": "^3.4.24",
"vue2": "npm:vue@^2.7.15", "vue2": "npm:vue@^2.7.16",
"webpack": "^5.89.0" "webpack": "^5.91.0"
}, },
"peerDependencies": { "peerDependencies": {
"@vue/composition-api": "^1.0.5", "@vue/composition-api": "^1.0.5",

11330
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
import esbuild from "rollup-plugin-esbuild"; import typescript from "rollup-plugin-ts";
import { dts } from "rollup-plugin-dts"; 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 css from "rollup-plugin-import-css"; import styles from "rollup-plugin-styles";
import { ignoreCss } from "./scripts/rollup.js"; import { injectVueDemi } from "./scripts/rollup";
/** /**
* Modifies the Rollup options for a build to support strict CSP * Modifies the Rollup options for a build to support strict CSP
@ -17,7 +18,7 @@ function configBuild(options, csp) {
result.plugins = [ result.plugins = [
...(csp ? [replace({ __CSP__: `${csp}`, preventAssignment: true })] : []), ...(csp ? [replace({ __CSP__: `${csp}`, preventAssignment: true })] : []),
...plugins, ...plugins,
csp ? css({ output: "style.css" }) : css({ inject: true }) csp ? styles({ mode: ["extract", "style.css"] }) : styles()
]; ];
// modify output file names // modify output file names
@ -38,37 +39,97 @@ function configBuild(options, csp) {
const builds = [ const builds = [
{ {
input: "src/index.ts", input: "src/index.ts",
plugins: [esbuild()], plugins: [
external: ["vue-demi", /^echarts/, "resize-detector"], typescript({
output: [ 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", file: "dist/index.esm.js",
format: "esm", format: "esm",
sourcemap: true sourcemap: true
}
},
{
input: "src/index.ts",
plugins: [typescript()],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: [
{
file: "dist/index.esm.min.js",
format: "esm",
sourcemap: true,
plugins: [
terser({
format: {
comments: false
}
})
]
}, },
{ {
file: "dist/index.cjs.js", file: "dist/index.cjs.js",
format: "cjs", format: "cjs",
exports: "named", exports: "named",
sourcemap: true sourcemap: true
}
]
},
{
input: "src/index.ts",
plugins: [esbuild({ minify: true })],
external: ["vue-demi", /^echarts/, "resize-detector"],
output: [
{
file: "dist/index.esm.min.js",
format: "esm",
sourcemap: true
}, },
{ {
file: "dist/index.cjs.min.js", file: "dist/index.cjs.min.js",
format: "cjs", format: "cjs",
exports: "named", exports: "named",
sourcemap: true sourcemap: true,
plugins: [
terser({
format: {
comments: false
}
})
]
}
]
},
{
input: "src/global.ts",
plugins: [resolve(), typescript()],
external: ["vue-demi", "echarts", "echarts/core"],
output: [
{
file: "dist/index.umd.js",
format: "umd",
name: "VueECharts",
exports: "default",
sourcemap: true,
globals: {
"vue-demi": "VueDemi",
echarts: "echarts",
"echarts/core": "echarts"
},
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
}
})
]
} }
] ]
} }
@ -76,22 +137,5 @@ 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.ts",
plugins: [
ignoreCss,
dts({
compilerOptions: {
// see https://github.com/unjs/unbuild/pull/57/files
preserveSymlinks: false
}
})
],
external: ["vue-demi", /^echarts/, "resize-detector"],
output: {
file: "dist/index.d.ts",
format: "esm"
}
}
]; ];

View File

@ -1,13 +1,16 @@
import { readFileSync, writeFileSync } from "node:fs"; const { readFileSync, writeFileSync } = require("fs");
import commentMark from "comment-mark"; const { resolve } = require("path");
import { getPackageMeta, resolvePath } from "./utils"; const commentMark = require("comment-mark");
const { name, version } = require("../package.json");
const { name, version } = getPackageMeta(); function resolvePath(...parts) {
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.23",
"vue@2": "2.7.16", "vue@2": "2.7.16",
echarts: "5.4.3", echarts: "5.4.3",
[name]: version [name]: version
@ -38,7 +41,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(import.meta.url, "..", name) resolvePath("..", name)
); );
README_FILES.forEach(file => { README_FILES.forEach(file => {

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
import fs from "node:fs"; const path = require("path");
import { resolvePath } from "./utils.js"; const fs = require("fs");
const packageFile = resolvePath(import.meta.url, "../package.json"); const packageFile = path.resolve(__dirname, "../package.json");
const typesPaths = { const typesPaths = {
3: "dist/index.d.ts", 3: "dist/index.d.ts",
@ -12,25 +12,23 @@ const typesPaths = {
function switchVersion(version) { function switchVersion(version) {
const typesPath = typesPaths[version]; const typesPath = typesPaths[version];
const pkg = JSON.parse(fs.readFileSync(packageFile, "utf8")); const package = JSON.parse(fs.readFileSync(packageFile, "utf8"));
if (typesPath !== pkg.types) { if (typesPath !== package.types) {
pkg.types = typesPath; package.types = typesPath;
fs.writeFileSync(packageFile, JSON.stringify(pkg, null, " "), "utf8"); fs.writeFileSync(packageFile, JSON.stringify(package, null, " "), "utf8");
} }
console.log(`[vue-echarts] Switched to Vue ${version} environment.`); console.log(`[vue-echarts] Switched to Vue ${version} environment.`);
} }
async function loadVue() { function loadVue() {
try { try {
const Vue = await import("vue"); return require("vue");
return Vue;
} catch (e) { } catch (e) {
return null; return null;
} }
} }
async function main() { const Vue = loadVue();
const Vue = await loadVue();
// Align the process with vue-demi // Align the process with vue-demi
if (!Vue || typeof Vue.version !== "string") { if (!Vue || typeof Vue.version !== "string") {
@ -46,6 +44,3 @@ async function main() {
} else { } else {
console.warn(`[vue-echarts] Vue version v${Vue.version} is not supported.`); console.warn(`[vue-echarts] Vue version v${Vue.version} is not supported.`);
} }
}
main();

View File

@ -1,7 +1,22 @@
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__"; const EMPTY_FILE_ID = "__rollup_empty__";
/** @type {import('rollup').Plugin} */ /** @type {import('rollup').Plugin} */
export const ignoreCss = { export const ingoreCss = {
name: "ignore-css", name: "ignore-css",
resolveId(source) { resolveId(source) {
if (source.endsWith(".css")) { if (source.endsWith(".css")) {

View File

@ -1,13 +0,0 @@
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,20 +13,11 @@ 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 { 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,
@ -39,8 +30,15 @@ import type {
UpdateOptionsInjection, UpdateOptionsInjection,
Emits Emits
} from "./types"; } from "./types";
import type { EChartsElement } from "./wc"; import {
usePublicAPI,
useAutoresize,
autoresizeProps,
useLoading,
loadingProps
} from "./composables";
import { isOn, omitOn, unwrapInjected } from "./utils";
import { register, TAG_NAME, type EChartsElement } from "./wc";
import "./style.css"; import "./style.css";
const __CSP__ = false; const __CSP__ = false;
@ -57,6 +55,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: {
@ -97,9 +97,62 @@ 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 (!inner.value) {
@ -116,27 +169,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];
@ -298,6 +330,7 @@ export default defineComponent({
inner, inner,
setOption, setOption,
nonEventAttrs, nonEventAttrs,
nativeListeners,
...publicApi ...publicApi
}; };
}, },
@ -305,7 +338,9 @@ 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";

View File

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

View File

@ -1,10 +1,11 @@
import { watch } from "vue-demi"; import { watch, type Ref, type PropType } from "vue-demi";
import { throttle } from "echarts/core"; import { throttle } from "echarts/core";
import { addListener, removeListener } from "resize-detector"; import {
addListener,
import type { Ref, PropType } from "vue-demi"; removeListener,
import type { ResizeCallback } from "resize-detector"; type ResizeCallback
import type { EChartsType } from "../types"; } from "resize-detector";
import { type EChartsType } from "../types";
type AutoresizeProp = type AutoresizeProp =
| boolean | boolean

View File

@ -1,7 +1,12 @@
import { inject, computed, watchEffect } from "vue-demi";
import { unwrapInjected } from "../utils"; import { unwrapInjected } from "../utils";
import {
import type { Ref, InjectionKey, PropType } from "vue-demi"; inject,
computed,
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

@ -76,7 +76,7 @@ const transformErrors = ref([]);
onMounted(async () => { onMounted(async () => {
await initialize({ await initialize({
wasmURL: "https://cdn.jsdelivr.net/npm/esbuild-wasm@0.19.2/esbuild.wasm" wasmURL: "https://cdn.jsdelivr.net/npm/esbuild-wasm@0.19.12/esbuild.wasm"
}); });
initializing.value = false; initializing.value = false;

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);

7
src/global.ts Normal file
View File

@ -0,0 +1,7 @@
import "echarts";
import ECharts, * as exported from "./index";
export default {
...ECharts,
...exported
};

View File

@ -1,2 +1,2 @@
x-vue-echarts{display:flex;flex-direction:column;width:100%;height:100%;min-width:0} x-vue-echarts{display:block;position:relative;width:100%;height:100%;min-width:0}
.vue-echarts-inner{flex-grow:1;min-width:0} .vue-echarts-inner{position:absolute!important;top:0;right:0;bottom:0;left:0}

View File

@ -1,6 +1,6 @@
import { init } from "echarts/core"; import { init } from "echarts/core";
import type { Ref } from "vue-demi";
import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts"; import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts";
import type { Ref } from "vue";
export type Injection<T> = T | null | Ref<T | null> | { value: T | null }; export type Injection<T> = T | null | Ref<T | null> | { value: T | null };

View File

@ -1,5 +1,4 @@
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 = {
@ -27,7 +26,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

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
import nested from "postcss-nested"; const nested = require("postcss-nested");
export default { module.exports = {
outputDir: "demo", outputDir: "demo",
css: { css: {
loaderOptions: { loaderOptions: {