echart在折线显示横纵(横纵线沿着折线展示)

315 阅读7分钟

产品有个需求,需要在echart折线上展示横纵向坐标系,echart的axisPointer默认是展示在鼠标当前位置的,不符合需求,所以是使用markline实现的

在线例子和源码

先上效果图

在这里插入图片描述

实现思路

  1. 横纵线的x轴线是比较容易的,因为echart的axixPointer的位置是鼠标当前坐标作的,所以x轴线直接用toltip的axisPointer
tooltip: {
    trigger: "axis",
    triggerOn: "mousemove",
    backgroundColor: "#FFFFFF",
    formatter: function () {},
    axisPointer: {
      type: "line",
      label: {
        show: true,
        backgroundColor: "#FF7613",
        borderRadius: 4,
        fontSize: 11,
        padding: [4, 5]
      },
      lineStyle: {
        color: "#FF7613",
        type: "dotted",
        width: 3 // 正常时的折线宽度
      }
    }
  },
  1. y轴线则使用的series的markLine,只需要把默认的箭头去掉接口
series: [
    {
      type: "line",
      data: data, // Y 轴的数据
      symbol: "none",
      label: {
        show: false
      },
      markLine: {
        symbol: "none",
        animation: false,
        label: {
          normal: {
            show: true,
            position: "start",
            backgroundColor: "#FF7613",
            borderRadius: 4,
            fontSize: 12, // 修改字体大小
            padding: [4, 6], // 修改内边距
            color: "#FFFFFF"
          }
        },
        lineStyle: {
          normal: {
            color: "#FF7613",
            type: "dotted",
            width: 3 // 正常时的折线宽度
          }
        },
        emphasis: {
          label: {
            normal: {
              show: false
            }
          },
          lineStyle: {
            normal: {
              color: "#FF7613",
              type: "dotted",
              width: 1 // hover时的折线宽度
            }
          }
        },
        data: []
      }
    }
  ]
  1. 第二步的markLine的data是空数组,这样是不会展示的线的
    • 需要在鼠标移动过程中实时画线,所以需要监听echart的mousemove事件,获取当前鼠标位置再转换成对应的坐标,最终得到实际的x轴位置(也就是当前x轴的下标),然后读取series的data[x]即可
    • 在展示markLine时候,需要展示axisPopinter,通过echart的dispatchAction(showtip)展示
    • 下面代码有注释每一步的作用
myChart.getZr().on("mousemove", (params) => {
  // 获取点击位置的坐标
  let pointInPixel = [params.offsetX, params.offsetY];
  // convertFromPixel将鼠标位置坐标进行转化
  // 返回[x, y],x对应鼠标点击处数据的下标,y对应鼠标点击处的数值
  let x = myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel)[0];
  const xAxis = option.xAxis;
  const xData = xAxis.data;
  // 兼容超出x轴的最大最小值时候,axisPointer的展示位置
  if (x > xData.length - 1) {
    x = xData.length - 1;
  } else if (x < 0) {
    x = 0;
  }
  // series[0].data[x]折线上的数据
  const markLineValue = option.series[0].data[x];
  const { series } = option;
  // 修改markLine的值
  series[0].markLine.data = [
    {
      yAxis: markLineValue
    }
  ];
  // 触发展示tooltip的axisPointer
  myChart.dispatchAction({
    type: "showTip",
    seriesIndex: 0,
    dataIndex: x
  });
  myChart.setOption({ series }, { lazyUpdate: true });
});
  1. 还需要添加一下鼠标移出mouseout事件,把markLine和axisPointer隐藏
// 监听鼠标移出事件,隐藏markline
myChart.getZr().on("mouseout", () => {
  const { series } = option;
  // 修改markLine的值
  series[0].markLine.data = [];
  myChart.setOption({ series }, { lazyUpdate: true });
});

window.addEventListener("resize", myChart.resize);

解释一下为什么不用markline做x轴的线,因为markLine的label会被echart遮挡(并不像axisPointer的label会自适应位置),可以调整grid的right,使右边空出来地方来展示label,但是这样web端还好,对于移动端就有点尴尬,浪费空间,建议使用axisPointer

在这里插入图片描述

完整代码,在线例子和源码点我

const dom = document.getElementById("chart-container");
var myChart = echarts.init(dom, null, {
  renderer: "canvas",
  useDirtyRect: false
});

const data = [ 32, 30, 29, 28, 26, 20, 18, 17, 17, 18, 19, 20, 21, 20, 21, 18, 12, 25, 26, 25, 26, 25, 30, 25, 29, 27, 28, 22, 23, 30, 26, 25, 24, 23, 16, 14, 18, 12, 10, 6, 8, 9, 9, 8, 9, 10, 12, 10, 13, 16, 20, 22, 23, 26, 25, 28, 29, 32, 38, 41, 39, 40, 41, 38, 37, 36, 35, 32, 28, 32, 38, 39, 40, 39, 36, 35, 34, 32, 26, 27, 29, 29, 31, 32, 38, 26, 22, 16, 17, 19, 18, 20, 25, 29, 30, 28, 31, 33, 42, 38, 41, 45];

