echarts实现矩阵图(线性相关图)

在项目开发中需要实现以下效果:元素之间两两相关
在这里插入图片描述
这种实际上是一种热力图,在基础的热力图上做修改,达到此效果。

  • 要点1:去除图表底色
visualMap: {
    show: false,
    pieces: [
      {
        min: 0,
        max: 100,
        color: "none",
      },
    ],
  },
  • 要点2:根据数据动态渲染底色
    图例如下
    在这里插入图片描述
    这里使用颜色渐变算法 颜色渐变算法
const gerColorOfWeight = (minNum, maxNum, colorStart, colorend, number) => {
  const colorR =
    ((colorend.red - colorStart.red) * (number - minNum)) / (maxNum - minNum) +
    colorStart.red;
  const colorG =
    ((colorend.green - colorStart.green) * (number - minNum)) /
      (maxNum - minNum) +
    colorStart.green;
  const colorB =
    ((colorend.blue - colorStart.blue) * (number - minNum)) /
      (maxNum - minNum) +
    colorStart.blue;
  const color = `rgb(${parseInt(colorR).toString()},${parseInt(
    colorG
  ).toString()},${parseInt(colorB).toString()})`;
  // #color=getColorstr((int(colorR),int(colorG),int(colorB)))#转换为16进制颜色
  return color;
};
  • 要点3:动态绘制形状
    给不同范围的值规定不同的宽度以及圆角
const handleDataColor = (val) => {
  // 取绝对值
  let value = Math.abs(val);
  let color = "";
  let startColor = null;
  let endColor = null;
  // 形状配置
  let opt = {};
  switch (true) {
    case value >= 0 && value < 25:
      if (val >= 0) {
        startColor = { red: 246, green: 255, blue: 148 };
        endColor = { red: 255, green: 228, blue: 119 };
      } else {
        startColor = { red: 177, green: 250, blue: 156 };
        endColor = { red: 246, green: 255, blue: 148 };
      }
      color = gerColorOfWeight(0, 25, startColor, endColor, value);
      opt = {
        width: 25,
        height: 25,
        borderRadius: 15,
      };
      break;
    case value >= 25 && value < 50:
      if (val >= 0) {
        startColor = { red: 255, green: 228, blue: 119 };
        endColor = { red: 253, green: 173, blue: 89 };
      } else {
        startColor = { red: 102, green: 220, blue: 159 };
        endColor = { red: 177, green: 250, blue: 156 };
      }
      color = gerColorOfWeight(25, 50, startColor, endColor, value);
      opt = {
        width: 20,
        height: 30,
        rotate: val < 0 ? 15 : -15,
        borderRadius: 60,
      };
      break;
    case value >= 50 && value < 75:
      if (val >= 0) {
        startColor = { red: 253, green: 173, blue: 89 };
        endColor = { red: 204, green: 82, blue: 72 };
      } else {
        startColor = { red: 85, green: 151, blue: 174 };
        endColor = { red: 102, green: 220, blue: 159 };
      }
      color = gerColorOfWeight(50, 75, startColor, endColor, value);
      opt = {
        width: 15,
        height: 30,
        rotate: val < 0 ? 30 : -30,
        borderRadius: 30,
      };
      break;
    case value >= 75 && value < 100:
      if (val >= 0) {
        startColor = { red: 204, green: 82, blue: 72 };
        endColor = { red: 153, green: 1, blue: 62 };
      } else {
        startColor = { red: 86, green: 80, blue: 188 };
        endColor = { red: 85, green: 151, blue: 174 };
      }
      color = gerColorOfWeight(75, 100, startColor, endColor, value);
      opt = {
        width: 10,
        height: 30,
        rotate: val < 0 ? 45 : -45,
        borderRadius: 35,
      };
      break;
  }
  return {
    color,
    opt,
  };
};

以下是完整代码

// 数据源
const dataOrigin = {
  xAxisData: [
    "SO₂",
    "NO₂",
    "CO",
    "O₃",
    "PM₁₀",
    "PM₂.₅",
    "T",
    "P",
    "RH",
    "WS",
    "WD",
    "RAIN",
  ],
  yAxisData: [
    "SO₂",
    "NO₂",
    "CO",
    "O₃",
    "PM₁₀",
    "PM₂.₅",
    "T",
    "P",
    "RH",
    "WS",
    "WD",
    "RAIN",
  ],
  seriesDatas: [],
};

