使用 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
定义了行, x2
、y1
、y2
属性而不是通过编译容器。这两项更改都使您想要的功能更容易实现,因为只发生一个转换,不需要考虑多个其他转换。我还将线条嵌套在多个 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。
我正在研究 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
定义了行, x2
、y1
、y2
属性而不是通过编译容器。这两项更改都使您想要的功能更容易实现,因为只发生一个转换,不需要考虑多个其他转换。我还将线条嵌套在多个 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。