产品需求:ECharts 鼠标自由刷选区域,定向放大图表

一. 背景

在 ECharts 中,图表开发属于最基础的组件开发,适合统计展示各种各样的数据,使用图形化的效果将海量数据直观的展示给用户,以便于让用户能够快速获取到数据展示及走向。但随着用户需求的不断迭代,我们最近的一个项目需求是:

需要将曲线图表的某一段曲线细致的呈现给用户,具体方式为:用户通过鼠标随意框选区域,进而放大展示所框选区域内的数据图表

提前预览效果图如下:

当涉及到框选区域选择并实现定向缩放的需求时,这是一个对于定向查看某段数据来说是非常实用的功能。通过框选区域实现定向缩放,可以帮助用户更方便地查看感兴趣的数据细节,提升数据可视化的交互性和用户体验。

在本篇文章中,我将介绍如何通过 ECharts 的 brushdataZoom 组件结合使用,实现在图表中进行框选区域选择,并实现定向缩放的功能。

二. 初步分析

1. 初步缩放功能

老生常谈,其实这个就是正常的图表缩放的需求,ECharts 提供了最基础的配置图表缩放属性,ECharts 的 dataZoom 组件 用于区域缩放,通过配置 dataZoom 属性实现曲线缩放。从而能自由关注细节的数据信息,或者概览数据整体,或者去除离群点的影响。

其中,最核心的代码如下所示:

javascript 复制代码
option = {
  dataZoom: [
    {
      id: "dataZoomX",
      type: "slider",
      xAxisIndex: [0],
    },
    {
      id: "dataZoomY",
      type: "slider",
      yAxisIndex: [0],
    },
  ],
};

配置完成后,通过鼠标滚轮放大或者拖动 x 轴或 y 轴滑块缩放图表,效果如下所示:

关于 ECharts dataZoom 配置项,如需更详细的使用,请参考 ECharts 官方文档:ECharts dataZoom 配置项参考

2. 探讨其他方案

很显然,以上的这种方案也是开发者最常使用的缩放功能,通过简单的配置 dataZoom 属性,可以实现在坐标轴的 x 轴或 y 轴添加缩放滑块,使用鼠标滚轮放大或者拖动滑块实现对曲线图的放大和缩小。但是这种却不是产品需求所需要的,还需要探索其他的方案来完成。

通过查询 ECharts 官方文档配置项手册,可以发现 ECharts 也提供了其他的方案可以实现曲线图的区域放大,主要有两种方案:

  • 配置 toolbox 工具栏

  • 使用 brush 区域选择组件

接下来,我将对这两种方案进行详细的方案实现和对比,马上开始吧!

三. 方案一:配置 toolbox 工具栏

通过配置 toolbox 工具栏,可以实现对图表数据区域定向缩放功能。

toolbox 为 ECharts 的工具栏,内置有导出图片,数据视图,动态类型切换,数据区域缩放,重置五个工具,如下所示:

  • 导出图片:saveAsImage

  • 数据视图:dataView

  • 动态类型切换:magicType

  • 数据区域缩放:dataZoom

  • 重置:restore

关于 toolbox 工具栏,主要有以上五种。其中,关于区域缩放的工具,就只有 dataZoom 了,因此,第一种实现方案就是配置 toolboxdataZoom 组件,可以实现数据区域缩放,官方目前只支持直角坐标系的缩放。

这种方案相对特别简单,只需要简单的配置一下工具栏,使其工具生效就可以使用框选区域放大了,代码如下所示:

javascript 复制代码
option = {
  toolbox: {
    feature: {
      dataZoom: {
        xAxisIndex: true, // 指定所有x轴被控制
        yAxisIndex: false, // 不控制任何y轴
      },
    },
  },
};

配置好的工具栏如下图所示:

关于更多的 ECharts toolbox 工具栏的其他配置项,本篇文章不做过多的解释,详细请参考官方文档:ECharts toolbox 配置项

