鸿蒙MPChart图表自定义(六)在图表中绘制游标
在鸿蒙开发中,MPChart 是一个非常强大的图表库,它可以帮助我们创建各种精美的图表。今天,我们将继续探索鸿蒙MPChart的自定义功能,重点介绍如何在图表中绘制游标。
OpenHarmony三方库中心仓
一、效果演示
以下是效果演示图,从动图可以看出,这是一个渐变蓝色的曲线图表,通过手指在图表上点击或者长按住滑动,可以在图表顶部展示出数据点的基本信息。这个效果也比较简单,只需要通过自定义UI就可以轻松实现。
二、绘制游标的步骤
在鸿蒙MPChart中,绘制游标可以通过以下步骤实现:
1. 页面组件定义
@Entry
@Component
struct LongPressSlideCursorPage {
这里定义了一个名为 LongPressSlideCursorPage
的页面组件,使用了 @Entry
和 @Component
装饰器,表示这是一个可以独立运行的页面组件。
2. 状态变量定义
@State private lineChartModel: LineChartModel = new LineChartModel();
@State positionX: number = 0;
@State positionY: number = 0;
@State cursorPositionX: number = 0;
@State cursorPositionY: number = 0;
@State dataX: number = 0;
@State dataY: number = 0;
@State showUI: boolean = false;
@State uiWidth: number = 0;
cursorSize: number = 100;
这些是页面的状态变量,用于存储图表模型、选中点的位置信息、游标位置信息、选中点的数据信息、是否显示UI、UI的宽度和游标的大小。
3. 数据选择监听器
@State private valueSelectedListener: OnChartValueSelectedListener = {onValueSelected: (e: EntryOhos, h: Highlight) => {this.showUI = true;this.dataX = Number(e.getX().toFixed(1));this.dataY = Number(e.getY().toFixed(1));let x = this.lineChartModel.getTransformer(AxisDependency.LEFT)?.getPixelForValues(e.getX(), e.getY()).x ?? 0;let y = this.lineChartModel.getTransformer(AxisDependency.LEFT)?.getPixelForValues(e.getX(), e.getY()).y ?? 0;this.positionX = x;this.positionY = y;if (x > this.uiWidth - this.cursorSize / 2 - 10) {x = this.uiWidth - this.cursorSize / 2 - 10;} else if (x < this.cursorSize / 2 + 10) {x = this.cursorSize / 2 + 10;}this.cursorPositionX = x;},onNothingSelected: () => {this.showUI = false;}
}
这是一个数据选择监听器,用于处理图表上的数据选中事件。当用户选中一个数据点时,会显示一个UI来显示选中点的详细信息。同时,会计算并设置游标的位置。
4. 数据初始化
aboutToAppear() {this.uiWidth = px2vp(display.getDefaultDisplaySync().width);let values: JArrayList<EntryOhos> = new JArrayList<EntryOhos>();for (let i = 1; i <= 30; i++) {values.add(new EntryOhos(i, Math.random() * 100));}let lineDataSet = new LineDataSet(values, 'DataSet');lineDataSet.setMode(Mode.CUBIC_BEZIER);lineDataSet.setDrawCircles(false);let lineDataSetList: JArrayList<ILineDataSet> = new JArrayList<ILineDataSet>();//渐变色填充let gradientFillColor = new JArrayList<ChartColorStop>();gradientFillColor.add(["#0099CC", 0.2]);gradientFillColor.add(["#7F0099CC", 0.4]);gradientFillColor.add(["#ffffff", 1.0]);lineDataSet.setGradientFillColor(gradientFillColor);lineDataSet.setDrawFilled(true);//不显示数值lineDataSet.setDrawValues(false);//设置线条颜色lineDataSet.setColorByColor(0x0099cc);//设置不显示指示线lineDataSet.setDrawHighlightIndicators(false);lineDataSetList.add(lineDataSet);let lineData: LineData = new LineData(lineDataSetList);this.lineChartModel?.setData(lineData);this.lineChartModel.setOnChartValueSelectedListener(this.valueSelectedListener);this.lineChartModel.setHighlightPerLongPressEnabled(false);this.lineChartModel.setVisibleXRangeMaximum(10);this.lineChartModel.setSwipeEnabled(true);//设置长按出游标 和 触发长按的时长this.lineChartModel.setLongPressCursorEnabled(true);this.lineChartModel.setLongPressDuration(160);}
在页面即将显示时,这段代码会初始化图表的数据。它创建了一个包含随机数据的 LineDataSet
,设置了数据集的样式,如渐变填充颜色、不显示数据点等。然后将数据集添加到 LineData
对象中,并将其设置到图表模型中。同时,设置了图表的一些属性,如最大显示X轴范围、是否允许滑动、长按持续时间等。
5. 页面构建
build() {Stack() {LineChart({ model: this.lineChartModel }).width('100%').height('50%').backgroundColor(Color.White).margin({ top: 100 })if (this.showUI) {Line().startPoint([0, 0]).endPoint([0, this.lineChartModel.getContentRect().height()+ 100]).stroke(Color.Yellow).strokeWidth(4).position({ x: this.positionX }).opacity(0.5)Column() {Text(`x = ${this.dataX.toFixed(1).toString()}`).fontSize(20).fontWeight(FontWeight.Bolder)Text(`y = ${this.dataY.toString()}`).fontSize(20).fontWeight(FontWeight.Bolder)}.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).backgroundColor('#F2F2F2').position({ x: this.cursorPositionX - this.cursorSize / 2 }).width(this.cursorSize).aspectRatio(1).borderRadius(5)Circle({ width: 14, height: 14 }).position({ x: this.positionX - 7, y: this.positionY + 100 - 7}).fill(Color.White)Circle({ width: 10, height: 10 }).position({ x: this.positionX - 5, y: this.positionY + 100 - 5}).fill(Color.Red)}}
}
这段代码构建了页面的布局。首先是一个 LineChart
组件,用于显示图表。当 showUI
为 true
时,会显示一个垂直线、一个包含选中点数据的文本列、一个圆形游标和一个红色的点,以突出显示选中的数据点。
页面完整代码如下:
import {JArrayList,EntryOhos,ILineDataSet,LineData,LineChart,LineChartModel,Mode,LineDataSet,XAxisPosition,OnChartValueSelectedListener,Highlight,AxisDependency,ChartColorStop,
} from '@ohos/mpchart';
import display from '@ohos.display';/** CursorPage组件 */
@Entry
@Component
struct LongPressSlideCursorPage {/** LineChart 图表配置构建类 */@State private lineChartModel: LineChartModel = new LineChartModel();/** 选中点位置信息 */@State positionX: number = 0;@State positionY: number = 0;/**游标位置信息*/@State cursorPositionX: number = 0;@State cursorPositionY: number = 0;/** 选中点X轴数据信息*/@State dataX: number = 0;/** 选中点Y轴数据信息 */@State dataY: number = 0;/** 是否展示UI */@State showUI: boolean = false;/** UI宽度 */@State uiWidth: number = 0;/** UI高度 */@State uiHeight: number = 0;/**游标宽高**/cursorSize: number = 100;/** 数据选择监听 */private valueSelectedListener: OnChartValueSelectedListener = {onValueSelected: (e: EntryOhos, h: Highlight) => {/** 数据选中时显示气泡UI */this.showUI = true;/** 设置选中点的位置信息和数据信息 */this.dataX = Number(e.getX().toFixed(1));this.dataY = Number(e.getY().toFixed(1));let x = this.lineChartModel.getTransformer(AxisDependency.LEFT)?.getPixelForValues(e.getX(), e.getY()).x ?? 0;let y = this.lineChartModel.getTransformer(AxisDependency.LEFT)?.getPixelForValues(e.getX(), e.getY()).y ?? 0;this.positionX = x;this.positionY = y;if (x > this.uiWidth - this.cursorSize / 2 - 10) {x = this.uiWidth - this.cursorSize / 2 - 10;} else if (x < this.cursorSize / 2 + 10) {x = this.cursorSize / 2 + 10}this.cursorPositionX = x;},onNothingSelected: () => {/** 去除气泡UI */this.showUI = false;}}/** 数据初始化 */aboutToAppear() {this.uiWidth = px2vp(display.getDefaultDisplaySync().width);/** 创建一个 JArrayList 对象,用于存储 EntryOhos 类型的数据 */let values: JArrayList<EntryOhos> = new JArrayList<EntryOhos>();/** 循环生成 1 到 20 的随机数据,并添加到 values 中 */for (let i = 1; i <= 30; i++) {values.add(new EntryOhos(i, Math.random() * 100));}/** 创建 LineDataSet 对象,使用 values 数据,并设置数据集的名称为 'DataSet' */let lineDataSet = new LineDataSet(values, 'DataSet');lineDataSet.setMode(Mode.CUBIC_BEZIER);lineDataSet.setDrawCircles(false);let lineDataSetList: JArrayList<ILineDataSet> = new JArrayList<ILineDataSet>();//渐变色填充let gradientFillColor = new JArrayList<ChartColorStop>();gradientFillColor.add(["#0099CC", 0.2]);gradientFillColor.add(["#7F0099CC", 0.4]);gradientFillColor.add(["#ffffff", 1.0]);lineDataSet.setGradientFillColor(gradientFillColor);lineDataSet.setDrawFilled(true);lineDataSet.setDrawValues(false);lineDataSet.setColorByColor(0x0099cc);lineDataSet.setDrawHighlightIndicators(false);lineDataSetList.add(lineDataSet);/** 创建 LineData 对象,使用 lineDataSetList 数据,并将其传递给 lineChartModel */let lineData: LineData = new LineData(lineDataSetList);this.lineChartModel?.setData(lineData);this.lineChartModel.setOnChartValueSelectedListener(this.valueSelectedListener);this.lineChartModel.setHighlightPerLongPressEnabled(false);this.lineChartModel.setVisibleXRangeMaximum(10);this.lineChartModel.setSwipeEnabled(true);this.lineChartModel.setLongPressDuration(160);this.lineChartModel.setLongPressCursorEnabled(true);}build() {Stack() {LineChart({ model: this.lineChartModel }).width('100%').height('50%').backgroundColor(Color.White).margin({ top: 100 })if (this.showUI) {Line().startPoint([0, 0]).endPoint([0, this.lineChartModel.getContentRect().height()+ 100]).stroke(Color.Yellow).strokeWidth(4).position({ x: this.positionX }).opacity(0.5)Column() {Text(`x = ${this.dataX.toFixed(1).toString()}`).fontSize(20).fontWeight(FontWeight.Bolder)Text(`y = ${this.dataY.toString()}`).fontSize(20).fontWeight(FontWeight.Bolder)}.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).backgroundColor('#F2F2F2').position({ x: this.cursorPositionX - this.cursorSize / 2 }).width(this.cursorSize).aspectRatio(1).borderRadius(5)Circle({ width: 14, height: 14 }).position({ x: this.positionX - 7, y: this.positionY + 100 - 7}).fill(Color.White)Circle({ width: 10, height: 10 }).position({ x: this.positionX - 5, y: this.positionY + 100 - 5}).fill(Color.Red)}}}
}
三、总结
这段代码通过定义状态变量、数据选择监听器、数据初始化和页面构建,实现了在鸿蒙应用中绘制带有游标的折线图。用户可以通过长按图表来选中数据点,并显示相关的详细信息。这种交互方式提高了图表的可用性和用户体验。希望这篇文章能帮助你在鸿蒙开发中更好地使用MPChart图表库。
有疑问或者感兴趣的朋友,可以加QQ群沟通交流:274130009
相关文章:

鸿蒙MPChart图表自定义(六)在图表中绘制游标
在鸿蒙开发中,MPChart 是一个非常强大的图表库,它可以帮助我们创建各种精美的图表。今天,我们将继续探索鸿蒙MPChart的自定义功能,重点介绍如何在图表中绘制游标。 OpenHarmony三方库中心仓 一、效果演示 以下是效果演示图&…...

poi-tl+kkviewfile实现生成pdf业务报告
需求背景,需要把ai生成的一些业务数据,生成一份pdf报告 需求分析 简单来说,就是json生成pdf的方案。 直接生成pdf。适合一些pdf样式简单的场景,一般就是纯文本按序渲染,或者是纯表格。如果需要一些复杂的排布&#x…...

【Uniapp-Vue3】scroll-view可滚动视图区域组件
如果我们有一个区域有限的大盒子(黑),而我们要在盒子中装的东西(灰)过多,我们就会用到滚动视图: 表现在代码上就是下面这个样子: <template><view class"scrollView&…...
asp.net core webapi中的数据注解与数据验证
在这一课中,主要讲解了如何在 Web API 中使用数据注解(Data Annotations)和进行数据验证,以确保请求数据的有效性和完整性。 在 Web API 中,数据验证是确保客户端传递的数据符合业务规则和格式要求的关键步骤。数据注…...
PixPin—— 高效截图工具的下载与使用攻略
在日常的工作和学习中,一款好用的截图工具能极大地提高我们的效率。今天就来给大家介绍一款功能强大的截图工具 ——PixPin。 下载篇 PixPin 的下载非常简单,只需访问下载网站,在首页就能找到适合你操作系统的下载链接。如果你使用的是 Win…...
Go语言的 的多态性(Polymorphism)基础知识
Go语言的多态性(Polymorphism)基础知识 在编程语言中,多态性是一个核心概念,它允许同一接口被不同的数据类型所实现,从而在不影响代码结构的情况下增强代码的灵活性和可扩展性。在Go语言中,多态性通过接口…...

Vue框架主要用来做什么?Vue框架的好处和特性.
在快速发展的互联网时代,前端开发技术的变革日新月异,为开发者带来了前所未有的机遇与挑战。Vue.js,作为前端开发领域的一颗璀璨新星,以其轻量级、高效灵活的特性,赢得了广大开发者的青睐。本文将深入探讨Vue框架的主要…...

科普CMOS传感器的工作原理及特点
在当今数字化成像的时代,图像传感器无疑是幕后的关键 “功臣”,它宛如一位神奇的 “光影魔法师”,通过光电效应这一奇妙的物理现象,将光子巧妙地转换成电荷,为图像的诞生奠定基础。而在众多类型的图像传感器中…...
tensorflow 内存错误
使用tensorflow训练多个模型时,训练过程中容易出现内存错误,在这里记录一下解决办法。希望能帮到各位。 2025-01-02 22:31:03.489713: W tensorflow/core/common_runtime/bfc_allocator.cc:275] Allocator (GPU_0_bfc) ran out of memory trying to all…...

spring boot解决swagger中的v2/api-docs泄露漏洞
在配置文件中添加以下配置 #解决/v2/api-docs泄露漏洞 springfox:documentation:swagger-ui:enabled: falseauto-startup: false 处理前: 处理后:...

计算机网络 (25)IPV6
前言 IPv6,全称为“互联网协议第6版”(Internet Protocol Version 6),是由互联网工程任务组(IETF)设计的用于替代IPv4的下一代IP协议。 一、产生背景 IPv4,即互联网协议第4版,是现行…...
小程序组件 —— 30 组件 - 背景图片的使用
在编写小程序的样式文件时,可以使用 background-image 属性来设置元素的背景图像;但是这个属性在微信小程序中使用时存在坑; 注意事项:微信小程序中的 background-iamge 不支持本地路径!需要使用网络图片,…...

《Opencv》信用卡信息识别项目
目录 一、项目介绍 二、数据材料介绍 1、模板图片(1张) 2、需要处理的信用卡图片(5张) 三、实现过程 1、导入需要用到的库 2、设置命令行参数 3、模板图像中数字的定位处理 4、信用卡图像处理 5、模板匹配 四、总结 一…...

Matlab贝叶斯估计MCMC分析药物对不同种群生物生理指标数据评估可视化
全文链接:https://tecdat.cn/?p38756 摘要:本文着重探讨了如何利用Matlab实现贝叶斯估计。阐述了具体的实现流程,涵盖数据加载、先验常数设定、马尔可夫链蒙特卡洛(MCMC)属性指定、模型构建、运行链条以及结果查看等环…...

java 转义 反斜杠 Unexpected internal error near index 1
代码: String str"a\\c"; //出现异常,Unexpected internal error near index 1 //System.out.println(str.replaceAll("\\", "c"));//以下三种都正确 System.out.println(str.replace(\\, c)); System.out.println(str.r…...
网络安全常见的问题
1. 什么是 DDoS 攻击?如何防范? 答:DDoS 攻击是指利用大量的计算机或者其他网络设备,同时向目标网络或者服务器 发送 大量的数据流量,以致其无法正常工作,从而导致网络瘫痪或者服务器宕机的攻击行 为。 …...

在ubuntu22.04中使用bear命令追踪内核编译报错的原因分析和解决方案
1.说明 我在ubuntu22.04中使用bear命令追踪内核编译时发生如下报错: 如图,在链接名为libexec.so的动态库时发生错误 2 分析及解决过程 打印变量 LIB 发现其为空,也就是说 bear会去 /usr/bear/ 去找 libexec.so 去看一下 /usr/bear/是否存…...

【软考网工笔记】操作系统管理与配置——Windows
1-域名解析 Cache 域名解析 Cache 即 DNS 快取,DNS 快取需要应用客户机域名解析服务 DNSClient,其进程名为 svchost.exe -k NetworkService,可以输入命令:net stop dnscache 将其结束。原理是在 Windows 系统中,加入了…...

vue3 css实现文字输出带光标显示,文字输出完毕,光标消失的效果
Vue实现过程如下: <template><div ><p ref"dom_element" class"typing" :class"{over_fill: record_input_over}"></p></div> </template> <script setup> import {onMounted, ref} from…...

什么情况会导致JVM退出?
大家好,我是锋哥。今天分享关于【什么情况会导致JVM退出?】面试题。希望对大家有帮助; 什么情况会导致JVM退出? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 JVM(Java Virtual Machine)在不同情况下可能会退出&am…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...