echarts散点图数据相差巨大的解决方案

发布时间 2023-11-03 15:14:28作者: 嘘嘘乖乖

1 这几天收到了一个新的需求,就是数据差距太大,导致页面很丑,让我优化一下,下面上图:

解决方案一:

将yAxis和xAxis的type设置为log,这个方式可以很好的解决这个问题,但是有一个前提就是你的数据不能为负数,如果为负数,则数据渲染会出错。那我们的y轴数据中假设就有负数咋办?那我们就用第二种方式解决。

解决方式二:

1、设置x轴 y轴间隔(这个间隔是初始间隔,你可以根据业务需求修改)

let InitialDataInterval = [0, 2, 5, 10, 50, 100, 200]//初始间隔X轴
let InitialDataIntervalY = [0, 5, 10, 15, 40, 80, 100]//初始间隔Y轴

2、根据原始数据修改上面的X轴和Y轴间隔

        因为你的X轴和Y轴数据可能不在上面设置的初始化间隔内,所以可以稍微修改一下X轴和Y轴间隔数据

   

//模拟数据
let swyl_data= [
        [16.91, 33.5],
        [3.06,6.23],
        [3.06,6.23],
        [862.79,12.22],
        [402.1,8.81],
        [59.83,6.32], 
        ]
    let  jcdl_data= [
          [2.74,5.1],
          [1.05,9.36],
          [97.30,18.0],
          [402.57,4.2],
          [0.770,13.8],
          [67.90,5.8],
        ]
    let rgzn_data = [
          [2.29,14.66],
          [392.19,0.61],
          [4.30,9.3],
          [ 6.920000,3.3] 
        ]
//----开始初始化间隔X---- InitialDataInterval  因为你的X轴数据可能不在上面设置的初始化间隔内
  let initData = getInitData(jcdl_data, rgzn_data, swyl_data, 0);
  let initDataY = getInitData(jcdl_data, rgzn_data, swyl_data, 1);
  function getInitData(arr1, arr2, arr3, index) {
    let arr = arr1
      .map((item) => item[index])
      .concat(arr2.map((item) => item[index]))
      .concat(arr3.map((item) => item[index]));
    return arr;
  }
  const dataInterval = parseInterval(initData, InitialDataInterval, 0);//X轴
  const dataIntervalY = parseInterval(initDataY, InitialDataIntervalY, 1); //Y轴
  function parseInterval(initData, myInterval, index) {
    const dataIntervals = [...myInterval];
    // 完善y轴的间隔
    let max_i = Math.max(...dataIntervals);
    let min_i = Math.min(...dataIntervals);
    let maxData = Math.max(...initData);
    let minData = Math.min(...initData);
    if (maxData > max_i) {
      dataIntervals.push(parseIntervalNum(maxData));
    }
    if (minData < min_i) {
      dataIntervals.unshift(parseIntervalNum(minData));
    }
    return dataIntervals;
  }
  function getPNum(num) {
    num = num.toString();
    let firstNumber = num.substr(0, 1);
    let endNumber = num.substr(1);
    return `${parseInt(firstNumber) + 1}${"0".repeat(endNumber.length)}`;
  }
  function parseIntervalNum(num) {
    // 记录前缀,主要为负数提供服务
    let prefix = "";
    if (num < 0) {
      prefix = "-";
    }
    // 将num转为正整数
    num = Math.abs(parseInt(num));
    let p_num = "";
    switch (num.toString().length) {
      case 1:
        p_num = 10;
        break;
      case 2:
        p_num = 100;
        break;
      case 3:
        p_num = 1000;
        break;
      case 4:
        p_num = 10000;
        break;
      case 5:
        p_num = getPNum(num);
        break;
      default:
        p_num = getPNum(num);
        break;
    }
    let finalNum = `${prefix}${p_num}`;
    return parseInt(finalNum);
  }
  // ----结束初始化间隔----

3、将原始数据做一些转换

let diff = Math.max(...initData) - Math.min(...initData) //以X轴数据为样本