四. 方案二:使用 brush 区域选择组件

其实通过以上介绍的这种方案,完全就可以实现刷选区域定向放大图表的需求,按理说文章到这也可以收尾了。但是本着探索的态度,我的好奇心驱使我继续探索是否还有其他的方案实现这种功能。

通过继续查询资料,可以发现,ECharts 还提供了 brush 区域选择组件,用户可以选择图中一部分数据,可以对框选的数据进行自定义操作。

原本,brush 区域选择组件是为了便于向用户展示被选中数据,或者基于被选中的数据做一些统计计算结果。但是,我们我们这里根据产品需求,也可以实现根据选择的区域,定向的放大图表,就是可能需要额外的处理一下刷选事件,再次触发图标行为,使其放大。

因此,第二种方法相对繁琐一些,我总结了以下几个步骤可以使用 brush 实现刷选放大功能。

  • 配置 brush 刷子

  • 监听回调事件

  • 放大图表区域

接下来,我将会对以上这几个步骤进行一一说明。

1. 配置 brush 刷子

配置刷子的类型和启动按钮

目前 brush 组件支持的图表类型:scatterbarcandlestickparallel 本身自带刷选功能,但并非由 brush 组件来提供)。点击 toolbox 中的按钮,能够进行『区域选择 』、『清除选择』等操作。

例如:在 bar 图中的 brush 效果(点击 toolbox 中的按钮启动刷选),可以进行选择 bar

看到这里,我不仅有个疑问,brush 不支持折线图??将信将疑,先不管,继续向下进行。

配置刷子刷选形状

目前刷子支持这几种选框:矩形刷子,任意形状刷子,横向刷子,纵向刷子,brush 相关的 toolbox 按钮如下所示:

  • rect:矩形刷子,开启矩形选框选择功能。

  • polygon:任意形状刷子,开启任意形状选框选择功能。

  • lineX:横向刷子,开启横向选择功能。

  • lineY:纵向刷子,开启纵向选择功能。

  • keep:切换『单选 』和『多选』模式。后者可支持同时画多个选框。前者支持单击清除所有选框。

  • clear:清空所有选框。

在这里,我们主要使用矩形刷子或横向刷子,它们两个的主要区别在于:

  • 横向刷子:主要支持 x 轴的框选操作

  • 矩形刷子:以矩形的形式可以在 x 轴、y 轴进行任意框选

通过代码配置选择使用刷子形状

javascript 复制代码
option = {
  brush: {
    toolbox: ["rect", "lineX", "clear"], // 配置使用矩形刷子、横向刷子、清除选项
  },
};

通过以上的少量配置,我们就实现了使用 brush 刷子框选曲线的功能,但是仅限于框选,框选完成后没有任何操作。效果如下图所示:

关于更多的 brush 刷子个性化的配置,请参考:ECharts brush 配置项

2. 监听回调事件

以上的阶段,我们仅仅实现了使用 brush 刷子框选曲线的功能,但是框选完成后我们应该怎么做?这才是重中之重,我们继续向下看。

通过查阅文档,官方文档也提供了 brush 的相关回调函数,这这里我们主要能使用到的有以下两个事件:

  • events.brushselected:在 setOption 时不会发出,在其他的 dispatchAction 时,或者用户在界面中创建、删除、修改选框时会发出。

  • events.brushEnd:"选框添加完毕"事件。即发出 brushEnd action 得到的事件。

简言之:在使用 brush 进行框选过程中会不断触发 brushselected 事件,在框选结束之后会触发 brushEnd 事件。

因此,在我们对曲线框选结束之后,对所框选的内容进行解析,获取到用户实际的框选数据,然后进行放大曲线。

javascript 复制代码
// 刷选过程触发事件
myChart.on("brushselected", function (params) {
  console.log("brushselected", params);
});
// 刷选完毕事件
myChart.on("brushEnd", function (params) {
  console.log("brushEnd", params);
});

