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)
53 _base.graphsView.addSeries(_altSeries)
56 function _refreshSeries() {
57 const fieldName = control.altFieldName
58 if (!logParser.parseComplete || fieldName.length === 0 || !_altSeries) {
59 if (_altSeries) _altSeries.clear()
63 const pixelWidth = Math.max(1, Math.floor(_base.graphsView.plotArea.width))
64 const points = logParser.fieldSamplesFiltered(fieldName, _base.zoomMinX, _base.zoomMaxX, pixelWidth)
67 if (!points || points.length === 0) return
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
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) {
87 const pad = Math.max(1, (maxY - minY) * 0.05)
88 _base.yAxis.min = minY - pad
89 _base.yAxis.max = maxY + pad
91 if (_base.markerVisible) {
92 _markerAltValue = logParser.fieldValueAt(control.altFieldName, _base.markerXValue)
96 // -------------------------------------------------------------------------
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
103 control.markerChanged(mid)
106 // -------------------------------------------------------------------------
108 // -------------------------------------------------------------------------
112 function onParseCompleteChanged() {
113 if (!logParser.parseComplete) {
114 if (_altSeries) _altSeries.clear()
116 control.markerCleared()
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)
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) }
135 if (visible && logParser.parseComplete && !_base.markerVisible) {
136 Qt.callLater(_initCursor)
140 // -------------------------------------------------------------------------
142 // -------------------------------------------------------------------------
146 logParser: control.logParser
147 xAxisShowLocalTime: control.xAxisShowLocalTime
148 yAxisTitle: qsTr("Alt (m)")
149 popupYOffset: ScreenTools.defaultFontPixelHeight * 0.4
151 // ---- Chart-specific popup rows ----
155 elide: Text.ElideMiddle
156 width: _base.popupWidth - (ScreenTools.defaultFontPixelWidth * 2)
160 spacing: ScreenTools.defaultFontPixelWidth * 0.3
162 QGCLabel { text: qsTr("Current") }
163 QGCLabel { text: isNaN(_markerAltValue) ? "—" : _markerAltValue.toFixed(1) + " m"; font.bold: true }
165 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
167 QGCLabel { visible: _hasAltRange; text: qsTr("Min") }
168 QGCLabel { visible: _hasAltRange; text: _altMin.toFixed(1) + " m"; font.bold: true }
170 Item { visible: _hasAltRange; width: ScreenTools.defaultFontPixelWidth * 0.5 }
172 QGCLabel { visible: _hasAltRange; text: qsTr("Max") }
173 QGCLabel { visible: _hasAltRange; text: _altMax.toFixed(1) + " m"; font.bold: true }