d3.js 一个饼图的案例

d3.js 一个饼图

参考链接:https://cloud.tencent.com/developer/article/1020344

效果图:
在这里插入图片描述
鼠标悬浮时:
在这里插入图片描述

<div>
  <svg id='svg6'/>
</div>
const oriData = [
      { 'x': 'A计划', 'y': 20 },
      { 'x': 'B计划', 'y': 40 },
      { 'x': 'C计划', 'y': 90 },
      { 'x': 'D计划', 'y': 80 },
      { 'x': 'E计划', 'y': 120 },
      { 'x': 'F计划', 'y': 100 },
      { 'x': 'G计划', 'y': 60 }
    ];
    const [width, height] = [750, 350];

    let svg = d3.select('#svg6')
      .attr('width', width)
      .attr('height', height)

    let g = svg.append('g')
      .attr('transform', 'translate( 140, 40 )')

    //设置饼图的半径
    let radius = Math.min(width, height) * 0.8 / 2

    let arc = d3.arc()
      .innerRadius(70)
      // .outerRadius(radius)
      .cornerRadius(10)

    //饼图与文字相连的曲线起点
    let pointStart = d3.arc()
      .innerRadius(radius)
      .outerRadius(radius)
    //饼图与文字相连的曲线终点
    let pointEnd = d3.arc()
      .innerRadius(radius + 20)
      .outerRadius(radius + 20)

    let drawData = d3
      .pie()
      .value(function(d) {
        return d.y
      })
      .sort(null)
      .sortValues(null)
      .startAngle(0)
      .endAngle(Math.PI * 2)
      .padAngle(0.05)(oriData)
    console.log(drawData)

    let colorScale = d3
      .scaleOrdinal()
      .domain(d3.range(0, oriData.length))
      .range(d3.schemeSet1);
    g.append('g')
      .attr('transform', 'translate( ' + radius + ', ' + radius + ' )')
      .attr('stroke', 'steelblue')
      .attr('stroke-width', 1)
      .selectAll('path')
      .data(drawData)
      .enter()
      .append('path')
      .attr('fill', function(d) {
        return colorScale(d.index)
      })
      .attr('d', function(d) {
        d.outerRadius = radius;
        return arc(d)
      })
      .on('mouseover', arcTween(radius + 20, 0))
      .on('mouseout', arcTween(radius, 150))
      .transition()
      .duration(2000)
      .attrTween('d', function (d) {
      //初始加载时的过渡效果
        let fn = d3.interpolate({
          endAngle: d.startAngle
        }, d)
        return function(t) {
          return arc(fn(t))
        }
      })

    function arcTween(outerRadius, delay) {
      // 设置缓动函数,为鼠标事件使用
      return function() {
        d3.select(this)
          .transition()
          .delay(delay)
          .attrTween('d', function(d) {
            let i = d3.interpolate(d.outerRadius, outerRadius)
            return function(t) {
              d.outerRadius = i(t)
              return arc(d)
            }
          })
      }
    }

    //文字层
    let sum = d3.sum(oriData, d => d.y);
    svg.append('g')
      .attr('transform', 'translate( ' + radius + ', ' + radius + ' )')
      .selectAll('text')
      .data(drawData)
      .enter()
      .append('text')
      .attr('transform', function(d) {
      // arc.centroid(d)将文字平移到弧的中心
        return 'translate(' + arc.centroid(d) + ') ' +
          //rotate 使文字旋转扇形夹角一半的位置(也可不旋转)
          'rotate(' + (-90 + (d.startAngle + (d.endAngle - d.startAngle)/2) * 180 / Math.PI) + ')'
      })
			//文字开始点在文字中间
      .attr('text-anchor', 'middle')
			//文字垂直居中
      .attr('dominant-baseline', 'central')
      .attr('font-size', '10px')
			//格式化文字显示格式
      .text(function(d) {
        return (d.data.y / sum * 100).toFixed(2) + '%';
      })
      // .attr('rotate', '30') //此设置为设置每个文字中字符的旋转,上面的旋转是以文字为一个整体的旋转

    //图例legend
    let legend = g.append('g')
      .attr('transform', 'translate( ' + radius * 2.5 + ', 0 )')
      .selectAll('g')
      .data(drawData)
      .enter()
      .append('g')
      .attr('transform', function(d, i) {
        return 'translate(0,' + i * 20 + ')'
      });

    legend
      .append('rect')
      .attr('width', 27)
      .attr('height', 18)
      .attr('fill', function(d) {
        return colorScale(d.index)
      });
    legend
      .append('text')
      .text(function(d) {
        return d.data.x
      })
      .style('font-size', 10)
      .attr('y', '1em')
      .attr('x', '3em')
      .attr('dy', 3)

    //曲线层
    g.append('g')
      .attr('transform', 'translate( ' + radius + ', ' + radius + ' )')
      .selectAll('path')
      .data(drawData)
      .enter()
      .append('path')
      .attr('d',
        d3
          .linkHorizontal()
          .source(function(d) {
            return pointStart.centroid(d)
          })
          .target(function(d) {
            return pointEnd.centroid(d)
          })
      )
      .style('stroke', '#999')
      .style('stroke-width', 1)
      .attr('fill', 'none')

    //饼图外面的文字
    g.append('g')
      .attr('transform', 'translate( ' + radius + ', ' + radius + ' )')
      .selectAll('path')
      .data(drawData)
      .enter()
      .append('text')
      .text(function(d) {
        return d.data.x
      })
      .attr('x', function(d) {
        return pointEnd.centroid(d)[0]
      })
      .attr('y', function(d) {
        return pointEnd.centroid(d)[1]
      })
      .style('font-size', 10)
      .attr('text-anchor', function(d) {
        if (d.startAngle > Math.PI) {
          return 'end'
        }
      })
      .attr('dominant-baseline', function(d) {
        if (d.index === 4) {
          return 'hanging'
        }
      })



    //测试文字
    /*svg.append('g')
      .append('text')
      .text('welcome to Beijing')
      .attr('dominant-baseline', 'hanging')
      .attr('transform', 'translate( 30, 30 ) rotate(0)')
      .style('font-style', 'italic')
      .attr('rotate', 12)
      */ 


    //测试arc
    // let arc = d3.arc()
    //   .innerRadius(0)
    //   .outerRadius(100)
    //   .startAngle(0)
    //   .endAngle(Math.PI/2)
    //   .cornerRadius(10)
    // svg.append('g')
    //   .attr('transform', 'translate( 200, 200 )')
    //   .append('path')
    //   .attr('fill', 'none')
    //   .attr('stroke', 'steelblue')
    //   .attr('stroke-width', 1.5)
    //   .attr('stroke-linejoin', 'round')
    //   .attr('stroke-linecap', 'round')
    //   .attr('d', arc)

    /*//测试transition
    svg.append('g')
      .attr('transform', 'translate( 300, 0 )')
      .append('rect')
      .attr("fill","red")
      .attr("x",100)
      .attr("y",100)
      .attr("width",100)
      .attr("height",30)
      .transition()
      .duration(2000)
      .attrTween('width', function(d, i, a) {
        return function(t) {
          return 100 + t * 300
        }
      })*/

  • 0
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值