使用上述代码监听刷选事件,得到的回调输出如下所示:

以上的 brushselected 有性能问题,下述会讲解如何优化这个性能问题

监听到刷选事件后,我们可以对其返回的数据进行解析,根据 coordRange 计算框选区域内的 x 轴和 y 轴坐标系的 startValueendValue,然后根据 startValueendValue 进行放大曲线点位。

具体代码如下所示:

javascript 复制代码
myChart.on("brushEnd", function (params) {
  console.log(params);
  if (params.areas.length === 0) {
    return;
  }
  // 根据 coordRange 计算框选区域内的x坐标的startValue和endValue,然后根据startValue和endValue进行放大曲线点位
  const xAxisRange = params.areas[0].coordRange[0];
  const yAxisRange = params.areas[0].coordRange[1];
  const xstartValue = xAxisRange[0]; //x 轴 startValue
  const xendValue = xAxisRange[1]; //x 轴 endValue
  const ystartValue = yAxisRange[0]; //y轴 startValue
  const yendValue = yAxisRange[1]; //y轴 endValue

  console.log("x轴:", xstartValue, xendValue);
  console.log("y轴:", ystartValue, yendValue);
});

提示:在目前的应用场景下,brushEndbrushselected 事件可以二选其一,在这里我使用的 brushEnd 事件。

以上操作,我们获取并解析成功,得到了刷选区域的 x 轴和 y 轴的坐标数据,根据这些数据,就可以适时的放大曲线。在进行下一步操作之前,我们先来优化一下使用 brushSelected 事件而导致的性能问题。

ECharts brush.brushEnd 回调事件 API

3. 避免性能问题

默认情况,刷选或者移动选区的时候,会不断得触发 brushSelected 事件,从而告诉外界选中的内容。

但是频繁的事件可能导致性能问题,或者动画效果很差。所以 brush 组件提供了 brush.throttleTypebrush.throttleDelay 来解决这个问题。

brush.throttleType 取值说明:

  • debounce:表示只有停止动作了(即一段时间没有操作了),才会触发事件。

  • fixRate:表示按照一定的频率触发事件。

brush.throttleDelay 取值说明:

  • 数值为毫秒数,例如:500 表示为 500 毫秒。

  • 默认为 0 表示不开启 throttle

注意:brush.throttleType 时间阈值或时间间隔由 brush.throttleDelay 指定。

通过配置 brush.throttleTypebrush.throttleDelay,可以解决性能问题,代码配置如下所示:

javascript 复制代码
option = {
  brush: {
    toolbox: ["rect", "lineX", "clear"], // 配置使用rect、lineX、clear
    throttleType: "debounce", // 指定为 debounce 模式
    throttleDelay: 500, // 表示按照 500ms 的频率触发事件
  },
};
  • 未配置防抖优化时,在进行刷选图表操作时,可以看见事件触发的密集度。
  • 配置 brush.throttleTypebrush.throttleDelay 后,再次进行刷选图表,可以发现已经没有频繁的事件触发。

4. 放大图表区域

曲线的配置项 option 中有 dataZoom 属性,主要用于区域缩放,关于 dataZoom 的配置,可以配置数据窗口范围,主要通过以下属性:

  • start:数据窗口范围的起始百分比。范围是:0 ~ 100。表示 0% ~ 100%。

  • end:数据窗口范围的结束百分比。范围是:0 ~ 100。

  • startValue:数据窗口范围的起始数值。

  • endValue:数据窗口范围的结束数值。

关于以上数据更详细的解释,你可以继续阅读官方文档:ECharts dataZoom 数据窗口范围配置项

通过以上两组数据,start 和 end 为一组数据,startValue 和 endValue 为一组数据,我们就可以实现曲线窗口的缩放。有以下两种思路可以实现图表放大:

  • 第一种,通过 setOption 重新给曲线设置 option,修改 dataZoom 属性,更新为最新的数据

  • 第二种,通过 dispatchAction 触发图表行为,修改数据区域缩放 dataZoom

