From a4a326800400d07fdab2da872c04d30c17602b4d Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 10 Aug 2016 14:12:10 +0300 Subject: [PATCH 1/9] Fix QT_BUILD_INTERNAL usage in autotests We need to do the define check after QtTest include, or otherwise the affected tests are always skipped. Change-Id: I472c1222a8c4f98cd722b9190c94412f7cf4808a Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- tests/auto/chartdataset/tst_chartdataset.cpp | 3 ++- tests/auto/domain/tst_domain.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/auto/chartdataset/tst_chartdataset.cpp b/tests/auto/chartdataset/tst_chartdataset.cpp index fcbb34bc..78c3d5a4 100644 --- a/tests/auto/chartdataset/tst_chartdataset.cpp +++ b/tests/auto/chartdataset/tst_chartdataset.cpp @@ -18,9 +18,10 @@ ** $QT_END_LICENSE$ ** ******************************************************************************/ -#ifndef QT_BUILD_INTERNAL #include +#ifndef QT_BUILD_INTERNAL + class tst_ChartDataSet: public QObject { Q_OBJECT diff --git a/tests/auto/domain/tst_domain.cpp b/tests/auto/domain/tst_domain.cpp index 8b960eae..55e4dba1 100644 --- a/tests/auto/domain/tst_domain.cpp +++ b/tests/auto/domain/tst_domain.cpp @@ -18,10 +18,11 @@ ** $QT_END_LICENSE$ ** ******************************************************************************/ -#ifndef QT_BUILD_INTERNAL #include +#ifndef QT_BUILD_INTERNAL + class tst_Domain: public QObject { Q_OBJECT From 1bba1635a61b8516b00a010345dffb54d648632d Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 29 Jun 2016 09:39:47 +0300 Subject: [PATCH 2/9] Fix issues with reverse axes Moved the reverse axis handling to domains instead of simply mirroring the painter. This fixes the following issues with reverse axes: - QChart mapping functions returned unreversed values - Bounding regions of series were incorrect - Mouse events gave wrong positions - Chart scrolling and zooming didn't account for reversed axes Task-number: QTBUG-54401 Change-Id: I6aed9e13c0d1d956a389dfe70f36f630d79d1ddf Reviewed-by: Janne Koskinen Reviewed-by: Miikka Heikkinen --- src/charts/areachart/areachartitem.cpp | 36 ++++--------- src/charts/chartitem.cpp | 13 ----- src/charts/chartitem_p.h | 1 - src/charts/domain/abstractdomain.cpp | 55 +++++++++++++++----- src/charts/domain/abstractdomain_p.h | 11 ++++ src/charts/domain/logxlogydomain.cpp | 53 ++++++++++++------- src/charts/domain/logxydomain.cpp | 44 +++++++++++----- src/charts/domain/xlogydomain.cpp | 40 ++++++++++---- src/charts/domain/xydomain.cpp | 39 ++++++++++---- src/charts/linechart/linechartitem.cpp | 4 -- src/charts/qabstractseries.cpp | 34 ------------ src/charts/qabstractseries_p.h | 2 - src/charts/scatterchart/scatterchartitem.cpp | 11 +--- src/charts/splinechart/splinechartitem.cpp | 4 -- src/charts/xychart/qxyseries.cpp | 10 +--- 15 files changed, 191 insertions(+), 166 deletions(-) diff --git a/src/charts/areachart/areachartitem.cpp b/src/charts/areachart/areachartitem.cpp index 88a6918b..b13cdc19 100644 --- a/src/charts/areachart/areachartitem.cpp +++ b/src/charts/areachart/areachartitem.cpp @@ -167,6 +167,8 @@ void AreaChartItem::handleDomainUpdated() AbstractDomain* d = m_upper->domain(); d->setSize(domain()->size()); d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY()); + d->setReverseX(domain()->isReverseX()); + d->setReverseY(domain()->isReverseY()); m_upper->handleDomainUpdated(); } @@ -174,6 +176,8 @@ void AreaChartItem::handleDomainUpdated() AbstractDomain* d = m_lower->domain(); d->setSize(domain()->size()); d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY()); + d->setReverseX(domain()->isReverseX()); + d->setReverseY(domain()->isReverseY()); m_lower->handleDomainUpdated(); } } @@ -191,8 +195,6 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt else painter->setClipRect(clipRect); - reversePainter(painter, clipRect); - painter->drawPath(m_path); if (m_pointsVisible) { painter->setPen(m_pointPen); @@ -201,8 +203,6 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt painter->drawPoints(m_lower->geometryPoints()); } - reversePainter(painter, clipRect); - // Draw series point label if (m_pointLabelsVisible) { static const QString xPointTag(QLatin1String("@xPoint")); @@ -231,17 +231,9 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt // Position text in relation to the point int pointLabelWidth = fm.width(pointLabel); QPointF position(m_upper->geometryPoints().at(i)); - if (!seriesPrivate()->reverseXAxis()) - position.setX(position.x() - pointLabelWidth / 2); - else - position.setX(domain()->size().width() - position.x() - pointLabelWidth / 2); - if (!seriesPrivate()->reverseYAxis()) { - position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 - - labelOffset); - } else { - position.setY(domain()->size().height() - position.y() - - m_series->upperSeries()->pen().width() / 2 - labelOffset); - } + position.setX(position.x() - pointLabelWidth / 2); + position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 + - labelOffset); painter->drawText(position, pointLabel); } } @@ -257,17 +249,9 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt // Position text in relation to the point int pointLabelWidth = fm.width(pointLabel); QPointF position(m_lower->geometryPoints().at(i)); - if (!seriesPrivate()->reverseXAxis()) - position.setX(position.x() - pointLabelWidth / 2); - else - position.setX(domain()->size().width() - position.x() - pointLabelWidth / 2); - if (!seriesPrivate()->reverseYAxis()) { - position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 - - labelOffset); - } else { - position.setY(domain()->size().height() - position.y() - - m_series->lowerSeries()->pen().width() / 2 - labelOffset); - } + position.setX(position.x() - pointLabelWidth / 2); + position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 + - labelOffset); painter->drawText(position, pointLabel); } } diff --git a/src/charts/chartitem.cpp b/src/charts/chartitem.cpp index 680710c8..8bdf68a3 100644 --- a/src/charts/chartitem.cpp +++ b/src/charts/chartitem.cpp @@ -44,19 +44,6 @@ void ChartItem::handleDomainUpdated() qWarning() << __FUNCTION__<< "Slot not implemented"; } -void ChartItem::reversePainter(QPainter *painter, const QRectF &clipRect) -{ - if (m_series->reverseXAxis()) { - painter->translate(clipRect.width(), 0); - painter->scale(-1, 1); - } - - if (m_series->reverseYAxis()) { - painter->translate(0, clipRect.height()); - painter->scale(1, -1); - } -} - #include "moc_chartitem_p.cpp" QT_CHARTS_END_NAMESPACE diff --git a/src/charts/chartitem_p.h b/src/charts/chartitem_p.h index 154d1ee3..b64a8ce6 100644 --- a/src/charts/chartitem_p.h +++ b/src/charts/chartitem_p.h @@ -47,7 +47,6 @@ public: public Q_SLOTS: virtual void handleDomainUpdated(); - void reversePainter(QPainter *painter, const QRectF &clipRect); QAbstractSeriesPrivate* seriesPrivate() const {return m_series;} protected: diff --git a/src/charts/domain/abstractdomain.cpp b/src/charts/domain/abstractdomain.cpp index 9619728b..705da029 100644 --- a/src/charts/domain/abstractdomain.cpp +++ b/src/charts/domain/abstractdomain.cpp @@ -37,7 +37,9 @@ AbstractDomain::AbstractDomain(QObject *parent) m_zoomResetMinX(0), m_zoomResetMaxX(0), m_zoomResetMinY(0), - m_zoomResetMaxY(0) + m_zoomResetMaxY(0), + m_reverseX(false), + m_reverseY(false) { } @@ -106,15 +108,6 @@ bool AbstractDomain::isEmpty() const return qFuzzyCompare(spanX(), 0) || qFuzzyCompare(spanY(), 0) || m_size.isEmpty(); } -QPointF AbstractDomain::calculateDomainPoint(const QPointF &point) const -{ - const qreal deltaX = m_size.width() / (m_maxX - m_minX); - const qreal deltaY = m_size.height() / (m_maxY - m_minY); - qreal x = point.x() / deltaX + m_minX; - qreal y = (point.y() - m_size.height()) / (-deltaY) + m_minY; - return QPointF(x, y); -} - // handlers void AbstractDomain::handleVerticalAxisRangeChanged(qreal min, qreal max) @@ -127,6 +120,18 @@ void AbstractDomain::handleHorizontalAxisRangeChanged(qreal min, qreal max) setRangeX(min, max); } +void AbstractDomain::handleReverseXChanged(bool reverse) +{ + m_reverseX = reverse; + emit updated(); +} + +void AbstractDomain::handleReverseYChanged(bool reverse) +{ + m_reverseY = reverse; + emit updated(); +} + void AbstractDomain::blockRangeSignals(bool block) { if (m_signalsBlocked!=block) { @@ -199,11 +204,17 @@ bool AbstractDomain::attachAxis(QAbstractAxis *axis) if (axis->orientation() == Qt::Vertical) { QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal))); QObject::connect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); + QObject::connect(axis, &QAbstractAxis::reverseChanged, + this, &AbstractDomain::handleReverseYChanged); + m_reverseY = axis->isReverse(); } if (axis->orientation() == Qt::Horizontal) { QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal))); QObject::connect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); + QObject::connect(axis, &QAbstractAxis::reverseChanged, + this, &AbstractDomain::handleReverseXChanged); + m_reverseX = axis->isReverse(); } return true; @@ -214,12 +225,16 @@ bool AbstractDomain::detachAxis(QAbstractAxis *axis) if (axis->orientation() == Qt::Vertical) { QObject::disconnect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal))); QObject::disconnect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); - } + QObject::disconnect(axis, &QAbstractAxis::reverseChanged, + this, &AbstractDomain::handleReverseYChanged); + } if (axis->orientation() == Qt::Horizontal) { QObject::disconnect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal))); QObject::disconnect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); - } + QObject::disconnect(axis, &QAbstractAxis::reverseChanged, + this, &AbstractDomain::handleReverseXChanged); + } return true; } @@ -261,6 +276,22 @@ void AbstractDomain::adjustLogDomainRanges(qreal &min, qreal &max) } } +// This function fixes the zoom rect based on axis reversals +QRectF AbstractDomain::fixZoomRect(const QRectF &rect) +{ + QRectF fixRect = rect; + if (m_reverseX || m_reverseY) { + QPointF center = rect.center(); + if (m_reverseX) + center.setX(m_size.width() - center.x()); + if (m_reverseY) + center.setY(m_size.height() - center.y()); + fixRect.moveCenter(QPointF(center.x(), center.y())); + } + + return fixRect; +} + #include "moc_abstractdomain_p.cpp" diff --git a/src/charts/domain/abstractdomain_p.h b/src/charts/domain/abstractdomain_p.h index abefdc54..1adbb869 100644 --- a/src/charts/domain/abstractdomain_p.h +++ b/src/charts/domain/abstractdomain_p.h @@ -103,6 +103,12 @@ public: static void looseNiceNumbers(qreal &min, qreal &max, int &ticksCount); static qreal niceNumber(qreal x, bool ceiling); + void setReverseX(bool reverse) { m_reverseX = reverse; } + void setReverseY(bool reverse) { m_reverseY = reverse; } + + bool isReverseX() const { return m_reverseX; } + bool isReverseY() const { return m_reverseY; } + Q_SIGNALS: void updated(); void rangeHorizontalChanged(qreal min, qreal max); @@ -111,9 +117,12 @@ Q_SIGNALS: public Q_SLOTS: void handleVerticalAxisRangeChanged(qreal min,qreal max); void handleHorizontalAxisRangeChanged(qreal min,qreal max); + void handleReverseXChanged(bool reverse); + void handleReverseYChanged(bool reverse); protected: void adjustLogDomainRanges(qreal &min, qreal &max); + QRectF fixZoomRect(const QRectF &rect); qreal m_minX; qreal m_maxX; @@ -126,6 +135,8 @@ protected: qreal m_zoomResetMaxX; qreal m_zoomResetMinY; qreal m_zoomResetMaxY; + bool m_reverseX; + bool m_reverseY; }; QT_CHARTS_END_NAMESPACE diff --git a/src/charts/domain/logxlogydomain.cpp b/src/charts/domain/logxlogydomain.cpp index 8bf80407..cfb213fc 100644 --- a/src/charts/domain/logxlogydomain.cpp +++ b/src/charts/domain/logxlogydomain.cpp @@ -81,15 +81,16 @@ void LogXLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void LogXLogYDomain::zoomIn(const QRectF &rect) { storeZoomReset(); - qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; - qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + QRectF fixedRect = fixZoomRect(rect); + qreal logLeftX = fixedRect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + qreal logRightX = fixedRect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal leftX = qPow(m_logBaseX, logLeftX); qreal rightX = qPow(m_logBaseX, logRightX); qreal minX = leftX < rightX ? leftX : rightX; qreal maxX = leftX > rightX ? leftX : rightX; - qreal logLeftY = m_logRightY - rect.bottom() * (m_logRightY - m_logLeftY) / m_size.height(); - qreal logRightY = m_logRightY - rect.top() * (m_logRightY - m_logLeftY) / m_size.height(); + qreal logLeftY = m_logRightY - fixedRect.bottom() * (m_logRightY - m_logLeftY) / m_size.height(); + qreal logRightY = m_logRightY - fixedRect.top() * (m_logRightY - m_logLeftY) / m_size.height(); qreal leftY = qPow(m_logBaseY, logLeftY); qreal rightY = qPow(m_logBaseY, logRightY); qreal minY = leftY < rightY ? leftY : rightY; @@ -101,8 +102,9 @@ void LogXLogYDomain::zoomIn(const QRectF &rect) void LogXLogYDomain::zoomOut(const QRectF &rect) { storeZoomReset(); - const qreal factorX = m_size.width() / rect.width(); - const qreal factorY = m_size.height() / rect.height(); + QRectF fixedRect = fixZoomRect(rect); + const qreal factorX = m_size.width() / fixedRect.width(); + const qreal factorY = m_size.height() / fixedRect.height(); qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2 * (1 - factorX); qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2 * (1 + factorX); @@ -123,6 +125,11 @@ void LogXLogYDomain::zoomOut(const QRectF &rect) void LogXLogYDomain::move(qreal dx, qreal dy) { + if (m_reverseX) + dx = -dx; + if (m_reverseY) + dy = -dy; + qreal stepX = dx * qAbs(m_logRightX - m_logLeftX) / m_size.width(); qreal leftX = qPow(m_logBaseX, m_logLeftX + stepX); qreal rightX = qPow(m_logBaseX, m_logRightX + stepX); @@ -145,23 +152,25 @@ QPointF LogXLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) c qreal x(0); qreal y(0); if (point.x() > 0 && point.y() > 0) { - x = (std::log10(point.x()) / std::log10(m_logBaseX)) * deltaX - m_logLeftX * deltaX; - y = (std::log10(point.y()) / std::log10(m_logBaseY)) * -deltaY - m_logLeftY * -deltaY + m_size.height(); + x = ((std::log10(point.x()) / std::log10(m_logBaseX)) - m_logLeftX) * deltaX; + y = ((std::log10(point.y()) / std::log10(m_logBaseY)) - m_logLeftY) * deltaY; ok = true; } else { qWarning() << "Logarithms of zero and negative values are undefined."; ok = false; if (point.x() > 0) - x = (std::log10(point.x()) / std::log10(m_logBaseX)) * deltaX - m_logLeftX * deltaX; + x = ((std::log10(point.x()) / std::log10(m_logBaseX)) - m_logLeftX) * deltaX; else x = 0; - if (point.y() > 0) { - y = (std::log10(point.y()) / std::log10(m_logBaseY)) * -deltaY - m_logLeftY * -deltaY - + m_size.height(); - } else { - y = m_size.height(); - } + if (point.y() > 0) + y = ((std::log10(point.y()) / std::log10(m_logBaseY)) - m_logLeftY) * deltaY; + else + y = 0; } + if (m_reverseX) + x = m_size.width() - x; + if (!m_reverseY) + y = m_size.height() - y; return QPointF(x, y); } @@ -175,8 +184,12 @@ QVector LogXLogYDomain::calculateGeometryPoints(const QVector for (int i = 0; i < vector.count(); ++i) { if (vector[i].x() > 0 && vector[i].y() > 0) { - qreal x = (std::log10(vector[i].x()) / std::log10(m_logBaseX)) * deltaX - m_logLeftX * deltaX; - qreal y = (std::log10(vector[i].y()) / std::log10(m_logBaseY)) * -deltaY - m_logLeftY * -deltaY + m_size.height(); + qreal x = ((std::log10(vector[i].x()) / std::log10(m_logBaseX)) - m_logLeftX) * deltaX; + if (m_reverseX) + x = m_size.width() - x; + qreal y = ((std::log10(vector[i].y()) / std::log10(m_logBaseY)) - m_logLeftY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; result[i].setX(x); result[i].setY(y); } else { @@ -191,8 +204,10 @@ QPointF LogXLogYDomain::calculateDomainPoint(const QPointF &point) const { const qreal deltaX = m_size.width() / qAbs(m_logRightX - m_logLeftX); const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY); - qreal x = qPow(m_logBaseX, m_logLeftX + point.x() / deltaX); - qreal y = qPow(m_logBaseY, m_logLeftY + (m_size.height() - point.y()) / deltaY); + qreal x = m_reverseX ? (m_size.width() - point.x()) : point.x(); + x = qPow(m_logBaseX, m_logLeftX + x / deltaX); + qreal y = m_reverseY ? point.y() : (m_size.height() - point.y()); + y = qPow(m_logBaseY, m_logLeftY + y / deltaY); return QPointF(x, y); } diff --git a/src/charts/domain/logxydomain.cpp b/src/charts/domain/logxydomain.cpp index cc33ba4a..a28dd259 100644 --- a/src/charts/domain/logxydomain.cpp +++ b/src/charts/domain/logxydomain.cpp @@ -73,8 +73,9 @@ void LogXYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void LogXYDomain::zoomIn(const QRectF &rect) { storeZoomReset(); - qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; - qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + QRectF fixedRect = fixZoomRect(rect); + qreal logLeftX = fixedRect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + qreal logRightX = fixedRect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal leftX = qPow(m_logBaseX, logLeftX); qreal rightX = qPow(m_logBaseX, logRightX); qreal minX = leftX < rightX ? leftX : rightX; @@ -84,8 +85,8 @@ void LogXYDomain::zoomIn(const QRectF &rect) qreal minY = m_minY; qreal maxY = m_maxY; - minY = maxY - dy * rect.bottom(); - maxY = maxY - dy * rect.top(); + minY = maxY - dy * fixedRect.bottom(); + maxY = maxY - dy * fixedRect.top(); setRange(minX, maxX, minY, maxY); } @@ -93,7 +94,8 @@ void LogXYDomain::zoomIn(const QRectF &rect) void LogXYDomain::zoomOut(const QRectF &rect) { storeZoomReset(); - const qreal factorX = m_size.width() / rect.width(); + QRectF fixedRect = fixZoomRect(rect); + const qreal factorX = m_size.width() / fixedRect.width(); qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2 * (1 - factorX); qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2 * (1 + factorX); @@ -102,11 +104,11 @@ void LogXYDomain::zoomOut(const QRectF &rect) qreal minX = leftX < rightX ? leftX : rightX; qreal maxX = leftX > rightX ? leftX : rightX; - qreal dy = spanY() / rect.height(); + qreal dy = spanY() / fixedRect.height(); qreal minY = m_minY; qreal maxY = m_maxY; - maxY = minY + dy * rect.bottom(); + maxY = minY + dy * fixedRect.bottom(); minY = maxY - dy * m_size.height(); setRange(minX, maxX, minY, maxY); @@ -114,6 +116,11 @@ void LogXYDomain::zoomOut(const QRectF &rect) void LogXYDomain::move(qreal dx, qreal dy) { + if (m_reverseX) + dx = -dx; + if (m_reverseY) + dy = -dy; + qreal stepX = dx * (m_logRightX - m_logLeftX) / m_size.width(); qreal leftX = qPow(m_logBaseX, m_logLeftX + stepX); qreal rightX = qPow(m_logBaseX, m_logRightX + stepX); @@ -137,9 +144,13 @@ QPointF LogXYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) cons const qreal deltaY = m_size.height() / (m_maxY - m_minY); qreal x(0); - qreal y = (point.y() - m_minY) * -deltaY + m_size.height(); + qreal y = (point.y() - m_minY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; if (point.x() > 0) { - x = (std::log10(point.x()) / std::log10(m_logBaseX)) * deltaX - m_logLeftX * deltaX; + x = ((std::log10(point.x()) / std::log10(m_logBaseX)) - m_logLeftX) * deltaX; + if (m_reverseX) + x = m_size.width() - x; ok = true; } else { x = 0; @@ -159,8 +170,12 @@ QVector LogXYDomain::calculateGeometryPoints(const QVector &ve for (int i = 0; i < vector.count(); ++i) { if (vector[i].x() > 0) { - qreal x = (std::log10(vector[i].x()) / std::log10(m_logBaseX)) * deltaX - m_logLeftX * deltaX; - qreal y = (vector[i].y() - m_minY) * -deltaY + m_size.height(); + qreal x = ((std::log10(vector[i].x()) / std::log10(m_logBaseX)) - m_logLeftX) * deltaX; + if (m_reverseX) + x = m_size.width() - x; + qreal y = (vector[i].y() - m_minY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; result[i].setX(x); result[i].setY(y); } else { @@ -176,8 +191,11 @@ QPointF LogXYDomain::calculateDomainPoint(const QPointF &point) const { const qreal deltaX = m_size.width() / (m_logRightX - m_logLeftX); const qreal deltaY = m_size.height() / (m_maxY - m_minY); - qreal x = qPow(m_logBaseX, m_logLeftX + point.x() / deltaX); - qreal y = (point.y() - m_size.height()) / (-deltaY) + m_minY; + qreal x = m_reverseX ? (m_size.width() - point.x()) : point.x(); + x = qPow(m_logBaseX, m_logLeftX + x / deltaX); + qreal y = m_reverseY ? point.y() : (m_size.height() - point.y()); + y /= deltaY; + y += m_minY; return QPointF(x, y); } diff --git a/src/charts/domain/xlogydomain.cpp b/src/charts/domain/xlogydomain.cpp index 396ce667..8a4f9af0 100644 --- a/src/charts/domain/xlogydomain.cpp +++ b/src/charts/domain/xlogydomain.cpp @@ -73,15 +73,16 @@ void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void XLogYDomain::zoomIn(const QRectF &rect) { storeZoomReset(); + QRectF fixedRect = fixZoomRect(rect); qreal dx = spanX() / m_size.width(); qreal maxX = m_maxX; qreal minX = m_minX; - maxX = minX + dx * rect.right(); - minX = minX + dx * rect.left(); + maxX = minX + dx * fixedRect.right(); + minX = minX + dx * fixedRect.left(); - qreal logLeftY = m_logRightY - rect.bottom() * (m_logRightY - m_logLeftY) / m_size.height(); - qreal logRightY = m_logRightY - rect.top() * (m_logRightY - m_logLeftY) / m_size.height(); + qreal logLeftY = m_logRightY - fixedRect.bottom() * (m_logRightY - m_logLeftY) / m_size.height(); + qreal logRightY = m_logRightY - fixedRect.top() * (m_logRightY - m_logLeftY) / m_size.height(); qreal leftY = qPow(m_logBaseY, logLeftY); qreal rightY = qPow(m_logBaseY, logRightY); qreal minY = leftY < rightY ? leftY : rightY; @@ -93,14 +94,15 @@ void XLogYDomain::zoomIn(const QRectF &rect) void XLogYDomain::zoomOut(const QRectF &rect) { storeZoomReset(); - qreal dx = spanX() / rect.width(); + QRectF fixedRect = fixZoomRect(rect); + qreal dx = spanX() / fixedRect.width(); qreal maxX = m_maxX; qreal minX = m_minX; - minX = maxX - dx * rect.right(); + minX = maxX - dx * fixedRect.right(); maxX = minX + dx * m_size.width(); - const qreal factorY = m_size.height() / rect.height(); + const qreal factorY = m_size.height() / fixedRect.height(); qreal newLogMinY = m_logLeftY + (m_logRightY - m_logLeftY) / 2 * (1 - factorY); qreal newLogMaxY = m_logLeftY + (m_logRightY - m_logLeftY) / 2 * (1 + factorY); qreal leftY = qPow(m_logBaseY, newLogMinY); @@ -113,6 +115,11 @@ void XLogYDomain::zoomOut(const QRectF &rect) void XLogYDomain::move(qreal dx, qreal dy) { + if (m_reverseX) + dx = -dx; + if (m_reverseY) + dy = -dy; + qreal x = spanX() / m_size.width(); qreal maxX = m_maxX; qreal minX = m_minX; @@ -137,9 +144,13 @@ QPointF XLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) cons const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY); qreal x = (point.x() - m_minX) * deltaX; + if (m_reverseX) + x = m_size.width() - x; qreal y(0); if (point.y() > 0) { - y = (std::log10(point.y()) / std::log10(m_logBaseY)) * -deltaY - m_logLeftY * -deltaY + m_size.height(); + y = ((std::log10(point.y()) / std::log10(m_logBaseY)) - m_logLeftY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; ok = true; } else { y = m_size.height(); @@ -160,7 +171,11 @@ QVector XLogYDomain::calculateGeometryPoints(const QVector &ve for (int i = 0; i < vector.count(); ++i) { if (vector[i].y() > 0) { qreal x = (vector[i].x() - m_minX) * deltaX; - qreal y = (std::log10(vector[i].y()) / std::log10(m_logBaseY)) * -deltaY - m_logLeftY * -deltaY + m_size.height(); + if (m_reverseX) + x = m_size.width() - x; + qreal y = ((std::log10(vector[i].y()) / std::log10(m_logBaseY)) - m_logLeftY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; result[i].setX(x); result[i].setY(y); } else { @@ -175,8 +190,11 @@ QPointF XLogYDomain::calculateDomainPoint(const QPointF &point) const { const qreal deltaX = m_size.width() / (m_maxX - m_minX); const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY); - qreal x = point.x() / deltaX + m_minX; - qreal y = qPow(m_logBaseY, m_logLeftY + (m_size.height() - point.y()) / deltaY); + qreal x = m_reverseX ? (m_size.width() - point.x()) : point.x(); + x /= deltaX; + x += m_minX; + qreal y = m_reverseY ? point.y() : (m_size.height() - point.y()); + y = qPow(m_logBaseY, m_logLeftY + y / deltaY); return QPointF(x, y); } diff --git a/src/charts/domain/xydomain.cpp b/src/charts/domain/xydomain.cpp index f9048de5..457380c3 100644 --- a/src/charts/domain/xydomain.cpp +++ b/src/charts/domain/xydomain.cpp @@ -63,6 +63,7 @@ void XYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void XYDomain::zoomIn(const QRectF &rect) { storeZoomReset(); + QRectF fixedRect = fixZoomRect(rect); qreal dx = spanX() / m_size.width(); qreal dy = spanY() / m_size.height(); @@ -71,10 +72,10 @@ void XYDomain::zoomIn(const QRectF &rect) qreal minY = m_minY; qreal maxY = m_maxY; - maxX = minX + dx * rect.right(); - minX = minX + dx * rect.left(); - minY = maxY - dy * rect.bottom(); - maxY = maxY - dy * rect.top(); + maxX = minX + dx * fixedRect.right(); + minX = minX + dx * fixedRect.left(); + minY = maxY - dy * fixedRect.bottom(); + maxY = maxY - dy * fixedRect.top(); if ((maxX - minX) == spanX()) { minX = m_minX; @@ -91,6 +92,7 @@ void XYDomain::zoomIn(const QRectF &rect) void XYDomain::zoomOut(const QRectF &rect) { storeZoomReset(); + QRectF fixedRect = fixZoomRect(rect); qreal dx = spanX() / rect.width(); qreal dy = spanY() / rect.height(); @@ -99,9 +101,9 @@ void XYDomain::zoomOut(const QRectF &rect) qreal minY = m_minY; qreal maxY = m_maxY; - minX = maxX - dx * rect.right(); + minX = maxX - dx * fixedRect.right(); maxX = minX + dx * m_size.width(); - maxY = minY + dy * rect.bottom(); + maxY = minY + dy * fixedRect.bottom(); minY = maxY - dy * m_size.height(); if ((maxX - minX) == spanX()) { @@ -118,6 +120,11 @@ void XYDomain::zoomOut(const QRectF &rect) void XYDomain::move(qreal dx, qreal dy) { + if (m_reverseX) + dx = -dx; + if (m_reverseY) + dy = -dy; + qreal x = spanX() / m_size.width(); qreal y = spanY() / m_size.height(); @@ -142,7 +149,11 @@ QPointF XYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) const const qreal deltaX = m_size.width() / (m_maxX - m_minX); const qreal deltaY = m_size.height() / (m_maxY - m_minY); qreal x = (point.x() - m_minX) * deltaX; - qreal y = (point.y() - m_minY) * -deltaY + m_size.height(); + if (m_reverseX) + x = m_size.width() - x; + qreal y = (point.y() - m_minY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; ok = true; return QPointF(x, y); } @@ -157,7 +168,11 @@ QVector XYDomain::calculateGeometryPoints(const QVector &vecto for (int i = 0; i < vector.count(); ++i) { qreal x = (vector[i].x() - m_minX) * deltaX; - qreal y = (vector[i].y() - m_minY) * -deltaY + m_size.height(); + if (m_reverseX) + x = m_size.width() - x; + qreal y = (vector[i].y() - m_minY) * deltaY; + if (!m_reverseY) + y = m_size.height() - y; result[i].setX(x); result[i].setY(y); } @@ -168,8 +183,12 @@ QPointF XYDomain::calculateDomainPoint(const QPointF &point) const { const qreal deltaX = m_size.width() / (m_maxX - m_minX); const qreal deltaY = m_size.height() / (m_maxY - m_minY); - qreal x = point.x() / deltaX + m_minX; - qreal y = (point.y() - m_size.height()) / (-deltaY) + m_minY; + qreal x = m_reverseX ? (m_size.width() - point.x()) : point.x(); + x /= deltaX; + x += m_minX; + qreal y = m_reverseY ? point.y() : (m_size.height() - point.y()); + y /= deltaY; + y += m_minY; return QPointF(x, y); } diff --git a/src/charts/linechart/linechartitem.cpp b/src/charts/linechart/linechartitem.cpp index 826428b8..730e3bf5 100644 --- a/src/charts/linechart/linechartitem.cpp +++ b/src/charts/linechart/linechartitem.cpp @@ -387,8 +387,6 @@ void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt painter->setClipRect(clipRect); } - reversePainter(painter, clipRect); - if (m_pointsVisible) { painter->setBrush(m_linePen.color()); painter->drawPath(m_linePath); @@ -404,8 +402,6 @@ void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt } } - reversePainter(painter, clipRect); - if (m_pointLabelsVisible) { if (m_pointLabelsClipping) painter->setClipping(true); diff --git a/src/charts/qabstractseries.cpp b/src/charts/qabstractseries.cpp index f9326394..f129d67f 100644 --- a/src/charts/qabstractseries.cpp +++ b/src/charts/qabstractseries.cpp @@ -449,40 +449,6 @@ void QAbstractSeriesPrivate::initializeAnimations(QChart::AnimationOptions optio Q_UNUSED(curve); } -bool QAbstractSeriesPrivate::reverseXAxis() -{ - bool reverseXAxis = false; - if (m_axes.size() != 0 && !(m_chart->chartType() == QChart::ChartTypePolar)) { - int i = 0; - while (i < m_axes.size()) { - if (m_axes.at(i)->orientation() == Qt::Horizontal && m_axes.at(i)->isReverse()) { - reverseXAxis = true; - break; - } - i++; - } - } - - return reverseXAxis; -} - -bool QAbstractSeriesPrivate::reverseYAxis() -{ - bool reverseYAxis = false; - if (m_axes.size() != 0 && !(m_chart->chartType() == QChart::ChartTypePolar)) { - int i = 0; - while (i < m_axes.size()) { - if (m_axes.at(i)->orientation() == Qt::Vertical && m_axes.at(i)->isReverse()) { - reverseYAxis = true; - break; - } - i++; - } - } - - return reverseYAxis; -} - // This function can be used to explicitly block OpenGL use from some otherwise supported series, // such as the line series used as edge series of an area series. void QAbstractSeriesPrivate::setBlockOpenGL(bool enable) diff --git a/src/charts/qabstractseries_p.h b/src/charts/qabstractseries_p.h index 01421a37..cec152aa 100644 --- a/src/charts/qabstractseries_p.h +++ b/src/charts/qabstractseries_p.h @@ -81,8 +81,6 @@ public: ChartPresenter *presenter() const; QChart* chart() { return m_chart; } - bool reverseXAxis(); - bool reverseYAxis(); void setBlockOpenGL(bool enable); diff --git a/src/charts/scatterchart/scatterchartitem.cpp b/src/charts/scatterchart/scatterchartitem.cpp index ef73ab9e..658f0b7e 100644 --- a/src/charts/scatterchart/scatterchartitem.cpp +++ b/src/charts/scatterchart/scatterchartitem.cpp @@ -186,17 +186,10 @@ void ScatterChartItem::updateGeometry() // fake anyway. After remove animation stops, geometry is updated to correct one. m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i)); QPointF position; - if (seriesPrivate()->reverseXAxis()) - position.setX(domain()->size().width() - point.x() - rect.width() / 2); - else - position.setX(point.x() - rect.width() / 2); - if (seriesPrivate()->reverseYAxis()) - position.setY(domain()->size().height() - point.y() - rect.height() / 2); - else - position.setY(point.y() - rect.height() / 2); + position.setX(point.x() - rect.width() / 2); + position.setY(point.y() - rect.height() / 2); item->setPos(position); - if (!m_visible || offGridStatus.at(i)) item->setVisible(false); else diff --git a/src/charts/splinechart/splinechartitem.cpp b/src/charts/splinechart/splinechartitem.cpp index ed6aec2c..001c1cb0 100644 --- a/src/charts/splinechart/splinechartitem.cpp +++ b/src/charts/splinechart/splinechartitem.cpp @@ -452,8 +452,6 @@ void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o painter->setClipRect(clipRect); } - reversePainter(painter, clipRect); - painter->drawPath(m_path); if (m_pointsVisible) { @@ -464,8 +462,6 @@ void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o painter->drawPoints(geometryPoints()); } - reversePainter(painter, clipRect); - if (m_pointLabelsVisible) { if (m_pointLabelsClipping) painter->setClipping(true); diff --git a/src/charts/xychart/qxyseries.cpp b/src/charts/xychart/qxyseries.cpp index e2159eeb..27d4be80 100644 --- a/src/charts/xychart/qxyseries.cpp +++ b/src/charts/xychart/qxyseries.cpp @@ -964,14 +964,8 @@ void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVectorsize().width() - position.x() - pointLabelWidth / 2); - if (!reverseYAxis()) - position.setY(position.y() - labelOffset); - else - position.setY(domain()->size().height() - position.y() - labelOffset); + position.setX(position.x() - pointLabelWidth / 2); + position.setY(position.y() - labelOffset); painter->drawText(position, pointLabel); } From 0c490d911ce81734d3b149a6937989c371399cc7 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 12 Aug 2016 12:07:31 +0300 Subject: [PATCH 3/9] Don't print warning at model mapper initialization if model is empty The warnings are relevant only if model has values. It is expected that initializing data from an empty model will not result in any values. Change-Id: Id696f8ccaf5efa0c577e6832a52c6f8e7b0c6cd8 Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- src/charts/xychart/qxymodelmapper.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/charts/xychart/qxymodelmapper.cpp b/src/charts/xychart/qxymodelmapper.cpp index f51703b0..2c9507aa 100644 --- a/src/charts/xychart/qxymodelmapper.cpp +++ b/src/charts/xychart/qxymodelmapper.cpp @@ -551,11 +551,15 @@ void QXYModelMapperPrivate::initializeXYFromModel() // determine when we should end looping. } } else { - // Invalid index right off the bat means series will be left empty, so output a warning - if (!xIndex.isValid()) - qWarning() << __FUNCTION__ << QStringLiteral("Invalid X coordinate index in model mapper."); - else if (!yIndex.isValid()) - qWarning() << __FUNCTION__ << QStringLiteral("Invalid Y coordinate index in model mapper."); + // Invalid index right off the bat means series will be left empty, so output a warning, + // unless model is also empty + int count = m_orientation == Qt::Vertical ? m_model->rowCount() : m_model->columnCount(); + if (count > 0) { + if (!xIndex.isValid()) + qWarning() << __FUNCTION__ << QStringLiteral("Invalid X coordinate index in model mapper."); + else if (!yIndex.isValid()) + qWarning() << __FUNCTION__ << QStringLiteral("Invalid Y coordinate index in model mapper."); + } } blockSeriesSignals(false); From 5820e450ad79f71f1ff0e12ec9cf06371288ea44 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 12 Aug 2016 13:22:17 +0300 Subject: [PATCH 4/9] Disconnect boxplot series from chart's dataset correctly When a boxplot series is removed from the chart, it must disconnect from chart's dataset. However, it only did it when animations were enabled. Task-number: QTBUG-55278 Change-Id: Iad89a586d16dc32299ae71aa63b3beccb4d51fdd Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- src/charts/boxplotchart/qboxplotseries.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/charts/boxplotchart/qboxplotseries.cpp b/src/charts/boxplotchart/qboxplotseries.cpp index b9d128dc..0d79707b 100644 --- a/src/charts/boxplotchart/qboxplotseries.cpp +++ b/src/charts/boxplotchart/qboxplotseries.cpp @@ -527,9 +527,10 @@ void QBoxPlotSeriesPrivate::handleSeriesRemove(QAbstractSeries *series) QBoxPlotSeries *removedSeries = static_cast(series); - if (q == removedSeries && m_animation) { - m_animation->stopAll(); - QObject::disconnect(m_chart->d_ptr->m_dataset, 0, removedSeries->d_func(), 0); + if (q == removedSeries) { + if (m_animation) + m_animation->stopAll(); + QObject::disconnect(m_chart->d_ptr->m_dataset, 0, this, 0); } // Test if series removed is me, then don't do anything From 1dbd61a9ea85094f318244cc8ba3d130db693eea Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 12 Aug 2016 15:46:54 +0300 Subject: [PATCH 5/9] Fix setting axis color properties to black for the first time The color properties didn't correctly check if the default pen/brush was in use and force the color setting in that case. Task-number: QTBUG-53337 Change-Id: Iaafcf105973f601be74e60d6d669f5fd16fa347f Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- src/charts/axis/qabstractaxis.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/charts/axis/qabstractaxis.cpp b/src/charts/axis/qabstractaxis.cpp index b4805588..bba70e76 100644 --- a/src/charts/axis/qabstractaxis.cpp +++ b/src/charts/axis/qabstractaxis.cpp @@ -515,7 +515,7 @@ QPen QAbstractAxis::linePen() const void QAbstractAxis::setLinePenColor(QColor color) { QPen p = linePen(); - if (p.color() != color) { + if (p.color() != color || d_ptr->m_axisPen == QChartPrivate::defaultPen()) { p.setColor(color); setLinePen(p); emit colorChanged(color); @@ -610,31 +610,31 @@ QPen QAbstractAxis::minorGridLinePen() const void QAbstractAxis::setGridLineColor(const QColor &color) { QPen pen = gridLinePen(); - if (color != pen.color()) { + if (color != pen.color() || d_ptr->m_gridLinePen == QChartPrivate::defaultPen()) { pen.setColor(color); - d_ptr->m_gridLinePen = pen; + setGridLinePen(pen); emit gridLineColorChanged(color); } } QColor QAbstractAxis::gridLineColor() { - return d_ptr->m_gridLinePen.color(); + return gridLinePen().color(); } void QAbstractAxis::setMinorGridLineColor(const QColor &color) { QPen pen = minorGridLinePen(); - if (color != pen.color()) { + if (color != pen.color() || d_ptr->m_minorGridLinePen == QChartPrivate::defaultPen()) { pen.setColor(color); - d_ptr->m_minorGridLinePen = pen; + setMinorGridLinePen(pen); emit minorGridLineColorChanged(color); } } QColor QAbstractAxis::minorGridLineColor() { - return d_ptr->m_minorGridLinePen.color(); + return minorGridLinePen().color(); } void QAbstractAxis::setLabelsVisible(bool visible) @@ -709,7 +709,7 @@ int QAbstractAxis::labelsAngle() const void QAbstractAxis::setLabelsColor(QColor color) { QBrush b = labelsBrush(); - if (b.color() != color) { + if (b.color() != color || d_ptr->m_labelsBrush == QChartPrivate::defaultBrush()) { b.setColor(color); setLabelsBrush(b); emit labelsColorChanged(color); @@ -852,7 +852,7 @@ QBrush QAbstractAxis::shadesBrush() const void QAbstractAxis::setShadesColor(QColor color) { QBrush b = shadesBrush(); - if (b.color() != color) { + if (b.color() != color || d_ptr->m_shadesBrush == QChartPrivate::defaultBrush()) { b.setColor(color); setShadesBrush(b); emit shadesColorChanged(color); @@ -866,8 +866,8 @@ QColor QAbstractAxis::shadesColor() const void QAbstractAxis::setShadesBorderColor(QColor color) { - QPen p = d_ptr->m_shadesPen; - if (p.color() != color) { + QPen p = shadesPen(); + if (p.color() != color || d_ptr->m_shadesPen == QChartPrivate::defaultPen()) { p.setColor(color); setShadesPen(p); emit shadesColorChanged(color); From cccd1b688333dcc5616e1fa48050c60a1a534421 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 15 Aug 2016 14:24:04 +0300 Subject: [PATCH 6/9] Fix logarithmic axis for area chart If the domain type of an area series differs from the domain type of an edge series of that area series, recreate the edge series domain so that the two domain types match. Task-number: QTRD-1967 Change-Id: Ifb6bbc449816729721cce43c7e0c8d2877bb0eaf Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- src/charts/areachart/areachartitem.cpp | 35 +++++++++++++++----------- src/charts/areachart/areachartitem_p.h | 2 ++ src/charts/chartdataset_p.h | 3 ++- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/charts/areachart/areachartitem.cpp b/src/charts/areachart/areachartitem.cpp index b13cdc19..c8fb40e3 100644 --- a/src/charts/areachart/areachartitem.cpp +++ b/src/charts/areachart/areachartitem.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -163,22 +164,26 @@ void AreaChartItem::handleUpdated() void AreaChartItem::handleDomainUpdated() { - if (m_upper) { - AbstractDomain* d = m_upper->domain(); - d->setSize(domain()->size()); - d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY()); - d->setReverseX(domain()->isReverseX()); - d->setReverseY(domain()->isReverseY()); - m_upper->handleDomainUpdated(); - } + fixEdgeSeriesDomain(m_upper); + fixEdgeSeriesDomain(m_lower); +} - if (m_lower) { - AbstractDomain* d = m_lower->domain(); - d->setSize(domain()->size()); - d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY()); - d->setReverseX(domain()->isReverseX()); - d->setReverseY(domain()->isReverseY()); - m_lower->handleDomainUpdated(); +void AreaChartItem::fixEdgeSeriesDomain(LineChartItem *edgeSeries) +{ + if (edgeSeries) { + AbstractDomain* mainDomain = domain(); + AbstractDomain* edgeDomain = edgeSeries->domain(); + + if (edgeDomain->type() != mainDomain->type()) { + // Change the domain of edge series to the same type as the area series + edgeDomain = dataSet()->createDomain(mainDomain->type()); + edgeSeries->seriesPrivate()->setDomain(edgeDomain); + } + edgeDomain->setSize(mainDomain->size()); + edgeDomain->setRange(mainDomain->minX(), mainDomain->maxX(), mainDomain->minY(), mainDomain->maxY()); + edgeDomain->setReverseX(mainDomain->isReverseX()); + edgeDomain->setReverseY(mainDomain->isReverseY()); + edgeSeries->handleDomainUpdated(); } } diff --git a/src/charts/areachart/areachartitem_p.h b/src/charts/areachart/areachartitem_p.h index e59d58e0..033a4977 100644 --- a/src/charts/areachart/areachartitem_p.h +++ b/src/charts/areachart/areachartitem_p.h @@ -79,6 +79,8 @@ public Q_SLOTS: void handleDomainUpdated(); private: + void fixEdgeSeriesDomain(LineChartItem *edgeSeries); + QAreaSeries *m_series; LineChartItem *m_upper; LineChartItem *m_lower; diff --git a/src/charts/chartdataset_p.h b/src/charts/chartdataset_p.h index b5c6806c..6c7dcdcc 100644 --- a/src/charts/chartdataset_p.h +++ b/src/charts/chartdataset_p.h @@ -73,6 +73,8 @@ public: GLXYSeriesDataManager *glXYSeriesDataManager() { return m_glXYSeriesDataManager; } + AbstractDomain* createDomain(AbstractDomain::DomainType type); + Q_SIGNALS: void axisAdded(QAbstractAxis* axis); void axisRemoved(QAbstractAxis* axis); @@ -83,7 +85,6 @@ private: void createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation); QAbstractAxis *createAxis(QAbstractAxis::AxisType type, Qt::Orientation orientation); AbstractDomain::DomainType selectDomain(QList axes); - AbstractDomain* createDomain(AbstractDomain::DomainType type); void deleteAllAxes(); void deleteAllSeries(); void findMinMaxForSeries(QList series,Qt::Orientations orientation, qreal &min, qreal &max); From c6d72bb6ebd860a38aac2e557bca330b0d5b1926 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 15 Aug 2016 16:30:28 +0300 Subject: [PATCH 7/9] Fix resize handling in Callout example Callouts are now positioned correctly when the chart is resized. Task-number: QTBUG-54492 Change-Id: I5660eb48e58348cc2d649b48965c342488294ae4 Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- examples/charts/callout/callout.cpp | 18 +++++++++++++----- examples/charts/callout/callout.h | 11 ++++++++++- examples/charts/callout/view.cpp | 8 +++++--- examples/charts/callout/view.h | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/examples/charts/callout/callout.cpp b/examples/charts/callout/callout.cpp index f20d0609..9699df61 100644 --- a/examples/charts/callout/callout.cpp +++ b/examples/charts/callout/callout.cpp @@ -24,15 +24,17 @@ #include #include #include +#include -Callout::Callout(QGraphicsItem * parent): - QGraphicsItem(parent) +Callout::Callout(QChart *chart): + QGraphicsItem(chart), + m_chart(chart) { } QRectF Callout::boundingRect() const { - QPointF anchor = mapFromParent(m_anchor); + QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor)); QRectF rect; rect.setLeft(qMin(m_rect.left(), anchor.x())); rect.setRight(qMax(m_rect.right(), anchor.x())); @@ -48,7 +50,7 @@ void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q QPainterPath path; path.addRoundedRect(m_rect, 5, 5); - QPointF anchor = mapFromParent(m_anchor); + QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor)); if (!m_rect.contains(anchor)) { QPointF point1, point2; @@ -80,7 +82,7 @@ void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q point2.setY(y2); path.moveTo(point1); - path.lineTo(mapFromParent(m_anchor)); + path.lineTo(anchor); path.lineTo(point2); path = path.simplified(); } @@ -118,3 +120,9 @@ void Callout::setAnchor(QPointF point) { m_anchor = point; } + +void Callout::updateGeometry() +{ + prepareGeometryChange(); + setPos(m_chart->mapToPosition(m_anchor) + QPoint(10, -50)); +} diff --git a/examples/charts/callout/callout.h b/examples/charts/callout/callout.h index 149c95e5..11d6ae59 100644 --- a/examples/charts/callout/callout.h +++ b/examples/charts/callout/callout.h @@ -22,6 +22,7 @@ #ifndef CALLOUT_H #define CALLOUT_H +#include #include #include @@ -29,13 +30,20 @@ QT_BEGIN_NAMESPACE class QGraphicsSceneMouseEvent; QT_END_NAMESPACE +QT_CHARTS_BEGIN_NAMESPACE +class QChart; +QT_CHARTS_END_NAMESPACE + +QT_CHARTS_USE_NAMESPACE + class Callout : public QGraphicsItem { public: - Callout(QGraphicsItem * parent = 0); + Callout(QChart *parent); void setText(const QString &text); void setAnchor(QPointF point); + void updateGeometry(); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); @@ -50,6 +58,7 @@ private: QRectF m_rect; QPointF m_anchor; QFont m_font; + QChart *m_chart; }; #endif // CALLOUT_H diff --git a/examples/charts/callout/view.cpp b/examples/charts/callout/view.cpp index b413989e..4d1adb11 100644 --- a/examples/charts/callout/view.cpp +++ b/examples/charts/callout/view.cpp @@ -90,6 +90,8 @@ void View::resizeEvent(QResizeEvent *event) m_chart->resize(event->size()); m_coordX->setPos(m_chart->size().width()/2 - 50, m_chart->size().height() - 20); m_coordY->setPos(m_chart->size().width()/2 + 50, m_chart->size().height() - 20); + foreach (Callout *callout, m_callouts) + callout->updateGeometry(); } QGraphicsView::resizeEvent(event); } @@ -103,6 +105,7 @@ void View::mouseMoveEvent(QMouseEvent *event) void View::keepCallout() { + m_callouts.append(m_tooltip); m_tooltip = new Callout(m_chart); } @@ -113,10 +116,9 @@ void View::tooltip(QPointF point, bool state) if (state) { m_tooltip->setText(QString("X: %1 \nY: %2 ").arg(point.x()).arg(point.y())); - QXYSeries *series = qobject_cast(sender()); - m_tooltip->setAnchor(m_chart->mapToPosition(point, series)); - m_tooltip->setPos(m_chart->mapToPosition(point, series) + QPoint(10, -50)); + m_tooltip->setAnchor(point); m_tooltip->setZValue(11); + m_tooltip->updateGeometry(); m_tooltip->show(); } else { m_tooltip->hide(); diff --git a/examples/charts/callout/view.h b/examples/charts/callout/view.h index e72df120..b7085b21 100644 --- a/examples/charts/callout/view.h +++ b/examples/charts/callout/view.h @@ -58,6 +58,7 @@ private: QGraphicsSimpleTextItem *m_coordY; QChart *m_chart; Callout *m_tooltip; + QList m_callouts; }; #endif From 2a1e8cf5133be5e15dc935a07f667302d3eff302 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 17 Aug 2016 15:27:59 +0300 Subject: [PATCH 8/9] Disconnect a series from ChartItem when it is removed from a chart If series is not disconnected, modifying points of removed series can crash the application, as the ChartItem is deleted using deleteLater(). Task-number: QTBUG-55348 Change-Id: I5159c5399486f7fb6e4e62578903923aa0108bb9 Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- src/charts/chartpresenter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/charts/chartpresenter.cpp b/src/charts/chartpresenter.cpp index 9273a136..96fcefee 100644 --- a/src/charts/chartpresenter.cpp +++ b/src/charts/chartpresenter.cpp @@ -139,6 +139,7 @@ void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series) ChartItem *chart = series->d_ptr->m_item.take(); chart->hide(); chart->disconnect(); + series->disconnect(chart); chart->deleteLater(); if (chart->animation()) chart->animation()->stopAndDestroyLater(); From 7a0be48ac39243d139cc4a78423ca033d5d90b3a Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 19 Aug 2016 13:40:24 +0300 Subject: [PATCH 9/9] Bump version to 2.1.2 Change-Id: I1910d0ac29c1740d1d6d340749999e21916db9c7 Reviewed-by: Mika Salmela Reviewed-by: Miikka Heikkinen --- .qmake.conf | 2 +- README | 2 +- dist/changes-2.1.2 | 25 +++++++++++++++++++++++++ src/charts/qchartglobal.h | 4 ++-- 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 dist/changes-2.1.2 diff --git a/.qmake.conf b/.qmake.conf index 5884e73c..de5242f0 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,3 +1,3 @@ load(qt_build_config) -MODULE_VERSION=2.1.1 +MODULE_VERSION=2.1.2 diff --git a/README b/README index 59fb1467..f9997e6f 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ --------------- -Qt Charts 2.1.1 +Qt Charts 2.1.2 --------------- Qt Charts module provides a set of easy to use chart components. It uses diff --git a/dist/changes-2.1.2 b/dist/changes-2.1.2 new file mode 100644 index 00000000..e73605e6 --- /dev/null +++ b/dist/changes-2.1.2 @@ -0,0 +1,25 @@ +Qt Charts 2.1.2 + +Fixed issues +------------ +- [QTBUG-54914] Make OpenGL accelerated series obey series visibility +- [QTBUG-54803] Ensure the chart is drawn whenever the render node is recreated +- [QTBUG-55098] Fix partial blurriness of the gl accelerated graph +- [QTBUG-54763] Clarify QML BarSet::values documentation +- [QTBUG-53073] Fix VXYModelMapper documentation +- [QTBUG-52654] Print console warning when invalid row/column used in model mapper +- [QTBUG-52086] Fix BarSet value rounding +- [QTBUG-53949] Fix axis minimum height in case of multiple axes on same orientation +- [QTBUG-54401] Fix issues with reverse axes + - QChart mapping functions returned unreversed values + - Bounding regions of series were incorrect + - Mouse events gave wrong positions + - Chart scrolling and zooming didn't account for reversed axes +- [QTBUG-55278] Disconnect boxplot series from chart's dataset correctly +- [QTBUG-53337] Fix setting axis color properties to black for the first time +- [QTBUG-55348] Disconnect a series from ChartItem when it is removed from a chart +- Fix logarithmic axis for area chart + +Fixed examples +-------------- +- [QTBUG-54492] Fix resize handling in Callout example diff --git a/src/charts/qchartglobal.h b/src/charts/qchartglobal.h index 76d3cf27..59e476df 100644 --- a/src/charts/qchartglobal.h +++ b/src/charts/qchartglobal.h @@ -24,11 +24,11 @@ #include -#define QT_CHARTS_VERSION_STR "2.1.1" +#define QT_CHARTS_VERSION_STR "2.1.2" /* QT_CHARTS_VERSION is (major << 16) + (minor << 8) + patch. */ -#define QT_CHARTS_VERSION 0x020101 +#define QT_CHARTS_VERSION 0x020102 /* can be used like #if (QT_CHARTS_VERSION >= QT_CHARTS_VERSION_CHECK(1, 1, 0)) */