D3 二维图表的绘制系列(十九)封闭图

上一篇: 漏斗图 https://blog.csdn.net/zjw_python/article/details/98497967

下一篇: 河流图 https://blog.csdn.net/zjw_python/article/details/98592543

代码结构和初始化画布的Chart对象介绍,请先看 https://blog.csdn.net/zjw_python/article/details/98182540

本图完整的源码地址: https://github.com/zjw666/D3_demo/tree/master/src/enclosureChart/basicEnclosure

1 图表效果

在这里插入图片描述

2 数据

{
    "name": "grandfather",
    "children": [
        {
            "name": "father",
            "children": [
                {
                    "name": "son",
                    "children": [
                        {"name": "grandson1", "house": 2},
                        {"name": "grandson2", "house": 3},
                        {"name": "grandson3", "house": 4}

                    ]
                }
            ]
        },
        {
            "name": "mother1",
            "children": [
                {
                    "name": "daughter1",
                    "children": [
                        {"name": "granddaughter1", "house": 4},
                        {"name": "granddaughter2", "house": 2}
                    ]
                },
                {
                    "name": "daughter2",
                    "children": [
                        {"name": "granddaughter3", "house": 4}
                    ]
                }
            ]
        },
        {
            "name": "mother2",
            "children": [
                {
                    "name": "son1",
                    "children": [
                        {"name": "grandson4", "house": 6},
                        {"name": "granddaughter4", "house": 1}
                    ]
                },
                {
                    
                    "name": "son2",
                    "children": [
                        {"name": "granddaughter5", "house": 2},
                        {"name": "grandson5", "house": 3},
                        {"name": "granddaughter5", "house": 2}
                    ]
                    
                }
            ]
        }

    ]
}

3 关键代码

导入数据

d3.json('./data.json').then(function(data){
....

一些样式参数配置

const config = {
        margins: {top: 80, left: 80, bottom: 50, right: 80},
        textColor: 'black',
        title: '基本封闭图',
        hoverColor: 'white',
        animateDuration: 1000
    }

数据转换,封闭图与矩形树图、树图等都是具有层次的数据结构,因此需要将原始数据转换一下,转换后,运用d3.pack添加布局信息

/* ----------------------------数据转换------------------------  */
    const root = d3.hierarchy(data)
                    .sum((d) => d.house)
                    .sort((a,b) => a.value - b.value);

    const pack = d3.pack()
                    .size([chart.getBodyWidth(), chart.getBodyHeight()])
    
    pack(root);

有了布局信息之后,我们直接就用circle元素渲染一个个圆圈,非常简单

/* ----------------------------渲染圆圈------------------------  */
    chart.renderCircle = function(){
        const groups = chart.body().selectAll('.g')
                                    .data(root.descendants());
                
              groups.enter()
                      .append('g')
                      .attr('class', (d, i) => 'g g-' + i)
                      .append('circle')
                      .attr('class', 'circle')
                    .merge(groups.selectAll('.circle'))
                      .attr('cx', (d) => d.x)
                      .attr('cy', (d) => d.y)
                      .attr('r', (d) => d.r)
                      .attr('fill', (d) => chart._colors(d.depth % 10));
            
              groups.exit()
                      .selectAll('.circle')
                      .transition().duration(config.animateDuration)
                      .attr('r', 0)
                      .remove();     
    }

渲染文本,注意文本长度不要超过圆圈的直径

/* ----------------------------渲染文本标签------------------------  */
    chart.renderText = function(){

        const texts = chart.body().selectAll('.text')
                                    .data(root.descendants());

              texts.enter()
                      .append('text')
                      .attr('class', 'text')
                   .merge(texts)
                      .attr('transform', (d) => 'translate(' + d.x + ',' + d.y + ')' )
                      .text((d) => d.data.name)
                      .attr('stroke', config.textColor)
                      .attr('fill', config.textColor)
                      .attr('text-anchor', 'middle')
                      .text( function(d){
                          if (d.children) return;
                          if (textWidthIsOk(d, this)){
                              return d.data.name;
                          }else{
                              return d.data.name.slice(0,3);
                          }
                        })
        
        // 检测文本长度是否合适
        function textWidthIsOk(d, text){
            const textWidth = text.getBBox().width;
            if (d.r*2 >= textWidth) return true;
            return false;
        }

    }

最后绑定鼠标交互事件,悬停鼠标圆圈变色

/* ----------------------------绑定鼠标交互事件------------------------  */
    chart.addMouseOn = function(){

        d3.selectAll('.g circle')
            .on('mouseover', function(){
                const e = d3.event;
                e.target.style.cursor = 'hand'

                d3.select(e.target)
                    .attr('fill', config.hoverColor);
                
            })
            .on('mouseleave', function(d){
                const e = d3.event;
                
                d3.select(e.target)
                    .attr('fill', chart._colors(d.depth % 10));
            });
    }

大功告成!!!

发布了250 篇原创文章 · 获赞 88 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/zjw_python/article/details/98591118
今日推荐