pie.js 7.18 KB

nv.models.pie = function() {
  var margin = {top: 20, right: 20, bottom: 20, left: 20},
      width = 500,
      height = 500,
      animate = 2000,
      radius = Math.min(width-(margin.right+margin.left), height-(margin.top+margin.bottom)) / 2,
      label ='label',
      field ='y',
      id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
      color = d3.scale.category20(),
      showLabels = true,
      donut = false,
      title = '';

      var lastWidth = 0,
      lastHeight = 0;


  var  dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'tooltipShow', 'tooltipHide');

  function chart(selection) {
    selection.each(function(data) {

      var svg = d3.select(this)
          .on("click", function(d,i) {
              dispatch.chartClick({
                  data: d,
                  index: i,
                  pos: d3.event,
                  id: id
              });
          });



        var background = svg.selectAll('svg.margin').data([data]);
        var parent = background.enter();
        parent.append("text")
            .attr("class", "title")
            .attr("dy", ".91em")
            .attr("text-anchor", "start")
            .text(title);
        parent.append('svg')
            .attr('class','margin')
            .attr('x', margin.left)
            .attr('y', margin.top)
            .style('overflow','visible');

        var wrap = background.selectAll('g.wrap').data([data]);
        wrap.exit().remove();
        var wEnter = wrap.enter();

        wEnter
          .append('g')
            .attr('class', 'wrap')
            .attr('id','wrap-'+id)
          .append('g')
            .attr('class', 'pie');



        wrap
            .attr('width', width) //-(margin.left+margin.right))
            .attr('height', height) //-(margin.top+margin.bottom))
            .attr("transform", "translate(" + radius + "," + radius + ")");




        var arc = d3.svg.arc()
          .outerRadius((radius-(radius / 5)));

        if (donut) arc.innerRadius(radius / 2);


      // Setup the Pie chart and choose the data element
      var pie = d3.layout.pie()
         .value(function (d) { return d[field]; });

      var slices = background.select('.pie').selectAll(".slice")
            .data(pie);

          slices.exit().remove();

        var ae = slices.enter().append("svg:g")
              .attr("class", "slice")
              .on('mouseover', function(d,i){
                        d3.select(this).classed('hover', true);
                        dispatch.tooltipShow({
                            label: d.data[label],
                            value: d.data[field],
                            data: d.data,
                            index: i,
                            pos: [d3.event.pageX, d3.event.pageY],
                            id: id
                        });

              })
              .on('mouseout', function(d,i){
                        d3.select(this).classed('hover', false);
                        dispatch.tooltipHide({
                            label: d.data[label],
                            value: d.data[field],
                            data: d.data,
                            index: i,
                            id: id
                        });
              })
              .on('click', function(d,i) {
                    dispatch.elementClick({
                        label: d.data[label],
                        value: d.data[field],
                        data: d.data,
                        index: i,
                        pos: d3.event,
                        id: id
                    });
                    d3.event.stopPropagation();
              })
              .on('dblclick', function(d,i) {
                dispatch.elementDblClick({
                    label: d.data[label],
                    value: d.data[field],
                    data: d.data,
                    index: i,
                    pos: d3.event,
                    id: id
                });
                 d3.event.stopPropagation();
              });

        var paths = ae.append("svg:path")
            .attr('class','path')
            .attr("fill", function(d, i) { return color(i); });
            //.attr('d', arc);

        slices.select('.path')
            .attr('d', arc)
            .transition()
            .ease("bounce")
            .duration(animate)
            .attrTween("d", tweenPie);

        if (showLabels) {
            // This does the normal label
            ae.append("text");

            slices.select("text")
              .transition()
              .duration(animate)
              .ease('bounce')
              .attr("transform", function(d) {
                 d.outerRadius = radius + 10; // Set Outer Coordinate
                 d.innerRadius = radius + 15; // Set Inner Coordinate
                 return "translate(" + arc.centroid(d) + ")";
              })
              .attr("text-anchor", "middle") //center the text on it's origin
              .style("font", "bold 12px Arial")
              .text(function(d, i) {  return d.data[label]; });
        }


        // Computes the angle of an arc, converting from radians to degrees.
        function angle(d) {
            var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
            return a > 90 ? a - 180 : a;
        }





        function tweenPie(b) {
            b.innerRadius = 0;
            var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
            return function(t) {
                return arc(i(t));
            };
        }


    });

    return chart;
  }

  chart.margin = function(_) {
    if (!arguments.length) return margin;
    margin = _;
    return chart;
  };

  chart.width = function(_) {
    if (!arguments.length) return width;
    if (margin.left + margin.right + 20 > _) {
      width = margin.left + margin.right + 20; // Min width
    } else {
      width = _;
    }
    radius = Math.min(width-(margin.left+margin.right), height-(margin.top+margin.bottom)) / 2;
    return chart;
  };

  chart.height = function(_) {
    if (!arguments.length) return height;
    if (margin.top + margin.bottom + 20 > _) {
      height = margin.top + margin.bottom + 20; // Min height
    } else {
      height = _;
    }
    radius = Math.min(width-(margin.left+margin.right), height-(margin.top+margin.bottom)) / 2;
    return chart;
  };

  chart.animate = function(_) {
    if (!arguments.length) return animate;
    animate = _;
    return chart;
  };

  chart.labelField = function(_) {
    if (!arguments.length) return (label);
      label = _;
      return chart;
  };

  chart.dataField = function(_) {
    if (!arguments.length) return (field);
    field = _;
    return chart;
  };

  chart.showLabels = function(_) {
      if (!arguments.length) return (showLabels);
      showLabels = _;
      return chart;
  };

  chart.donut = function(_) {
        if (!arguments.length) return (donut);
        donut = _;
        return chart;
  };

  chart.title = function(_) {
        if (!arguments.length) return (title);
        title = _;
        return chart;
  };

  chart.id = function(_) {
        if (!arguments.length) return id;
        id = _;
        return chart;
  };

  chart.dispatch = dispatch;



    return chart;
}