多图表共用legend

0.1功能要求

多饼图共用一个legend,并且要求legend可以控制所有饼图。

​ 如图所示:

​ 1.legend可以控制某一块饼显隐

​ 2.鼠标放上 饼图强调,并显示tip,移走隐藏

image-20230524152340906

0.2实现思路

1.分析:

​ 这四个饼图的legend都是一样的,数据格式也是一样的,只是具体数据内容不一样

2.思路

​ 因此独立出来的图例实际上也是一个饼图,但是只显示legend,饼图给隐藏了,然后在操作legend的时候使用bus把操作的块传给了其他饼图,并执行函数同步操作,就形成了共用legend,并可操作其他饼图。

代码:

一、lengend和 饼图盒子代码

<template>
  <el-card class="pie-card">
    <div slot="header" class="clearfix">
      <span>各能源消耗占比</span>
    </div>
    <div class="container">
      <div class="pie-legend">
      	// legend 随便传入了一个饼图数据,为了获取相同的lengend
        <PieLegend :pieData="pieData.总体" />
      </div>
      <div class="pie-container">
        <div class="pie-box">
          <MediumPie :title="cardTitle[0]" :pieData="pieData.总体" />
        </div>
        <div class="pie-box">
          <MediumPie :title="cardTitle[1]" :pieData="pieData.一号炉" />
        </div>
        <div class="pie-box">
          <MediumPie :title="cardTitle[2]" :pieData="pieData.二号炉" />
        </div>
        <div class="pie-box">
          <MediumPie :title="cardTitle[3]" :pieData="pieData.三号炉" />
        </div>
      </div>
    </div>
  </el-card>
</template>

<script>
import MediumPie from "../echarts/MediumPie.vue";
import PieLegend from "../echarts/PieLegend.vue";
export default {
  components: { MediumPie, PieLegend },
  name: "MediumPiePanel",
  props: ["cardTitle", "pieData"],
  data() {
    return {};
  },
};
</script>
<style lang="scss" scoped>
.pie-card {
  height: 80vh;
  min-height: 580px;
}
.container {
  position: relative;
}
.pie-container {
  justify-content: center;
  align-items: center;
  display: flex;
  flex-wrap: wrap; // 允许flex布局换行
  margin-left: 190px;
}
.pie-box {
  width: 47.6%;
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: all 0.3s ease-in-out;
  margin: 5px;
}

.pie-box:hover {
  transform: translateY(-5px);
  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
  background-color: #f1f1f1;
}
.pie-legend {
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  border-radius: 0px;
  margin: 5px;
  position: absolute;
  top: 0px;
  left: 0px;
  height: 98%;
  width: 180px;
}
</style>

二、legend代码

<template>
  <el-card style="height: 100%">
    <div class="line-container">
      <div ref="PieChart" class="line-box" style="height: 64vh"></div>
    </div>
  </el-card>
</template>

