##// END OF EJS Templates
better use of gradients in barcharts
sauimone -
r512:db1a02a52a65
parent child
Show More
@@ -1,82 +1,83
1 1 #include <QApplication>
2 2 #include <QMainWindow>
3 3 #include <QStandardItemModel>
4 4 #include <qpercentbarseries.h>
5 5 #include <qchartview.h>
6 6 #include <qbarset.h>
7 7 #include <qchartaxis.h>
8 8 #include <QStringList>
9 9
10 10 QTCOMMERCIALCHART_USE_NAMESPACE
11 11
12 12 int main(int argc, char *argv[])
13 13 {
14 14 QApplication a(argc, argv);
15 15 QMainWindow window;
16 16
17 17 //! [1]
18 18 // Define categories
19 19 QStringList categories;
20 20 categories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun";
21 21 //! [1]
22 22
23 23 //! [2]
24 24 // Create some test sets for chat
25 25 QBarSet *set0 = new QBarSet("Bub");
26 26 QBarSet *set1 = new QBarSet("Bob");
27 27 QBarSet *set2 = new QBarSet("Guybrush");
28 28 QBarSet *set3 = new QBarSet("Larry");
29 29 QBarSet *set4 = new QBarSet("Zak");
30 30
31 31 *set0 << 1 << 2 << 3 << 4 << 5 << 6;
32 32 *set1 << 5 << 0 << 0 << 4 << 0 << 7;
33 33 *set2 << 3 << 5 << 8 << 13 << 8 << 5;
34 34 *set3 << 5 << 6 << 7 << 3 << 4 << 5;
35 35 *set4 << 9 << 7 << 5 << 3 << 1 << 2;
36 36 //! [2]
37 37
38 38 //! [3]
39 39 // Create series and add sets to it
40 40 QPercentBarSeries* series = new QPercentBarSeries(categories);
41 41
42 42 series->addBarSet(set0);
43 43 series->addBarSet(set1);
44 44 series->addBarSet(set2);
45 45 series->addBarSet(set3);
46 46 series->addBarSet(set4);
47 47 //! [3]
48 48
49 49 //! [4]
50 50 // Enable tooltip
51 51 series->setToolTipEnabled();
52 52
53 53 // Connect clicked signal of set to toggle floating values of set.
54 54 // Note that we leave QBarset "Zak" unconnected here, so clicking on it doesn't toggle values.
55 55 QObject::connect(set0,SIGNAL(clicked(QString)),set0,SIGNAL(toggleFloatingValues()));
56 56 QObject::connect(set1,SIGNAL(clicked(QString)),set1,SIGNAL(toggleFloatingValues()));
57 57 QObject::connect(set2,SIGNAL(clicked(QString)),set2,SIGNAL(toggleFloatingValues()));
58 58 QObject::connect(set3,SIGNAL(clicked(QString)),set3,SIGNAL(toggleFloatingValues()));
59 QObject::connect(set4,SIGNAL(clicked(QString)),set4,SIGNAL(toggleFloatingValues()));
59 60 //! [4]
60 61
61 62 //! [5]
62 63 // Create view for chart and add series to it. Apply theme.
63 64
64 65 QChartView* chartView = new QChartView(&window);
65 66 chartView->addSeries(series);
66 67 chartView->setChartTitle("simple percent barchart");
67 68 chartView->setChartTheme(QChart::ChartThemeIcy);
68 69 //! [5]
69 70
70 71 //! [6]
71 72 chartView->axisX()->setAxisVisible(false);
72 73 chartView->axisX()->setGridVisible(false);
73 74 chartView->axisX()->setLabelsVisible(false);
74 75 //! [6]
75 76
76 77 window.setCentralWidget(chartView);
77 78 window.resize(400, 300);
78 79 window.show();
79 80
80 81 return a.exec();
81 82 }
82 83
@@ -1,95 +1,96
1 1 #include "barpresenter_p.h"
2 2 #include "bar_p.h"
3 3 #include "barvalue_p.h"
4 4 #include "separator_p.h"
5 5 #include "qbarset.h"
6 6 #include <QDebug>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 BarPresenter::BarPresenter(QBarSeries *series, QChart *parent) :
11 11 BarPresenterBase(series, parent)
12 12 {
13 13 }
14 14
15 15 void BarPresenter::layoutChanged()
16 16 {
17 17 // Scale bars to new layout
18 18 // Layout for bars:
19 19 if (mSeries->barsetCount() <= 0) {
20 20 qDebug() << "No sets in model!";
21 21 return;
22 22 }
23 23
24 24 if (childItems().count() == 0) {
25 25 qDebug() << "WARNING: BarPresenter::layoutChanged called before graphics items are created!";
26 26 return;
27 27 }
28 28
29 29 // Use temporary qreals for accurancy (we might get some compiler warnings... :)
30 30 int categoryCount = mSeries->categoryCount();
31 31 int setCount = mSeries->barsetCount();
32 32
33 33 qreal tW = mWidth;
34 34 qreal tH = mHeight;
35 35 qreal tM = mSeries->max();
36 36 qreal scale = (tH/tM);
37 37 qreal tC = categoryCount + 1;
38 38 qreal categoryWidth = tW/tC;
39 39 mBarWidth = categoryWidth / (setCount+1);
40 40
41 41 int itemIndex(0);
42 42 for (int category=0; category < categoryCount; category++) {
43 43 qreal xPos = categoryWidth * category + categoryWidth /2;
44 44 qreal yPos = mHeight;
45 45 for (int set = 0; set < setCount; set++) {
46 46 qreal barHeight = mSeries->valueAt(set,category) * scale;
47 47 Bar* bar = mBars.at(itemIndex);
48 48
49 49 // TODO: width settable per bar?
50 50 bar->resize(mBarWidth, barHeight);
51 51 bar->setBrush(mSeries->barsetAt(set)->brush());
52 52 bar->setPos(xPos, yPos-barHeight);
53 53 itemIndex++;
54 54 xPos += mBarWidth;
55 55 }
56 56 }
57 57
58 58 // Position separators
59 59 qreal xPos = categoryWidth + categoryWidth/2 - mBarWidth /2;
60 60 for (int s=0; s < mSeparators.count(); s++) {
61 61 Separator* sep = mSeparators.at(s);
62 62 sep->setPos(xPos,0);
63 63 sep->setSize(QSizeF(1,mHeight));
64 sep->setColor(QColor(255,0,0,255)); // TODO: color for separations from theme
64 65 xPos += categoryWidth;
65 66 }
66 67
67 68 // Position floating values
68 69 itemIndex = 0;
69 70 for (int category=0; category < mSeries->categoryCount(); category++) {
70 71 qreal xPos = categoryWidth * category + categoryWidth/2 + mBarWidth/2;
71 72 qreal yPos = mHeight;
72 73 for (int set=0; set < mSeries->barsetCount(); set++) {
73 74 qreal barHeight = mSeries->valueAt(set,category) * scale;
74 75 BarValue* value = mFloatingValues.at(itemIndex);
75 76
76 // TODO: remove hard coding, apply layout
77 value->resize(100,50);
77 QBarSet* barSet = mSeries->barsetAt(set);
78 value->resize(100,50); // TODO: proper layout for this.
78 79 value->setPos(xPos, yPos-barHeight/2);
79 value->setPen(QPen(QColor(255,255,255,255)));
80 value->setPen(barSet->floatingValuePen());
80 81
81 82 if (mSeries->valueAt(set,category) != 0) {
82 83 value->setValueString(QString::number(mSeries->valueAt(set,category)));
83 84 } else {
84 85 value->setValueString(QString(""));
85 86 }
86 87
87 88 itemIndex++;
88 89 xPos += mBarWidth;
89 90 }
90 91 }
91 92 }
92 93
93 94 #include "moc_barpresenter_p.cpp"
94 95
95 96 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,179 +1,178
1 1 #include "barpresenterbase_p.h"
2 2 #include "bar_p.h"
3 3 #include "barvalue_p.h"
4 4 #include "separator_p.h"
5 5 #include "qbarset.h"
6 6 #include "qbarseries.h"
7 7 #include "qchart.h"
8 8 #include "qchartaxis.h"
9 9 #include "qchartaxiscategories.h"
10 10 #include <QDebug>
11 11 #include <QToolTip>
12 12
13 13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 14
15 15 BarPresenterBase::BarPresenterBase(QBarSeries *series, QChart *parent)
16 16 : ChartItem(parent)
17 17 ,mLayoutSet(false)
18 18 ,mSeries(series)
19 19 ,mChart(parent)
20 20 {
21 21 connect(series,SIGNAL(showToolTip(QPoint,QString)),this,SLOT(showToolTip(QPoint,QString)));
22 22 connect(series,SIGNAL(enableSeparators(bool)),this,SLOT(enableSeparators(bool)));
23 23 enableSeparators(series->separatorsVisible());
24 24 initAxisLabels();
25 25 dataChanged();
26 26 }
27 27
28 28 BarPresenterBase::~BarPresenterBase()
29 29 {
30 30 disconnect(this,SLOT(showToolTip(QPoint,QString)));
31 31 disconnect(this,SLOT(enableSeparators(bool)));
32 32 }
33 33
34 34 void BarPresenterBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
35 35 {
36 36 if (!mLayoutSet) {
37 37 qDebug() << "BarPresenterBase::paint called without layout set. Aborting.";
38 38 return;
39 39 }
40 40 foreach(QGraphicsItem* i, childItems()) {
41 41 i->paint(painter,option,widget);
42 42 }
43 43 }
44 44
45 45 QRectF BarPresenterBase::boundingRect() const
46 46 {
47 47 return QRectF(0,0,mWidth,mHeight);
48 48 }
49 49
50 50 void BarPresenterBase::dataChanged()
51 51 {
52 52 // TODO: performance optimizations. Do we really need to delete and create items every time data is changed or can we reuse them?
53 53 // Delete old bars
54 54 foreach (QGraphicsItem* item, childItems()) {
55 55 delete item;
56 56 }
57 57
58 58 mBars.clear();
59 59 mSeparators.clear();
60 60 mFloatingValues.clear();
61 61
62 62 // Create new graphic items for bars
63 63 for (int c=0; c<mSeries->categoryCount(); c++) {
64 64 QString category = mSeries->categoryName(c);
65 65 for (int s=0; s<mSeries->barsetCount(); s++) {
66 66 QBarSet *set = mSeries->barsetAt(s);
67 67 Bar *bar = new Bar(category,this);
68 68 childItems().append(bar);
69 69 mBars.append(bar);
70 70 connect(bar,SIGNAL(clicked(QString)),set,SIGNAL(clicked(QString)));
71 71 connect(bar,SIGNAL(rightClicked(QString)),set,SIGNAL(rightClicked(QString)));
72 72 connect(bar,SIGNAL(hoverEntered(QPoint)),set,SLOT(barHoverEnterEvent(QPoint)));
73 73 connect(bar,SIGNAL(hoverLeaved()),set,SLOT(barHoverLeaveEvent()));
74 74 }
75 75 }
76 76
77 77 // Create separators
78 78 int count = mSeries->categoryCount() - 1; // There is one less separator than columns
79 79 for (int i=0; i<count; i++) {
80 80 Separator* sep = new Separator(this);
81 sep->setColor(QColor(255,0,0,255)); // TODO: color for separations from theme
82 81 sep->setVisible(mSeries->separatorsVisible());
83 82 childItems().append(sep);
84 83 mSeparators.append(sep);
85 84 }
86 85
87 86 // Create floating values
88 87 for (int category=0; category<mSeries->categoryCount(); category++) {
89 88 for (int s=0; s<mSeries->barsetCount(); s++) {
90 89 QBarSet *set = mSeries->barsetAt(s);
91 90 BarValue *value = new BarValue(*set, this);
92 91 childItems().append(value);
93 92 mFloatingValues.append(value);
94 93 connect(set,SIGNAL(toggleFloatingValues()),value,SLOT(toggleVisible()));
95 94 }
96 95 }
97 96 }
98 97
99 98 void BarPresenterBase::initAxisLabels()
100 99 {
101 100 int count = mSeries->categoryCount();
102 101 if (0 == count) {
103 102 return;
104 103 }
105 104
106 105 mChart->axisX()->setTicksCount(count+2);
107 106
108 107 qreal min = 0;
109 108 qreal max = count+1;
110 109
111 110 mChart->axisX()->setMin(min);
112 111 mChart->axisX()->setMax(max);
113 112
114 113 QChartAxisCategories* categories = mChart->axisX()->categories();
115 114 categories->clear();
116 115 for (int i=0; i<count; i++) {
117 116 categories->insert(i+1,mSeries->categoryName(i));
118 117 }
119 118
120 119
121 120
122 121 mChart->axisX()->setLabelsVisible(true);
123 122 }
124 123
125 124 //handlers
126 125
127 126 void BarPresenterBase::handleModelChanged(int index)
128 127 {
129 128 // qDebug() << "BarPresenterBase::handleModelChanged" << index;
130 129 dataChanged();
131 130 }
132 131
133 132 void BarPresenterBase::handleDomainChanged(const Domain& domain)
134 133 {
135 134 qDebug() << "BarPresenterBase::handleDomainChanged";
136 135 /*
137 136 int count = mSeries->categoryCount();
138 137 if (0 == count) {
139 138 return;
140 139 }
141 140
142 141 // Position labels to domain
143 142 qreal min = domain.minX();
144 143 qreal max = domain.maxX();
145 144 qreal step = (max-min)/count;
146 145 QChartAxisCategories& categories = mChart->axisX()->categories();
147 146 categories.clear();
148 147 for (int i=0; i<count; i++) {
149 148 categories.insert(min,mSeries->categoryName(i));
150 149 min += step;
151 150 }
152 151 */
153 152 }
154 153
155 154 void BarPresenterBase::handleGeometryChanged(const QRectF& rect)
156 155 {
157 156 mWidth = rect.width();
158 157 mHeight = rect.height();
159 158 layoutChanged();
160 159 mLayoutSet = true;
161 160 setPos(rect.topLeft());
162 161 }
163 162
164 163 void BarPresenterBase::showToolTip(QPoint pos, QString tip)
165 164 {
166 165 // TODO: cool tooltip instead of default
167 166 QToolTip::showText(pos,tip);
168 167 }
169 168
170 169 void BarPresenterBase::enableSeparators(bool enabled)
171 170 {
172 171 for (int i=0; i<mSeparators.count(); i++) {
173 172 mSeparators.at(i)->setVisible(enabled);
174 173 }
175 174 }
176 175
177 176 #include "moc_barpresenterbase_p.cpp"
178 177
179 178 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,103 +1,103
1 1 #include "percentbarpresenter_p.h"
2 2 #include "bar_p.h"
3 3 #include "barvalue_p.h"
4 4 #include "separator_p.h"
5 5 #include "qbarset.h"
6 6 #include <QDebug>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10
11 11 PercentBarPresenter::PercentBarPresenter(QBarSeries *series, QChart *parent) :
12 12 BarPresenterBase(series, parent)
13 13 {
14 14 }
15 15
16 16 void PercentBarPresenter::layoutChanged()
17 17 {
18 18 // Scale bars to new layout
19 19 // Layout for bars:
20 20 if (mSeries->barsetCount() <= 0) {
21 21 qDebug() << "No sets in model!";
22 22 // Nothing to do.
23 23 return;
24 24 }
25 25
26 26 if (childItems().count() == 0) {
27 27 qDebug() << "WARNING: PercentBarPresenter::layoutChanged called before graphics items are created!";
28 28 return;
29 29 }
30 30
31 31 // Use temporary qreals for accurancy (we might get some compiler warnings... :)
32 32 qreal tW = mWidth;
33 33 qreal tC = mSeries->categoryCount() + 1;
34 34 qreal cC = mSeries->categoryCount() * 2 + 1;
35 35 mBarWidth = tW / cC;
36 36 qreal xStep = (tW/tC);
37 37 qreal xPos = ((tW/tC) - mBarWidth / 2);
38 38 qreal h = mHeight;
39 39
40 40 int itemIndex(0);
41 41 for (int category = 0; category < mSeries->categoryCount(); category++) {
42 42 qreal colSum = mSeries->categorySum(category);
43 43 qreal scale = (h / colSum);
44 44 qreal yPos = h;
45 45 for (int set=0; set < mSeries->barsetCount(); set++) {
46 46 qreal barHeight = mSeries->valueAt(set, category) * scale;
47 47 Bar* bar = mBars.at(itemIndex);
48 48
49 49 // TODO: width settable per bar?
50 50 bar->resize(mBarWidth, barHeight);
51 51 bar->setBrush(mSeries->barsetAt(set)->brush());
52 52 bar->setPos(xPos, yPos-barHeight);
53 53 itemIndex++;
54 54 yPos -= barHeight;
55 55 }
56 56 xPos += xStep;
57 57 }
58 58
59 59 // Position separators
60 60 xPos = xStep + xStep/2;
61 61 for (int s=0; s < mSeries->categoryCount() - 1; s++) {
62 62 Separator* sep = mSeparators.at(s);
63 63 sep->setPos(xPos,0);
64 64 sep->setSize(QSizeF(1,mHeight));
65 65 xPos += xStep;
66 66 }
67 67
68 68 // Position floating values
69 69 itemIndex = 0;
70 70 xPos = (tW/tC);
71 71 for (int category=0; category < mSeries->categoryCount(); category++) {
72 72 qreal yPos = h;
73 73 qreal colSum = mSeries->categorySum(category);
74 74 qreal scale = (h / colSum);
75 75 for (int set=0; set < mSeries->barsetCount(); set++) {
76 76 qreal barHeight = mSeries->valueAt(set,category) * scale;
77 77 BarValue* value = mFloatingValues.at(itemIndex);
78 78
79 // TODO: remove hard coding, apply layout
80 value->resize(100,50);
79 QBarSet* barSet = mSeries->barsetAt(set);
80 value->resize(100,50); // TODO: proper layout for this.
81 81 value->setPos(xPos, yPos-barHeight/2);
82 value->setPen(QPen(QColor(255,255,255,255)));
82 value->setPen(barSet->floatingValuePen());
83 83
84 84 if (mSeries->valueAt(set,category) != 0) {
85 85 int p = mSeries->percentageAt(set,category) * 100;
86 86 QString vString(QString::number(p));
87 87 vString.truncate(3);
88 88 vString.append("%");
89 89 value->setValueString(vString);
90 90 } else {
91 91 value->setValueString(QString(""));
92 92 }
93 93
94 94 itemIndex++;
95 95 yPos -= barHeight;
96 96 }
97 97 xPos += xStep;
98 98 }
99 99 }
100 100
101 101 #include "moc_percentbarpresenter_p.cpp"
102 102
103 103 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,175 +1,191
1 1 #include "qbarset.h"
2 2 #include <QDebug>
3 3 #include <QToolTip>
4 4
5 5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6 6
7 7 /*!
8 8 \class QBarSet
9 9 \brief part of QtCommercial chart API.
10 10
11 11 QBarSet represents one set of bars. Set of bars contains one data value for each category.
12 12 First value of set is assumed to belong to first category, second to second category and so on.
13 13 If set has fewer values than there are categories, then the missing values are assumed to be
14 14 at the end of set. For missing values in middle of a set, numerical value of zero is used.
15 15
16 16 \mainclass
17 17
18 18 \sa QBarSeries, QStackedBarSeries, QPercentBarSeries
19 19 */
20 20
21 21 /*!
22 22 \fn void QBarSet::clicked(QString category)
23 23 \brief signals that set has been clicked
24 24 Parameter \a category describes on which category was clicked
25 25 */
26 26
27 27 /*!
28 28 \fn void QBarSet::rightClicked(QString category)
29 29 \brief signals that set has been clicked with right mouse button
30 30 Parameter \a category describes on which category was clicked
31 31 */
32 32
33 33 /*!
34 34 \fn void QBarSet::hoverEnter(QPoint pos)
35 35 \brief signals that mouse has entered over the set at position \a pos.
36 36 */
37 37
38 38 /*!
39 39 \fn void QBarSet::hoverLeave()
40 40 \brief signals that mouse has left from the set.
41 41 */
42 42
43 43 /*!
44 44 \fn void QBarSet::toggleFloatingValues()
45 45 \brief \internal
46 46 */
47 47
48 48 /*!
49 49 \fn void QBarSet::showToolTip(QPoint pos, QString tip)
50 50 \brief \internal \a pos \a tip
51 51 */
52 52
53 53
54 54 /*!
55 55 Constructs QBarSet with a name of \a name and with parent of \a parent
56 56 */
57 57 QBarSet::QBarSet(QString name, QObject *parent)
58 58 : QObject(parent)
59 59 ,mName(name)
60 60 {
61 61 }
62 62
63 63 /*!
64 64 Sets new \a name for set.
65 65 */
66 66 void QBarSet::setName(QString name)
67 67 {
68 68 mName = name;
69 69 }
70 70
71 71 /*!
72 72 Returns name of the set.
73 73 */
74 74 QString QBarSet::name()
75 75 {
76 76 return mName;
77 77 }
78 78
79 79 /*!
80 80 Appends new value \a value to the end of set.
81 81 */
82 82 QBarSet& QBarSet::operator << (const qreal &value)
83 83 {
84 84 mValues.append(value);
85 85 return *this;
86 86 }
87 87
88 88 /*!
89 89 Returns count of values in set.
90 90 */
91 91 int QBarSet::count()
92 92 {
93 93 return mValues.count();
94 94 }
95 95
96 96 /*!
97 97 Returns value of set indexed by \a index
98 98 */
99 99 qreal QBarSet::valueAt(int index)
100 100 {
101 101 return mValues.at(index);
102 102 }
103 103
104 104 /*!
105 105 Sets a new value \a value to set, indexed by \a index
106 106 */
107 107 void QBarSet::setValue(int index, qreal value)
108 108 {
109 109 mValues.replace(index,value);
110 110 }
111 111
112 112 /*!
113 113 Returns total sum of all values in barset.
114 114 */
115 115 qreal QBarSet::total()
116 116 {
117 117 qreal total(0);
118 118 for (int i=0; i<mValues.count(); i++) {
119 119 total += mValues.at(i);
120 120 }
121 121 return total;
122 122 }
123 123
124 124 /*!
125 125 Sets pen for set. Bars of this set are drawn using \a pen
126 126 */
127 127 void QBarSet::setPen(const QPen pen)
128 128 {
129 129 mPen = pen;
130 130 }
131 131
132 132 /*!
133 133 Returns pen of the set.
134 134 */
135 135 QPen QBarSet::pen() const
136 136 {
137 137 return mPen;
138 138 }
139 139
140 140 /*!
141 141 Sets brush for the set. Bars of this set are drawn using \a brush
142 142 */
143 143 void QBarSet::setBrush(const QBrush brush)
144 144 {
145 145 mBrush = brush;
146 146 }
147 147
148 148 /*!
149 149 Returns brush of the set.
150 150 */
151 151 QBrush QBarSet::brush() const
152 152 {
153 153 return mBrush;
154 154 }
155 155
156 156 /*!
157 Sets the pen for floating values that are drawn on top of this set
158 */
159 void QBarSet::setFloatingValuePen(const QPen pen)
160 {
161 mFloatingValuePen = pen;
162 }
163
164 /*!
165 Returns the pen for floating values that are drawn on top of this set
166 */
167 QPen QBarSet::floatingValuePen() const
168 {
169 return mFloatingValuePen;
170 }
171
172 /*!
157 173 \internal \a pos
158 174 */
159 175 void QBarSet::barHoverEnterEvent(QPoint pos)
160 176 {
161 177 emit showToolTip(pos, mName);
162 178 emit hoverEnter(pos);
163 179 }
164 180
165 181 /*!
166 182 \internal
167 183 */
168 184 void QBarSet::barHoverLeaveEvent()
169 185 {
170 186 // Emit signal to user of charts
171 187 emit hoverLeave();
172 188 }
173 189
174 190 #include "moc_qbarset.cpp"
175 191 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,67 +1,70
1 1 #ifndef QBARSET_H
2 2 #define QBARSET_H
3 3
4 4 #include <qchartglobal.h>
5 5 #include <QPen>
6 6 #include <QBrush>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 class QTCOMMERCIALCHART_EXPORT QBarSet : public QObject
11 11 {
12 12 Q_OBJECT
13 13 public:
14 14 QBarSet(QString name, QObject *parent = 0);
15 15
16 16 void setName(QString name);
17 17 QString name();
18 18 QBarSet& operator << (const qreal &value); // appends new value to set
19 19
20 20 // TODO: remove indices eventually. Use as internal?
21 21 int count(); // count of values in set
22 22 qreal valueAt(int index); // for modifying individual values
23 23 void setValue(int index, qreal value); // setter for individual value
24 24 qreal total(); // total values in the set
25 25
26 26 // TODO:
27 27 //qreal value(QString category);
28 28 //void setValue(QString category, qreal value);
29 29
30 30 void setPen(const QPen pen);
31 31 QPen pen() const;
32 32
33 33 void setBrush(const QBrush brush);
34 34 QBrush brush() const;
35 35
36 void setFloatingValuePen(const QPen pen);
37 QPen floatingValuePen() const;
38
36 39 Q_SIGNALS:
37 40 void clicked(QString category); // Clicked and hover signals exposed to user
38 41 void rightClicked(QString category);
39 42 void toggleFloatingValues();
40 43
41 44 // TODO: Expose this to user or not?
42 45 // TODO: TO PIMPL --->
43 46 void hoverEnter(QPoint pos);
44 47 void hoverLeave();
45 48 void showToolTip(QPoint pos, QString tip); // Private signal
46 49 // <--- TO PIMPL
47 50
48 51 public Q_SLOTS:
49 52 // These are for internal communication
50 53 // TODO: TO PIMPL --->
51 54 void barHoverEnterEvent(QPoint pos);
52 55 void barHoverLeaveEvent();
53 56 // <--- TO PIMPL
54 57
55 58 private:
56 59
57 60 QString mName;
58 61 QList<qreal> mValues; // TODO: replace with map (category, value)
59 62 QMap<QString,qreal> mMappedValues;
60 63 QPen mPen;
61 64 QBrush mBrush;
62
65 QPen mFloatingValuePen;
63 66 };
64 67
65 68 QTCOMMERCIALCHART_END_NAMESPACE
66 69
67 70 #endif // QBARSET_H
@@ -1,106 +1,106
1 1 #include "stackedbarpresenter_p.h"
2 2 #include "bar_p.h"
3 3 #include "barvalue_p.h"
4 4 #include "separator_p.h"
5 5 #include "qbarset.h"
6 6 #include <QDebug>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 StackedBarPresenter::StackedBarPresenter(QBarSeries *series, QChart *parent) :
11 11 BarPresenterBase(series,parent)
12 12 {
13 13 }
14 14
15 15 StackedBarPresenter::~StackedBarPresenter()
16 16 {
17 17 }
18 18
19 19
20 20 void StackedBarPresenter::layoutChanged()
21 21 {
22 22 // Scale bars to new layout
23 23 // Layout for bars:
24 24 if (mSeries->barsetCount() <= 0) {
25 25 qDebug() << "No sets in model!";
26 26 // Nothing to do.
27 27 return;
28 28 }
29 29
30 30 if (mSeries->categoryCount() == 0) {
31 31 qDebug() << "No categories in model!";
32 32 // Nothing to do
33 33 return;
34 34 }
35 35
36 36 if (childItems().count() == 0) {
37 37 qDebug() << "WARNING: StackedBarPresenter::layoutChanged called before graphics items are created!";
38 38 return;
39 39 }
40 40
41 41 // Use temporary qreals for accurancy (we might get some compiler warnings... :)
42 42 qreal maxSum = mSeries->maxCategorySum();
43 43 qreal h = mHeight;
44 44 qreal scale = (h / maxSum);
45 45 qreal tW = mWidth;
46 46 qreal tC = mSeries->categoryCount() + 1;
47 47 qreal cC = mSeries->categoryCount() * 2 + 1;
48 48 mBarWidth = tW / cC;
49 49 qreal xStep = (tW/tC);
50 50 qreal xPos = ((tW/tC) - mBarWidth / 2);
51 51
52 52 int itemIndex(0);
53 53 for (int category = 0; category < mSeries->categoryCount(); category++) {
54 54 qreal yPos = h;
55 55 for (int set=0; set < mSeries->barsetCount(); set++) {
56 56 qreal barHeight = mSeries->valueAt(set, category) * scale;
57 57 Bar* bar = mBars.at(itemIndex);
58 58
59 59 bar->resize(mBarWidth, barHeight);
60 60 bar->setBrush(mSeries->barsetAt(set)->brush());
61 61 bar->setPos(xPos, yPos-barHeight);
62 62 itemIndex++;
63 63 yPos -= barHeight;
64 64 }
65 65 xPos += xStep;
66 66 }
67 67
68 68 // Position separators
69 69 xPos = xStep + xStep/2;
70 70 for (int s=0; s < mSeries->categoryCount() - 1; s++) {
71 71 Separator* sep = mSeparators.at(s);
72 72 sep->setPos(xPos,0);
73 73 sep->setSize(QSizeF(1,mHeight));
74 74 xPos += xStep;
75 75 }
76 76
77 77 // Position floating values
78 78 itemIndex = 0;
79 79 xPos = (tW/tC);
80 80 for (int category=0; category < mSeries->categoryCount(); category++) {
81 81 qreal yPos = h;
82 82 for (int set=0; set < mSeries->barsetCount(); set++) {
83 83 qreal barHeight = mSeries->valueAt(set,category) * scale;
84 84 BarValue* value = mFloatingValues.at(itemIndex);
85 85
86 // TODO: remove hard coding, apply layout
87 value->resize(100,50);
86 QBarSet* barSet = mSeries->barsetAt(set);
87 value->resize(100,50); // TODO: proper layout for this.
88 88 value->setPos(xPos, yPos-barHeight/2);
89 value->setPen(QPen(QColor(255,255,255,255)));
89 value->setPen(barSet->floatingValuePen());
90 90
91 91 if (mSeries->valueAt(set,category) != 0) {
92 92 value->setValueString(QString::number(mSeries->valueAt(set,category)));
93 93 } else {
94 94 value->setValueString(QString(""));
95 95 }
96 96
97 97 itemIndex++;
98 98 yPos -= barHeight;
99 99 }
100 100 xPos += xStep;
101 101 }
102 102 }
103 103
104 104 #include "moc_stackedbarpresenter_p.cpp"
105 105
106 106 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,332 +1,356
1 1 #include "charttheme_p.h"
2 2 #include "qchart.h"
3 3 #include "qchartaxis.h"
4 4 #include <QTime>
5 5
6 6 //series
7 7 #include "qbarset.h"
8 8 #include "qbarseries.h"
9 9 #include "qstackedbarseries.h"
10 10 #include "qpercentbarseries.h"
11 11 #include "qlineseries.h"
12 12 #include "qareaseries.h"
13 13 #include "qscatterseries.h"
14 14 #include "qpieseries.h"
15 15 #include "qpieslice.h"
16 16 #include "qsplineseries.h"
17 17
18 18 //items
19 19 #include "axisitem_p.h"
20 20 #include "barpresenter_p.h"
21 21 #include "stackedbarpresenter_p.h"
22 22 #include "percentbarpresenter_p.h"
23 23 #include "linechartitem_p.h"
24 24 #include "areachartitem_p.h"
25 25 #include "scatterchartitem_p.h"
26 26 #include "piepresenter_p.h"
27 27 #include "splinechartitem_p.h"
28 28
29 29 //themes
30 30 #include "chartthemedefault_p.h"
31 31 #include "chartthemevanilla_p.h"
32 32 #include "chartthemeicy_p.h"
33 33 #include "chartthemegrayscale_p.h"
34 34 #include "chartthemescientific_p.h"
35 35
36 36
37 37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 38
39 39 ChartTheme::ChartTheme(QChart::ChartTheme id)
40 40 {
41 41 m_id = id;
42 42 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
43 43 }
44 44
45 45
46 46 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
47 47 {
48 48 switch(theme) {
49 49 case QChart::ChartThemeVanilla:
50 50 return new ChartThemeVanilla();
51 51 case QChart::ChartThemeIcy:
52 52 return new ChartThemeIcy();
53 53 case QChart::ChartThemeGrayscale:
54 54 return new ChartThemeGrayscale();
55 55 case QChart::ChartThemeScientific:
56 56 return new ChartThemeScientific();
57 57 default:
58 58 return new ChartThemeDefault();
59 59 }
60 60 }
61 61
62 62 void ChartTheme::decorate(QChart* chart)
63 63 {
64 64 chart->setChartBackgroundBrush(m_backgroundGradient);
65 65 }
66 66 //TODO helper to by removed later
67 67 void ChartTheme::decorate(ChartItem* item, QSeries* series,int count)
68 68 {
69 69 switch(series->type())
70 70 {
71 71 case QSeries::SeriesTypeLine: {
72 72 QLineSeries* s = static_cast<QLineSeries*>(series);
73 73 LineChartItem* i = static_cast<LineChartItem*>(item);
74 74 decorate(i,s,count);
75 75 break;
76 76 }
77 77 case QSeries::SeriesTypeArea: {
78 78 QAreaSeries* s = static_cast<QAreaSeries*>(series);
79 79 AreaChartItem* i = static_cast<AreaChartItem*>(item);
80 80 decorate(i,s,count);
81 81 break;
82 82 }
83 83 case QSeries::SeriesTypeBar: {
84 84 QBarSeries* b = static_cast<QBarSeries*>(series);
85 85 BarPresenter* i = static_cast<BarPresenter*>(item);
86 86 decorate(i,b,count);
87 87 break;
88 88 }
89 89 case QSeries::SeriesTypeStackedBar: {
90 90 QStackedBarSeries* s = static_cast<QStackedBarSeries*>(series);
91 91 StackedBarPresenter* i = static_cast<StackedBarPresenter*>(item);
92 92 decorate(i,s,count);
93 93 break;
94 94 }
95 95 case QSeries::SeriesTypePercentBar: {
96 96 QPercentBarSeries* s = static_cast<QPercentBarSeries*>(series);
97 97 PercentBarPresenter* i = static_cast<PercentBarPresenter*>(item);
98 98 decorate(i,s,count);
99 99 break;
100 100 }
101 101 case QSeries::SeriesTypeScatter: {
102 102 QScatterSeries* s = qobject_cast<QScatterSeries*>(series);
103 103 Q_ASSERT(s);
104 104 ScatterChartItem* i = static_cast<ScatterChartItem*>(item);
105 105 Q_ASSERT(i);
106 106 decorate(i, s, count);
107 107 break;
108 108 }
109 109 case QSeries::SeriesTypePie: {
110 110 QPieSeries* s = static_cast<QPieSeries*>(series);
111 111 PiePresenter* i = static_cast<PiePresenter*>(item);
112 112 decorate(i,s,count);
113 113 break;
114 114 }
115 115 default:
116 116 qDebug()<<"Wrong item to be decorated by theme";
117 117 break;
118 118 }
119 119
120 120 }
121 121
122 122 void ChartTheme::decorate(AreaChartItem* item, QAreaSeries* series,int count)
123 123 {
124 124 QPen pen;
125 125 QBrush brush;
126 126
127 127 if(pen != series->pen()){
128 128 item->setPen(series->pen());
129 129 }else{
130 130 pen.setColor(m_seriesColors.at(count%m_seriesColors.size()));
131 131 pen.setWidthF(2);
132 132 item->setPen(pen);
133 133 }
134 134
135 135 if(brush != series->brush()){
136 136 item->setBrush(series->brush());
137 137 }else{
138 138 QBrush brush(m_seriesColors.at(count%m_seriesColors.size()));
139 139 item->setBrush(brush);
140 140 }
141 141 }
142 142
143 143
144 144 void ChartTheme::decorate(LineChartItem* item, QLineSeries* series,int count)
145 145 {
146 146 QPen pen;
147 147 if(pen != series->pen()){
148 148 item->setLinePen(series->pen());
149 149 return;
150 150 }
151 151 pen.setColor(m_seriesColors.at(count%m_seriesColors.size()));
152 152 pen.setWidthF(2);
153 153 item->setLinePen(pen);
154 154 }
155 155
156 156 void ChartTheme::decorate(BarPresenter* item, QBarSeries* series,int count)
157 157 {
158 158 QList<QBarSet*> sets = series->barSets();
159 159 for (int i=0; i<sets.count(); i++) {
160 160 qreal pos = (qreal) i / (qreal) sets.count();
161 161 QColor c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), pos);
162 162 sets.at(i)->setBrush(QBrush(c));
163
164 // Pick label color as far as possible from bar color (within gradient).
165 // 0.3 is magic number that was picked as value that gave enough contrast with icy theme gradient :)
166 // TODO: better picking of label color?
167 if (pos < 0.3) {
168 c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 1);
169 } else {
170 c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 0);
171 }
172 sets.at(i)->setFloatingValuePen(QPen(c));
163 173 }
164 174 }
165 175
166 176 void ChartTheme::decorate(StackedBarPresenter* item, QStackedBarSeries* series,int count)
167 177 {
168 178 QList<QBarSet*> sets = series->barSets();
169 179 for (int i=0; i<sets.count(); i++) {
170 180 qreal pos = (qreal) i / (qreal) sets.count();
171 181 QColor c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), pos);
172 182 sets.at(i)->setBrush(QBrush(c));
183
184 if (pos < 0.3) {
185 c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 1);
186 } else {
187 c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 0);
188 }
189 sets.at(i)->setFloatingValuePen(QPen(c));
173 190 }
174 191 }
175 192
176 193 void ChartTheme::decorate(PercentBarPresenter* item, QPercentBarSeries* series,int count)
177 194 {
178 195 QList<QBarSet*> sets = series->barSets();
179 196 for (int i=0; i<sets.count(); i++) {
180 197 qreal pos = (qreal) i / (qreal) sets.count();
181 198 QColor c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), pos);
182 199 sets.at(i)->setBrush(QBrush(c));
200
201 if (pos < 0.3) {
202 c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 1);
203 } else {
204 c = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 0);
205 }
206 sets.at(i)->setFloatingValuePen(QPen(c));
183 207 }
184 208 }
185 209
186 210 void ChartTheme::decorate(ScatterChartItem* item, QScatterSeries* series, int count)
187 211 {
188 212 Q_ASSERT(item);
189 213 Q_ASSERT(series);
190 214
191 215 QColor color = m_seriesColors.at(count % m_seriesColors.size());
192 216 // TODO: define alpha in the theme? or in the series?
193 217 //color.setAlpha(120);
194 218
195 219 QBrush brush(color, Qt::SolidPattern);
196 220 item->setBrush(Qt::blue);
197 221
198 222 QPen pen(brush, 3);
199 223 pen.setColor(color);
200 224 item->setPen(pen);
201 225 }
202 226
203 227 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int count)
204 228 {
205 229 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
206 230 for (int i(0); i < series->slices().count(); i++) {
207 231 qreal pos = (qreal) i / (qreal) series->count();
208 232 QColor penColor = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 0.1);
209 233 series->slices().at(i)->setSlicePen(penColor);
210 234 QColor brushColor = colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), pos);
211 235 series->slices().at(i)->setSliceBrush(brushColor);
212 236 }
213 237 }
214 238
215 239
216 240 void ChartTheme::decorate(QChartAxis* axis, AxisItem* item)
217 241 {
218 242 //TODO: dummy defults for now
219 243 axis->setLabelsBrush(Qt::black);
220 244 axis->setLabelsPen(Qt::NoPen);
221 245 axis->setShadesPen(Qt::NoPen);
222 246 axis->setShadesOpacity(0.5);
223 247 }
224 248
225 249 void ChartTheme::decorate(SplineChartItem* item, QSplineSeries* series, int count)
226 250 {
227 251 Q_ASSERT(item);
228 252 Q_ASSERT(series);
229 253
230 254 QPen pen;
231 255
232 256 if(pen != series->pen()){
233 257 item->setLinePen(series->pen());
234 258 }else{
235 259 pen.setColor(m_seriesColors.at(count%m_seriesColors.size()));
236 260 pen.setWidthF(series->pen().widthF());
237 261 item->setLinePen(series->pen());
238 262 }
239 263
240 264 // QColor color = m_seriesColors.at(count % m_seriesColors.size());
241 265 // TODO: define alpha in the theme? or in the series?
242 266 //color.setAlpha(120);
243 267
244 268 // QBrush brush(color, Qt::SolidPattern);
245 269 // presenter->m_markerBrush = brush;
246 270
247 271 // QPen pen(brush, 3);
248 272 // pen.setColor(color);
249 273 // presenter->m_markerPen = pen;
250 274 }
251 275
252 276 void ChartTheme::generateSeriesGradients()
253 277 {
254 278 // Generate gradients in HSV color space
255 279 foreach (QColor color, m_seriesColors) {
256 280 QLinearGradient g;
257 281 qreal h = color.hsvHueF();
258 282 qreal s = color.hsvSaturationF();
259 283
260 284 // TODO: tune the algorithm to give nice results with most base colors defined in
261 285 // most themes. The rest of the gradients we can define manually in theme specific
262 286 // implementation.
263 287 QColor start = color;
264 288 start.setHsvF(h, 0.05, 0.95);
265 289 g.setColorAt(0.0, start);
266 290
267 291 g.setColorAt(0.5, color);
268 292
269 293 QColor end = color;
270 294 end.setHsvF(h, s, 0.25);
271 295 g.setColorAt(1.0, end);
272 296
273 297 m_seriesGradients << g;
274 298 }
275 299 }
276 300
277 301
278 302 QColor ChartTheme::colorAt(const QColor &start, const QColor &end, qreal pos)
279 303 {
280 304 Q_ASSERT(pos >=0.0 && pos <= 1.0);
281 305 qreal r = start.redF() + ((end.redF() - start.redF()) * pos);
282 306 qreal g = start.greenF() + ((end.greenF() - start.greenF()) * pos);
283 307 qreal b = start.blueF() + ((end.blueF() - start.blueF()) * pos);
284 308 QColor c;
285 309 c.setRgbF(r, g, b);
286 310 return c;
287 311 }
288 312
289 313 QColor ChartTheme::colorAt(const QGradient &gradient, qreal pos)
290 314 {
291 315 Q_ASSERT(pos >=0 && pos <= 1.0);
292 316
293 317 // another possibility:
294 318 // http://stackoverflow.com/questions/3306786/get-intermediate-color-from-a-gradient
295 319
296 320 QGradientStops stops = gradient.stops();
297 321 int count = stops.count();
298 322
299 323 // find previous stop relative to position
300 324 QGradientStop prev = stops.first();
301 325 for (int i=0; i<count; i++) {
302 326 QGradientStop stop = stops.at(i);
303 327 if (pos > stop.first)
304 328 prev = stop;
305 329
306 330 // given position is actually a stop position?
307 331 if (pos == stop.first) {
308 332 //qDebug() << "stop color" << pos;
309 333 return stop.second;
310 334 }
311 335 }
312 336
313 337 // find next stop relative to position
314 338 QGradientStop next = stops.last();
315 339 for (int i=count-1; i>=0; i--) {
316 340 QGradientStop stop = stops.at(i);
317 341 if (pos < stop.first)
318 342 next = stop;
319 343 }
320 344
321 345 //qDebug() << "prev" << prev.first << "pos" << pos << "next" << next.first;
322 346
323 347 qreal range = next.first - prev.first;
324 348 qreal posDelta = pos - prev.first;
325 349 qreal relativePos = posDelta / range;
326 350
327 351 //qDebug() << "range" << range << "posDelta" << posDelta << "relativePos" << relativePos;
328 352
329 353 return colorAt(prev.second, next.second, relativePos);
330 354 }
331 355
332 356 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now