Wind Turbine Dashboard

A wind turbine dashboard with 2D and 3D graphs.

The Wind Turbine Dashboard example demonstrates how to use both 2D and 3D graphs in a simulated real-world application.

Running the Example

To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, see Qt Creator: Tutorial: Build and run.

Overview of the Application

The example demonstrates a wind turbine monitoring dashboard, referred to as the Aerospace Hub, which displays simulated data from an imaginary wind turbine field. A variety of graph types are employed to visualize different kinds of data. For example, a 2D graph with a spline series illustrates hourly power output, while an accompanying area series represents the accumulated power over the same period. Multiple data views are available, allowing users to explore and analyze the information from different perspectives.

The main interface features a settings toolbar on the left. Depending on the selected mode, the layout may include a status pane, a dashboard of smaller graphs, a primary large graph, or a detailed settings panel - either individually or in combination. This flexible design enables users to customize their view and focus on the most relevant data for their current analysis.

Dashboard View

The dashboard view presents the current system status alongside a scrollable pane that displays miniature previews of the various graphs. Up to four graphs are shown simultaneously, allowing users to conveniently browse through all six available visualizations and quickly assess key performance metrics at a glance.

Detail View

The detail view, accessible by selecting a miniature graph from the dashboard, enables users to examine the chosen visualization in greater depth and at a larger scale. Depending on the graph type, users can zoom, pan, or rotate the view to explore the data interactively. Additionally, individual data points can be hovered over or clicked to reveal more detailed information about the specific item of interest.

Settings View

The settings view, accessible by clicking either the settings button in the toolbar or in a miniature graph, allows users to adjust the visual theme of the graphs and modify settings specific to each graph type. Certain configurations persist after exiting the settings view, while others apply only within the current view, providing flexibility for both temporary and permanent adjustments.

Implementation Details

Everything in the application has been designed in a modular fashion. Main view, which is the Main.qml file, is an ApplicationWindow, which instantiaties the data simulators for each graph, as well as the root Item holding all of the UI elements.

The FontLoader is used for applying a global font for the whole UI.

 ApplicationWindow {
     ...

     FontLoader { ... }
     font.family: interFont.name

     // Data simulators
     PieSimulator {
         id: piesim
         ...
     }

     BarSimulator {
         id: barsim
         ...
     }

     LineSimulator {
         id: linesim
         ...
     }

     Data3DSimulator {
         id: barDataSimulator
         ...
     }

     Data3DSimulator {
         id: scatterDataSimulator
         ...
     }

     Data3DSimulator {
         id: surfaceDataSimulator
         ...
     }

     // Root item
     Item {...}
 }

