echarts 气泡图-非重叠均匀分布气泡图解决方案(基于echarts)_echarts气泡图_河

气泡图是数据可视化需求中常见的图表形式。 但到目前为止,echarts、d3、higncharts还没有直接提供配置来完成不重叠且均匀分布的气泡图的工作。 幸运的是,我们可以通过配置echart的关系图来完成我们的气泡图需求。

以下是气泡图完成后的效果(数据加载后有动画效果,但气泡支持拖动,下面动画不和谐的部分是键盘拖动):

最终稳定后的疗效如下:

为了有更好的适用性,将绘制气泡图的操作封装在一个函数中。 以Vue项目为例,完成这个气泡图的配置需要的步骤如下:

1:从npm下载echarts模块。

2:在main.js文件中引入关系图相关的模块echarts 气泡图,将echart的主模块与Vue原型对象绑定,方便后续调用。 代码如下:

// 引入 EChart 主模块
let echarts = require('echarts/lib/echarts')
// 引入图表
require('echarts/lib/chart/graph');
Vue.prototype.$chart = echarts

3:编译气泡图的配置函数,具体代码如下:

    // 入参说明: 
    // 1. data 原始气泡数据,是一个对象数组,形如[{name: '可乐', amount: 49}]
    // 2. format 数组依次指定气泡中展示的名称以及影响气泡大小的数据值, 形如['name', 'amount']
    // 3. dom 气泡图绘制所需要的dom id名
    initBubbleChart (data = [], format = [], dom) {
      let [maxValue, temp] = [0, []]
      data.forEach(item => {
        temp.push(item[format[1]])
      })
      maxValue = Math.max.apply(null, temp)
      // 气泡颜色数组
      let color = [
        '#FFB600', '#886CFF', '#0084FF',
        '#4CB690','#58B458', '#6C6C6C',
        '#F56161', '#FC754C','#5F5EEC'
      ]
      // 气泡颜色备份
      let bakeColor = [...color]
      // 气泡数据
      let bubbleData  = []
      // 气泡基础大小
      let basicSize = 70
      // 节点之间的斥力因子,值越大,气泡间距越大
      let repulsion = 380
      // 根据气泡数量配置基础大小和斥力因子(以实际情况进行适当调整,使气泡合理分布)
      if (data.length >= 5 && data.length = 10 && data.length = 20) {
        basicSize = 30
        repulsion = 75
      }
      // 填充气泡数据数组bubbleData
      for (let item of data) {
        // 确保气泡数据条数少于或等于气泡颜色数组大小时,气泡颜色不重复
        if (!bakeColor.length) bakeColor = [...color]
        let colorSet = new Set(bakeColor)
        let curIndex = Math.round(Math.random()*(colorSet.size - 1))
        let curColor = bakeColor[curIndex]
        colorSet.delete(curColor)
        bakeColor = [...colorSet]
        // 气泡大小设置
        let size = (item[format[1]] * basicSize * 2) / maxValue
        if (size < basicSize) size = basicSize
        bubbleData.push({
          "name": item[format[0]],
          "value": item[format[1]],
          "symbolSize": size,
          "draggable": true,
          "itemStyle": {
              "normal": {"color": curColor}
          }
        })
      }
      let bubbleId = document.getElementById(dom)
      let bubbleChart = this.$chart.init(bubbleId)
      let bubbleOptions = {
          backgroundColor: '#fff',
          animationEasingUpdate: 'bounceIn',
          series: [{
              type: 'graph',
              layout: 'force',
              force: {
                  repulsion: repulsion,
                  edgeLength: 10
              },
              // 是否开启鼠标缩放和平移漫游
              roam: false,
              label: {normal: {show: true}},
              data: bubbleData
          }]
      }
      bubbleChart.setOption(bubbleOptions)
    }

4:在模板中添加标签,提供气泡图所需的dom,如下图:

5:打算测试数据,调用initBubbleChart方法,如下:

let data = [
  {label: '可乐', amount: 100},
  {label: '雪碧', amount: 70},
  {label: '土豆', amount: 30},
  {label: '饼干', amount: 50}
]
this.initBubbleChart(data, ['label', 'amount'], 'bubble')

完成后就可以看到初期的疗效。 这里绘制气泡图的方法可以根据指定气泡数据中的某个值相对设置气泡的大小,同时还支持自定义气泡的颜色。 (不建议使用随机函数来获取气泡的颜色,因为这样的随机颜色组合大多很难搭配,所以建议自己挑选颜色,或者让UI给你8或9种颜色,这样整个气泡图就会有更好的疗效展示)。

下面我们看一下,不同气泡数据量下的疗效图(气泡底面大小、宽度、颜色可以自己定义):

随着气泡数量的增多,里面的整体疗效还是可以接受的。 同时,你也可以听到,气泡中的数据量不能太多echarts 气泡图,否则会变得更加拥挤。 关于echarts关系图的更多配置,可以前往echarts官网。 这个非重叠且均匀分布的气泡图解决方案介绍到此结束。 如有疑问,请在博客下方留言。

✍需求背景

在日常开发中,我们经常会遇到需要使用图表的地方。 Echarts图表库是一个流行的图标库。 在使用过程中,我们会遇到一些问题。 分享一个我遇到的值得记录的问题。 :

在开发图表需求时,经常需要图表适应页面,而在使用Echarts时,会遇到这样的问题:

当我将图表的宽度设置为50%时,发现上面的元素无法识别%,会渲染为px,即50px。

✔解决方案:

网上查了很多资料,据说源代码很难识别。 之后,我需要动态获取它。 后来自己测试了一下,发现好像可以设置,但是长度没有拉伸的原因是在echarts图表init的时候。 Parent 元素还没有长度,比如标签页,比如一些特殊的页面。 事实上,如果要适配比例echarts图表自适应echarts图表自适应,需要在父元素有长度时进行初始化。 这里可以使用nextTick进行处理。

✨小贴士:

不过仅仅初始化似乎无法满足自适应页面的需求,我们可以结合

echart 提供的 resize() 和 window.addEventListener('resize', fn) 实现。

请记住使用 this.$once('hook:beforeDestroy') 来销毁窃听。

相关代码:

    // 自适应
    const handler = () => echart.resize()
    window.addEventListener('resize', handler)
    this.$once('hook:beforeDestroy', () => {
        window.removeEventListener('resize', handler)
    })