使用 d3 在旋转的线上画笔以创建缩放效果

brush on rotated lines using d3 to create zoom effect

我正在研究 this plnkr。我有 30 度角、45 度角和 60 度角的三条线。我想在这些线上应用画笔,这样当画笔绘制图表时,线条会在它穿过画笔矩形的位置重新绘制,并在轴上设置适当的值。非常感谢任何解决此问题的帮助或提示。

编辑:如果您有不同的解决方案来绘制旋转的线条并在其上画笔,也欢迎使用。请帮忙。

var ga = d3.select("svg")
    .append("g")
    .attr("class", "a axis")
    .attr("transform", "translate(" + margin.left + "," + (height + margin.top) + ")")
    .selectAll("g")
    .data([30, 45, 60])
    .enter()
    .append("g")
    .attr("class", "rotatedlines")
    .attr("transform", function(d) { return "rotate(" + -d + ")"; })
    .attr("stroke-width", 1)
    .attr("stroke", "black")
    .attr("stroke-dasharray", "5,5");

您可以通过d3.event.target.extent()访问笔刷范围。绘制比例尺的流程是这样的:

  • 设置比例
  • 设置轴
  • 画轴

笔刷一刷完,就要修改比例,然后根据当前的x和y域重新绘制坐标轴。你是这个意思吗?

我整理了一下代码并做了一点演示:http://plnkr.co/edit/epKbXbcBR2MiwUOMlU5A?p=preview

解释我的解决方案:

要采取的基本步骤如下:

  • 将 x 和 y 尺度的域更新为笔刷范围
  • 重新绘制轴
  • 计算线的比例因子和平移
  • 相应地缩放和平移线容器
  • 重置画笔

请注意,第 3 步和第 4 步是必需的,因为您没有使用比例来绘制所有内容——更好的方法是为每条线定义两个点作为绑定到元素的数据,然后使用要重绘的比例尺。这将使代码更简单。

用你的方法还是有可能的。为了方便它,我对您的代码做了一些修改——特别是,我清理了具有不同翻译的各种嵌套 g 元素,并通过它们的 x1 定义了行, x2y1y2 属性而不是通过编译容器。这两项更改都使您想要的功能更容易实现,因为只发生一个转换,不需要考虑多个其他转换。我还将线条嵌套在多个 g 元素中,以便可以更轻松地缩放和翻译它们。

画笔处理函数现在看起来像这样:

// update scales, redraw axes
var extent = brush.extent();
x.domain(brush.empty() ? x2.domain() : [ extent[0][0], extent[1][0] ]);
y.domain(brush.empty() ? y2.domain() : [ extent[0][1], extent[1][1] ]);
xAxisG.call(xAxis);
yAxisG.call(yAxis);

这段代码应该是不言自明的——比例域根据画笔的当前范围更新,轴也重新绘制。

// compute and apply scaling and transformation of the g elements containing the lines
var sx = (x2.domain()[1] - x2.domain()[0])/(x.domain()[1] - x.domain()[0]),
    sy = (y2.domain()[1] - y2.domain()[0])/(y.domain()[1] - y.domain()[0]),
    dx = -x2(x.domain()[0]) - x2.range()[0],
    dy = -y2(y.domain()[1]) - y2.range()[1];
d3.selectAll("g.container")
  .attr("transform", "translate(" + [sx * dx, sy * dy] + ")scale(" + [sx, sy] + ")");

这是棘手的部分——基于新的比例域,我们需要计算线条的比例和平移。比例因子只是旧范围与新范围的比率(请注意,我复制了未修改的比例),即大于 1 的数字。平移决定了 (0,0)坐标并通过旧 (0,0) 坐标(我从原始尺度的范围中得到)和根据原始尺度的新域原点的位置的差异计算。

同时应用平移和缩放时,我们需要将偏移量乘以缩放因子。

// reset brush
brush.clear();
d3.select(".brush").call(brush);

最后,我们清除画笔并重置它以摆脱灰色矩形。

完成演示 here