【未完成待续】还有个小bug(移动光标是连续的,没有自动锁定到最近的点上,后边会改)
先上结果
1、十字光标形式
2、其他形式光标
环境
硬件:通用PC / 手机 / Jetson Xavier NX 套件
系统:Ubuntu 20.4 / Android / Windows (均测试有效)
软件 :QT6.2.4 + Qml
图标字体: adimecoin-Regular.ttf下载
解决
0、思路
使用QtCharts 的ChartView->LineSeries 实现曲线图,获取触摸位置,换算出曲线上对应的值,得到marker的位置(mymarker.xx,mymarker.yy),在marker的位置绘制游标。
1、实现
XYPoint { x: 0; y: 0 }
XYPoint { x: 1; y: 2.1 }
XYPoint { x: 2; y: 3.3 }
XYPoint { x: 3; y: 2.1 }
XYPoint { x: 4; y: 4.9 }
XYPoint { x: 5; y: 3.0 }
XYPoint { x: 7; y: 3.3 }
2、封装 LineSeriesMarker.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtCharts 2.3
/******************************************************************************
* Copyright 2022-Adiemcoin.
* All right reserved. See COPYRIGHT for detailed Information.
*
* @file LineSeriesMarker.qml
* @brief XXXX Function
*
* @author Adimecoin(QQ:413819260)
* @e-mail adimecoin@foxmail.com
* @date 2022/11/03
* @history
*1、实现LineSeries曲线 的游标功能 (十字游标)
*****************************************************************************/
ChartView {
property double zoomMultiple:1 //X轴缩放倍数
property color markerColor: "#17a81a" //游标颜色
property int markerDecimalDigits: 4 //游标数据小数位位数
property double markerX: 0.0
property double markerY: 0.0
property int mylineWidth: 1 //线宽
property color mylineColor: "white" //线颜色
property bool axisXGridVisible: false
property bool axisYGridVisible: false
property int axisXLabelPointSize: 8 //轴标字体大小
property int axisYLabelPointSize: 8
property color axisXLabelColor: "white" //轴标签颜色
property color axisYLabelColor: "white"
property double axisXValueMax: 1
property double axisXValueMin: -1 //X轴显示范围
property double axisYValueMax: 1
property double axisYValueMin: -1//Y轴显示范围
id: adimecoin
antialiasing: true //抗锯齿
legend.visible: false
MouseArea{
anchors.fill: parent
hoverEnabled: true //鼠标离开区域
onPositionChanged: {//获取鼠标移动时的位置(Xmouse ,Ymouse)
//使用mapToValue转换该鼠标屏幕位置处LineSeries坐标系的坐标值
var chatviewPosition = adimecoin.mapToValue(Qt.point(mouse.x,mouse.y),myline);
//由该坐标值的横坐标获得LineSeries曲线上的对应点的值,注意,这里由于at方法 的参数是索引,所以x轴的值要转换一下
var value = myline.at(chatviewPosition.x / zoomMultiple);
//将坐标值对应的点还原成屏幕位置(Xscreen ,Yscreen)
var screenPosition = adimecoin.mapToPosition(value,myline)
//设置maker显示位置
mymarker.xx = mouse.x
mymarker.yy = screenPosition.y
mymarker.requestPaint()
}
onExited:{//检测鼠标是否离开图表区域,注意hoverEnabled的区别
mymarker.xx = 0
mymarker.yy = 0
mymarker.requestPaint()
}
}
Canvas{ //绘制游标
id:mymarker
anchors.fill: parent
property double xx: 0
property double yy: 0
property int temp
onPaint: {
if(xx+yy>0){
var ctx = getContext("2d")//绘制十字交叉的竖线
ctx.clearRect(0,0,parent.width,parent.height)
ctx.strokeStyle = markerColor
ctx.fillStyle = markerColor
ctx.lineWidth = 1
ctx.font="8px adimecoin"
var value = adimecoin.mapToValue(Qt.point(xx,yy),myline);
temp = value.x * Math.pow(10,markerDecimalDigits)
markerX = temp
markerX = markerX / Math.pow(10,markerDecimalDigits)
temp = value.y * Math.pow(10,markerDecimalDigits)
markerY = temp
markerY = markerY / Math.pow(10,markerDecimalDigits)
ctx.fillText("("+markerX+","+markerY+")",xx+5,yy-10)//十字游标样式
// ctx.fillText("\uF4E0",xx-4,yy-5) //箭头游标样式
ctx.lineWidth = 3
ctx.beginPath()
ctx.moveTo(xx,adimecoin.plotArea.y)
ctx.lineTo(xx,adimecoin.plotArea.height+adimecoin.plotArea.y)
ctx.stroke()
ctx.beginPath()//绘制十字交叉的横线
ctx.moveTo(adimecoin.plotArea.x,yy)
ctx.lineTo(adimecoin.plotArea.x+adimecoin.plotArea.width,yy)
ctx.stroke()
}else{//鼠标离开图表区域时,清除游标
var ctx2 = getContext("2d")
ctx2.clearRect(0,0,parent.width,parent.height)
}
}
}
LineSeries { //曲线
id:myline
// useOpenGL:true
width: mylineWidth
color:mylineColor
ValueAxis {//X轴值
id: axisXValue
gridVisible: axisXGridVisible
labelsFont{
pointSize:axisXLabelPointSize
}
labelsColor: axisXLabelColor
min: axisXValueMin
max: axisXValueMax
}
ValueAxis {//X轴值
id: axisYValue
gridVisible: axisYGridVisible
labelsFont{
pointSize:axisYLabelPointSize
}
labelsColor: axisYLabelColor
min: axisYValueMin
max: axisYValueMax
}
axisX: axisXValue
axisY: axisYValue
}
}
/*##^##
Designer {
D{i:0;autoSize:true;formeditorZoom:0.9;height:480;width:640}
}
##^##*/
3、调用
//在需要的地方调用 封装好的LineSeriesMarker
LineSeriesMarker {
id: charX
anchors.fill: parent
antialiasing: true
backgroundColor:"transparent"
plotAreaColor: "transparent"
legend.visible: false
visible: true
axisXValueMin: 0
axisXValueMax: 10
axisYValueMin: -1
axisYValueMax: 5
}
OK!
至此,问题解决。欢迎留言交流