d3.js饼图绘制,V3与V4.

饼图的绘制稍微复杂一点点,主要是网上很多教程还是老版本d3.
这里用的是 D3 4.0 API Reference.

效果图

和上几篇文章写到的一样,首先新建svg,考虑缩放问题,
长高"100%",提供给后面svg使用.
在这里我直接给了两个list做数据了,一个是用来画饼图的数据,一个是上面的文字.
同时新建一个list存放你想要用的颜色列表.

var width = "100%";
    var hight = "100%";
    var radius = 150;                            //饼图半径,后面也用做图像相对于原点的偏移量
    var color = ["steelblue","steelblue"];     //颜色列表
    var gender_list = ["女性用户","男性用户"];
    var gender_list_value = ["30","40"];

接下来新建svg,我在id为gender_plotdiv下append了这个svg.
在这里饼图的结构是:<svg>内部一个<g>来装载整个饼图,这个<g>里面有数个<g>代表饼图的每一小片,而每个小片是由一个<path>和一个<text>组成的.
也就是说,饼图的每一部分是一个<path>!所有的样式都要针对<path>来设定.

直方图的话是一个rec

一个饼图的结构

和直方图不同的是,饼图没有比例尺了,
这里直接把数据绑定给svg:.data([gender_list_value])

    var gender_svg = d3.select("#gender_plot")
        .append("svg")              //创建svg
            .attr("width", width)  //长
            .attr("height", hight) //高
            .attr("viewBox","0 0 300 300") //视窗,因为上面饼图的半径为150,这里视窗就刚好设定为直径300
            .attr("preserveAspectRatio","xMaxYMax meet")
            .data([gender_list_value]) //关联数据,注意要加方括号
        .append("g")                //make a group to hold our pie chart
            .attr("transform", "translate(" + radius + "," + radius + ")");   //move the center of the pie chart from 0, 0 to radius, radius

接下来是根据每一片的弧度啊,半径啊,起始角啊什么的计算每一个<path>的路径.
用的是d3的arc()方法会帮你计算这些,返回的既是一条path中的d属性.
d属性具体说明在这里.
从某种意义上来讲,这里的arc()方法有点类似画直方图时的比例尺,只不过在调用的时候是,输入数据list后输出算出每一部分相应的path路径.

这里必须设定圆弧的外半径内半径. (不然没法算路径啊是吧...)
外半径就是饼图外圆圈的半径,内径一般为0,表示没有空心,但是如果你想画圆环图,这里的内径相应的给出就好.

    var arc = d3.arc()              //这里是用arc()方法来创建后面的path
        .outerRadius(radius)
         .innerRadius(0);

    var pie = d3.pie()           //pie方法,自动根据原数据list计算每一部分的扇形角度占比
        .value(function(d) { return d; });    //用无名函数给pie方法依次传输绑定的数据

    var arcs = gender_svg.selectAll("g.slice")     //给每个饼图的部分一个类名,叫slice
        .data(pie)                          //把pie方法传进来,用于放置饼图每一部分
        .enter()                            //用enter方法
            .append("g")                //补足g元素
                .attr("class", "slice");    //添加类名

接下来输入数据,根据输出的path路径依次生成path,并加入text部分:
enter方法参考之前的文章d3.js直方图与坐标轴基础.

 gender_svg.selectAll("g.slice")     //给每个饼图的部分一个类名,叫slice
        .data(pie)                          //把pie方法传进来,用于放置饼图每一部分
        .enter()                            //用enter方法
            .append("g")                //补足g元素
                .attr("class", "slice")    //添加类名
            .append("path") //加入path元素
                .attr("fill", function(d, i) { return color[i]; } )//颜色选择根据数据的索引按顺序给
                .attr("stroke","white")//设定描边的颜色,笔画粗线默认
                .attr("d", arc) //设定d属性!既Path的路径,由arc方法给出!
                .attr("opacity",0.4) //设定透明度
        .on("mouseover",function(d,i){ //鼠标交互动态效果
            d3.select(this)
                .attr("opacity",1);
        })
        .on("mouseout",function(d,i){
            d3.select(this)
                .transition()
                .duration(500)
                .attr("opacity",0.4);
        })
        .on("click",function () {

        });
                                 

        gender_svg.selectAll("g.slice").append("text")  //给饼图的每一部分添加text元素
                .attr("transform", function(d) {                   
                      d.innerRadius = 0; 
                      d.outerRadius = radius;
                      return "translate(" + arc.centroid(d) + ")";        //返回path的中心用于设置文字相对于(0,0)的偏移
                  })
                .attr("text-anchor", "middle") //文字居中
                .attr("font-size", "80%")//文字大小
                .text(function(d, i) { return gender_list[i]; }); //文字内容从数据list中根据index获取

到此,首图上的饼图就应该可以实现啦~
:)


这里是V3版本

主要只有两个地方的不同,既axis的语法和scale的语法.

var width = "100%";
    var hight = "100%";
    var radius = 150;                            //radius
    var color = ["steelblue","steelblue"];     //builtin range of colors
  var genders = {{gender_list}}

if (genders[0]== "f"){
  var gender_list = ["女性用户","男性用户"];
}
else if (genders[0]== "m"){
  var gender_list = ["男性用户","女性用户"];
}

    var gender_list = ["女性用户","男性用户"];
    var gender_list_value = {{gender_list_value}};

    var gender_svg = d3.select("#gender_plot")
        .append("svg")         
            .attr("width", width)          
            .attr("height", hight)
            .attr("viewBox","0 0 300 350")
            .attr("preserveAspectRatio","xMaxYMax meet")
            .data([gender_list_value])
          .append("g")             
            .attr("transform", "translate(" + radius + "," + radius + ")");   

    var arc = d3.svg.arc()       //这里语法不同       
        .outerRadius(radius)
            .innerRadius(0);

    var pie = d3.layout.pie()           //这里语法不同
        .value(function(d) { return d; });   

    gender_svg.selectAll("g.slice")     
        .data(pie)                         
        .enter()                          
            .append("g")               
                .attr("class", "slice")   
            .append("path")
                .attr("fill", function(d, i) { return color[i]; } )
                .attr("stroke","white")
                .attr("d", arc)
                .attr("opacity",0.4)
        .on("mouseover",function(d,i){
            d3.select(this)
                .attr("opacity",1);

          tooltip.html( parseInt(100*(gender_list_value[i]/(gender_list_value[0]+gender_list_value[1])))+"%")
                    .style("left", (d3.event.pageX+10) + "px")
                    .style("top", (d3.event.pageY - 10) + "px")
                    .style("opacity",1.0);
        })
        .on("mouseout",function(d,i){
            d3.select(this)
                .transition()
                .duration(500)
                .attr("opacity",0.4);
          tooltip.style("opacity",0.0);
        })
         .on("mousemove",function(d){
            tooltip.style("left", (d3.event.pageX+ 10) + "px")
                    .style("top", (d3.event.pageY - 10) + "px");
        })
        .on("click",function () {

        });
                                    

        gender_svg.selectAll("g.slice").append("text")                                     
                .attr("transform", function(d) {                   
                d.innerRadius = 0;
                d.outerRadius = radius;
                return "translate(" + arc.centroid(d) + ")";        
            })
            .attr("text-anchor", "middle")
                .attr("font-size", "80%")
            .text(function(d, i) { return gender_list[i]; });
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容