RangePoints适用于不同大小的圆圈

时间:2014-07-14 00:33:28

标签: javascript html css svg d3.js

是否可以指定rangePoints来处理不同大小的圆圈,以便距离是通过边缘而不是中心来计算的?

例如,这就是我得到的:

()表示圆边; < ---->表示由rangePoints计算的距离

(   <----)---(-><-)-------(-> )

^注意中间圆圈看起来更接近最左边的圆圈。相反,我想看到以下内容:

(        )<---->(  )<---->(  )

我正在使用的功能类似于:

var y = d3.scale.ordinal()
   .domain(data.map(function(d) { return d.value}))
   .rangePoints([0, width]);

var item = chart.append("g")
    .selectAll("circle")
         .data(data)
    .enter().append("circle")
    .attr("cy", function(d) { return y(d.value); })

1 个答案:

答案 0 :(得分:1)

正如@LarsKotthoff所提到的,你需要一个自定义比例实现来做到这一点。

在这种情况下,这有点复杂,因为规模不仅需要考虑域中元素的数量,还需要考虑它们的确切值。基本上,在计算每个元素的位置时,您的比例需要考虑其前面每个元素所占用的空间,并且还包括基于总空间划分的间隔。

以下是它必须做的事情:

首先,在设置比例时,您需要执行以下操作:

  • 查找输出范围所涵盖的总距离
  • 查找域中每个元素的直径总和
  • 利用这些差异找到剩余可用空间
  • 将剩余空间除以空格数(元素数减1)

这将为您提供每个圆圈之间所需空间的值。

然后对每个元素:

  • 查找前面圆圈直径的总和
  • 将间隔符值乘以前面的圆圈数
  • 将这些总和添加到当前圆的半径

因此,您的比例需要基于索引和基准。

这是一个相当粗略的实现,假设域是一个半径数组,范围是输出的端点:

var customPointScale = function() {
  var domain,
      range;
  // returned scale fn takes datum and index
  function scale(d,i) {
    var n = domain.length,
        totalSpan = range[1] - range[0],
        // loop over the domain to find the sum of the diameters
        sumDiameters = (function(){
          var output = 0;
          for (var a = 0; a < n; a++) {
            // add radius * 2 to get diameter
            output += domain[a] * 2;
          }
          return output;
        })(),
        remainingSpace = totalSpan - sumDiameters,
        // there is one fewer space than the number of elements
        spacer = remainingSpace / (n-1);

    // loop over the elements that came before to find the distance spanned
    var distanceSoFar = (function() {
      var output = 0;
      for(var a = 0; a < i; a++) {
        // diameter + spacer, for each element traversed
        output += (domain[a] * 2) + spacer;
      }
      return output;
    })();

    // return the radius plus the distance traversed so far
    return d + distanceSoFar;
  }
  scale.domain = function(_) {
    if (!arguments.length) return domain;
    domain = _;
    return scale;
  };
  scale.range = function(_) {
    if (!arguments.length) return range;
    range = _;
    return scale;
  };
  return scale;
};

这是一个JSBin,它将此实现与一些示例数据结合使用。希望有所帮助。