【问题标题】:Read inner and outer radius of arc - d3.js读取圆弧的内半径和外半径 - d3.js
【发布时间】:2015-01-22 08:08:41
【问题描述】:

我正在从事一个处理大型关系数据的可视化表示的项目。我们使用饼图来显示数据组件(按顺序)。由于空间不足,我们一次只显示 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");
}

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

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

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

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

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

【问题讨论】:

    标签: svg d3.js transform


    【解决方案1】:

    就这样,

    ...
    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】:

      从技术上讲,可以从path 元素的d 属性中检索innerRadiusouterRadius,但它需要解析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);
          });
      }
      

      【讨论】:

      • 谢谢,现在我将内半径和外半径存储在一个变量中,以便我可以重复使用它。但现在我面临其他一些问题 - 当转换发生时,它会旋转,但看起来像是从点重新渲染为弧。因为我没有改变内半径和外半径,它只是开始和结束的角度。我怎样才能只设置转换的开始和结束角度?我在 attrTween 上看到了几个示例,但它需要 dataSet,我没有使用也不想使用它,因为我需要控制(为每个 pie 组件分配唯一的 id、颜色、指针等)在每个 pie 组件上
      【解决方案3】:

      以下是我编写的几个函数,用于获取使用 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;
      }
      

      【讨论】:

        最近更新 更多