The root item holds the background graphics and a Layout handling the placement of each UI element in the view:

 // Background image
 Image {
     anchors.fill: parent
     source: root.state === "ShowSettings" ? "images/settings-bg.png"
                                           : "images/dashboard-bg.png"
     fillMode: Image.PreserveAspectCrop
 }

 // Everything except background image
 ColumnLayout {
     anchors.fill: parent
     ...

Most of the elements have been taken out of the Main.qml file itself into their own QML components to be used in the layouts, like the ToolBarItem in the snippet below:

 // Vertical toolbar
 ToolBarItem {
     Layout.preferredWidth: GlobalSettings.toolbarwidth
     Layout.fillHeight: true
 }

 // Everything except vertical toolbar, header, and background image
 ColumnLayout {
     id: maincontentview
     Layout.fillWidth: true
     Layout.fillHeight: true
     ...

Transitions between different view is handled using states and transitions:

 states: [
     State {
         name: "ShowDashboard"
     },
     State {
         name: "ShowSettings"
         PropertyChanges {
             maincontent.opacity: 0
             settingscontent.opacity: 1
         }
         PropertyChanges {
             viewtextdesc.text: "/  Settings"
         }
     },
     ...
 // Use transitions to bring the selected view to the front
 transitions: [
     Transition {
         NumberAnimation {
             properties: "opacity"
             easing.type: Easing.InOutCubic
             duration: 1000
         }
     }
 ]
Dashboard

Dashboard is a part of the main content, another RowLayout inside the Layout hierarchy:

 // Main content
 RowLayout {
     id: maincontent
     Layout.fillWidth: true
     Layout.fillHeight: true
     ...

It is made up of a status pane and a dashboard pane:

 // Status area; turbine image, notification, status texts, and turbine name
 StatusPane {
     id: statuspane
     Layout.preferredWidth: GlobalSettings.statusimagewidth
     Layout.fillHeight: true
 }

 // Scrollable dashboard graph area, shown when in ShowDashboard state
 DashboardPane {
     id: dashboardpane
     contentheight: statuspane.height * 1.5
     Layout.preferredWidth: GlobalSettings.dashboardwidth
     Layout.fillHeight: true
 }
Status Pane

Status pane has also been made up of smaller elements, implemented in their own QML components:

 // Masking the turbine image of the background image
 ImageItem {
     anchors.fill: parent
 }

 // Notification
 NotificationItem {
     anchors.top: turbineimage.top
     anchors.horizontalCenter: turbineimage.horizontalCenter
     anchors.topMargin: GlobalSettings.doublespacing
     width: turbineimage.width / 1.25
 }

 // Status
 StatusItem {
     anchors.centerIn: turbineimage
     width: turbineimage.width / 1.5
     height: turbineimage.width / 1.75
 }

 // Turbine name
 Label {
     ...

The implementation of these is not relevant, so that part will be skipped.

Dashboard Pane

Dashboard is the element holding the six small graph previews. Only four of those are visible at a time, so they have to be added inside an element that can be scrolled. In this case, it is done with a Flickable, which holds a GridLayout:

 Flickable {
     property alias contentheight: content.height

     clip: true

     contentHeight: contentheight

     boundsBehavior: Flickable.StopAtBounds
     interactive: true
     visible: opacity > 0.5

     Item {
         id: content
         width: parent.width

         GridLayout {
             id: grid
             columns: 2
     ...

The graph previews are added inside the grid layout, and like most other elements, they have been implemented inside their own elements:

 // Graph 1: Power output over time
 SmallGraphItem {
     Layout.fillWidth: true
     Layout.fillHeight: true
     state: "Area2D"
     linesimulator: linesim
 }

 // Graph 2: Energy production x Turbine
 SmallGraphItem {
     Layout.fillWidth: true
     Layout.fillHeight: true
     state: "Bar2D"
     barsimulator: barsim
 }
 ...

The SmallGraphItem element is a generic one, holding all different graph types inside it, and the required type is given to it as a state.

SmallGraphItem has:

  • A header element
  • An instance of each graph type, for which visibility is set to false by default using an opacity trigger
  • A rectangle to darken the preview
  • A mouse area to handle hover and mouse clicks on the preview
 Pie2DGraph {
     id: pie2d
     anchors.topMargin: header.height + GlobalSettings.defaultspacing
     anchors.rightMargin: GlobalSettings.defaultspacing
     anchors.fill: parent
     opacity: 0
     piesimulator: smallgraph.piesimulator
 }

 Bar3DGraph {
     id: bar3d
     anchors.topMargin: header.height + GlobalSettings.defaultspacing
     anchors.bottomMargin: GlobalSettings.defaultspacing
     anchors.fill: parent
     opacity: 0
     cameraZoomLevel: GlobalSettings.defaultzoom
     cameraPreset: GlobalSettings.defaultpreset
 }
 ...

Opacities are used for transition animations, which is why they have been set to 0 in the previews by default. When opacity is animated above 0.5, the preview graph itself is set visible:

 Bars3D {
     id: graph
     visible: opacity > 0.5
     ...
Details

Details is also a part of the main content, using the same RowLayout inside the Layout hierarchy. It is made up of the same status pane as the Dashboard, and a details pane:

 // Details graph, shown when in correct state
 BigGraphItem {
     id: detailspane
     Layout.preferredWidth: GlobalSettings.dashboardwidth
     Layout.fillHeight: true
     state: root.state
     radius: GlobalSettings.defaultradius
     piesimulator: piesim
     barsimulator: barsim
     linesimulator: linesim
     detailsview: true
 }

The details pane, BigGraphItem, is similar to the SmallGraphItem in a sense that it also holds an instance of each graph in it, in addition to other elements:

 // Graphs
 Area2DGraph {
     id: area2dbig
     Layout.fillWidth: true
     Layout.fillHeight: true
     Layout.margins: GlobalSettings.defaultmargin
     opacity: 0
     panStyle: GraphsView.PanStyle.Drag
     zoomStyle: GraphsView.ZoomStyle.Center
     linesimulator: biggraph.linesimulator
     onVisibleChanged: {
         if (visible)
             biggraph.activegraph = area2dbig
     }
 }

 Bar2DGraph {
     id: bar2dbig
     Layout.fillWidth: true
     Layout.fillHeight: true
     Layout.margins: GlobalSettings.defaultmargin
     opacity: 0
     panStyle: GraphsView.PanStyle.Drag
     zoomStyle: GraphsView.ZoomStyle.Center
     barsimulator: biggraph.barsimulator
     onVisibleChanged: {
         if (visible)
             biggraph.activegraph = bar2dbig
     }
 }
 ...

Other elements included are a dropdown combobox for selecting the graph type, control buttons for rotating, panning, and zooming - depending on the graph type - and a tooltip for the buttons. Like SmallGraphItem, the graph type shown is decided based on the state.

Settings

Settings has been taken outside the main content Layout, as it is not using any parts of the Dashboard or Details views:

 // Settings
 SettingsItem {
     id: settingscontent
     anchors.fill: parent
     ...

Settings view holds another BigGraphItem for displaying the graph, and a settings pane for adjusting either the GraphsTheme properties or some properties sepcific to the selected graph type.

 // Graph detail
 BigGraphItem {
     id: settingsgraph
     width: GlobalSettings.settingsgraphwidth
     anchors.top: parent.top
     anchors.bottom: parent.bottom
     anchors.topMargin: GlobalSettings.graphdetailmargin
     radius: GlobalSettings.defaultradius
     opacity: parent.opacity
     piesimulator: settingsitem.piesimulator
     barsimulator: settingsitem.barsimulator
     linesimulator: settingsitem.linesimulator
 }

 // Settings pane
 StackLayout {
     id: settingspane
     ...
Global Theme

The settings on the General Settings tab affect all graphs in the application. A global GraphsTheme has been implemented as a Singleton in GlobalSettings.qml:

 pragma Singleton
 ...
 QtObject {
     id: global
     ...
 // Common graph theme
 property var theme: GraphsTheme {
     plotAreaBackgroundVisible: false
     backgroundVisible: false
     colorScheme: GraphsTheme.ColorScheme.Dark
     theme: GraphsTheme.Theme.BlueSeries
     labelTextColor: "#AEAEAE"
     labelBackgroundVisible: true
     labelFont.pointSize: global.fontsize28px
     grid.mainColor: "#AEAEAE"
     grid.mainWidth: 1
     baseGradients: [ global.customgradient ]
 }

This global shared theme is set to each graph as the theme:

 theme: GlobalSettings.theme

As a singleton, the GlobalSettings.qml needs to be tagged as one in the CMakeLists.txt as well, to be usable in the application:

 set_source_files_properties(qml/GlobalSettings.qml
     PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
Graph Settings

The settings in the Graph Settings tab only affect the currently selected graph. These settings do not change the global theme, but the series in the active graph only.

Example project @ code.qt.io