react中echarts-for-react图表点击节点以及节点当前列进行节点高亮

109 阅读1分钟
// 数据
const [data, setData] = useState({ user_list: [] });
// myChart 折线图实例
const [myChart, setMyChart] = useState<EChartsInstance>(null);
// selectIndex 存放高亮数据下标
const [selectIndex, setSelectIndex] = useState<number>();

useEffect(() => {
  if (myChart) {
    myChart?.getZr().off('click');
    myChart.getZr().on('click', (e: ISafeAny) => {
      const pointInPixel = [e.offsetX, e.offsetY];
      const pointInGrid = myChart.convertFromPixel(
        {
          seriesIndex: 0
        },
        pointInPixel
      );
      const xIndex = pointInGrid[0];
      //索引下标
      const handleIndex = Number(xIndex);
      // 这里是判断是否点击的是同一个点,如果当前点击的点已经高亮则不需要再进来
      if (selectIndex !== handleIndex) {
        setSelectIndex(handleIndex);
        const item = data?.user_list[handleIndex];
      }
    });
  }
}, [myChart, selectIndex, data]);

// 使用 ReactEcharts 渲染
<ReactEcharts
  onChartReady={(chart) => setMyChart(chart)}
  option={getSearchOption(data?.user_list, data?.request_list, selectIndex)}
  style={{ height: '312px', background: '#fff', marginBottom: 16 }}
/>
// 主要就是这个 highlightIndex 并且设置图例不可点击 selectedMode: false
const getSearchOption = function (userList: IBaseData[] = [], requestList: IBaseData[] = [], highlightIndex?: number) {
  const xData: string[] = [];
  const sUserCountData: number[] = [];
  const sRequestCountData: number[] = [];
  for (let i = 0; i < userList.length; i++) {
    const x = userList[i].day;
    const sUserCount = userList[i].count;
    const sRequestCount = requestList[i].count;
    xData.push(x);
    sUserCountData.push(sUserCount);
    sRequestCountData.push(sRequestCount);
  }
  const option = {
    color: ['#1e89ff'],
    title: false,
    legend: {
      bottom: 0,
      selectedMode: false,
      data: [
        {
          name: '用户量',
          itemStyle: {
            color: EBasicDataColors.用户量
          }
        },
        {
          name: '搜索次数',
          itemStyle: {
            color: EBasicDataColors.次数
          }
        }
      ]
    },
    tooltip: {
      trigger: 'axis',
      backgroundColor: 'rgba(238, 244, 248, 0.80)',
      borderColor: '#E9ECF2',
      formatter: getFormatterTooltip
    },
    grid: { left: 50, right: 50, top: 30, bottom: 50 },
    xAxis: {
      name: '',
      type: 'category',
      boundaryGap: false,
      data: xData,
      axisLine: {
        color: '#c1c7ce',
        type: 'solid',
        width: 1
      },
      show: true
    },
    yAxis: {
      name: '',
      type: 'value',
      splitLine: {
        show: true,
        lineStyle: {
          color: '#dfe3e5',
          type: 'dashed'
        }
      }
    },
    series: [
      {
        name: '用户量',
        type: 'line',
        showSymbol: true,
        smooth: true,
        itemStyle: {
          color: EBasicDataColors.用户量
        },
        lineStyle: {
          color: EBasicDataColors.用户量
        },
        areaStyle: {
          opacity: 0.8,
          color: getGraphicLinearGradient(['rgba(98, 204, 201, 0.12)', 'rgba(98, 204, 201, 0.00)'])
        },
        data: sUserCountData.map((item, index) => {
          if (index === highlightIndex) {
            return {
              value: item,
              itemStyle: {
                color: '#f00'
              }
            };
          }
          return item;
        })
      },
      {
        name: '搜索次数',
        type: 'line',
        showSymbol: true,
        smooth: true,
        itemStyle: {
          color: EBasicDataColors.次数
        },
        lineStyle: {
          color: EBasicDataColors.次数
        },
        areaStyle: {
          opacity: 0.8,
          color: getGraphicLinearGradient(['rgba(108, 126, 224, 0.12)', 'rgba(108, 126, 224, 0.00)'])
        },
        data: sRequestCountData.map((item, index) => {
          if (index === highlightIndex) {
            return {
              value: item,
              itemStyle: {
                color: '#f00'
              }
            };
          }
          return item;
        })
      }
    ]
  };
  return option;
};