在这里我主要使用的 startValue 和 endValue,因为在上面的步骤中,通过对刷选区域回调数据的解析,我们已经得到的数据就是 startValue 和 endValue,因此接下来,我分别对这两种方案进行实现说明:

第一种:通过 setOption 更新 option,放大图表

通过 setOption 更新曲线 option 的 dataZoom 属性,修改 x 轴和 y 轴的 startValueendValue

javascript 复制代码
myChart.setOption({
  dataZoom: [
    {
      xAxisIndex: [0], // 控制x轴
      startValue: startValue, // x轴起始数值
      endValue: endValue, // x轴结束数值
    },
    {
      yAxisIndex: [0], // 控制y轴
      startValue: ystartValue, // y轴起始数值
      endValue: yendValue, // y轴结束数值
    },
  ],
});

第二种:通过 dispatchAction 触发图表行为,放大图表

dispatchAction 为触发图表行为,例如图例开关 legendToggleSelect, 数据区域缩放 dataZoom,显示提示框 showTip 等等。

payload 参数可以通过 batch 属性同时触发多个行为,在这里我们也会使用 batch 同时触发 x 轴和 y 轴的放大。

javascript 复制代码
myChart.dispatchAction({
  type: "dataZoom",
  batch: [
    {
      // 第一个 dataZoom 组件,x轴
      startValue: startValue,
      endValue: endValue,
    },
    {
      // 第二个 dataZoom 组件,y轴
      startValue: ystartValue,
      endValue: yendValue,
    },
  ],
});

关于 dispatchAction 图表行为,更多的详细信息请参考 ECharts dispatchAction 图表行为 API

五. 两种方案对比

先回顾一下,通过以上的介绍,可以有两种方案实现刷选区域放大的功能:

  • 方案一:配置 toolbox 工具栏,添加 dataZoom 缩放组件

  • 方案二:使用 brush 刷子区域选择组件

  1. 方案一简单快捷,只需要简单配置 toolbox 工具栏,即可实现刷选放大功能。

  2. 方案二流程复杂,定制化需求高,可能会出现不明确的 bug。

如果您仅仅是需要刷选放大图表,建议选择方案一;如果您不仅需要放大图表,还需要对刷选区域进行统计数据,建议使用方案二,能够统计计算框内数据,适合定制化统计展示。

六. 注意事项

  1. 在使用 brush 进行刷选或者移动选区的时候,会不断得触发 brushSelected 事件,需要进行节流或防抖事件,避免性能问题。
javascript 复制代码
option = {
  brush: {
    throttleType: "debounce", // 指定为 debounce 模式
    throttleDelay: 500, // 表示按照 500ms 的频率触发事件
  },
};
  • 可以使用官方的配置项,但需要注意 brush.throttleType 时间阈值或时间间隔由 brush.throttleDelay 指定,不指定会失效。
  • 也可以使用防抖或节流函数,是同样的性能优化原理,关于防抖和截流,参考:前端性能优化 | 防抖与节流
  1. 在使用 brush 刷选区域结束并完成区域放大后,需要主动清除所有选框,否则,曲线图上则会存在选框区域未清除。
javascript 复制代码
myChart.dispatchAction({
  type: "brush",
  areas: [],
});
  1. 注意缩放选区的 startendstartValueendValue 对应的值的含义,它们是有区别的。
  • startend 为一组,表示数据窗口范围的起始和结束百分比,表示缩放滑块处于当前坐标轴的百分比

  • startValueendValue 为一组,表示数据窗口范围的起始和结束数值,可以设置为数组值本身,也可以设置为数组的 index,但是如果设置为数组值本身,会在内部自动转化为数组的 index

  1. 特别注意:注意 ECharts 版本的差异性

