echarts实现气泡图(气泡之间不叠加)

2023-11-17

前言:echarts本身是有气泡图的,官方气泡图的特点是每个气泡的位置是基于坐标轴进行定位,如图1和2所示。但是本文所介绍的气泡图并不是官方所介绍的气泡图,而是一类区别于官方的图表类型,这种图表类型通常采用d3.js插件实现,如图3所示。从图1、图2、图3可以看出两种气泡图的展示,各有其特点。图1和图2,虽然是基于坐标轴,但气泡图之间容易叠加在一起。图3所示的气泡图则没有这个缺点,气泡之间互相相邻,彼此之间各不侵犯。众多周知,d3.js主要是svg技术实现的图表插件,而Echarts则主要是基于canvas画布技术实现的。两者之间虽然互相没有关联,但实现的算法确是可以参考和借鉴的。

这里写图片描述

官方气泡图1

这里写图片描述
官方气泡图2

这里写图片描述
d3气泡图

实现思路:通过研究d3.js气泡图的代码构建过程,我发现其实现的核心主要在于计算每一个气泡的x、y、r,这三个跟气泡生成相关的属性值,只要把这三个属性值求出来了,那么问题自然就可以解决了。然后采用Echarts插件配置项中的graphic接口,添加circle和text类型元素,就可以渲染成一个个气泡。

具体实现
(1)求解每一个气泡的x、y、r属性。这个工作很麻烦,涉及的算法,也挺复杂的。通过研究d3.js,我发现其求解每一个气泡的属性代码就有500多行。主要是思路是,首先构建一个所有气泡的根气泡(这个根气泡会包含所有的子气泡,但不会在页面上渲染出来,它主要作用是定位和布局),接着求解每一个气泡的x、y、r的值,特别指出的是每一个气泡的半径r,是通过其值得开根号求出的,最后根据根气泡的信息和渲染区域大小再判断是否要缩放气泡(即缩放x、y、半径r)。具体的求解代码如下所示,其中有两个重要的函数echarts.util.pack和echarts.util.hierarchy,这两个接口是求解气泡属性的关键,具体的实现源码,我已从d3.js插件里面将其独立出来了。如果大家想了解,可以到此处下载。压缩出来的文件中,bubbleUtil.js有详细源码。下载地址:http://download.csdn.net/download/mulumeng981/10023337

    /**
       * 获取气泡图的根气泡和各气泡的属性:颜色、坐标位置(x,y)、半径(r)
       * @param {Function}  data: 初始化数据
       * @param {Function}  pack: 布局函数
       * @return {Array} 气泡信息集合            
    */
    function processBubbleData(data, container) {
        var width = container.style.width.replace('px', '');
        var height = container.style.height.replace('px', '');
        //初始化气泡图显示的布局(主要是宽度和高度) 
        var pack = echarts.util.pack()
        .size([width, height])
        .padding(1);

        var index = 0;              
        var color = ["#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5",          
        "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5"];  

        var root = echarts.util.hierarchy({children: data})
                   .sum(function(d) { return d.value; })
                   .each(function(d){
                       d.color = color[index % 20];
                       index++;
                       return d.color;
                   });

        return pack(root).leaves(); 
    }

