diff options
93 files changed, 1177 insertions, 685 deletions
@@ -1,5 +1,5 @@ --------------- -Qt Charts 5.7.0 +Qt Charts --------------- 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..96ec6710 --- /dev/null +++ b/dist/changes-2.1.2 @@ -0,0 +1,26 @@ +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 +- [QTBUG-55431] Fix setting area series edge series after area series is shown + +Fixed examples +-------------- +- [QTBUG-54492] Fix resize handling in Callout example diff --git a/examples/charts/areachart/areachart.pro b/examples/charts/areachart/areachart.pro index e8e1a074..96e138ab 100644 --- a/examples/charts/areachart/areachart.pro +++ b/examples/charts/areachart/areachart.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = areachart -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/areachart +INSTALLS += target diff --git a/examples/charts/audio/audio.pro b/examples/charts/audio/audio.pro index 6a3b6917..c6df9be0 100644 --- a/examples/charts/audio/audio.pro +++ b/examples/charts/audio/audio.pro @@ -1,15 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts multimedia -QT += multimedia - -TARGET = audio -TEMPLATE = app +HEADERS += \ + widget.h \ + xyseriesiodevice.h -SOURCES += main.cpp\ - widget.cpp \ +SOURCES += \ + main.cpp\ + widget.cpp \ xyseriesiodevice.cpp -HEADERS += widget.h \ - xyseriesiodevice.h +target.path = $$[QT_INSTALL_EXAMPLES]/charts/audio +INSTALLS += target diff --git a/examples/charts/barchart/barchart.pro b/examples/charts/barchart/barchart.pro index 14db3c88..eaa7a037 100644 --- a/examples/charts/barchart/barchart.pro +++ b/examples/charts/barchart/barchart.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = barchart -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/barchart +INSTALLS += target diff --git a/examples/charts/barmodelmapper/barmodelmapper.pro b/examples/charts/barmodelmapper/barmodelmapper.pro index 91b8f367..45a5e224 100644 --- a/examples/charts/barmodelmapper/barmodelmapper.pro +++ b/examples/charts/barmodelmapper/barmodelmapper.pro @@ -1,16 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -QT += core gui +HEADERS += \ + customtablemodel.h \ + tablewidget.h -TARGET = barmodelmapper -TEMPLATE = app +SOURCES += \ + customtablemodel.cpp \ + main.cpp \ + tablewidget.cpp - -SOURCES += main.cpp\ - tablewidget.cpp \ - customtablemodel.cpp - -HEADERS += tablewidget.h \ - customtablemodel.h +target.path = $$[QT_INSTALL_EXAMPLES]/charts/barmodelmapper +INSTALLS += target diff --git a/examples/charts/boxplotchart/boxplotchart.pro b/examples/charts/boxplotchart/boxplotchart.pro index c2483511..10ed4515 100644 --- a/examples/charts/boxplotchart/boxplotchart.pro +++ b/examples/charts/boxplotchart/boxplotchart.pro @@ -1,13 +1,14 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = boxplotchart -SOURCES += main.cpp \ - boxdatareader.cpp +HEADERS += \ + boxdatareader.h + +SOURCES += \ + boxdatareader.cpp \ + main.cpp \ RESOURCES += \ boxplotdata.qrc -HEADERS += \ - boxdatareader.h +target.path = $$[QT_INSTALL_EXAMPLES]/charts/boxplotchart +INSTALLS += target diff --git a/examples/charts/callout/callout.cpp b/examples/charts/callout/callout.cpp index 2c843393..bb37802a 100644 --- a/examples/charts/callout/callout.cpp +++ b/examples/charts/callout/callout.cpp @@ -32,15 +32,17 @@ #include <QtGui/QFontMetrics> #include <QtWidgets/QGraphicsSceneMouseEvent> #include <QtGui/QMouseEvent> +#include <QtCharts/QChart> -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())); @@ -56,7 +58,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; @@ -88,7 +90,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(); } @@ -126,3 +128,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 35de08d5..67cc76ff 100644 --- a/examples/charts/callout/callout.h +++ b/examples/charts/callout/callout.h @@ -30,6 +30,7 @@ #ifndef CALLOUT_H #define CALLOUT_H +#include <QtCharts/QChartGlobal> #include <QtWidgets/QGraphicsItem> #include <QtGui/QFont> @@ -37,13 +38,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); @@ -58,6 +66,7 @@ private: QRectF m_rect; QPointF m_anchor; QFont m_font; + QChart *m_chart; }; #endif // CALLOUT_H diff --git a/examples/charts/callout/callout.pro b/examples/charts/callout/callout.pro index b0da66d6..688b69e9 100644 --- a/examples/charts/callout/callout.pro +++ b/examples/charts/callout/callout.pro @@ -1,15 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = callout -TEMPLATE = app +HEADERS += \ + callout.h \ + view.h SOURCES += \ - main.cpp\ - callout.cpp \ - view.cpp + callout.cpp \ + main.cpp\ + view.cpp -HEADERS += \ - callout.h \ - view.h +target.path = $$[QT_INSTALL_EXAMPLES]/charts/callout +INSTALLS += target diff --git a/examples/charts/callout/view.cpp b/examples/charts/callout/view.cpp index 1c90eef0..9c1eca69 100644 --- a/examples/charts/callout/view.cpp +++ b/examples/charts/callout/view.cpp @@ -98,6 +98,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); } @@ -111,6 +113,7 @@ void View::mouseMoveEvent(QMouseEvent *event) void View::keepCallout() { + m_callouts.append(m_tooltip); m_tooltip = new Callout(m_chart); } @@ -121,10 +124,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<QXYSeries *>(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 4744a1c3..4d17461b 100644 --- a/examples/charts/callout/view.h +++ b/examples/charts/callout/view.h @@ -66,6 +66,7 @@ private: QGraphicsSimpleTextItem *m_coordY; QChart *m_chart; Callout *m_tooltip; + QList<Callout *> m_callouts; }; #endif diff --git a/examples/charts/candlestickchart/candlestickchart.pro b/examples/charts/candlestickchart/candlestickchart.pro index 9a334bd6..f7080e77 100644 --- a/examples/charts/candlestickchart/candlestickchart.pro +++ b/examples/charts/candlestickchart/candlestickchart.pro @@ -1,6 +1,4 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts TARGET = candlestickchart @@ -12,3 +10,6 @@ HEADERS += \ RESOURCES += \ candlestickdata.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/candlestickchart +INSTALLS += target diff --git a/examples/charts/chartinteractions/chartinteractions.pro b/examples/charts/chartinteractions/chartinteractions.pro index 8cf4c36c..4027eb3c 100644 --- a/examples/charts/chartinteractions/chartinteractions.pro +++ b/examples/charts/chartinteractions/chartinteractions.pro @@ -1,11 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -QT += core gui +HEADERS += \ + chart.h \ + chartview.h -TARGET = chartinteractions -TEMPLATE = app +SOURCES += \ + chart.cpp \ + chartview.cpp \ + main.cpp -HEADERS += chart.h chartview.h -SOURCES += main.cpp chart.cpp chartview.cpp +target.path = $$[QT_INSTALL_EXAMPLES]/charts/chartinteractions +INSTALLS += target diff --git a/examples/charts/charts.pro b/examples/charts/charts.pro index 704d9cc0..b64b464f 100644 --- a/examples/charts/charts.pro +++ b/examples/charts/charts.pro @@ -1,52 +1,55 @@ TEMPLATE = subdirs -SUBDIRS += areachart \ +SUBDIRS += \ + areachart \ + barchart \ + barmodelmapper \ + boxplotchart \ + callout \ + candlestickchart \ + chartinteractions \ + chartthemes \ customchart \ + donutbreakdown \ + donutchart \ + dynamicspline \ + horizontalbarchart \ + horizontalpercentbarchart \ + horizontalstackedbarchart \ + legend \ + legendmarkers \ + lineandbar \ linechart \ + logvalueaxis \ + modeldata \ + multiaxis \ + nesteddonuts \ percentbarchart \ piechart \ + piechartcustomization \ piechartdrilldown \ + polarchart \ scatterchart \ scatterinteractions \ splinechart \ stackedbarchart \ stackedbarchartdrilldown \ - zoomlinechart \ - modeldata \ - barchart \ - boxplotchart \ - candlestickchart \ - legend \ - barmodelmapper \ - lineandbar \ - horizontalbarchart \ - horizontalstackedbarchart \ - horizontalpercentbarchart \ - donutbreakdown \ temperaturerecords \ - donutchart \ - multiaxis \ - legendmarkers \ - logvalueaxis \ - polarchart \ - piechartcustomization \ - dynamicspline \ - nesteddonuts \ - chartinteractions \ - callout \ - chartthemes + zoomlinechart qtHaveModule(quick) { - SUBDIRS += qmlboxplot \ + SUBDIRS += \ + qmlaxes \ + qmlboxplot \ qmlcandlestick \ - qmlpiechart \ - qmlweather \ - qmlf1legends \ + qmlchart \ qmlcustomizations \ - qmlaxes \ qmlcustomlegend \ + qmlf1legends \ + qmloscilloscope \ + qmlpiechart \ qmlpolarchart \ - qmlchart \ - qmloscilloscope + qmlweather + } qtHaveModule(multimedia) { diff --git a/examples/charts/chartthemes/chartthemes.pro b/examples/charts/chartthemes/chartthemes.pro index 2a414557..5985f55c 100644 --- a/examples/charts/chartthemes/chartthemes.pro +++ b/examples/charts/chartthemes/chartthemes.pro @@ -1,7 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = chartthemes -SOURCES = main.cpp themewidget.cpp -HEADERS = themewidget.h +HEADERS += \ + themewidget.h + +SOURCES += \ + main.cpp \ + themewidget.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/chartthemes +INSTALLS += target diff --git a/examples/charts/customchart/customchart.pro b/examples/charts/customchart/customchart.pro index 5f3f7382..e82b94ae 100644 --- a/examples/charts/customchart/customchart.pro +++ b/examples/charts/customchart/customchart.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = customchart -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/customchart +INSTALLS += target diff --git a/examples/charts/datetimeaxis/datetimeaxis.pro b/examples/charts/datetimeaxis/datetimeaxis.pro index 0ec9d715..09869b05 100644 --- a/examples/charts/datetimeaxis/datetimeaxis.pro +++ b/examples/charts/datetimeaxis/datetimeaxis.pro @@ -1,8 +1,10 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = datetimeaxis -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp RESOURCES += \ sundata.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/datetimeaxis +INSTALLS += target diff --git a/examples/charts/donutbreakdown/donutbreakdown.pro b/examples/charts/donutbreakdown/donutbreakdown.pro index fecef7b8..85ef9d3a 100644 --- a/examples/charts/donutbreakdown/donutbreakdown.pro +++ b/examples/charts/donutbreakdown/donutbreakdown.pro @@ -1,12 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = donutbreakdown -SOURCES += main.cpp\ +HEADERS += \ + donutbreakdownchart.h \ + mainslice.h + +SOURCES += \ donutbreakdownchart.cpp \ + main.cpp \ mainslice.cpp -HEADERS += \ - donutbreakdownchart.h \ - mainslice.h +target.path = $$[QT_INSTALL_EXAMPLES]/charts/donutbreakdown +INSTALLS += target diff --git a/examples/charts/donutchart/donutchart.pro b/examples/charts/donutchart/donutchart.pro index 72d4ea4d..71017d12 100644 --- a/examples/charts/donutchart/donutchart.pro +++ b/examples/charts/donutchart/donutchart.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = donutchart -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/donutchart +INSTALLS += target diff --git a/examples/charts/dynamicspline/dynamicspline.pro b/examples/charts/dynamicspline/dynamicspline.pro index feb26895..1aedeca4 100644 --- a/examples/charts/dynamicspline/dynamicspline.pro +++ b/examples/charts/dynamicspline/dynamicspline.pro @@ -1,7 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = dynamicspline -HEADERS += chart.h -SOURCES += main.cpp chart.cpp +HEADERS += \ + chart.h + +SOURCES += \ + chart.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/dynamicspline +INSTALLS += target diff --git a/examples/charts/examples.pri b/examples/charts/examples.pri deleted file mode 100644 index 7b2eaaa7..00000000 --- a/examples/charts/examples.pri +++ /dev/null @@ -1,17 +0,0 @@ - -INCLUDEPATH += ../../../include - -LIBS += -L$$OUT_PWD/../../../lib - -TEMPLATE = app - -QT += charts -QT += core gui widgets - -contains(TARGET, qml.*) { - QT += qml quick -} - -target.path = $$[QT_INSTALL_EXAMPLES]/charts/$$TARGET -INSTALLS += target - diff --git a/examples/charts/horizontalbarchart/horizontalbarchart.pro b/examples/charts/horizontalbarchart/horizontalbarchart.pro index 61ec088e..f0acf2bc 100644 --- a/examples/charts/horizontalbarchart/horizontalbarchart.pro +++ b/examples/charts/horizontalbarchart/horizontalbarchart.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = horizontalbarchart -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/horizontalbarchart +INSTALLS += target diff --git a/examples/charts/horizontalpercentbarchart/horizontalpercentbarchart.pro b/examples/charts/horizontalpercentbarchart/horizontalpercentbarchart.pro index d6168695..5bd65774 100644 --- a/examples/charts/horizontalpercentbarchart/horizontalpercentbarchart.pro +++ b/examples/charts/horizontalpercentbarchart/horizontalpercentbarchart.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = horizontalpercentbarchart -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/horizontalpercentbarchart +INSTALLS += target diff --git a/examples/charts/horizontalstackedbarchart/horizontalstackedbarchart.pro b/examples/charts/horizontalstackedbarchart/horizontalstackedbarchart.pro index 5c08d212..b6ba1612 100644 --- a/examples/charts/horizontalstackedbarchart/horizontalstackedbarchart.pro +++ b/examples/charts/horizontalstackedbarchart/horizontalstackedbarchart.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = horizontalstackedbarchart -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/horizontalstackedbarchart +INSTALLS += target diff --git a/examples/charts/legend/legend.pro b/examples/charts/legend/legend.pro index 5e22fb2a..5e832ed8 100644 --- a/examples/charts/legend/legend.pro +++ b/examples/charts/legend/legend.pro @@ -1,10 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} - -TARGET = legend -SOURCES += main.cpp \ - mainwidget.cpp +QT += charts HEADERS += \ mainwidget.h + +SOURCES += \ + main.cpp \ + mainwidget.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/legend +INSTALLS += target diff --git a/examples/charts/legendmarkers/legendmarkers.pro b/examples/charts/legendmarkers/legendmarkers.pro index f79bdba4..169393e0 100644 --- a/examples/charts/legendmarkers/legendmarkers.pro +++ b/examples/charts/legendmarkers/legendmarkers.pro @@ -1,10 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} - -TARGET = legendmarkers -SOURCES += main.cpp \ - mainwidget.cpp +QT += charts HEADERS += \ mainwidget.h + +SOURCES += \ + main.cpp \ + mainwidget.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/legendmarkers +INSTALLS += target diff --git a/examples/charts/lineandbar/lineandbar.pro b/examples/charts/lineandbar/lineandbar.pro index dd94abd5..073cca49 100644 --- a/examples/charts/lineandbar/lineandbar.pro +++ b/examples/charts/lineandbar/lineandbar.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = lineandbar -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/lineandbar +INSTALLS += target diff --git a/examples/charts/linechart/linechart.pro b/examples/charts/linechart/linechart.pro index d3eb640a..71f70965 100644 --- a/examples/charts/linechart/linechart.pro +++ b/examples/charts/linechart/linechart.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = linechart -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/linechart +INSTALLS += target diff --git a/examples/charts/logvalueaxis/logvalueaxis.pro b/examples/charts/logvalueaxis/logvalueaxis.pro index ede43079..196a062a 100644 --- a/examples/charts/logvalueaxis/logvalueaxis.pro +++ b/examples/charts/logvalueaxis/logvalueaxis.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = logvalueaxis -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/logvalueaxis +INSTALLS += target diff --git a/examples/charts/modeldata/modeldata.pro b/examples/charts/modeldata/modeldata.pro index 7c302bd9..95d3d689 100644 --- a/examples/charts/modeldata/modeldata.pro +++ b/examples/charts/modeldata/modeldata.pro @@ -1,16 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -QT += core gui +HEADERS += \ + customtablemodel.h \ + tablewidget.h -TARGET = modeldata -TEMPLATE = app +SOURCES += \ + customtablemodel.cpp \ + main.cpp \ + tablewidget.cpp - -SOURCES += main.cpp\ - tablewidget.cpp \ - customtablemodel.cpp - -HEADERS += tablewidget.h \ - customtablemodel.h +target.path = $$[QT_INSTALL_EXAMPLES]/charts/modeldata +INSTALLS += target diff --git a/examples/charts/multiaxis/multiaxis.pro b/examples/charts/multiaxis/multiaxis.pro index 33de57cb..9edca6ba 100644 --- a/examples/charts/multiaxis/multiaxis.pro +++ b/examples/charts/multiaxis/multiaxis.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = multiaxis -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/multiaxis +INSTALLS += target diff --git a/examples/charts/nesteddonuts/nesteddonuts.pro b/examples/charts/nesteddonuts/nesteddonuts.pro index fadab0cd..571f1a06 100644 --- a/examples/charts/nesteddonuts/nesteddonuts.pro +++ b/examples/charts/nesteddonuts/nesteddonuts.pro @@ -1,8 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = nesteddonuts -SOURCES += main.cpp\ - widget.cpp -HEADERS += widget.h +HEADERS += \ + widget.h + +SOURCES += \ + main.cpp \ + widget.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/nesteddonuts +INSTALLS += target diff --git a/examples/charts/openglseries/openglseries.pro b/examples/charts/openglseries/openglseries.pro index 0ae11595..e0c13cfe 100644 --- a/examples/charts/openglseries/openglseries.pro +++ b/examples/charts/openglseries/openglseries.pro @@ -1,9 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = openglseries -SOURCES += main.cpp \ - datasource.cpp -HEADERS += datasource.h +HEADERS += \ + datasource.h +SOURCES += \ + datasource.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/openglseries +INSTALLS += target diff --git a/examples/charts/percentbarchart/percentbarchart.pro b/examples/charts/percentbarchart/percentbarchart.pro index 983159d1..cfb718b0 100644 --- a/examples/charts/percentbarchart/percentbarchart.pro +++ b/examples/charts/percentbarchart/percentbarchart.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = percentbarchart -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/percentbarchart +INSTALLS += target diff --git a/examples/charts/piechart/piechart.pro b/examples/charts/piechart/piechart.pro index 7bd48514..e3767910 100644 --- a/examples/charts/piechart/piechart.pro +++ b/examples/charts/piechart/piechart.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = piechart -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/piechart +INSTALLS += target diff --git a/examples/charts/piechartcustomization/piechartcustomization.pro b/examples/charts/piechartcustomization/piechartcustomization.pro index 722744de..081e9105 100644 --- a/examples/charts/piechartcustomization/piechartcustomization.pro +++ b/examples/charts/piechartcustomization/piechartcustomization.pro @@ -1,16 +1,17 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} - -TARGET = piechartcustomization -SOURCES += main.cpp \ - pentool.cpp \ - brushtool.cpp \ - customslice.cpp \ - mainwidget.cpp +QT += charts HEADERS += \ - pentool.h \ brushtool.h \ customslice.h \ - mainwidget.h + mainwidget.h \ + pentool.h + +SOURCES += \ + brushtool.cpp \ + customslice.cpp \ + main.cpp \ + mainwidget.cpp \ + pentool.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/piechartcustomization +INSTALLS += target diff --git a/examples/charts/piechartdrilldown/piechartdrilldown.pro b/examples/charts/piechartdrilldown/piechartdrilldown.pro index 0f9626c9..60866fc3 100644 --- a/examples/charts/piechartdrilldown/piechartdrilldown.pro +++ b/examples/charts/piechartdrilldown/piechartdrilldown.pro @@ -1,11 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = piechartdrilldown -SOURCES += main.cpp \ - drilldownslice.cpp \ - drilldownchart.cpp +QT += charts HEADERS += \ drilldownchart.h \ drilldownslice.h + +SOURCES += \ + drilldownchart.cpp \ + drilldownslice.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/piechartdrilldown +INSTALLS += target diff --git a/examples/charts/polarchart/polarchart.pro b/examples/charts/polarchart/polarchart.pro index 8759c1ce..a046ca86 100644 --- a/examples/charts/polarchart/polarchart.pro +++ b/examples/charts/polarchart/polarchart.pro @@ -1,6 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = polarchart -SOURCES += main.cpp chartview.cpp -HEADERS += chartview.h +QT += charts + +HEADERS += \ + chartview.h + +SOURCES += \ + chartview.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/polarchart +INSTALLS += target diff --git a/examples/charts/qmlaxes/qmlaxes.pro b/examples/charts/qmlaxes/qmlaxes.pro index 50b4c012..6fb5b4f9 100644 --- a/examples/charts/qmlaxes/qmlaxes.pro +++ b/examples/charts/qmlaxes/qmlaxes.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlaxes/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlaxes/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlaxes +INSTALLS += target diff --git a/examples/charts/qmlboxplot/qmlboxplot.pro b/examples/charts/qmlboxplot/qmlboxplot.pro index 237f05f1..3afed6af 100644 --- a/examples/charts/qmlboxplot/qmlboxplot.pro +++ b/examples/charts/qmlboxplot/qmlboxplot.pro @@ -1,9 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp +SOURCES += \ + main.cpp -OTHER_FILES += \ - qml/qmlboxplot/main.qml +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlboxplot/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlboxplot +INSTALLS += target diff --git a/examples/charts/qmlcandlestick/qmlcandlestick.pro b/examples/charts/qmlcandlestick/qmlcandlestick.pro index 58e63037..83f08895 100644 --- a/examples/charts/qmlcandlestick/qmlcandlestick.pro +++ b/examples/charts/qmlcandlestick/qmlcandlestick.pro @@ -1,6 +1,4 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick RESOURCES += resources.qrc @@ -8,3 +6,9 @@ SOURCES += main.cpp OTHER_FILES += \ qml/qmlcandlestick/main.qml + +DISTFILES += \ + qml/qmlcandlestick/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlcandlestick +INSTALLS += target diff --git a/examples/charts/qmlchart/qmlchart.pro b/examples/charts/qmlchart/qmlchart.pro index 82426424..f665ee12 100644 --- a/examples/charts/qmlchart/qmlchart.pro +++ b/examples/charts/qmlchart/qmlchart.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlchart/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlchart/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlchart +INSTALLS += target diff --git a/examples/charts/qmlcustomizations/qmlcustomizations.pro b/examples/charts/qmlcustomizations/qmlcustomizations.pro index ae2d4e5b..a2d316d6 100644 --- a/examples/charts/qmlcustomizations/qmlcustomizations.pro +++ b/examples/charts/qmlcustomizations/qmlcustomizations.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlcustomizations/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlcustomizations/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlcustomizations +INSTALLS += target diff --git a/examples/charts/qmlcustomlegend/qmlcustomlegend.pro b/examples/charts/qmlcustomlegend/qmlcustomlegend.pro index d42afded..478b68ac 100644 --- a/examples/charts/qmlcustomlegend/qmlcustomlegend.pro +++ b/examples/charts/qmlcustomlegend/qmlcustomlegend.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlcustomlegend/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlcustomlegend/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlcustomlegend +INSTALLS += target diff --git a/examples/charts/qmlf1legends/qmlf1legends.pro b/examples/charts/qmlf1legends/qmlf1legends.pro index fc8c04f4..a3081f15 100644 --- a/examples/charts/qmlf1legends/qmlf1legends.pro +++ b/examples/charts/qmlf1legends/qmlf1legends.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlf1legends/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlf1legends/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlf1legends +INSTALLS += target diff --git a/examples/charts/qmloscilloscope/qmloscilloscope.pro b/examples/charts/qmloscilloscope/qmloscilloscope.pro index a66fabcd..34ef74db 100644 --- a/examples/charts/qmloscilloscope/qmloscilloscope.pro +++ b/examples/charts/qmloscilloscope/qmloscilloscope.pro @@ -1,11 +1,17 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} - -RESOURCES += resources.qrc -SOURCES += main.cpp \ - datasource.cpp -OTHER_FILES += qml/qmloscilloscope/* +QT += charts qml quick HEADERS += \ datasource.h + +SOURCES += \ + main.cpp \ + datasource.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmloscilloscope/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmloscilloscope +INSTALLS += target diff --git a/examples/charts/qmlpiechart/qmlpiechart.pro b/examples/charts/qmlpiechart/qmlpiechart.pro index 926f9c2d..7f87bb1a 100644 --- a/examples/charts/qmlpiechart/qmlpiechart.pro +++ b/examples/charts/qmlpiechart/qmlpiechart.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlpiechart/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlpiechart/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlpiechart +INSTALLS += target diff --git a/examples/charts/qmlpolarchart/qmlpolarchart.pro b/examples/charts/qmlpolarchart/qmlpolarchart.pro index aa3341a5..340fbf86 100644 --- a/examples/charts/qmlpolarchart/qmlpolarchart.pro +++ b/examples/charts/qmlpolarchart/qmlpolarchart.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlpolarchart/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlpolarchart/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlpolarchart +INSTALLS += target diff --git a/examples/charts/qmlweather/qmlweather.pro b/examples/charts/qmlweather/qmlweather.pro index 5e0d8df4..f51e6c8f 100644 --- a/examples/charts/qmlweather/qmlweather.pro +++ b/examples/charts/qmlweather/qmlweather.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts qml quick -RESOURCES += resources.qrc -SOURCES += main.cpp -OTHER_FILES += qml/qmlweather/* +SOURCES += \ + main.cpp + +RESOURCES += \ + resources.qrc + +DISTFILES += \ + qml/qmlweather/* + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/qmlweather +INSTALLS += target diff --git a/examples/charts/scatterchart/scatterchart.pro b/examples/charts/scatterchart/scatterchart.pro index 8170d6f4..fdb468d6 100644 --- a/examples/charts/scatterchart/scatterchart.pro +++ b/examples/charts/scatterchart/scatterchart.pro @@ -1,9 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = scatterchart -SOURCES += main.cpp \ - chartview.cpp +QT += charts HEADERS += \ chartview.h + +SOURCES += \ + chartview.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/scatterchart +INSTALLS += target diff --git a/examples/charts/scatterinteractions/scatterinteractions.pro b/examples/charts/scatterinteractions/scatterinteractions.pro index 596fe020..e069df7f 100644 --- a/examples/charts/scatterinteractions/scatterinteractions.pro +++ b/examples/charts/scatterinteractions/scatterinteractions.pro @@ -1,9 +1,11 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = scatterinteractions -SOURCES += main.cpp \ - chartview.cpp -HEADERS += \ +HEADERS += \ chartview.h + +SOURCES += \ + chartview.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/scatterinteractions +INSTALLS += target diff --git a/examples/charts/splinechart/splinechart.pro b/examples/charts/splinechart/splinechart.pro index b2624f53..e71b7780 100644 --- a/examples/charts/splinechart/splinechart.pro +++ b/examples/charts/splinechart/splinechart.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = splinechart -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/splinechart +INSTALLS += target diff --git a/examples/charts/stackedbarchart/stackedbarchart.pro b/examples/charts/stackedbarchart/stackedbarchart.pro index f6a77b6a..1034c61d 100644 --- a/examples/charts/stackedbarchart/stackedbarchart.pro +++ b/examples/charts/stackedbarchart/stackedbarchart.pro @@ -1,5 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = stackedbarchart -SOURCES += main.cpp +QT += charts + +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/stackedbarchart +INSTALLS += target diff --git a/examples/charts/stackedbarchartdrilldown/stackedbarchartdrilldown.pro b/examples/charts/stackedbarchartdrilldown/stackedbarchartdrilldown.pro index c10066f4..7cd09466 100644 --- a/examples/charts/stackedbarchartdrilldown/stackedbarchartdrilldown.pro +++ b/examples/charts/stackedbarchartdrilldown/stackedbarchartdrilldown.pro @@ -1,6 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = stackedbarchartdrilldown -SOURCES += main.cpp drilldownseries.cpp drilldownchart.cpp -HEADERS += drilldownseries.h drilldownchart.h +QT += charts + +HEADERS += \ + drilldownchart.h \ + drilldownseries.h + +SOURCES += \ + drilldownchart.cpp \ + drilldownseries.cpp \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/stackedbarchartdrilldown +INSTALLS += target diff --git a/examples/charts/temperaturerecords/temperaturerecords.pro b/examples/charts/temperaturerecords/temperaturerecords.pro index e2eb6be3..b8f34907 100644 --- a/examples/charts/temperaturerecords/temperaturerecords.pro +++ b/examples/charts/temperaturerecords/temperaturerecords.pro @@ -1,6 +1,7 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} +QT += charts -TARGET = temperaturerecords -SOURCES += main.cpp +SOURCES += \ + main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/temperaturerecords +INSTALLS += target diff --git a/examples/charts/zoomlinechart/zoomlinechart.pro b/examples/charts/zoomlinechart/zoomlinechart.pro index c98161b2..a9f38f14 100644 --- a/examples/charts/zoomlinechart/zoomlinechart.pro +++ b/examples/charts/zoomlinechart/zoomlinechart.pro @@ -1,7 +1,13 @@ -!include( ../examples.pri ) { - error( "Couldn't find the examples.pri file!" ) -} -TARGET = zoomlinechart -HEADERS += chart.h chartview.h - -SOURCES += main.cpp chart.cpp chartview.cpp +QT += charts + +HEADERS += \ + chart.h \ + chartview.h + +SOURCES += \ + main.cpp \ + chart.cpp \ + chartview.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/charts/zoomlinechart +INSTALLS += target 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/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 f62fc806..c065787f 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(); diff --git a/src/chartsqml2/declarativebarseries.cpp b/src/chartsqml2/declarativebarseries.cpp index 70fbcf36..d335f9d5 100644 --- a/src/chartsqml2/declarativebarseries.cpp +++ b/src/chartsqml2/declarativebarseries.cpp @@ -87,12 +87,12 @@ void DeclarativeBarSet::setValues(QVariantList values) } } - QVector<int> indexValueList; + QVector<qreal> indexValueList; indexValueList.resize(maxValue + 1); for (int i = 0; i < values.count(); i++) { if (values.at(i).canConvert(QVariant::Point)) { - indexValueList.replace(values.at(i).toPoint().x(), values.at(i).toPoint().y()); + indexValueList.replace(values.at(i).toPoint().x(), values.at(i).toPointF().y()); } } diff --git a/src/chartsqml2/declarativechart.cpp b/src/chartsqml2/declarativechart.cpp index 967d9eaa..9a5b2678 100644 --- a/src/chartsqml2/declarativechart.cpp +++ b/src/chartsqml2/declarativechart.cpp @@ -587,13 +587,18 @@ QSGNode *DeclarativeChart::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdateP if (!node) { node = new DeclarativeChartNode(window()); + // Ensure that chart is rendered whenever node is recreated + if (m_sceneImage) + m_sceneImageDirty = true; } const QRectF &bRect = boundingRect(); // Update renderNode data if (node->renderNode()) { if (m_glXYDataManager->dataMap().size() || m_glXYDataManager->mapDirty()) { - const QRectF &plotArea = m_chart->plotArea(); + // Convert plotArea to QRect and back to QRectF to get rid of sub-pixel widths/heights + // which can cause unwanted partial antialising of the graph. + const QRectF plotArea = QRectF(m_chart->plotArea().toRect()); const QSizeF &chartAreaSize = m_chart->size(); // We can't use chart's plot area directly, as chart enforces a minimum size diff --git a/src/chartsqml2/declarativeopenglrendernode.cpp b/src/chartsqml2/declarativeopenglrendernode.cpp index c6c48e66..a0b4ec7f 100644 --- a/src/chartsqml2/declarativeopenglrendernode.cpp +++ b/src/chartsqml2/declarativeopenglrendernode.cpp @@ -290,39 +290,41 @@ void DeclarativeOpenGLRenderNode::renderGL(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); - - if (!vbo) { - vbo = new QOpenGLBuffer; - m_seriesBufferMap.insert(i.key(), vbo); - vbo->create(); - } - vbo->bind(); - if (data->dirty) { - vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat)); - data->dirty = false; - } + 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); + + if (!vbo) { + vbo = new QOpenGLBuffer; + m_seriesBufferMap.insert(i.key(), vbo); + vbo->create(); + } + vbo->bind(); + if (data->dirty) { + vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat)); + data->dirty = false; + } - 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(); } } diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 1b04ac7c..81557a7f 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -23,6 +23,7 @@ SUBDIRS += \ domain \ chartdataset \ qlegend \ + qareaseries \ cmake \ qcandlestickmodelmapper \ qcandlestickseries \ diff --git a/tests/auto/qareaseries/qareaseries.pro b/tests/auto/qareaseries/qareaseries.pro new file mode 100644 index 00000000..a87857ab --- /dev/null +++ b/tests/auto/qareaseries/qareaseries.pro @@ -0,0 +1,4 @@ +!include( ../auto.pri ) { + error( "Couldn't find the auto.pri file!" ) +} +SOURCES += tst_qareaseries.cpp diff --git a/tests/auto/qareaseries/tst_qareaseries.cpp b/tests/auto/qareaseries/tst_qareaseries.cpp new file mode 100644 index 00000000..e03989c0 --- /dev/null +++ b/tests/auto/qareaseries/tst_qareaseries.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ + +#include <QtTest/QtTest> +#include <QtGui/QImage> +#include <QtCharts/QChartView> +#include <QtCharts/QAreaSeries> +#include <QtCharts/QLineSeries> +#include <QtCharts/QChartView> +#include <QtCharts/QValueAxis> +#include <tst_definitions.h> + +QT_CHARTS_USE_NAMESPACE + +class tst_QAreaSeries : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void areaSeries(); + void dynamicEdgeSeriesChange(); + +protected: + QLineSeries *createUpperSeries(); + QLineSeries *createLowerSeries(); + void checkPixels(const QColor &upperColor, const QColor ¢erColor, const QColor &lowerColor); + + QChartView *m_view; + QChart *m_chart; + QColor m_brushColor; + QColor m_backgroundColor; + QValueAxis *m_axisX; + QValueAxis *m_axisY; +}; + +void tst_QAreaSeries::initTestCase() +{ + m_brushColor = QColor("#123456"); + m_backgroundColor = QColor("#abcfef"); +} + +void tst_QAreaSeries::cleanupTestCase() +{ + QTest::qWait(1); // Allow final deleteLaters to run +} + +void tst_QAreaSeries::init() +{ + m_view = new QChartView(newQChartOrQPolarChart()); + m_view->setGeometry(0, 0, 400, 400); + m_chart = m_view->chart(); + m_chart->setBackgroundBrush(m_backgroundColor); + m_chart->legend()->setVisible(false); + m_axisX = new QValueAxis; + m_axisY = new QValueAxis; + m_axisX->setRange(0, 4); + m_axisY->setRange(0, 10); + m_chart->addAxis(m_axisX, Qt::AlignBottom); + m_chart->addAxis(m_axisY, Qt::AlignRight); +} + +void tst_QAreaSeries::cleanup() +{ + delete m_view; + m_view = 0; + m_chart = 0; +} + +void tst_QAreaSeries::areaSeries() +{ + QLineSeries *series0 = createUpperSeries(); + QLineSeries *series1 = createLowerSeries(); + QAreaSeries *series = new QAreaSeries(series0, series1); + + QCOMPARE(series->brush(), QBrush()); + QCOMPARE(series->pen(), QPen()); + QCOMPARE(series->pointsVisible(), false); + QCOMPARE(series->pointLabelsVisible(), false); + QCOMPARE(series->pointLabelsFormat(), QLatin1String("@xPoint, @yPoint")); + QCOMPARE(series->pointLabelsClipping(), true); + QCOMPARE(series->pointLabelsColor(), QPen().color()); + QCOMPARE(series->upperSeries(), series0); + QCOMPARE(series->lowerSeries(), series1); + QCOMPARE(series->color(), QPen().color()); + QCOMPARE(series->borderColor(), QPen().color()); + + series->setBrush(QBrush(m_brushColor)); + m_chart->addSeries(series); + series->attachAxis(m_axisX); + series->attachAxis(m_axisY); + m_view->show(); + QTest::qWaitForWindowShown(m_view); + + checkPixels(m_backgroundColor, m_brushColor, m_backgroundColor); +} + +void tst_QAreaSeries::dynamicEdgeSeriesChange() +{ + QAreaSeries *series = new QAreaSeries; + series->setBrush(QBrush(m_brushColor)); + + m_chart->addSeries(series); + series->attachAxis(m_axisX); + series->attachAxis(m_axisY); + m_view->show(); + QTest::qWaitForWindowShown(m_view); + + checkPixels(m_backgroundColor, m_backgroundColor, m_backgroundColor); + + QLineSeries *series0 = createUpperSeries(); + series->setUpperSeries(series0); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_brushColor, m_brushColor); + + QLineSeries *series1 = createLowerSeries(); + series->setLowerSeries(series1); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_brushColor, m_backgroundColor); + + series->setLowerSeries(nullptr); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_brushColor, m_brushColor); + + series->setUpperSeries(nullptr); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_backgroundColor, m_backgroundColor); +} + +QLineSeries *tst_QAreaSeries::createUpperSeries() +{ + QLineSeries *series = new QLineSeries(); + *series << QPointF(0, 10) << QPointF(1, 7) << QPointF(2, 6) << QPointF(3, 7) << QPointF(4, 10); + return series; +} + +QLineSeries *tst_QAreaSeries::createLowerSeries() +{ + QLineSeries *series = new QLineSeries(); + *series << QPointF(0, 0) << QPointF(1, 3) << QPointF(2, 4) << QPointF(3, 3) << QPointF(4, 0); + return series; +} + +void tst_QAreaSeries::checkPixels(const QColor &upperColor, + const QColor ¢erColor, + const QColor &lowerColor) +{ + QImage screenGrab = m_view->grab().toImage(); + QCOMPARE(QColor(screenGrab.pixel(200, 50)), upperColor); + QCOMPARE(QColor(screenGrab.pixel(200, 200)), centerColor); + QCOMPARE(QColor(screenGrab.pixel(200, 350)), lowerColor); +} + +QTEST_MAIN(tst_QAreaSeries) + +#include "tst_qareaseries.moc" + |