前言
通过前面的Hicharts
入门,本文将继续大家探索HiCharts
的功能,通过实现三个功能区域缩放、数据联动、图表点击
,学习HiCharts的其他常用功能,看看他们之间可以碰撞出什么火花呢?
功能示例
- 区域缩放:框选一定范围内曲线,单独显示
- 数据联动:框选曲线,展示框选的曲线数据
- 图表点击:点击某个曲线点,产生交互
往期文章
一、区域缩放
在HiCharts
中实现区域缩放
也是及其简单,只需要加上如下配置项即可
yaml
chart: {
zoomType: "x",
panning: true,
panKey: "shift",
}
配置 | 说明 |
---|---|
zoomType | 缩放类型 |
panning | 允许在图表中平移。最好与panKey配合使用 ,以结合缩放和平移功能 |
panKey | 允许设置一个按键来在缩放和平移之间切换, |

二、数据联动
接下来我们需要实现,框选一定范围内的曲线,然后数据表格跟着联动更新,只展示图表中框选的数据;具体实现的实现步骤如下
- 监听框选事件
- 取出框选范围
- 筛选框选的数据并更新表格
主要难点在于,如何取出框选的范围?那就需要用到selection
函数了
selection
: 是 Highcharts 中的一个 图表事件回调函数 ,专门用于处理用户在图表上通过鼠标拖动进行 框选(范围选择) 的操作。
为了方便演示功能,稍稍改造前面的示例代码,加上table表格展示,代码如下
css
<script setup lang="ts">
import Highcharts from 'highcharts'
import {onMounted, ref} from "vue";
interface PhoneSalesData {
index: number;
month: string;
xiaomi: number;
huawei: number;
}
const chartRef = ref<HTMLDivElement>()
const tableRef = ref()
const selectedRows = ref<PhoneSalesData[]>([])
const allPhoneSalesData: PhoneSalesData[] = [
{index: 0, month: '1月', xiaomi: 4.2, huawei: 8.5},
{index: 1, month: '2月', xiaomi: 3.8, huawei: 7.8},
{index: 2, month: '3月', xiaomi: 4.5, huawei: 9.1},
{index: 3, month: '4月', xiaomi: 5.1, huawei: 6.2},
{index: 4, month: '5月', xiaomi: 5.7, huawei: 5.4},
{index: 5, month: '6月', xiaomi: 6.3, huawei: 10.9},
{index: 6, month: '7月', xiaomi: 6.8, huawei: 12.2},
{index: 7, month: '8月', xiaomi: 7.2, huawei: 11.8},
{index: 8, month: '9月', xiaomi: 7.5, huawei: 10.5},
{index: 9, month: '10月', xiaomi: 8.1, huawei: 8.3},
{index: 10, month: '11月', xiaomi: 8.6, huawei: 9.2},
{index: 11, month: '12月', xiaomi: 9.2, huawei: 11.8},
]
const tableData = ref<PhoneSalesData[]>([...allPhoneSalesData])
const handleSelectionChange = (val: PhoneSalesData[]) => {
selectedRows.value = val
}
const initCharts = () => {
// 初始化图表配置
const options = {
chart: {
zoomType: "x",
panning: true,
panKey: "shift",
events: {
selection: function (e) {
console.log(e);
return true;
}
}
},
title: {
text: '手机品牌月度销量',
align: 'left'
},
subtitle: {
text: '市场调研',
align: 'left'
},
yAxis: {
title: {
text: '销量 (百万台)'
}
},
xAxis: {
categories: tableData.value.map(item => item.month)
},
legend: {
enabled: true, // 显示图例
align: 'right',
verticalAlign: 'top'
},
tooltip: {
valueSuffix: ' 百万台'
},
plotOptions: {
series: {
marker: {
enabled: true // 显示数据点
}
}
},
series: [
{
name: '小米',
data: tableData.value.map(item => item.xiaomi)
},
{
name: '华为',
data: tableData.value.map(item => item.huawei)
}
]
}
// 初始化图表
Highcharts.chart(chartRef.value, options);
}
onMounted(() => {
initCharts();
})
</script>
<template>
<div>
<div ref="chartRef" class="chart"></div>
<div class="data-table">
<h3>销售数据表</h3>
<el-table
ref="tableRef"
:data="tableData"
style="width: 100%"
@selection-change="handleSelectionChange"
border
stripe
height="350px"
>
<el-table-column type="selection" width="55"/>
<el-table-column prop="month" label="月份" width="120"/>
<el-table-column prop="xiaomi" label="小米 (百万台)"/>
<el-table-column prop="huawei" label="华为 (百万台)"/>
</el-table>
</div>
</div>
</template>
<style scoped>
.chart {
width: 100%;
height: 350px;
margin-top: 20px;
border: 1px solid #eee;
border-radius: 4px;
padding: 10px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.data-table {
margin-top: 30px;
padding: 20px;
border: 1px solid #eee;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.data-table h3 {
margin-top: 0;
margin-bottom: 15px;
color: #333;
}
</style>
其中selection
已经定义好了,只要图表发生框选事件,我们就可以拿到框选的信息,控制台打印如下

参数 | 说明 |
---|---|
xAxis | X 轴范围数组,每个对象对应一个 X 轴 |
yAxis | Y 轴范围数组 |
type | 事件类型,值为字符串 |
展开 xAxis,我们可以看到共有两个对象属性,每个对象对应一个X轴,框选的范围我们便可以从这个对象数组取出,min代表最小范围,max代表最大范围,等下我们可以基于这两个参数,筛选出图表中在这个范围内的点

arduino
selection: function (e) {
console.log(e);
// 取出x轴的最小值和最大值
const minX = e.xAxis[0].min;
const maxX = e.xAxis[0].max;
// 遍历曲线点,判断是否在框选范围内
for (const series of this.series) {
// 过滤符合条件的点
const points = series.points.filter(
point => point.x >= minX && point.x <= maxX
);
if (points.length === 0) continue; // 如果没有选中点,跳过后续处理
console.log(points)
}
return true;
}
通过上述代码,我们实现了取出每条曲线被框选到曲线点数据,打印结果如下图

展开某个曲线点,里面记录着曲线点的一些基本信息,比如X轴位置、Y轴位置、颜色等信息,当然也有我们所定义的数据信息,比如 index,通过index去匹配表格数据,然后更新表格的数据,就可以达到图表与表格的数据联动效果,通过 keySet 去筛选数据,然后表格数据

在筛选框选范围的曲线点的同时,记录下曲线点记录下的数据标识,根据这个标识去筛选数据,然后更新我们数据表格,便可以达到曲线和表格联动效果
arduino
selection: function (e) {
console.log(e);
// 取出x轴的最小值和最大值
const minX = e.xAxis[0].min;
const maxX = e.xAxis[0].max;
const keySet = new Set();
// 遍历曲线点,判断是否在框选范围内
for (const series of this.series) {
// 过滤符合条件的点
const points = series.points.filter(
point => point.x >= minX && point.x <= maxX
);
if (points.length === 0) continue; // 如果没有选中点,跳过后续处理
console.log(points)
// 取出选中点的 index
points.forEach((point) => keySet.add(point.index))
}
console.log(keySet)
// 筛选数据
tableData.value = allPhoneSalesData.filter(item => keySet.has(item.index))
return true;
}
此时效果虽然实现了,但是还有点问题,每次发生框选行为后,右上角会出现一个重置缩放的按钮,此时点击会没有效果,控制台会报错,


这是因为 框选 和 重置缩放 都会触发selection
函数,其中 重置缩放 所得到的值与框选的值有所不同,重置缩放是没有 xAxis和yAxis对象的,但是多了resetSelection
属性,所以我们需要加上一个判断,如果是重置缩放,我们需要放行,不进行筛选操作,同时恢复表格数据(因为用户前面可能框选了数据,那此时表格数据不是完整的,那么重置缩放之后,我们也需要进行恢复)

kotlin
// 缩放重置时直接返回,不处理任何数据
if (e.resetSelection) {
// 恢复数据
tableData.value = [...allPhoneSalesData]
return true;
}
效果如下图

三、曲线点击
不仅有监听框选数据的函数,还有监听曲线点击的函数,其配置在plotOptions -> series -> events -> click
下,示例代码
css
plotOptions: {
series: {
events: {
click: async function (e) {
console.log(e);
}
}
}
}

通过点击返回的数据,我们可以去匹配到该条表格数据,从而实现一些特殊操作,比如将对应的表格数据移动到顶部
ini
click: async function (e) {
console.log(e);
// 取出 index 值
const index = e.point.index;
console.log("index", index);
// 匹配对应的表格数据
const findIndex = allPhoneSalesData.findIndex(item => item.index == index);
if (findIndex == -1) return;
const matchData = allPhoneSalesData[findIndex];
// 将该条数据移到顶部
tableData.value = [matchData, ...tableData.value.filter(item => item.index !== matchData.index)]
}

四、结语
HiCharts在数据交互这块,整体感觉还不错,使用者可以通过各种API去扩展操作,例如前面实现的图表与表格的联动
,也正是因为这一点,所以去专门去学习研究了一下,发现效果还是不错的。如果有错误之处,欢迎讨论指正!!!