You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在QML的ChartView上绘制垂直线以获取各绘图曲线的交点位置

QML ChartView 鼠标悬浮垂直线及交点获取实现方案

垂直参考线效果示意图

实现步骤

  • 监听ChartView的鼠标移动、出入事件,控制垂直线的显隐和位置
  • 完成视图坐标与图表数据坐标的转换,获取鼠标当前位置对应的x轴数值
  • 遍历所有已绘制的曲线系列,线性插值计算垂直线与各曲线的交点坐标

完整示例代码

import QtQuick 2.15
import QtCharts 2.15

ChartView {
    id: chartView
    anchors.fill: parent
    antialiasing: true

    // 坐标轴定义
    ValueAxis {
        id: axisX
        min: 0
        max: 10
    }
    ValueAxis {
        id: axisY
        min: 0
        max: 10
    }

    // 示例曲线1
    LineSeries {
        id: series1
        name: "曲线1"
        axisX: axisX
        axisY: axisY
        XYPoint { x: 0; y: 2 }
        XYPoint { x: 2; y: 4 }
        XYPoint { x: 5; y: 1 }
        XYPoint { x: 8; y: 7 }
        XYPoint { x: 10; y: 5 }
    }

    // 示例曲线2
    LineSeries {
        id: series2
        name: "曲线2"
        axisX: axisX
        axisY: axisY
        XYPoint { x: 0; y: 7 }
        XYPoint { x: 3; y: 2 }
        XYPoint { x: 6; y: 8 }
        XYPoint { x: 9; y: 3 }
        XYPoint { x: 10; y: 6 }
    }

    // 垂直参考线
    Rectangle {
        id: verticalLine
        width: 1
        color: "red"
        height: chartView.plotArea.height
        visible: false
        x: 0
        y: chartView.plotArea.y
    }

    // 鼠标事件处理
    onHovered: {
        if (containsMouse) {
            verticalLine.visible = true
            // 鼠标位置转x轴数值
            let mouseDataX = chartView.mapToValue(mouse, axisX).x
            // 更新垂直线位置
            let linePos = chartView.mapToPosition(Qt.point(mouseDataX, 0), axisX)
            verticalLine.x = linePos.x

            // 计算所有曲线交点
            let intersections = []
            for (let i = 0; i < chartView.series.length; i++) {
                let series = chartView.series[i]
                if (series.type !== AbstractSeries.SeriesTypeLine) continue

                // 线性插值计算对应x的y值
                let yVal = interpolateY(series, mouseDataX)
                if (yVal !== null) {
                    intersections.push({
                        seriesName: series.name,
                        x: mouseDataX,
                        y: yVal
                    })
                }
            }
            // 打印交点,可根据需求做后续处理
            console.log("当前交点:", JSON.stringify(intersections))
        } else {
            verticalLine.visible = false
        }
    }

    // 线性插值工具函数
    function interpolateY(series, xVal) {
        let count = series.count
        if (count < 2 || xVal < series.at(0).x || xVal > series.at(count-1).x) {
            return null
        }
        // 查找相邻点
        for (let i = 0; i < count - 1; i++) {
            let p1 = series.at(i)
            let p2 = series.at(i+1)
            if (xVal >= p1.x && xVal <= p2.x) {
                // 线性插值计算y
                let ratio = (xVal - p1.x) / (p2.x - p1.x)
                return p1.y + ratio * (p2.y - p1.y)
            }
        }
        return null
    }
}

关键说明

  • 坐标转换:必须使用mapToValue()和mapToPosition()完成视图坐标与数据坐标的互转,适配轴范围调整、窗口缩放等场景
  • 交点计算:示例中使用线性插值得到准确交点,若曲线点数较多可将遍历逻辑替换为二分查找,提升计算性能
  • 样式自定义:垂直线的颜色、宽度、虚线效果可直接修改verticalLine的属性,也可替换为Shape组件实现更复杂的样式

内容的提问来源于stack exchange,提问作者MReza Bagherzadeh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 10:51:03