跳至内容

d3-brush

刷选是指使用指向手势(例如单击并拖动鼠标)交互式地指定一个或二维选定区域。刷选通常用于选择离散元素,例如散点图中的点或桌面上的文件。它也可以用于放大感兴趣的区域,或选择连续区域以进行 跨过滤器数据 或实时直方图

Mona Lisa Histogram

d3-brush 模块使用 SVG 为鼠标和触摸事件实现刷选。单击并拖动刷选区域以平移选定区域。单击并拖动其中一个选定句柄以移动选定区域的相应边(或边)。单击并拖动不可见的覆盖层以定义新的刷选区域,或者在可刷选区域内单击并按住 META(⌘)键。在移动刷选时按住 ALT(⌥)键会导致其围绕其中心重新定位,而按住 SPACE 键会锁定当前刷选大小,只允许平移。

刷选还支持程序化控制。例如,您可以监听 结束 事件,然后使用 brush.move 启动过渡以将刷选区域捕捉到语义边界

Brush Snapping

或者您可以让刷选区域在您单击当前选定区域之外时重新居中

Click-to-Recenter

brush()

示例 · 源代码 · 创建一个新的二维刷选。

brushX()

示例 · 源代码 · 创建一个沿 x 维度的新一维刷选。

brushY()

源代码 · 创建一个沿 y 维度的新一维刷选。

brush(group)

示例 · 源代码 · 将刷选应用于指定的 group,它必须是 SVG G 元素选择。此函数通常不会直接调用,而是通过 selection.call 调用。例如,要渲染一个刷选

js
svg.append("g")
    .attr("class", "brush")
    .call(d3.brush().on("brush", brushed));

在内部,刷选使用 selection.on 来绑定必要的拖动事件监听器。监听器使用名称 .brush,因此您可以随后取消绑定刷选事件监听器,如下所示

js
group.on(".brush", null);

刷选还会创建显示刷选区域和接收交互输入事件所需的 SVG 元素。您可以根据需要添加、删除或修改这些元素以更改刷选外观;您也可以应用样式表以修改刷选外观。二维刷选的结构如下所示

html
<g class="brush" fill="none" pointer-events="all" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
  <rect class="overlay" pointer-events="all" cursor="crosshair" x="0" y="0" width="960" height="500"></rect>
  <rect class="selection" cursor="move" fill="#777" fill-opacity="0.3" stroke="#fff" shape-rendering="crispEdges" x="112" y="194" width="182" height="83"></rect>
  <rect class="handle handle--n" cursor="ns-resize" x="107" y="189" width="192" height="10"></rect>
  <rect class="handle handle--e" cursor="ew-resize" x="289" y="189" width="10" height="93"></rect>
  <rect class="handle handle--s" cursor="ns-resize" x="107" y="272" width="192" height="10"></rect>
  <rect class="handle handle--w" cursor="ew-resize" x="107" y="189" width="10" height="93"></rect>
  <rect class="handle handle--nw" cursor="nwse-resize" x="107" y="189" width="10" height="10"></rect>
  <rect class="handle handle--ne" cursor="nesw-resize" x="289" y="189" width="10" height="10"></rect>
  <rect class="handle handle--se" cursor="nwse-resize" x="289" y="272" width="10" height="10"></rect>
  <rect class="handle handle--sw" cursor="nesw-resize" x="107" y="272" width="10" height="10"></rect>
</g>

覆盖矩形覆盖由 brush.extent 定义的可刷选区域。选择矩形覆盖由当前 刷选区域 定义的区域。句柄矩形覆盖刷选区域的边缘和角,允许交互式地修改刷选区域中的相应值。要以编程方式修改刷选区域,请使用 brush.move.

brush.move(group, selection, event)

示例 · 源代码 · 在指定的 group 上设置刷选的活动 selection,它必须是 SVG G 元素选择过渡selection 必须定义为一个数字数组,或为 null 以清除刷选区域。对于 二维刷选,它必须定义为 [[x0, y0], [x1, y1]],其中 x0 是最小 x 值,y0 是最小 y 值,x1 是最大 x 值,而 y1 是最大 y 值。对于 x 刷选,它必须定义为 [x0, x1];对于 y 刷选,它必须定义为 [y0, y1]。选定区域也可以指定为一个函数,该函数返回这样的数组;如果是一个函数,它将为每个选定元素调用,并传递当前数据 d 和索引 i,其中 this 上下文为当前 DOM 元素。返回的数组定义该元素的刷选区域。

brush.clear(group, event)

示例 · 源代码 · brush.move 的别名,带有 null 选定区域。

brush.extent(extent)

