[英]Accessibility: d3 brush/zoom can get focus and be controlled with keyboard
我将使用这个bl.ock作为参考。 我相信它是你形象的源泉。
缩放和画笔功能比较
我们感兴趣的是这个块中的几个东西,缩放代码和刷牙代码:
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
这两个功能:
差异很重要:
刷子功能使用d3.zoomIdentity更新比例,它必须这样做,因为它需要更新缩放功能以反映当前缩放比例和变换。
缩放功能手动设置画笔,它必须这样做,因为画笔需要更新。
放大并刷“没有事件”
要通过键盘控制它,可能更容易使用brushed()函数作为模板。 这是因为当前缩放变换可能难以检索,而相对容易欺骗画笔中的变化。
在brushed函数中,d3.event.selection中的值是一个数组,包含画笔包含的值范围(范围中的值,而不是域)。 它是由画笔覆盖的参考/上下文比例x2中的最小和最大范围值的数组。 这是我们唯一需要更新缩放和画笔的东西。
要放大,我们可以获取焦点x比例的域并找到域的最小值和最大值。 然后我们可以重新设置焦点x比例的域稍微小一点,有效地放大。 下面的代码将域转换为范围,并在将其转换回域之前缩小范围 - 这是不必要的,但更紧密地遵循brushed()函数并且意味着不必处理日期。
var xMin = x2(x.domain()[0]);
var xMax = x2(x.domain()[1]);
var currentDifference = Math.abs(xMin-xMax);
xMin += currentDifference / 2 / 3 // increase the minimum value of the domain
xMax -= currentDifference / 2 / 3 // decrease the maximum value of the domain
x.domain([xMin,xMax].map(x2.invert, x2));
我们也可以这样设置缩放比例:
var identity = d3.zoomIdentity
.scale(width/ (xMax - xMin))
我们还想修改缩放的变换,以便我们放大到前一个更大域的中心。 以下只是示例块中使用的代码的再现,但为了说明,名称更清晰:
var identity = d3.zoomIdentity
.scale(width/ (xMax - xMin))
.translate(-xMin, 0);
如果我们使用brushed函数作为模板,我们最终可能会:
var xMin = x2(x.domain()[0]); // minimum value in x range currently
var xMax = x2(x.domain()[1]); // maximum value in x range currently
var currentDifference = Math.abs(xMax-xMin); // center point of range
xMin += currentDifference / 2 / 3 // reduce the distance between center point and end points
xMax -= currentDifference / 2 / 3
x.domain([xMin,xMax].map(x2.invert, x2)); // convert the range to a domain
focus.select(".area").attr("d", area); // redraw the chart
focus.select(".axis--x").call(xAxis); // redraw the axis
var identity = d3.zoomIdentity
.scale(width/ (xMax - xMin))
.translate(-xMin, 0); // update the zoom factor
context.select(".brush").call(brush.move, x.range().map(identity.invertX, identity)); // update the brush
svg.select(".zoom").call(zoom.transform, identity); // apply the zoom factor
这会将焦点区域缩放到以当前域中心为中心的区域。 使用上面的代码,域将缩小三分之一,但可以根据您的需要进行更改。
与原始拉丝功能相比,唯一真正的区别是我们:
这就对了。
其他行动
您可以通过展开而不缩小域来缩小,只需在定义新终点时切换符号:
xMin -= currentDifference / 2 / 3
xMax += currentDifference / 2 / 3
向左移动看起来像:
xMin -= currentDifference / 2 / 3
xMax -= currentDifference / 2 / 3
而自然地向右移动则恰恰相反。
添加键盘
现在你所要做的就是设置一个监听器来监听击键:
d3.select("body")
.on("keypress", function() {
if (d3.event.key == "a") {
// one of zoom in/out/pan
}
else if (d3.event.key == "b" {
//...
}
});
全部放在一起
我已经组装了一个显示所有内容的块,我使用asdw作为关键输入:
最后一点:我已经包含了一项检查,以确保新域位于边界内:我们不想缩放超出数据域的范围。
这是一个例子。
由于SVG 2.0还没有在这里,并且在SVG 1.0中不支持可聚焦元素,我最终使用<a xlink:href="#">
技巧来关注左/右刻度。 还决定获得整个画笔元素的焦点不一定是因为通过左/右刻度移动可以实现适当的范围。
private createResizeTick(resizeClass: string, id: string, brushTickClass: string, tickIndex: number, bottom: number) {
let self = this;
// +++++++++++++++++++ NEW CODE +++++++++++++++++++
let aElement = this._xBrushElement.selectAll(resizeClass)
.append('a')
.attr('id', id)
.attr('xlink:href', '#')
.on('keydown', () => {
if ((<KeyboardEvent>d3.event).keyCode !== 37 && (<KeyboardEvent>d3.event).keyCode !== 39) {
return;
}
// A function which adjusts brush's domain (specific to data model)
self.brushKeyMove((<KeyboardEvent>d3.event).keyCode, tickIndex);
})
.on('keyup', () => {
if ((<KeyboardEvent>d3.event).keyCode !== 37 && (<KeyboardEvent>d3.event).keyCode !== 39) {
return;
}
self.brushOnEnd(); // A function which already processes native onBrushEnd event
document.getElementById(id).focus();
});
// --------------- END OF NEW CODE ---------------
aElement.append('text')
.attr('class', 'brushtick ' + brushTickClass)
.attr('transform', 'translate(0,' + bottom + ')')
.attr('x', 0)
.attr('y', 6)
.attr('dy', '0.35em');
}
结果如下:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.