##// END OF EJS Templates
Animation framework for barchart.
sauimone -
r671:c28ddd8c89e3
parent child
Show More
@@ -0,0 +1,49
1 #include "baranimation_p.h"
2 #include "barchartitem_p.h"
3 #include <QParallelAnimationGroup>
4 #include <QTimer>
5
6 Q_DECLARE_METATYPE(QVector<QSizeF>)
7
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
10 BarAnimation::BarAnimation(BarChartItem *item)
11 :ChartAnimation(item),
12 m_item(item)
13 {
14 }
15
16 BarAnimation::~BarAnimation()
17 {
18 }
19
20 void BarAnimation::updateValues(const BarLayout& layout)
21 {
22 // TODO:
23 qDebug() << "BarAnimation::updateValues";
24 }
25
26
27 QVariant BarAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const
28 {
29 QVector<QSizeF> startVector = qVariantValue<QVector<QSizeF> > (from);
30 QVector<QSizeF> endVector = qVariantValue<QVector<QSizeF> > (to);
31 QVector<QSizeF> result;
32
33 Q_ASSERT(startVector.count() == endVector.count()) ;
34
35 for(int i =0 ;i< startVector.count();i++){
36 QSizeF value = startVector[i] + ((endVector[i]- endVector[i]) * progress);
37 result << value;
38 }
39 return qVariantFromValue(result);
40 }
41
42 void BarAnimation::updateCurrentValue(const QVariant &)
43 {
44 // TODO?
45 }
46
47 #include "moc_baranimation_p.cpp"
48
49 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,36
1 #ifndef BARANIMATION_P_H_
2 #define BARANIMATION_P_H_
3
4 #include "chartanimation_p.h"
5 #include "barchartitem_p.h"
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9 class BarChartItem;
10 class QBarSet;
11 class BarSetAnimation;
12
13 class BarAnimation : public ChartAnimation
14 {
15 Q_OBJECT
16
17 public:
18 BarAnimation(BarChartItem *item);
19 ~BarAnimation();
20
21 void updateValues(const BarLayout& layout);
22
23 public: // from QVariantAnimation
24 virtual QVariant interpolated (const QVariant & from, const QVariant & to, qreal progress ) const;
25 virtual void updateCurrentValue (const QVariant & value );
26
27 public Q_SLOTS:
28
29 private:
30 BarChartItem *m_item;
31 QHash<QBarSet*, BarSetAnimation*> m_animations;
32 };
33
34 QTCOMMERCIALCHART_END_NAMESPACE
35
36 #endif
@@ -1,20 +1,24
1 1 INCLUDEPATH += $$PWD
2 2 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/axisanimation.cpp \
6 6 $$PWD/chartanimator.cpp \
7 7 $$PWD/xyanimation.cpp \
8 8 $$PWD/pieanimation.cpp \
9 9 $$PWD/piesliceanimation.cpp \
10 $$PWD/splineanimation.cpp
10 $$PWD/splineanimation.cpp \
11 $$PWD/baranimation.cpp
12
11 13
12 14
13 15 PRIVATE_HEADERS += \
14 16 $$PWD/axisanimation_p.h \
15 17 $$PWD/chartanimator_p.h \
16 18 $$PWD/chartanimation_p.h \
17 19 $$PWD/xyanimation_p.h \
18 20 $$PWD/pieanimation_p.h \
19 21 $$PWD/piesliceanimation_p.h \
20 $$PWD/splineanimation_p.h
22 $$PWD/splineanimation_p.h \
23 $$PWD/baranimation_p.h
24
@@ -1,261 +1,285
1 1 #include "chartanimator_p.h"
2 2 #include "axisanimation_p.h"
3 3 #include "xyanimation_p.h"
4 4 #include "splineanimation_p.h"
5 5 #include "xychartitem_p.h"
6 6 #include "pieanimation_p.h"
7 #include "baranimation_p.h"
8 #include "barchartitem_p.h"
7 9 #include "areachartitem_p.h"
8 10 #include "splinechartitem_p.h"
9 11 #include "scatterchartitem_p.h"
10 12 #include <QTimer>
11 13
12 14 Q_DECLARE_METATYPE(QVector<QPointF>)
13 15 Q_DECLARE_METATYPE(QVector<qreal>)
14 16
15 17 QTCOMMERCIALCHART_BEGIN_NAMESPACE
16 18
17 19 const static int duration = 1000;
18 20
19 21 ChartAnimator::ChartAnimator(QObject *parent):QObject(parent)
20 22 {
21 23 }
22 24
23 25 ChartAnimator::~ChartAnimator()
24 26 {
25 27 }
26 28
27 29 void ChartAnimator::addAnimation(AxisItem* item)
28 30 {
29 31 ChartAnimation* animation = m_animations.value(item);
30 32
31 33 if(!animation) {
32 34 animation = new AxisAnimation(item);
33 35 m_animations.insert(item,animation);
34 36 }
35 37
36 38 item->setAnimator(this);
37 39 }
38 40
39 41 void ChartAnimator::addAnimation(SplineChartItem* item)
40 42 {
41 43 ChartAnimation* animation = m_animations.value(item);
42 44
43 45 if(!animation) {
44 46 animation = new SplineAnimation(item);
45 47 m_animations.insert(item,animation);
46 48 }
47 49
48 50 item->setAnimator(this);
49 51 }
50 52
51 53 void ChartAnimator::addAnimation(ScatterChartItem* item)
52 54 {
53 55 ChartAnimation* animation = m_animations.value(item);
54 56
55 57 if(!animation) {
56 58 animation = new XYAnimation(item);
57 59 m_animations.insert(item,animation);
58 60 }
59 61
60 62 item->setAnimator(this);
61 63 }
62 64
63 65 void ChartAnimator::addAnimation(LineChartItem* item)
64 66 {
65 67 ChartAnimation* animation = m_animations.value(item);
66 68
67 69 if(!animation) {
68 70 animation = new XYAnimation(item);
69 71 m_animations.insert(item,animation);
70 72 }
71 73
72 74 item->setAnimator(this);
73 75 }
74 76
75 77 void ChartAnimator::addAnimation(PieChartItem* item)
76 78 {
77 79 ChartAnimation* animation = m_animations.value(item);
78 80
79 81 if(!animation) {
80 82 animation = new PieAnimation(item);
81 83 m_animations.insert(item,animation);
82 84 }
83 85
84 86 item->setAnimator(this);
85 87 }
86 88
89 void ChartAnimator::addAnimation(BarChartItem* item)
90 {
91 ChartAnimation* animation = m_animations.value(item);
92
93 if(!animation) {
94 animation = new BarAnimation(item);
95 m_animations.insert(item,animation);
96 }
97
98 item->setAnimator(this);
99 }
100
101
87 102 void ChartAnimator::removeAnimation(ChartItem* item)
88 103 {
89 104 item->setAnimator(0);
90 105 m_animations.remove(item);
91 106 }
92 107
93 108 void ChartAnimator::updateLayout(AxisItem* item , QVector<qreal>& newLayout)
94 109 {
95 110 AxisAnimation* animation = static_cast<AxisAnimation*>(m_animations.value(item));
96 111
97 112 Q_ASSERT(animation);
98 113
99 114 QVector<qreal> oldLayout = item->layout();
100 115
101 116 if(newLayout.count()==0) return;
102 117
103 118 switch(m_state)
104 119 {
105 120 case ZoomOutState: {
106 121 QRectF rect = item->geometry();
107 122 oldLayout.resize(newLayout.count());
108 123
109 124 for(int i=0,j=oldLayout.count()-1;i<(oldLayout.count()+1)/2;i++,j--)
110 125 {
111 126 oldLayout[i]= item->axisType()==AxisItem::X_AXIS?rect.left():rect.bottom();
112 127 oldLayout[j]= item->axisType()==AxisItem::X_AXIS?rect.right():rect.top();
113 128 }
114 129 }
115 130 break;
116 131 case ZoomInState: {
117 132 int index = qMin(oldLayout.count()*(item->axisType()==AxisItem::X_AXIS?m_point.x():(1 -m_point.y())),newLayout.count()-1.0);
118 133 oldLayout.resize(newLayout.count());
119 134
120 135 for(int i=0;i<oldLayout.count();i++)
121 136 {
122 137 oldLayout[i]= oldLayout[index];
123 138 }
124 139 }
125 140 break;
126 141 case ScrollDownState:
127 142 case ScrollRightState: {
128 143 oldLayout.resize(newLayout.count());
129 144
130 145 for(int i=0, j=i+1;i<oldLayout.count()-1;i++,j++)
131 146 {
132 147 oldLayout[i]= oldLayout[j];
133 148 }
134 149 }
135 150 break;
136 151 case ScrollUpState:
137 152 case ScrollLeftState: {
138 153 oldLayout.resize(newLayout.count());
139 154
140 155 for(int i=oldLayout.count()-1, j=i-1;i>0;i--,j--)
141 156 {
142 157 oldLayout[i]= oldLayout[j];
143 158 }
144 159 }
145 160 break;
146 161 default: {
147 162 oldLayout.resize(newLayout.count());
148 163 QRectF rect = item->geometry();
149 164 for(int i=0, j=oldLayout.count()-1;i<oldLayout.count();i++,j--)
150 165 {
151 166 oldLayout[i]= item->axisType()==AxisItem::X_AXIS?rect.left():rect.top();
152 167 }
153 168 }
154 169 break;
155 170 }
156 171
157 172
158 173 if(animation->state()!=QAbstractAnimation::Stopped) {
159 174 animation->stop();
160 175 }
161 176
162 177 animation->setDuration(duration);
163 178 animation->setEasingCurve(QEasingCurve::OutQuart);
164 179 QVariantAnimation::KeyValues value;
165 180 animation->setKeyValues(value); //workaround for wrong interpolation call
166 181 animation->setKeyValueAt(0.0, qVariantFromValue(oldLayout));
167 182 animation->setKeyValueAt(1.0, qVariantFromValue(newLayout));
168 183
169 184 QTimer::singleShot(0,animation,SLOT(start()));
170 185 }
171 186
172 187 void ChartAnimator::updateLayout(SplineChartItem* item, QVector<QPointF>& oldPoints ,QVector<QPointF>& newPoints, QVector<QPointF>& oldControlPoints, QVector<QPointF>& newControlPoints,int index)
173 188 {
174 189 SplineAnimation* animation = static_cast<SplineAnimation*>(m_animations.value(item));
175 190
176 191 Q_ASSERT(animation);
177 192
178 193 if(newPoints.count()<2 || newControlPoints.count()<2) return;
179 194
180 195 bool empty = oldPoints.count()==0;
181 196
182 197
183 198 if(animation->state()!=QAbstractAnimation::Stopped) {
184 199 animation->stop();
185 200 }
186 201
187 202 animation->setDuration(duration);
188 203 if(!empty)
189 204 animation->setAnimationType(ChartAnimation::MoveDownAnimation);
190 205 else
191 206 animation->setAnimationType(ChartAnimation::LineDrawAnimation);
192 207
193 208 animation->setEasingCurve(QEasingCurve::OutQuart);
194 209 animation->setValues(oldPoints,newPoints,oldControlPoints,newControlPoints,index);
195 210
196 211 QTimer::singleShot(0,animation,SLOT(start()));
197 212 }
198 213
199 214
200 215 void ChartAnimator::updateLayout(XYChartItem* item, QVector<QPointF>& oldPoints , QVector<QPointF>& newPoints, int index)
201 216 {
202 217 XYAnimation* animation = static_cast<XYAnimation*>(m_animations.value(item));
203 218
204 219 Q_ASSERT(animation);
205 220
206 221 if(newPoints.count()==0) return;
207 222
208 223 bool empty = oldPoints.count()==0;
209 224
210 225
211 226 if(animation->state()!=QAbstractAnimation::Stopped) {
212 227 animation->stop();
213 228 }
214 229
215 230 animation->setDuration(duration);
216 231 if(!empty)
217 232 animation->setAnimationType(ChartAnimation::MoveDownAnimation);
218 233 else
219 234 animation->setAnimationType(ChartAnimation::LineDrawAnimation);
220 235
221 236 animation->setEasingCurve(QEasingCurve::OutQuart);
222 237 animation->setValues(oldPoints,newPoints,index);
223 238
224 239 QTimer::singleShot(0,animation,SLOT(start()));
225 240 }
226 241
227 242 void ChartAnimator::addAnimation(PieChartItem* item, QPieSlice *slice, const PieSliceData &sliceData, bool isEmpty)
228 243 {
229 244 PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item));
230 245 Q_ASSERT(animation);
231 246 animation->addSlice(slice, sliceData, isEmpty);
232 247 }
233 248
234 249 void ChartAnimator::removeAnimation(PieChartItem* item, QPieSlice *slice)
235 250 {
236 251 PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item));
237 252 Q_ASSERT(animation);
238 253 animation->removeSlice(slice);
239 254 }
240 255
241 256 void ChartAnimator::updateLayout(PieChartItem* item, const PieLayout &layout)
242 257 {
243 258 PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item));
244 259 Q_ASSERT(animation);
245 260 animation->updateValues(layout);
246 261 }
247 262
248 263 void ChartAnimator::updateLayout(PieChartItem* item, QPieSlice *slice, const PieSliceData &sliceData)
249 264 {
250 265 PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item));
251 266 Q_ASSERT(animation);
252 267 animation->updateValue(slice, sliceData);
253 268 }
254 269
270 void ChartAnimator::updateLayout(BarChartItem* item, const BarLayout &layout)
271 {
272 qDebug() << "ChartAnimator::updateLayout";
273 BarAnimation* animation = static_cast<BarAnimation*>(m_animations.value(item));
274 Q_ASSERT(animation);
275 animation->updateValues(layout);
276 }
277
278
255 279 void ChartAnimator::setState(State state,const QPointF& point)
256 280 {
257 281 m_state=state;
258 282 m_point=point;
259 283 }
260 284
261 285 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,53 +1,57
1 1 #ifndef CHARTANIMATOR_P_H_
2 2 #define CHARTANIMATOR_P_H_
3 3 #include "qchartglobal.h"
4 4 #include "chartanimation_p.h"
5 5 #include "piechartitem_p.h"
6 #include "barchartitem_p.h"
6 7 #include <QPointF>
7 8
8 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 10
10 11 class ChartItem;
11 12 class AxisItem;
12 13 class AreaChartItem;
13 14 class SplineChartItem;
14 15 class ScatterChartItem;
15 16 class LineChartItem;
16 17 class XYChartItem;
17 18
18 19 class ChartAnimator : public QObject {
19 20
20 21 public:
21 22 //TODO: this should be flags in case of two state at the time
22 23 enum State{ShowState, ScrollUpState, ScrollDownState, ScrollLeftState,ScrollRightState,ZoomInState,ZoomOutState};
23 24 ChartAnimator(QObject *parent = 0);
24 25 virtual ~ChartAnimator();
25 26
26 27 void addAnimation(AxisItem* item);
27 28 void addAnimation(PieChartItem* item);
28 29 void addAnimation(ScatterChartItem* item);
29 30 void addAnimation(LineChartItem* item);
30 31 void addAnimation(SplineChartItem* item);
32 void addAnimation(BarChartItem* item);
31 33 void removeAnimation(ChartItem* item);
32 34
33 35 void animationStarted();
34 36 void updateLayout(XYChartItem* item, QVector<QPointF>& oldLayout,QVector<QPointF>& newLayout,int index);
35 37 void updateLayout(SplineChartItem* item, QVector<QPointF>& oldPoints , QVector<QPointF>& newPoints, QVector<QPointF>& oldControlPoints, QVector<QPointF>& newContorlPoints,int index);
36 38 void updateLayout(AxisItem* item, QVector<qreal>& layout);
37 39
38 40 void addAnimation(PieChartItem* item, QPieSlice *slice, const PieSliceData &sliceData, bool isEmpty);
39 41 void removeAnimation(PieChartItem* item, QPieSlice *slice);
40 42 void updateLayout(PieChartItem* item, const PieLayout &layout);
41 43 void updateLayout(PieChartItem* item, QPieSlice *slice, const PieSliceData &sliceData);
42 44
45 void updateLayout(BarChartItem* item, const BarLayout &layout);
46
43 47 void setState(State state,const QPointF& point = QPointF());
44 48
45 49 private:
46 50 QMap<ChartItem*,ChartAnimation*> m_animations;
47 51 State m_state;
48 52 QPointF m_point;
49 53 };
50 54
51 55 QTCOMMERCIALCHART_END_NAMESPACE
52 56
53 57 #endif
@@ -1,239 +1,275
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 #include "chartanimator_p.h"
10 11 #include <QDebug>
11 12 #include <QToolTip>
12 13
13 14 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 15
15 16 BarChartItem::BarChartItem(QBarSeries *series, QChart *parent) :
16 17 ChartItem(parent),
17 18 mHeight(0),
18 19 mWidth(0),
19 20 mLayoutSet(false),
20 21 mSeries(series),
21 22 mChart(parent)
22 23 {
23 24 connect(series,SIGNAL(showToolTip(QPoint,QString)),this,SLOT(showToolTip(QPoint,QString)));
24 25 connect(series, SIGNAL(updatedBars()), this, SLOT(layoutChanged()));
26 //TODO: connect(series,SIGNAL("position or size has changed"), this, SLOT(handleLayoutChanged()));
27 connect(series, SIGNAL(restructuredBar(int)), this, SLOT(handleModelChanged(int)));
25 28 setZValue(ChartPresenter::BarSeriesZValue);
26 29 initAxisLabels();
27 30 dataChanged();
28 31 }
29 32
30 33 BarChartItem::~BarChartItem()
31 34 {
32 35 disconnect(this,SLOT(showToolTip(QPoint,QString)));
33 36 }
34 37
35 38 void BarChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
36 39 {
37 40 if (!mLayoutSet) {
38 41 qDebug() << "BarChartItem::paint called without layout set. Aborting.";
39 42 return;
40 43 }
41 44 foreach(QGraphicsItem* i, childItems()) {
42 45 i->paint(painter,option,widget);
43 46 }
44 47 }
45 48
46 49 QRectF BarChartItem::boundingRect() const
47 50 {
48 51 return QRectF(0, 0, mWidth, mHeight);
49 52 }
50 53
51 54 void BarChartItem::dataChanged()
52 55 {
53 56 // TODO: performance optimizations. Do we really need to delete and create items every time data is changed or can we reuse them?
54 57 // Delete old bars
55 58 foreach (QGraphicsItem* item, childItems()) {
56 59 delete item;
57 60 }
58 61
59 62 mBars.clear();
60 63 mFloatingValues.clear();
61 64
62 65 // Create new graphic items for bars
63 66 for (int c=0; c<mSeries->categoryCount(); c++) {
64 67 QString category = mSeries->categoryName(c);
65 68 for (int s=0; s<mSeries->barsetCount(); s++) {
66 69 QBarSet *set = mSeries->barsetAt(s);
67 70 Bar *bar = new Bar(category,this);
68 71 childItems().append(bar);
69 72 mBars.append(bar);
70 73 connect(bar,SIGNAL(clicked(QString)),set,SIGNAL(clicked(QString)));
71 74 connect(bar,SIGNAL(rightClicked(QString)),set,SIGNAL(rightClicked(QString)));
72 75 connect(bar,SIGNAL(hoverEntered(QPoint)),set,SLOT(barHoverEnterEvent(QPoint)));
73 76 connect(bar,SIGNAL(hoverLeaved()),set,SLOT(barHoverLeaveEvent()));
74 77 }
75 78 }
76 79
77 80 // Create floating values
78 81 for (int category=0; category<mSeries->categoryCount(); category++) {
79 82 for (int s=0; s<mSeries->barsetCount(); s++) {
80 83 QBarSet *set = mSeries->barsetAt(s);
81 84 BarValue *value = new BarValue(*set, this);
82 85 childItems().append(value);
83 86 mFloatingValues.append(value);
84 87 connect(set,SIGNAL(toggleFloatingValues()),value,SLOT(toggleVisible()));
85 88 }
86 89 }
87 90 }
88 91
89 92 void BarChartItem::layoutChanged()
90 93 {
91 94 // Scale bars to new layout
92 95 // Layout for bars:
93 96 if (mSeries->barsetCount() <= 0) {
94 97 qDebug() << "No sets in model!";
95 98 return;
96 99 }
97 100
98 101 if (childItems().count() == 0) {
99 102 qDebug() << "WARNING: BarChartitem::layoutChanged called before graphics items are created!";
100 103 return;
101 104 }
102 105
103 106 // Use temporary qreals for accurancy (we might get some compiler warnings... :)
104 107 int categoryCount = mSeries->categoryCount();
105 108 int setCount = mSeries->barsetCount();
106 109
107 110 qreal tW = mWidth;
108 111 qreal tH = mHeight;
109 112 qreal tM = mSeries->max();
110 113 qreal scale = (tH/tM);
111 114 qreal tC = categoryCount + 1;
112 115 qreal categoryWidth = tW/tC;
113 116 mBarWidth = categoryWidth / (setCount+1);
114 117
115 118 int itemIndex(0);
116 119 for (int category=0; category < categoryCount; category++) {
117 120 qreal xPos = categoryWidth * category + categoryWidth /2 + mBarWidth/2;
118 121 qreal yPos = mHeight;
119 122 for (int set = 0; set < setCount; set++) {
120 123 qreal barHeight = mSeries->valueAt(set,category) * scale;
121 124 Bar* bar = mBars.at(itemIndex);
122 125
123 126 // TODO: width settable per bar?
124 127 bar->resize(mBarWidth, barHeight);
125 128 bar->setPen(mSeries->barsetAt(set)->pen());
126 129 bar->setBrush(mSeries->barsetAt(set)->brush());
127 130 bar->setPos(xPos, yPos-barHeight);
128 131 itemIndex++;
129 132 xPos += mBarWidth;
130 133 }
131 134 }
132 135
133 136 // Position floating values
134 137 itemIndex = 0;
135 138 for (int category=0; category < mSeries->categoryCount(); category++) {
136 139 qreal xPos = categoryWidth * category + categoryWidth/2 + mBarWidth;
137 140 qreal yPos = mHeight;
138 141 for (int set=0; set < mSeries->barsetCount(); set++) {
139 142 qreal barHeight = mSeries->valueAt(set,category) * scale;
140 143 BarValue* value = mFloatingValues.at(itemIndex);
141 144
142 145 QBarSet* barSet = mSeries->barsetAt(set);
143 146 value->resize(100,50); // TODO: proper layout for this.
144 147 value->setPos(xPos, yPos-barHeight/2);
145 148 value->setPen(barSet->floatingValuePen());
146 149
147 150 if (mSeries->valueAt(set,category) != 0) {
148 151 value->setValueString(QString::number(mSeries->valueAt(set,category)));
149 152 } else {
150 153 value->setValueString(QString(""));
151 154 }
152 155
153 156 itemIndex++;
154 157 xPos += mBarWidth;
155 158 }
156 159 }
157 160 update();
158 161 }
159 162
163 BarLayout BarChartItem::calculateLayout()
164 {
165 BarLayout layout;
166 foreach(Bar* bar, mBars) {
167 layout.insert(bar,bar->boundingRect().size());
168 }
169
170 return layout;
171 }
172
173 void BarChartItem::applyLayout(const BarLayout &layout)
174 {
175 if (m_animator)
176 m_animator->updateLayout(this, layout);
177 else
178 setLayout(layout);
179 }
180
181 void BarChartItem::setLayout(const BarLayout &layout)
182 {
183 foreach (Bar *bar, layout.keys()) {
184 bar->setSize(layout.value(bar));
185 }
186 update();
187 }
160 188
161 189 void BarChartItem::initAxisLabels()
162 190 {
163 191 int count = mSeries->categoryCount();
164 192 if (0 == count) {
165 193 return;
166 194 }
167 195
168 196 mChart->axisX()->setTicksCount(count+2);
169 197
170 198 qreal min = 0;
171 199 qreal max = count+1;
172 200
173 201 mChart->axisX()->setMin(min);
174 202 mChart->axisX()->setMax(max);
175 203
176 204 QChartAxisCategories* categories = mChart->axisX()->categories();
177 205 categories->clear();
178 206 for (int i=0; i<count; i++) {
179 207 categories->insert(i+1,mSeries->categoryName(i));
180 208 }
181 209
182 210
183 211
184 212 mChart->axisX()->setLabelsVisible(true);
185 213 }
186 214
187 215 //handlers
188 216
189 217 void BarChartItem::handleModelChanged(int index)
190 218 {
191 219 Q_UNUSED(index)
192 220 dataChanged();
193 221 }
194 222
195 223 void BarChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
196 224 {
197 225 // TODO:
198 226 Q_UNUSED(minX)
199 227 Q_UNUSED(maxX)
200 228 Q_UNUSED(minY)
201 229 Q_UNUSED(maxY)
202 230
203 231 /*
204 232 int count = mSeries->categoryCount();
205 233 if (0 == count) {
206 234 return;
207 235 }
208 236
209 237 // Position labels to domain
210 238 qreal min = domain.minX();
211 239 qreal max = domain.maxX();
212 240 qreal step = (max-min)/count;
213 241 QChartAxisCategories& categories = mChart->axisX()->categories();
214 242 categories.clear();
215 243 for (int i=0; i<count; i++) {
216 244 categories.insert(min,mSeries->categoryName(i));
217 245 min += step;
218 246 }
219 247 */
220 248 }
221 249
222 250 void BarChartItem::handleGeometryChanged(const QRectF& rect)
223 251 {
224 252 mWidth = rect.width();
225 253 mHeight = rect.height();
226 254 layoutChanged();
227 255 mLayoutSet = true;
228 256 setPos(rect.topLeft());
229 257 }
230 258
259 void BarChartItem::handleLayoutChanged()
260 {
261 BarLayout layout = calculateLayout();
262 applyLayout(layout);
263 update();
264 }
265
266
231 267 void BarChartItem::showToolTip(QPoint pos, QString tip)
232 268 {
233 269 // TODO: cool tooltip instead of default
234 270 QToolTip::showText(pos,tip);
235 271 }
236 272
237 273 #include "moc_barchartitem_p.cpp"
238 274
239 275 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,64 +1,71
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 // Common implemantation of different presenters.
17 typedef QHash<Bar*, QSizeF> BarLayout;
18
18 19 class BarChartItem : public QObject, public ChartItem
19 20 {
20 21 Q_OBJECT
21 22 public:
22 23 BarChartItem(QBarSeries *series, QChart *parent = 0);
23 24 virtual ~BarChartItem();
24 25
25 26 public:
26 27 // From QGraphicsItem
27 28 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
28 29 QRectF boundingRect() const;
29 30
30 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
31 32 virtual void dataChanged(); // data of series has changed -> need to recalculate bar sizes
32 33 private slots:
33 34 virtual void layoutChanged(); // layout has changed -> need to recalculate bar sizes
34 35
36 public:
37 BarLayout calculateLayout();
38 void applyLayout(const BarLayout &layout);
39 void setLayout(const BarLayout &layout);
40
35 41 protected:
36 42 void initAxisLabels();
37 43
38 44 public slots:
39 45 void handleModelChanged(int index);
40 46 void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY);
41 47 void handleGeometryChanged(const QRectF& size);
48 void handleLayoutChanged();
42 49
43 50 // Internal slots
44 51 void showToolTip(QPoint pos, QString tip); // shows tooltip (if enabled)
45 52
46 53 protected:
47 54
48 55 // TODO: consider these.
49 56 int mHeight; // Layout spesific
50 57 int mWidth;
51 58 qreal mBarWidth;
52 59
53 60 bool mLayoutSet; // True, if component has been laid out.
54 61
55 62 // Not owned.
56 63 QBarSeries* mSeries;
57 64 QList<Bar*> mBars;
58 65 QList<BarValue*> mFloatingValues;
59 66 QChart* mChart;
60 67 };
61 68
62 69 QTCOMMERCIALCHART_END_NAMESPACE
63 70
64 71 #endif // BARCHARTITEM_H
@@ -1,391 +1,391
1 1 #include "qchart.h"
2 2 #include "qchartaxis.h"
3 3 #include "chartpresenter_p.h"
4 4 #include "chartdataset_p.h"
5 5 #include "charttheme_p.h"
6 6 #include "chartanimator_p.h"
7 7 //series
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 "qpieseries.h"
14 14 #include "qscatterseries.h"
15 15 #include "qsplineseries.h"
16 16 //items
17 17 #include "axisitem_p.h"
18 18 #include "areachartitem_p.h"
19 19 #include "barchartitem_p.h"
20 20 #include "stackedbarchartitem_p.h"
21 21 #include "percentbarchartitem_p.h"
22 22 #include "linechartitem_p.h"
23 23 #include "piechartitem_p.h"
24 24 #include "scatterchartitem_p.h"
25 25 #include "splinechartitem_p.h"
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart),
30 30 m_chart(chart),
31 31 m_animator(0),
32 32 m_dataset(dataset),
33 33 m_chartTheme(0),
34 34 m_zoomIndex(0),
35 35 m_rect(QRectF(QPoint(0,0),m_chart->size())),
36 36 m_options(QChart::NoAnimation),
37 37 m_themeForce(false)
38 38 {
39 39 createConnections();
40 40 setChartTheme(QChart::ChartThemeDefault,false);
41 41 }
42 42
43 43 ChartPresenter::~ChartPresenter()
44 44 {
45 45 delete m_chartTheme;
46 46 }
47 47
48 48 void ChartPresenter::createConnections()
49 49 {
50 50 QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged()));
51 51 QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),this,SLOT(handleSeriesAdded(QSeries*,Domain*)));
52 52 QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*)));
53 53 QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*,Domain*)),this,SLOT(handleAxisAdded(QChartAxis*,Domain*)));
54 54 QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*)));
55 55 }
56 56
57 57
58 58 QRectF ChartPresenter::geometry() const
59 59 {
60 60 return m_rect;
61 61 }
62 62
63 63 void ChartPresenter::handleGeometryChanged()
64 64 {
65 65 QRectF rect(QPoint(0,0),m_chart->size());
66 66 rect.adjust(m_chart->padding(),m_chart->padding(), -m_chart->padding(), -m_chart->padding());
67 67
68 68 //rewrite zoom stack
69 69 for(int i=0;i<m_zoomStack.count();i++){
70 70 QRectF r = m_zoomStack[i];
71 71 qreal w = rect.width()/m_rect.width();
72 72 qreal h = rect.height()/m_rect.height();
73 73 QPointF tl = r.topLeft();
74 74 tl.setX(tl.x()*w);
75 75 tl.setY(tl.y()*h);
76 76 QPointF br = r.bottomRight();
77 77 br.setX(br.x()*w);
78 78 br.setY(br.y()*h);
79 79 r.setTopLeft(tl);
80 80 r.setBottomRight(br);
81 81 m_zoomStack[i]=r;
82 82 }
83 83
84 84 m_rect = rect;
85 85 Q_ASSERT(m_rect.isValid());
86 86 emit geometryChanged(m_rect);
87 87 }
88 88
89 89 void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain)
90 90 {
91 91 AxisItem* item = new AxisItem(axis,this,axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
92 92
93 93 if(m_options.testFlag(QChart::GridAxisAnimations)){
94 94 m_animator->addAnimation(item);
95 95 }
96 96
97 97 if(axis==m_dataset->axisX()){
98 98 m_chartTheme->decorate(axis,true,m_themeForce);
99 99 QObject::connect(domain,SIGNAL(rangeXChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int)));
100 100 //initialize
101 101 item->handleRangeChanged(domain->minX(),domain->maxX(),domain->tickXCount());
102 102
103 103 }
104 104 else{
105 105 m_chartTheme->decorate(axis,false,m_themeForce);
106 106 QObject::connect(domain,SIGNAL(rangeYChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int)));
107 107 //initialize
108 108 item->handleRangeChanged(domain->minY(),domain->maxY(),domain->tickYCount());
109 109 }
110 110
111 111 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
112 112 //initialize
113 113 item->handleGeometryChanged(m_rect);
114 114 m_axisItems.insert(axis, item);
115 115 }
116 116
117 117 void ChartPresenter::handleAxisRemoved(QChartAxis* axis)
118 118 {
119 119 AxisItem* item = m_axisItems.take(axis);
120 120 Q_ASSERT(item);
121 121 if(m_animator) m_animator->removeAnimation(item);
122 122 delete item;
123 123 }
124 124
125 125
126 126 void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain)
127 127 {
128 128 ChartItem *item = 0 ;
129 129
130 130 switch(series->type())
131 131 {
132 132 case QSeries::SeriesTypeLine: {
133 133
134 134 QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
135 135 LineChartItem* line = new LineChartItem(lineSeries,m_chart);
136 136 if(m_options.testFlag(QChart::SeriesAnimations)) {
137 137 m_animator->addAnimation(line);
138 138 }
139 139 m_chartTheme->decorate(lineSeries, m_dataset->seriesIndex(series),m_themeForce);
140 140 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),line,SLOT(handleGeometryChanged(const QRectF&)));
141 141 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),line,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
142 142 item = line;
143 143 break;
144 144 }
145 145
146 146 case QSeries::SeriesTypeArea: {
147 147
148 148 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
149 149 AreaChartItem* area = new AreaChartItem(areaSeries,m_chart);
150 150 if(m_options.testFlag(QChart::SeriesAnimations)) {
151 151 m_animator->addAnimation(area->upperLineItem());
152 152 if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem());
153 153 }
154 154 m_chartTheme->decorate(areaSeries, m_dataset->seriesIndex(series),m_themeForce);
155 155 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),area,SLOT(handleGeometryChanged(const QRectF&)));
156 156 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),area,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
157 157 item=area;
158 158 break;
159 159 }
160 160
161 161 case QSeries::SeriesTypeBar: {
162 162 QBarSeries* barSeries = static_cast<QBarSeries*>(series);
163 163 BarChartItem* bar = new BarChartItem(barSeries,m_chart);
164 164 if(m_options.testFlag(QChart::SeriesAnimations)) {
165 // m_animator->addAnimation(bar);
165 m_animator->addAnimation(bar);
166 166 }
167 167 m_chartTheme->decorate(barSeries, m_dataset->seriesIndex(barSeries),m_themeForce);
168 168 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
169 169 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
170 170 item=bar;
171 171 break;
172 172 }
173 173
174 174 case QSeries::SeriesTypeStackedBar: {
175 175 QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
176 176 StackedBarChartItem* bar = new StackedBarChartItem(stackedBarSeries,m_chart);
177 177 if(m_options.testFlag(QChart::SeriesAnimations)) {
178 // m_animator->addAnimation(bar);
178 m_animator->addAnimation(bar);
179 179 }
180 180 m_chartTheme->decorate(stackedBarSeries, m_dataset->seriesIndex(stackedBarSeries),m_themeForce);
181 181 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
182 182 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
183 183 item=bar;
184 184 break;
185 185 }
186 186
187 187 case QSeries::SeriesTypePercentBar: {
188 188 QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
189 189 PercentBarChartItem* bar = new PercentBarChartItem(percentBarSeries,m_chart);
190 190 if(m_options.testFlag(QChart::SeriesAnimations)) {
191 // m_animator->addAnimation(bar);
191 m_animator->addAnimation(bar);
192 192 }
193 193 m_chartTheme->decorate(percentBarSeries, m_dataset->seriesIndex(percentBarSeries),m_themeForce);
194 194 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
195 195 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
196 196 item=bar;
197 197 break;
198 198 }
199 199
200 200 case QSeries::SeriesTypeScatter: {
201 201 QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series);
202 202 ScatterChartItem *scatter = new ScatterChartItem(scatterSeries, m_chart);
203 203 if(m_options.testFlag(QChart::SeriesAnimations)) {
204 204 m_animator->addAnimation(scatter);
205 205 }
206 206 m_chartTheme->decorate(scatterSeries, m_dataset->seriesIndex(series),m_themeForce);
207 207 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),scatter,SLOT(handleGeometryChanged(const QRectF&)));
208 208 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),scatter,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
209 209 item = scatter;
210 210 break;
211 211 }
212 212
213 213 case QSeries::SeriesTypePie: {
214 214 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
215 215 PieChartItem* pie = new PieChartItem(pieSeries, this, m_chart);
216 216 if(m_options.testFlag(QChart::SeriesAnimations)) {
217 217 m_animator->addAnimation(pie);
218 218 }
219 219 m_chartTheme->decorate(pieSeries, m_dataset->seriesIndex(series),m_themeForce);
220 220 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&)));
221 221 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),pie,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
222 222 // Hide all from background when there is only piechart
223 223 // TODO: refactor this ugly code... should be one setting for this
224 224 if (m_chartItems.count() == 0) {
225 225 m_chart->axisX()->hide();
226 226 m_chart->axisY()->hide();
227 227 }
228 228 item=pie;
229 229 break;
230 230 }
231 231
232 232 case QSeries::SeriesTypeSpline: {
233 233 QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
234 234 SplineChartItem* spline = new SplineChartItem(splineSeries, m_chart);
235 235 if(m_options.testFlag(QChart::SeriesAnimations)) {
236 236 m_animator->addAnimation(spline);
237 237 }
238 238 m_chartTheme->decorate(splineSeries, m_dataset->seriesIndex(series),m_themeForce);
239 239 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),spline,SLOT(handleGeometryChanged(const QRectF&)));
240 240 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),spline,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
241 241 item=spline;
242 242 break;
243 243 }
244 244 default: {
245 245 qDebug()<< "Series type" << series->type() << "not implemented.";
246 246 break;
247 247 }
248 248 }
249 249
250 250 //initialize
251 251 item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY());
252 252 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
253 253 m_chartItems.insert(series,item);
254 254 zoomReset();
255 255 }
256 256
257 257 void ChartPresenter::handleSeriesRemoved(QSeries* series)
258 258 {
259 259 ChartItem* item = m_chartItems.take(series);
260 260 Q_ASSERT(item);
261 261 if(m_animator) {
262 262 //small hack to handle area animations
263 263 if(series->type()==QSeries::SeriesTypeArea){
264 264 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
265 265 AreaChartItem* area = static_cast<AreaChartItem*>(item);
266 266 m_animator->removeAnimation(area->upperLineItem());
267 267 if(areaSeries->lowerSeries()) m_animator->removeAnimation(area->lowerLineItem());
268 268 }else
269 269 m_animator->removeAnimation(item);
270 270 }
271 271 delete item;
272 272 }
273 273
274 274 void ChartPresenter::setChartTheme(QChart::ChartTheme theme,bool force)
275 275 {
276 276 if(m_chartTheme && m_chartTheme->id() == theme) return;
277 277 delete m_chartTheme;
278 278 m_themeForce = force;
279 279 m_chartTheme = ChartTheme::createTheme(theme);
280 280 m_chartTheme->decorate(m_chart,m_themeForce);
281 281 m_chartTheme->decorate(m_chart->legend(),m_themeForce);
282 282 resetAllElements();
283 283 }
284 284
285 285 QChart::ChartTheme ChartPresenter::chartTheme()
286 286 {
287 287 return m_chartTheme->id();
288 288 }
289 289
290 290 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
291 291 {
292 292 if(m_options!=options) {
293 293
294 294 m_options=options;
295 295
296 296 if(m_options!=QChart::NoAnimation && !m_animator) {
297 297 m_animator= new ChartAnimator(this);
298 298
299 299 }
300 300 resetAllElements();
301 301 }
302 302
303 303 }
304 304
305 305 void ChartPresenter::resetAllElements()
306 306 {
307 307 QList<QChartAxis*> axisList = m_axisItems.uniqueKeys();
308 308 QList<QSeries*> seriesList = m_chartItems.uniqueKeys();
309 309
310 310 foreach(QChartAxis* axis, axisList) {
311 311 handleAxisRemoved(axis);
312 312 handleAxisAdded(axis,m_dataset->domain(axis));
313 313 }
314 314 foreach(QSeries* series, seriesList) {
315 315 handleSeriesRemoved(series);
316 316 handleSeriesAdded(series,m_dataset->domain(series));
317 317 }
318 318 }
319 319
320 320 void ChartPresenter::zoomIn()
321 321 {
322 322 QRectF rect = geometry();
323 323 rect.setWidth(rect.width()/2);
324 324 rect.setHeight(rect.height()/2);
325 325 rect.moveCenter(geometry().center());
326 326 zoomIn(rect);
327 327 }
328 328
329 329 void ChartPresenter::zoomIn(const QRectF& rect)
330 330 {
331 331 QRectF r = rect.normalized();
332 332 r.translate(-m_chart->padding(), -m_chart->padding());
333 333 if(m_animator) {
334 334
335 335 QPointF point(r.center().x()/geometry().width(),r.center().y()/geometry().height());
336 336 m_animator->setState(ChartAnimator::ZoomInState,point);
337 337 }
338 338 m_dataset->zoomInDomain(r,geometry().size());
339 339 m_zoomStack<<r;
340 340 m_zoomIndex++;
341 341 if(m_animator) {
342 342 m_animator->setState(ChartAnimator::ShowState);
343 343 }
344 344 }
345 345
346 346 void ChartPresenter::zoomOut()
347 347 {
348 348 if(m_zoomIndex==0) return;
349 349 if(m_animator)
350 350 {
351 351 m_animator->setState(ChartAnimator::ZoomOutState);
352 352 }
353 353 m_dataset->zoomOutDomain(m_zoomStack[m_zoomIndex-1],geometry().size());
354 354 m_zoomIndex--;
355 355 m_zoomStack.resize(m_zoomIndex);
356 356 if(m_animator){
357 357 m_animator->setState(ChartAnimator::ShowState);
358 358 }
359 359 }
360 360
361 361 void ChartPresenter::zoomReset()
362 362 {
363 363 m_zoomIndex=0;
364 364 m_zoomStack.resize(m_zoomIndex);
365 365 }
366 366
367 367 void ChartPresenter::scroll(int dx,int dy)
368 368 {
369 369 if(m_animator){
370 370 if(dx<0) m_animator->setState(ChartAnimator::ScrollLeftState,QPointF());
371 371 if(dx>0) m_animator->setState(ChartAnimator::ScrollRightState,QPointF());
372 372 if(dy<0) m_animator->setState(ChartAnimator::ScrollUpState,QPointF());
373 373 if(dy>0) m_animator->setState(ChartAnimator::ScrollDownState,QPointF());
374 374 }
375 375
376 376 m_dataset->scrollDomain(dx,dy,geometry().size());
377 377
378 378 if(m_animator){
379 379 m_animator->setState(ChartAnimator::ShowState);
380 380 }
381 381 }
382 382
383 383 QChart::AnimationOptions ChartPresenter::animationOptions() const
384 384 {
385 385 return m_options;
386 386 }
387 387
388 388
389 389 #include "moc_chartpresenter_p.cpp"
390 390
391 391 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now