// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \example qmlaxishandling \meta tags {DataVisualization, Scatter3D, Custom Input Handler, Dynamic Data, Custom Axis Formatter, Scatter Graph} \title Axis Handling \ingroup qtdatavisualization_qmlexamples \brief Implementing axis dragging with a custom input handler in QML, and creating a custom axis formatter. \since QtDataVisualization 6.5 \e {Axis Handling} demonstrates two different custom features with axes. The features have their own tabs in the application. The following sections concentrate on those features only and skip explaining the basic functionality - for more detailed QML example documentation, see \l{Simple Scatter Graph}. \image qmlaxishandling-example.png \include examples-run.qdocinc \section1 Axis Dragging In the \uicontrol {Axis Dragging} tab, implement a custom input handler in QML that enables you to drag axis labels to change axis ranges. Further, use orthographic projection and dynamically update the properties of a custom item. \section2 Overriding Default Input Handling To deactivate the default input handling mechanism, set the active input handler of Scatter3D graph to \c{null}: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 0 \dots Then, add a MouseArea and set it to fill the parent, which is the same \c Item our \c scatterGraph is contained in. Also, set it to accept only left mouse button presses, as in this example the other buttons are not needed: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 1 \dots Then, listen to mouse presses, and when caught, send a selection query to the graph: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 2 The \c{onPositionChanged} signal handler catches the current mouse position that will be needed for move distance calculation: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 3 \dots At the end of \c{onPositionChanged}, save the previous mouse position for move distance calculation that will be introduced later: \dots 0 \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 4 \section2 Translating Mouse Movement to Axis Range Change In \c {scatterGraph}, listen to \c {onSelectedElementChanged}. The signal is emitted after the selection query has been made in the \c{onPressed} of the \c{inputArea}. Set the element type into a property you defined (\c{property int selectedAxisLabel: -1}) in the main component, since it is of a type you are interested in: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 5 Then, back in the \c onPositionChanged of \c{inputArea}, check if a mouse button is pressed and if you have a current axis label selection. If the conditions are met, call the function that does the conversion from mouse movement to axis range update: \dots 0 \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 6 \dots 0 The conversion is easy in this case, as the camera rotation is fixed. You can use some precalculated values, calculate mouse move distance, and apply the values to the selected axis range: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 7 For a more sophisticated conversion from mouse movement to axis range update, see \l{Graph Gallery}. \section2 Other Features The example also demonstrates how to use orthographic projection and how to update properties of a custom item on the fly. Orthographic projection is very simple. You'll just need to change the \c orthoProjection property of \c{scatterGraph}. The example has a button for toggling it on and off: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 8 For custom items, add one to the \c customItemList of \c{scatterGraph}: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 9 You implement a timer to add, remove, and rotate all the items in the graph, and use the same timer for rotating the custom item: \snippet qmlaxishandling/qml/qmlaxishandling/AxisDragging.qml 10 \dots \section1 Axis Formatters In the \uicontrol {Axis Formatter} tab, create a custom axis formatter. It also illustrates how to use predefined axis formatters. \section2 Custom Axis Formatter Customizing axis formatters requires subclassing the QValue3DAxisFormatter, which cannot be done in QML code alone. In this example, the axis interprets the float values as a timestamp and shows the date in the axis labels. To achieve this, introduce a new class called \c CustomFormatter, which subclasses the QValue3DAxisFormatter: \snippet qmlaxishandling/customformatter.h 2 \dots 0 Since float values of a QScatter3DSeries cannot be directly cast into QDateTime values due to difference in data width, some sort of mapping between the two is needed. To do the mapping, specify an origin date for the formatter and interpret the float values from the QScatter3DSeries as date offsets to that origin value. The origin date is given as a property: \snippet qmlaxishandling/customformatter.h 1 For the mapping from value to QDateTime, use the \c valueToDateTime() method: \snippet qmlaxishandling/customformatter.cpp 0 To function as an axis formatter, \c CustomFormatter needs to reimplement some virtual methods: \snippet qmlaxishandling/customformatter.h 0 The first two are simple, just create a new instance of \c CustomFormatter and copy the necessary data over to it. Use these two methods to create and update a cache of formatter for rendering purposes. Remember to call the superclass implementation of \c populateCopy(): \snippet qmlaxishandling/customformatter.cpp 1 \c CustomFormatter does the bulk of its work in the \c recalculate() method, where our formatter calculates the grid, subgrid, and label positions, as well as formats the label strings. In the custom formatter, ignore the segment count of the axis and draw a grid line always at midnight. Subsegment count and label positioning is handled normally: \snippet qmlaxishandling/customformatter.cpp 2 The axis labels are formatted to show only the date. However, to increase the resolution of the timestamp of the selection label, specify another property for the custom formatter to allow the user to customize it: \snippet qmlaxishandling/customformatter.h 3 This selection format property is used in the reimplemented \c stringToValue method, where the submitted format is ignored and the custom selection format substituted for it: \snippet qmlaxishandling/customformatter.cpp 3 To expose our new custom formatter to the QML, declare it and make it a QML module. For information about how to do this, see \l{Surface Graph Gallery}. \section2 QML In the QML code, define a different axis for each dimension: \snippet qmlaxishandling/qml/qmlaxishandling/AxisFormatting.qml 3 The Z-axis is just a regular ValueAxis3D: \snippet qmlaxishandling/qml/qmlaxishandling/AxisFormatting.qml 0 For the Y-axis, define a logarithmic axis. To make ValueAxis3D show a logarithmic scale, specify LogValueAxis3DFormatter for \c formatter property of the axis: \snippet qmlaxishandling/qml/qmlaxishandling/AxisFormatting.qml 2 And finally, for the X-axis use the new \c CustomFormatter: \snippet qmlaxishandling/qml/qmlaxishandling/AxisFormatting.qml 1 The rest of the application consists of fairly self-explanatory logic for modifying the axes and showing the graph. \section1 Example Contents */