123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- <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 { ModuleDataChart } from '/@/views/vent/deviceManager/configurationTable/types';
- import { EChartsOption, graphic } from 'echarts';
- import { getData, getFormattedText } from '../../hooks/helper';
- const props = withDefaults(
- defineProps<{
- chartData: Record<string, any>[] | Record<string, any>;
- chartConfig: ModuleDataChart;
- 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 = [], legend, order, type, sortBy, series } = props.chartConfig;
- const textStyle = {
- color: '#fff',
- };
- let sorttedData: any[] = [];
- if (Array.isArray(props.chartData)) {
- sorttedData = props.chartData;
- } else {
- sorttedData = [props.chartData];
- }
- // 如果这个配置指明了需要排序则执行排序
- 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);
- }
- });
- }
- // 该项作为下面所有图表依赖的基准系列数据
- const baseSeries: { name: string; data: [string, string][] }[] = sorttedData.reduce((res: any[], baseData) => {
- series.forEach((serie) => {
- res.push({
- name: getFormattedText(baseData, serie.label),
- data: (getData(baseData, serie.readFrom) || []).map((data) => {
- return [getData(data, serie.xprop), getData(data, serie.yprop)]; /** x y */
- // return { name: getData(data, serie.xprop), value: getData(data, serie.yprop) }; /** x y */
- }),
- });
- });
- return res;
- }, []);
- if (type === 'pie') {
- return {
- textStyle,
- legend: {
- textStyle,
- show: legend.show,
- },
- tooltip: {
- trigger: 'item',
- },
- color: ['#d9a1ff', '#00d1ff', '#82fe78'],
- series: baseSeries.map((serie) => {
- return {
- type: 'pie',
- radius: ['50%', '75%'],
- center: ['50%', '55%'],
- labelLine: { show: false },
- label: { show: false },
- itemStyle: {
- shadowBlur: 20,
- shadowColor: '#259bcf',
- },
- data: serie.data.map((e) => ({
- name: e[0],
- value: e[1],
- })),
- };
- }),
- };
- }
- // 柱状图
- if (type === 'bar') {
- return {
- textStyle,
- grid: {
- top: 50,
- bottom: 50,
- },
- legend: {
- textStyle,
- show: legend.show,
- },
- tooltip: {
- trigger: 'item',
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- axisLabel: {
- interval: 0,
- width: 800 / get(baseSeries, '[0].data.length', 1),
- overflow: 'break',
- },
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- splitLine: {
- lineStyle: {
- opacity: 0.1,
- },
- },
- };
- }),
- series: baseSeries.reduce((curr: EChartsOption[], serie, index) => {
- const colors = ['#66ffff', '#ffff66'];
- if (baseSeries.length === 1) {
- curr.push({
- ...serie,
- type: 'pictorialBar',
- symbol: 'circle',
- symbolPosition: 'end',
- symbolSize: [20, 20],
- symbolOffset: [0, -10],
- barGap: '-100%',
- yAxisIndex: index,
- itemStyle: {
- color: colors[index % colors.length],
- },
- });
- }
- curr.push({
- ...serie,
- type: 'bar',
- silent: true,
- yAxisIndex: index,
- barWidth: 10,
- barGap: '100%',
- 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` },
- ]),
- borderRadius: [5, 5, 0, 0],
- },
- });
- return curr;
- }, []),
- };
- }
- // 折线图和上面的柱状图类似
- if (type === 'line') {
- return {
- textStyle,
- legend: {
- show: legend.show,
- top: 10,
- right: 10,
- textStyle,
- },
- grid: {
- left: 60,
- top: 40,
- right: 60,
- bottom: 30,
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- axisLabel: {
- width: 100,
- overflow: 'break',
- },
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- splitLine: {
- lineStyle: {
- opacity: 0.1,
- },
- },
- };
- }),
- series: baseSeries.map((serie) => {
- return {
- ...serie,
- type: 'line',
- };
- }),
- };
- }
- // 平滑曲线图
- if (type === 'line_smooth') {
- return {
- textStyle,
- legend: {
- show: legend.show,
- top: 10,
- textStyle,
- },
- grid: {
- left: 60,
- right: 60,
- bottom: 30,
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- splitLine: {
- lineStyle: {
- opacity: 0.1,
- },
- },
- };
- }),
- series: baseSeries.map((serie) => {
- return {
- ...serie,
- type: 'line',
- smooth: true,
- itemStyle: {
- opacity: 0,
- },
- };
- }),
- };
- }
- // 折线区域图,即折线下面的区域填满
- if (type === 'line_area') {
- return {
- textStyle,
- legend: {
- textStyle,
- show: legend.show,
- },
- grid: {
- left: 50,
- top: 50,
- right: 50,
- bottom: 50,
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- boundaryGap: false,
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- splitLine: {
- lineStyle: {
- color: '#fff',
- opacity: 0.1,
- },
- },
- };
- }),
- series: baseSeries.map((serie, index) => {
- const colors = ['#66ffff', '#6666ff'];
- return {
- ...serie,
- type: 'line',
- symbol: 'none',
- endLabel: { distance: 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 {
- textStyle,
- legend: {
- textStyle,
- show: legend.show,
- top: 10,
- right: 10,
- },
- grid: {
- left: 40,
- top: 50,
- right: 40,
- bottom: 10,
- show: false,
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- };
- }),
- series: baseSeries.map((serie, i) => {
- return {
- ...serie,
- type: i % 2 ? 'line' : 'bar',
- smooth: true,
- barWidth: 20,
- };
- }),
- };
- }
- // 堆叠柱状图
- if (type === 'bar_stack') {
- return {
- textStyle,
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow',
- },
- },
- grid: {
- top: 50,
- bottom: 30,
- },
- legend: {
- textStyle,
- show: legend.show,
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- splitLine: {
- lineStyle: {
- color: 'rgba(21,80,126,0.3)',
- type: 'dashed',
- },
- },
- };
- }),
- series: baseSeries.map((serie) => {
- return {
- ...serie,
- type: 'bar',
- stack: 'stackME',
- barMaxWidth: '24',
- emphasis: {
- focus: 'series',
- },
- label: {
- show: true,
- position: 'top', //在上方显示
- textStyle: {
- //数值样式
- color: '#fff',
- fontSize: 14,
- },
- },
- };
- }),
- color: ['#F56731', '#00E8FF'],
- };
- }
- // 柱状图,圆柱形样式
- if (type === 'bar_cylinder') {
- return {
- textStyle,
- grid: {
- top: 40,
- bottom: 50,
- },
- legend: {
- textStyle,
- show: legend.show,
- },
- tooltip: {
- trigger: 'item',
- },
- xAxis: xAxis.map((e) => {
- return {
- ...e,
- type: 'category',
- axisLabel: {
- interval: 0,
- width: 800 / get(baseSeries, '[0].data.length', 1),
- overflow: 'break',
- },
- };
- }),
- yAxis: yAxis.map((e) => {
- return {
- ...e,
- splitLine: {
- lineStyle: {
- opacity: 0.1,
- },
- },
- };
- }),
- series: baseSeries.reduce((curr: EChartsOption[], serie, index) => {
- const colors = ['#66ffff', '#00ff66', '#ffff66'];
- if (baseSeries.length === 1) {
- curr.push({
- ...serie,
- type: 'pictorialBar',
- symbol: 'circle',
- symbolPosition: 'end',
- symbolSize: [20, 10],
- symbolOffset: [0, -5],
- barGap: '-100%',
- yAxisIndex: index,
- itemStyle: {
- color: ({ dataIndex }) => colors[dataIndex % colors.length],
- },
- });
- curr.push({
- ...serie,
- type: 'pictorialBar',
- symbol: 'circle',
- symbolPosition: 'start',
- symbolSize: [20, 10],
- symbolOffset: [0, 5],
- barGap: '-100%',
- yAxisIndex: index,
- itemStyle: {
- color: ({ dataIndex }) => colors[dataIndex % colors.length],
- },
- });
- }
- curr.push({
- ...serie,
- type: 'bar',
- silent: true,
- yAxisIndex: index,
- barWidth: 20,
- barGap: '100%',
- itemStyle: {
- color: ({ dataIndex }) =>
- new graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: `${colors[dataIndex % colors.length]}44` },
- { offset: 0.5, color: colors[dataIndex % colors.length] },
- { offset: 1, color: colors[dataIndex % colors.length] },
- ]),
- borderRadius: [5, 5, 0, 0],
- },
- });
- return curr;
- }, []),
- };
- }
- return {};
- };
- watch(
- () => props.chartData,
- () => {
- initCharts();
- },
- {
- immediate: true,
- }
- );
- function initCharts() {
- const o = genChartOption();
- setOptions(o as EChartsOption, false);
- }
- </script>
|