Skip to content

Commit ada3f98

Browse files
committed
feat(hooks): add use-echarts
1 parent 0bab941 commit ada3f98

File tree

3 files changed

+205
-0
lines changed

3 files changed

+205
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"ant-design-vue": "4.1.1",
5454
"clipboard": "2.0.11",
5555
"dayjs": "1.11.10",
56+
"echarts": "5.4.3",
5657
"lodash-es": "4.17.21",
5758
"nprogress": "0.2.0",
5859
"pinia": "2.1.7",

pnpm-lock.yaml

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hooks/chart/use-echarts.ts

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import { effectScope, nextTick, onScopeDispose, ref, watch } from 'vue';
2+
import type { ComputedRef, Ref } from 'vue';
3+
import * as echarts from 'echarts/core';
4+
import { BarChart, GaugeChart, LineChart, PictorialBarChart, PieChart, RadarChart, ScatterChart } from 'echarts/charts';
5+
import type {
6+
BarSeriesOption,
7+
GaugeSeriesOption,
8+
LineSeriesOption,
9+
PictorialBarSeriesOption,
10+
PieSeriesOption,
11+
RadarSeriesOption,
12+
ScatterSeriesOption
13+
} from 'echarts/charts';
14+
import {
15+
DatasetComponent,
16+
GridComponent,
17+
LegendComponent,
18+
TitleComponent,
19+
ToolboxComponent,
20+
TooltipComponent,
21+
TransformComponent
22+
} from 'echarts/components';
23+
import type {
24+
DatasetComponentOption,
25+
GridComponentOption,
26+
LegendComponentOption,
27+
TitleComponentOption,
28+
ToolboxComponentOption,
29+
TooltipComponentOption
30+
} from 'echarts/components';
31+
import { LabelLayout, UniversalTransition } from 'echarts/features';
32+
import { CanvasRenderer } from 'echarts/renderers';
33+
import { useElementSize } from '@vueuse/core';
34+
35+
export type ECOption = echarts.ComposeOption<
36+
| BarSeriesOption
37+
| LineSeriesOption
38+
| PieSeriesOption
39+
| ScatterSeriesOption
40+
| PictorialBarSeriesOption
41+
| RadarSeriesOption
42+
| GaugeSeriesOption
43+
| TitleComponentOption
44+
| LegendComponentOption
45+
| TooltipComponentOption
46+
| GridComponentOption
47+
| ToolboxComponentOption
48+
| DatasetComponentOption
49+
>;
50+
51+
echarts.use([
52+
TitleComponent,
53+
LegendComponent,
54+
TooltipComponent,
55+
GridComponent,
56+
DatasetComponent,
57+
TransformComponent,
58+
ToolboxComponent,
59+
BarChart,
60+
LineChart,
61+
PieChart,
62+
ScatterChart,
63+
PictorialBarChart,
64+
RadarChart,
65+
GaugeChart,
66+
LabelLayout,
67+
UniversalTransition,
68+
CanvasRenderer
69+
]);
70+
71+
interface ChartHooks {
72+
onRender?: (chart: echarts.ECharts) => void | Promise<void>;
73+
onDestroy?: (chart: echarts.ECharts) => void | Promise<void>;
74+
}
75+
76+
/**
77+
* use echarts
78+
*
79+
* @param options echarts options
80+
* @param darkMode dark mode
81+
*/
82+
export function useEcharts(options: ECOption, darkMode: Ref<boolean> | ComputedRef<boolean>, hooks?: ChartHooks) {
83+
const scope = effectScope();
84+
85+
const domRef = ref<HTMLElement | null>(null);
86+
87+
const initialSize = { width: 0, height: 0 };
88+
const { width, height } = useElementSize(domRef, initialSize);
89+
90+
let chart: echarts.ECharts | null = null;
91+
92+
function canRender() {
93+
return initialSize.width > 0 && initialSize.height > 0;
94+
}
95+
96+
function isRendered() {
97+
return Boolean(domRef.value && chart);
98+
}
99+
100+
function setOptions(opts: ECOption) {
101+
if (isRendered()) {
102+
chart?.clear();
103+
chart?.setOption({ ...opts, backgroundColor: 'transparent' });
104+
}
105+
}
106+
107+
async function render() {
108+
if (domRef.value) {
109+
const chartTheme = darkMode.value ? 'dark' : 'light';
110+
111+
await nextTick();
112+
113+
chart = echarts.init(domRef.value, chartTheme);
114+
115+
setOptions(options);
116+
117+
await hooks?.onRender?.(chart);
118+
}
119+
}
120+
121+
function resize() {
122+
chart?.resize();
123+
}
124+
125+
async function destroy() {
126+
if (!chart) return;
127+
128+
await hooks?.onDestroy?.(chart);
129+
chart?.dispose();
130+
chart = null;
131+
}
132+
133+
async function changeTheme() {
134+
await destroy();
135+
await render();
136+
}
137+
138+
/**
139+
* render chart by size
140+
*
141+
* @param w
142+
* @param h
143+
*/
144+
async function renderChartBySize(w: number, h: number) {
145+
initialSize.width = w;
146+
initialSize.height = h;
147+
148+
// size is abnormal, destroy chart
149+
if (!canRender()) {
150+
await destroy();
151+
152+
return;
153+
}
154+
155+
// render chart
156+
if (!isRendered()) {
157+
await render();
158+
return;
159+
}
160+
161+
// resize chart
162+
resize();
163+
}
164+
165+
scope.run(() => {
166+
watch([width, height], ([newWidth, newHeight]) => {
167+
renderChartBySize(newWidth, newHeight);
168+
});
169+
170+
watch(darkMode, () => {
171+
changeTheme();
172+
});
173+
});
174+
175+
onScopeDispose(() => {
176+
destroy();
177+
scope.stop();
178+
});
179+
180+
return {
181+
domRef,
182+
setOptions
183+
};
184+
}

0 commit comments

Comments
 (0)