如何在 d3 的两个不同坐标 system/transforms 中用一条线连接两个点?

How to connect two points with a line in two different coordinate system/transforms in d3?

我试图通过连接 4 组点来创建闭合路径,但这些点位于 2 个不同的 transforms

例如,我有三个饼图,其中两个使用 d3.layout.pack() 并且在更大的饼图中:

var width = 700,
  height = 500,
  radius = Math.min(width, height) / 2,
  thickness = 20,
  length_inner = 2 * Math.sqrt(Math.pow(radius, 2) / 2);

var data = [{
  "name": "bob",
  "toward": "against",
  "fruit": "apple",
  "value": 5
}, {
  "name": "rob",
  "toward": "for",
  "fruit": "apple",
  "value": 9
}, {
  "name": "alice",
  "toward": "for",
  "fruit": "orange",
  "value": 3
}, {
  "name": "mike",
  "toward": "against",
  "fruit": "orange",
  "value": 6
}, {
  "name": "katy",
  "toward": "for",
  "fruit": "orange",
  "value": 8
}]

var data_inner = _(data).chain()
  .groupBy("fruit")
  .map(function(v, k) {
    return {
      "name": k,
      "sum": _(v).chain()
        .pluck("value")
        .reduce(function(memo, num) {
          return memo + num;
        }, 0)
        .value(),
      "data": v
    };
  })
  .value()

var svg = d3.select("svg")
  .attr({
    "width": width,
    "height": height
  })
  .append("g")
  .attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");

var outer = svg
  .append("g")
  .attr("class", "outer");

var color_outer = d3.scale.category20b();

var arc_outer = d3.svg.arc()
  .innerRadius(radius - thickness)
  .outerRadius(radius);

var pie_outer = d3.layout.pie()
  .value(function(d) {
    return d.value;
  })
  .sort(null)
  .padAngle(.02);

var path_outer = outer.selectAll("path")
  .data(pie_outer(data))
  .enter()
  .append("g")
  .attr("class", "arc_outer")
  .append("path")
  .attr("d", arc_outer)
  .attr("fill", function(d, i) {
    return color_outer(d.data["name"]);
  });

var inner = svg
  .append("g")
  .attr({
    "class": "inner",
    "transform": "translate(" + -(length_inner / 2) + "," + -(length_inner / 2) + ")"
  });

var bubble_inner = d3.layout.pack()
  .value(function(d) {
    return d.sum;
  })
  .sort(null)
  .size([length_inner, length_inner])
  .padding(10);

var node_inner = inner.selectAll("g.node_inner")
  .data(
    bubble_inner.nodes({
      children: data_inner
    })
    .filter(function(d) {
      return !d.children;
    })
  )
  .enter()
  .append("g")
  .attr({
    "class": "node_inner",
    "transform": function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    }
  });

var arc_inner = d3.svg.arc();
var pie_inner = d3.layout.pie()
  .value(function(d) {
    return d.value;
  });

var arc_inner_g = node_inner.selectAll("g.arc_inner")
  .data(function(d) {
    return pie_inner(d.data).map(function(m) {
      m.r = d.r;
      return m;
    });
  });

arc_inner_g.enter()
  .append("g")
  .attr("class", "arc_inner")
  .append("path")
  .attr("d", function(d) {
    arc_inner.innerRadius(d.r - thickness);
    arc_inner.outerRadius(d.r);
    return arc_inner(d);
  })
  .style("fill", function(d, i) {
    return d.data.toward === "for" ? "#2ca02c" : "d62728";
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

<body>
  <svg>
  </svg>
</body>

现在我正尝试用贝塞尔曲线从饼图的外部到内部连接两个点,如下所示:

然后关闭另外两个点创建一个<path>,稍后填充(抱歉,Photoshop 技能太差):

我试图避免使用一个统一的坐标系。即使我必须这样做,我也不确定该怎么做,因为我不知道如何在没有 transforms.

的情况下创建两个内圆

我能够使用几个 d3.path() 函数绘制路径:

// d is the data attached to the outer pie but also includes
// the respective inner pie's angles, cx, cy, and radius
function link_d_path(d) {
        if(d.value === 0) return "";

        var r_o = radius - thickness,
            offset = -Math.PI / 2,
            path_o_start = d.startAngle + offset,
            path_o_end   = d.endAngle   + offset,
            cx_i = -length_inner / 2 + d.node_x,
            cy_i = -length_inner / 2 + d.node_y,
            path_i_start = d.inner_startAngle + offset,
            path_i_end   = d.inner_endAngle   + offset,
            angle_diff = ((path_o_start + path_o_end) / 2 + (path_i_start + path_i_end) / 2) / 2,
            r_i = d.node_r,
            path = d3_path.path();

        path.arc(0, 0, r_o, path_o_start, path_o_end);
        path.bezierCurveTo(
            r_o * Math.cos(path_o_end),
            r_o * Math.sin(path_o_end),
            cx_i + (r_i + link_radius_cp_offset) * Math.cos(path_i_end),
            cy_i + (r_i + link_radius_cp_offset) * Math.sin(path_i_end),
            cx_i + r_i * Math.cos(path_i_end),
            cy_i + r_i * Math.sin(path_i_end)
        );
        path.arc(cx_i, cy_i, r_i, path_i_end, path_i_start, true);
        path.bezierCurveTo(
            cx_i + (r_i + link_radius_cp_offset) * Math.cos(path_i_start),
            cy_i + (r_i + link_radius_cp_offset) * Math.sin(path_i_start),
            r_o * Math.cos(path_o_start),
            r_o * Math.sin(path_o_start),
            r_o * Math.cos(path_o_start),
            r_o * Math.sin(path_o_start)
        );

        return path.toString();
    }

我只需要在贝塞尔曲线期间从极坐标转换为笛卡尔曲线。 path.arc()已经取了极坐标。

请注意,length_inner 是内部饼图的 cx 和 cy 相对于外部饼图的 cx 和 cy 的偏移量。