From 5389336c8e0d244b3c995bf7db5d42393388e97d 2012-01-30 13:23:04 From: sauimone Date: 2012-01-30 13:23:04 Subject: [PATCH] percent bar chart --- diff --git a/example/percentbarchart/chartwidget.cpp b/example/percentbarchart/chartwidget.cpp new file mode 100644 index 0000000..d6c7532 --- /dev/null +++ b/example/percentbarchart/chartwidget.cpp @@ -0,0 +1,6 @@ +#include "chartwidget.h" + +ChartWidget::ChartWidget(QWidget *parent) : + QChartView(parent) +{ +} diff --git a/example/percentbarchart/chartwidget.h b/example/percentbarchart/chartwidget.h new file mode 100644 index 0000000..b5625e3 --- /dev/null +++ b/example/percentbarchart/chartwidget.h @@ -0,0 +1,21 @@ +#ifndef CHARTWIDGET_H +#define CHARTWIDGET_H + +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + + +class ChartWidget : public QChartView +{ + Q_OBJECT +public: + explicit ChartWidget(QWidget *parent = 0); + +signals: + +public slots: + +}; + +#endif // CHARTWIDGET_H diff --git a/example/percentbarchart/main.cpp b/example/percentbarchart/main.cpp new file mode 100644 index 0000000..056eb91 --- /dev/null +++ b/example/percentbarchart/main.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include "chartwidget.h" + +QTCOMMERCIALCHART_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QMainWindow window; + + PercentBarChartSeries* series0 = new PercentBarChartSeries(); + + // Create some test data to chart + QStandardItemModel dataModel(5,10); + QModelIndex index; + index = dataModel.index(0,0); + + // Series 0 + dataModel.setData(dataModel.index(0,0),1); + dataModel.setData(dataModel.index(0,1),2); + dataModel.setData(dataModel.index(0,2),3); + dataModel.setData(dataModel.index(0,3),4); + dataModel.setData(dataModel.index(0,4),5); + dataModel.setData(dataModel.index(0,5),6); + dataModel.setData(dataModel.index(0,6),7); + dataModel.setData(dataModel.index(0,7),8); + dataModel.setData(dataModel.index(0,8),9); + dataModel.setData(dataModel.index(0,9),10); + + // Series 1, some other items missing + dataModel.setData(dataModel.index(1,0),5); + dataModel.setData(dataModel.index(1,3),4); + dataModel.setData(dataModel.index(1,5),7); + dataModel.setData(dataModel.index(1,6),8); + dataModel.setData(dataModel.index(1,8),9); + dataModel.setData(dataModel.index(1,9),9); + + // Series 2 + dataModel.setData(dataModel.index(2,0),3); + dataModel.setData(dataModel.index(2,1),5); + dataModel.setData(dataModel.index(2,2),8); + dataModel.setData(dataModel.index(2,3),13); + dataModel.setData(dataModel.index(2,4),8); + dataModel.setData(dataModel.index(2,5),5); + dataModel.setData(dataModel.index(2,6),3); + dataModel.setData(dataModel.index(2,7),2); + dataModel.setData(dataModel.index(2,8),1); + dataModel.setData(dataModel.index(2,9),1); + + // Series 3 + dataModel.setData(dataModel.index(3,0),5); + dataModel.setData(dataModel.index(3,1),6); + dataModel.setData(dataModel.index(3,2),7); + dataModel.setData(dataModel.index(3,3),3); + dataModel.setData(dataModel.index(3,4),4); + dataModel.setData(dataModel.index(3,5),5); + dataModel.setData(dataModel.index(3,6),8); + dataModel.setData(dataModel.index(3,7),9); + dataModel.setData(dataModel.index(3,8),10); + dataModel.setData(dataModel.index(3,9),5); + + // Series 4 + dataModel.setData(dataModel.index(4,0),9); + dataModel.setData(dataModel.index(4,1),7); + dataModel.setData(dataModel.index(4,2),5); + dataModel.setData(dataModel.index(4,3),3); + dataModel.setData(dataModel.index(4,4),1); + dataModel.setData(dataModel.index(4,5),2); + dataModel.setData(dataModel.index(4,6),4); + dataModel.setData(dataModel.index(4,7),6); + dataModel.setData(dataModel.index(4,8),8); + dataModel.setData(dataModel.index(4,9),10); + + series0->setData(&dataModel); + + ChartWidget* chartWidget = new ChartWidget(&window); + chartWidget->addSeries(series0); + + window.setCentralWidget(chartWidget); + window.resize(400, 300); + window.show(); + + return a.exec(); +} + diff --git a/example/percentbarchart/percentbarchart.pro b/example/percentbarchart/percentbarchart.pro new file mode 100644 index 0000000..b2c8e0e --- /dev/null +++ b/example/percentbarchart/percentbarchart.pro @@ -0,0 +1,17 @@ +!include( ../../common.pri ) { + error( "Couldn't find the common.pri file!" ) +} + +!include( ../../integrated.pri ) { + error( "Couldn't find the integrated.pri file !") +} + +TARGET = percentbarchart +TEMPLATE = app +QT += core gui +SOURCES += main.cpp \ + chartwidget.cpp + +HEADERS += \ + chartwidget.h + diff --git a/src/barchart/bargroup.cpp b/src/barchart/bargroup.cpp index 984af6b..f19053c 100644 --- a/src/barchart/bargroup.cpp +++ b/src/barchart/bargroup.cpp @@ -28,6 +28,7 @@ void BarGroup::setPlotDomain(const PlotDomain& data) { qDebug() << "BarGroup::setPlotDomain"; // TODO: + mPlotDomain = data; } void BarGroup::setBarWidth( int w ) @@ -100,7 +101,7 @@ void BarGroup::layoutChanged() return; } - // TODO: better way to auto-layout + // TODO: better way to auto-layout? // Use reals for accurancy (we might get some compiler warnings... :) int columnCount = mSeries.countColumns(); int rowCount = mSeries.countRows(); @@ -113,17 +114,12 @@ void BarGroup::layoutChanged() qreal tC = columnCount+1; qreal xStepPerSeries = (tW/tC); - //qint startPos = (mWidth / (count+1)) - mSeries.countSeries() * mBarDefaultWidth /2; -// qDebug() << "XPOS:" << xPos; - qDebug() << "XSTEP:" << xStepPerSeries; - // TODO: Correct the calculations... // Scaling. int itemIndex(0); for (int column=0; column < columnCount; column++) { qreal xPos = xStepPerSeries * column + ((tW + mBarDefaultWidth*rowCount)/(columnCount*2)); - qDebug() << "XPOS:" << xPos; for (int row = 0; row < rowCount; row++) { qreal barHeight = mSeries.valueAt(row, column) * scale; Bar* bar = reinterpret_cast (childItems().at(itemIndex)); @@ -137,22 +133,6 @@ void BarGroup::layoutChanged() } } - /* - for (int series = 0; series < mSeries.countRows(); series++) { - for (int item=0; item < mSeries.countColumns(); item++) { - qreal barHeight = mSeries.valueAt(series, item) * scale; - Bar* bar = reinterpret_cast (childItems().at(itemIndex)); - - // TODO: width settable per bar? - bar->resize(mBarDefaultWidth, barHeight); - bar->setColor(mColors.at(series)); - bar->setPos(xPos, mHeight); // item*posStep+startPos + series * mBarDefaultWidth, mHeight); - itemIndex++; - xPos += mBarDefaultWidth; - } - xPos = xStepPerSeries * series; - } - */ mLayoutDirty = true; } diff --git a/src/barchart/bargroup.h b/src/barchart/bargroup.h index f630c7a..0dc8432 100644 --- a/src/barchart/bargroup.h +++ b/src/barchart/bargroup.h @@ -47,6 +47,8 @@ private: bool mLayoutDirty; QList mColors; // List of colors for series for now + + PlotDomain mPlotDomain; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/percentbarchartseries.cpp b/src/barchart/percentbarchartseries.cpp new file mode 100644 index 0000000..a373939 --- /dev/null +++ b/src/barchart/percentbarchartseries.cpp @@ -0,0 +1,110 @@ +#include "percentbarchartseries.h" + +#include +#include +#include "percentbarchartseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +PercentBarChartSeries::PercentBarChartSeries(QObject *parent) : + QChartSeries(parent) +{ +} + +bool PercentBarChartSeries::setData(QAbstractItemModel* model) +{ + mModel = model; +} + +int PercentBarChartSeries::min() +{ + Q_ASSERT(mModel->rowCount() > 0); + Q_ASSERT(mModel->columnCount() > 0); + + // TODO: make min and max members and update them when data changes. + // This is slower since they are checked every time, even if data is same since previous call. + int min = INT_MAX; + + for (int i=0; i rowCount(); i++) { + for(int j=0; jcolumnCount(); j++) { + int temp = mModel->data(mModel->index(i,j)).toInt(); + if (temp < min) { + min = temp; + } + } + } + return min; +} + +int PercentBarChartSeries::max() +{ + Q_ASSERT(mModel->rowCount() > 0); + Q_ASSERT(mModel->columnCount() > 0); + + // TODO: make min and max members and update them when data changes. + // This is slower since they are checked every time, even if data is same since previous call. + int max = INT_MIN; + + for (int i=0; i rowCount(); i++) { + for(int j=0; jcolumnCount(); j++) { + int temp = mModel->data(mModel->index(i,j)).toInt(); + if (temp > max) { + max = temp; + } + } + } + return max; +} + +int PercentBarChartSeries::maxColumnSum() +{ + Q_ASSERT(mModel->rowCount() > 0); + Q_ASSERT(mModel->columnCount() > 0); + + int max = INT_MIN; + + for (int col=0; col columnCount(); col++) { + int sum = columnSum(col); + if (sum > max) { + max = sum; + } + } + return max; +} + +int PercentBarChartSeries::countRows() +{ + return mModel->rowCount(); +} + +int PercentBarChartSeries::countColumns() +{ + return mModel->columnCount(); +} + +int PercentBarChartSeries::countTotalItems() +{ + return mModel->rowCount() * mModel->columnCount(); +} + +int PercentBarChartSeries::valueAt(int row, int column) +{ + QModelIndex index = mModel->index(row,column); + return mModel->data(index).toInt(); +} + +int PercentBarChartSeries::columnSum(int column) +{ + int sum(0); + int count = mModel->rowCount(); + + for (int row = 0; row < count; row++) { + sum += mModel->data(mModel->index(row,column)).toInt(); + } + return sum; +} + +#include "moc_percentbarchartseries.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE + diff --git a/src/barchart/percentbarchartseries.h b/src/barchart/percentbarchartseries.h new file mode 100644 index 0000000..a2cb80a --- /dev/null +++ b/src/barchart/percentbarchartseries.h @@ -0,0 +1,47 @@ +#ifndef PERCENTBARCHARTSERIES_H +#define PERCENTBARCHARTSERIES_H + +#include +#include +#include "qchartseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class PercentBarGroup; + +class QTCOMMERCIALCHART_EXPORT PercentBarChartSeries : public QChartSeries +{ + Q_OBJECT +public: + PercentBarChartSeries(QObject* parent=0); + + // from QChartSeries + virtual QChartSeriesType type() const { return QChartSeries::SeriesTypePercentBar; } + + // TODO: Better data model? + virtual bool setData(QAbstractItemModel* model); + + // Methods to find out minimum and maximum values of data + int min(); + int max(); + int maxColumnSum(); // returns maximum sum of items in all columns. + + int countRows(); + int countColumns(); + int countTotalItems(); + int valueAt(int row, int column); + + int columnSum(int column); + +public Q_SLOTS: + +private: + + QAbstractItemModel* mModel; + PercentBarGroup* mPercentBarGroup; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + + +#endif // PERCENTBARCHARTSERIES_H diff --git a/src/barchart/percentbargroup.cpp b/src/barchart/percentbargroup.cpp new file mode 100644 index 0000000..af4ed37 --- /dev/null +++ b/src/barchart/percentbargroup.cpp @@ -0,0 +1,136 @@ +#include "percentbargroup.h" + +#include "stackedbargroup.h" +#include "bar.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +StackedBarGroup::StackedBarGroup(StackedBarChartSeries& series, QGraphicsItem *parent) : + ChartItem(parent) + ,mSeries(series) + ,mLayoutSet(false) + ,mLayoutDirty(true) + ,mBarDefaultWidth(20) // TODO: remove hard coding, when we have layout code ready +{ + dataChanged(); +} + + +void StackedBarGroup::setSize(const QSize& size) +{ + qDebug() << "StackedBarGroup::setSize"; + mWidth = size.width(); + mHeight = size.height(); + layoutChanged(); + mLayoutSet = true; +} + +void StackedBarGroup::setPlotDomain(const PlotDomain& data) +{ + qDebug() << "StackedBarGroup::setPlotDomain"; + // TODO: +} + +void StackedBarGroup::setBarWidth( int w ) +{ + mBarDefaultWidth = w; +} + +int StackedBarGroup::addColor( QColor color ) +{ + int colorIndex = mColors.count(); + mColors.append(color); + return colorIndex; +} + +void StackedBarGroup::resetColors() +{ + mColors.clear(); +} + +void StackedBarGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + if (!mLayoutSet) { + qDebug() << "QBarChart::paint called without layout set. Aborting."; + return; + } + if (mLayoutDirty) { + // Layout or data has changed. Need to redraw. + foreach(QGraphicsItem* i, childItems()) { + i->paint(painter,option,widget); + } + } +} + +QRectF StackedBarGroup::boundingRect() const +{ + return QRectF(0,0,mWidth,mHeight); +} + + +void StackedBarGroup::dataChanged() +{ + qDebug() << "QBarChart::dataChanged mSeries"; + + // Find out maximum and minimum of all series + mMax = mSeries.max(); + mMin = mSeries.min(); + + // Delete old bars + // Is this correct way to delete childItems? + foreach (QGraphicsItem* item, childItems()) { + delete item; + } + + // Create new graphic items for bars + int totalItems = mSeries.countTotalItems(); + for (int i=0; i (childItems().at(itemIndex)); + + // TODO: width settable per bar? + bar->resize(mBarDefaultWidth, barHeight); + bar->setColor(mColors.at(row)); + bar->setPos(xPos, yPos); + itemIndex++; + yPos -= barHeight; + } + xPos += xStep; + } + mLayoutDirty = true; +} + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/percentbargroup.h b/src/barchart/percentbargroup.h new file mode 100644 index 0000000..e049c28 --- /dev/null +++ b/src/barchart/percentbargroup.h @@ -0,0 +1,55 @@ +#ifndef PERCENTBARGROUP_H +#define PERCENTBARGROUP_H + +#include "chartitem_p.h" +#include "bar.h" +#include "percentbarchartseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class PercentBarGroup : public ChartItem +{ +public: + PercentBarGroup(PercentBarChartSeries& series, QGraphicsItem *parent = 0); + + // From ChartItem + virtual void setSize(const QSize& size); + virtual void setPlotDomain(const PlotDomain& data); + + // Layout "api" + void setPos(qreal x, qreal y); + void setBarWidth( int w ); // Default width for each bar + + int addColor( QColor color ); + void resetColors(); + + // From QGraphicsItem + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QRectF boundingRect() const; + +private: + + void dataChanged(); // data of series has changed -> need to recalculate bar sizes + void layoutChanged(); // layout has changed -> need to recalculate bar sizes + +private: + + // Data + PercentBarChartSeries& mSeries; + int mMin; // Min and max values of data. (updated when data is changed, used when drawing) + int mMax; + + int mHeight; // Layout spesific + int mWidth; + int mBarDefaultWidth; + + bool mLayoutSet; // True, if component has been laid out. + bool mLayoutDirty; + + QList mColors; // List of colors for series for now + +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // PERCENTBARGROUP_H diff --git a/src/barchart/stackedbargroup.cpp b/src/barchart/stackedbargroup.cpp index 6ce7844..28242b3 100644 --- a/src/barchart/stackedbargroup.cpp +++ b/src/barchart/stackedbargroup.cpp @@ -1,10 +1,10 @@ -#include "stackedbargroup.h" +#include "percentbargroup.h" #include "bar.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE -StackedBarGroup::StackedBarGroup(StackedBarChartSeries& series, QGraphicsItem *parent) : +PercentBarGroup::PercentBarGroup(PercentBarChartSeries& series, QGraphicsItem *parent) : ChartItem(parent) ,mSeries(series) ,mLayoutSet(false) @@ -15,39 +15,39 @@ StackedBarGroup::StackedBarGroup(StackedBarChartSeries& series, QGraphicsItem *p } -void StackedBarGroup::setSize(const QSize& size) +void PercentBarGroup::setSize(const QSize& size) { - qDebug() << "StackedBarGroup::setSize"; + qDebug() << "PercentBarGroup::setSize"; mWidth = size.width(); mHeight = size.height(); layoutChanged(); mLayoutSet = true; } -void StackedBarGroup::setPlotDomain(const PlotDomain& data) +void PercentBarGroup::setPlotDomain(const PlotDomain& data) { - qDebug() << "StackedBarGroup::setPlotDomain"; + qDebug() << "PercentBarGroup::setPlotDomain"; // TODO: } -void StackedBarGroup::setBarWidth( int w ) +void PercentBarGroup::setBarWidth( int w ) { mBarDefaultWidth = w; } -int StackedBarGroup::addColor( QColor color ) +int PercentBarGroup::addColor( QColor color ) { int colorIndex = mColors.count(); mColors.append(color); return colorIndex; } -void StackedBarGroup::resetColors() +void PercentBarGroup::resetColors() { mColors.clear(); } -void StackedBarGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +void PercentBarGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { if (!mLayoutSet) { qDebug() << "QBarChart::paint called without layout set. Aborting."; @@ -61,13 +61,13 @@ void StackedBarGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *o } } -QRectF StackedBarGroup::boundingRect() const +QRectF PercentBarGroup::boundingRect() const { return QRectF(0,0,mWidth,mHeight); } -void StackedBarGroup::dataChanged() +void PercentBarGroup::dataChanged() { qDebug() << "QBarChart::dataChanged mSeries"; @@ -91,7 +91,7 @@ void StackedBarGroup::dataChanged() mLayoutDirty = true; } -void StackedBarGroup::layoutChanged() +void PercentBarGroup::layoutChanged() { // Scale bars to new layout // Layout for bars: @@ -102,10 +102,6 @@ void StackedBarGroup::layoutChanged() // TODO: better way to auto-layout // Use reals for accurancy (we might get some compiler warnings... :) - qreal maxSum = mSeries.maxColumnSum(); - qreal h = mHeight; - qreal scale = (h / maxSum); - int count = mSeries.countColumns(); int itemIndex(0); qreal tW = mWidth; @@ -114,6 +110,9 @@ void StackedBarGroup::layoutChanged() qreal xPos = ((tW/tC) + mBarDefaultWidth / 2); for (int column = 0; column < mSeries.countColumns(); column++) { + qreal colSum = mSeries.columnSum(column); + qreal h = mHeight; + qreal scale = (h / colSum); qreal yPos = h; for (int row=0; row < mSeries.countRows(); row++) { qreal barHeight = mSeries.valueAt(row, column) * scale; diff --git a/src/qchart.cpp b/src/qchart.cpp index ddb081c..81b2e3e 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -9,6 +9,8 @@ #include "bargroup.h" #include "stackedbarchartseries.h" #include "stackedbargroup.h" +#include "percentbarchartseries.h" +#include "percentbargroup.h" #include "xylinechartitem_p.h" #include "plotdomain_p.h" @@ -115,6 +117,23 @@ void QChart::addSeries(QChartSeries* series) childItems().append(stackedBarGroup); break; } + case QChartSeries::SeriesTypePercentBar: { + + qDebug() << "barSeries added"; + PercentBarChartSeries* percentBarSeries = static_cast(series); + PercentBarGroup* percentBarGroup = new PercentBarGroup(*percentBarSeries,this); + + // Add some fugly colors for 5 fist series... + percentBarGroup->addColor(QColor(255,0,0,128)); + percentBarGroup->addColor(QColor(255,255,0,128)); + percentBarGroup->addColor(QColor(0,255,0,128)); + percentBarGroup->addColor(QColor(0,0,255,128)); + percentBarGroup->addColor(QColor(255,128,0,128)); + + m_chartItems<(series); scatterSeries->d->setParentItem(this); @@ -164,6 +183,10 @@ QChartSeries* QChart::createSeries(QChartSeries::QChartSeriesType type) series = new StackedBarChartSeries(this); break; } + case QChartSeries::SeriesTypePercentBar: { + series = new PercentBarChartSeries(this); + break; + } case QChartSeries::SeriesTypeScatter: { series = new QScatterSeries(this); break; diff --git a/src/qchartseries.h b/src/qchartseries.h index 9677140..9cbceaa 100644 --- a/src/qchartseries.h +++ b/src/qchartseries.h @@ -16,6 +16,7 @@ public: // SeriesTypeArea, SeriesTypeBar, SeriesTypeStackedBar, + SeriesTypePercentBar, SeriesTypePie, SeriesTypeScatter // SeriesTypeSpline diff --git a/src/src.pro b/src/src.pro index cb12945..15f6655 100644 --- a/src/src.pro +++ b/src/src.pro @@ -17,6 +17,8 @@ SOURCES += \ barchart/bar.cpp \ barchart/stackedbarchartseries.cpp \ barchart/stackedbargroup.cpp \ + barchart/percentbarchartseries.cpp \ + barchart/percentbargroup.cpp \ xylinechart/qxychartseries.cpp \ xylinechart/xylinechartitem.cpp \ plotdomain.cpp \ @@ -50,6 +52,8 @@ PUBLIC_HEADERS += \ barchart/bargroup.h \ barchart/stackedbarchartseries.h \ barchart/stackedbargroup.h \ + barchart/percentbarchartseries.h \ + barchart/percentbargroup.h \ qchartview.h \ qchartaxis.h