From 73eb5fa755de3b611f3e395e757e7cb9df5b0b80 2012-01-22 20:39:56 From: Tero Ahola Date: 2012-01-22 20:39:56 Subject: [PATCH] Integrated draft version of pie series --- diff --git a/common.pri b/common.pri index db250bd..0429bf9 100644 --- a/common.pri +++ b/common.pri @@ -1,4 +1,4 @@ -CONFIG+=integrated_build #remove if you want to build against installed libs +#CONFIG+=integrated_build #remove if you want to build against installed libs CHART_BUILD_HEADER_DIR = $$PWD/include CHART_BUILD_LIB_DIR = $$PWD/lib diff --git a/src/pieslice.cpp b/src/pieslice.cpp new file mode 100644 index 0000000..d2800b3 --- /dev/null +++ b/src/pieslice.cpp @@ -0,0 +1,75 @@ +#include "pieslice.h" +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +PieSlice::PieSlice(const QColor& color, qreal startAngle, qreal span) + : m_color(color), + m_startAngle(startAngle), + m_span(span) +{ + setAcceptHoverEvents(true); +} + +PieSlice::~PieSlice() +{ +} + +QRectF PieSlice::boundingRect() const +{ + return parentItem()->boundingRect(); +} + +QPainterPath PieSlice::shape() const +{ + qreal angle = (-m_startAngle) + (90); + qreal span = -m_span; + + QPainterPath path; + path.moveTo(boundingRect().center()); + path.arcTo(boundingRect(), angle, span); + + // TODO: draw the shape so that it might have a hole in the center + // - Sin & Cos will be needed to find inner/outer arc endpoints + + // dx, dy are offsets from the center + //qreal l = boundingRect().height(); + //qreal dx = qSin(angle*(M_PI/180)) * l; + //qreal dy = qCos(angle*(M_PI/180)) * l; + + // TODO: exploded slice? + + return path; +} + +void PieSlice::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + // Setup painter + painter->setBrush(m_color); + QPen pen; + //pen.setColor(m_color.darker()); + pen.setColor(Qt::gray); + pen.setWidth(1); + painter->setPen(pen); + + // From Qt docs: + // The startAngle and spanAngle must be specified in 1/16th of a degree, i.e. a full circle equals 5760 (16 * 360). + // Positive values for the angles mean counter-clockwise while negative values mean the clockwise direction. + // Zero degrees is at the 3 o'clock position. + // + // For sake of simplicity convert this so that zero degrees is at 12 o'clock and full circle is 360. + //qreal angle = (-m_startAngle*16) + (90*16); + //qreal span = -m_span*16; + //painter->drawPie(boundingRect(), angle, span); + + painter->drawPath(shape()); +} + +void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent * event) +{ + QGraphicsItem::hoverEnterEvent(event); + qDebug() << "hover" << m_color << m_startAngle << m_span; +} + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/pieslice.h b/src/pieslice.h new file mode 100644 index 0000000..71c4dfd --- /dev/null +++ b/src/pieslice.h @@ -0,0 +1,31 @@ +#ifndef PIESLICE_H +#define PIESLICE_H + +#include "qchartglobal.h" +#include +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class PieSlice : public QGraphicsItem +{ +public: + PieSlice(const QColor& color, qreal startAngle, qreal span); + ~PieSlice(); + +public: // from QGraphicsItem + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void hoverEnterEvent(QGraphicsSceneHoverEvent * event); + +private: + QColor m_color; + qreal m_startAngle; + qreal m_span; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // PIESLICE_H diff --git a/src/qchart.cpp b/src/qchart.cpp index 1060322..1480451 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -2,6 +2,7 @@ #include "qchartseries.h" #include "qscatterseries.h" #include "qscatterseries_p.h" +#include "qpieseries.h" #include "qxychartseries.h" #include "xylinechartitem_p.h" #include "xyplotdomain_p.h" @@ -86,34 +87,45 @@ void QChart::addSeries(QChartSeries* series) d->m_xyLineChartItems<(series); - if (scatter) { - scatter->d->setParentItem(this); - scene()->addItem(scatter->d); - } - break; - } + // TODO: Not tested: +// case QChartSeries::SeriesTypeScatter: { +// QScatterSeries *scatter = qobject_cast(series); +// if (scatter) { +// scatter->d->setParentItem(this); +// scene()->addItem(scatter->d); +// } +// break; +// } } } QChartSeries* QChart::createSeries(QList x, QList y, QChartSeries::QChartSeriesType type) { - // TODO: support also other types in addition to scatter - Q_ASSERT(type == QChartSeries::SeriesTypeScatter); - QChartSeries *series = 0; + // TODO: support also other types; not only scatter and pie + Q_ASSERT(type == QChartSeries::SeriesTypeScatter + || type == QChartSeries::SeriesTypePie); switch (type) { case QChartSeries::SeriesTypeScatter: { QScatterSeries *scatterSeries = new QScatterSeries(x, y, this); + connect(this, SIGNAL(sizeChanged(QRectF, qreal, qreal)), + scatterSeries, SLOT(chartSizeChanged(QRectF, qreal, qreal))); scatterSeries->d->setParentItem(this); - break; + return scatterSeries; + } + case QChartSeries::SeriesTypePie: { + // TODO: we now have also a list of y values as a parameter, it is ignored + // we should use a generic data class instead of list of x and y values + QPieSeries *pieSeries = new QPieSeries(x, this); + connect(this, SIGNAL(sizeChanged(QRectF, qreal, qreal)), + pieSeries, SLOT(chartSizeChanged(QRectF, qreal, qreal))); + return pieSeries; } default: break; } - return series; + return 0; } void QChart::setSize(const QSizeF& size) diff --git a/src/qchartseries.h b/src/qchartseries.h index 6bb158d..54d5d54 100644 --- a/src/qchartseries.h +++ b/src/qchartseries.h @@ -14,7 +14,7 @@ public: SeriesTypeLine = 0, // SeriesTypeArea, // SeriesTypeBar, -// SeriesTypePie, + SeriesTypePie, SeriesTypeScatter // SeriesTypeSpline }; diff --git a/src/qpieseries.cpp b/src/qpieseries.cpp new file mode 100644 index 0000000..35907fa --- /dev/null +++ b/src/qpieseries.cpp @@ -0,0 +1,54 @@ +#include "qpieseries.h" +#include "pieslice.h" +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +QPieSeries::QPieSeries(QList x, QGraphicsObject *parent) : + QChartSeries(parent), + m_x(x) +{ +} + +QPieSeries::~QPieSeries() +{ +} + +void QPieSeries::chartSizeChanged(QRectF rect, qreal xscale, qreal yscale) +{ + qreal fullPie = 360; + qreal total = 0; + foreach (qreal value, m_x) + total += value; + + // We must have a parent for the graphics items we create + // TODO: maybe QChartSeries needs to be a QGraphicsObject to make this clear for the users? + QGraphicsItem *parentItem = qobject_cast(parent()); + Q_ASSERT(parentItem); + qreal angle = 0; + foreach (qreal value, m_x) { + qreal span = value / total * fullPie; + PieSlice *slice = new PieSlice(randomColor(), angle, span); + slice->setParentItem(parentItem); + m_slices.append(slice); + angle += span; + } +} + +QColor QPieSeries::randomColor() +{ + QColor c; + c.setRed(qrand() % 255); + c.setGreen(qrand() % 255); + c.setBlue(qrand() % 255); + return c; +} + +void QPieSeries::setData(QList data) +{ +} + +#include "moc_qpieseries.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/qpieseries.h b/src/qpieseries.h new file mode 100644 index 0000000..4d48bd7 --- /dev/null +++ b/src/qpieseries.h @@ -0,0 +1,40 @@ +#ifndef PIESERIES_H +#define PIESERIES_H + +#include "qchartseries.h" +#include +#include +#include + +class QGraphicsObject; +QTCOMMERCIALCHART_BEGIN_NAMESPACE +class PieSlice; + +class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries +{ + Q_OBJECT +public: + // TODO: use a generic data class instead of x and y + QPieSeries(QList x, QGraphicsObject *parent = 0); + ~QPieSeries(); + QColor randomColor(); + void setData(QList data); + +public: // from QChartSeries + QChartSeriesType type() const { return QChartSeries::SeriesTypePie; } + +public Q_SLOTS: + void chartSizeChanged(QRectF rect, qreal xscale, qreal yscale); + +private: + //Q_DECLARE_PRIVATE(QPieSeries) + Q_DISABLE_COPY(QPieSeries) + // TODO: move the followin to internal impl + QList m_x; + QList m_slices; + QSizeF m_size; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // PIESERIES_H diff --git a/src/qscatterseries.cpp b/src/qscatterseries.cpp index cfb723e..7033e31 100644 --- a/src/qscatterseries.cpp +++ b/src/qscatterseries.cpp @@ -56,7 +56,6 @@ QScatterSeries::QScatterSeries(QList x, QList y, QObject *parent) QChartSeries(parent), d(new QScatterSeriesPrivate(x, y, qobject_cast (parent))) { - connect(parent, SIGNAL(sizeChanged(QRectF, qreal, qreal)), this, SLOT(chartSizeChanged(QRectF, qreal, qreal))); } void QScatterSeries::chartSizeChanged(QRectF rect, qreal xscale, qreal yscale) diff --git a/src/qscatterseries.h b/src/qscatterseries.h index f35d85c..8c5197c 100644 --- a/src/qscatterseries.h +++ b/src/qscatterseries.h @@ -12,11 +12,11 @@ class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QChartSeries Q_OBJECT public: //QScatterSeries(QSeriesData *data, QObject *chart); - QScatterSeries(QList x, QList y, QObject *chart = 0); + QScatterSeries(QList x, QList y, QObject *parent = 0); ~QScatterSeries(); public: // from QChartSeries - virtual QChartSeriesType type() const { return QChartSeries::SeriesTypeScatter; } + QChartSeriesType type() const { return QChartSeries::SeriesTypeScatter; } public Q_SLOTS: void chartSizeChanged(QRectF rect, qreal xscale, qreal yscale); diff --git a/src/src.pro b/src/src.pro index 866780c..e597449 100644 --- a/src/src.pro +++ b/src/src.pro @@ -17,20 +17,24 @@ SOURCES += \ xylinechart/xygrid.cpp \ xylinechart/xyplotdomain.cpp \ qscatterseries.cpp \ + qpieseries.cpp \ qchart.cpp \ axis.cpp \ - qchartwidget.cpp + qchartwidget.cpp \ + pieslice.cpp PRIVATE_HEADERS += \ xylinechart/xylinechartitem_p.h \ xylinechart/xyplotdomain_p.h \ xylinechart/xygrid_p.h \ qscatterseries_p.h \ + pieslice.h \ axis_p.h PUBLIC_HEADERS += \ qchartseries.h \ qscatterseries.h \ + qpieseries.h \ qchart.h \ qchartwidget.h \ qchartglobal.h \ @@ -73,3 +77,5 @@ QMAKE_EXTRA_TARGETS += chartversion unix:QMAKE_DISTCLEAN += -r $$CHART_BUILD_HEADER_DIR $$CHART_BUILD_LIB_DIR win32:QMAKE_DISTCLEAN += /Q $$CHART_BUILD_HEADER_DIR $$CHART_BUILD_LIB_DIR + + diff --git a/test/chartwidgettest/mainwidget.cpp b/test/chartwidgettest/mainwidget.cpp index c46f1f5..f37845f 100644 --- a/test/chartwidgettest/mainwidget.cpp +++ b/test/chartwidgettest/mainwidget.cpp @@ -142,6 +142,8 @@ void MainWidget::addSeries(QString series, QString data) if (series == "Scatter") { /*QChartSeries* scatterSeries = */ m_chartWidget->createSeries(x, y, QChartSeries::SeriesTypeScatter); + } else if (series == "Pie") { + m_chartWidget->createSeries(x, y, QChartSeries::SeriesTypePie); } else if (series == "Line") { m_chartWidget->addSeries(series0); } else {