##// END OF EJS Templates
barchart domain fix
sauimone -
r674:2c12358822ee
parent child
Show More
@@ -1,275 +1,281
1 1 #include "barchartitem_p.h"
2 2 #include "bar_p.h"
3 3 #include "barvalue_p.h"
4 4 #include "qbarset.h"
5 5 #include "qbarseries.h"
6 6 #include "qchart.h"
7 7 #include "qchartaxis.h"
8 8 #include "qchartaxiscategories.h"
9 9 #include "chartpresenter_p.h"
10 10 #include "chartanimator_p.h"
11 11 #include <QDebug>
12 12 #include <QToolTip>
13 13
14 14 QTCOMMERCIALCHART_BEGIN_NAMESPACE
15 15
16 16 BarChartItem::BarChartItem(QBarSeries *series, QChart *parent) :
17 17 ChartItem(parent),
18 18 mHeight(0),
19 19 mWidth(0),
20 20 mLayoutSet(false),
21 21 mSeries(series),
22 22 mChart(parent)
23 23 {
24 24 connect(series,SIGNAL(showToolTip(QPoint,QString)),this,SLOT(showToolTip(QPoint,QString)));
25 25 connect(series, SIGNAL(updatedBars()), this, SLOT(layoutChanged()));
26 26 //TODO: connect(series,SIGNAL("position or size has changed"), this, SLOT(handleLayoutChanged()));
27 27 connect(series, SIGNAL(restructuredBar(int)), this, SLOT(handleModelChanged(int)));
28 28 setZValue(ChartPresenter::BarSeriesZValue);
29 29 initAxisLabels();
30 30 dataChanged();
31 31 }
32 32
33 33 BarChartItem::~BarChartItem()
34 34 {
35 35 disconnect(this,SLOT(showToolTip(QPoint,QString)));
36 36 }
37 37
38 38 void BarChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
39 39 {
40 40 if (!mLayoutSet) {
41 41 qDebug() << "BarChartItem::paint called without layout set. Aborting.";
42 42 return;
43 43 }
44 44 foreach(QGraphicsItem* i, childItems()) {
45 45 i->paint(painter,option,widget);
46 46 }
47 47 }
48 48
49 49 QRectF BarChartItem::boundingRect() const
50 50 {
51 51 return QRectF(0, 0, mWidth, mHeight);
52 52 }
53 53
54 54 void BarChartItem::dataChanged()
55 55 {
56 56 // TODO: performance optimizations. Do we really need to delete and create items every time data is changed or can we reuse them?
57 57 // Delete old bars
58 58 foreach (QGraphicsItem* item, childItems()) {
59 59 delete item;
60 60 }
61 61
62 62 mBars.clear();
63 63 mFloatingValues.clear();
64 64
65 65 // Create new graphic items for bars
66 66 for (int c=0; c<mSeries->categoryCount(); c++) {
67 67 QString category = mSeries->categoryName(c);
68 68 for (int s=0; s<mSeries->barsetCount(); s++) {
69 69 QBarSet *set = mSeries->barsetAt(s);
70 70 Bar *bar = new Bar(category,this);
71 71 childItems().append(bar);
72 72 mBars.append(bar);
73 73 connect(bar,SIGNAL(clicked(QString)),set,SIGNAL(clicked(QString)));
74 74 connect(bar,SIGNAL(rightClicked(QString)),set,SIGNAL(rightClicked(QString)));
75 75 connect(bar,SIGNAL(hoverEntered(QPoint)),set,SLOT(barHoverEnterEvent(QPoint)));
76 76 connect(bar,SIGNAL(hoverLeaved()),set,SLOT(barHoverLeaveEvent()));
77 77 }
78 78 }
79 79
80 80 // Create floating values
81 81 for (int category=0; category<mSeries->categoryCount(); category++) {
82 82 for (int s=0; s<mSeries->barsetCount(); s++) {
83 83 QBarSet *set = mSeries->barsetAt(s);
84 84 BarValue *value = new BarValue(*set, this);
85 85 childItems().append(value);
86 86 mFloatingValues.append(value);
87 87 connect(set,SIGNAL(toggleFloatingValues()),value,SLOT(toggleVisible()));
88 88 }
89 89 }
90 90 }
91 91
92 92 void BarChartItem::layoutChanged()
93 93 {
94 94 // Scale bars to new layout
95 95 // Layout for bars:
96 96 if (mSeries->barsetCount() <= 0) {
97 97 qDebug() << "No sets in model!";
98 98 return;
99 99 }
100 100
101 101 if (childItems().count() == 0) {
102 102 qDebug() << "WARNING: BarChartitem::layoutChanged called before graphics items are created!";
103 103 return;
104 104 }
105 105
106 106 // Use temporary qreals for accurancy (we might get some compiler warnings... :)
107 107 int categoryCount = mSeries->categoryCount();
108 108 int setCount = mSeries->barsetCount();
109 109
110 110 qreal tW = mWidth;
111 111 qreal tH = mHeight;
112 112 qreal tM = mSeries->max();
113
114 // Domain:
115 if (mDomainMaxY > tM) {
116 tM = mDomainMaxY;
117 }
118
113 119 qreal scale = (tH/tM);
114 120 qreal tC = categoryCount + 1;
115 121 qreal categoryWidth = tW/tC;
116 122 mBarWidth = categoryWidth / (setCount+1);
117 123
118 124 int itemIndex(0);
119 125 for (int category=0; category < categoryCount; category++) {
120 126 qreal xPos = categoryWidth * category + categoryWidth /2 + mBarWidth/2;
121 127 qreal yPos = mHeight;
122 128 for (int set = 0; set < setCount; set++) {
123 129 qreal barHeight = mSeries->valueAt(set,category) * scale;
124 130 Bar* bar = mBars.at(itemIndex);
125 131
126 132 // TODO: width settable per bar?
127 133 bar->resize(mBarWidth, barHeight);
128 134 bar->setPen(mSeries->barsetAt(set)->pen());
129 135 bar->setBrush(mSeries->barsetAt(set)->brush());
130 136 bar->setPos(xPos, yPos-barHeight);
131 137 itemIndex++;
132 138 xPos += mBarWidth;
133 139 }
134 140 }
135 141
136 142 // Position floating values
137 143 itemIndex = 0;
138 144 for (int category=0; category < mSeries->categoryCount(); category++) {
139 145 qreal xPos = categoryWidth * category + categoryWidth/2 + mBarWidth;
140 146 qreal yPos = mHeight;
141 147 for (int set=0; set < mSeries->barsetCount(); set++) {
142 148 qreal barHeight = mSeries->valueAt(set,category) * scale;
143 149 BarValue* value = mFloatingValues.at(itemIndex);
144 150
145 151 QBarSet* barSet = mSeries->barsetAt(set);
146 152 value->resize(100,50); // TODO: proper layout for this.
147 153 value->setPos(xPos, yPos-barHeight/2);
148 154 value->setPen(barSet->floatingValuePen());
149 155
150 156 if (mSeries->valueAt(set,category) != 0) {
151 157 value->setValueString(QString::number(mSeries->valueAt(set,category)));
152 158 } else {
153 159 value->setValueString(QString(""));
154 160 }
155 161
156 162 itemIndex++;
157 163 xPos += mBarWidth;
158 164 }
159 165 }
160 166 update();
161 167 }
162 168
163 169 BarLayout BarChartItem::calculateLayout()
164 170 {
165 171 BarLayout layout;
166 172 foreach(Bar* bar, mBars) {
167 173 layout.insert(bar,bar->boundingRect().size());
168 174 }
169 175
170 176 return layout;
171 177 }
172 178
173 179 void BarChartItem::applyLayout(const BarLayout &layout)
174 180 {
175 181 if (m_animator)
176 182 m_animator->updateLayout(this, layout);
177 183 else
178 184 setLayout(layout);
179 185 }
180 186
181 187 void BarChartItem::setLayout(const BarLayout &layout)
182 188 {
183 189 foreach (Bar *bar, layout.keys()) {
184 190 bar->setSize(layout.value(bar));
185 191 }
186 192 update();
187 193 }
188 194
189 195 void BarChartItem::initAxisLabels()
190 196 {
191 197 int count = mSeries->categoryCount();
192 198 if (0 == count) {
193 199 return;
194 200 }
195 201
196 202 mChart->axisX()->setTicksCount(count+2);
197 203
198 204 qreal min = 0;
199 205 qreal max = count+1;
200 206
201 207 mChart->axisX()->setMin(min);
202 208 mChart->axisX()->setMax(max);
203 209
204 210 QChartAxisCategories* categories = mChart->axisX()->categories();
205 211 categories->clear();
206 212 for (int i=0; i<count; i++) {
207 213 categories->insert(i+1,mSeries->categoryName(i));
208 214 }
209 215
210 216
211 217
212 218 mChart->axisX()->setLabelsVisible(true);
213 219 }
214 220
215 221 //handlers
216 222
217 223 void BarChartItem::handleModelChanged(int index)
218 224 {
219 225 Q_UNUSED(index)
220 226 dataChanged();
221 227 }
222 228
223 229 void BarChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
224 230 {
225 // TODO:
226 Q_UNUSED(minX)
227 Q_UNUSED(maxX)
228 Q_UNUSED(minY)
229 Q_UNUSED(maxY)
231 mDomainMinX = minX;
232 mDomainMaxX = maxX;
233 mDomainMinY = minY;
234 mDomainMaxY = maxY;
235 layoutChanged();
230 236
231 237 /*
232 238 int count = mSeries->categoryCount();
233 239 if (0 == count) {
234 240 return;
235 241 }
236 242
237 243 // Position labels to domain
238 244 qreal min = domain.minX();
239 245 qreal max = domain.maxX();
240 246 qreal step = (max-min)/count;
241 247 QChartAxisCategories& categories = mChart->axisX()->categories();
242 248 categories.clear();
243 249 for (int i=0; i<count; i++) {
244 250 categories.insert(min,mSeries->categoryName(i));
245 251 min += step;
246 252 }
247 253 */
248 254 }
249 255
250 256 void BarChartItem::handleGeometryChanged(const QRectF& rect)
251 257 {
252 258 mWidth = rect.width();
253 259 mHeight = rect.height();
254 260 layoutChanged();
255 261 mLayoutSet = true;
256 262 setPos(rect.topLeft());
257 263 }
258 264
259 265 void BarChartItem::handleLayoutChanged()
260 266 {
261 267 BarLayout layout = calculateLayout();
262 268 applyLayout(layout);
263 269 update();
264 270 }
265 271
266 272
267 273 void BarChartItem::showToolTip(QPoint pos, QString tip)
268 274 {
269 275 // TODO: cool tooltip instead of default
270 276 QToolTip::showText(pos,tip);
271 277 }
272 278
273 279 #include "moc_barchartitem_p.cpp"
274 280
275 281 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,71 +1,76
1 1 #ifndef BARCHARTITEM_H
2 2 #define BARCHARTITEM_H
3 3
4 4 #include "chartitem_p.h"
5 5 #include "qbarseries.h"
6 6 #include <QPen>
7 7 #include <QBrush>
8 8 #include <QGraphicsItem>
9 9
10 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 11
12 12 class Bar;
13 13 class BarValue;
14 14 class QChartAxisCategories;
15 15 class QChart;
16 16
17 17 typedef QHash<Bar*, QSizeF> BarLayout;
18 18
19 19 class BarChartItem : public QObject, public ChartItem
20 20 {
21 21 Q_OBJECT
22 22 public:
23 23 BarChartItem(QBarSeries *series, QChart *parent = 0);
24 24 virtual ~BarChartItem();
25 25
26 26 public:
27 27 // From QGraphicsItem
28 28 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
29 29 QRectF boundingRect() const;
30 30
31 31 // TODO: Consider the domain for layoutChanged. May be use case, may not be. If it is, then the derived classes need to implement it
32 32 virtual void dataChanged(); // data of series has changed -> need to recalculate bar sizes
33 33 private slots:
34 34 virtual void layoutChanged(); // layout has changed -> need to recalculate bar sizes
35 35
36 36 public:
37 37 BarLayout calculateLayout();
38 38 void applyLayout(const BarLayout &layout);
39 39 void setLayout(const BarLayout &layout);
40 40
41 41 protected:
42 42 void initAxisLabels();
43 43
44 44 public slots:
45 45 void handleModelChanged(int index);
46 46 void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY);
47 47 void handleGeometryChanged(const QRectF& size);
48 48 void handleLayoutChanged();
49 49
50 50 // Internal slots
51 51 void showToolTip(QPoint pos, QString tip); // shows tooltip (if enabled)
52 52
53 53 protected:
54 54
55 55 // TODO: consider these.
56 56 int mHeight; // Layout spesific
57 57 int mWidth;
58 58 qreal mBarWidth;
59 59
60 qreal mDomainMinX;
61 qreal mDomainMaxX;
62 qreal mDomainMinY;
63 qreal mDomainMaxY;
64
60 65 bool mLayoutSet; // True, if component has been laid out.
61 66
62 67 // Not owned.
63 68 QBarSeries* mSeries;
64 69 QList<Bar*> mBars;
65 70 QList<BarValue*> mFloatingValues;
66 71 QChart* mChart;
67 72 };
68 73
69 74 QTCOMMERCIALCHART_END_NAMESPACE
70 75
71 76 #endif // BARCHARTITEM_H
@@ -1,97 +1,102
1 1 #include "stackedbarchartitem_p.h"
2 2 #include "bar_p.h"
3 3 #include "barvalue_p.h"
4 4 #include "qbarset.h"
5 5 #include <QDebug>
6 6
7 7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 8
9 9 StackedBarChartItem::StackedBarChartItem(QBarSeries *series, QChart *parent) :
10 10 BarChartItem(series,parent)
11 11 {
12 12 }
13 13
14 14 StackedBarChartItem::~StackedBarChartItem()
15 15 {
16 16 }
17 17
18 18
19 19 void StackedBarChartItem::layoutChanged()
20 20 {
21 21 // Scale bars to new layout
22 22 // Layout for bars:
23 23 if (mSeries->barsetCount() <= 0) {
24 24 qDebug() << "No sets in model!";
25 25 // Nothing to do.
26 26 return;
27 27 }
28 28
29 29 if (mSeries->categoryCount() == 0) {
30 30 qDebug() << "No categories in model!";
31 31 // Nothing to do
32 32 return;
33 33 }
34 34
35 35 if (childItems().count() == 0) {
36 36 qDebug() << "WARNING: StackedBarChartItem::layoutChanged called before graphics items are created!";
37 37 return;
38 38 }
39 39
40 40 // Use temporary qreals for accurancy (we might get some compiler warnings... :)
41 41 qreal maxSum = mSeries->maxCategorySum();
42 // Domain:
43 if (mDomainMaxY > maxSum) {
44 maxSum = mDomainMaxY;
45 }
46
42 47 qreal h = mHeight;
43 48 qreal scale = (h / maxSum);
44 49 qreal tW = mWidth;
45 50 qreal tC = mSeries->categoryCount() + 1;
46 51 qreal cC = mSeries->categoryCount() * 2 + 1;
47 52 mBarWidth = tW / cC;
48 53 qreal xStep = (tW/tC);
49 54 qreal xPos = ((tW/tC) - mBarWidth / 2);
50 55
51 56 int itemIndex(0);
52 57 for (int category = 0; category < mSeries->categoryCount(); category++) {
53 58 qreal yPos = h;
54 59 for (int set=0; set < mSeries->barsetCount(); set++) {
55 60 qreal barHeight = mSeries->valueAt(set, category) * scale;
56 61 Bar* bar = mBars.at(itemIndex);
57 62
58 63 bar->resize(mBarWidth, barHeight);
59 64 bar->setPen(mSeries->barsetAt(set)->pen());
60 65 bar->setBrush(mSeries->barsetAt(set)->brush());
61 66 bar->setPos(xPos, yPos-barHeight);
62 67 itemIndex++;
63 68 yPos -= barHeight;
64 69 }
65 70 xPos += xStep;
66 71 }
67 72
68 73 // Position floating values
69 74 itemIndex = 0;
70 75 xPos = (tW/tC);
71 76 for (int category=0; category < mSeries->categoryCount(); category++) {
72 77 qreal yPos = h;
73 78 for (int set=0; set < mSeries->barsetCount(); set++) {
74 79 qreal barHeight = mSeries->valueAt(set,category) * scale;
75 80 BarValue* value = mFloatingValues.at(itemIndex);
76 81
77 82 QBarSet* barSet = mSeries->barsetAt(set);
78 83 value->resize(100,50); // TODO: proper layout for this.
79 84 value->setPos(xPos, yPos-barHeight/2);
80 85 value->setPen(barSet->floatingValuePen());
81 86
82 87 if (mSeries->valueAt(set,category) != 0) {
83 88 value->setValueString(QString::number(mSeries->valueAt(set,category)));
84 89 } else {
85 90 value->setValueString(QString(""));
86 91 }
87 92
88 93 itemIndex++;
89 94 yPos -= barHeight;
90 95 }
91 96 xPos += xStep;
92 97 }
93 98 }
94 99
95 100 #include "moc_stackedbarchartitem_p.cpp"
96 101
97 102 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now