6import QGroundControl.Controls
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.
16 required property var logParser
17 required property string altFieldName ///< e.g. "vehicle_global_position.alt"
19 property bool xAxisShowLocalTime: false
21 signal markerChanged(double timestampSeconds)
22 signal markerCleared()
23 signal zoomApplied(real minX, real maxX)
25 // -------------------------------------------------------------------------
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
34 // -------------------------------------------------------------------------
35 // Public API (delegated to _base)
36 // -------------------------------------------------------------------------
37 function setSharedZoom(minX, maxX) { _base.setSharedZoom(minX, maxX) }
38 function setSharedCursor(t) { _base.setSharedCursor(t) }
40 // -------------------------------------------------------------------------
42 // -------------------------------------------------------------------------
46 color: QGroundControl.globalPalette.colorGreen
51 Component.onCompleted: {
52 _altSeries = _altSeriesComp.createObject(_base.graphsView, {
56 _base.graphsView.addSeries(_altSeries)
59 function _refreshSeries() {
60 const fieldName = control.altFieldName
61 if (!logParser.parseComplete || fieldName.length === 0 || !_altSeries) {
62 if (_altSeries) _altSeries.clear()
66 const pixelWidth = Math.max(1, Math.floor(_base.graphsView.plotArea.width))
67 const points = logParser.fieldSamplesFiltered(fieldName, _base.zoomMinX, _base.zoomMaxX, pixelWidth)
70 if (!points || points.length === 0) return
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
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) {
90 const pad = Math.max(1, (maxY - minY) * 0.05)
91 _base.yAxis.min = minY - pad
92 _base.yAxis.max = maxY + pad
94 if (_base.markerVisible) {
95 _markerAltValue = logParser.fieldValueAt(control.altFieldName, _base.markerXValue)
99 // -------------------------------------------------------------------------
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
106 control.markerChanged(mid)
109 // -------------------------------------------------------------------------
111 // -------------------------------------------------------------------------
115 function onParseCompleteChanged() {
116 if (!logParser.parseComplete) {
117 if (_altSeries) _altSeries.clear()
119 control.markerCleared()
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)
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) }
138 if (visible && logParser.parseComplete && !_base.markerVisible) {
139 Qt.callLater(_initCursor)
143 // -------------------------------------------------------------------------
145 // -------------------------------------------------------------------------
149 logParser: control.logParser
150 xAxisShowLocalTime: control.xAxisShowLocalTime
151 yAxisTitle: qsTr("Alt (m)")
152 popupYOffset: ScreenTools.defaultFontPixelHeight * 0.4
154 // ---- Chart-specific popup rows ----
158 elide: Text.ElideMiddle
159 width: _base.popupWidth - (ScreenTools.defaultFontPixelWidth * 2)
163 spacing: ScreenTools.defaultFontPixelWidth * 0.3
165 QGCLabel { text: qsTr("Current") }
166 QGCLabel { text: isNaN(_markerAltValue) ? "—" : _markerAltValue.toFixed(1) + " m"; font.bold: true }
168 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
170 QGCLabel { visible: _hasAltRange; text: qsTr("Min") }
171 QGCLabel { visible: _hasAltRange; text: _altMin.toFixed(1) + " m"; font.bold: true }
173 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
175 QGCLabel { visible: _hasAltRange; text: qsTr("Max") }
176 QGCLabel { visible: _hasAltRange; text: _altMax.toFixed(1) + " m"; font.bold: true }