示例 · 源代码 · 如果指定了 extent,则将可刷选区域设置为指定点的数组 [[x0, y0], [x1, y1]],其中 [x0, y0] 是左上角,而 [x1, y1] 是右下角,并返回此刷选。extent 也可以指定为一个函数,该函数返回这样的数组;如果是一个函数,它将为每个选定元素调用,并传递当前数据 d 和索引 i,其中 this 上下文为当前 DOM 元素。如果未指定 extent,则返回当前区域访问器,该访问器默认为

js
function defaultExtent() {
  var svg = this.ownerSVGElement || this;
  if (svg.hasAttribute("viewBox")) {
    svg = svg.viewBox.baseVal;
    return [[svg.x, svg.y], [svg.x + svg.width, svg.y + svg.height]];
  }
  return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
}

此默认实现要求拥有者 SVG 元素具有定义的 viewBox,或 widthheight 属性。或者,考虑使用 element.getBoundingClientRect。(在 Firefox 中,element.clientWidthelement.clientHeight 对于 SVG 元素为零!)

刷选区域决定了不可见覆盖层的大小,也限制了刷选区域;刷选区域不能超出刷选区域。

brush.filter(filter)

示例 · 源代码 · 如果指定了 filter,则将过滤器设置为指定的函数并返回刷选。如果未指定 filter,则返回当前过滤器,该过滤器默认为

js
function filter(event) {
  return !event.ctrlKey && !event.button;
}

如果过滤器返回假值,则会忽略启动事件,并且不会启动任何刷选手势。因此,过滤器确定哪些输入事件会被忽略。默认过滤器会忽略次要按钮上的 mousedown 事件,因为这些按钮通常用于其他目的,例如上下文菜单。

brush.touchable(touchable)

源代码 · 如果指定了 touchable,则将触摸支持检测器设置为指定的函数并返回刷选。如果未指定 touchable,则返回当前触摸支持检测器,该检测器默认为

js
function touchable() {
  return navigator.maxTouchPoints || ("ontouchstart" in this);
}

只有当检测器在刷选 应用 时对于相应元素返回真值时,才会注册触摸事件监听器。默认检测器适用于大多数能够进行触摸输入的浏览器,但并非所有浏览器;例如,Chrome 的移动设备模拟器无法检测到。

brush.keyModifiers(modifiers)

源代码 · 如果指定了 modifiers,则设置刷选在刷选期间是否监听按键事件并返回刷选。如果未指定 modifiers,则返回当前行为,该行为默认为 true。

brush.handleSize(size)

源代码 · 如果指定了 size,则将画笔手柄的大小设置为指定数字并返回画笔。如果未指定 size,则返回当前手柄大小,默认值为 6。此方法必须在 将画笔应用于选择 之前调用;更改手柄大小不会影响之前呈现的画笔。

brush.on(typenames, listener)

源代码 · 如果指定了 listener,则为指定的 typenames 设置事件 listener 并返回画笔。如果已为相同类型和名称注册了事件监听器,则在添加新的监听器之前会移除现有的监听器。如果 listener 为 null,则移除指定的 typenames 的当前事件监听器(如果有)。如果未指定 listener,则返回与指定的 typenames 匹配的第一个当前分配的监听器(如果有)。当分派指定事件时,每个 listener 将使用与 selection.on 监听器相同的上下文和参数调用:当前事件 event 和数据 d,其中 this 上下文为当前 DOM 元素。

typenames 是一个字符串,包含一个或多个用空格分隔的 typename。每个 typename 是一个 type,后面可以 optionally 跟着一个点 (.) 和一个 name,例如 brush.foobrush.bar;名称允许为相同 type 注册多个监听器。type 必须是以下之一

  • start - 在画笔手势开始时,例如在鼠标按下时。
  • brush - 当画笔移动时,例如在鼠标移动时。
  • end - 在画笔手势结束时,例如在鼠标松开时。

有关更多信息,请参阅 dispatch.on画笔事件

brushSelection(node)

示例 · 源代码 · 返回指定 node 的当前画笔选择。在内部,元素的画笔状态存储为 element.__brush;但是,您应该使用此方法而不是直接访问它。如果给定的 node 没有选择,则返回 null。否则,selection 被定义为一个数字数组。对于 二维画笔,它是 [[x0, y0], [x1, y1]],其中 x0 是最小 x 值,y0 是最小 y 值,x1 是最大 x 值,y1 是最大 y 值。对于 x 画笔,它是 [x0, x1];对于 y 画笔,它是 [y0, y1]。

画笔事件

当调用 画笔事件监听器 时,它会收到当前的画笔事件。event 对象公开了一些字段

  • target - 关联的 画笔行为
  • type - 字符串“start”、“brush”或“end”;请参阅 brush.on
  • selection - 当前的 画笔选择
  • sourceEvent - 底层的输入事件,例如鼠标移动或触摸移动。
  • mode - 字符串“drag”、“space”、“handle”或“center”;画笔的模式。