- Qt 6.7
- Qt Graphs
- Surface Graph Gallery
- Qt Graphs | Commercial or GPLv3

# Surface Graph Gallery

     // Copyright (C) 2023 The Qt Company Ltd.
     // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

     import QtQuick
     import QtQuick.Controls
     import QtGraphs
     import SurfaceGallery

     Item {
         id: oscilloscopeView

         property int sampleColumns: sampleSlider.value
         property int sampleRows: sampleColumns / 2
         property int sampleCache: 24

         required property bool portraitMode

         property real controlWidth: oscilloscopeView.portraitMode ? oscilloscopeView.width - 10
                                                                   : oscilloscopeView.width / 4 - 6.66

         property real buttonWidth: oscilloscopeView.portraitMode ? oscilloscopeView.width - 10
                                                                  : oscilloscopeView.width / 3 - 7.5

         onSampleRowsChanged: {
             surfaceSeries.selectedPoint = surfaceSeries.invalidSelectionPosition
             generateData()
         }

         DataSource {
             id: dataSource
         }

         Item {
             id: dataView
             anchors.bottom: parent.bottom
             width: parent.width
             height: parent.height - controlArea.height

             Surface3D {
                 id: surfaceGraph
                 anchors.fill: parent

                 Surface3DSeries {
                     id: surfaceSeries
                     drawMode: Surface3DSeries.DrawSurfaceAndWireframe
                     itemLabelFormat: "@xLabel, @zLabel: @yLabel"
                     itemLabelVisible: false

                     onItemLabelChanged: {
                         if (surfaceSeries.selectedPoint == surfaceSeries.invalidSelectionPosition)
                             selectionText.text = "No selection";
                         else
                             selectionText.text = surfaceSeries.itemLabel;
                     }
                 }

                 shadowQuality: AbstractGraph3D.ShadowQuality.None
                 selectionMode: AbstractGraph3D.SelectionSlice | AbstractGraph3D.SelectionItemAndColumn
                 theme: Theme3D {
                     type: Theme3D.Theme.Isabelle
                     backgroundEnabled: false
                 }
                 cameraPreset: AbstractGraph3D.CameraPreset.FrontHigh

                 axisX.labelFormat: "%d ms"
                 axisY.labelFormat: "%d W"
                 axisZ.labelFormat: "%d mV"
                 axisX.min: 0
                 axisY.min: 0
                 axisZ.min: 0
                 axisX.max: 1000
                 axisY.max: 100
                 axisZ.max: 800
                 axisX.segmentCount: 4
                 axisY.segmentCount: 4
                 axisZ.segmentCount: 4
                 measureFps: true
                 renderingMode: AbstractGraph3D.RenderingMode.DirectToBackground

                 onCurrentFpsChanged: (currentFps)=> {
                                          fpsText.text = "FPS: " + currentFps;
                                      }

                 Component.onCompleted: oscilloscopeView.generateData();
             }
         }

         Timer {
             id: refreshTimer
             interval: 1000 / frequencySlider.value
             running: true
             repeat: true
             onTriggered: dataSource.update(surfaceSeries);
         }

         Rectangle {
             id: controlArea
             height: oscilloscopeView.portraitMode ? flatShadingToggle.implicitHeight * 7
                                                   : flatShadingToggle.implicitHeight * 2
             anchors.left: parent.left
             anchors.top: parent.top
             anchors.right: parent.right
             color: surfaceGraph.theme.backgroundColor

             // Samples
             Rectangle {
                 id: samples
                 width: oscilloscopeView.controlWidth
                 height: flatShadingToggle.implicitHeight
                 anchors.left: parent.left
                 anchors.top: parent.top
                 anchors.margins: 5

                 color: surfaceGraph.theme.windowColor
                 border.color: surfaceGraph.theme.gridLineColor
                 border.width: 1
                 radius: 4

                 Row {
                     anchors.centerIn: parent
                     spacing: 10
                     padding: 5

                     Slider {
                         id: sampleSlider
                         from: oscilloscopeView.sampleCache * 2
                         to: from * 10
                         stepSize: oscilloscopeView.sampleCache

                         background: Rectangle {
                             x: sampleSlider.leftPadding
                             y: sampleSlider.topPadding + sampleSlider.availableHeight / 2
                                - height / 2
                             implicitWidth: 200
                             implicitHeight: 4
                             width: sampleSlider.availableWidth
                             height: implicitHeight
                             radius: 2
                             color: surfaceGraph.theme.gridLineColor

                             Rectangle {
                                 width: sampleSlider.visualPosition * parent.width
                                 height: parent.height
                                 color: surfaceGraph.theme.labelTextColor
                                 radius: 2
                             }
                         }

                         handle: Rectangle {
                             x: sampleSlider.leftPadding + sampleSlider.visualPosition
                                * (sampleSlider.availableWidth - width)
                             y: sampleSlider.topPadding + sampleSlider.availableHeight / 2
                                - height / 2
                             implicitWidth: 20
                             implicitHeight: 20
                             radius: 10
                             color: sampleSlider.pressed ? surfaceGraph.theme.gridLineColor
                                                         : surfaceGraph.theme.windowColor
                             border.color: sampleSlider.pressed ? surfaceGraph.theme.labelTextColor
                                                                : surfaceGraph.theme.gridLineColor
                         }

                         Component.onCompleted: value = from;
                     }

                     Text {
                         id: samplesText
                         text: "Samples: " + (oscilloscopeView.sampleRows * oscilloscopeView.sampleColumns)
                         verticalAlignment: Text.AlignVCenter
                         horizontalAlignment: Text.AlignHCenter
                         color: surfaceGraph.theme.labelTextColor
                     }
                 }
             }

             // Frequency
             Rectangle {
                 id: frequency
                 width: oscilloscopeView.controlWidth
                 height: flatShadingToggle.implicitHeight
                 anchors.left: oscilloscopeView.portraitMode ? parent.left : samples.right
                 anchors.top: oscilloscopeView.portraitMode ? samples.bottom : parent.top
                 anchors.margins: 5

                 color: surfaceGraph.theme.windowColor
                 border.color: surfaceGraph.theme.gridLineColor
                 border.width: 1
                 radius: 4

                 Row {
                     anchors.centerIn: parent
                     spacing: 10
                     padding: 5

                     Slider {
                         id: frequencySlider
                         from: 2
                         to: 60
                         stepSize: 2
                         value: 30

                         background: Rectangle {
                             x: frequencySlider.leftPadding
                             y: frequencySlider.topPadding + frequencySlider.availableHeight / 2
                                - height / 2
                             implicitWidth: 200
                             implicitHeight: 4
                             width: frequencySlider.availableWidth
                             height: implicitHeight
                             radius: 2
                             color: surfaceGraph.theme.gridLineColor

                             Rectangle {
                                 width: frequencySlider.visualPosition * parent.width
                                 height: parent.height
                                 color: surfaceGraph.theme.labelTextColor
                                 radius: 2
                             }
                         }

                         handle: Rectangle {
                             x: frequencySlider.leftPadding + frequencySlider.visualPosition
                                * (frequencySlider.availableWidth - width)
                             y: frequencySlider.topPadding + frequencySlider.availableHeight / 2
                                - height / 2
                             implicitWidth: 20
                             implicitHeight: 20
                             radius: 10
                             color: frequencySlider.pressed ? surfaceGraph.theme.gridLineColor
                                                            : surfaceGraph.theme.windowColor
                             border.color: frequencySlider.pressed ? surfaceGraph.theme.labelTextColor
                                                                   : surfaceGraph.theme.gridLineColor
                         }
                     }

                     Text {
                         id: frequencyText
                         text: "Freq: " + frequencySlider.value + " Hz"
                         verticalAlignment: Text.AlignVCenter
                         horizontalAlignment: Text.AlignHCenter
                         color: surfaceGraph.theme.labelTextColor
                     }
                 }
             }

             // FPS
             Rectangle {
                 id: fpsindicator
                 width: oscilloscopeView.controlWidth
                 height: flatShadingToggle.implicitHeight
                 anchors.left: oscilloscopeView.portraitMode ? parent.left : frequency.right
                 anchors.top: oscilloscopeView.portraitMode ? frequency.bottom : parent.top
                 anchors.margins: 5

                 color: surfaceGraph.theme.windowColor
                 border.color: surfaceGraph.theme.gridLineColor
                 border.width: 1
                 radius: 4

                 Text {
                     id: fpsText
                     anchors.fill: parent
                     verticalAlignment: Text.AlignVCenter
                     horizontalAlignment: Text.AlignHCenter
                     color: surfaceGraph.theme.labelTextColor
                 }
             }

             // Selection
             Rectangle {
                 id: selection
                 width: oscilloscopeView.controlWidth
                 height: flatShadingToggle.implicitHeight
                 anchors.left: oscilloscopeView.portraitMode ? parent.left : fpsindicator.right
                 anchors.top: oscilloscopeView.portraitMode ? fpsindicator.bottom : parent.top
                 anchors.margins: 5

                 color: surfaceGraph.theme.windowColor
                 border.color: surfaceGraph.theme.gridLineColor
                 border.width: 1
                 radius: 4

                 Text {
                     id: selectionText
                     anchors.fill: parent
                     verticalAlignment: Text.AlignVCenter
                     horizontalAlignment: Text.AlignHCenter
                     text: "No selection"
                     color: surfaceGraph.theme.labelTextColor
                 }
             }

             // Flat shading
             Button {
                 id: flatShadingToggle
                 width: oscilloscopeView.buttonWidth
                 anchors.left: parent.left
                 anchors.top: selection.bottom
                 anchors.margins: 5

                 text: surfaceSeries.flatShadingSupported ? "Show\nSmooth" : "Flat\nnot supported"
                 enabled: surfaceSeries.flatShadingSupported

                 onClicked: {
                     if (surfaceSeries.flatShadingEnabled) {
                         surfaceSeries.flatShadingEnabled = false;
                         text = "Show\nFlat"
                     } else {
                         surfaceSeries.flatShadingEnabled = true;
                         text = "Show\nSmooth"
                     }
                 }

                 contentItem: Text {
                     text: flatShadingToggle.text
                     opacity: flatShadingToggle.enabled ? 1.0 : 0.3
                     color: surfaceGraph.theme.labelTextColor
                     horizontalAlignment: Text.AlignHCenter
                     verticalAlignment: Text.AlignVCenter
                     elide: Text.ElideRight
                 }

                 background: Rectangle {
                     opacity: flatShadingToggle.enabled ? 1 : 0.3
                     color: flatShadingToggle.down ? surfaceGraph.theme.gridLineColor
                                                   : surfaceGraph.theme.windowColor
                     border.color: flatShadingToggle.down ? surfaceGraph.theme.labelTextColor
                                                          : surfaceGraph.theme.gridLineColor
                     border.width: 1
                     radius: 2
                 }
             }

             // Surface grid
             Button {
                 id: surfaceGridToggle
                 width: oscilloscopeView.buttonWidth
                 anchors.left: oscilloscopeView.portraitMode ? parent.left : flatShadingToggle.right
                 anchors.top: oscilloscopeView.portraitMode ? flatShadingToggle.bottom : selection.bottom
                 anchors.margins: 5

                 text: "Hide\nSurface Grid"

                 onClicked: {
                     if (surfaceSeries.drawMode & Surface3DSeries.DrawWireframe) {
                         surfaceSeries.drawMode &= ~Surface3DSeries.DrawWireframe;
                         text = "Show\nSurface Grid";
                     } else {
                         surfaceSeries.drawMode |= Surface3DSeries.DrawWireframe;
                         text = "Hide\nSurface Grid";
                     }
                 }

                 contentItem: Text {
                     text: surfaceGridToggle.text
                     color: surfaceGraph.theme.labelTextColor
                     horizontalAlignment: Text.AlignHCenter
                     verticalAlignment: Text.AlignVCenter
                     elide: Text.ElideRight
                 }

                 background: Rectangle {
                     color: surfaceGridToggle.down ? surfaceGraph.theme.gridLineColor
                                                   : surfaceGraph.theme.windowColor
                     border.color: surfaceGridToggle.down ? surfaceGraph.theme.labelTextColor
                                                          : surfaceGraph.theme.gridLineColor
                     border.width: 1
                     radius: 2
                 }
             }

             // Exit
             Button {
                 id: exitButton
                 width: oscilloscopeView.buttonWidth
                 height: surfaceGridToggle.height
                 anchors.left: oscilloscopeView.portraitMode ? parent.left : surfaceGridToggle.right
                 anchors.top: oscilloscopeView.portraitMode ? surfaceGridToggle.bottom : selection.bottom
                 anchors.margins: 5

                 text: "Quit"

                 onClicked: Qt.quit();

                 contentItem: Text {
                     text: exitButton.text
                     color: surfaceGraph.theme.labelTextColor
                     horizontalAlignment: Text.AlignHCenter
                     verticalAlignment: Text.AlignVCenter
                     elide: Text.ElideRight
                 }

                 background: Rectangle {
                     color: exitButton.down ? surfaceGraph.theme.gridLineColor
                                            : surfaceGraph.theme.windowColor
                     border.color: exitButton.down ? surfaceGraph.theme.labelTextColor
                                                   : surfaceGraph.theme.gridLineColor
                     border.width: 1
                     radius: 2
                 }
             }
         }

         function generateData() {
             dataSource.generateData(oscilloscopeView.sampleCache, oscilloscopeView.sampleRows,
                                     oscilloscopeView.sampleColumns,
                                     surfaceGraph.axisX.min, surfaceGraph.axisX.max,
                                     surfaceGraph.axisY.min, surfaceGraph.axisY.max,
                                     surfaceGraph.axisZ.min, surfaceGraph.axisZ.max);
         }
     }