/** * 将请求返回的图表展示数据解析为前台展示用的config */ import moment from 'moment'; import EllipsisTooltip from '../components/common/ellipsisTooltip/index'; import { deepAssign, numberFormat } from '../utils/baseUtils'; import STATISTICS_OPTION from '../components/chartDesigner/sections/statisticsOption.json'; import themes from '../components/chartDesigner/sections/style/theme/index'; import EChartsMedia from './EChartsMedia'; export default function(viewType, data, chartConfig, themeName, styleConfig) { if(!data) { return {}; } try { let t = themes.find(t => t.name === themeName); let theme = t ? t.config : themes[0].config; let o, themeConfig; switch(viewType) { case 'bar': { themeConfig = deepAssign({}, theme.base, theme.bar, theme.xAxis, theme.yAxis, theme.dataZoom); o = barOption(data, chartConfig, themeConfig, styleConfig); break; } case 'pie': { themeConfig = deepAssign({}, theme.base, theme.pie); o = pieOption(data, chartConfig, themeConfig, styleConfig); break; } case 'line': { themeConfig = deepAssign({}, theme.base, theme.line, theme.xAxis, theme.yAxis, theme.dataZoom); o = lineOption(data, chartConfig, themeConfig, styleConfig); break; } case 'scatter': { themeConfig = deepAssign({}, theme.base, theme.scatter, theme.xAxis, theme.yAxis, theme.dataZoom); o = scatterOption(data, chartConfig, themeConfig, styleConfig); break; } case 'aggregateTable': { themeConfig = deepAssign({}, theme.base, theme.aggregateTable); o = aggregateTableOption(data, chartConfig, themeConfig, styleConfig); break; }case 'dataView' : { themeConfig = deepAssign({}, theme.base, theme.dataView); o = dataViewOption(data, chartConfig, themeConfig, styleConfig); break; } case 'indicator': themeConfig = deepAssign({}, theme.base, theme.indicator); o = indicatorOption(data, chartConfig, themeConfig, styleConfig); break; default:{ o = {}; break; } } return o; }catch(e) { console.error(e); } } function barOption(data, barConfig, themeConfig, styleConfig) { const { xAxis, yAxis, groupBy } = barConfig; const { barMaxWidth, barMinHeight, barGap, stack, labelVisible, labelPosition, labelDistance, labelRotate, xNameLocation, xNameGap, xNameRotate, xLabelHiddenCover, xLabelRotate, dataZoomVisible, xLabelMargin, yNameLocation, yNameGap, yNameRotate, labelZeroVisible } = styleConfig; let xTitle = xAxis?`${xAxis.column.label}`:null let yTitle = yAxis?`${yAxis.column.label}`:null let hasGroupBy = !!groupBy && !!groupBy.key; let legendVisible = hasGroupBy; data.serieses = data.serieses || []; let option = deepAssign({ originConfig: { ...barConfig }, tooltip : { trigger: "axis", axisPointer: { type: "cross" } }, legend: { show: legendVisible }, xAxis: [{ type: 'category', nameLocation: (xNameLocation === '' || xNameLocation === null || xNameLocation === undefined) ? 'end' : xNameLocation, nameGap: (xNameGap === '' || xNameGap === null || xNameGap === undefined) ? 15 : Number(xNameGap), nameRotate: (xNameRotate === '' || xNameRotate === null || xNameRotate === undefined) ? 0 : Number(xNameRotate), axisLabel: { interval: xLabelHiddenCover === undefined ? 'auto' : (!!xLabelHiddenCover ? 'auto' : 0), rotate: (xLabelRotate === '' || xLabelRotate === null || xLabelRotate === undefined) ? 0 : Number(xLabelRotate), margin: (xLabelMargin === '' || xLabelMargin === null || xLabelMargin === undefined) ? 8 : Number(xLabelMargin), }, data: data.xAxis.map(d => { let gv= xAxis.granularity.value; if(!d) { return '空'; } let xv = d; if(gv === 'halfYear') { let arr = d.split('-H'); xv = `${arr[0] || '-'} ${['上半年', '下半年'][arr[1] - 1]}`; }else if(gv === 'month') { let arr = d.split('-'); xv = `${arr[0] || '-'}/${arr[1]}`; }else if(gv === 'quarter') { let arr = d.split('-'); xv = `${arr[0] || '-'} ${['一', '二', '三', '四'][arr[1] - 1] + '季度'}`; }else if(gv === 'week') { let arr = d.split('-'); xv = (arr[0] || '-') + ' ' + arr[1] + '周' } return xv; }), name: xTitle || '横轴', }], yAxis: [{ name: yTitle || '纵轴', type: 'value', nameLocation: (yNameLocation === '' || yNameLocation === null || yNameLocation === undefined) ? 'end' : yNameLocation, nameGap: (yNameGap === '' || yNameGap === null || yNameGap === undefined) ? 15 : Number(yNameGap), nameRotate: (yNameRotate === '' || yNameRotate === null || yNameRotate === undefined) ? 0 : Number(yNameRotate), }], series: data.serieses.map(s => { return { name: !!groupBy && !!groupBy.key ? s.name : yAxis.column.label, type: 'bar', data: s.value.map(v => numberFormat(v)), barMaxWidth: barMaxWidth || 60, barMinHeight: barMinHeight || 0, barGap: barGap || '30%', stack: !!groupBy && !!groupBy.key && !!stack, label: { normal: { show: !!labelVisible, position: labelPosition || 'inside', distance: (labelDistance === '' || labelDistance === null || labelDistance === undefined) ? 5 : Number(labelDistance), rotate: (labelRotate === '' || labelRotate === null || labelRotate === undefined) ? 0 : Number(labelRotate), formatter: !labelZeroVisible ? (params) => { const { value } = params; return Number(value) === 0 ? '' : value; } : '{c}' } } } }), dataZoom: { show: !!dataZoomVisible } }, themeConfig); let mediaOption = { baseOption: option, media: EChartsMedia('bar', legendVisible, dataZoomVisible, { legend: option.legend }) } return mediaOption; } function lineOption(data, lineConfig, themeConfig, styleConfig) { const { labelSymbol, xNameLocation, xNameGap, xNameRotate, xLabelRotate, xLabelMargin, xLabelHiddenCover, yNameLocation, yNameGap, yNameRotate, stack, labelVisible, labelPosition, labelDistance, labelRotate, lineSmooth, labelSymbolSize, dataZoomVisible } = styleConfig; const { xAxis, yAxis, groupBy } = lineConfig; let xTitle = xAxis?`${xAxis.column.label}`:null let yTitle = yAxis?`${yAxis.column.label}`:null let hasGroupBy = !!groupBy && !!groupBy.key; let legendVisible = hasGroupBy; data.serieses = data.serieses || []; let option = deepAssign({ originConfig: { ...lineConfig }, tooltip : { trigger: "axis", axisPointer: { type: "cross" } }, legend: { show: legendVisible }, xAxis: [{ name: xTitle || '横轴', type: 'category', nameLocation: (xNameLocation === '' || xNameLocation === null || xNameLocation === undefined) ? 'end' : xNameLocation, nameGap: (xNameGap === '' || xNameGap === null || xNameGap === undefined) ? 15 : Number(xNameGap), nameRotate: (xNameRotate === '' || xNameRotate === null || xNameRotate === undefined) ? 0 : Number(xNameRotate), axisLabel: { interval: xLabelHiddenCover === undefined ? 'auto' : (!!xLabelHiddenCover ? 'auto' : 0), rotate: (xLabelRotate === '' || xLabelRotate === null || xLabelRotate === undefined) ? 0 : Number(xLabelRotate), margin: (xLabelMargin === '' || xLabelMargin === null || xLabelMargin === undefined) ? 8 : Number(xLabelMargin), }, data: data.xAxis.map(d => { let gv= xAxis.granularity.value; if(!d) { return '空'; } let xv = d; if(gv === 'halfYear') { let arr = d.split('-H'); xv = `${arr[0] || '-'} ${['上半年', '下半年'][arr[1] - 1]}`; }else if(gv === 'month') { let arr = d.split('-'); xv = `${arr[0] || '-'}/${arr[1]}`; }else if(gv === 'quarter') { let arr = d.split('-'); xv = `${arr[0] || '-'} ${['一', '二', '三', '四'][arr[1] - 1] + '季度'}`; }else if(gv === 'week') { let arr = d.split('-'); xv = (arr[0] || '-') + ' ' + arr[1] + '周' } return xv; }), }], yAxis: [{ name: yTitle || '纵轴', type: 'value', nameLocation: (yNameLocation === '' || yNameLocation === null || yNameLocation === undefined) ? 'end' : yNameLocation, nameGap: (yNameGap === '' || yNameGap === null || yNameGap === undefined) ? 15 : Number(yNameGap), nameRotate: (yNameRotate === '' || yNameRotate === null || yNameRotate === undefined) ? 0 : Number(yNameRotate), }], series: data.serieses.map(s => { return { name: !!groupBy && !!groupBy.key ? s.name : yAxis.column.label, type: 'line', data: s.value.map(v => numberFormat(v)), stack: !!groupBy && !!groupBy.key && !!stack, label: { normal: { show: !!labelVisible, position: labelPosition || 'inside', distance: (labelDistance === '' || labelDistance === null || labelDistance === undefined) ? 5 : Number(labelDistance), rotate: (labelRotate === '' || labelRotate === null || labelRotate === undefined) ? 0 : Number(labelRotate), formatter: '{c}' } }, symbol: !labelSymbol ? 'emptyCircle' : labelSymbol, symbolSize: (labelSymbolSize === '' || labelSymbolSize === null || labelSymbolSize === undefined) ? 4 : Number(labelSymbolSize), smooth: !!lineSmooth, } }), dataZoom: { show: !!dataZoomVisible } }, themeConfig); let mediaOption = { baseOption: option, media: EChartsMedia('line', legendVisible, dataZoomVisible, { legend: option.legend }) } return mediaOption; } function pieOption(data, pieConfig, themeConfig, styleConfig) { let { labelHidden } = styleConfig; let { xAxis, yAxis } = pieConfig; let columnName = xAxis.column.label; let dataList = (data.serieses || [{ value: [] }])[0].value; let option = deepAssign({ originConfig: { ...pieConfig }, tooltip : { trigger: 'item', formatter: function(params) { let { seriesName, name, value, percent } = params; return `${seriesName}:    ${name}
${yAxis.column.label}:  ${value} (${percent}%)`; } }, grid: { left: 50, right: 50, top: 50, bottom: 50, containLabel: true }, series : [{ name: columnName, type: 'pie', radius: [0, '65%'], center: ['50%', '50%'], label: { normal: { show: labelHidden === undefined ? true : !labelHidden, }, emphasis: { show: true, } }, labelLine: { normal: { show: labelHidden === undefined ? true : !labelHidden, }, emphasis: { show: true, } }, avoidLabelOverlap: labelHidden === undefined ? true : !labelHidden, data: dataList.map(v => { let obj = { ...v }; obj.value = numberFormat(obj.value) if(!v.name) { obj.name = '空' }else { let gv= pieConfig.xAxis.granularity.value; if(gv === 'halfYear') { let arr = v.name.split('-H'); obj.name = `${arr[0] || '-'} ${['上半年', '下半年'][arr[1] - 1]}`; }else if(gv === 'month') { let arr = v.name.split('-'); obj.name = `${arr[0] || '-'}/${arr[1]}`; }else if(gv === 'quarter') { let arr = v.name.split('-'); obj.name = `${arr[0] || '-'} ${['一', '二', '三', '四'][arr[1] - 1] + '季度'}`; }else if(gv === 'week') { let arr = v.name.split('-'); obj.name = (arr[0] || '-') + ' ' + arr[1] + '周' } } return obj; }) }] }, themeConfig); let mediaOption = { baseOption: option, media: EChartsMedia('pie', true, false, { legend: option.legend }) } return mediaOption; } function scatterOption(data, scatterConfig, themeConfig, styleConfig) { const { labelSymbol, xNameLocation, xNameGap, xNameRotate, yNameLocation, yNameGap, yNameRotate, labelSymbolSize, dataZoomVisible } = styleConfig; const { xAxis, yAxis, groupBy } = scatterConfig; let xTitle = xAxis?`${xAxis.column.label}`:null let yTitle = yAxis?`${yAxis.column.label}`:null; let hasGroupBy = !!groupBy && !!groupBy.key; let legendVisible = hasGroupBy; let option = deepAssign({ originConfig: { ...scatterConfig }, tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } }, legend: { show: legendVisible }, xAxis : [{ type : 'value', name: xTitle || '横轴', nameLocation: (xNameLocation === '' || xNameLocation === null || xNameLocation === undefined) ? 'end' : xNameLocation, nameGap: (xNameGap === '' || xNameGap === null || xNameGap === undefined) ? 15 : Number(xNameGap), nameRotate: (xNameRotate === '' || xNameRotate === null || xNameRotate === undefined) ? 0 : Number(xNameRotate), scale:true, splitLine: { show: true } }], yAxis : [{ type : 'value', name: yTitle || '纵轴', nameLocation: (yNameLocation === '' || yNameLocation === null || yNameLocation === undefined) ? 'end' : yNameLocation, nameGap: (yNameGap === '' || yNameGap === null || yNameGap === undefined) ? 15 : Number(yNameGap), nameRotate: (yNameRotate === '' || yNameRotate === null || yNameRotate === undefined) ? 0 : Number(yNameRotate), scale:true, splitLine: { show: true }, }], series : (data.serieses || []).map(s => { return { name: s.name, type: 'scatter', symbol: !labelSymbol ? 'circle' : labelSymbol, symbolSize: (labelSymbolSize === '' || labelSymbolSize === null || labelSymbolSize === undefined) ? 10 : Number(labelSymbolSize), data: s.mdata.map(m => { return [m.date, numberFormat(m.value)] }) } }), dataZoom: { show: !!dataZoomVisible } }, themeConfig); let mediaOption = { baseOption: option, media: EChartsMedia('scatter', legendVisible, dataZoomVisible, { legend: option.legend }) } return mediaOption; } function aggregateTableOption( data, aggregateTableConfig, themeConfig, styleConfig) { const { targetColumn, groupBy, statistics: statisticsNames } = aggregateTableConfig; const { direction } = styleConfig; let statistics = statisticsNames.map(s => { if(!s.name) { let f = STATISTICS_OPTION.find(o => o.value === s); return !!f ? { name: f.value, label: f.label } : null; } return s }).filter(s => !!s), group1Name = groupBy.length > 0 ? groupBy[0].key : null, group2Name = groupBy.length > 1 ? groupBy[1].key : null, group1s = [], group2s = [], tableData; const resData = data.valueList; if(!group1Name) { // 无分组 let o = {}; statistics.forEach(s => { o[s.name] = numberFormat(resData[s.name]) }); tableData = o; }else { if(!group2Name) { // 只有一个分组 resData.forEach(d => { let v = d[group1Name]; if(group1s.indexOf(v) === -1) { group1s.push(v); } }); tableData = resData.map(d => { let o = {}; statistics.forEach(s => { o[s.name] = numberFormat(d[s.name]) }); return o; }); }else { // 有两个分组 resData.forEach(d => { let v1 = d[group1Name]; let v2 = d[group2Name]; if(group1s.indexOf(v1) === -1) { group1s.push(v1); } if(group2s.indexOf(v2) === -1) { group2s.push(v2); } }); tableData = group1s.map(g => { let obj = {}, list = resData.filter(d => d[group1Name] === g) // .slice(0, 5); obj[group1Name] = g; obj['data'] = group2s.map(g => { let o = {}; o[group2Name] = g; statistics.forEach(s => { let v = list.find(l => l[group2Name] === g); o[s.name] = v ? (typeof v[s.name] === 'number' ? numberFormat(v[s.name]) : '') : ''; }); return o; }); return obj; }); } } let option = { originConfig: { ...aggregateTableConfig }, themeConfig, targetColumn, direction: direction || 'horizontal', group1Name: groupBy.length > 0 ? groupBy[0].key : null, group2Name: groupBy.length > 1 ? groupBy[1].key : null, group1s, group2s, statistics, data: tableData }; console.log(option); return option; } function dataViewOption(data, dataViewConfig, themeConfig, styleConfig) { const { list, pageNum, pageSize, pages, total } = data.valueList; let { viewColumns } = dataViewConfig; let columns = viewColumns || []; let dataSource = list || []; let option = { originConfig: { ...dataViewConfig }, themeConfig, columns: columns.map(c => { let obj = { title: c.label, dataIndex: c.name, } if(c.type === 'time') { obj.render = (v, r, i) => { let text = v === null ? '空' : moment(v).isValid() ? moment(v).format('YYYY-MM-DD') : v return {text} } }else { obj.render = v => { let text = v === null ? '空' : v return {text} } } return obj; }), dataSource: dataSource.map((d, i) => { return { ...d, key: i} }), page: pageNum, pageSize, pages, total, }; return option; } function indicatorOption(data, indicatorConfig, themeConfig, styleConfig) { const { xAxis, yAxis, otherColumn } = indicatorConfig; let option = { originConfig: { ...indicatorConfig }, themeConfig, data: (data.serieses || []).map(d => ({ name: xAxis.column.value ? (xAxis.column.type === 'time' ? (moment(d.name).isValid() ? moment(d.name).format('YYYY-MM-DD') : d.name) : d.name) : undefined, key: `${yAxis.column.label}(${yAxis.gauge.label})`, value: d.value, others: otherColumn.map(c => ({ name: c.label, value: c.type === 'time' ? (moment(d[c.value]).isValid() ? moment(d[c.value]).format('YYYY-MM-DD') : d[c.value]) : d[c.value] })) })) }; return option; }