柱状图 显示正负值,点击列表联动柱状图

## 简单易懂的Echars案例,实现点击列表联动饼图
1. 安装 echarts-for-react
2. 项目中引入 import ReactECharts from 'echarts-for-react';
3. 开始写案例啦!!!


1. 首先我们先写一个左侧列表 StageLine
利用StageItem 将 data 中的数据遍历并展示。 

import React = require('react');
import { StageItem } from './StageItem';

const data = [
  { name: '糖', value: '12' },
  { name: '蛋白质', value: '24' },
  { name: '脂肪', value: '15' },
  { name: '碳水化合物', value: '-15' },
];

type StageLineProps = {
  handleClickPie?: (index: number) => void;
  setCurrentIndex?: (o: number) => void;
};

export default function StageLine({
  handleClickPie,
  setCurrentIndex,
}: StageLineProps) {
  return (
    <div>
      {data?.map((item, index) => {
        return (
          <div
            key={index}
            onClick={() => {
              handleClickPie?.(index);
              setCurrentIndex?.(index);
            }}
          >
            <StageItem title={item.name} value={item.value} />
          </div>
        );
      })}
    </div>
  );
}


#### StageLine 子组件 StageItem

import { Group, Text } from '@mantine/core';
import React = require('react');

type StageItemProps = { title: string; value: string };

export function StageItem({ title, value }: StageItemProps) {
  return (
    <Group
      spacing={2}
      noWrap
      align="center"
      sx={{
        cursor: 'pointer',
        width: 200,
        display: 'flex',
        flexDirection: 'row',
        flexWrap: 'nowrap',
        justifyContent: 'center',
        alignItems: 'stretch',
        alignContent: 'stretch',
        alignSelf: 'normal',
      }}
    >
      <Text
        sx={{
          backgroundColor: '#004399',
          padding: '6px 8px',
          color: 'white',
          minWidth: 40,
          maxWidth: 85,
          lineHeight: '18px',
          alignItems: 'stretch',
          display: 'inline-block',
          flexShrink: 0,
        }}
        size={12}
        weight={600}
      >
        {title}
      </Text>
      <Text
        sx={{
          backgroundColor: 'rgba(0, 67, 153, 0.06)',
          padding: '6px 8px',
          color: '#004399',
          flexGrow: 1,
          '.react-katex ': {
            // height: '26px',
          },
        }}
        size={12}
        weight={600}
      >
        {value ?? '-'}
        {/* <div style={{ display: 'inline-block' }}>{unit}</div> */}
      </Text>
    </Group>
  );
}

#### 2.接下来我们写右侧柱状图
我们利用 forwardRef 来接受从父组件传递过来的 ref,并将 ref 赋给柱状图组件 ReactECharts。拿到柱状图的ref 我们 就可以实现左右联动的效果啦!

