7import QGroundControl.Controls
8import QGroundControl.FactControls
13 QGCPalette { id: qgcPal }
15 property real availableHeight
16 property real availableWidth
20 property var tuningMode
21 property double chartDisplaySec: 8 // number of seconds to display
22 property bool showAutoModeChange: false
23 property bool showAutoTuning: false
24 property bool useAutoTuning: false
26 property real _margins: ScreenTools.defaultFontPixelHeight / 2
27 property int _currentAxis: 0
28 property var _xAxis: xAxis
29 property var _yAxis: yAxis
30 property int _msecs: 0
31 property double _last_t: 0
32 property var _savedTuningParamValues: [ ]
34 readonly property int _tickSeparation: 5
35 readonly property int _maxTickSections: 10
37 property string _chartTitle: ""
38 readonly property var _seriesColors: ["#21be2b", "#c62828", "#1565c0", "#f9a825", "#6a1b9a", "#00838f"]
39 property var _legendModel: []
42 id: lineSeriesComponent
46 function adjustYAxisMin(yAxis, newValue) {
47 var newMin = Math.min(yAxis.min, newValue)
48 if (newMin % 5 != 0) {
50 newMin = Math.floor(newMin / _tickSeparation) * _tickSeparation
55 function adjustYAxisMax(yAxis, newValue) {
56 var newMax = Math.max(yAxis.max, newValue)
57 if (newMax % 5 != 0) {
59 newMax = Math.floor(newMax / _tickSeparation) * _tickSeparation
64 function resetGraphs() {
65 for (var i = 0; i < chart.seriesList.length; ++i) {
66 chart.seriesList[i].clear()
76 // Save the current set of tuning values so we can reset to them
77 function saveTuningParamValues() {
78 _savedTuningParamValues = [ ]
79 for (var i=0; i<axis[_currentAxis].params.count; i++) {
80 var currentTuneParam = controller.getParameterFact(-1, axis[_currentAxis].params.get(i).param)
81 _savedTuningParamValues.push(currentTuneParam.valueString)
83 savedRepeater.model = _savedTuningParamValues
86 function resetToSavedTuningParamValues() {
87 for (var i=0; i<axis[_currentAxis].params.count; i++) {
88 var currentTuneParam = controller.getParameterFact(-1,
89 axis[_currentAxis].params.get(i).param)
90 currentTuneParam.value = _savedTuningParamValues[i]
94 function axisIndexChanged() {
95 while (chart.seriesList.length > 0) {
96 var s = chart.seriesList[0]
101 axis[_currentAxis].plot.forEach(function(e, idx) {
102 var color = _seriesColors[idx % _seriesColors.length]
103 var series = lineSeriesComponent.createObject(chart, {name: e.name, color: color})
104 chart.addSeries(series)
105 legendItems.push({name: e.name, color: color})
107 _legendModel = legendItems
108 var chartTitle = axis[_currentAxis].plotTitle
109 if (chartTitle == null)
110 chartTitle = axis[_currentAxis].name
111 _chartTitle = chartTitle + " " + title
112 saveTuningParamValues()
116 Component.onCompleted: {
118 globals.activeVehicle.setPIDTuningTelemetryMode(tuningMode)
119 saveTuningParamValues()
122 Component.onDestruction: globals.activeVehicle.setPIDTuningTelemetryMode(Vehicle.ModeDisabled)
123 on_CurrentAxisChanged: axisIndexChanged()
132 _xAxis.max = _msecs / 1000
133 _xAxis.min = _msecs / 1000 - chartDisplaySec
135 var firstPoint = _msecs == 0
137 var len = axis[_currentAxis].plot.length
138 for (var i = 0; i < len; ++i) {
139 var value = axis[_currentAxis].plot[i].value
141 chart.seriesList[i].append(_msecs/1000, value)
146 adjustYAxisMin(_yAxis, value)
147 adjustYAxisMax(_yAxis, value)
150 var minSec = _msecs/1000 - 3*60
151 while (chart.seriesList[i].count > 0 && chart.seriesList[i].at(0).x < minSec) {
152 chart.seriesList[i].remove(0)
157 var t = new Date().getTime() // in ms
163 property int _maxPointCount: 10000 / interval
168 Layout.fillWidth: true
169 Layout.alignment: Qt.AlignTop
170 spacing: ScreenTools.defaultFontPixelHeight / 4
171 clip: true // chart has redraw problems
176 font.pointSize: ScreenTools.defaultFontPointSize
177 font.family: ScreenTools.normalFontFamily
178 anchors.horizontalCenter: parent.horizontalCenter
183 width: Math.max(_minChartWidth, availableWidth - rightPanel.width - parent.spacing - _margins)
184 height: Math.max(_minChartHeight, availableHeight - leftPanelBottomColumn.height - chartTitleLabel.height - legendRow.height - parent.spacing * 3 - _margins)
186 property real _minChartWidth: ScreenTools.defaultFontPixelWidth * 40
187 property real _minChartHeight: ScreenTools.defaultFontPixelHeight * 15
190 colorScheme: qgcPal.globalTheme === QGCPalette.Light ? GraphsTheme.ColorScheme.Light : GraphsTheme.ColorScheme.Dark
191 plotAreaBackgroundColor: qgcPal.window
192 grid.mainColor: Qt.rgba(qgcPal.text.r, qgcPal.text.g, qgcPal.text.b, 0.5)
193 grid.subColor: Qt.rgba(qgcPal.text.r, qgcPal.text.g, qgcPal.text.b, 0.3)
195 labelBackgroundVisible: false
196 labelTextColor: qgcPal.text
204 titleText: ScreenTools.isShortScreen ? "" : qsTr("sec")
205 titleFont.pointSize: ScreenTools.defaultFontPointSize
206 titleFont.family: ScreenTools.normalFontFamily
214 tickInterval: _tickSeparation
215 titleFont.pointSize: ScreenTools.defaultFontPointSize
216 titleFont.family: ScreenTools.normalFontFamily
219 // enable mouse dragging
221 property var _startPoint: undefined
222 property double _scaling: 0
224 onPressed: (mouse) => {
225 _startPoint = Qt.point(mouse.x, mouse.y)
226 if (chart.seriesList.length > 0) {
227 var start = chart.seriesList[0].dataPointCoordinatesAt(_startPoint.x, _startPoint.y)
228 var next = chart.seriesList[0].dataPointCoordinatesAt(mouse.x+1, mouse.y+1)
229 _scaling = next.x - start.x
232 onWheel: (wheel) => {
233 if (wheel.angleDelta.y > 0)
234 chartDisplaySec /= 1.2
236 chartDisplaySec *= 1.2
237 _xAxis.min = _xAxis.max - chartDisplaySec
239 onPositionChanged: (mouse) => {
240 if(_startPoint != undefined) {
241 dataTimer.running = false
242 var cp = Qt.point(mouse.x, mouse.y)
243 var dx = (cp.x - _startPoint.x) * _scaling
251 _startPoint = undefined
258 spacing: ScreenTools.defaultFontPixelWidth
259 anchors.horizontalCenter: parent.horizontalCenter
264 spacing: ScreenTools.defaultFontPixelWidth / 2
266 width: ScreenTools.defaultFontPixelHeight
267 height: ScreenTools.defaultFontPixelHeight / 3
268 color: modelData.color
269 anchors.verticalCenter: parent.verticalCenter
273 font.pointSize: ScreenTools.smallFontPointSize
280 id: leftPanelBottomColumn
281 spacing: ScreenTools.defaultFontPixelHeight / 4
288 onClicked: resetGraphs()
292 text: dataTimer.running ? qsTr("Stop") : qsTr("Start")
294 dataTimer.running = !dataTimer.running
296 if (showAutoModeChange && autoModeChange.checked) {
297 globals.activeVehicle.flightMode = dataTimer.running ? globals.activeVehicle.stabilizedFlightMode : globals.activeVehicle.pauseFlightMode
302 target: globals.activeVehicle
304 if (armed && !dataTimer.running) { // start plotting on arming if not already running
305 dataTimer.running = true
313 visible: showAutoModeChange
315 text: qsTr("Automatic Flight Mode Switching")
318 dataTimer.running = false
323 visible: autoModeChange.checked
325 text: qsTr("Switches to 'Stabilized' when you click Start.")
326 font.pointSize: ScreenTools.smallFontPointSize
330 text: qsTr("Switches to '%1' when you click Stop.").arg(globals.activeVehicle.pauseFlightMode)
331 font.pointSize: ScreenTools.smallFontPointSize
339 Layout.alignment: Qt.AlignTop
342 visible: showAutoTuning
345 id: useAutoTuningRadio
346 text: qsTr("Use auto-tuning")
347 checked: useAutoTuning
348 onClicked: useAutoTuning = true
351 id: useManualTuningRadio
352 text: qsTr("Use manual tuning")
353 checked: !useAutoTuning
354 onClicked: useAutoTuning = false
359 visible: showAutoTuning && useAutoTuningRadio.checked
363 visible: !showAutoTuning || useManualTuningRadio.checked
368 visible: axis.length > 1
370 QGCLabel { text: qsTr("Select Tuning:") }
376 checked: index == _currentAxis
377 onClicked: _currentAxis = index
383 // Instantiate all sliders (instead of switching the model), so that
384 // values are not changed unexpectedly if they do not match with a tick value.
390 model: axis[index].params
392 property int axisIndex: index
394 SettingsGroupLayout {
397 headingDescription: description
398 visible: _currentAxis === paramRepeater.axisIndex
399 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 40
402 fact: controller.getParameterFact(-1, param)
405 majorTickStepSize: step
406 Layout.fillWidth: true
413 QGCLabel { text: qsTr("Clipboard Values:") }
416 rows: savedRepeater.model.length
417 flow: GridLayout.TopToBottom
419 columnSpacing: _margins
422 model: axis[_currentAxis].params
424 QGCLabel { text: param }
430 QGCLabel { text: modelData }
439 text: qsTr("Save To Clipboard")
440 onClicked: saveTuningParamValues()
444 text: qsTr("Restore From Clipboard")
445 onClicked: resetToSavedTuningParamValues()