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 _base.graphsView.addSeries(_altSeries)
54 }
55
56 function _refreshSeries() {
57 const fieldName = control.altFieldName
58 if (!logParser.parseComplete || fieldName.length === 0 || !_altSeries) {
59 if (_altSeries) _altSeries.clear()
60 return
61 }
62
63 const pixelWidth = Math.max(1, Math.floor(_base.graphsView.plotArea.width))
64 const points = logParser.fieldSamplesFiltered(fieldName, _base.zoomMinX, _base.zoomMaxX, pixelWidth)
65
66 _altSeries.clear()
67 if (!points || points.length === 0) return
68
69 let minY = Number.MAX_VALUE
70 let maxY = -Number.MAX_VALUE
71 for (let i = 0; i < points.length; i++) {
72 _altSeries.append(points[i].x, points[i].y)
73 if (points[i].y < minY) minY = points[i].y
74 if (points[i].y > maxY) maxY = points[i].y
75 }
76
77 // Track full-dataset min/max (not just visible window)
78 const fr = logParser.fieldMinMax(fieldName)
79 if (fr && fr.min !== undefined && fr.min <= fr.max) {
80 _altMin = fr.min
81 _altMax = fr.max
82 _hasAltRange = true
83 } else {
84 _hasAltRange = false
85 }
86
87 const pad = Math.max(1, (maxY - minY) * 0.05)
88 _base.yAxis.min = minY - pad
89 _base.yAxis.max = maxY + pad
90
91 if (_base.markerVisible) {
92 _markerAltValue = logParser.fieldValueAt(control.altFieldName, _base.markerXValue)
93 }
94 }
95
96 // -------------------------------------------------------------------------
97 // Cursor helpers
98 // -------------------------------------------------------------------------
99 function _initCursor() {
100 if (!logParser.parseComplete || _base.xAxis.max <= _base.xAxis.min) return
101 const mid = (_base.xAxis.min + _base.xAxis.max) / 2
102 _base.setCursor(mid)
103 control.markerChanged(mid)
104 }
105
106 // -------------------------------------------------------------------------
107 // Connections
108 // -------------------------------------------------------------------------
109 Connections {
110 target: logParser
111
112 function onParseCompleteChanged() {
113 if (!logParser.parseComplete) {
114 if (_altSeries) _altSeries.clear()
115 _hasAltRange = false
116 control.markerCleared()
117 return
118 }
119 const hasRange = logParser.minTimestamp >= 0 && logParser.maxTimestamp > logParser.minTimestamp
120 _base.initRange(hasRange ? logParser.minTimestamp : 0,
121 hasRange ? logParser.maxTimestamp : 1)
122 Qt.callLater(control._initCursor)
123 }
124 }
125
126 Connections {
127 target: _base
128 function onZoomRangeSet(minX, maxX) { Qt.callLater(_refreshSeries) }
129 function onCursorPositionSet(t) { _markerAltValue = logParser.fieldValueAt(altFieldName, t) }
130 function onCursorMoved(t) { control.markerChanged(t) }
131 function onZoomApplied(minX, maxX) { control.zoomApplied(minX, maxX) }
132 }
133
134 onVisibleChanged: {
135 if (visible && logParser.parseComplete && !_base.markerVisible) {
136 Qt.callLater(_initCursor)
137 }
138 }
139
140 // -------------------------------------------------------------------------
141 // Base chart
142 // -------------------------------------------------------------------------
143 LogViewerBaseChart {
144 id: _base
145 anchors.fill: parent
146 logParser: control.logParser
147 xAxisShowLocalTime: control.xAxisShowLocalTime
148 yAxisTitle: qsTr("Alt (m)")
149 popupYOffset: ScreenTools.defaultFontPixelHeight * 0.4
150
151 // ---- Chart-specific popup rows ----
152 QGCLabel {
153 text: altFieldName
154 font.bold: true
155 elide: Text.ElideMiddle
156 width: _base.popupWidth - (ScreenTools.defaultFontPixelWidth * 2)
157 }
158
159 RowLayout {
160 spacing: ScreenTools.defaultFontPixelWidth * 0.3
161
162 QGCLabel { text: qsTr("Current") }
163 QGCLabel { text: isNaN(_markerAltValue) ? "—" : _markerAltValue.toFixed(1) + " m"; font.bold: true }
164
165 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
166
167 QGCLabel { visible: _hasAltRange; text: qsTr("Min") }
168 QGCLabel { visible: _hasAltRange; text: _altMin.toFixed(1) + " m"; font.bold: true }
169
170 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
171
172 QGCLabel { visible: _hasAltRange; text: qsTr("Max") }
173 QGCLabel { visible: _hasAltRange; text: _altMax.toFixed(1) + " m"; font.bold: true }
174 }
175 }
176}