const xData = [ "2023-09-21", "2023-09-22", "2023-09-23", "2023-09-24", "2023-09-25", "2023-09-26", "2023-09-27", "2023-09-28", "2023-09-29", "2023-09-30", "2023-10-01", "2023-10-02", "2023-10-03", "2023-10-04", "2023-10-05", "2023-10-06", "2023-10-07", "2023-10-08", "2023-10-09", "2023-10-10", "2023-10-11", "2023-10-12", "2023-10-13", "2023-10-14", "2023-10-15", "2023-10-16", "2023-10-17", "2023-10-18", "2023-10-19", "2023-10-20", "2023-10-21", "2023-10-22", "2023-10-23", "2023-10-24", "2023-10-25", "2023-10-26", "2023-10-27", "2023-10-28", "2023-10-29", "2023-10-30", "2023-10-31", "2023-11-01", "2023-11-02", "2023-11-03", "2023-11-04", "2023-11-05", "2023-11-06", "2023-11-07", "2023-11-08", "2023-11-09", "2023-11-10", "2023-11-11", "2023-11-12", "2023-11-13", "2023-11-14", "2023-11-15", "2023-11-16", "2023-11-17", "2023-11-18", "2023-11-19", "2023-11-20", "2023-11-21", "2023-11-22", "2023-11-23", "2023-11-24", "2023-11-25", "2023-11-26", "2023-11-27", "2023-11-28", "2023-11-29", "2023-11-30", "2023-12-01", "2023-12-02", "2023-12-03", "2023-12-04", "2023-12-05", "2023-12-06", "2023-12-07", "2023-12-08", "2023-12-09", "2023-12-10", "2023-12-11", "2023-12-12", "2023-12-13", "2023-12-14", "2023-12-15", "2023-12-16", "2023-12-17", "2023-12-18", "2023-12-19", "2023-12-20", "2023-12-21", "2023-12-22", "2023-12-23", "2023-12-24", "2023-12-25", "2023-12-26", "2023-12-27", "2023-12-28", "2023-12-29", "2023-12-30", "2023-12-31"];

const option = {
  tooltip: {
    trigger: "axis",
    triggerOn: "mousemove",
    backgroundColor: "#FFFFFF",
    formatter: function () {},
    axisPointer: {
      type: "line",
      label: {
        show: true,
        backgroundColor: "#FF7613",
        borderRadius: 4,
        fontSize: 11,
        padding: [4, 5]
      },
      lineStyle: {
        color: "#FF7613",
        type: "dotted",
        width: 3 // 正常时的折线宽度
      }
    }
  },
  grid: {
    left: "10%",
    right: "10%",
    bottom: "10%",
    top: "10%",
    containLabel: true
  },
  xAxis: {
    type: "category",
    data: xData
  },
  yAxis: {
    type: "value"
  },
  series: [
    {
      type: "line",
      data: data, // Y 轴的数据
      symbol: "none",
      label: {
        show: false
      },
      markLine: {
        symbol: "none",
        animation: false,
        label: {
          normal: {
            show: true,
            position: "start",
            backgroundColor: "#FF7613",
            borderRadius: 4,
            fontSize: 12, // 修改字体大小
            padding: [4, 6], // 修改内边距
            color: "#FFFFFF"
          }
        },
        lineStyle: {
          normal: {
            color: "#FF7613",
            type: "dotted",
            width: 3 // 正常时的折线宽度
          }
        },
        emphasis: {
          label: {
            normal: {
              show: false
            }
          },
          lineStyle: {
            normal: {
              color: "#FF7613",
              type: "dotted",
              width: 1 // hover时的折线宽度
            }
          }
        },
        data: []
      }
    }
  ]
};

myChart.setOption(option);

// 监听鼠标移进事件,展示markline和tooltip的axisPointer
myChart.getZr().on("mousemove", (params) => {
  // 获取点击位置的坐标
  let pointInPixel = [params.offsetX, params.offsetY];
  // convertFromPixel将鼠标位置坐标进行转化
  // 返回[x, y],x对应鼠标点击处数据的下标,y对应鼠标点击处的数值
  let x = myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel)[0];
  const xAxis = option.xAxis;
  const xData = xAxis.data;
  // 兼容超出x轴的最大最小值时候,axisPointer的展示位置
  if (x > xData.length - 1) {
    x = xData.length - 1;
  } else if (x < 0) {
    x = 0;
  }
  // series[0].data[x]折线上的数据
  const markLineValue = option.series[0].data[x];
  const { series } = option;
  // 修改markLine的值
  series[0].markLine.data = [
    {
      yAxis: markLineValue
    }
  ];
  // 触发展示tooltip的axisPointer
  myChart.dispatchAction({
    type: "showTip",
    seriesIndex: 0,
    dataIndex: x
  });
  myChart.setOption({ series }, { lazyUpdate: true });
});

// 监听鼠标移出事件,隐藏markline
myChart.getZr().on("mouseout", () => {
  const { series } = option;
  // 修改markLine的值
  series[0].markLine.data = [];
  myChart.setOption({ series }, { lazyUpdate: true });
});

window.addEventListener("resize", myChart.resize);