<script>
import echarts from "echarts";
export default {
  name: "PieLegend",
  props: ["pieData"],
  data() {
    return {
      mychart: null,
    };
  },
  created() {},
  methods: {
    init() {
      // 基于准备好的dom,初始化echars实例
      this.mychart = echarts.init(this.$refs.PieChart);
      // 指定图表的配置项和数据
      var option = {
        legend: {
          // orient: "horizontal",  // 设置legend的方向
          orient: "vertical",
          top: "center", // 设置legend的位置
          left: "left",
          type: "scroll", // 设置legend是否有轮动条模式
          // selectedMode: false, // 取消图例点击事件
        },

        series: [
          {
          // 这是legend的颜色,这里的颜色必须和其他饼图一样
            color: [
              "#D0104C",
              "#00CED1",
              "#FF8C00",
              "#BA55D3",
              "#32CD32",
              "#FFD700",
              "#5ab1ef",
              "#b6a2de",
              "#67e0e3",
              "#2ec7c9",
              "#FFC0CB",
              "#9370DB",
              "#AFEEEE",
              "#1B813E",
            ],
            // name: "Access From",
            type: "pie",
            radius: "0%", // 饼图大小 设置0为了隐藏饼图
            center: ["5000%", "5000%"], // 饼图位置
            data: this.pieData,// 饼图的数据
          },
        ],
      };
      this.mychart.setOption(option);
    },
    // 点击图例触发修改其他四个饼图
    handleLegendClick(params) {
    	// 触发兄弟组件,也就是其他饼图的方法,并传入params.name 参数
      this.$bus.$emit("changeLegendSelected", params.name);
    },

    handleLegendMouseover(event) {
    	// 获取鼠标现在所在的位置
      const legendDataIndex = event.topTarget.parent.__legendDataIndex; // 每个legend的index
      // 该监听器正在监听一个`echarts 事件`。
      // 因为不仅仅是图例可以触发鼠标经过事件,不是图例的没用index,所以要过滤一下
      if (legendDataIndex != undefined && legendDataIndex >= 0) {
        this.$bus.$emit("legendMouseover", legendDataIndex);
      }
    },

    handleLegendMouseout(event) {
    	// 有的鼠标移出触发的事件没用parent属性所以要加?为可选的
      if (event.topTarget?.parent != undefined) {
        const legendDataIndex = event.topTarget.parent.__legendDataIndex; // 每个legend的index
        // 该监听器正在监听一个`echarts 事件`。
        if (legendDataIndex != undefined && legendDataIndex >= 0) {
          this.$bus.$emit("legendMouseout", legendDataIndex);
        }
      }
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.init();
      // 监听图例点击事件
      this.mychart.on("legendselectchanged", this.handleLegendClick);
      // 监听鼠标经过图例事件,注意这不仅仅是监听图例的,也会监听其他的
      // 但是监听图例会有一个index也就是鼠标在第几个图例上,具体看handle代码
      this.mychart.getZr().on("mouseover", this.handleLegendMouseover);
      // 监听鼠标移除图例事件
      this.mychart.getZr().on("mouseout", this.handleLegendMouseout);
    });
  },
  beforeDestroy() {
  	// 销毁各个监听器
    this.mychart.off("legendselectchanged", this.handleLegendClick);
    this.mychart.getZr().off("mouseover", this.handleLegendMouseover);
    this.mychart.getZr().off("mouseout", this.handleLegendMouseout);
    this.mychart.dispose(); // 销毁图表对象
    this.mychart = null; // 清空对图表对象的引用
  },
  watch: {
    // 每次仪表盘数据
    pieData: {
      handler(newValue, oldValue) {
        // 重新绘制
        this.init();
      },
      deep: true,
    },
  },
  computed: {
    chartHeight() {
      const ratio = 0.8; // 高度与窗口高度的比例系数
      return `${this.LineBoxHeight * ratio}px`;
    },
  },
};
</script>

<style lang="scss" scoped>
.line-container {
  height: 100%;
}
</style>

三、饼图代码:

<template>
  <el-card style="height: 100%">
    <div slot="header" class="clearfix">
    // 标题
      <span>{{ title }}</span>
    </div>
    // 饼图容器
    <div class="line-container">
      <div ref="PieChart" class="line-box" style="height: 23vh"></div>
    </div>
  </el-card>
</template>