import { forwardRef } from 'react';
import { lazy } from 'react';
import type { EChartsInstance } from 'echarts-for-react';
import React = require('react');
const ReactECharts = lazy(() => import('echarts-for-react'));
const NegativeData = [
  { name: '糖', value: '12' },
  { name: '蛋白质', value: '24' },
  { name: '脂肪', value: '15' },
  { name: '碳水化合物', value: '-15' },
];
export const Negative = forwardRef<EChartsInstance, any>((_, ref) => {
  const colors = [
    '#1F3C88',
    '#2E4FA3',
    '#6B90D8',
    '#8DBEEB',
    '#B6D0F8',
    '#DAEBFB',
    '#F0F8FD',
  ];

  const colorData = NegativeData?.map((d, index) => {
    return {
      data: [...Array(index + 1).fill(0), d.value],
      name: d.name,
      type: 'bar',
      stack: 'Total',
      barWidth: 20,
      itemStyle: {
        color: colors[(index + 1) % colors.length],
        borderWidth: 1.5,
        borderColor: 'transparent',
      },
      emphasis: {
        itemStyle: {
          shadowBlur: 5,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)',
        },
      },
    };
  });

  const legendData = NegativeData?.map((d) => d.name);

  const options = {
    legend: {
      bottom: 100 - 17 * (legendData?.length ?? 0),
      itemWidth: 10,
      itemHeight: 10,
      orient: 'vertical',
      backgroundColor: 'rgba(0,67,153,0.06)',
      padding: [12, 20],
      itemGap: 7,
      icon: 'rect',
      textStyle: {
        padding: [0, 0, 0, 4],
        color: '#111',
        fontWeight: 400,
        fontFamily: 'sans-serif',
        lineHeight: 15,
        fontSize: 12,
      },
    },
    title: {
      text: '',
      left: 'center',
      textStyle: {
        fontSize: '16px',
        fontWeight: 700,
        color: '#111',
      },
    },
    tooltip: {
      trigger: 'item',
      formatter: ` {a}<br/> {c} `,
      textStyle: {
        fontSize: 14,
        color: '#333',
      },
    },
    grid: {
      top: 50,
      bottom: 150,
    },
    xAxis: {
      type: 'value',
      position: 'top',
      axisLine: { show: false },
      axisLabel: { show: false },
      axisTick: { show: false },
      splitLine: { show: false },
    },
    yAxis: {
      type: 'category',
      axisLine: { show: true },
      axisLabel: { show: false },
      axisTick: { show: false },
      splitLine: { show: false },
    },
    series: [...(colorData ?? [])],
  };

  return (
    <ReactECharts
      ref={ref}
      option={options}
      style={{ width: 250, height: 500, margin: '25px auto' }}
      opts={{ renderer: 'svg' }}
    />
  );
});


#### 3. 在最外层父级,写一些方法,进行联动操作。 
   handleClickPie 方法是当我们点击左侧列表时,对应部分的右边饼图高亮显示,点击当前项,同时要取消上一次点击项的高亮。那么此时,我们就要拿到,之前高亮的项的index(prePieRef)和当前的高亮的项的index(currentIndex)。
   clickOutsidePieRef:点击屏幕其他位置时,取消当前高亮
   注意📢:这个ref必须给饼图的外层容器,否则不能生效!

import { Box, Group } from '@mantine/core';
import * as React from 'react';
import { useRef, useState } from 'react';
import { Negative } from './Negative';
import StageLine from './StageLine';
import './style.css';
import ReactECharts from 'echarts-for-react';
import { useClickOutside } from '@mantine/hooks';

export default function App() {
  const negativeRef = useRef<ReactECharts>(null);
  const preNegativeRef = useRef(-1);
  const [currentIndex, setCurrentIndex] = useState(-1);

  const clickOutsideNegativeRef = useClickOutside(() => {
    const downplay = negativeRef?.current?.getEchartsInstance()?.dispatchAction({
      type: 'downplay',
      seriesIndex: currentIndex,
      dataIndex: currentIndex + 1,
    });
    const hideTip = negativeRef?.current?.getEchartsInstance()?.dispatchAction({
      type: 'hideTip',
    });
    return { downplay, hideTip };
  });

  const handleClickNegative = (index: number) => {
    if (preNegativeRef.current >= 0) {
      negativeRef?.current?.getEchartsInstance()?.dispatchAction({
        type: 'downplay',
        seriesIndex: preNegativeRef.current,
        dataIndex: preNegativeRef.current + 1,
      });
    }
    negativeRef?.current?.getEchartsInstance()?.dispatchAction({
      type: 'highlight',
      seriesIndex: index,
      dataIndex: index + 1,
    });
    preNegativeRef.current = index;
    negativeRef?.current?.getEchartsInstance()?.dispatchAction({
      type: 'showTip',
      seriesIndex: index,
      dataIndex: index + 1,
    });
  };
  console.log(negativeRef)
  return (
    <Group>
      <StageLine
        handleClickNegative={handleClickNegative}
        setCurrentIndex={setCurrentIndex}
      />
      <Box ref={clickOutsideNegativeRef}>
        <Negative ref={negativeRef} />
      </Box>
    </Group>
  );
}


最后附上源码:

React Ts (forked) - StackBlitz

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值