本文所有的演示示例代码,所使用的 ECharts 版本为 5.4.3,目前官方已经发布了 5.5 的版本。可能在项目中也有用到其他版本的,如果有在项目中使用同样的配置代码但图表效果展示不一致,请先排查一下是否为 ECharts 版本不一致导致的问题,不同的 ECharts 版本可能在使用方式上会有所差异。

七. 总结

通过以上流程性的介绍和学习,按照顺序仔细阅读的话,相信大家对于实现通过鼠标框选区域,放大数据图表的功能有一个清晰的思路,主要有两种方案进行选择,

如果需要快速的使用刷选功能而尽量少的改动代码,就使用方案一:使用 toolbox 配置 dataZoom 区域放大组件,简单快捷,使用方便。如果不仅想要刷选区域放大,还需要对刷选区域进行统计数据,则需要定制使用 brush 刷子,但同时要注意代码的性能优化。

本篇文章到这就结束了,希望能够帮助你更好地理解和使用 ECharts,以上为项目经验所得,如果有任何错误,敬请指出!

如果您感觉文章还不错,点个赞再走吧!

文档资料链接

ECharts 配置项手册:https://echarts.apache.org/zh/option.html

ECharts API 文档:https://echarts.apache.org/zh/api.html

体验 Demo 地址 1

体验 Demo 地址 2

完整代码 option

javascript 复制代码
// 随机生成一些图表数据
const data = Array.from({ length: 100 }, (_, index) => {
  return [
    new Date(Date.UTC(2024, 2, 6, 0, 0, 0) + index * 60 * 1000)
      .toISOString()
      .slice(0, 19)
      .replace("T", " "),
    Math.floor(Math.random() * (40 - 20 + 1)) + 20,
  ];
});
// 完整 option
const option = {
  tooltip: {
    trigger: "axis",
  },
  toolbox: {
    feature: {
      dataZoom: {},
      restore: {},
    },
  },
  brush: {
    throttleType: "debounce",
    throttleDelay: 500,
    xAxisIndex: "all",
    toolbox: ["rect", "clear"],
  },
  xAxis: {
    type: "time",
  },
  yAxis: {
    type: "value",
    name: "温度(°C)",
    min: 0,
    max: 50,
  },
  dataZoom: [
    { type: "slider", xAxisIndex: [0], start: 0, end: 100 },
    { type: "slider", yAxisIndex: [0], start: 0, end: 100 },
  ],
  series: {
    name: "温度(°C)",
    type: "line",
    smooth: true,
    //  随机生成数据
    data: data,
  },
};
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(document.getElementById("main"));
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
myChart.on("brushEnd", function (params) {
  // 判断是否有框选区域
  if (params.areas.length === 0) {
    return;
  }
  console.log(params);
  // 根据 coordRange 计算框选区域内的x坐标的startValue和endValue
  const xAxisRange = params.areas[0].coordRange[0];
  const yAxisRange = params.areas[0].coordRange[1];
  const xstartValue = xAxisRange[0]; //x 轴 startValue
  const xendValue = xAxisRange[1]; //x 轴 endValue
  const ystartValue = yAxisRange[0]; //y轴 startValue
  const yendValue = yAxisRange[1]; //y轴 endValue
  console.log("x轴:", xstartValue, xendValue);
  console.log("y轴:", ystartValue, yendValue);
  // 图表行为,根据startValue和endValue进行放大图表区域
  myChart.setOption({
    dataZoom: [
      {
        xAxisIndex: [0], // 控制x轴
        startValue: xstartValue, // x轴起始数值
        endValue: xendValue, // x轴结束数值
      },
      {
        yAxisIndex: [0], // 控制y轴
        startValue: ystartValue, // y轴起始数值
        endValue: yendValue, // y轴结束数值
      },
    ],
  });
  // 如果 areas 为空,则删除所有选框。否则,曲线图上则会存在选框区域未清除
  myChart.dispatchAction({
    type: "brush",
    areas: [],
  });
});

如果您感觉文章还不错,点个赞再走吧!

相关推荐
热爱编程的小曾16 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin28 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox40 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox