D3 二维图表的绘制系列(九)基础饼图

D3 二维图表的绘制系列(十)环状饼图 上一篇: 基础饼图 https://blog.youkuaiyun.com/zjw_python/article/details/98214359 下一篇: 南丁格尔图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/artic... 阅读详情

上一篇: 曲线图 https://blog.youkuaiyun.com/zjw_python/article/details/98478578

下一篇: 环形饼图 https://blog.youkuaiyun.com/zjw_python/article/details/98480632

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

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

1 图表效果

在这里插入图片描述

2 数据

date,money
Mon,120
Tue,200
Wed,150
Thu,80
Fri,70
Sat,110
Sun,130

3 关键代码

导入数据

d3.csv('./data.csv', function(d){
    return {
        date: d.date,
        money: +d.money
    };
}).then(function(data){
.....

一些参数样式配置

const config = {
        margins: {top: 80, left: 80, bottom: 50, right: 80},
        textColor: 'black',
        title: '饼图',
        innerRadius: 0,
        outerRadius: 100,
        textOffsetH: 10,
        lineColor: 'black',
        animateDuration: 1000
    }

尺度转换,饼图运用了d3.pie(),其能方便得根据数据计算每个扇形得起始和终止角度

/* ----------------------------尺度转换------------------------  */
    chart.arcAngle = d3.pie()
                    .sort((d,i) => i)
                    .value((d) => d.money);

直接运用d3.arc渲染扇形。注意,如果我们要扇形具有变化得动画效果时,不能直接应用transition的属性d插值,这样会造成扇形变形,因此我们需要运用中间帧函数,并记录上一次扇形的角度,达到过渡效果

/* ----------------------------渲染扇形------------------------  */
    chart.renderSlices = function(){
        const slices = chart.body().append('g')
                            .classed('pie', true)
                            .attr('transform', 'translate(' + chart.getBodyWidth()/2 + ',' + chart.getBodyHeight()/2 + ')')
                            .selectAll('.arc')
                            .data(chart.arcAngle(data));

              slices.enter()
                        .append('path')
                        .attr('class', (d,i) => 'arc arc-' + i)
                    .merge(slices)
                        .attr('fill', (d,i) => chart._colors(i))
                        .transition().duration(config.animateDuration)
                        .attrTween("d", arcTween)

              slices.exit()
                        .remove();

        const arc = d3.arc()
                        .outerRadius(config.outerRadius)
                        .innerRadius(config.innerRadius);

        function arcTween(d){
            let currentArc = this._current;

            if (!currentArc){
                currentArc = {startAngle: 0, endAngle: 0};
            }

            const interpolate = d3.interpolate(currentArc, d);
            this._current = interpolate(1);   //当饼图更新时,从当前角度过渡到新角度

            return function(t){
                return arc(interpolate(t));
            }
        }
    }

渲染扇形没有什么难度,比较麻烦的是文本标签的连线。为了美观,文本标签的连线由一条水平线和一条斜线组成,同时,水平线的长度要根据文字标签所在的角度进行相应的缩短和变长,除此之外还要注意文本标签的text-anchor和水平偏移距离,小于180度,要左对齐,大于180度要右对齐

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

        // ----渲染文本标签-----
        const arc = d3.arc()
                        .outerRadius(config.outerRadius * 2.5)
                        .innerRadius(config.innerRadius);

        const scaleTextDx = d3.scaleLinear()
                                .domain([0, Math.PI/2])
                                .range([config.textOffsetH, config.textOffsetH * 3]);

        const labels = d3.select('.pie')
                            .selectAll('.label')
                            .data(chart.arcAngle(data));

              labels.enter()
                        .append('text')
                        .classed('label', true)
                    .merge(labels)
                        .attr('stroke', config.textColor)
                        .attr('fill', config.textColor)
                        .attr('text-anchor', (d) => {
                            return (d.endAngle + d.startAngle)/2 > Math.PI ? 'end' : 'start';
                        })
                        .attr('dy', '0.35em')
                        .attr('dx', computeTextDx)
                        .transition().duration(0).delay(config.animateDuration)
                        .attr('transform', (d) => {
                            return 'translate(' + arc.centroid(d) + ')'
                        })
                        .text((d) => d.data.date+': '+d.data.money);

                labels.exit()
                        .remove();

        // ----渲染标签连线-----
        const arc1 = d3.arc()
                        .outerRadius(config.outerRadius * 2)
                        .innerRadius(config.innerRadius);

        const points = getLinePoints();

        const generateLine = d3.line()
                                .x((d) => d[0])
                                .y((d) => d[1]);

        const  lines = d3.select('.pie')
                            .selectAll('.line')
                            .data(points);

               lines.enter()
                        .insert('path',':first-child')
                        .classed('line', true)
                    .merge(lines)
                        .transition().duration(0).delay(config.animateDuration)
                        .attr('fill', 'none')
                        .attr('stroke', config.lineColor)
                        .attr('d', generateLine);

                lines.exit()
                        .remove();

        function computeTextDx(d){                      //计算文本水平偏移
            const middleAngle = (d.endAngle + d.startAngle)/2;
            let dx = ''
            if (middleAngle < Math.PI){
                dx = scaleTextDx(Math.abs(middleAngle - Math.PI/2));
            }else{
                dx = -scaleTextDx(Math.abs(middleAngle - Math.PI*3/2));
            }
            return dx;
        }

        function getLinePoints(){                       //生成连线的点
            return chart.arcAngle(data).map((d) =>{
                const line = [];
                const tempPoint = arc.centroid(d);
                const tempDx = computeTextDx(d);
                const dx = tempDx > 0 ? tempDx - config.textOffsetH : tempDx + config.textOffsetH;
                line.push(arc1.centroid(d));
                line.push(tempPoint);
                line.push([tempPoint[0] + dx, tempPoint[1]]);
                return line;
            })
        }
    }

最后为每个扇形都绑定交互事件

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

        const arcLarger = d3.arc()
                            .outerRadius(config.outerRadius * 1.1)
                            .innerRadius(config.innerRadius);

        const arcNormal = d3.arc()
                            .outerRadius(config.outerRadius)
                            .innerRadius(config.innerRadius);

        d3.selectAll('.arc')
            .on('mouseover', function(d){
                const e = d3.event;

                d3.select(e.target)
                    .attr('d', arcLarger(d));
            })
            .on('mouseleave', function(d){
                const e = d3.event;

                d3.select(e.target)
                    .attr('d', arcNormal(d));
            })
    }

大功告成!!!


如果觉得这篇文章帮助了您,请打赏一个小红包鼓励作者继续创作哦!!!

在这里插入图片描述

D3 二维图表的绘制系列(一)介绍 1 介绍 D3 (或者叫 D3.js )是一个基于 web 标准的 JavaScript 可视化库. D3 可以借助 SVG, Canvas 以及HTML 将你的数据生动的展现出来. D3 结合了强大的可视化交互技术以及数据驱动 DOM 的技术,让你可以借助于现代浏览器的强大功能自由的对数据进行可视化 学习了d3一个多月,通过绘制一些简单的二维图表,总算入门了d3。强烈推荐《D3数据可视化实战... 阅读详情

相关推荐

D3 二维图表的绘制系列(十五)雷达图

上一篇: 气泡图 https://blog.youkuaiyun.com/zjw_python/article/details/98480632 下一篇: 矩形树状图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/articl...

zjw_python的博客 5368

D3系列第一弹——绘制饼图

学习产品的路上也要继续学习代码

lucky_sdy的博客 1463

D3 二维图表的绘制系列(二十)河流图

上一篇: 封闭图 https://blog.youkuaiyun.com/zjw_python/article/details/98492510 下一篇: 仪表盘图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article...

zjw_python的博客 5869

HTML和JavaScript的D3绘制普通饼图(不含数据)

今天,抽出空来了,接着发文,尽量补齐之前的发文任务。 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>饼图</title> </head> <body> <script src="./d3.v4.min.js" charset="UTF-8"></script><!--D3文件--&