<script>
import echarts from "echarts";
export default {
  name: "MediumPie",
  props: ["title", "pieData"],
  data() {
    return {
      mychart: null,
    };
  },
  created() {},
  methods: {
    handleChangeLegendSelected(params) { // params就是bus传过来 的参数
      // 修改图例选中状态
      this.mychart.dispatchAction({
        type: "legendToggleSelect", 
        // 图例名称
        name: params,
      });
    },
    // 鼠标移入图例高亮 show tip
    handleLegendMouseover(legendIndex) {
      this.mychart.dispatchAction({
        type: "highlight",
        seriesIndex: 0,// 这个是数据系列,有的一个echarts里面放了多组数据,本案例只有一组所以是0
        dataIndex: legendIndex,// 第几个图例
      });
		// 显示tip
      this.mychart.dispatchAction({
        type: "showTip",
        seriesIndex: 0,
        dataIndex: legendIndex,
      });
    },
    // 鼠标移出图例恢复正常
    handleLegendMouseout(legendIndex) {
      this.mychart.dispatchAction({
        type: "downplay",
        seriesIndex: 0,
        dataIndex: legendIndex,
      });
	// 隐藏 tip
      this.mychart.dispatchAction({
        type: "hideTip",
        seriesIndex: 0,
        dataIndex: legendIndex,
      });
    },
    init() {
      // 基于准备好的dom,初始化echars实例
      this.mychart = echarts.init(this.$refs.PieChart);
      // 指定图表的配置项和数据
      var option = {
        // legend选项必须要加,不然就操作不了要求的功能
        legend: {
          // orient: "horizontal",
          orient: "vertical",
          top: "bottom",
          left: "left",
          type: "scroll",
          // 是否显示图例,这个一定要加,不然饼图会显示自己的图例
          show: false, 
        },
        // 鼠标hover提示内容
        tooltip: {
          trigger: "item",
          // formatter: "{a} <br/>{b} : {c} ({d}%)",
          formatter: "{b} : {c} ({d}%)",
          // 下面的函数,用于tip可以完整显示,不用被盒子挡住
          position: function (point, params, dom, rect, size) {
            // 鼠标坐标和提示框位置的参考坐标系是:以外层div的左上角那一点为原点,x轴向右,y轴向下
            // 提示框位置
            var x = 0; // x坐标位置
            var y = 0; // y坐标位置

            // 当前鼠标位置
            var pointX = point[0];
            var pointY = point[1];

            // 外层div大小
            // var viewWidth = size.viewSize[0];
            // var viewHeight = size.viewSize[1];

            // 提示框大小
            var boxWidth = size.contentSize[0];
            var boxHeight = size.contentSize[1];

            // boxWidth > pointX 说明鼠标左边放不下提示框
            if (boxWidth > pointX) {
              x = 5;
            } else {
              // 左边放的下
              x = pointX - boxWidth;
            }

            // boxHeight > pointY 说明鼠标上边放不下提示框
            if (boxHeight > pointY) {
              y = 5;
            } else {
              // 上边放得下
              y = pointY - boxHeight;
            }

            return [x, y];
          }, // 设置显示位置
        },
        series: [
          {
            color: [
              "#D0104C",
              "#00CED1",
              "#FF8C00",
              "#BA55D3",
              "#32CD32",
              "#FFD700",
              "#5ab1ef",
              "#b6a2de",
              "#67e0e3",
              "#2ec7c9",
              "#FFC0CB",
              "#9370DB",
              "#AFEEEE",
              "#1B813E",
            ],
            // name: "Access From",
            type: "pie",
            radius: "90%", // 饼图大小
            center: ["50%", "50%"], // 饼图位置
            label: {
              normal: {
                show: false,
              },
            },
            labelLine: {
              normal: {
                show: false,
              },
            },

            data: this.pieData,
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: "rgba(0, 0, 0, 0.5)",
              },
            },
          },
        ],
      };
      this.mychart.setOption(option);
    },
    // 从传过来的值分解出仪表盘的值
    getLineValue() {},
  
  },
  mounted() {
    this.$nextTick(() => {
      this.init();
      // 修改图例选中状态,当图例组件的bus被触发时,这些函数就会被执行
      this.$bus.$on("changeLegendSelected", this.handleChangeLegendSelected);
      // 鼠标经过
      this.$bus.$on("legendMouseover", this.handleLegendMouseover);
      // 鼠标移除
      this.$bus.$on("legendMouseout", this.handleLegendMouseout);
    });
  },
  watch: {
    // 每次仪表盘数据
    pieData: {
      handler(newValue, oldValue) {
        // 重新绘制
        this.init();
      },
      deep: true,
    },
  },
  computed: {
    chartHeight() {
      const ratio = 0.8; // 高度与窗口高度的比例系数
      return `${this.LineBoxHeight * ratio}px`;
    },
  },
};
</script>

<style lang="scss" scoped>

</style>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值