小工具知识网

当前位置: 首页 > 行业知识 > echarts柱状图可鼠标左击出现自定义弹框,右击隐藏弹框并阻止默认右击事件

行业知识

echarts柱状图可鼠标左击出现自定义弹框,右击隐藏弹框并阻止默认右击事件

2026-11-15 22:06:48 来源:互联网转载

���项x轴数据对应有两条柱图和一条阴影效果是学习其它博客得到的效果,这个是学习的原文链接:echarts两个合并柱体(普通柱状图+象形柱图)共享一个柱体阴影

因为这次情况比较特殊,不仅需要自定义弹框内容,而且也需要鼠标的右击事件隐藏效果。这里我就假设在已有阴影效果的基础上,针对鼠标点击显示弹框进行记录。若有需要源码在后面,可自取。

echarts自定义弹框内容

  • 效果图展示
  • 前记
  • 鼠标左击事件(click)
    • 参数介绍
    • 自定义弹框的样式
    • 逻辑代码部分
      • 添加自定义元素
      • 清除之前的菜单元素
      • 左击方法的全部代码
      • 鼠标右击事件(contextmenu)
        • 逻辑代码部分
          • chart.getZr().on 与 chart.on
          • 隐藏鼠标右击后的默认行为
          • 右击方法的全部代码
          • 源码

            效果图展示

            前记

            echarts的鼠标事件:点击跳转至官方的鼠标事件

            官网给的事件行为逻辑:点击跳转至官网的事件与行为

            下面是具体含义:

            click:当用户在图表上进行单击操作时触发,可以用于实现单击选中数据点或者执行特定的交互操作。

            dblclick:当用户在图表上进行双击操作时触发,可以用于实现双击放大或者展开详细信息等功能。

            mousedown:当用户按下鼠标按钮时触发,可以用于实现拖拽、绘制选框等交互操作。

            mousemove:当用户在图表上移动鼠标时触发,可以用于实现实时显示数据信息或者跟随鼠标移动的提示框。

            mouseup:当用户释放鼠标按钮时触发,可以用于结束拖拽、绘制等操作。

            mouseover:当鼠标悬停在图表元素上时触发,可以用于显示详细信息或者高亮当前元素。

            mouseout:当鼠标移出图表元素时触发,可以用于隐藏信息框或者取消高亮状态。

            globalout:当鼠标移出图表区域时触发,可以用于清除所有高亮状态或者隐藏全局提示框。

            contextmenu:当用户在图表上右键单击时触发,可以用于显示自定义的右键菜单或者执行特定的操作。

            这里用到的是click单击以及contextmenu右键单击事件。

            鼠标左击事件(click)

            这里在绑定点击操作里,根据被点击的位置使用子绝父相(子盒子position: absolute;父盒子position: relative;),设定自定义弹框的位置。

            参数介绍

            点击阴影部分时,可查看params值,params.event.event与vue的鼠标右击事件 @contextmenu="func"传的event参数一样,通过这个可以设置被点击盒子的显示位置,设定其top值及left值。

            自定义弹框的样式

            1、若添加自定义类名可通过pdom.classList.add(“类名”),在 JavaScript 中,classList 是 DOM 元素的属性,它提供了一组方法来操作元素的类名。其中,.add() 方法用于向元素的类列表中添加一个或多个类名。

            2、若添加自定义样式可通过pdom.style.cssText,此方法是用于设置元素的内联样式的属性。直接将 CSS 样式规则作为字符串赋给元素的内联样式,从而一次性设置多个样式属性。

            单引号与反引号的区别:

            反引号是 ES6 中的模板字符串语法。使用反引号包裹字符串可以实现字符串插值,即在字符串中嵌入变量或表达式的值。

            与单引号和双引号相比,使用反引号的优势在于可以在字符串中直接引用变量,而无需使用字符串连接符(+)来拼接字符串。这样使得代码更具可读性,并且更容易维护。

            在下面这段代码中,反引号用于创建一个模板字符串,其中 ${} 内部的表达式会被计算并替换为实际的值。这样就可以动态地设置 left 和 top 样式属性的值,根据 params.event.event.pageX 和 params.event.event.pageY 的实时数值来确定自定义p菜单的位置。

            逻辑代码部分

            添加自定义元素

            通过 createElement 方法创建视图元素,这里创建了三个p,分别为父盒子(.custom-menu)、两个子盒子(.menu-item),元素结构如下图。

            清除之前的菜单元素

            自定义弹框已经创建显示好了,每次左击时都会出现一个新创建的弹框,接下来就需要隐藏之前出现的,如何拿到之前的弹框呢?那么就需要一个全局参数 currentMenu: null 记录当前菜单,用于判断是否存在菜单并使用 removeChild 方法删除子节点。

            这里分为两种情况使用清除,一是每次左击时清除之前被左击显示的菜单;二是点击菜单里的某项子盒子时清除盒子。清除逻辑都差不多,只不过需要分情况调用而已。

            左击方法的全部代码

            chartLeftEvent(chart) {      chart.on("click", (params) => {        console.log("params", params);        if (this.currentMenu && this.currentMenu.parentNode === document.body) {          document.body.removeChild(this.currentMenu); // 清除之前的菜单元素        }        const menu = document.createElement("p");// 创建一个新的 p 元素,并将其赋给名为 menu 的常量        menu.classList.add("custom-menu");// 为新创建的 p 元素添加一个自定义样式类名 "custom-menu"        // 使用模板字符串设置 p 元素的内联样式,动态确定菜单的位置        menu.style.cssText = `    left: ${params.event.event.pageX}px;    top: ${params.event.event.pageY}px;  `;  // 将创建好的 p 元素添加到页面的 body 元素中,显示出菜单        document.body.appendChild(menu);        const menuItem1 = document.createElement("p");        menuItem1.className = "menu-item";        menuItem1.style.cssText = `          border-radius: 0px 10px 0px 0px;        `;        menuItem1.innerText = "查看具体信息1";        menuItem1.onclick = () => {          console.log("查看工步信息");          if (this.currentMenu && this.currentMenu.parentNode === document.body) {            document.body.removeChild(this.currentMenu); // 清除之前的菜单元素          }        };        menu.appendChild(menuItem1);        const menuItem2 = document.createElement("p");        menuItem2.className = "menu-item";        menuItem2.style.cssText = `          border-radius: 0px 0px 0px 10px;        `;        menuItem2.innerText = "查看具体信息2";        menuItem2.onclick = () => {          console.log("查看人员信息");          if (this.currentMenu && this.currentMenu.parentNode === document.body) {            document.body.removeChild(this.currentMenu); // 清除之前的菜单元素          }        };        menu.appendChild(menuItem2);        this.currentMenu = menu; // 保存当前菜单元素      });    },

            鼠标右击事件(contextmenu)

            逻辑代码部分

            chart.getZr().on 与 chart.on

            在 echarts 中,chart.getZr().on 与 chart.on 的区别主要在于事件绑定的对象和事件触发的时机:

            chart.on与chart.getZr().on的区别:

            chart.on: 这种方式是在 echarts 实例上直接绑定事件监听器。通过 chart.on 可以监听 echarts实例上的特定事件,如鼠标点击图表、图例切换等。这种方式适用于监听 echarts 提供的交互事件,如点击图表某个系列时触发的事件。

            chart.getZr().on: 这种方式是直接在 echarts 实例的底层渲染容器(即 ZRender 实例)上绑定事件监听器。通过chart.getZr() 可以获取到 ZRender 实例,然后使用 .on 方法可以在 ZRender 实例上监听各种原生 DOM事件,如鼠标点击、移动等。这种方式可以实现更加底层的事件监听,对 echarts 渲染的交互细节进行定制。

            总体来说,使用 chart.getZr().on 可以监听更加底层的原生 DOM 事件,而 chart.on 则用于监听 echarts 封装的图表交互事件。这里的左击事件用的chart.on,右击事件用的chart.getZr().on ,大家都可以感受一下。

            隐藏鼠标右击后的默认行为

            右击图表示默认会显示下图这个菜单,所以需要通过preventDefault方法阻止默认右击事件

            右击方法的全部代码

            chartRightEvent(chart) {      // 使用箭头函数      chart.getZr().on("contextmenu", (params) => {        params.event.preventDefault(); // 取消默认右击事件        if (this.currentMenu && this.currentMenu.parentNode === document.body) {          document.body.removeChild(this.currentMenu); // 清除之前的菜单元素        }      });    },

            源码

             
            ....data() {    return {     currentMenu: null, // 保存当前显示的菜单元素   };},mounted() {    this.updateChartData();  }, methods: { // 柱状图    updateChartData() {      var xdata = [        "ABCD01-01",        "ABCD01-02",        "ABCD01-03",        "ABCD01-04",        "ABCD01-05",        "ABCD01-06",        "ABCD01-07",        "ABCD01-08",        "ABCD01-09",        "ABCD01-10",        "ABCD01-11",        "ABCD01-12",        "ABCD01-13",        "ABCD01-14",        "ABCD01-15",        "ABCD01-16",        "ABCD01-17",        "ABCD01-18",        "ABCD01-19",        "ABCD01-20",        "ABCD01-21",        "ABCD01-22",        "ABCD01-23",        "ABCD01-24",      ];      var ctdata = [        21,        18,        34,        31,        22,        18,        18,        18,        18,        18,        18,        18,        21,        15,        34,        31,        22,        18,        18,        18,        18,        18,        18,        18,      ];      var stdata = [        20.5,        15,        31,        31,        18,        9,        9,        9,        9,        9,        9,        9,        20.5,        15,        31,        31,        18,        9,        9,        9,        9,        9,        9,        9,      ];      var bgdata = [        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,        10,      ];      var maxValue = 34; //最大秒数      var maxCenterName = "ABCD01-03"; //最大秒数对应的工站      var threshold = 8; //差值      const chartDom = document.getElementById("barChart");      const chart = echarts.init(chartDom, "dark");      var option;      option = {        backgroundColor: "transparent",        // 预设颜色优先级低于series里定义的颜色,所以象形柱图不会被污染        color: [          {            type: "linear",            x: 0,            y: 1,            x2: 0,            y2: 0,            colorStops: [              {                offset: 0,                color: "rgba(204, 218, 234,0)", // 0% 处的颜色              },              {                offset: 1,                color: "rgba(204, 218, 234,1)", // 100% 处的颜色              },            ],          },          {            type: "linear",            x: 0,            y: 1,            x2: 0,            y2: 0,            colorStops: [              {                offset: 0,                color: "rgba(93, 207, 207,0)", // 0% 处的颜色              },              {                offset: 1,                color: "rgba(93, 207, 207,1)", // 100% 处的颜色              },            ],          },        ],        grid: {          left: "3%",          right: "6%",          bottom: "15%",        },        legend: {          orient: "vertical", // 设置图例垂直排列          right: 10, // 调整图例距离右侧的距离          top: "top", // 设置图例位于上方          itemWidth: 10, // 设置宽度          itemHeight: 10, // 设置高度          textStyle: {            color: "#fff",          },        },        xAxis: [          {            type: "category",            axisTick: {              show: false,            },            data: xdata,            axisLabel: {              show: true,              color: "#ffffff",            },            axisLabel: {              show: true,              color: "#ffffff",              fontSize: 12, // 设置字体大小为12            },          },          {            type: "category",            show: false,            data: this.xAxisData_,          },        ],        yAxis: [          {            type: "value",            name: "second",            min: 0,            max: 40,            splitNumber: 5,            nameTextStyle: {              //y轴上方单位的颜色              color: "#fff",            },            splitLine: {              lineStyle: {                color: "rgba(133, 139, 145,0.3)",              },            },            axisLabel: {              show: true,              color: "#ffffff",            },          },          {            type: "value",            alignTicks: true,            show: false,          },          {            type: "value",            show: false,          },        ],        dataZoom: [          {            type: "slider", // 设置为滑动条            show: true, // 显示滑动条            start: 0, // 滑动条起始位置            end: 100 / (12 - 10) - 1, // 滑动条结束位置            bottom: 10, // 滑动条距离底部的距离            textStyle: {              color: "#fff",            },            backgroundColor: "#acb7c3", // 设置背景颜色            handleStyle: {              color: "#2a82e4", // 设置左右两边的可滑动收缩竖线颜色            },          },        ],        series: [          {            name: "DATA1",            data: ctdata,            type: "bar",            barWidth: 10,            barGap: 1, //柱子之间间距            yAxisIndex: 0,            z: 2,            label: {              show: true,              position: "top",              color: "white",            },            // 标记线配置            markLine: {              data: [                {                  yAxis: maxValue, // 最大值的纵坐标                  label: {                    show: true,                    position: "end",                    formatter: "瓶颈CT:" + maxValue + "s\n" + maxCenterName, // 标记线的标签                    textStyle: {                      color: "red",                    },                  },                  lineStyle: {                    type: "dashed", // 设置为虚线                    color: "red", // 标记线的颜色                  },                  symbol: ["none", "arrow"], // 取消箭头样式                  silent: true, // 取消鼠标悬浮时的高亮效果                },              ],            },          },          {            name: "DATA2",            data: stdata,            type: "bar",            barWidth: 10,            yAxisIndex: 1,            z: 2,            label: {              show: true,              position: "top",              color: "#66e1df",            },          },          {            data: bgdata,            type: "bar",            barWidth: 55,            yAxisIndex: 2,            xAxisIndex: 1,            z: 1,            itemStyle: {              normal: {                color: function (params) {                  var ctValue = ctdata[params.dataIndex];                  var stValue = stdata[params.dataIndex];                  if (Math.abs(ctValue - stValue) > threshold) {                    return "rgba(102, 77, 107,0.6)";                  } else {                    return "rgba(0,0,0,0.16)";                  }                },              },            },          },        ],      };      option && chart.setOption(option);      this.chartRightEvent(chart);      this.chartLeftEvent(chart);    },    chartRightEvent(chart) {      chart.getZr().on("contextmenu", (params) => {        params.event.preventDefault(); // 取消默认右击事件        // 使用箭头函数        if (this.currentMenu && this.currentMenu.parentNode === document.body) {          document.body.removeChild(this.currentMenu); // 清除之前的菜单元素        }      });    },    chartLeftEvent(chart) {      chart.on("click", (params) => {        console.log("params", params);        // let xIndex = chart.convertFromPixel({ seriesIndex: 0 }, [        //   params.offsetX,        //   params.offsetY,        // ])[0]; // 阴影索引值        // console.log("xIndex", xIndex);        if (this.currentMenu && this.currentMenu.parentNode === document.body) {          document.body.removeChild(this.currentMenu); // 清除之前的菜单元素        }        const menu = document.createElement("p");        menu.classList.add("custom-menu"); // 添加自定义样式类名        menu.style.cssText = `    left: ${params.event.event.pageX}px;    top: ${params.event.event.pageY}px;  `;        document.body.appendChild(menu);        const menuItem1 = document.createElement("p");        menuItem1.className = "menu-item";        menuItem1.style.cssText = `          border-radius: 0px 10px 0px 0px;        `;        menuItem1.innerText = "查看具体信息1";        menuItem1.onclick = () => {          console.log("查看工步信息");          if (this.currentMenu && this.currentMenu.parentNode === document.body) {            document.body.removeChild(this.currentMenu); // 清除之前的菜单元素          }        };        menu.appendChild(menuItem1);        const menuItem2 = document.createElement("p");        menuItem2.className = "menu-item";        menuItem2.style.cssText = `          border-radius: 0px 0px 0px 10px;        `;        menuItem2.innerText = "查看具体信息2";        menuItem2.onclick = () => {          console.log("查看人员信息");          if (this.currentMenu && this.currentMenu.parentNode === document.body) {            document.body.removeChild(this.currentMenu); // 清除之前的菜单元素          }        };        menu.appendChild(menuItem2);        this.currentMenu = menu; // 保存当前菜单元素      });    },    }
            /* echarts图表样式 */.custom-menu {  position: absolute;  width: 130px;  box-shadow: rgb(0 0 0 / 30%) 1px 1px 3px;  z-index: 999;  background: rgb(69 140 199 / 80%);  border: none;  border-radius: 0px 10px 0px 10px;  color: #fff;  display: flex;  flex-direction: column;  align-items: center;}.menu-item {  padding: 5px 0px;  cursor: pointer;  width: 100%;  display: flex;  justify-content: center;}.menu-itemborder1 {  border-radius: 0px 10px 0px 0px;}.menu-itemborder2 {  border-radius: 0px 0px 0px 10px;}.menu-item:hover {  background-color: #a2bbda;}

上一篇:恐龙岛服务器怎么买?

下一篇:前端调用后端接口,导出excel文件打开显示[object object]