Forerunner and Successor 先駆者と後継者 384

D3 二维图表的绘制系列(二十三)旭日图

上一篇: 桑基图 https://blog.youkuaiyun.com/zjw_python/article/details/98492510 下一篇: 力导向图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article...

zjw_python的博客 3620

D3 二维图表的绘制系列(二十九)径向树图

上一篇: 关系图-弦图 代码结构和初始化画布的Chart对象介绍,请先看 这里 本图完整的源码地址: 这里 1 图表效果 2 数据 { "name": "letter", "children": [ { "name": "a", "children": [ { ...

zjw_python的博客 6222

十大案例,带你使用D3.js实现数据可视化

原文:Learn to Create D3.js Data Visualizations by Example 译者:kmokidd,UI 工程师。 责编:陈秋歌,优快云内容运营,关注前端开发、用户体验技术领域。研发心得、项目实战、前沿技术、外文翻译……,只要是技术干货,十分欢迎投稿至chenqg#youkuaiyun.com。人人都是主编,这里就是你的舞台。 基于 D3.js ,编写 H...

小秋博客 2万+

D3 二维图表的绘制系列(二十七)日历热力图

上一篇: 盒须图 https://blog.youkuaiyun.com/zjw_python/article/details/99581418 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article/details/98182540 本图完整的源码地址: https://github.com/zjw666/D3_demo/tree/...

zjw_python的博客 5703

D3学习篇-画饼图

D3之画饼图的步骤

ly2230976595的博客 2332

D3 二维图表的绘制系列(十一)南丁格尔图

上一篇: 环状饼图 https://blog.youkuaiyun.com/zjw_python/article/details/98480632 下一篇: 基础散点图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/artic...

zjw_python的博客 4292

D3 二维图表的绘制系列(二十八)关系图-弦图 chord

上一篇: 日历热力图 代码结构和初始化画布的Chart对象介绍,请先看 这里 本图完整的源码地址: 这里 1 图表效果 2 数据 { "citys": ["北京","上海","广州","深圳","香港"], "population": [ [1000,3015,4567,1234,3714], [3214,2000,2060,124,3234], [8761,65...

zjw_python的博客 5631

D3 二维图表的绘制系列(十八)漏斗图

上一篇: 树图 https://blog.youkuaiyun.com/zjw_python/article/details/98492510 下一篇: 封闭图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article/d...

zjw_python的博客 4651

D3 二维图表的绘制系列(二)基础柱状图

代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article/details/98182540 本图完整的源码地址: https://github.com/zjw666/D3_demo/tree/master/src/barChart/basicBarChart 1 图表效果 2 数据 date,money Mon,120 T...

zjw_python的博客 3501

D3 二维图表的绘制系列(十七)树图

上一篇: 矩形树图 https://blog.youkuaiyun.com/zjw_python/article/details/98480632 下一篇: 漏斗图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article...

zjw_python的博客 3849

D3 二维图表的绘制系列(二十一)仪表盘图

上一篇: 河流图 https://blog.youkuaiyun.com/zjw_python/article/details/98492510 下一篇: 桑基图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article/...

zjw_python的博客 2886

D3 二维图表的绘制系列(二十二)桑基图sankey

上一篇: 仪表盘图 https://blog.youkuaiyun.com/zjw_python/article/details/98492510 下一篇: 旭日图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article...

zjw_python的博客 6101

D3 二维图表的绘制系列(七)堆叠面积图

上一篇: 基础折线图 https://blog.youkuaiyun.com/zjw_python/article/details/98210977 下一篇: 曲线图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/articl...

zjw_python的博客 6066

D3 二维图表的绘制系列(十六)矩形树状图

上一篇: 雷达图 https://blog.youkuaiyun.com/zjw_python/article/details/98480632 下一篇: 树图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article/d...

zjw_python的博客 5977
上一篇: D3 二维图表的绘制系列(八)曲线图
下一篇: D3 二维图表的绘制系列(十)环状饼图
PAT-python-zjw
博客等级 码龄10年 381粉丝 408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值