diff --git a/examples/donut/widget.cpp b/examples/donut/widget.cpp index 19fb1cf..ba7cc5c 100644 --- a/examples/donut/widget.cpp +++ b/examples/donut/widget.cpp @@ -17,24 +17,29 @@ Widget::Widget(QWidget *parent) QChartView *chartView = new QChartView; chartView->setRenderHint(QPainter::Antialiasing); - for (int i = 0; i < 7; i++) { + qreal minSize = 0.1; + qreal maxSize = 0.9; + int donutsCount = 5; + for (int i = 0; i < donutsCount; i++) { QPieSeries *donut = new QPieSeries; + donut->setDonut(); donut->setLabelsVisible(); - for (int j = 0; j < 4; j++) { + int sliceCount = 3 + qrand() % 3; + for (int j = 0; j < sliceCount; j++) { qreal value = 100 + qrand() % 100; - donut->append(QString("%1").arg(value), value); + QPieSlice *slice = new QPieSlice(QString("%1").arg(value), value); + connect(slice, SIGNAL(hovered(bool)), this, SLOT(explodeSlice(bool))); + donut->append(slice); donut->slices().last()->setLabelVisible(true); -// QFont labelFont = donut->slices().last()->labelFont(); -// // labelFont.setUnderline(true); -// labelFont.setBold(true); -// donut->slices().last()->setLabelFont(labelFont); - donut->slices().last()->setLabelColor(Qt::white); + donut->slices().last()->setLabelColor(Qt::white); + donut->setDonutInnerSize(minSize + i * (maxSize - minSize) / donutsCount); + donut->setPieSize(minSize + (i + 1) * (maxSize - minSize) / donutsCount); } + m_donuts.append(donut); qreal phase = qrand() % 180; donut->setPieStartAngle(phase); donut->setPieEndAngle(360 + phase); chartView->chart()->addSeries(donut); - m_donutsGroup.append(donut); } // create main layout @@ -44,7 +49,7 @@ Widget::Widget(QWidget *parent) chartView->chart()->setAnimationOptions(QChart::AllAnimations); - QTimer *updateTimer = new QTimer(this); + updateTimer = new QTimer(this); connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateRotation())); updateTimer->start(750); } @@ -56,10 +61,35 @@ Widget::~Widget() void Widget::updateRotation() { - for (int i = 0; i < m_donutsGroup.count(); i++) { - QPieSeries *donut = m_donutsGroup.donuts().at(i); + // int tobeupdated = qrand() % m_donutsGroup.count(); + for (int i = 0; i < m_donuts.count(); i++) { + QPieSeries *donut = m_donuts.at(i); qreal phaseShift = -50 + qrand() % 100; donut->setPieStartAngle(donut->pieStartAngle() + phaseShift); donut->setPieEndAngle(donut->pieEndAngle() + phaseShift); } } + +void Widget::explodeSlice(bool exploded) +{ + QPieSlice *slice = qobject_cast(sender()); + if (exploded) { + updateTimer->stop(); + qreal sliceStartAngle = slice->startAngle(); + qreal sliceEndAngle = slice->startAngle() + slice->angleSpan(); + + QPieSeries *donut = slice->series(); + qreal seriesIndex = m_donuts.indexOf(donut); + for (int i = seriesIndex + 1; i < m_donuts.count(); i++) { + m_donuts.at(i)->setPieStartAngle(sliceEndAngle); + m_donuts.at(i)->setPieEndAngle(360 + sliceStartAngle); + } + } else { + for (int i = 0; i < m_donuts.count(); i++) { + m_donuts.at(i)->setPieStartAngle(0); + m_donuts.at(i)->setPieEndAngle(360); + } + updateTimer->start(); + } + slice->setExploded(exploded); +} diff --git a/examples/donut/widget.h b/examples/donut/widget.h index cc1ab07..79cd6cf 100644 --- a/examples/donut/widget.h +++ b/examples/donut/widget.h @@ -2,7 +2,9 @@ #define WIDGET_H #include -#include +#include + +class QTimer; QTCOMMERCIALCHART_USE_NAMESPACE @@ -16,9 +18,11 @@ public: public slots: void updateRotation(); + void explodeSlice(bool exploded); private: - QDonutGroup m_donutsGroup; + QList m_donuts; + QTimer *updateTimer; }; #endif // WIDGET_H diff --git a/examples/donutdrilldown/donutdrilldown.pro b/examples/donutdrilldown/donutdrilldown.pro new file mode 100644 index 0000000..671a8f2 --- /dev/null +++ b/examples/donutdrilldown/donutdrilldown.pro @@ -0,0 +1,9 @@ +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +TARGET = donutdrilldown +SOURCES += main.cpp\ + widget.cpp + +HEADERS += widget.h diff --git a/examples/donutdrilldown/main.cpp b/examples/donutdrilldown/main.cpp new file mode 100644 index 0000000..7b1f424 --- /dev/null +++ b/examples/donutdrilldown/main.cpp @@ -0,0 +1,11 @@ +#include +#include "widget.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Widget w; + w.show(); + + return a.exec(); +} diff --git a/examples/donutdrilldown/widget.cpp b/examples/donutdrilldown/widget.cpp new file mode 100644 index 0000000..fd749ba --- /dev/null +++ b/examples/donutdrilldown/widget.cpp @@ -0,0 +1,120 @@ +#include "widget.h" +#include + +#include +#include +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +Widget::Widget(QWidget *parent) + : QWidget(parent), + mainData(0) +{ + setMinimumSize(800, 600); + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + + QChartView *chartView = new QChartView; + chartView->setRenderHint(QPainter::Antialiasing); + chartView->chart()->setAnimationOptions(QChart::AllAnimations); + + mainData = new QPieSeries; + for (int j = 0; j < 4; j++) { + + // create new slice for the mainData + QPieSlice *slice = new QPieSlice; + slice->setLabelPosition(QPieSlice::LabelInside); + slice->setLabelColor(Qt::white); + mainData->append(slice); + + // create a new detailed data for the slice + QPieSeries *donut = new QPieSeries; + donut->setDonut(); + donut->setLabelsVisible(); + donut->setDonutInnerSize(mainData->pieSize()); + donut->setPieSize(mainData->pieSize() + 0.2); + + // when mainData slice is redrawn make sure the detailed data slices are aligned with it + connect(slice, SIGNAL(startAngleChanged()), this, SLOT(updatedStartAngle())); + connect(slice, SIGNAL(angleSpanChanged()), this, SLOT(updatedAngleSpan())); + + // create the detailed data + for (int j = 0; j < 3; j++) { + qreal value = 10 + qrand() % 100; + QPieSlice *slice = new QPieSlice(QString("%1").arg(value), value); + donut->append(slice); + donut->slices().last()->setLabelVisible(true); + donut->slices().last()->setLabelColor(Qt::white); + } + detailedData.append(donut); + + // update the value and label of mainData + slice->setValue(donut->sum()); + slice->setLabel(QString("%1").arg(donut->sum())); + } + + mainData->setLabelsVisible(); + chartView->chart()->addSeries(mainData); + for (int i = 0; i < detailedData.count(); i++) + chartView->chart()->addSeries(detailedData.at(i)); + + // create main layout + QGridLayout* mainLayout = new QGridLayout; + mainLayout->addWidget(chartView, 1, 1); + setLayout(mainLayout); + + // modify the value of one detailed slice every 2.5 sec + QTimer *updateTimer = new QTimer(this); + connect(updateTimer, SIGNAL(timeout()), this, SLOT(highlight())); + updateTimer->start(2500); +} + +Widget::~Widget() +{ + +} + +void Widget::updatedStartAngle() +{ + // when the mainData slice has been updated the detailed data QPieSeries object as well + QPieSlice* slice = qobject_cast(sender()); + QPieSeries *detailsDonut = detailedData.at(slice->series()->slices().indexOf(slice)); + detailsDonut->setPieStartAngle(slice->startAngle()); +} + +void Widget::updatedAngleSpan() +{ + // when the mainData slice has been updated the detailed data QPieSeries object as well + QPieSlice* slice = qobject_cast(sender()); + QPieSeries *detailsDonut = detailedData.at(slice->series()->slices().indexOf(slice)); + detailsDonut->setPieEndAngle(slice->startAngle() + slice->angleSpan()); +} + +void Widget::updateRotation() +{ + // update the selected slice + qreal newValue = 10 + qrand() % 100; + detailedData.at(detailIndex)->slices().at(sliceIndex)->setValue(newValue); + detailedData.at(detailIndex)->slices().at(sliceIndex)->setLabel(QString("%1").arg(newValue)); + + // update the mainData slice with a new sum of the detailed data values + mainData->slices().at(detailIndex)->setValue(detailedData.at(detailIndex)->sum()); + mainData->slices().at(detailIndex)->setLabel(QString("%1").arg(detailedData.at(detailIndex)->sum())); + + // change the explode state of the selected slice back to normal + detailedData.at(detailIndex)->slices().at(sliceIndex)->setExploded(false); +} + +void Widget::highlight() +{ + // choose one random detailed data slice to be updated. + detailIndex = qrand() % mainData->count(); + sliceIndex = qrand() % detailedData.at(detailIndex)->count(); + + // set the slice to exploded to make the change easier to observe + detailedData.at(detailIndex)->slices().at(sliceIndex)->setExploded(); + + // give the user time to focus on the slice that will be changed + QTimer::singleShot(1000, this, SLOT(updateRotation())); +} diff --git a/examples/donutdrilldown/widget.h b/examples/donutdrilldown/widget.h new file mode 100644 index 0000000..c03196c --- /dev/null +++ b/examples/donutdrilldown/widget.h @@ -0,0 +1,30 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +class Widget : public QWidget +{ + Q_OBJECT + +public: + Widget(QWidget *parent = 0); + ~Widget(); + +public slots: + void updatedStartAngle(); + void updatedAngleSpan(); + void updateRotation(); + void highlight(); + +private: + QPieSeries *mainData; + QList detailedData; + int detailIndex; + int sliceIndex; +}; + +#endif // WIDGET_H diff --git a/examples/examples.pro b/examples/examples.pro index a30cbb0..51c74ef 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -27,4 +27,5 @@ SUBDIRS += \ horizontalbarchart \ horizontalstackedbarchart \ horizontalpercentbarchart \ - donut + donut \ + donutdrilldown diff --git a/src/piechart/piechart.pri b/src/piechart/piechart.pri index 7bce39a..2c45c4e 100644 --- a/src/piechart/piechart.pri +++ b/src/piechart/piechart.pri @@ -8,8 +8,7 @@ SOURCES += \ $$PWD/qpieslice.cpp \ $$PWD/qpiemodelmapper.cpp \ $$PWD/qvpiemodelmapper.cpp \ - $$PWD/qhpiemodelmapper.cpp \ - piechart/qdonutgroup.cpp + $$PWD/qhpiemodelmapper.cpp PRIVATE_HEADERS += \ $$PWD/pieslicedata_p.h \ @@ -17,13 +16,11 @@ PRIVATE_HEADERS += \ $$PWD/piesliceitem_p.h \ $$PWD/qpieslice_p.h \ $$PWD/qpieseries_p.h \ - $$PWD/qpiemodelmapper_p.h \ - $$PWD/qdonutgroup_p.h + $$PWD/qpiemodelmapper_p.h PUBLIC_HEADERS += \ $$PWD/qpieseries.h \ $$PWD/qpieslice.h \ $$PWD/qpiemodelmapper.h \ $$PWD/qvpiemodelmapper.h \ - $$PWD/qhpiemodelmapper.h \ - $$PWD/qdonutgroup.h + $$PWD/qhpiemodelmapper.h diff --git a/src/piechart/piesliceitem.cpp b/src/piechart/piesliceitem.cpp index ee51148..83916a7 100644 --- a/src/piechart/piesliceitem.cpp +++ b/src/piechart/piesliceitem.cpp @@ -88,7 +88,7 @@ void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*op painter->translate(m_labelTextRect.center()); painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2); painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText); - }else if (m_data.m_labelPosition == QPieSlice::LabelOutside) { + } else if (m_data.m_labelPosition == QPieSlice::LabelOutside) { painter->setClipRect(parentItem()->boundingRect()); painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color()); painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText); diff --git a/src/piechart/qdonutgroup.cpp b/src/piechart/qdonutgroup.cpp deleted file mode 100644 index c958a55..0000000 --- a/src/piechart/qdonutgroup.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "qdonutgroup.h" -#include "qdonutgroup_p.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -QDonutGroup::QDonutGroup(QObject *parent) : - QObject(parent), - d_ptr(new QDonutGroupPrivate(this)) -{ -} - -void QDonutGroup::append(QPieSeries *donut) -{ - insert(count(), donut); -} - -bool QDonutGroup::insert(int index, QPieSeries* donut) -{ - if (donut == 0) - return false; - - donut->setDonut(); - Q_D(QDonutGroup); - d->m_donuts.insert(index, donut); - qreal donutFraction = 1.0 / (d->m_donuts.count() + 1); - for(int i = 0; i < d->m_donuts.count(); i++) { - d->m_donuts[i]->setPieSize( (i + 2) * donutFraction); - d->m_donuts[i]->setDonutInnerSize( (i + 1) * donutFraction); - } - return true; -} - -bool QDonutGroup::remove(QPieSeries* donut) -{ - Q_D(QDonutGroup); - int index = d->m_donuts.indexOf(donut); - if (index == -1) - return false; - else - d->m_donuts.removeOne(donut); - - return true; -} - -void QDonutGroup::clear() -{ - Q_D(QDonutGroup); - d->m_donuts.clear(); -} - -QList QDonutGroup::donuts() const -{ - Q_D(const QDonutGroup); - return d->m_donuts; -} - -int QDonutGroup::count() const -{ - Q_D(const QDonutGroup); - return d->m_donuts.count(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -QDonutGroupPrivate::QDonutGroupPrivate(QDonutGroup *q): - QObject(q), - q_ptr(q) -{ - // -} - -#include "moc_qdonutgroup.cpp" -#include "moc_qdonutgroup_p.cpp" - -QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/qdonutgroup.h b/src/piechart/qdonutgroup.h deleted file mode 100644 index 9de5760..0000000 --- a/src/piechart/qdonutgroup.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef QDONUTGROUP_H -#define QDONUTGROUP_H - -#include -#include - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -//class QPieSeries; -class QDonutGroupPrivate; - -class QTCOMMERCIALCHART_EXPORT QDonutGroup : public QObject -{ - Q_OBJECT -public: - explicit QDonutGroup(QObject *parent = 0); - - void append(QPieSeries *donut); - - bool insert(int index, QPieSeries* donut); - - bool remove(QPieSeries* donut); - void clear(); - - QList donuts() const; - int count() const; - -protected: - QDonutGroupPrivate * const d_ptr; - Q_DECLARE_PRIVATE(QDonutGroup) -}; - -QTCOMMERCIALCHART_END_NAMESPACE - -#endif // QDONUTGROUP_H diff --git a/src/piechart/qdonutgroup_p.h b/src/piechart/qdonutgroup_p.h deleted file mode 100644 index deb3f20..0000000 --- a/src/piechart/qdonutgroup_p.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef QDONUTGROUP_P_H -#define QDONUTGROUP_P_H - -#include -#include - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -class QPieSeries; - -class QDonutGroupPrivate : public QObject -{ - Q_OBJECT -public: - explicit QDonutGroupPrivate(QDonutGroup *q); - - void append(QPieSeries *donut); - -private: - QList m_donuts; - -private: - QDonutGroup *q_ptr; - Q_DECLARE_PUBLIC(QDonutGroup) -}; - -QTCOMMERCIALCHART_END_NAMESPACE - -#endif // QDONUTGROUP_P_H