@visx/brush 使用指南:为 visx 图表实现 Brush 框选与区域缩放交互

发布时间:2026/9/20 6:21:47
@visx/brush 使用指南:为 visx 图表实现 Brush 框选与区域缩放交互 数据可视化前端图表库【免费下载链接】visx visx | visualization components项目地址https://gitcode.com/gh_mirrors/vi/visx点击查看免费下载visx 是 Airbnb 开源的一套基于 React D3 的可视化组件库其中visx/brush用于在图表或坐标轴上框选子区域是实现缩放到选中区间、时间范围选择、联动过滤等交互的核心组件。本文将围绕 packages/visx-brush/Readme.md 展开结合仓库源码与测试系统讲解 Brush 的安装方式、核心 Props、内部工作流程与回调数据结构帮助你直接在项目中落地一套可运行、可定制的框选交互。安装visx/brush是一个独立的 npm 包安装方式与 visx 其他模块一致npm install --save visx/brush从 package.json 可以看到它同时提供 CommonJSlib/index.js与 ESMesm/index.js两种产物声明了sideEffects: false可被打包工具安全地做 Tree Shaking。它的运行依赖包括visx/drag、visx/event、visx/group、visx/scale、visx/shape与classnames其中拖拽核心逻辑由visx/drag提供。注意react是 peerDependency要求 React 18 或 19^18.0.0 || ^19.0.0。包的唯一对外导出是Brush组件见 src/index.tsexport { default as Brush } from ./Brush; export type * from ./types;也就是说你在使用时只需要import { Brush } from visx/brush即可。Brush 是什么官方文档对其定位只有一句话A brush allows you to select a sub-region of your chart or axisBrush 允许你选择图表或坐标轴的子区域。一个典型的场景是在图表下方放置一个迷你总览图overview用户用鼠标在总览图上拖出一个矩形选区主图detail view随即缩放到该区间——这正是 visx-demo 中 brush 示例如pages/brush呈现的效果。Brush 既能横向、纵向框选也能整体拖动选区、拖拽选区边缘或角落调整大小。核心 Props 一览Brush组件本身的全部 Props 定义在 src/Brush.tsx 中下面按用途分组说明。坐标与尺寸Prop类型默认值说明xScaleScalenullx 轴比例尺用于把选区像素范围反算为数据域domainyScaleScalenully 轴比例尺用于把选区像素范围反算为数据域widthnumber0Brush 舞台stage宽度heightnumber0Brush 舞台高度marginMarginShape全 0从舞台尺寸中减去的边距top/left/right/bottom注意Scale类型来自visx/scale的D3Scale见 src/types.ts因此连续型比例尺linear/time/log与离散型比例尺ordinal/band/point都可以传入组件内部会针对两种类型分别做反算处理下文详述。回调Prop类型说明onChange(bounds: Bounds \| null) void选区变化拖动/缩放过程中即触发最常用onBrushStart(start) void一次框选初始化时触发不是移动时onBrushEnd(bounds: Bounds \| null) void鼠标松开、选区尺寸更新结束时触发onMouseMove函数未拖拽时鼠标在舞台内移动onMouseLeave函数鼠标离开舞台onClick函数点击舞台三个 Brush 回调都携带Bounds结构见 src/types.tstype Bounds { x0: number; // 选区的起始 x已经是数据域domain值 x1: number; // 选区的结束 x数据域值 xValues?: unknown[]; // 仅离散比例尺时存在被框住的离散值数组 y0: number; y1: number; yValues?: unknown[]; };关键点回调里拿到的不是像素坐标而是经过比例尺反算后的数据域。看 src/Brush.tsx 的handleChange/convertRangeToDomainhandleChange (brush: BaseBrushState) { const { onChange } this.props; if (!onChange) return; const { x0 } brush.extent; // 选区尚未真正形成x0 未定义或为负时回传 null if (typeof x0 undefined || x0 0) { onChange(null); return; } onChange(this.convertRangeToDomain(brush)); };extent中的x0/x1/y0/y1是像素值convertRangeToDomain调用getDomainFromExtent(xScale, x0, x1, SAFE_PIXEL)SAFE_PIXEL 2src/Brush.tsx将其转换为数据域。因此你的典型用法是拿到bounds后直接xScale.domain(bounds.x0 ~ x1)去更新主图无需自己做像素换算。选区行为Prop类型默认值说明brushDirectionvertical \| horizontal \| bothhorizontal允许框选的方向initialBrushPositionPartialBrushStartEndnull初始选区的start/end像素坐标可只传 x 或 y 一部分resizeTriggerAreasResizeTriggerAreas[][left, right]允许通过哪些边/角调整选区大小left/right/top/bottom/topLeft/topRight/bottomLeft/bottomRightbrushRegionxAxis \| yAxis \| chartchart框选的对象区域决定舞台的定位与尺寸计算xAxisOrientationtop \| bottombottombrushRegionxAxis时 x 轴所在方位yAxisOrientationleft \| rightrightbrushRegionyAxis时 y 轴所在方位selectedBoxStyleSVGPropsSVGRectElement见下选中矩形selection rect的样式disableDraggingSelectionbooleanfalse是否禁止拖动整个选区disableDraggingOverlaybooleanfalse是否禁止在舞台空白处点击创建/移动选区resetOnEndbooleanfalse拖拽结束后是否重置 Brush 为空闲状态handleSizenumber4缩放手柄尺寸作用于所有resizeTriggerAreasuseWindowMoveEventsbooleanfalse是否把拖拽事件挂到 window 上防止拖出舞台后事件丢失renderBrushHandle(props) ReactNodenull自定义手柄渲染函数innerRefRefBaseBrush—拿到内部BaseBrush实例的引用可调用其命令式方法selectedBoxStyle的默认值src/Brush.tsx{ fill: steelblue, fillOpacity: 0.2, stroke: steelblue, strokeWidth: 1, strokeOpacity: 0.8, }brushRegion在图表上框选还是在坐标轴上框选brushRegion是 Brush 区别于一般框选组件的关键能力——它允许你只框选图表的绘图区、x 轴区域或y 轴区域。舞台的定位与尺寸计算在 src/Brush.tsxchart舞台覆盖整个图表区域left 0, top 0宽高等于width/heightyAxis舞台覆盖 y 轴所在边距。yAxisOrientationright时left width宽度取marginRightleft时left -marginLeft宽度取marginLeftxAxis舞台覆盖 x 轴所在边距。xAxisOrientationbottom时top height高度取marginBottomtop时top -marginTop高度取marginTop。因此使用 x 轴框选时你需要把布局设计成图表下方留出 x 轴高度即设置margin.bottomBrush 的舞台才会落在正确的轴带区域。内部架构BaseBrush 与四个子组件Brush是一个薄封装src/Brush.tsx负责将像素选区换算为数据域、计算 brushRegion 舞台几何、把margin与回调透传给内部的BaseBrush。真正承载交互状态机的是BaseBrushsrc/BaseBrush.tsx它是一个 class 组件内部维护BaseBrushStatetype BaseBrushState { start: Point; // 选区起点像素 end: Point; // 选区终点像素 extent: Bounds; // 像素范围的 x0/x1/y0/y1 bounds: Bounds; // 舞台可活动边界 isBrushing: boolean; // 是否正在框选 brushingType?: move | select | ResizeTriggerAreas; // 当前交互类型 activeHandle: ResizeTriggerAreas | null; };BaseBrush的 render 由四种子组件拼装目录见 src/BrushOverlaysrc/BrushOverlay.tsx覆盖整个舞台的透明Bar来自visx/shape负责接收 pointer 事件以从空白处拉出选区或整体移动选区BrushSelectionsrc/BrushSelection.tsx半透明选中矩形selectedBoxStyle并在四边/四角渲染 8 个缩放触发区BrushHandle / BrushCornersrc/BrushHandle.tsx、src/BrushCorner.tsx选区边缘与角落的缩放手柄可用renderBrushHandle自定义渲染内部再套用visx/drag的Drag组件完成拖拽坐标跟踪。BaseBrush对拖拽的三种交互做了分支处理src/BaseBrush.tsxselect以起始点与实时指针位置计算 extentmove整体平移选区并夹取在bounds内validDx/validDy做了边界钳制边/角缩放如left/right/top/bottom分别只移动对应的边。当width/height变化如窗口缩放导致父容器尺寸变化时componentDidUpdate会按比例缩放现有 extent 以保持选区相对位置src/BaseBrush.tsx。另外开启useWindowMoveEvents后componentDidMount会在window上挂mouseup/mousemove监听避免鼠标移出舞台导致拖拽中断。比例尺反算scaleInvert 与 getDomainFromExtent把像素 extent 转回数据域依赖 src/utils.ts 中的两个函数scaleInvert(scale, value)src/utils.ts若比例尺自带invert连续型如 scaleLinear/scaleTime直接调用scale.invert(value)否则视为离散比例尺ordinal/band/point因为没有invert会利用range与step()计算出每个 band 的宽度通过循环确定value落在第几个 band返回对应索引。getDomainFromExtent(scale, start, end, tolerentDelta)src/utils.ts对选区两端做容差偏移SAFE_PIXEL 2把 start/end 反算为数据域连续比例尺返回{ start, end }离散比例尺返回{ values }即scale.domain()中被框住的那一段值数组。这正是Bounds中xValues/yValues的来源。对应的单测覆盖在 test/utils.test.ts例如验证了连续比例尺下start/end等于scale.invert(边界±容差)离散比例尺下values等于被框住的 domain 项Brush组件的冒烟测试见 test/Brush.test.tsx。实战示例总览图联动主图缩放下面给出一个可直接运行的骨架总览图上的Brush框选结果反向驱动主图的xScale.domain。import { useState } from react; import { Brush } from visx/brush; import { scaleLinear } from visx/scale; import type { Bounds } from visx/brush/lib/types; function BrushOverview({ width, height, data }: { width: number; height: number; data: number[] }) { // 主图的 x 域由 Brush 回调驱动 const [xDomain, setXDomain] useState[number, number]([0, data.length - 1]); const xScale scaleLinearnumber({ range: [0, width], domain: [0, data.length - 1], }); const onBrushChange (bounds: Bounds | null) { if (!bounds) return; // bounds.x0/x1 已由 Brush 内部反算为数据域可直接使用 setXDomain([bounds.x0, bounds.x1]); }; return ( svg width{width} height{height} {/* 这里渲染总览折线等图形 */} Brush xScale{xScale} yScale{scaleLinear({ range: [height, 0], domain: [0, Math.max(...data)] })} width{width} height{height} margin{{ top: 0, left: 0, right: 0, bottom: 0 }} brushDirectionhorizontal resizeTriggerAreas{[left, right]} initialBrushPosition{{ start: { x: 0 }, end: { x: width / 2 } }} onChange{onBrushChange} / /svg ); }几个易错点提醒onChange在选区尚未形成时会回调null代码里务必判空若只需横向框选把brushDirection设为horizontal并只在resizeTriggerAreas中保留[left, right]避免出现 y 方向手柄想框选 x 轴而不是整个图表时设置brushRegionxAxis、xAxisOrientationbottom并把图表布局的下边距留给轴带需要初始就有选区用initialBrushPosition传入像素级start/end可只提供 x 分量在窗口尺寸会变化的容器中使用时Brush 会在width/height变化后按比例维持选区无需手动重置。小结visx/brush以极少的对外 API一个Brush组件、一套回调与Bounds数据结构封装了框选交互的完整状态机内部由BaseBrush驱动拖拽逻辑Brush负责像素到数据域的反算与轴区/图区的舞台定位。理解brushRegion的三类舞台几何、Bounds中连续/离散比例尺的差异化输出以及onChange(null)的空值语义就能快速把它接入总览-详情联动、时间范围选择等典型图表交互中。赞分享数据可视化前端图表库【免费下载链接】visx visx | visualization components项目地址https://gitcode.com/gh_mirrors/vi/visx点击查看免费下载相关推荐visx/brush交互实现构建可筛选数据范围的高级图表控件visx/brush交互实现构建可筛选数据范围的高级图表控件 在数据可视化场景中用户常常需要对图表数据进行局部观察与分析。传统静态图表无法满足动态筛选需求数据可视化前端图表库visx/brush多选功能实现不连续数据范围选择的高级交互visx/brush多选功能实现不连续数据范围选择的高级交互 在数据可视化应用中用户常常需要从图表中选择特定范围的数据进行分析。传统的单选交互只能选择连续数据可视化前端图表库visx/zoom 完整指南用 React 组件为图表与视口实现平移、缩放与手势交互visx/zoom 完整指南用 React 组件为图表与视口实现平移、缩放与手势交互 visx/zoom 是 visx 生态中专门用于交互缩放zoom数据可视化前端图表库上一篇解密Spotify音乐离线化突破流媒体限制的技术重构下一篇实战指南如何在3步内快速集成专业级金融图表库到你的Web应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询