| <template> | |
| <div class="chart" ref="chartRef"></div> | |
| </template> | |
| <script lang="ts" setup> | |
| import { onMounted, ref, computed, watch } from 'vue' | |
| import tinycolor from 'tinycolor2' | |
| import type { ChartData, ChartOptions, ChartType } from '@/types/slides' | |
| import { getChartOption } from './chartOption' | |
| import * as echarts from 'echarts/core' | |
| import { BarChart, LineChart, PieChart, ScatterChart, RadarChart } from 'echarts/charts' | |
| import { LegendComponent } from 'echarts/components' | |
| import { SVGRenderer } from 'echarts/renderers' | |
| echarts.use([ | |
| BarChart, | |
| LineChart, | |
| PieChart, | |
| ScatterChart, | |
| RadarChart, | |
| LegendComponent, | |
| SVGRenderer, | |
| ]) | |
| const props = defineProps<{ | |
| width: number | |
| height: number | |
| type: ChartType | |
| data: ChartData | |
| themeColors: string[] | |
| textColor?: string | |
| options?: ChartOptions | |
| }>() | |
| let chart: echarts.ECharts | null = null | |
| const chartRef = ref<HTMLElement>() | |
| const themeColors = computed(() => { | |
| let colors: string[] = [] | |
| if (props.themeColors.length >= 10) colors = props.themeColors | |
| else if (props.themeColors.length === 1) colors = tinycolor(props.themeColors[0]).analogous(10).map(color => color.toRgbString()) | |
| else { | |
| const len = props.themeColors.length | |
| const supplement = tinycolor(props.themeColors[len - 1]).analogous(10 + 1 - len).map(color => color.toRgbString()) | |
| colors = [...props.themeColors.slice(0, len - 1), ...supplement] | |
| } | |
| return colors | |
| }) | |
| const updateOption = () => { | |
| const option = getChartOption({ | |
| type: props.type, | |
| data: props.data, | |
| themeColors: themeColors.value, | |
| textColor: props.textColor, | |
| lineSmooth: props.options?.lineSmooth || false, | |
| stack: props.options?.stack || false, | |
| }) | |
| if (option) chart!.setOption(option, true) | |
| } | |
| onMounted(() => { | |
| chart = echarts.init(chartRef.value, null, { renderer: 'svg' }) | |
| updateOption() | |
| const resizeListener = () => chart!.resize() | |
| const resizeObserver = new ResizeObserver(resizeListener) | |
| resizeObserver.observe(chartRef.value!) | |
| }) | |
| watch(() => props.type, updateOption) | |
| watch(() => props.data, updateOption) | |
| watch(() => props.themeColors, updateOption) | |
| watch(() => props.textColor, updateOption) | |
| </script> | |
| <style lang="scss" scoped> | |
| .chart { | |
| width: 100%; | |
| height: 100%; | |
| } | |
| </style> |