feat: add default style, injectable update-options & loading-options

This commit is contained in:
Justineo
2021-02-22 11:50:43 +08:00
parent aaab149c11
commit b8d9ca7991
7 changed files with 98 additions and 52 deletions

View File

@ -1,13 +1,14 @@
import typescript from "rollup-plugin-typescript2"; import typescript from "rollup-plugin-typescript2";
import { terser } from "rollup-plugin-terser"; import { terser } from "rollup-plugin-terser";
import resolve from "@rollup/plugin-node-resolve"; import resolve from "@rollup/plugin-node-resolve";
import postcss from "rollup-plugin-postcss";
import dts from "rollup-plugin-dts"; import dts from "rollup-plugin-dts";
/** @type {import('rollup').RollupOptions} */ /** @type {import('rollup').RollupOptions} */
const options = [ const options = [
{ {
input: "src/index.ts", input: "src/index.ts",
plugins: [typescript()], plugins: [typescript(), postcss()],
external: ["vue-demi", "echarts/core", "resize-detector"], external: ["vue-demi", "echarts/core", "resize-detector"],
output: [ output: [
{ {
@ -50,8 +51,8 @@ const options = [
}, },
{ {
input: "src/all.ts", input: "src/all.ts",
plugins: [resolve(), typescript()], plugins: [resolve(), typescript(), postcss()],
external: ["vue-demi", "echarts/core"], external: ["vue", "echarts", "echarts/core"],
output: [ output: [
{ {
file: "dist/index.umd.js", file: "dist/index.umd.js",
@ -59,7 +60,8 @@ const options = [
name: "VueECharts", name: "VueECharts",
sourcemap: true, sourcemap: true,
globals: { globals: {
"vue-demi": "VueDemi", vue: "Vue",
echarts: "echarts",
"echarts/core": "echarts" "echarts/core": "echarts"
} }
}, },
@ -69,7 +71,8 @@ const options = [
name: "VueECharts", name: "VueECharts",
sourcemap: true, sourcemap: true,
globals: { globals: {
"vue-demi": "VueDemi", vue: "Vue",
echarts: "echarts",
"echarts/core": "echarts" "echarts/core": "echarts"
}, },
plugins: [ plugins: [
@ -84,7 +87,7 @@ const options = [
}, },
{ {
input: "src/index.ts", input: "src/index.ts",
plugins: [dts()], plugins: [postcss(), dts()],
output: { output: {
file: "dist/index.d.ts", file: "dist/index.d.ts",
format: "es" format: "es"

View File

@ -2,6 +2,7 @@
import { import {
defineComponent, defineComponent,
ref, ref,
unref,
shallowRef, shallowRef,
toRefs, toRefs,
watch, watch,
@ -10,10 +11,17 @@ import {
onMounted, onMounted,
onUnmounted, onUnmounted,
h, h,
PropType PropType,
watchEffect
} from "vue-demi"; } from "vue-demi";
import { init as initChart } from "echarts/core"; import { init as initChart } from "echarts/core";
import { EChartsType, OptionType } from "./types"; import {
EChartsType,
InitOptions,
Option,
UpdateOptions,
Theme
} from "./types";
import { import {
usePublicAPI, usePublicAPI,
useAutoresize, useAutoresize,
@ -21,37 +29,49 @@ import {
useLoading, useLoading,
loadingProps loadingProps
} from "./composables"; } from "./composables";
import "./style.css";
type InitParameters = Parameters<typeof initChart>; export const INIT_OPTIONS_KEY = "ecInitOptions";
type ThemeParameter = InitParameters[1]; export const UPDATE_OPTIONS_KEY = "ecUpdateOptions";
type InitOptsParameter = InitParameters[2]; export { LOADING_OPTIONS_KEY } from "./composables";
export default defineComponent({ export default defineComponent({
name: "echarts", name: "echarts",
props: { props: {
option: Object as PropType<OptionType>, option: Object as PropType<Option>,
theme: { theme: {
type: [Object, String] as PropType<ThemeParameter> type: [Object, String] as PropType<Theme>
}, },
initOptions: Object as PropType<InitOptsParameter>, initOptions: Object as PropType<InitOptions>,
updateOptions: Object as PropType<UpdateOptions>,
group: String, group: String,
manualUpdate: Boolean, manualUpdate: Boolean,
...autoresizeProps, ...autoresizeProps,
...loadingProps ...loadingProps
}, },
setup(props, { attrs }) { setup(props, { attrs }) {
const defaultInitOptions = inject( const defaultInitOptions = inject(INIT_OPTIONS_KEY, {}) as InitOptions;
"echartsInitOptions", const defaultUpdateOptions = inject(
UPDATE_OPTIONS_KEY,
{} {}
) as InitOptsParameter; ) as UpdateOptions;
const root = ref<HTMLElement>(); const root = ref<HTMLElement>();
const chart = shallowRef<EChartsType>(); const chart = shallowRef<EChartsType>();
const manualOption = shallowRef<OptionType>(); const manualOption = shallowRef<Option>();
const realOption = computed( const realOption = computed(
() => manualOption.value || props.option || Object.create(null) () => manualOption.value || props.option || Object.create(null)
); );
const realInitOptions = computed(() => ({
...defaultInitOptions,
...props.initOptions
}));
const realUpdateOptions = computed(() => ({
...defaultUpdateOptions,
...props.updateOptions
}));
const { autoresize, manualUpdate, loading, loadingOptions } = toRefs(props);
function init(option?: OptionType) { function init(option?: Option) {
if (chart.value || !root.value) { if (chart.value || !root.value) {
return; return;
} }
@ -59,7 +79,7 @@ export default defineComponent({
const instance = (chart.value = initChart( const instance = (chart.value = initChart(
root.value, root.value,
props.theme, props.theme,
props.initOptions || defaultInitOptions realInitOptions.value
)); ));
if (props.group) { if (props.group) {
@ -67,7 +87,7 @@ export default defineComponent({
} }
Object.keys(attrs) Object.keys(attrs)
.filter(key => key.indexOf(`on`) === 0) .filter(key => key.indexOf("on") === 0)
.forEach(key => { .forEach(key => {
const handler = attrs[key] as any; const handler = attrs[key] as any;
@ -82,10 +102,10 @@ export default defineComponent({
} }
}); });
instance.setOption(option || realOption.value, true); instance.setOption(option || realOption.value, realUpdateOptions.value);
} }
function setOption(option: OptionType, ...rest: any[]) { function setOption(option: Option, updateOptions?: UpdateOptions) {
if (props.manualUpdate) { if (props.manualUpdate) {
manualOption.value = option; manualOption.value = option;
} }
@ -93,7 +113,10 @@ export default defineComponent({
if (!chart.value) { if (!chart.value) {
init(option); init(option);
} else { } else {
chart.value.setOption(option, ...rest); chart.value.setOption(option, {
...realUpdateOptions.value,
...updateOptions
});
} }
} }
@ -104,7 +127,6 @@ export default defineComponent({
} }
} }
const { autoresize, manualUpdate, loading, loadingOptions } = toRefs(props);
let unwatchOption: (() => void) | null = null; let unwatchOption: (() => void) | null = null;
watch( watch(
manualUpdate, manualUpdate,
@ -117,21 +139,14 @@ export default defineComponent({
if (!manualUpdate) { if (!manualUpdate) {
unwatchOption = watch( unwatchOption = watch(
() => props.option, () => props.option,
(val, oldVal) => { option => {
if (!val) { if (!option) {
return; return;
} }
if (!chart.value) { if (!chart.value) {
init(); init();
} else { } else {
// mutating `option` will lead to merging chart.value.setOption(option, props.updateOptions);
// replacing it with new reference will lead to not merging
// eg.
// `this.option = Object.assign({}, this.option, { ... })`
// will trigger `this.chart.setOption(val, true)
// `this.option.title.text = 'Trends'`
// will trigger `this.chart.setOption(val, false)`
chart.value.setOption(val, val !== oldVal);
} }
}, },
{ deep: true } { deep: true }
@ -154,14 +169,11 @@ export default defineComponent({
} }
); );
watch( watchEffect(() => {
() => props.group, if (props.group && chart.value) {
group => { chart.value.group = props.group;
if (group && chart.value) {
chart.value.group = group;
}
} }
); });
const publicApi = usePublicAPI(chart, init); const publicApi = usePublicAPI(chart, init);
@ -177,13 +189,20 @@ export default defineComponent({
onUnmounted(cleanup); onUnmounted(cleanup);
return { const exposed = {
root, root,
setOption, setOption,
...publicApi ...publicApi
}; };
Object.defineProperty(exposed, "chart", {
get() {
return unref(chart);
}
});
return exposed;
}, },
render() { render() {
return h("div", { ref: "root" }); return h("div", { class: "echarts", ref: "root" });
} }
}); });

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 { Ref } from "vue-demi";
import { EChartsType, OptionType } from "../types"; import { EChartsType, Option } from "../types";
const METHOD_NAMES = [ const METHOD_NAMES = [
"getWidth", "getWidth",
@ -24,7 +24,7 @@ type PublicMethods = Pick<EChartsType, MethodName>;
export function usePublicAPI( export function usePublicAPI(
chart: Ref<EChartsType | undefined>, chart: Ref<EChartsType | undefined>,
init: (option?: OptionType) => void init: (option?: Option) => void
) { ) {
function makePublicMethod<T extends MethodName>( function makePublicMethod<T extends MethodName>(
name: T name: T

View File

@ -1,13 +1,13 @@
import { Ref, watch } from "vue-demi"; import { Ref, watch } from "vue-demi";
import { throttle } from "echarts/core"; import { throttle } from "echarts/core";
import { addListener, removeListener, ResizeCallback } from "resize-detector"; import { addListener, removeListener, ResizeCallback } from "resize-detector";
import { EChartsType, OptionType } from "../types"; import { EChartsType, Option } from "../types";
export function useAutoresize( export function useAutoresize(
chart: Ref<EChartsType | undefined>, chart: Ref<EChartsType | undefined>,
autoresize: Ref<boolean>, autoresize: Ref<boolean>,
root: Ref<HTMLElement | undefined>, root: Ref<HTMLElement | undefined>,
option: Ref<OptionType> option: Ref<Option>
): void { ): void {
let resizeListener: ResizeCallback | null = null; let resizeListener: ResizeCallback | null = null;
let lastArea = 0; let lastArea = 0;

View File

@ -1,11 +1,19 @@
import { Ref, watchEffect } from "vue-demi"; import { inject, computed, Ref, watchEffect } from "vue-demi";
import { EChartsType } from "../types"; import { EChartsType } from "../types";
export const LOADING_OPTIONS_KEY = "ecLoadingOptions";
export function useLoading( export function useLoading(
chart: Ref<EChartsType | undefined>, chart: Ref<EChartsType | undefined>,
loading: Ref<boolean>, loading: Ref<boolean>,
loadingOptions?: Ref<object | undefined> loadingOptions?: Ref<object | undefined>
): void { ): void {
const defaultLoadingOptions = inject(LOADING_OPTIONS_KEY, {}) as object;
const realLoadingOptions = computed(() => ({
...defaultLoadingOptions,
...loadingOptions?.value
}));
watchEffect(() => { watchEffect(() => {
const instance = chart.value; const instance = chart.value;
if (!instance) { if (!instance) {
@ -13,7 +21,7 @@ export function useLoading(
} }
if (loading.value) { if (loading.value) {
instance.showLoading(loadingOptions?.value); instance.showLoading(realLoadingOptions.value);
} else { } else {
instance.hideLoading(); instance.hideLoading();
} }

1
src/style.css Normal file
View File

@ -0,0 +1 @@
.echarts{width:100%;height:100%}

View File

@ -1,5 +1,20 @@
import { init } from "echarts/core"; import { init } from "echarts/core";
export type EChartsType = ReturnType<typeof init>; type InitType = typeof init;
export type InitParameters = Parameters<InitType>;
export type Theme = NonNullable<InitParameters[1]>;
export type InitOptions = NonNullable<InitParameters[2]>;
export type EChartsType = ReturnType<InitType>;
type SetOptionType = EChartsType["setOption"]; type SetOptionType = EChartsType["setOption"];
export type OptionType = Parameters<SetOptionType>[0]; export type Option = Parameters<SetOptionType>[0];
// TODO: Wait for apache/echarts#14289 to ship in v5.1,
// so that we can use SetOptionOpts directly
export interface UpdateOptions {
notMerge?: boolean;
lazyUpdate?: boolean;
silent?: boolean;
replaceMerge?: any;
transition?: any;
}