繁体   English   中英

辅助功能:d3画笔/缩放可以获得焦点并通过键盘控制

[英]Accessibility: d3 brush/zoom can get focus and be controlled with keyboard

任何提示如何使用键盘控制d3刷/变焦的提示:1。能够专注于画笔控制2.能够使用键盘更改画笔区域

开箱即用吗?

在此输入图像描述

更新 :显然没有开箱即用的解决方案(希望d3会在某个时候提供它)。 这意味着自定义解决方案将取决于可视化/方案。 发布实际的用户体验和要求,并为此特定案例提供解决方案。

为了满足可访问性要求,任务是修改下面的图表控件,以便能够使用键盘进行缩放/刷新。 这包括:1)能够设置焦点; 2)能够使用左右箭头键进行控制。

在此输入图像描述

我将使用这个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));

这两个功能:

  • 检查是否应该执行该函数的主体
  • 设置一个新的x scale域
  • 更新区域和轴

差异很重要:

刷子功能使用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作为关键输入:

  • a:潘左
  • d:向右平移
  • w:放大
  • s:缩小。

最后一点:我已经包含了一项检查,以确保新域位于边界内:我们不想缩放超出数据域的范围。

这是一个例子。

由于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM