123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- <template>
- <div ref="chartRef" :style="{ height, width }"></div>
- </template>
- <script lang="ts" setup>
- import { ref, Ref, watch } from 'vue';
- import { useECharts } from '/@/hooks/web/useECharts';
- import { get } from 'lodash-es';
- import { Config } from '/@/views/vent/deviceManager/configurationTable/types';
- import { EChartsOption, graphic } from 'echarts';
- import { getFormattedText } from '../../../../deviceManager/configurationTable/adapters';
- const props = withDefaults(
- defineProps<{
- chartData: Record<string, any> | Record<string, any>[];
- chartConfig: Config['moduleData']['chart']['0'];
- height: string;
- width: string;
- }>(),
- {
- chartData: () => [],
- height: '100%',
- width: '100%',
- }
- );
- const chartRef = ref<HTMLDivElement | null>(null);
- const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
- // 核心方法,生成适用与 echart 的选项,这个方法需要适配 chart 类型的每种子类型
- const genChartOption = () => {
- // 依据每一个图表配置生成图表选项
- const { yAxis = [], xAxis = [], order, type, sortBy, series } = props.chartConfig;
- const isArray = Array.isArray(props.chartData);
- // 饼状图通常依赖单个对象的不同字段绘制
- if (type === 'pie' && !isArray) {
- return {
- legend: { show: false },
- color: ['#d9a1ff', '#00d1ff', '#82fe78'],
- series: [
- {
- type: 'pie',
- radius: ['50%', '75%'],
- center: ['50%', '55%'],
- data: series.map((serie) => {
- return {
- name: serie.label,
- value: get(props.chartData, serie.prop, 0),
- labelLine: { show: false },
- label: { show: false },
- itemStyle: {
- shadowBlur: 20,
- shadowColor: '#259bcf',
- },
- };
- }),
- },
- ],
- };
- }
- if (!isArray) return {};
- let sorttedData = [...(props.chartData as any[])];
- // 如果这个配置指明了需要排序则执行排序
- if (sortBy && order) {
- sorttedData.sort((pre, cur) => {
- if (order === 'asc') {
- return get(pre, sortBy, 0) - get(cur, sortBy, 0);
- } else {
- return get(cur, sortBy, 0) - get(pre, sortBy, 0);
- }
- });
- }
- // 柱状图则要求使用数组形式的数据作依赖
- if (type === 'bar') {
- return {
- grid: {
- top: 50,
- height: 150,
- },
- textStyle: {
- color: '#fff',
- },
- legend: { show: false },
- xAxis: xAxis.map((e) => {
- return {
- type: 'category',
- data: sorttedData.map((d) => {
- return getFormattedText(d, e.label);
- }),
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- name: e.label,
- position: e.align,
- splitLine: {
- lineStyle: {
- color: '#ffffff',
- opacity: 0.3,
- },
- },
- };
- }),
- series: series.reduce((curr: EChartsOption[], serie, index) => {
- const colors = ['#66ffff', '#ffff66'];
- // 系列选项,如果指定了x轴配置则以x轴配置优先
- const data = sorttedData.map((d) => {
- return {
- name: serie.label,
- value: get(d, serie.prop, 0),
- };
- });
- curr.push({
- name: 'pictorial element',
- type: 'pictorialBar',
- symbol: 'circle',
- symbolPosition: 'end',
- symbolSize: [16, 16],
- symbolOffset: [0, -8],
- yAxisIndex: index,
- itemStyle: {
- color: colors[index % colors.length],
- },
- data,
- });
- curr.push({
- name: 'reference bar',
- type: 'bar',
- silent: true,
- yAxisIndex: index,
- itemStyle: {
- color: new graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: colors[index % colors.length] },
- { offset: 0.2, color: colors[index % colors.length] },
- { offset: 1, color: `${colors[index % colors.length]}22` },
- ]),
- },
- tooltip: { show: false },
- barWidth: 8,
- data,
- });
- return curr;
- }, []),
- };
- }
- // 折线图和上面的柱状图类似
- if (type === 'line') {
- return {
- legend: {
- top: 10,
- right: 10,
- textStyle: {
- color: '#fff',
- },
- },
- // backgroundColor: '#081f33',
- textStyle: {
- color: '#fff',
- },
- grid: {
- left: 60,
- top: 50,
- right: 60,
- bottom: 50,
- },
- xAxis: xAxis.map((e) => {
- return {
- type: 'category',
- data: sorttedData.map((d) => {
- return getFormattedText(d, e.label);
- }),
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- name: e.label,
- position: e.align,
- splitLine: {
- lineStyle: {
- color: '#fff',
- opacity: 0.3,
- },
- },
- };
- }),
- series: series.map((serie) => {
- const data = sorttedData.map((d) => {
- return {
- name: serie.label,
- value: get(d, serie.prop, 0),
- };
- });
- return {
- type: 'line',
- data,
- };
- }),
- };
- }
- // 折线图和上面的柱状图类似
- if (type === 'line_smooth') {
- return {
- legend: {
- top: 10,
- right: 10,
- textStyle: {
- color: '#fff',
- },
- },
- // backgroundColor: '#081f33',
- textStyle: {
- color: '#fff',
- },
- grid: {
- left: 50,
- top: 50,
- right: 50,
- bottom: 50,
- },
- xAxis: xAxis.map((e) => {
- return {
- type: 'category',
- data: sorttedData.map((d) => {
- return getFormattedText(d, e.label);
- }),
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- name: e.label,
- position: e.align,
- splitLine: {
- lineStyle: {
- opacity: 0.3,
- },
- },
- };
- }),
- series: series.map((serie) => {
- const data = sorttedData.map((d) => {
- return {
- name: serie.label,
- value: get(d, serie.prop, 0),
- };
- });
- return {
- type: 'line',
- data,
- smooth: true,
- };
- }),
- };
- }
- // 折线图和上面的柱状图类似
- if (type === 'line_area') {
- return {
- legend: {
- show: false,
- },
- // backgroundColor: '#081f33',
- textStyle: {
- color: '#fff',
- },
- grid: {
- left: 50,
- top: 50,
- right: 50,
- bottom: 50,
- },
- xAxis: xAxis.map((e) => {
- return {
- type: 'category',
- boundaryGap: false,
- data: sorttedData.map((d) => {
- return getFormattedText(d, e.label);
- }),
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- name: e.label,
- position: e.align,
- splitLine: {
- lineStyle: {
- color: '#fff',
- opacity: 0.3,
- },
- },
- };
- }),
- series: series.map((serie, index) => {
- const colors = ['#66ffff', '#6666ff'];
- const data = sorttedData.map((d) => {
- return {
- name: serie.label,
- value: get(d, serie.prop, 0),
- };
- });
- return {
- type: 'line',
- data,
- symbol: 'none',
- endLabel: { distance: 0 },
- // itemStyle: { show: false, opacity: 0 },
- lineStyle: { color: colors[index % colors.length] },
- areaStyle: {
- origin: 'auto',
- color: new graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: colors[index % colors.length] },
- { offset: 0.2, color: colors[index % colors.length] },
- { offset: 1, color: `${colors[index % colors.length]}22` },
- ]),
- },
- };
- }),
- };
- }
- if (type === 'line_bar') {
- return {
- legend: {
- top: 10,
- right: 10,
- textStyle: {
- color: '#fff',
- },
- },
- // backgroundColor: '#081f33',
- textStyle: {
- color: '#fff',
- },
- grid: {
- left: 40,
- top: 50,
- right: 40,
- bottom: 10,
- show: false,
- },
- xAxis: xAxis.map(() => {
- return {
- type: 'category',
- show: false,
- };
- }),
- yAxis: yAxis.map(() => {
- return {
- show: false,
- // name: e.label,
- // position: e.align,
- };
- }),
- series: series.map((serie, i) => {
- const data = sorttedData.map((d) => {
- return {
- name: serie.label,
- value: get(d, serie.prop, 0),
- label: {
- show: true,
- position: 'top',
- borderWidth: 0,
- color: '#fff',
- },
- itemStyle: {
- color: new graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: '#66ffff' },
- { offset: 0.2, color: '#66ffff' },
- { offset: 1, color: '#66ffff22' },
- ]),
- },
- };
- });
- return {
- type: i % 2 ? 'line' : 'bar',
- smooth: true,
- data,
- barWidth: 20,
- };
- }),
- };
- }
- return {};
- };
- watch(
- () => props.chartData,
- () => {
- initCharts();
- }
- );
- function initCharts() {
- const o = genChartOption();
- setOptions(o as EChartsOption, false);
- }
- </script>
|