通过构造echarts返回体EchartsData.class
,在返回体内开发功能代码,实现echarts数据的改动。
特点:
1、y轴数据的数量级自动调整,使图表变化趋势更明显;
2、支持多维度数据【可以有1-N多个维度】
// EchartsData对象构造样例代码
List<String> xAxis = Arrays.asList("鲤鱼","草鱼","三文鱼","鳕鱼","龙利鱼","鲫鱼");
List<Object> barList = Arrays.asList("12345","2345","3456","4567","67891","7891");final EchartsData echartsData = new EchartsData("新增情况图表", xAxis).setFirstYAxis("总数", barList);
echartsData.setLineYAxis(“利用率(%)”, line1List);
// echartsData.setLineYAxis(“利用率_2”, line2List);
// ...
// echartsData.setLineYAxis(“利用率_N”, lineNList);
xxx
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.Getter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;/*** echarts 表格数据结构体*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter // 规定了“不同图标类型的y坐标值”与y坐标系维度列表的对应关系,故不允许随意set
public class EchartsData extends HashMap<String, Object> {/*** 标题*/private final String title;/*** 横坐标值*/private final List<String> xAxis;/*** 多维纵坐标的维度名称列表* 按索引号,分别对应坐标值:barList、line1List、line2List* 若对应的坐标值列表List为空,则表示无数据*/private List<String> yAxisDimensionNameList;/*** 柱状图-纵坐标值* 元素可能为简单数据类型,* 也可能为DataWithItemStyleVO.class类型,用于标识该值的显示样式*/private List<Object> barList; // 柱状图
// private List<String> line{0}List; // 折线图public EchartsData(String title, List<String> xAxis) {this.title = title;this.xAxis = xAxis;this.yAxisDimensionNameList = new ArrayList<>();// map对象,使用MapSerializer解析时,不会序列自身的属性put("title", this.title);put("xAxis", this.xAxis);put("yAxisDimensionNameList", this.yAxisDimensionNameList);}public EchartsData setFirstYAxis(String dimension, List<?> barList) {ParamException.isTrue(StringUtils.isBlank(dimension), "inputParam[dimension] should not be blank");if (CollectionUtils.isEmpty(barList)) {return this;}YAxis yAxis = balanceNum(dimension, barList);yAxisDimensionNameList.add(yAxis.getDimension());this.barList = yAxis.getDataList();put("barList", this.barList);return this;}public EchartsData setLineYAxis(String dimension, List<String> lineList) {ParamException.isTrue(StringUtils.isBlank(dimension), "inputParam[dimension] should not be blank");if (CollectionUtils.isEmpty(lineList)) {return this;}YAxis yAxis = balanceNum(dimension, lineList); // 不指定索引号add,避免覆盖原有元素yAxisDimensionNameList.add(yAxis.getDimension());int index = yAxisDimensionNameList.size() - 1;final String key = MessageFormat.format("line{0}List", index);put(key, yAxis.getDataList());return this;}private YAxis balanceNum(String sourceDimension, List<?> sourceList) {List<Object> targetList;String targetDimension;List<BigDecimal> tempNumList = new ArrayList<>();sourceList.forEach(data -> {String value;if (data instanceof DataWithItemStyleVO) {value = ((DataWithItemStyleVO) data).getValue();} else {value = String.valueOf(data);}// 非数字会报错final BigDecimal dNum = NumberUtil.parseStrToBigDecimal(value);tempNumList.add(dNum);});tempNumList.sort(BigDecimal::compareTo);final BigDecimal min = tempNumList.get(0);final int minLength = String.valueOf(min.intValue()).length();final BigDecimal max = tempNumList.get(tempNumList.size() - 1);final int maxLength = String.valueOf(max.intValue()).length();// 是否进行数值大小转换if (!sourceDimension.contains("率") // 为了避免调整百分数,双保险(部分字段的百分数值,没有带百分号。若数值本身的带百分号的minLength=1不会转换)。若是转化,单位会很奇怪,又是百分号、又是数量单位。&& maxLength >= minLength// 不可自动调整的数据如(为了避免调整百分数):88 vs 10; 987 vs 10; 101 vs 99&& (minLength > 2 || (minLength > 1 && (maxLength - minLength) > 1)) // 如:880 vs 100; 8800 vs 10) {targetList = new ArrayList<>();// 将最小值,处理成个位数。缩短无用y轴刻度,使y轴数值差异明显化// 若存在负数、小数:存在小数-因为整数位数为0故不会进行转化;存在负数-要求最小值即负数的位数比正数最大值位数短即可(否则转换后正数会小于0不符合所有值绝对值都大于零的预期)。int powerOfTen = minLength - 1;BigDecimal divisor = BigDecimal.valueOf(10).pow(powerOfTen); // 10的n次方。使得最小值为个位数for (int i = 0; i < sourceList.size(); i++) { // 不打乱原排序Object data = sourceList.get(i);DataWithItemStyleVO dataWithItemStyleVO = null;String value;if (data instanceof DataWithItemStyleVO) {dataWithItemStyleVO = (DataWithItemStyleVO) data;value = dataWithItemStyleVO.getValue();} else {value = String.valueOf(data);}final BigDecimal dNum = NumberUtil.parseStrToBigDecimal(value);final BigDecimal divide = dNum.divide(divisor);if (Objects.isNull(dataWithItemStyleVO)) {targetList.add(divide.toString());} else {targetList.add(new DataWithItemStyleVO(divide.toString(), dataWithItemStyleVO.getItemStyle()));}}// 追加转换后的单位NumCountUnitEnum unitEnum = NumCountUnitEnum.valueOf(powerOfTen);targetDimension = MessageFormat.format("{0}({1})", sourceDimension, unitEnum.getCountUnitName()); // 中文括号前端无法识别} else {// 数值小于1000,不做处理targetList = sourceList.stream().map(data -> (Object) data).collect(Collectors.toList());targetDimension = sourceDimension;}YAxis yaxis = new YAxis();yaxis.setDataList(targetList);yaxis.setDimension(targetDimension);return yaxis;}enum NumCountUnitEnum {ONE(0, "个"),TWO(1, "十"),THREE(2, "百"),FOUR(3, "千"),FIVE(4, "万"),SIX(5, "十万"),SEVEN(6, "百万"),EIGHT(7, "千万"),NINE(8, "亿"),;/*** 10的幂次*/private Integer powerOfTen;/*** 计数单位中文名*/private String countUnitName;NumCountUnitEnum(Integer powerOfTen, String countUnitName) {this.powerOfTen = powerOfTen;this.countUnitName = countUnitName;}public static NumCountUnitEnum valueOf(Integer powerOfTen) {ParamException.isTrue(Objects.isNull(powerOfTen), "invalid null powerOfTen");for (NumCountUnitEnum elem : values()) {if (powerOfTen.equals(elem.powerOfTen)) {return elem;}}throw new ParamException(String.format("invalid powerOfTen: [%s]", powerOfTen));}public Integer getPowerOfTen() {return powerOfTen;}public String getCountUnitName() {return countUnitName;}}@Dataclass YAxis {private String dimension;private List<Object> dataList;}
}