summaryrefslogtreecommitdiffstats
path: root/src/charts
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-09-21 08:33:05 +0200
committerLiang Qi <liang.qi@qt.io>2016-09-21 08:33:05 +0200
commit06c412094b60517af015637322798da6224e34c2 (patch)
tree0f8e68383c9fc08f07e80ca3e24e5a4531e65365 /src/charts
parent105d75533d31ceee0c39ef9e084294ed49ecbd89 (diff)
parent6e224c11080feef2c6d7857d061a92e320e50899 (diff)
Merge remote-tracking branch 'origin/5.8' into dev
Diffstat (limited to 'src/charts')
-rw-r--r--src/charts/areachart/areachartitem.cpp157
-rw-r--r--src/charts/areachart/areachartitem_p.h5
-rw-r--r--src/charts/areachart/qareaseries.cpp16
-rw-r--r--src/charts/axis/chartaxiselement.cpp11
-rw-r--r--src/charts/axis/qabstractaxis.cpp22
-rw-r--r--src/charts/barchart/qbarset.cpp17
-rw-r--r--src/charts/boxplotchart/qboxplotseries.cpp7
-rw-r--r--src/charts/chartdataset_p.h3
-rw-r--r--src/charts/chartitem.cpp13
-rw-r--r--src/charts/chartitem_p.h1
-rw-r--r--src/charts/chartpresenter.cpp1
-rw-r--r--src/charts/domain/abstractdomain.cpp55
-rw-r--r--src/charts/domain/abstractdomain_p.h11
-rw-r--r--src/charts/domain/logxlogydomain.cpp53
-rw-r--r--src/charts/domain/logxydomain.cpp44
-rw-r--r--src/charts/domain/xlogydomain.cpp40
-rw-r--r--src/charts/domain/xydomain.cpp39
-rw-r--r--src/charts/glwidget.cpp68
-rw-r--r--src/charts/layout/cartesianchartlayout.cpp4
-rw-r--r--src/charts/linechart/linechartitem.cpp7
-rw-r--r--src/charts/qabstractseries.cpp34
-rw-r--r--src/charts/qabstractseries_p.h2
-rw-r--r--src/charts/scatterchart/scatterchartitem.cpp21
-rw-r--r--src/charts/splinechart/splinechartitem.cpp4
-rw-r--r--src/charts/xychart/glxyseriesdata.cpp15
-rw-r--r--src/charts/xychart/glxyseriesdata_p.h3
-rw-r--r--src/charts/xychart/qvxymodelmapper.cpp2
-rw-r--r--src/charts/xychart/qxymodelmapper.cpp33
-rw-r--r--src/charts/xychart/qxyseries.cpp10
-rw-r--r--src/charts/xychart/xychart.cpp6
-rw-r--r--src/charts/xychart/xychart_p.h1
31 files changed, 427 insertions, 278 deletions
diff --git a/src/charts/areachart/areachartitem.cpp b/src/charts/areachart/areachartitem.cpp
index d05aa3a3..df3cc8af 100644
--- a/src/charts/areachart/areachartitem.cpp
+++ b/src/charts/areachart/areachartitem.cpp
@@ -33,6 +33,7 @@
#include <QtCharts/QLineSeries>
#include <private/chartpresenter_p.h>
#include <private/abstractdomain_p.h>
+#include <private/chartdataset_p.h>
#include <QtGui/QPainter>
#include <QtWidgets/QGraphicsSceneMouseEvent>
#include <QtCore/QDebug>
@@ -94,10 +95,39 @@ void AreaChartItem::setPresenter(ChartPresenter *presenter)
{
if (m_upper)
m_upper->setPresenter(presenter);
- if (m_lower) {
+ if (m_lower)
m_lower->setPresenter(presenter);
+ ChartItem::setPresenter(presenter);
+}
+
+void AreaChartItem::setUpperSeries(QLineSeries *series)
+{
+ delete m_upper;
+ if (series)
+ m_upper = new AreaBoundItem(this, series);
+ else
+ m_upper = 0;
+ if (m_upper) {
+ m_upper->setPresenter(presenter());
+ fixEdgeSeriesDomain(m_upper);
+ } else {
+ updatePath();
+ }
+}
+
+void AreaChartItem::setLowerSeries(QLineSeries *series)
+{
+ delete m_lower;
+ if (series)
+ m_lower = new AreaBoundItem(this, series);
+ else
+ m_lower = 0;
+ if (m_lower) {
+ m_lower->setPresenter(presenter());
+ fixEdgeSeriesDomain(m_lower);
+ } else {
+ updatePath();
}
- ChartItem::setPresenter(presenter);
}
QRectF AreaChartItem::boundingRect() const
@@ -115,31 +145,34 @@ void AreaChartItem::updatePath()
QPainterPath path;
QRectF rect(QPointF(0,0),domain()->size());
- path = m_upper->path();
-
- if (m_lower) {
- // Note: Polarcharts always draw area correctly only when both series have equal width or are
- // fully displayed. If one series is partally off-chart, the connecting line between
- // the series does not attach to the end of the partially hidden series but to the point
- // where it intersects the axis line. The problem is especially noticeable when one of the series
- // is entirely off-chart, in which case the connecting line connects two ends of the
- // visible series.
- // This happens because we get the paths from linechart, which omits off-chart segments.
- // To properly fix, linechart would need to provide true full path, in right, left, and the rest
- // portions to enable proper clipping. However, combining those to single visually unified area
- // would be a nightmare, since they would have to be painted separately.
- path.connectPath(m_lower->path().toReversed());
- } else {
- QPointF first = path.pointAtPercent(0);
- QPointF last = path.pointAtPercent(1);
- if (presenter()->chartType() == QChart::ChartTypeCartesian) {
- path.lineTo(last.x(), rect.bottom());
- path.lineTo(first.x(), rect.bottom());
- } else { // polar
- path.lineTo(rect.center());
+ if (m_upper) {
+ path = m_upper->path();
+
+ if (m_lower) {
+ // Note: Polarcharts draw area correctly only when both series have equal width or are
+ // fully displayed. If one series is partally off-chart, the connecting line between
+ // the series does not attach to the end of the partially hidden series but to the point
+ // where it intersects the axis line. The problem is especially noticeable when one of
+ // the series is entirely off-chart, in which case the connecting line connects two
+ // ends of the visible series.
+ // This happens because we get the paths from linechart, which omits off-chart segments.
+ // To properly fix, linechart would need to provide true full path, in right, left,
+ // and the rest portions to enable proper clipping. However, combining those to single
+ // visually unified area would be a nightmare, since they would have to be painted
+ // separately.
+ path.connectPath(m_lower->path().toReversed());
+ } else {
+ QPointF first = path.pointAtPercent(0);
+ QPointF last = path.pointAtPercent(1);
+ if (presenter()->chartType() == QChart::ChartTypeCartesian) {
+ path.lineTo(last.x(), rect.bottom());
+ path.lineTo(first.x(), rect.bottom());
+ } else { // polar
+ path.lineTo(rect.center());
+ }
}
+ path.closeSubpath();
}
- path.closeSubpath();
// Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses
// a region that has to be compatible with QRect.
@@ -171,18 +204,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());
- 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());
- 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();
}
}
@@ -190,6 +231,7 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
{
Q_UNUSED(widget)
Q_UNUSED(option)
+
painter->save();
painter->setPen(m_linePen);
painter->setBrush(m_brush);
@@ -199,18 +241,15 @@ 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);
- painter->drawPoints(m_upper->geometryPoints());
+ if (m_upper)
+ painter->drawPoints(m_upper->geometryPoints());
if (m_lower)
painter->drawPoints(m_lower->geometryPoints());
}
- reversePainter(painter, clipRect);
-
// Draw series point label
if (m_pointLabelsVisible) {
static const QString xPointTag(QLatin1String("@xPoint"));
@@ -239,17 +278,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);
}
}
@@ -265,17 +296,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);
}
}
@@ -286,7 +309,7 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
void AreaChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
- emit pressed(m_upper->domain()->calculateDomainPoint(event->pos()));
+ emit pressed(domain()->calculateDomainPoint(event->pos()));
m_lastMousePos = event->pos();
m_mousePressed = true;
ChartItem::mousePressEvent(event);
@@ -308,16 +331,16 @@ void AreaChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
void AreaChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
- emit released(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
+ emit released(domain()->calculateDomainPoint(m_lastMousePos));
if (m_mousePressed)
- emit clicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
+ emit clicked(domain()->calculateDomainPoint(m_lastMousePos));
m_mousePressed = false;
ChartItem::mouseReleaseEvent(event);
}
void AreaChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
- emit doubleClicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
+ emit doubleClicked(domain()->calculateDomainPoint(m_lastMousePos));
ChartItem::mouseDoubleClickEvent(event);
}
diff --git a/src/charts/areachart/areachartitem_p.h b/src/charts/areachart/areachartitem_p.h
index fafd8588..be943877 100644
--- a/src/charts/areachart/areachartitem_p.h
+++ b/src/charts/areachart/areachartitem_p.h
@@ -68,6 +68,9 @@ public:
void setPresenter(ChartPresenter *presenter);
QAreaSeries *series() const { return m_series; }
+ void setUpperSeries(QLineSeries *series);
+ void setLowerSeries(QLineSeries *series);
+
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
@@ -87,6 +90,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/areachart/qareaseries.cpp b/src/charts/areachart/qareaseries.cpp
index ebff7f0f..739efd71 100644
--- a/src/charts/areachart/qareaseries.cpp
+++ b/src/charts/areachart/qareaseries.cpp
@@ -406,13 +406,18 @@ QAbstractSeries::SeriesType QAreaSeries::type() const
/*!
Sets the \a series that is to be used as the area chart upper series.
+ If the upper series is null, the area chart is not drawn, even if it has a lower series.
*/
void QAreaSeries::setUpperSeries(QLineSeries *series)
{
Q_D(QAreaSeries);
+
if (d->m_upperSeries != series) {
- series->d_ptr->setBlockOpenGL(true);
+ if (series)
+ series->d_ptr->setBlockOpenGL(true);
d->m_upperSeries = series;
+ if (!d->m_item.isNull())
+ static_cast<AreaChartItem *>(d->m_item.data())->setUpperSeries(series);
}
}
@@ -428,8 +433,13 @@ QLineSeries *QAreaSeries::upperSeries() const
void QAreaSeries::setLowerSeries(QLineSeries *series)
{
Q_D(QAreaSeries);
- series->d_ptr->setBlockOpenGL(true);
- d->m_lowerSeries = series;
+ if (d->m_lowerSeries != series) {
+ if (series)
+ series->d_ptr->setBlockOpenGL(true);
+ d->m_lowerSeries = series;
+ if (!d->m_item.isNull())
+ static_cast<AreaChartItem *>(d->m_item.data())->setLowerSeries(series);
+ }
}
QLineSeries *QAreaSeries::lowerSeries() const
diff --git a/src/charts/axis/chartaxiselement.cpp b/src/charts/axis/chartaxiselement.cpp
index f4faa5de..c5a1ab91 100644
--- a/src/charts/axis/chartaxiselement.cpp
+++ b/src/charts/axis/chartaxiselement.cpp
@@ -240,8 +240,15 @@ void ChartAxisElement::handleVisibleChanged(bool visible)
m_labels->setVisible(axis()->labelsVisible());
m_title->setVisible(axis()->isTitleVisible());
}
-
- if (presenter()) presenter()->layout()->invalidate();
+ if (presenter()) {
+ if (visible) {
+ QSizeF before = effectiveSizeHint(Qt::PreferredSize);
+ QSizeF after = sizeHint(Qt::PreferredSize);
+ if (before != after)
+ QGraphicsLayoutItem::updateGeometry();
+ }
+ presenter()->layout()->invalidate();
+ }
}
void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
diff --git a/src/charts/axis/qabstractaxis.cpp b/src/charts/axis/qabstractaxis.cpp
index 10848d9d..bc1697fe 100644
--- a/src/charts/axis/qabstractaxis.cpp
+++ b/src/charts/axis/qabstractaxis.cpp
@@ -523,7 +523,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);
@@ -618,31 +618,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)
@@ -717,7 +717,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);
@@ -860,7 +860,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);
@@ -874,8 +874,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);
diff --git a/src/charts/barchart/qbarset.cpp b/src/charts/barchart/qbarset.cpp
index d7832293..85175cb2 100644
--- a/src/charts/barchart/qbarset.cpp
+++ b/src/charts/barchart/qbarset.cpp
@@ -280,12 +280,19 @@ QT_CHARTS_BEGIN_NAMESPACE
/*!
\qmlproperty QVariantList BarSet::values
- The values of the bar set. You can set either a list of reals or a list of points as values. If you set a list of
- reals as values, the values are automatically completed to points by using the index of a value as it's
- x-coordinate. For example the following sets have equal values:
+ The values of the bar set. You can set either a list of reals or a list of points as values.
+
+ If you set a list of reals as values, the values directly define the bar set values.
+
+ If you set a list of points as values, the x-coordinate of the point specifies its zero-based
+ index in the bar set. The size of the bar set is the highest x-coordinate value + 1.
+ If a point is missing for any x-coordinate between zero and the highest value,
+ it gets value zero.
+
+ For example the following sets have equal values:
\code
- myBarSet1.values = [0, 5, 1, 5];
- myBarSet2.values = [Qt.point(0, 0), Qt.point(1, 5), Qt.point(2, 1), Qt.point(3, 5)];
+ myBarSet1.values = [5, 0, 1, 5];
+ myBarSet2.values = [Qt.point(0, 5), Qt.point(2, 1), Qt.point(3, 5)];
\endcode
*/
diff --git a/src/charts/boxplotchart/qboxplotseries.cpp b/src/charts/boxplotchart/qboxplotseries.cpp
index 9515c60b..26184735 100644
--- a/src/charts/boxplotchart/qboxplotseries.cpp
+++ b/src/charts/boxplotchart/qboxplotseries.cpp
@@ -535,9 +535,10 @@ void QBoxPlotSeriesPrivate::handleSeriesRemove(QAbstractSeries *series)
QBoxPlotSeries *removedSeries = static_cast<QBoxPlotSeries *>(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
diff --git a/src/charts/chartdataset_p.h b/src/charts/chartdataset_p.h
index bc2917bc..4552ad20 100644
--- a/src/charts/chartdataset_p.h
+++ b/src/charts/chartdataset_p.h
@@ -81,6 +81,8 @@ public:
GLXYSeriesDataManager *glXYSeriesDataManager() { return m_glXYSeriesDataManager; }
+ AbstractDomain* createDomain(AbstractDomain::DomainType type);
+
Q_SIGNALS:
void axisAdded(QAbstractAxis* axis);
void axisRemoved(QAbstractAxis* axis);
@@ -92,7 +94,6 @@ private:
void createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation);
QAbstractAxis *createAxis(QAbstractAxis::AxisType type, Qt::Orientation orientation);
AbstractDomain::DomainType selectDomain(QList<QAbstractAxis* > axes);
- AbstractDomain* createDomain(AbstractDomain::DomainType type);
void deleteAllAxes();
void deleteAllSeries();
void findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max);
diff --git a/src/charts/chartitem.cpp b/src/charts/chartitem.cpp
index 58a97d01..fda019c9 100644
--- a/src/charts/chartitem.cpp
+++ b/src/charts/chartitem.cpp
@@ -52,19 +52,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 266d246b..ad4266d3 100644
--- a/src/charts/chartitem_p.h
+++ b/src/charts/chartitem_p.h
@@ -55,7 +55,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/chartpresenter.cpp b/src/charts/chartpresenter.cpp
index f15bc880..a4955141 100644
--- a/src/charts/chartpresenter.cpp
+++ b/src/charts/chartpresenter.cpp
@@ -147,6 +147,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();
diff --git a/src/charts/domain/abstractdomain.cpp b/src/charts/domain/abstractdomain.cpp
index fb906c66..9186686e 100644
--- a/src/charts/domain/abstractdomain.cpp
+++ b/src/charts/domain/abstractdomain.cpp
@@ -45,7 +45,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)
{
}
@@ -114,15 +116,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)
@@ -135,6 +128,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) {
@@ -207,11 +212,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;
@@ -222,12 +233,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;
}
@@ -269,6 +284,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 1e1782bf..b6f5d7dd 100644
--- a/src/charts/domain/abstractdomain_p.h
+++ b/src/charts/domain/abstractdomain_p.h
@@ -111,6 +111,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);
@@ -119,9 +125,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;
@@ -134,6 +143,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 ab799e68..1651132c 100644
--- a/src/charts/domain/logxlogydomain.cpp
+++ b/src/charts/domain/logxlogydomain.cpp
@@ -89,15 +89,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;
@@ -109,8 +110,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);
@@ -131,6 +133,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);
@@ -153,23 +160,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);
}
@@ -183,8 +192,12 @@ QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QVector<QPointF>
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 {
@@ -199,8 +212,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 d8f712d9..b5cef8db 100644
--- a/src/charts/domain/logxydomain.cpp
+++ b/src/charts/domain/logxydomain.cpp
@@ -81,8 +81,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;
@@ -92,8 +93,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);
}
@@ -101,7 +102,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);
@@ -110,11 +112,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);
@@ -122,6 +124,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);
@@ -145,9 +152,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;
@@ -167,8 +178,12 @@ QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QVector<QPointF> &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 {
@@ -184,8 +199,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 172a9de4..75187197 100644
--- a/src/charts/domain/xlogydomain.cpp
+++ b/src/charts/domain/xlogydomain.cpp
@@ -81,15 +81,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;
@@ -101,14 +102,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);
@@ -121,6 +123,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;
@@ -145,9 +152,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();
@@ -168,7 +179,11 @@ QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QVector<QPointF> &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 {
@@ -183,8 +198,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 da54b4fa..1e79de52 100644
--- a/src/charts/domain/xydomain.cpp
+++ b/src/charts/domain/xydomain.cpp
@@ -71,6 +71,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();
@@ -79,10 +80,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;
@@ -99,6 +100,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();
@@ -107,9 +109,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()) {
@@ -126,6 +128,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();
@@ -150,7 +157,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);
}
@@ -165,7 +176,11 @@ QVector<QPointF> XYDomain::calculateGeometryPoints(const QVector<QPointF> &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);
}
@@ -176,8 +191,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/glwidget.cpp b/src/charts/glwidget.cpp
index 784f4b3a..ff22050f 100644
--- a/src/charts/glwidget.cpp
+++ b/src/charts/glwidget.cpp
@@ -334,41 +334,43 @@ void GLWidget::render(bool selection)
QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
GLXYSeriesData *data = i.value();
- if (selection) {
- m_selectionVector[counter] = i.key();
- m_program->setUniformValue(m_colorUniformLoc, QVector3D((counter & 0xff) / 255.0f,
- ((counter & 0xff00) >> 8) / 255.0f,
- ((counter & 0xff0000) >> 16) / 255.0f));
- counter++;
- } else {
- m_program->setUniformValue(m_colorUniformLoc, data->color);
- }
- m_program->setUniformValue(m_minUniformLoc, data->min);
- m_program->setUniformValue(m_deltaUniformLoc, data->delta);
- m_program->setUniformValue(m_matrixUniformLoc, data->matrix);
- bool dirty = data->dirty;
- if (!vbo) {
- vbo = new QOpenGLBuffer;
- m_seriesBufferMap.insert(i.key(), vbo);
- vbo->create();
- dirty = true;
- }
- vbo->bind();
- if (dirty) {
- vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
- data->dirty = false;
- m_selectionRenderNeeded = true;
- }
+ if (data->visible) {
+ if (selection) {
+ m_selectionVector[counter] = i.key();
+ m_program->setUniformValue(m_colorUniformLoc, QVector3D((counter & 0xff) / 255.0f,
+ ((counter & 0xff00) >> 8) / 255.0f,
+ ((counter & 0xff0000) >> 16) / 255.0f));
+ counter++;
+ } else {
+ m_program->setUniformValue(m_colorUniformLoc, data->color);
+ }
+ m_program->setUniformValue(m_minUniformLoc, data->min);
+ m_program->setUniformValue(m_deltaUniformLoc, data->delta);
+ m_program->setUniformValue(m_matrixUniformLoc, data->matrix);
+ bool dirty = data->dirty;
+ if (!vbo) {
+ vbo = new QOpenGLBuffer;
+ m_seriesBufferMap.insert(i.key(), vbo);
+ vbo->create();
+ dirty = true;
+ }
+ vbo->bind();
+ if (dirty) {
+ vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
+ dirty = false;
+ m_selectionRenderNeeded = true;
+ }
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
- if (data->type == QAbstractSeries::SeriesTypeLine) {
- glLineWidth(data->width);
- glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
- } else { // Scatter
- m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
- glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ if (data->type == QAbstractSeries::SeriesTypeLine) {
+ glLineWidth(data->width);
+ glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
+ } else { // Scatter
+ m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
+ glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
+ }
+ vbo->release();
}
- vbo->release();
}
m_program->release();
}
diff --git a/src/charts/layout/cartesianchartlayout.cpp b/src/charts/layout/cartesianchartlayout.cpp
index 7a3d8638..80a852a7 100644
--- a/src/charts/layout/cartesianchartlayout.cpp
+++ b/src/charts/layout/cartesianchartlayout.cpp
@@ -233,11 +233,11 @@ QRectF CartesianChartLayout::calculateAxisMinimum(const QRectF &minimum, const Q
switch (axis->axis()->alignment()) {
case Qt::AlignLeft:
left.setWidth(left.width() + size.width());
- left.setHeight(qMax(left.height() * 2, size.height()));
+ left.setHeight(qMax(left.height(), size.height()));
break;
case Qt::AlignRight:
right.setWidth(right.width() + size.width());
- right.setHeight(qMax(right.height() * 2, size.height()));
+ right.setHeight(qMax(right.height(), size.height()));
break;
case Qt::AlignTop:
top.setWidth(qMax(top.width(), size.width()));
diff --git a/src/charts/linechart/linechartitem.cpp b/src/charts/linechart/linechartitem.cpp
index afb1284d..03099356 100644
--- a/src/charts/linechart/linechartitem.cpp
+++ b/src/charts/linechart/linechartitem.cpp
@@ -347,6 +347,7 @@ void LineChartItem::handleUpdated()
bool doGeometryUpdate =
(m_pointsVisible != m_series->pointsVisible())
|| (m_series->pointsVisible() && (m_linePen != m_series->pen()));
+ bool visibleChanged = m_series->isVisible() != isVisible();
setVisible(m_series->isVisible());
setOpacity(m_series->opacity());
m_pointsVisible = m_series->pointsVisible();
@@ -358,6 +359,8 @@ void LineChartItem::handleUpdated()
m_pointLabelsClipping = m_series->pointLabelsClipping();
if (doGeometryUpdate)
updateGeometry();
+ else if (m_series->useOpenGL() && visibleChanged)
+ refreshGlChart();
update();
}
@@ -392,8 +395,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);
@@ -409,8 +410,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 271f7f66..9f2c21b9 100644
--- a/src/charts/qabstractseries.cpp
+++ b/src/charts/qabstractseries.cpp
@@ -454,40 +454,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 cbdfb5f8..0d50ea2b 100644
--- a/src/charts/qabstractseries_p.h
+++ b/src/charts/qabstractseries_p.h
@@ -89,8 +89,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 cc1ecb60..2defadf5 100644
--- a/src/charts/scatterchart/scatterchartitem.cpp
+++ b/src/charts/scatterchart/scatterchartitem.cpp
@@ -194,17 +194,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
@@ -256,15 +249,21 @@ void ScatterChartItem::setBrush(const QBrush &brush)
void ScatterChartItem::handleUpdated()
{
- int count = m_items.childItems().count();
+ if (m_series->useOpenGL()) {
+ if ((m_series->isVisible() != m_visible)) {
+ m_visible = m_series->isVisible();
+ refreshGlChart();
+ }
+ return;
+ }
+ int count = m_items.childItems().count();
if (count == 0)
return;
bool recreate = m_visible != m_series->isVisible()
|| m_size != m_series->markerSize()
|| m_shape != m_series->markerShape();
-
m_visible = m_series->isVisible();
m_size = m_series->markerSize();
m_shape = m_series->markerShape();
diff --git a/src/charts/splinechart/splinechartitem.cpp b/src/charts/splinechart/splinechartitem.cpp
index 4f7e7cb2..0f9c1e24 100644
--- a/src/charts/splinechart/splinechartitem.cpp
+++ b/src/charts/splinechart/splinechartitem.cpp
@@ -460,8 +460,6 @@ void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
painter->setClipRect(clipRect);
}
- reversePainter(painter, clipRect);
-
painter->drawPath(m_path);
if (m_pointsVisible) {
@@ -472,8 +470,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/glxyseriesdata.cpp b/src/charts/xychart/glxyseriesdata.cpp
index 37da55b1..9a6f330a 100644
--- a/src/charts/xychart/glxyseriesdata.cpp
+++ b/src/charts/xychart/glxyseriesdata.cpp
@@ -50,6 +50,7 @@ void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *d
if (!data) {
data = new GLXYSeriesData;
data->type = series->type();
+ data->visible = series->isVisible();
QColor sc;
if (data->type == QAbstractSeries::SeriesTypeScatter) {
QScatterSeries *scatter = static_cast<QScatterSeries *>(series);
@@ -68,6 +69,8 @@ void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *d
data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
connect(series, &QXYSeries::useOpenGLChanged, this,
&GLXYSeriesDataManager::handleSeriesOpenGLChange);
+ connect(series, &QXYSeries::visibleChanged, this,
+ &GLXYSeriesDataManager::handleSeriesVisibilityChange);
m_seriesDataMap.insert(series, data);
m_mapDirty = true;
}
@@ -174,6 +177,18 @@ void GLXYSeriesDataManager::handleSeriesOpenGLChange()
removeSeries(series);
}
+void GLXYSeriesDataManager::handleSeriesVisibilityChange()
+{
+ QXYSeries *series = qobject_cast<QXYSeries *>(sender());
+ if (series) {
+ GLXYSeriesData *data = m_seriesDataMap.value(series);
+ if (data) {
+ data->visible = series->isVisible();
+ data->dirty = true;
+ }
+ }
+}
+
void GLXYSeriesDataManager::handleScatterColorChange()
{
QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
diff --git a/src/charts/xychart/glxyseriesdata_p.h b/src/charts/xychart/glxyseriesdata_p.h
index 578ab217..4a22e575 100644
--- a/src/charts/xychart/glxyseriesdata_p.h
+++ b/src/charts/xychart/glxyseriesdata_p.h
@@ -58,6 +58,7 @@ struct GLXYSeriesData {
QAbstractSeries::SeriesType type;
QVector2D min;
QVector2D delta;
+ bool visible;
QMatrix4x4 matrix;
public:
GLXYSeriesData &operator=(const GLXYSeriesData &data) {
@@ -68,6 +69,7 @@ public:
type = data.type;
min = data.min;
delta = data.delta;
+ visible = data.visible;
matrix = data.matrix;
return *this;
}
@@ -103,6 +105,7 @@ public Q_SLOTS:
void cleanup();
void handleSeriesPenChange();
void handleSeriesOpenGLChange();
+ void handleSeriesVisibilityChange();
void handleScatterColorChange();
void handleScatterMarkerSizeChange();
diff --git a/src/charts/xychart/qvxymodelmapper.cpp b/src/charts/xychart/qvxymodelmapper.cpp
index fb7f63ab..3b68d809 100644
--- a/src/charts/xychart/qvxymodelmapper.cpp
+++ b/src/charts/xychart/qvxymodelmapper.cpp
@@ -120,7 +120,7 @@ QT_CHARTS_BEGIN_NAMESPACE
Minimal and default value is: -1 (count limited by the number of rows in the model)
*/
/*!
- \qmlproperty int VXYModelMapper::columnCount
+ \qmlproperty int VXYModelMapper::rowCount
Defines the number of rows of the model that are mapped as the data for series. The default value is
-1 (count limited by the number of rows in the model).
*/
diff --git a/src/charts/xychart/qxymodelmapper.cpp b/src/charts/xychart/qxymodelmapper.cpp
index b6037858..51f4a85a 100644
--- a/src/charts/xychart/qxymodelmapper.cpp
+++ b/src/charts/xychart/qxymodelmapper.cpp
@@ -32,6 +32,7 @@
#include <QtCharts/QXYSeries>
#include <QtCore/QAbstractItemModel>
#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
QT_CHARTS_BEGIN_NAMESPACE
@@ -544,15 +545,31 @@ void QXYModelMapperPrivate::initializeXYFromModel()
int pointPos = 0;
QModelIndex xIndex = xModelIndex(pointPos);
QModelIndex yIndex = yModelIndex(pointPos);
- while (xIndex.isValid() && yIndex.isValid()) {
- QPointF point;
- point.setX(valueFromModel(xIndex));
- point.setY(valueFromModel(yIndex));
- m_series->append(point);
- pointPos++;
- xIndex = xModelIndex(pointPos);
- yIndex = yModelIndex(pointPos);
+
+ if (xIndex.isValid() && yIndex.isValid()) {
+ while (xIndex.isValid() && yIndex.isValid()) {
+ QPointF point;
+ point.setX(valueFromModel(xIndex));
+ point.setY(valueFromModel(yIndex));
+ m_series->append(point);
+ pointPos++;
+ xIndex = xModelIndex(pointPos);
+ yIndex = yModelIndex(pointPos);
+ // Don't warn about invalid index after the first, those are valid and used to
+ // determine when we should end looping.
+ }
+ } else {
+ // 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);
}
diff --git a/src/charts/xychart/qxyseries.cpp b/src/charts/xychart/qxyseries.cpp
index f3a253cd..fd8562a1 100644
--- a/src/charts/xychart/qxyseries.cpp
+++ b/src/charts/xychart/qxyseries.cpp
@@ -972,14 +972,8 @@ void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QP
// Position text in relation to the point
int pointLabelWidth = fm.width(pointLabel);
QPointF position(points.at(i));
- if (!reverseXAxis())
- position.setX(position.x() - pointLabelWidth / 2);
- else
- position.setX(domain()->size().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);
}
diff --git a/src/charts/xychart/xychart.cpp b/src/charts/xychart/xychart.cpp
index 1811a76e..4314f6dd 100644
--- a/src/charts/xychart/xychart.cpp
+++ b/src/charts/xychart/xychart.cpp
@@ -128,6 +128,12 @@ void XYChart::updateGlChart()
updateGeometry();
}
+// Doesn't update gl geometry, but refreshes the chart
+void XYChart::refreshGlChart()
+{
+ presenter()->updateGLWidget();
+}
+
//handlers
void XYChart::handlePointAdded(int index)
diff --git a/src/charts/xychart/xychart_p.h b/src/charts/xychart/xychart_p.h
index c0348c18..c5737cca 100644
--- a/src/charts/xychart/xychart_p.h
+++ b/src/charts/xychart/xychart_p.h
@@ -88,6 +88,7 @@ Q_SIGNALS:
protected:
virtual void updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index = -1);
virtual void updateGlChart();
+ virtual void refreshGlChart();
private:
inline bool isEmpty();