读取弧的内半径和外半径 - d3.js

时间:2015-01-22 08:08:42

标签: svg d3.js transform

我正在开发一个处理大型关系数据可视化表示的项目。我们使用饼图来显示数据组件(按顺序)。由于空间不足,我们一次只能显示10个。

请考虑以下示例:

假设我有100个数据组件,其中我将在给定的时间点仅显示10个。我正在使用的逻辑是,我将其他90个组件的开始和结束角度设置为0(零)。对于那些10个组件我在哪里计算开始和结束角度如下 -

var angle = 360;
var count = 10;
if(data.length > count) angle = angle/count; //data is array of data component names
else angle = angle/data.length;

//Initially I'll be displaying first ten components
for(var i=0; i<data.length; i++){
    var startAngle = i * angle;
    var endAngle = startAngle + angle;
    var pi = = Math.PI/180;

    var arc = d3.svg.arc()
        .innerRadius(innerRadius) //dynamic value, calculated based on available space
        .outerRadius(outerRadius) //dynamic value, calculated based on available space
        .startAngle((startAngle)*pi)
        .endAngle((endAngle)*pi);

    //Hiding rest of the data components
    if(i >= count){
        arc.startAngle(0);
        arc.endAngle(0);
    }

    arcGroup.append("path")
        .attr("d", arc)
        .attr("stroke", "#2E2E2E")
        .attr("stroke-width", "1")
        .attr("fill","gold");

    var text = arcGroup.append("text")
        .attr("transform", "translate(" + arc.centroid() + ")")
        .attr("text-anchor", "middle")
        .attr("font-family","noto_sansregular")
        .attr("font-size", 40)
        .attr("font-weight","Bold")
        .attr("fill", "#000000")
        .attr("y",0)
        .style("visibility", "visible")
        .text(data[i]);

    //Hiding text of hidden arcs
    if(i >= count) text.style("visibility", "hidden");
}

然后,如果用户想要查看其余组件,我将提供两个按钮来旋转(时钟或反时钟)内容。

如果当前视图是 - &gt; 1,2,3,4,5,6,7,8,9,10

顺时针旋转一个单元格,结果视图应为 - &gt; 100,1,2,3,4,5,6,7,8,9

在这种情况下,我需要隐藏组件'10'并显示组件'100',并移动其余的单元格。为了实现这一点,我只需要改变弧的起始和终止角度。我可以创建具有计算角度的新弧对象。

这里的问题是我不知道如何获得动态创建的弧的内半径和外半径。

3 个答案:

答案 0 :(得分:2)

从技术上讲,可以从innerRadius元素的outerRadius属性中检索dpath,但它需要解析DSL并且会很繁琐。这些值不会通过d3 很好地存储在元素本身上。

因此,如果您在更新元素时​​重新计算innerRadiusouterRadius会更好:

function showFromIdx(firstIndex) {
  argGroup.selectAll('path')
    .data( d3.range(data.length)
             .map(function (d) { 
                return (d - firstIndex + data.length) % data.length; 
              })
    )
    .attr('d', function (d) {
      // You will have to calculate the radii again here.
      var innerRadius = foo(d), outerRadius = bar(d);
      return d3.svg.arc()
              .startAngle(i < count ? i * angle : 0)
              .endAngle(i < count ? (i + 1) * angle : 0)
              .innerRadius(innerRadius)
              .outerRadius(outerRadius)(d);
    });
}

答案 1 :(得分:2)

就像那样,

...
arcGroup.append("path")
    .filter(function(d) { 
        // You're Not restricted to the "filter" function
        var innerRadius = d.innerRadius()(d);
        var outerRadius = d.outerRadius()(d);
    })
    .attr("d", arc)
...

答案 2 :(得分:1)

以下是我编写的几个函数,用于获取使用d3创建的弧的内半径和外半径。如果您在代码中发现错误,请告诉我。

function getInnerRadiusFromArc(arc) {
  var numbersInPattern = _getArcNumbers(arc);

  // Possibly, that's sector, so it starts from 0.
  // Or maybe that's something else.
  if (numbersInPattern.length < 4) {
    return 0;
  }

  // Getting minimum from the array.
  var innerRadius = Math.min.apply(null, numbersInPattern);

  return innerRadius;
}

function getOuterRadiusFromArc(arc) {
  var numbersInPattern = _getArcNumbers(arc);

  // Getting maximum from the array.
  var outerRadius = Math.max.apply(null, numbersInPattern);

  return outerRadius;
}

function _getArcNumbers(arc) {
  // Path description parameter, containing necessary data.
  var pathDescription = arc.getAttribute("d");

  // We need to get all patterns like A<number>,<number>.
  // RegExp source:
  // http://www.regular-expressions.info/floatingpoint.html
  const numberRegExp = /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/g;
  var arcPattern = new RegExp("A" + numberRegExp.source + "," + numberRegExp.source, "g");
  var arcParameters = pathDescription.match(arcPattern);

  var numbersInPattern = [];

  // We get all the numbers from array ["A<number>,<number>", "A<number>,<number>", ...].
  for (let parameterIndex = 0; parameterIndex < arcParameters.length; parameterIndex++) {
    let parameter = arcParameters[parameterIndex];

    let numbers = parameter.match(numberRegExp);

    if (numbers !== null) {
      numbersInPattern = numbersInPattern.concat(numbers);
    }
  }

  // Transform strings in our array to numbers.
  numbersInPattern = numbersInPattern.map(function (numberString) {
    return parseFloat(numberString);
  });

  return numbersInPattern;
}