diff --git a/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.cpp b/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.cpp index ff350a15..9cb3a954 100644 --- a/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.cpp +++ b/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.cpp @@ -332,6 +332,7 @@ void QDateTimeAxis::setZoom(qreal zoom) } d->m_zoom = zoom; + d->calculateVisualRange(); emit zoomChanged(zoom); emit update(); } @@ -352,6 +353,7 @@ void QDateTimeAxis::setPan(qreal pan) } d->m_pan = pan; + d->calculateVisualRange(); emit panChanged(pan); emit update(); } @@ -362,6 +364,18 @@ qreal QDateTimeAxis::pan() const return d->m_pan; } +QDateTime QDateTimeAxis::visualMin() const +{ + Q_D(const QDateTimeAxis); + return QDateTime::fromMSecsSinceEpoch(d->m_visualMin, d->m_timeZone); +} + +QDateTime QDateTimeAxis::visualMax() const +{ + Q_D(const QDateTimeAxis); + return QDateTime::fromMSecsSinceEpoch(d->m_visualMax, d->m_timeZone); +} + /////////////////////////////////////////////////////////////////////////////// QDateTimeAxisPrivate::QDateTimeAxisPrivate() {} @@ -407,8 +421,30 @@ void QDateTimeAxisPrivate::setRange(qreal min, qreal max) emit q->maxChanged(QDateTime::fromMSecsSinceEpoch(max, QTimeZone::UTC)); } - if (changed) + if (changed) { + calculateVisualRange(); emit q->rangeChanged(min, max); + } +} + +void QDateTimeAxisPrivate::calculateVisualRange() +{ + Q_Q(QDateTimeAxis); + qreal diff = m_max - m_min; + qreal center = diff / 2.0f + m_min + m_pan; + diff /= m_zoom; + qreal max = center + diff / 2.0f; + qreal min = center - diff / 2.0f; + + if (!qFuzzyCompare(m_visualMin, min)) { + m_visualMin = min; + emit q->visualMinChanged(min); + } + + if (!qFuzzyCompare(m_visualMax, max)) { + m_visualMax = max; + emit q->visualMaxChanged(max); + } } QT_END_NAMESPACE diff --git a/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.h b/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.h index 9cb437c2..6c806f75 100644 --- a/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.h +++ b/src/graphs2d/axis/datetimeaxis/qdatetimeaxis.h @@ -25,6 +25,8 @@ class Q_GRAPHS_EXPORT QDateTimeAxis : public QAbstractAxis QString timeZone READ timeZone WRITE setTimeZone NOTIFY timeZoneChanged REVISION(6, 11)) Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged REVISION(6, 11)) Q_PROPERTY(qreal pan READ pan WRITE setPan NOTIFY panChanged REVISION(6, 11)) + Q_PROPERTY(QDateTime visualMin READ visualMin NOTIFY visualMinChanged REVISION(6, 11)) + Q_PROPERTY(QDateTime visualMax READ visualMax NOTIFY visualMaxChanged REVISION(6, 11)) QML_NAMED_ELEMENT(DateTimeAxis) @@ -62,6 +64,9 @@ public: qreal pan() const; void setPan(qreal pan); + QDateTime visualMin() const; + QDateTime visualMax() const; + Q_SIGNALS: void minChanged(const QDateTime &min); void maxChanged(const QDateTime &max); @@ -71,6 +76,8 @@ Q_SIGNALS: Q_REVISION(6, 11) void timeZoneChanged(const QString &timeZone); Q_REVISION(6, 11) void zoomChanged(qreal zoom); Q_REVISION(6, 11) void panChanged(qreal pan); + Q_REVISION(6, 11) void visualMinChanged(qreal min); + Q_REVISION(6, 11) void visualMaxChanged(qreal max); private: Q_DECLARE_PRIVATE(QDateTimeAxis) diff --git a/src/graphs2d/axis/datetimeaxis/qdatetimeaxis_p.h b/src/graphs2d/axis/datetimeaxis/qdatetimeaxis_p.h index a5c5680b..617e00a4 100644 --- a/src/graphs2d/axis/datetimeaxis/qdatetimeaxis_p.h +++ b/src/graphs2d/axis/datetimeaxis/qdatetimeaxis_p.h @@ -33,6 +33,8 @@ protected: QString m_format = QStringLiteral("dd-MMMM-yy"); qreal m_zoom = 1.0; qreal m_pan = 0.0; + qreal m_visualMin; + qreal m_visualMax; public: void setMin(const QVariant &min) override; @@ -41,6 +43,7 @@ public: void setRange(qreal min, qreal max) override; qreal min() override { return m_min; } qreal max() override { return m_max; } + void calculateVisualRange(); private: Q_DECLARE_PUBLIC(QDateTimeAxis) diff --git a/src/graphs2d/axis/valueaxis/qvalueaxis.cpp b/src/graphs2d/axis/valueaxis/qvalueaxis.cpp index e1b7649a..8f622249 100644 --- a/src/graphs2d/axis/valueaxis/qvalueaxis.cpp +++ b/src/graphs2d/axis/valueaxis/qvalueaxis.cpp @@ -366,6 +366,7 @@ void QValueAxis::setZoom(qreal zoom) Q_D(QValueAxis); if (d->m_zoom != zoom) { d->m_zoom = zoom; + d->calculateVisualRange(); emit update(); emit zoomChanged(zoom); } else { @@ -385,6 +386,7 @@ void QValueAxis::setPan(qreal pan) Q_D(QValueAxis); if (d->m_pan != pan) { d->m_pan = pan; + d->calculateVisualRange(); emit update(); emit panChanged(pan); } else { @@ -399,6 +401,18 @@ qreal QValueAxis::pan() const return d->m_pan; } +qreal QValueAxis::visualMin() const +{ + Q_D(const QValueAxis); + return d->m_visualMin; +} + +qreal QValueAxis::visualMax() const +{ + Q_D(const QValueAxis); + return d->m_visualMax; +} + /*! Returns the type of the axis. */ @@ -477,8 +491,28 @@ void QValueAxisPrivate::setRange(qreal min, qreal max) emit q->maxChanged(max); } - if (changed) + if (changed) { + calculateVisualRange(); emit q->rangeChanged(min, max); + } +} + +void QValueAxisPrivate::calculateVisualRange() +{ + Q_Q(QValueAxis); + qreal diff = m_max - m_min; + qreal center = diff / 2.0f + m_min + m_pan; + diff /= m_zoom; + qreal min = center - diff / 2.0f; + qreal max = center + diff / 2.0f; + if (!qFuzzyCompare(m_visualMin, min)) { + m_visualMin = min; + emit q->visualMinChanged(min); + } + if (!qFuzzyCompare(m_visualMax, max)) { + m_visualMax = max; + emit q->visualMaxChanged(max); + } } QT_END_NAMESPACE diff --git a/src/graphs2d/axis/valueaxis/qvalueaxis.h b/src/graphs2d/axis/valueaxis/qvalueaxis.h index 8f564f77..9cb2ad16 100644 --- a/src/graphs2d/axis/valueaxis/qvalueaxis.h +++ b/src/graphs2d/axis/valueaxis/qvalueaxis.h @@ -28,6 +28,8 @@ class Q_GRAPHS_EXPORT QValueAxis : public QAbstractAxis qreal tickInterval READ tickInterval WRITE setTickInterval NOTIFY tickIntervalChanged FINAL) Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged REVISION(6, 9)) Q_PROPERTY(qreal pan READ pan WRITE setPan NOTIFY panChanged REVISION(6, 9)) + Q_PROPERTY(qreal visualMin READ visualMin NOTIFY visualMinChanged REVISION(6, 11)) + Q_PROPERTY(qreal visualMax READ visualMax NOTIFY visualMaxChanged REVISION(6, 11)) QML_NAMED_ELEMENT(ValueAxis) public: @@ -67,6 +69,9 @@ public: void setPan(qreal pan); qreal pan() const; + qreal visualMin() const; + qreal visualMax() const; + Q_SIGNALS: void minChanged(qreal min); void maxChanged(qreal max); @@ -78,6 +83,8 @@ Q_SIGNALS: void tickIntervalChanged(qreal tickInterval); Q_REVISION(6, 9) void zoomChanged(qreal zoom); Q_REVISION(6, 9) void panChanged(qreal pan); + Q_REVISION(6, 11) void visualMinChanged(qreal visualMin); + Q_REVISION(6, 11) void visualMaxChanged(qreal visualMax); private: Q_DECLARE_PRIVATE(QValueAxis) diff --git a/src/graphs2d/axis/valueaxis/qvalueaxis_p.h b/src/graphs2d/axis/valueaxis/qvalueaxis_p.h index a4a74ce0..5a4fa78f 100644 --- a/src/graphs2d/axis/valueaxis/qvalueaxis_p.h +++ b/src/graphs2d/axis/valueaxis/qvalueaxis_p.h @@ -28,6 +28,7 @@ public: qreal min() override { return m_min; } qreal max() override { return m_max; } void setRange(qreal min,qreal max) override; + void calculateVisualRange(); protected: void setMin(const QVariant &min) override; @@ -44,6 +45,8 @@ private: qreal m_tickInterval; qreal m_zoom = 1.0; qreal m_pan = 0.0; + qreal m_visualMin = m_min; + qreal m_visualMax = m_max; Q_DECLARE_PUBLIC(QValueAxis) }; diff --git a/tests/manual/qmltestbed/qml/qmltestbed/DateTimeAxis.qml b/tests/manual/qmltestbed/qml/qmltestbed/DateTimeAxis.qml index cb758f8c..ffe227d7 100644 --- a/tests/manual/qmltestbed/qml/qmltestbed/DateTimeAxis.qml +++ b/tests/manual/qmltestbed/qml/qmltestbed/DateTimeAxis.qml @@ -12,80 +12,109 @@ Rectangle { width: 800 height: 600 color: "#202020" - - RowLayout { - id:bar + ColumnLayout { + id: infoLayout + anchors { + left: parent.left + right: parent.right + leftMargin: 25 + } height: 100 - - Text { - Layout.leftMargin: 20 - font.pixelSize: 24 - color: "#ffffff" - text: "X:" - } - - Slider { - id: sliderX - - value: (new Date(1950,1,1)).getTime() - from: (new Date(1900,1,1)).getTime() - to: (new Date(2000,1,1)).getTime() - } - - Text { - font.pixelSize: 24 - color: "#ffffff" - text: "Y:" - } - - Slider { - id: sliderY - - value: (new Date(1950,1,1)).getTime() - from: (new Date(1900,1,1)).getTime() - to: (new Date(2000,1,1)).getTime() - } - - Text { - Layout.leftMargin: 20 - font.pixelSize: 24 - color: "#ffffff" - text: "X Ticks:" - } - - SpinBox { - onValueChanged: xAxis.tickInterval = value - } - - Text { - Layout.leftMargin: 20 - font.pixelSize: 24 - color: "#ffffff" - text: "X Format:" - } - TextField { - placeholderText: "MMMM-yyyy" - onAccepted: xAxis.labelFormat = text - } - - CheckBox { - id: zoomAreaEnabled - text: "Zoom area enabled" - contentItem: Text { - text: zoomAreaEnabled.text - font: zoomAreaEnabled.font + spacing: 0 + RowLayout { + Layout.fillHeight: true + Layout.fillWidth: true + Text { + Layout.leftMargin: 20 + font.pixelSize: 24 color: "#ffffff" - verticalAlignment: Text.AlignVCenter - leftPadding: zoomAreaEnabled.indicator.width + zoomAreaEnabled.spacing + text: "X:" + } + Slider { + id: sliderX + value: (new Date(1950,1,1)).getTime() + from: (new Date(1900,1,1)).getTime() + to: (new Date(2000,1,1)).getTime() + } + Text { + font.pixelSize: 24 + color: "#ffffff" + text: "Y:" + } + Slider { + id: sliderY + value: (new Date(1950,1,1)).getTime() + from: (new Date(1900,1,1)).getTime() + to: (new Date(2000,1,1)).getTime() + } + Text { + Layout.leftMargin: 20 + font.pixelSize: 24 + color: "#ffffff" + text: "X Ticks:" + } + SpinBox { + onValueChanged: xAxis.tickInterval = value + } + Text { + Layout.leftMargin: 20 + font.pixelSize: 24 + color: "#ffffff" + text: "X Format:" + } + TextField { + placeholderText: "MMMM-yyyy" + onAccepted: xAxis.labelFormat = text + } + CheckBox { + id: zoomAreaEnabled + text: "Zoom area enabled" + contentItem: Text { + text: zoomAreaEnabled.text + font: zoomAreaEnabled.font + color: "#ffffff" + verticalAlignment: Text.AlignVCenter + leftPadding: zoomAreaEnabled.indicator.width + zoomAreaEnabled.spacing + } + } + } + RowLayout { + Layout.fillHeight: true + spacing: 50 + Column { + Label { + id: visualXMin + text: "X Axis visualMin: " + xAxis.visualMin + color: "white" + } + Label { + id: visualXMax + text: "X Axis visualMax: " + xAxis.visualMax + color: "white" + } + } + Column { + Label { + id: visualYMin + text: "Y Axis visualMin: " + yAxis.visualMin + color: "white" + } + Label { + id: visualYMax + text: "Y Axis visualMax: " + yAxis.visualMax + color: "white" + } } } } + + GraphsView { anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom - anchors.top: bar.bottom + anchors.top: infoLayout.bottom anchors.margins: 10 zoomStyle: GraphsView.ZoomStyle.Center; panStyle: zoomAreaEnabled.checked ? GraphsView.PanStyle.None : GraphsView.PanStyle.Drag diff --git a/tests/manual/qmltestbed/qml/qmltestbed/LineProperties.qml b/tests/manual/qmltestbed/qml/qmltestbed/LineProperties.qml index 00d145d3..43b3149c 100644 --- a/tests/manual/qmltestbed/qml/qmltestbed/LineProperties.qml +++ b/tests/manual/qmltestbed/qml/qmltestbed/LineProperties.qml @@ -152,6 +152,22 @@ Rectangle { toValue: 40 onSliderValueChanged: yAxis.max = sliderValue; } + CustomLabel { + id: visualRangeMinXLabel + text: qsTr("X Axis visualMin: %1").arg(Number(xAxis.visualMin).toLocaleString()) + } + CustomLabel { + id: visualRangeMaxXLabel + text: qsTr("X Axis visualMax: %1").arg(Number(xAxis.visualMax).toLocaleString()) + } + CustomLabel { + id: visualRangeMinYLabel + text: qsTr("Y Axis visualMin: %1").arg(Number(yAxis.visualMin).toLocaleString()) + } + CustomLabel { + id: visualRangeMaxYLabel + text: qsTr("Y Axis visualMax: %1").arg(Number(yAxis.visualMax).toLocaleString()) + } } GraphsView {