(2)使用Echarts插件渲染气泡图。
众所周知,Echarts插件的配置主要是option的配置,而气泡图的配置主要是option中graphic接口的配置。而本文在设计中将一个气泡和其相关的文本看成一个集合。如下所示是具体实现源码。

    /**
       * 绘制Echarts图表
       * @param {Object} container: dom实例
    */
    function drawChart(chart, bubbleData) {                                                         
        var option = {
             tooltip: {
                show: true,
                triggerOn: 'none',
                formatter: function (params) {
                    return '<span  style="border-radius: 6px;width: 12px;height: 12px;display: inline-block;background-color:' + params.color +'"></span>' + ' ' +  params.data.name + ':  ' + params.data.value;
                }
            },
            graphic: getCircleOption(bubbleData, chart),
            series: []
        };          
        chart.setOption(option);
    }

    /**
       * 获取气泡的graphic配置项
       * @param {Array} processData: 气泡的属性信息集合
       * @param {Object} chart: echarts实例
       * @return {Array}  配置项集合
    */          
    function getCircleOption(processData, chart) {
         return echarts.util.map(processData, function (item, dataIndex) {
            return {
                type: 'group',
                id: 'circleGroup' + dataIndex,
                bounding: 'raw',
                color: item.color,
                data: item.data,    
                children: getChildOption(item, dataIndex, chart),                           
                onmousemove: function (event) {
                    showTooltip.call(this, event, chart);                                                   
                },
                onmouseout: function (event) {                       
                    hideTooltip.call(this, event, chart);
                }
            };
        });                             
    }
    /**
       * 得到各个气泡和文本节点配置信息
       * @param {Object} item: 气泡的属性信息
       * @dataIndex {Number} dataIndex: 气泡的序号
       * @param {Object} chart: echarts实例
       * @return {Array} children: 配置项集合
    */
    function getChildOption(item, dataIndex, chart) {
        var children = [];
        children.push({
            id: 'circle' + dataIndex,
            type: 'circle',
            shape: {
                cx: item.x,
                cy: item.y,
                r: item.r 
            },
            name: 'mainElem',
            style: {
                fill: item.color
            },
            eventData: {
                id: 'circle' + dataIndex
            },
            onclick: bindClickEvent         
        });
        children.push({                   
            type: 'text',                   
            style: {
                fill: '#fff',
                text: item.data.name,
                x: item.x - item.r / 4,
                y: item.y
            },
            value: item.value
        });
        return children;
        /**
           * 气泡绑定click事件
        */
        function bindClickEvent() {
            var circle = new echarts.graphic.Circle({
               shape: this.shape,
               style: {
                   stroke: 'green',
                   fill: null,
                   lineWidth: 2     
               }
            });
            this.parent.add(circle);
            chart.addClickElem(circle);
        }
    }

(3)配置每一个气泡的提示框
Echarts是有提示框组件的,叫tooltip,显示和隐藏的时候调用的接口都是dispatchAction,只是传递的参数不一样而已。

**显示提示框。**
有下面两种使用方式。
1 指定在相对容器的位置处显示提示框,如果指定的位置无法显示则无效。
dispatchAction({
    type: 'showTip',
    // 屏幕上的 x 坐标
    x: number,
    // 屏幕上的 y 坐标
    y: number,
    // 本次显示 tooltip 的位置。只在本次 action 中生效。
    // 缺省则使用 option 中定义的 tooltip 位置。
    position: Array.<number>|string|Function
})

2 指定数据图形,根据 tooltip 的配置项显示提示框。

dispatchAction({
    type: 'showTip',
    // 系列的 index,在 tooltip 的 trigger 为 axis 的时候可选。
    seriesIndex?: number,
    // 数据的 index,如果不指定也可以通过 name 属性根据名称指定数据
    dataIndex?: number,
    // 可选,数据名称,在有 dataIndex 的时候忽略
    name?: string,
    // 本次显示 tooltip 的位置。只在本次 action 中生效。
    // 缺省则使用 option 中定义的 tooltip 位置。
    position: Array.<number>|string|Function,
})

**隐藏提示框。**
dispatchAction({
    type: 'hideTip'
})

针对本文的情况,主要采用的是显示的第一个接口,由于本文没有采用配置项中的series属性,故采用显示框的第一种方法,如下代码所示。特别注意的是formatterParams参数的配置,一定要有,不然就无法显示出提示框。

    /**
       * 利用dispatchAction函数显示每个气泡信息
       *@param {Object} event 
       *@param {Object} chart: echarts instance
    */
    function showTooltip(event, chart) {
        chart.dispatchAction({
            type: 'showTip',
            // 屏幕上的 x 坐标
            x: event.offsetX,                   
            // 屏幕上的 y 坐标
            y: event.offsetY,
            tooltip: {
                formatterParams: {
                    color: this.color,
                    data: this.data
                }                       
            }                   
        }); 
        //显示气泡的边界条纹             
        this.childOfName('mainElem').setStyle({
             stroke: 'green',
             lineWidth: 2                                
        });                 
    }
    /**
      * 隐藏提示框
      *@param {Object} event 
      *@param {Object} chart: echarts instance
    */
    function hideTooltip(event, chart) {
        chart.dispatchAction({
            type: 'hideTip'
        });             
        this.childOfName('mainElem').setStyle({
             stroke: null                        
        });
    }

