QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
LogViewerAltChart.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Layouts
3import QtGraphs
4
5import QGroundControl
6import QGroundControl.Controls
7
8/// Altitude mini-chart for the Log Viewer Map tab.
9/// Displays vehicle_global_position.alt (or equivalent) as a line chart
10/// with zoom, position marker, and value popup. The marker timestamp is
11/// exposed via the markerChanged / markerCleared signals so the parent
12/// can place a dot on the map.
13Item {
14 id: control
15
16 required property var logParser
17 required property string altFieldName ///< e.g. "vehicle_global_position.alt"
18
19 property bool xAxisShowLocalTime: false
20
21 signal markerChanged(double timestampSeconds)
22 signal markerCleared()
23 signal zoomApplied(real minX, real maxX)
24
25 // -------------------------------------------------------------------------
26 // Internal state
27 // -------------------------------------------------------------------------
28 property real _markerAltValue: 0
29 property real _altMin: 0
30 property real _altMax: 0
31 property bool _hasAltRange: false
32 property var _altSeries: null
33
34 // -------------------------------------------------------------------------
35 // Public API (delegated to _base)
36 // -------------------------------------------------------------------------
37 function setSharedZoom(minX, maxX) { _base.setSharedZoom(minX, maxX) }
38 function setSharedCursor(t) { _base.setSharedCursor(t) }
39
40 // -------------------------------------------------------------------------
41 // Series management
42 // -------------------------------------------------------------------------
43 Component {
44 id: _altSeriesComp
45 LineSeries {
46 color: QGroundControl.globalPalette.colorGreen
47 width: 2
48 }
49 }
50
51 Component.onCompleted: {
52 _altSeries = _altSeriesComp.createObject(_base.graphsView, {
53 axisX: _base.xAxis,
54 axisY: _base.yAxis
55 })
56 _base.graphsView.addSeries(_altSeries)
57 }
58
59 function _refreshSeries() {
60 const fieldName = control.altFieldName
61 if (!logParser.parseComplete || fieldName.length === 0 || !_altSeries) {
62 if (_altSeries) _altSeries.clear()
63 return
64 }
65
66 const pixelWidth = Math.max(1, Math.floor(_base.graphsView.plotArea.width))
67 const points = logParser.fieldSamplesFiltered(fieldName, _base.zoomMinX, _base.zoomMaxX, pixelWidth)
68
69 _altSeries.clear()
70 if (!points || points.length === 0) return
71
72 let minY = Number.MAX_VALUE
73 let maxY = -Number.MAX_VALUE
74 for (let i = 0; i < points.length; i++) {
75 _altSeries.append(points[i].x, points[i].y)
76 if (points[i].y < minY) minY = points[i].y
77 if (points[i].y > maxY) maxY = points[i].y
78 }
79
80 // Track full-dataset min/max (not just visible window)
81 const fr = logParser.fieldMinMax(fieldName)
82 if (fr && fr.min !== undefined && fr.min <= fr.max) {
83 _altMin = fr.min
84 _altMax = fr.max
85 _hasAltRange = true
86 } else {
87 _hasAltRange = false
88 }
89
90 const pad = Math.max(1, (maxY - minY) * 0.05)
91 _base.yAxis.min = minY - pad
92 _base.yAxis.max = maxY + pad
93
94 if (_base.markerVisible) {
95 _markerAltValue = logParser.fieldValueAt(control.altFieldName, _base.markerXValue)
96 }
97 }
98
99 // -------------------------------------------------------------------------
100 // Cursor helpers
101 // -------------------------------------------------------------------------
102 function _initCursor() {
103 if (!logParser.parseComplete || _base.xAxis.max <= _base.xAxis.min) return
104 const mid = (_base.xAxis.min + _base.xAxis.max) / 2
105 _base.setCursor(mid)
106 control.markerChanged(mid)
107 }
108
109 // -------------------------------------------------------------------------
110 // Connections
111 // -------------------------------------------------------------------------
112 Connections {
113 target: logParser
114
115 function onParseCompleteChanged() {
116 if (!logParser.parseComplete) {
117 if (_altSeries) _altSeries.clear()
118 _hasAltRange = false
119 control.markerCleared()
120 return
121 }
122 const hasRange = logParser.minTimestamp >= 0 && logParser.maxTimestamp > logParser.minTimestamp
123 _base.initRange(hasRange ? logParser.minTimestamp : 0,
124 hasRange ? logParser.maxTimestamp : 1)
125 Qt.callLater(control._initCursor)
126 }
127 }
128
129 Connections {
130 target: _base
131 function onZoomRangeSet(minX, maxX) { Qt.callLater(_refreshSeries) }
132 function onCursorPositionSet(t) { _markerAltValue = logParser.fieldValueAt(altFieldName, t) }
133 function onCursorMoved(t) { control.markerChanged(t) }
134 function onZoomApplied(minX, maxX) { control.zoomApplied(minX, maxX) }
135 }
136
137 onVisibleChanged: {
138 if (visible && logParser.parseComplete && !_base.markerVisible) {
139 Qt.callLater(_initCursor)
140 }
141 }
142
143 // -------------------------------------------------------------------------
144 // Base chart
145 // -------------------------------------------------------------------------
146 LogViewerBaseChart {
147 id: _base
148 anchors.fill: parent
149 logParser: control.logParser
150 xAxisShowLocalTime: control.xAxisShowLocalTime
151 yAxisTitle: qsTr("Alt (m)")
152 popupYOffset: ScreenTools.defaultFontPixelHeight * 0.4
153
154 // ---- Chart-specific popup rows ----
155 QGCLabel {
156 text: altFieldName
157 font.bold: true
158 elide: Text.ElideMiddle
159 width: _base.popupWidth - (ScreenTools.defaultFontPixelWidth * 2)
160 }
161
162 RowLayout {
163 spacing: ScreenTools.defaultFontPixelWidth * 0.3
164
165 QGCLabel { text: qsTr("Current") }
166 QGCLabel { text: isNaN(_markerAltValue) ? "—" : _markerAltValue.toFixed(1) + " m"; font.bold: true }
167
168 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
169
170 QGCLabel { visible: _hasAltRange; text: qsTr("Min") }
171 QGCLabel { visible: _hasAltRange; text: _altMin.toFixed(1) + " m"; font.bold: true }
172
173 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
174
175 QGCLabel { visible: _hasAltRange; text: qsTr("Max") }
176 QGCLabel { visible: _hasAltRange; text: _altMax.toFixed(1) + " m"; font.bold: true }
177 }
178 }
179}
180