/**
* 将请求返回的图表展示数据解析为前台展示用的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;
}