3dmax如何显示参考图_读者提问,如何让 tooltip 提示框内显示饼图

79b1c08df03e075a6439ab82e2173a28.png

b07a1f03c061e48045bb2d2dccb2cd18.png
效果截图

前些天有读者问,ECharts 的提示框(tooltip)内,能不能添加一个饼图?

我之前倒是看到过用饼图作为散点图数据点的例子,感觉应该有办法……但是提示框和那个不太一样,估计需要研究一下——所以先回复说,这个之前没有尝试过,我有空试一下。

实现思路(一段曲折的过程)

当天晚上有事,没来及看,转天上班途中,先看了眼配置项手册,在确认没有现成功能可用的同时,注意到了一个关键点:提示框是一个 DOM 节点,也就是有办法作为 ECharts 的容器。

浮层的渲染模式,默认以 'html 即额外的 DOM 节点展示 tooltip;此外还可以设置为 'richText' 表示以富文本的形式渲染,渲染的结果在图表对应的 Canvas 中(目前 SVG 尚未支持富文本),这对于一些没有 DOM 的环境(如微信小程序)有更好的支持。 「ECharts 配置项手册」 https:// echarts.apache.org/zh/o ption.html#tooltip.renderMode

另外,其实从「tooltip.formatter」默认的换行符是「<br />」而不是「n」这一个特点上,也可以推测得到的。

有了这个关键点,大体的思路就有了:

  • 通过回调函数返回一个带 id 属性的 div,比如
<div id="tooltipPie" style="width: 100px;height:100px;"></div>
  • 以这个 div 为容器,初始化 ECharts 实例;
  • 根据触发提示框的 params 属性,准备相应的饼图配置项,渲染对应的饼图

3d8b393128cb91a179dc46cf550953ea.png
大体思路图示

但是还存在一个问题需要解决,这个问题有 2 个难点:

  • 在提示框首次弹出之前,带 id 的 div(回调函数返回的「饼图容器」)是不存在的,而且每次触发提示框显示/移动,这个 div 会被覆盖,也就是渲染好的「canvas」元素会消失——所以每次触发 tooltip,都需要重新渲染饼图;

98fb06758a5bc0304985eff6f1fec47c.png
问题 1
  • 从ECharts API 看,提示框的显示、隐藏,并没有事件可供监听,也没办法把这个动作加到「tooltip.formatter」的回调函数中,因为「问题 1」的覆盖,发生在函数返回结果之后。

为了解决这个问题,我想到了 2 种尝试的思路:

  1. 通过监听「events.finished」事件,主图表渲染动作完成后,如果存在提示框饼图的容器(div),则触发饼图的重新渲染;
  2. 通过回调函数的嵌套,在「tooltip.formatter」的回调函数中,再嵌一个 callback,加一定延时后渲染饼图。

然后我就开始尝试有可能最简单的第 1 种,结果发现提示框中的饼图时有时无……然后经过各种分析,打点、测试、翻源码(其实没咋看懂= =b),明白了大致原因:

提示框(tooltip)的移动,不触发「events.finished」事件,也就是当提示框指示的数据项/数据轴没发生改变时,提示框发生了「move」,而不是先「hide」再「show」

  • 「tooltip.formatter」的回调函数执行,提示框层(div)的位置变了,提示框里的饼图没了(回调函数 return 了新的「饼图容器」);
  • 「events.finished」事件没有发生,新的饼图没有补上……

第 1 种思路尝试失败-_-b

然后开始试图尝试第 2 种,但作为一个先接触 ECharts 后接触 JavaScript 的 JS 小白,我毫无悬念地、稀里糊涂地失败了TAT

各位前端大神们,有兴趣的话,可以亲自尝试一下,我就不班门弄斧了……

被 callback 虐了半天的自己,郁闷了 10 多分钟……然后终于,自暴自弃地,想到了简单暴力的第 3 种方法:

  • 通过「setInterval」每隔一段时间(比如 10 毫秒),判断是否存在提示框饼图的空容器(div),如存在则触发饼图的重新渲染。
// 准备一个饼图的 option
let pieOption = {
    series: {
        type: "pie",
        labelLine: {
            show: false
        },
        label: {
            show: false 
        }
    },
    animation: false
};

option = {
    title: {
        text: '读者提问,提示框能否显示饼图'
    },
    xAxis: {
        data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
    },
    yAxis: {},
    tooltip: {
        trigger: 'axis',
        formatter: params => {
            // 根据触发提示框的数据,准备饼图数据
            let pieData = [];
            for (let i in params) {
                pieData.push({
                    name: params[i].seriesName,
                    value: params[i].value,
                    color: params[i].color
                });
            }
            
            // 将饼图数据存入饼图 option.series.data
            pieOption.series.data = pieData;
            return `${params[0].axisValue}<br/><div id="tooltipPie" style="width: 100px;height:100px;"></div>`;
        }
    },
    series: [{
        type: 'bar',
        stack: 'stack1',
        data: [220, 182, 191, 234, 290, 330, 310]
    }, {
        type: 'bar',
        stack: 'stack1',
        data: [120, 122, 91, 324, 113, 130, 410]
    }, {
        type: 'bar',
        stack: 'stack1',
        data: [42, 32, 29, 72, 31, 63, 101]
    }]
};


/**
 * 因为每次弹出/移动提示框,都会覆盖提示框 DOM,所以只能每次都重新渲染饼图
 * (暂且使用了个笨办法 setInterval,10 毫秒判断处理一次 = =b,有时间再想想更好的方式)
 */
setInterval(function(){
    if (document.getElementById('tooltipPie') !== null && document.getElementById('tooltipPie').innerHTML === '') {
        if (typeof tooltipChart !== 'undefined') {
            return tooltipChart.setOption(pieOption);
        }
        var tooltipChart = echarts.init(document.getElementById("tooltipPie"));
        tooltipChart.setOption(pieOption);
    }
},10);

就是这段,每隔 10 毫秒,检测一次提示框饼图容器的内部是否为空,如果是,就重新渲染一遍饼图,这次算是非常不优雅的成功了-_-o

点击查看 ECharts Gallery 例子​gallery.echartsjs.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值