const handleDataColor = (val) => {
  let value = Math.abs(val);
  let color = "";
  let startColor = null;
  let endColor = null;
  let opt = {};
  switch (true) {
    case value >= 0 && value < 25:
      if (val >= 0) {
        startColor = { red: 246, green: 255, blue: 148 };
        endColor = { red: 255, green: 228, blue: 119 };
      } else {
        startColor = { red: 177, green: 250, blue: 156 };
        endColor = { red: 246, green: 255, blue: 148 };
      }
      color = gerColorOfWeight(0, 25, startColor, endColor, value);
      opt = {
        width: 25,
        height: 25,
        borderRadius: 15,
      };
      break;
    case value >= 25 && value < 50:
      if (val >= 0) {
        startColor = { red: 255, green: 228, blue: 119 };
        endColor = { red: 253, green: 173, blue: 89 };
      } else {
        startColor = { red: 102, green: 220, blue: 159 };
        endColor = { red: 177, green: 250, blue: 156 };
      }
      color = gerColorOfWeight(25, 50, startColor, endColor, value);
      opt = {
        width: 20,
        height: 30,
        rotate: val < 0 ? 15 : -15,
        borderRadius: 60,
      };
      break;
    case value >= 50 && value < 75:
      if (val >= 0) {
        startColor = { red: 253, green: 173, blue: 89 };
        endColor = { red: 204, green: 82, blue: 72 };
      } else {
        startColor = { red: 85, green: 151, blue: 174 };
        endColor = { red: 102, green: 220, blue: 159 };
      }
      color = gerColorOfWeight(50, 75, startColor, endColor, value);
      opt = {
        width: 15,
        height: 30,
        rotate: val < 0 ? 30 : -30,
        borderRadius: 30,
      };
      break;
    case value >= 75 && value < 100:
      if (val >= 0) {
        startColor = { red: 204, green: 82, blue: 72 };
        endColor = { red: 153, green: 1, blue: 62 };
      } else {
        startColor = { red: 86, green: 80, blue: 188 };
        endColor = { red: 85, green: 151, blue: 174 };
      }
      color = gerColorOfWeight(75, 100, startColor, endColor, value);
      opt = {
        width: 10,
        height: 30,
        rotate: val < 0 ? 45 : -45,
        borderRadius: 35,
      };
      break;
  }
  return {
    color,
    opt,
  };
};
const gerColorOfWeight = (minNum, maxNum, colorStart, colorend, number) => {
  const colorR =
    ((colorend.red - colorStart.red) * (number - minNum)) / (maxNum - minNum) +
    colorStart.red;
  const colorG =
    ((colorend.green - colorStart.green) * (number - minNum)) /
      (maxNum - minNum) +
    colorStart.green;
  const colorB =
    ((colorend.blue - colorStart.blue) * (number - minNum)) /
      (maxNum - minNum) +
    colorStart.blue;
  const color = `rgb(${parseInt(colorR).toString()},${parseInt(
    colorG
  ).toString()},${parseInt(colorB).toString()})`;
  // #color=getColorstr((int(colorR),int(colorG),int(colorB)))#转换为16进制颜色
  return color;
};

dataOrigin.xAxisData.forEach((item, index) => {
  dataOrigin.yAxisData.forEach((itm, idx) => {
    let list = [];
    let value = Math.floor(Math.random() * 100);
    list.push(item);
    list.push(itm);
    if (item == itm) {
      list.push(100);
    } else if (index % 2 !== 0 || idx % 2 === 0) {
      list.push(-value);
    } else {
      list.push(value);
    }
    dataOrigin.seriesDatas.push({
      name: "",
      data: [list],
      color: list[2] == 100 ? "none" : handleDataColor(list[2]).color,
      labelOpt: list[2] == 100 ? {} : handleDataColor(list[2]).opt,
    });
  });
});

option = {
  grid: {
    top: 40,
    left: 65,
    right: 15,
    bottom: 65,
    show: true,
    width: 421,
    height: 421,
    borderColor: "#061A19",
    borderWidth: 2,
  },
  visualMap: {
    show: false,
    pieces: [
      {
        min: 0,
        max: 100,
        color: "none",
      },
    ],
  },
  xAxis: {
    type: "category",
    data: dataOrigin.xAxisData,
    nameGap: 18,
    nameRotate: 90,
    axisLine: {
      show: false,
    },
    axisTick: {
      show: true,
      alignWithLabel: true,
      lineStyle: {
        color: "#061A19",
        width: 2,
      },
    },
    splitArea: {
      show: false,
    },
    axisLabel: {
      interval: 0,
      fontSize: 14,
      fontFamily: "Source Han Sans CN",
      fontWeight: 500,
      color: "#061A19",
    },
  },
  yAxis: {
    type: "category",
    data: dataOrigin.yAxisData,
    nameGap: 18,
    axisLine: {
      show: false,
    },
    axisTick: {
      show: true,
      alignWithLabel: true,
      lineStyle: {
        color: "#061A19",
        width: 2,
      },
    },
    splitArea: {
      show: false,
    },
    axisLabel: {
      fontSize: 14,
      fontFamily: "Source Han Sans CN",
      fontWeight: 500,
      color: "#061A19",
    },
  },
  series: dataOrigin.seriesDatas.map(({ name, data, color, labelOpt }) => ({
    name,
    data,
    type: "heatmap",
    label: {
      show: true,
      backgroundColor: color,
      ...labelOpt,
      lineheight: 30,
      verticalAlign: "middle",
      fontSize: 14,
      fontFamily: "Source Han Sans CN",
      fontWeight: 500,
      color: "#061A19",
    },
    itemStyle: {
      color: "none",
      borderCap: "round",
    },
    markLine: {
      lineStyle: {
        type: "dashed",
        color: "#14C3BA",
        width: 2,
      },
      data: [
        [
          {
            xAxis: "SO₂",
            yAxis: "SO₂",
            symbol: "none",
          },
          {
            xAxis: "RAIN",
            yAxis: "RAIN",
            symbol: "none",
          },
        ],
      ],
    },
  })),
};

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值