我正在使用d3.js,并想知道如何获取范围的边缘、宽度、坐标等信息。在这个例子中http://bl.ocks.org/mbostock/1667367
使用刷子控件时,可以通过刷子对象上的 .extent()
方法访问有关刷子状态的信息。
.extent()
方法返回的信息取决于您连接到刷子对象的比例尺类型。
如果您连接了一个比例尺(无论是 X 轴比例尺还是 Y 轴比例尺,但不是两者都连接),则 extent 方法返回形式为 [minimum, maximum]
的两个元素的数组。
如果您将 X 和 Y 比例尺都附加到刷子对象,则 extent 方法返回嵌套形式的数组: [[xMinimum, yMinimum], [xMaximum, yMaximum]]
但是,这些最小值和最大值是什么?这也取决于比例尺。如果比例尺具有有效的 .invert(value)
方法,则最小值和最大值将转换为您的数据域值。对于离散型、阈值型和其他没有简单的 invert
方法的比例尺,刷子函数将返回在刷子元素有效的坐标系中的值。
要回答您所链接的特定示例的问题,需要查看刷子对象和比例尺对象。在该示例中,刷子连接到较小的“上下文”图表(x2
比例尺)的水平比例尺上:
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
上面创建的画笔对象仅存在于Javascript中,而不在文档中。 然而,该对象也是一个函数,可以调用(类似于轴函数),以创建一系列响应鼠标事件的矩形(这些矩形是不可见的),以及一个“extent”矩形(在此示例中为带白色边框的灰色)。
context.append("g")
.attr("class", "x brush")
.call(brush) //call the brush function, causing it to create the rectangles
.selectAll("rect") //select all the just-created rectangles
.attr("y", -6)
.attr("height", height2 + 7); //set their height
不可见矩形的默认大小基于X和Y比例尺的输出范围。由于此刷子没有Y比例尺,因此必须明确设置矩形的恒定高度和垂直位置。
extent矩形的初始大小基于brush对象的范围(默认情况下宽度和高度为零)。该矩形的高度也在上述代码中设置。
当用户与屏幕上的刷子进行交互时,刷子对象会捕获这些事件并(1)更新“extent”矩形的宽度,(2)调用你在.on("brush", brushed)
中关联的“brush”事件的函数。
brushed()
函数是:
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
该刷子的目的是对主图进行缩放,这是通过设置主图X轴的域来实现的。如果刷子的宽度为零,则brush.empty()
返回true,主图的X轴域设置为小图中显示的完整域。
然而,如果刷子具有有效宽度,则空测试返回false,并将域设置为brush.extent()
的结果。因为刷子附加到一个线性X比例尺上,没有Y比例尺,所以范围以[xMin, xMax]
(在数据数字中)的形式返回,这正好是设置域所需的。
如果您需要了解数据值中的宽度,只需简单地减去即可:
var extent = brush.extent(); //returns [xMin, xMax]
var width = extent[1] - extent[0]; //data-width = max - min
然而,如果您要在屏幕上绘制其他元素,则需要知道SVG中的实际坐标,而不仅仅是数据值。 要进行转换,您使用与将数据转换为SVG坐标所用的相同内容:比例尺函数。请牢记使用控制小图表的x2
比例尺,而不是主图表缩放的比例尺,那就是:
var extent = brush.extent(); //returns [xMin, xMax]
var rangeExtent = [x2( extent[0] ), x2( extent[1] ) ]; //convert
var rangeWidth = rangeExtent[1] - rangeExtent[0];
再次强调,此示例是针对具有 一个(水平 / X)线性尺度的刷子。如果您同时使用 X 和 Y 线性尺度,则需要使用以下代码分离出 X 和 Y 范围值:
function brushed() {
if (brush.empty()) {
//either the height OR the width is empty
x.domain( x2.domain() ); //reset X scale
y.domain( y2.domain() ); //reset Y scale
}
var extent = brush.extent();
x.domain( [extent[0][0] , extent[1][0] ] ); //min and max data X values
y.domain( [extent[0][1] , extent[1][1] ] ); //min and max data Y values
var rangeExtent = [
[x2(extent[0][0]), y2(extent[0][1])],
[x2(extent[1][0]), y2(extent[1][1])]
];
var rangeWidth = rangeExtent[1][0] - rangeExtent[0][0];
var rangeHeight = rangeExtent[1][1] - rangeExtent[0][1];
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
focus.select(".y.axis").call(yAxis);
}
如果你想知道矩形左上角的坐标,你还需要知道你的Y轴比例尺是否将最小值从顶部向下切换。
或者,你可以从屏幕上的“范围”矩形获取宽度、高度和左上角坐标,刷子对象会为你修改它:
function brushed() {
//use the brush object's values to set the data domains:
if (brush.empty()) {
//either the height OR the width is empty
x.domain( x2.domain() ); //reset X scale
y.domain( y2.domain() ); //reset Y scale
}
var extent = brush.extent();
x.domain( [extent[0][0] , extent[1][0] ] ); //min and max data X values
y.domain( [extent[0][1] , extent[1][1] ] ); //min and max data Y values
//use the brush extent rectangle to get the SVG coordinates:
var extentRect = d3.select("g.x.brush rect.extent");
var rangeWidth = extentRect.attr("width");
var rangeHeight = extentRect.attr("height");
var rangeLeft = extentRect.attr("x");
var rangeTop = extentRect.attr("y");
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
focus.select(".y.axis").call(yAxis);
}
如果你正在使用序数刻度,缩放会更加复杂,但查找屏幕坐标则较为简单。 这个答案描述了如何使用一个带有序数刻度的brush来缩放。然而,由于.extent()
返回的值已经在SVG坐标中,如果需要坐标和宽度,则无需使用比例尺自身进行转换。
Brush控件的API页面在页面顶部有一组缩略图像;单击其中任意一个即可打开一个工作示例。对于更多讨论,您可能会对这篇带有另一个很好的brush实例的教程感兴趣。