javascript - d3.js:饼图布局 - 调整 Angular 以创建快门效果

标签 javascript d3.js charts

我的任务是使用 d3.js 重新创建一个交互式饼图 - 我的饼图各部分的 Angular 不是从饼图的中间开始的(见下图)并且稍微偏离。绘制我想要的快门效果的最佳方法是什么?您可以在下面看到我的代码到了什么地方。

JS fiddle : http://jsfiddle.net/vh6nwtpb/3/

我想要获得的效果: enter image description here

JS代码

  // Data Used for this example...
  var dataSet1 = [
    {legendLabel: "Legend String 1", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#252d38", seghovcolour: "#005190"},
    {legendLabel: "Legend String 2", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#173c59", seghovcolour: "#005190"},
    {legendLabel: "Legend String 3", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#223343", seghovcolour: "#005190"},
    {legendLabel: "Legend String 4", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#20364b", seghovcolour: "#005190"},
    {legendLabel: "Legend String 5", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#1d3853", seghovcolour: "#005190"},
    {legendLabel: "Legend String 6", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#015190", seghovcolour: "#005190"},
    {legendLabel: "Legend String 7", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#144162", seghovcolour: "#005190"},
    {legendLabel: "Legend String 8", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#0f436a", seghovcolour: "#005190"},
    {legendLabel: "Legend String 9", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#0f4873", seghovcolour: "#005190"},
    {legendLabel: "Legend String 10", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#0d4b7c", seghovcolour: "#005190"},
    {legendLabel: "Legend String 11", magnitude: 9.09, link: "https://www.uk-cpi.com/", segcolour: "#0f5086", seghovcolour: "#005190"}
  ];

  function drawPie( pieName, dataSet, selectString, colors, margin, outerRadius, innerRadius, sortArcs ) {
    var colorScale = d3.scale.category20c();
    var canvasWidth = 620;
    var canvasHeight = 0;
    var innerRadius = 150;
    var outerRadius = 300;
    var pieWidthTotal = outerRadius * 2;
    var pieCenterX = outerRadius + margin/2;
    var pieCenterY = outerRadius + margin/2;
    var legendVerticalOffset = outerRadius - margin;
    var legendTextOffset = 20;
    var textVerticalSpace = 20;
    var pieDrivenHeight = outerRadius*2 + margin*2;
    var legendTextDrivenHeight = (dataSet.length * textVerticalSpace) + margin*2;

    // Autoadjust Canvas Height
    if (pieDrivenHeight >= legendTextDrivenHeight)
    {
      canvasHeight = pieDrivenHeight;
    }
    else
    {
      canvasHeight = legendTextDrivenHeight;
    }

    var x = d3.scale.linear().domain([0, d3.max(dataSet, function(d) { return d.magnitude; })]).rangeRound([0, pieWidthTotal]);
    var y = d3.scale.linear().domain([0, dataSet.length]).range([0, (dataSet.length * 20)]);

    // HOVER COLOUR
    var synchronizedMouseOver = function() {
      var arc = d3.select(this);
      var indexValue = arc.attr("index_value");

      var arcSelector = "." + "pie-" + pieName + "-arc-" + indexValue;
      var selectedArc = d3.selectAll(arcSelector);
      var colorValue = selectedArc.attr("color_hover");
      selectedArc.style("fill", colorValue);
    };

    var synchronizedMouseOut = function() {
      var arc = d3.select(this);
      var indexValue = arc.attr("index_value");

      var arcSelector = "." + "pie-" + pieName + "-arc-" + indexValue;
      var selectedArc = d3.selectAll(arcSelector);
      var colorValue = selectedArc.attr("fill");
      selectedArc.style("fill", colorValue);

    };


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

    // Create a drawing canvas...
    var canvas = d3.select(selectString)
      .append("svg:svg") //create the SVG element inside the <body>
        .data([dataSet]) //associate our data with the document
        .attr("width", canvasWidth) //set the width of the canvas
        .attr("height", canvasHeight) //set the height of the canvas
        .append("svg:g") //make a group to hold our pie chart
        .attr("transform", "translate(" + pieCenterX + "," + pieCenterY + ")") // Set center of pie

// Define an arc generator. This will create <path> elements for using arc data.
    var arc = d3.svg.arc()
        .innerRadius(innerRadius) // Causes center of pie to be hollow
        .outerRadius(outerRadius);

// Define a pie layout: the pie angle encodes the value of dataSet.
// Since our data is in the form of a post-parsed CSV string, the
// values are Strings which we coerce to Numbers.
      var pie = d3.layout.pie()
        .value(function(d) { return d.magnitude; })
        .sort(function(a, b) {if (sortArcs==1) { return b.magnitude - a.magnitude; } else { return null; } });

      // Select all <g> elements with class slice (there aren't any yet)
      var arcs = canvas.selectAll("g.slice")
      // Associate the generated pie data (an array of arcs, each having startAngle,
      // endAngle and value properties)
      .data(pie)
      // This will create <g> elements for every "extra" data element that should be associated
      // with a selection. The result is creating a <g> for every object in the data array
      // Create a group to hold each slice (we will have a <path> and a <text>      // element associated with each slice)
        .enter().append("svg:a")
      .attr("xlink:href", function(d) { return d.data.link; })
      .append("svg:g")
      .attr("class", "slice")    //allow us to style things in the slices (like text)
          // Set the color for each slice to be chosen from the color function defined above
          // This creates the actual SVG path using the associated data (pie) with the arc drawing function
      .style("stroke", "White" )
      .attr("d", arc);

    arcs.append("svg:path")

      // Set the color for each slice to be chosen from the color function defined above
      // This creates the actual SVG path using the associated data (pie) with the arc drawing function


      .attr("fill", function(d, i) { return d.data.segcolour; })
      .attr("color_hover", function(d, i) { return d.data.seghovcolour; })


      .attr("index_value", function(d, i) { return "index-" + i; })
      .attr("class", function(d, i) { return "pie-" + pieName + "-arc-index-" + i; })
      .style("stroke", "White" )
      .attr("d", arc)
      .on('mouseover', synchronizedMouseOver)
      .on("mouseout", synchronizedMouseOut)
      .transition()
      .ease("")
      .duration(2000)
      .delay(function(d, i) { return i * 0; })
      .attrTween("d", tweenPie);

    // Add a magnitude value to the larger arcs, translated to the arc centroid and rotated.
    arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; }).append("svg:text")
      .attr("dy", ".35em")
      .attr("text-anchor", "middle")
      //.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; })
      .attr("transform", function(d) { //set the label's origin to the center of the arc
        //we have to make sure to set these before calling arc.centroid
        d.outerRadius = outerRadius; // Set Outer Coordinate
        d.innerRadius = innerRadius; // Set Inner Coordinate
        return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")";
      })
      .style("fill", "White")
      .style("font", "normal 12px Arial")
      .text(function(d) { return d.data.magnitude; });

    // 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;
    }

  };

最佳答案

为了达到预期的效果,每 block 的内弧必须偏移几个弧度。

不幸的是,仅使用 D3 是不可能的。问题是我们只能指定 start and end angles整个弧线。我们不能仅指定内弧或外弧的开始和结束 Angular 。

如果我们检查 D3's arc source code responsible for drawing the arc ,我们可以调整这条线:

else context.arc(0, 0, r0, a10, a00, cw);

到:

else {
  var offsetDegrees = 10,
      offsetRadians = offsetDegrees * Math.PI / 180;
  context.arc(0, 0, r0, a10 + offsetRadians, a00 + offsetRadians, cw);
}

并达到预期的效果。

不幸的是,此更改会扰乱圆弧质心的计算以及可能的许多其他功能。

更改源代码从来都不是一个好的做法,这种效果应该在 d3-shape 库中提出或作为 D3 插件实现。

关于javascript - d3.js:饼图布局 - 调整 Angular 以创建快门效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38956648/

相关文章:

java - 如何将数据从java程序传递到javafx应用程序图表?

wpf - 将集合绑定(bind)到 WPF 工具包图表

javascript - 如何在 Angular 服务中使用providedIn 'root'

javascript - 在 promise 链中将数据推送到新数组时出现问题

javascript - D3.js map 上的绘图点

javascript - d3.js:仅显示 xAxis 上的部分数据

vb.net - 我可以更改折线图的宽度吗?

javascript - 如何从 Firestore 检索第一个和最后一个集合

javascript - 将参数传递给内联函数

javascript - 创建自定义 d3 布局