(4)绑定有利于用户操作的事件,如点击气泡图,气泡边缘变绿色等。

    /**
      * 图表添加事件处理函数
      * @param {Object} chart: echarts实例
    */
    function bindChartEvent(chart) {
        //点击气泡后的回调
        chart.addClickElem = function (elem) {
            if (this.currentElem !== elem && this.currentElem != null) {
                this.currentElem.parent.remove(this.currentElem);           
            }
            this.currentElem = elem;
        };  

        //点击canvas中非气泡部分                
        chart._zr.on('click', function (params) {
            if(params.target == null) {
                if (chart.currentElem != null) {
                    chart.currentElem.parent.remove(chart.currentElem); 
                    chart.currentElem = null;                       
                }
            }
        });

        //点击页面中非canvas部分
        document.onclick = function (event) {
            if (event.toElement.tagName != 'CANVAS') {
                if (chart.currentElem != null) {
                    chart.currentElem.parent.remove(chart.currentElem); 
                    chart.currentElem = null;                       
                }
            }
        };
    }

总结: 以上就是气泡图实现的主要代码,难点主要是气泡属性信息的计算,这一块主要采用的是d3.js的算法,本人主要是作为一个代码的搬运工,将其从d3.js中独立出来,并嵌入到Echarts中。详细的demo,大家可下载此处:http://download.csdn.net/download/mulumeng981/10023337,本人已将其封装成有一个插件,只要按要求传递参数,即可生成气泡图。如图4所示。

        require(['bubbleUtil'],function(bubbleUtil){
            var data = [ 
                {"name":"黄瓜", "value":12345},
                {"name":"猕猴桃", "value":7345},
                {"name":"红提", "value":1345},
                {"name":"枣子", "value":2345}, 
                {"name":"火龙果", "value":345}, 
                {"name":"葡萄", "value":14534},
                {"name":"橘子", "value":9435} ,
                {"name":"柚子", "value":134} ,
                {"name":"桃子", "value":6346} ,
                {"name":"西红柿", "value":634} ,
                {"name":"梨子", "value":6346} ,
                {"name":"苹果", "value":3644} ,
                {"name":"香蕉", "value":2346} ,
                {"name":"小明", "value":3869} ,
                {"name":"小米", "value":6534} ,
                {"name":"大米", "value":45} ,
                {"name":"玉米", "value":8345}             
            ];  

            bubbleUtil(data, document.getElementById('container'));         
        });

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

echarts实现气泡图(气泡之间不叠加) 的相关文章