// ---开始将原始数据做一些转换
  function echartsDataParse(data, mydataInterval, i, needParseY) {
    //needParseY 是否需要转换Y轴
      // 定义数据间隔 
    let echartsData = [];
    data.forEach((item, index) => {
      // 在数据间隔中查找小于当前项的最大值
      const min_v = Math.max(...mydataInterval.filter((v) => v <= item[0]));
      // 在数据间隔中查询大于当前项的最小值
      const max_v = Math.min(...mydataInterval.filter((v) => v > item[0]));
      // 寻找min_v所在下标
      const index_v = mydataInterval.findIndex((v) => v === min_v);
      // 计算该项在y轴上应该展示的位置
      let x_value = ((item[0] - min_v) / (max_v - min_v)) * 10 + index_v * 10;
      // 判断是否要Y轴转换
      if (needParseY) {
        const min_v_Y = Math.max(...dataIntervalY.filter((v) => v <= item[1]));
        // 在数据间隔中查询大于当前项的最小值
        const max_v_Y = Math.min(...dataIntervalY.filter((v) => v > item[1]));
        // 寻找min_v所在下标
        const index_v_Y = dataIntervalY.findIndex((v) => v === min_v_Y);
        // 计算该项在y轴上应该展示的位置
        let y_value =
          ((item[1] - min_v_Y) / (max_v_Y - min_v_Y)) * 10 + index_v_Y * 10;
        echartsData.push([x_value, y_value, item[0], item[1]]);
      } else {
        echartsData.push([x_value, item[1], item[0], item[1]]);
      }
    });
    return echartsData;
  }
  //  ----转换结束

 4、把转换后的数据挂到series上面

series: [
      {
        name: "商品1",
        type: "scatter",
        data:
          diff > 200? echartsDataParse(jcdl_data, dataInterval, 0, true): jcdl_data,
      },
      {
        name: "商品2",
        type: "scatter",
        data:
          diff > 200? echartsDataParse(swyl_data, dataInterval, 0, true): swyl_data,
      },
      {
        name: "商品3",
        type: "scatter",
        data:
          diff > 200? echartsDataParse(rgzn_data, dataInterval, 0, true): rgzn_data,
      },
    ]

5、修改xAxis和yAxis的axisLabel的formatter

xAxis: {
      type: "value",
      name: "",
      // type: "log", //使用对数
      // logBase: 10, // 底数
      // nameGap: 16,
      nameTextStyle: {
        color: "rgba(255, 255, 255, 0.4)",
        fontSize: 14,
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: "rgba(255, 255, 255, 0.6)",
          width: 0.3,
        },
      },
      axisLine: {
        lineStyle: {
          color: "rgba(255, 255, 255, 0.4)",
        },
      },
      axisTick: {
        show: false, //隐藏X轴刻度
      },
      axisLabel: {
        show: true,
        // formatter: "{value}",
        formatter: (v, i) => {
          if (diff > 200) {
            return axisLabelFormat(v, i, " ", dataInterval);
          }
          return `${v}`;
        },
        textStyle: {
          color: "rgba(255,255,255,0.6)", //X轴文字颜色
          fontSize: 14,
        },
        color: "rgba(255,255,255,0.6)",
      },
    },
    yAxis: {
      type: "value",
      name: "",
      nameLocation: "end",
      // nameGap: 20,
      nameTextStyle: {
        color: "rgba(255, 255, 255, 0.4)",
        fontSize: 16,
      },
      axisLine: {
        lineStyle: {
          color: "rgba(255, 255, 255, 0.6)",
        },
      },
      axisTick: {
        lineStyle: {
          color: "rgba(255, 255, 255, 0.4)",
        },
      },
      splitLine: {
        lineStyle: {
          color: "rgba(255, 255, 255, 0.6)",
          width: 0.3,
        },
      },
      axisLabel: {
        formatter: (v, i) => {
          if (diff > 200) {
            return axisLabelFormat(v, i, "%", dataIntervalY);
          }
          return `${v}`;
        },
        textStyle: {
          color: "rgba(255, 255, 255, 0.4)",
        },
      },
    },
        
  //开始转换X 轴label
  function axisLabelFormat(v, i, suffix = "", dataInterval) {
    dataInterval.forEach((item, index) => {
      if (i == index) v = item + suffix;
    });
    return v;
  }

 6、修改tooltip

由于我们挂载到series的值是转换后的值,所以我们在这里的提示要改为原来的值

tooltip: {
      show: true,
      trigger: "item",
      backgroundColor: "rgba(54,55,65,0.4)",
      borderColor: "rgba(54,55,65,0.4)",
      textStyle: {
        color: "#fff",
      },
      formatter: function (params) {
        let str = "";
        if (params.componentType == "series") {
          str = `<div style="font-size:14px;">
					收入(元):${diff > 200 ? params.data[2] : params.data[0]}
					</div>
					<div style="font-size:14px;margin-top:10px">
					投入占收入百分比:${diff > 200 ? params.data[3] : params.data[1]}%
					</div>
					`;
        }
        return str;
      },
    },

 解决后的图

 

 

参考文章:https://blog.csdn.net/cai_niao5623/article/details/125394119(折线图的)