From dd283485728c4e4b60fb49c2d278b5049971356c 2012-02-09 14:49:13 From: Tero Ahola Date: 2012-02-09 14:49:13 Subject: [PATCH] Integrated scatter again. Missing functionality. Fixed compilation issue in declarative part. --- diff --git a/qmlplugin/declarativeseries.cpp b/qmlplugin/declarativeseries.cpp index 6a131d9..db763f8 100644 --- a/qmlplugin/declarativeseries.cpp +++ b/qmlplugin/declarativeseries.cpp @@ -44,7 +44,7 @@ void DeclarativeSeries::initSeries() switch (m_seriesType) { case SeriesTypeLine: { - m_series = QLineChartSeries::create(this); + m_series = new QLineChartSeries(this); for (qreal i(0.0); i < 100.0; i += 1.0) ((QLineChartSeries *)m_series)->add(i, i); chart->addSeries(m_series); diff --git a/src/chartdataset.cpp b/src/chartdataset.cpp index 9544a0c..78469dc 100644 --- a/src/chartdataset.cpp +++ b/src/chartdataset.cpp @@ -5,6 +5,7 @@ #include "stackedbarchartseries.h" #include "percentbarchartseries.h" #include "qpieseries.h" +#include "qscatterseries.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -89,6 +90,18 @@ void ChartDataSet::addSeries(QChartSeries* series) break; } + case QChartSeries::SeriesTypeScatter: { + QScatterSeries *scatterSeries = qobject_cast(series); + Q_ASSERT(scatterSeries); + foreach (QPointF point, scatterSeries->data()) { + domain.m_minX = qMin(domain.m_minX, point.x()); + domain.m_maxX = qMax(domain.m_maxX, point.x()); + domain.m_minY = qMin(domain.m_minY, point.y()); + domain.m_maxY = qMax(domain.m_maxY, point.y()); + } + break; + } + default: { qDebug()<<__FUNCTION__<<"type" << series->type()<<"not supported"; return; diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index f3ba54a..0f03195 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -9,6 +9,7 @@ #include "percentbarchartseries.h" #include "qlinechartseries.h" #include "qpieseries.h" +#include "qscatterseries.h" //items #include "axisitem_p.h" #include "bargroup.h" @@ -17,6 +18,7 @@ #include "percentbargroup.h" #include "linechartanimationitem_p.h" #include "piepresenter.h" +#include "scatterpresenter.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -122,28 +124,19 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) m_chartItems.insert(series,item); break; } - /* - case QChartSeries::SeriesTypeScatter: { - QScatterSeries *scatterSeries = qobject_cast(series); - scatterSeries->d->m_theme = m_chartTheme->themeForSeries(); - scatterSeries->d->setParentItem(this); - scatterSeries->d->m_boundingRect = m_rect.adjusted(margin(),margin(), -margin(), -margin()); - m_chartItems << scatterSeries->d; - m_chartTheme->addObserver(scatterSeries->d); - - foreach (qreal x, scatterSeries->d->m_x) { - domain.m_minX = qMin(domain.m_minX, x); - domain.m_maxX = qMax(domain.m_maxX, x); - } - foreach (qreal y, scatterSeries->d->m_y) { - domain.m_minY = qMin(domain.m_minY, y); - domain.m_maxY = qMax(domain.m_maxY, y); - } - - break; - } - */ - + case QChartSeries::SeriesTypeScatter: { + QScatterSeries *scatterSeries = qobject_cast(series); + ScatterPresenter *scatterPresenter = new ScatterPresenter(scatterSeries, m_chart); + QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), + scatterPresenter, SLOT(handleGeometryChanged(const QRectF&))); + QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), + scatterPresenter, SLOT(handleDomainChanged(const Domain&))); +// scatterSeries->d->m_theme = m_chartTheme->themeForSeries(); +// scatterSeries->d->setParentItem(this); +// scatterSeries->d->m_boundingRect = m_rect.adjusted(margin(),margin(), -margin(), -margin()); + m_chartItems.insert(scatterSeries, scatterPresenter); + break; + } case QChartSeries::SeriesTypePie: { QPieSeries *pieSeries = qobject_cast(series); PiePresenter* pie = new PiePresenter(m_chart, pieSeries); @@ -153,7 +146,6 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) m_chartItems.insert(series, pie); break; } - default: { qDebug()<< "Series type" << series->type() << "not implemented."; break; diff --git a/src/qchart.cpp b/src/qchart.cpp index ca11d7e..bd7d45a 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -36,8 +36,6 @@ void QChart::addSeries(QChartSeries* series) //TODO on review, is it really needed ?? QChartSeries* QChart::createSeries(QChartSeries::QChartSeriesType type) { - // TODO: support also other types; not only scatter and pie - QChartSeries *series(0); switch (type) { diff --git a/src/qscatterseries.cpp b/src/qscatterseries.cpp index b01fa31..92a5ef2 100644 --- a/src/qscatterseries.cpp +++ b/src/qscatterseries.cpp @@ -1,138 +1,68 @@ #include "qscatterseries.h" #include "qscatterseries_p.h" #include "qchart.h" -#include -#include -#include QTCOMMERCIALCHART_BEGIN_NAMESPACE -//#define QSeriesData QList - -QScatterSeriesPrivate::QScatterSeriesPrivate(QGraphicsItem *parent) : - ChartItem(parent), - m_boundingRect(), - m_markerColor(QColor()), - m_visibleChartArea() +QScatterSeriesPrivate::QScatterSeriesPrivate() : + m_data(QList()) { - if (parent) - m_boundingRect = parent->boundingRect(); } -void QScatterSeriesPrivate::changeGeometry() -{ - if (m_boundingRect.isValid()) { - prepareGeometryChange(); - qreal scalex = m_boundingRect.width() / m_visibleChartArea.spanX(); - qreal scaley = m_boundingRect.height() / m_visibleChartArea.spanY(); - m_scenex.clear(); - m_sceney.clear(); - - // Convert relative coordinates to absolute pixel coordinates that can be used for drawing - foreach(qreal x, m_x) - m_scenex.append(m_boundingRect.left() + x * scalex - m_visibleChartArea.m_minX * scalex); - - foreach(qreal y, m_y) - m_sceney.append(m_boundingRect.bottom() - y * scaley + m_visibleChartArea.m_minY * scaley); - } -} - -void QScatterSeriesPrivate::setSize(const QSizeF &size) -{ -// m_boundingRect = QRectF(pos().x(), pos().y(), size.width(), size.height()); - m_boundingRect = QRectF(0, 0, size.width(), size.height()); - changeGeometry(); -} - -void QScatterSeriesPrivate::themeChanged(ChartTheme *theme) -{ - //m_theme = theme->themeForSeries(); -} - -void QScatterSeriesPrivate::setPlotDomain(const Domain& plotDomain) -{ - //m_visibleChartArea = plotDomain; - changeGeometry(); -} - -QRectF QScatterSeriesPrivate::boundingRect() const +QScatterSeries::QScatterSeries(QObject *parent) : + QChartSeries(parent), + d(new QScatterSeriesPrivate()) { - return m_boundingRect; } -void QScatterSeriesPrivate::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) -{ - // TODO: The opacity should be user definable? - //brush.setColor(QColor(255, 82, 0, 100)); - if (m_markerColor.isValid()) { - QPen pen = painter->pen(); - QBrush brush = pen.brush(); - brush.setColor(m_markerColor); - pen.setBrush(brush); - pen.setWidth(4); - painter->setPen(pen); - } - else - //painter->setPen(m_theme.markerPen); -// brush.setColor(m_theme..lineColor); - - // TODO: m_scenex and m_sceny are left empty during construction -> we would need a resize - // event right after construction or maybe given a size during initialization - for (int i(0); i < m_scenex.count() && i < m_sceney.count(); i++) { - if (scene()->width() > m_scenex.at(i) && scene()->height() > m_sceney.at(i)) - //painter->drawArc(m_scenex.at(i), m_sceney.at(i), 2, 2, 0, 5760); - painter->drawPoint(m_scenex.at(i), m_sceney.at(i)); - } -} - -QScatterSeries::QScatterSeries(QObject *parent) : - QChartSeries(parent), - d(new QScatterSeriesPrivate(qobject_cast (parent))) +QScatterSeries::~QScatterSeries() { + delete d; } +// TODO: change to list of QPointFs? bool QScatterSeries::setData(QList xlist, QList ylist) { + d->m_data.clear(); // TODO: validate data - d->m_x = xlist; - d->m_y = ylist; + for (int i(0); i < xlist.count() && i < ylist.count(); i++) { + d->m_data.append(QPointF(xlist[i], ylist[i])); + } + // TODO: the following updates the visible chart area setting of the series, we would instead // need to update the _chart's_ visible area... this would require a callback or // similar to the parenting QChart object... - foreach (qreal x, d->m_x) { - d->m_visibleChartArea.m_minX = qMin(d->m_visibleChartArea.m_minX, x); - d->m_visibleChartArea.m_maxX = qMax(d->m_visibleChartArea.m_maxX, x); - } - foreach (qreal y, d->m_y) { - d->m_visibleChartArea.m_minY = qMin(d->m_visibleChartArea.m_minY, y); - d->m_visibleChartArea.m_maxY = qMax(d->m_visibleChartArea.m_maxY, y); - } - - d->changeGeometry(); - +// foreach (qreal x, d->m_x) { +// d->m_visibleChartArea.m_minX = qMin(d->m_visibleChartArea.m_minX, x); +// d->m_visibleChartArea.m_maxX = qMax(d->m_visibleChartArea.m_maxX, x); +// } +// foreach (qreal y, d->m_y) { +// d->m_visibleChartArea.m_minY = qMin(d->m_visibleChartArea.m_minY, y); +// d->m_visibleChartArea.m_maxY = qMax(d->m_visibleChartArea.m_maxY, y); +// } +// d->changeGeometry(); + + emit changed(); return true; } -void QScatterSeries::setMarkerColor(QColor color) +QList QScatterSeries::data() { - d->m_markerColor = color; + return d->m_data; } -QColor QScatterSeries::markerColor() +void QScatterSeries::setMarkerColor(QColor color) { - return d->m_markerColor; + // TODO: +// d->m_markerColor = color; } -// TODO: -//void QScatterSeries::chartScaleChanged(qreal xscale, qreal yscale) -//{ -// d->rescale(xscale, yscale); -//} - -QScatterSeries::~QScatterSeries() +QColor QScatterSeries::markerColor() { - delete d; + // TODO: +// return d->m_markerColor; + return QColor(); } #include "moc_qscatterseries.cpp" diff --git a/src/qscatterseries.h b/src/qscatterseries.h index 5afee55..7c72359 100644 --- a/src/qscatterseries.h +++ b/src/qscatterseries.h @@ -20,17 +20,22 @@ public: // from QChartSeries QChartSeriesType type() const { return QChartSeries::SeriesTypeScatter; } bool setData(QList x, QList y); +public: + QList data(); +Q_SIGNALS: + // TODO: move to PIMPL? + // TODO: more finegrained signaling + void changed(); + public Q_SLOTS: // TODO: also affects opacity of the marker...? To be documented void setMarkerColor(QColor color); QColor markerColor(); // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot //void setMarkerShape(QChartSeries::MarkerShape/QScatterSeries::MarkerShape shape); - private: Q_DECLARE_PRIVATE(QScatterSeries) Q_DISABLE_COPY(QScatterSeries) - friend class QChart; QScatterSeriesPrivate *const d; }; diff --git a/src/qscatterseries_p.h b/src/qscatterseries_p.h index 896b8be..2893c64 100644 --- a/src/qscatterseries_p.h +++ b/src/qscatterseries_p.h @@ -1,45 +1,23 @@ #ifndef QSCATTERSERIESPRIVATE_H #define QSCATTERSERIESPRIVATE_H +#include "qchartglobal.h" #include "qchartseries.h" -#include "charttheme_p.h" -#include "chartitem_p.h" -#include "domain_p.h" -#include QTCOMMERCIALCHART_BEGIN_NAMESPACE /*! * The PIMPL class of QScatterSeries. */ -class QScatterSeriesPrivate : public ChartItem +class QScatterSeriesPrivate { public: - QScatterSeriesPrivate(QGraphicsItem *parent); - -public: // from ChartObjectInterface - void setSize(const QSizeF &size); - void setPlotDomain(const Domain& data); - -public: // from ChartThemeObserver - void themeChanged(ChartTheme *theme); - -public: // from QGraphicsItem - QRectF boundingRect() const; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QScatterSeriesPrivate(); public: - void changeGeometry(); - QRectF m_boundingRect; // TODO: use the chart data class instead of list of x and y values? - QList m_x; - QList m_y; - QList m_scenex; - QList m_sceney; - QColor m_markerColor; - //SeriesTheme m_theme; - Domain m_visibleChartArea; + QList m_data; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scatterpresenter.cpp b/src/scatterpresenter.cpp new file mode 100644 index 0000000..434cd21 --- /dev/null +++ b/src/scatterpresenter.cpp @@ -0,0 +1,93 @@ +#include "scatterpresenter.h" +#include "qscatterseries.h" +#include +#include +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent) : + ChartItem(parent), + m_series(series), + m_boundingRect(), + //m_markerColor(QColor()), + m_markerColor(QColor(255, 0, 0)), + m_visibleChartArea() +{ + if (parent) + m_boundingRect = parent->boundingRect(); + + if (series) { + connect(series, SIGNAL(changed()), this, SLOT(handleModelChanged())); + } +} + +void ScatterPresenter::handleDomainChanged(const Domain& domain) +{ + m_visibleChartArea = domain; + changeGeometry(); +} + +void ScatterPresenter::handleGeometryChanged(const QRectF& rect) +{ + m_boundingRect = rect; + changeGeometry(); +} + +void ScatterPresenter::handleModelChanged() +{ + // TODO: more fine grained modelChanged signaling + changeGeometry(); +} + +void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +{ + // TODO: The opacity should be user definable? + //brush.setColor(QColor(255, 82, 0, 100)); + if (m_markerColor.isValid()) { + QPen pen = painter->pen(); + QBrush brush = pen.brush(); + brush.setColor(m_markerColor); + pen.setBrush(brush); + pen.setWidth(4); + painter->setPen(pen); + } + else { + //painter->setPen(m_theme.markerPen); +// brush.setColor(m_theme..lineColor); + } + + // TODO: m_scenex and m_sceny are left empty during construction -> we would need a resize + // event right after construction or maybe given a size during initialization + qDebug() << "scene w: "<< scene()->width() << " h: " << scene()->height(); + for (int i(0); i < m_scenex.count() && i < m_sceney.count(); i++) { + qDebug() << "scene w: "<< scene()->width() << " h: " << scene()->height(); + qDebug() << "x: "<< m_scenex.at(i) << " y: " << m_sceney.at(i); + if (scene()->width() > m_scenex.at(i) && scene()->height() > m_sceney.at(i)) + //painter->drawArc(m_scenex.at(i), m_sceney.at(i), 2, 2, 0, 5760); + painter->drawPoint(m_scenex.at(i), m_sceney.at(i)); + } +} + +void ScatterPresenter::changeGeometry() +{ + if (m_boundingRect.isValid()) { + + prepareGeometryChange(); + qreal scalex = m_boundingRect.width() / m_visibleChartArea.spanX(); + qreal scaley = m_boundingRect.height() / m_visibleChartArea.spanY(); + m_scenex.clear(); + m_sceney.clear(); + + // Convert relative coordinates to absolute pixel coordinates that can be used for drawing + foreach (QPointF point, m_series->data()) { + m_scenex.append(m_boundingRect.left() + point.x() * scalex - m_visibleChartArea.m_minX * scalex); + m_sceney.append(m_boundingRect.bottom() - point.y() * scaley + m_visibleChartArea.m_minY * scaley); + } + } +} + +#include "moc_scatterpresenter.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scatterpresenter.h b/src/scatterpresenter.h new file mode 100644 index 0000000..6050c97 --- /dev/null +++ b/src/scatterpresenter.h @@ -0,0 +1,46 @@ +#ifndef SCATTERPRESENTER_H +#define SCATTERPRESENTER_H + +#include "qchartglobal.h" +#include "chartitem_p.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QScatterSeries; + +/*! + * The "business logic" of scatter series. This is a QObject that does not have a parent QObject. + * The QGraphicsItem parent owns the object instead. + */ +class ScatterPresenter : public QObject, public ChartItem +{ + Q_OBJECT +public: + explicit ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent = 0); + +public: // from ChartItem + QRectF boundingRect() const { return m_boundingRect; } + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + +signals: + +public Q_SLOTS: + void handleDomainChanged(const Domain& domain); + void handleGeometryChanged(const QRectF& rect); + void handleModelChanged(); + +public: + void changeGeometry(); + + QScatterSeries *m_series; + QRectF m_boundingRect; + QList m_scenex; + QList m_sceney; + QColor m_markerColor; + Domain m_visibleChartArea; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // SCATTERPRESENTER_H diff --git a/src/src.pro b/src/src.pro index af887e4..d054ce8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -21,6 +21,7 @@ SOURCES += barchart/barchartseries.cpp \ barchart/bargroupbase.cpp \ barchart/barchartseriesbase.cpp \ qscatterseries.cpp \ + #scatterpresentation.cpp \ qchart.cpp \ axisitem.cpp \ qchartview.cpp \ @@ -29,13 +30,15 @@ SOURCES += barchart/barchartseries.cpp \ charttheme.cpp \ chartdataset.cpp \ chartpresenter.cpp \ - domain.cpp + domain.cpp \ + scatterpresenter.cpp PRIVATE_HEADERS += linechart/linechartitem_p.h \ linechart/linechartanimationitem_p.h \ barchart/barlabel_p.h \ barchart/bar_p.h \ barchart/separator_p.h \ qscatterseries_p.h \ + #scatterpresentation.h \ axisitem_p.h \ chartitem_p.h \ charttheme_p.h \ @@ -64,7 +67,8 @@ THEMES += themes/chartthemeicy_p.h \ themes/chartthemegrayscale_p.h \ themes/chartthemescientific_p.h \ themes/chartthemevanilla_p.h -HEADERS += $$PUBLIC_HEADERS +HEADERS += $$PUBLIC_HEADERS \ + scatterpresenter.h HEADERS += $$PRIVATE_HEADERS HEADERS += $$THEMES INCLUDEPATH += linechart \ diff --git a/test/qmlchart/qml/qmlchart/main.qml b/test/qmlchart/qml/qmlchart/main.qml index cc63236..9d0daa0 100644 --- a/test/qmlchart/qml/qmlchart/main.qml +++ b/test/qmlchart/qml/qmlchart/main.qml @@ -13,9 +13,25 @@ Rectangle { anchors.fill: parent theme: Chart.ThemeIcy - Series { - seriesType: Series.SeriesTypePie +// PieSeries { +// labels: ["point1", "point2", "point3", "point4", "point5"] +// datax: [2, 1.5, 3, 3, 3] +// } + PieSeries { + name: "raspberry pie" + seriesLabels: ["point1", "point2", "point3", "point4", "point5"] + seriesData: [2, 1.5, 3, 3, 3] + } + ScatterSeries { + name: "scatter1" + datax: [2, 1.5, 3, 3, 3] + datay: [2, 1.5, 3, 3, 3] } +// Series { +// labels: ["point1", "point2", "point3", "point4", "point5"] +// datax: [2, 1.5, 3, 3, 3] +// seriesType: Series.SeriesTypePie +// } Series { seriesType: Series.SeriesTypeScatter }