随机推荐

  • 无需GPU无需网络“本地部署chatGPT”(更新StableVicuna)

    想当初图像生成从DELL到stable diffusion再到苹果的移动部署过了两三年吧 聊天bot才发展几个月就可以边缘部署了 如果苹果更新silicon npu和运存翻倍 争取apple watch也能本地内置 最快ios18 mac
  • Apache网页优化压缩步骤

    Apache网页与安全优化 Apache网页优化 1 网页压缩 2 网页缓存 Apache安全优化 1 配置防盗链 2 隐藏版本信息 Apache 网页 优化概述 1 在企业中 部署Apache后只采用默认的配置参数 会引发网站很多问题 换
  • Python笔记:操作ndarray元素:访问、删除、插入

    引入 import numpy as np 在此引入一次 下面直接使用 np 访问ndarray元素 x np array 1 2 3 4 5 print print x x print print This is First Elemen
  • 《UnityAPI.Animation动画》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+Animation+AddClip+CrossFade+立钻哥哥++OK++)

    UnityAPI Animation动画 版本 作者 参与者 完成日期 备注 UnityAPI Animation V01 1 0 严立钻 2020 06 23 UnityAPI Animation动画 发布说明 UnityAPI Anim
  • Android——单选多选按钮的使用详解

    button1 Button findViewById R id button1 button2 Button findViewById R id button2 button1 setOnClickListener this button
  • java学习总结——protobuf3的语法

    本文主要讨论protobuf3在编写proto接口描述文件时的语法 下面是一个proto文件的实例 syntax proto3 import address proto package com study blog protobuf opt
  • [激光原理与应用-40]:《光电检测技术-7》- 常见光干涉仪及其应用

    目录 第1章 干涉仪概述 1 1 什么是干涉仪 1 2 基本原理 1 3 分类 1 4 应用 1 5 干涉仪的类型 第2章 常见光干涉仪 2 1 迈克尔逊干涉仪 2 2 泰曼 格林干涉仪 2 3 移相干涉测量仪 2 4 菲索共路干涉仪 第1
  • vue+webpack5:If you want to include a polyfill, you need to

    升级 vue cli 5 0 1 发现 const path require path 异常 发现默认webpack 是 提示v5区别于v4不再自动引入Polyfills 需要手动添加 按照控制台提示 1 安装path browserify
  • mysql不包含模糊查询

    包含like 不包含not like select from 数据库表 where HouseName like 江门奥园项目 and HouseName like 幢 and HouseName not like 商 不包含not in
  • jupyter修改文件目录和虚拟环境

    在我们安装完jupyter的时候 他是默认为根目录的 我们想切换到我们自己创建的文件目录中该怎么做呢 请看下面步骤 一 切换文件目录 首先 先在我们要放的目录下创建一个文件夹 如 我的为 F Jupyter 在命令行窗口中输入 jupyte
  • cocos2dx 常见的49中动作详解

    bool HelloWorld init 1 super init first if CCLayer init return false CCSprite sp CCSprite create Icon png sp gt setPosit
  • java中的类型赋值常见错误

    Java中float double long类型变量赋值添加f d L尾缀问题 添加尾缀说明 我们知道Java在变量赋值的时候 其中float double long数据类型变量 需要在赋值直接量后面分别添加f或F d或D l或L尾缀来说明
  • JAVA的可变类与不可变类

    可变类和不可变类 Mutable and Immutable Objects 的初步定义 可变类 当你获得这个类的一个实例引用时 你可以改变这个实例的内容 不可变类 当你获得这个类的一个实例引用时 你不可以改变这个实例的内容 不可变类的实例
  • Mybatis批量插入数据的三种方式分享

    转自 Mybatis批量插入数据的三种方式分享 下文笔者讲述Mybatis插入数据的方法分享 如下所示 for循环insert long start System currentTimeMillis for int i 0 i lt 100
  • 结构化思维

    我们在求职时 经常能看到岗位要求上写着 逻辑思维 系统 结构化思维 身为一个直觉的打工仔 面对未来Boss耳提面命的 能力标签 我们怎能视若无睹 逻辑思维 好理解 不就 判断 推理 嘛 可这 结构化思维 是啥 很多人就答不上来了 在理解概念
  • electron ajax路径,electron 文件及文件夹上传的问题探索

    不晓得如今electron最新版的dialog解决了这个问题没有 选择文件夹的时候没有返回文件夹里面全部的文件 而是返回了文件夹的路径 一样的在网页端是能够经过webkitDirectory获取到文件夹下面全部的文件node 我试了不少的方
  • https开头的网址是什么意思_网址是什么意思?基础知识普及

    通俗的理解网址就是常说的URL 是很多个它一起组成了数量庞大形形色色的网站 网址 Uniform Resource Locator 统一资源定位器 是计算机Web网络相关的术语 就是网页地址的意思 我们的互联网世界就是由很多的网址组成 也可
  • 2021-04-06

    开源 开源的概念 开源 一词对应英文 Open Source 最初起源于软件开发领域 因此也称为 开放源代码 对应的软件则称为开源软件 Open Source Software 除了我们熟知的开源软件以外 开源的表现形式还有开源硬件 Ope
  • C++编译器为类自动生成拷贝构造函数的情况

    在一下情况中C 会为类自动生成拷贝构造函数 1 类中有虚函数 这种情况即意味着类的对象中有指向虚函数表的指针 考虑下面的情况 class A private int m a public virtual void ShowVal void
  • echarts实现气泡图(气泡之间不叠加)

    前言 echarts本身是有气泡图的 官方气泡图的特点是每个气泡的位置是基于坐标轴进行定位 如图1和2所示 但是本文所介绍的气泡图并不是官方所介绍的气泡图 而是一类区别于官方的图表类型 这种图表类型通常采用d3 js插件实现 如图3所示 从