@@ -0,0 +1,94 | |||
|
1 | #include "PieAnimation_p.h" | |
|
2 | #include "piesliceanimation_p.h" | |
|
3 | #include "piechartitem_p.h" | |
|
4 | #include <QParallelAnimationGroup> | |
|
5 | #include <QTimer> | |
|
6 | ||
|
7 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
|
8 | ||
|
9 | PieAnimation::PieAnimation(PieChartItem *item) | |
|
10 | :ChartAnimation(item), | |
|
11 | m_item(item) | |
|
12 | { | |
|
13 | } | |
|
14 | ||
|
15 | PieAnimation::~PieAnimation() | |
|
16 | { | |
|
17 | } | |
|
18 | ||
|
19 | void PieAnimation::setValues(QVector<PieSliceLayout>& newValues) | |
|
20 | { | |
|
21 | PieSliceAnimation *animation = 0; | |
|
22 | ||
|
23 | foreach (PieSliceLayout endLayout, newValues) { | |
|
24 | animation = m_animations.value(endLayout.m_data); | |
|
25 | if (animation) { | |
|
26 | // existing slice | |
|
27 | animation->stop(); | |
|
28 | animation->updateValue(endLayout); | |
|
29 | } else { | |
|
30 | // new slice | |
|
31 | animation = new PieSliceAnimation(m_item); | |
|
32 | m_animations.insert(endLayout.m_data, animation); | |
|
33 | PieSliceLayout startLayout = endLayout; | |
|
34 | startLayout.m_radius = 0; | |
|
35 | //startLayout.m_startAngle = 0; | |
|
36 | //startLayout.m_angleSpan = 0; | |
|
37 | animation->setValue(startLayout, endLayout); | |
|
38 | } | |
|
39 | animation->setDuration(1000); | |
|
40 | animation->setEasingCurve(QEasingCurve::OutQuart); | |
|
41 | QTimer::singleShot(0, animation, SLOT(start())); // TODO: use sequential animation? | |
|
42 | } | |
|
43 | ||
|
44 | foreach (QPieSlice *s, m_animations.keys()) { | |
|
45 | bool isFound = false; | |
|
46 | foreach (PieSliceLayout layout, newValues) { | |
|
47 | if (s == layout.m_data) | |
|
48 | isFound = true; | |
|
49 | } | |
|
50 | if (!isFound) { | |
|
51 | // slice has been deleted | |
|
52 | animation = m_animations.value(s); | |
|
53 | animation->stop(); | |
|
54 | PieSliceLayout endLayout = m_animations.value(s)->currentSliceValue(); | |
|
55 | endLayout.m_radius = 0; | |
|
56 | // TODO: find the actual angle where this slice disappears | |
|
57 | endLayout.m_startAngle = endLayout.m_startAngle + endLayout.m_angleSpan; | |
|
58 | endLayout.m_angleSpan = 0; | |
|
59 | animation->updateValue(endLayout); | |
|
60 | animation->setDuration(1000); | |
|
61 | animation->setEasingCurve(QEasingCurve::OutQuart); | |
|
62 | connect(animation, SIGNAL(finished()), this, SLOT(destroySliceAnimationComplete())); | |
|
63 | QTimer::singleShot(0, animation, SLOT(start())); | |
|
64 | } | |
|
65 | } | |
|
66 | } | |
|
67 | ||
|
68 | void PieAnimation::updateValue(PieSliceLayout& endLayout) | |
|
69 | { | |
|
70 | PieSliceAnimation *animation = m_animations.value(endLayout.m_data); | |
|
71 | Q_ASSERT(animation); | |
|
72 | animation->stop(); | |
|
73 | animation->updateValue(endLayout); | |
|
74 | animation->setDuration(1000); | |
|
75 | animation->setEasingCurve(QEasingCurve::OutQuart); | |
|
76 | QTimer::singleShot(0, animation, SLOT(start())); | |
|
77 | } | |
|
78 | ||
|
79 | void PieAnimation::updateCurrentValue(const QVariant &) | |
|
80 | { | |
|
81 | // nothing to do... | |
|
82 | } | |
|
83 | ||
|
84 | void PieAnimation::destroySliceAnimationComplete() | |
|
85 | { | |
|
86 | PieSliceAnimation *animation = static_cast<PieSliceAnimation*>(sender()); | |
|
87 | QPieSlice *slice = m_animations.key(animation); | |
|
88 | m_item->destroySlice(slice); | |
|
89 | delete m_animations.take(slice); | |
|
90 | } | |
|
91 | ||
|
92 | #include "moc_pieanimation_p.cpp" | |
|
93 | ||
|
94 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -0,0 +1,35 | |||
|
1 | #ifndef PIEANIMATION_P_H_ | |
|
2 | #define PIEANIMATION_P_H_ | |
|
3 | ||
|
4 | #include "chartanimation_p.h" | |
|
5 | #include "piechartitem_p.h" | |
|
6 | #include "piesliceanimation_p.h" | |
|
7 | ||
|
8 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
|
9 | ||
|
10 | class PieChartItem; | |
|
11 | ||
|
12 | class PieAnimation : public ChartAnimation | |
|
13 | { | |
|
14 | Q_OBJECT | |
|
15 | ||
|
16 | public: | |
|
17 | PieAnimation(PieChartItem *item); | |
|
18 | ~PieAnimation(); | |
|
19 | void setValues(QVector<PieSliceLayout>& newValues); | |
|
20 | void updateValue(PieSliceLayout& newValue); | |
|
21 | ||
|
22 | public: // from QVariantAnimation | |
|
23 | void updateCurrentValue(const QVariant &value); | |
|
24 | ||
|
25 | public Q_SLOTS: | |
|
26 | void destroySliceAnimationComplete(); | |
|
27 | ||
|
28 | private: | |
|
29 | PieChartItem *m_item; | |
|
30 | QHash<QPieSlice*, PieSliceAnimation*> m_animations; | |
|
31 | }; | |
|
32 | ||
|
33 | QTCOMMERCIALCHART_END_NAMESPACE | |
|
34 | ||
|
35 | #endif |
@@ -0,0 +1,77 | |||
|
1 | #include "PieSliceAnimation_p.h" | |
|
2 | #include "piechartitem_p.h" | |
|
3 | #include "qpieslice.h" | |
|
4 | ||
|
5 | Q_DECLARE_METATYPE(QtCommercialChart::PieSliceLayout) | |
|
6 | ||
|
7 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
|
8 | ||
|
9 | qreal linearPos(qreal start, qreal end, qreal pos) | |
|
10 | { | |
|
11 | return start + ((end - start) * pos); | |
|
12 | } | |
|
13 | ||
|
14 | QPointF linearPos(QPointF start, QPointF end, qreal pos) | |
|
15 | { | |
|
16 | qreal x = linearPos(start.x(), end.x(), pos); | |
|
17 | qreal y = linearPos(start.y(), end.y(), pos); | |
|
18 | return QPointF(x, y); | |
|
19 | } | |
|
20 | ||
|
21 | PieSliceAnimation::PieSliceAnimation(PieChartItem *item) | |
|
22 | :QVariantAnimation(item), | |
|
23 | m_item(item) | |
|
24 | { | |
|
25 | } | |
|
26 | ||
|
27 | PieSliceAnimation::~PieSliceAnimation() | |
|
28 | { | |
|
29 | } | |
|
30 | ||
|
31 | void PieSliceAnimation::setValue(PieSliceLayout& startValue, PieSliceLayout& endValue) | |
|
32 | { | |
|
33 | if (state() != QAbstractAnimation::Stopped) | |
|
34 | stop(); | |
|
35 | ||
|
36 | setKeyValueAt(0.0, qVariantFromValue(startValue)); | |
|
37 | setKeyValueAt(1.0, qVariantFromValue(endValue)); | |
|
38 | } | |
|
39 | ||
|
40 | void PieSliceAnimation::updateValue(PieSliceLayout& endValue) | |
|
41 | { | |
|
42 | if (state() != QAbstractAnimation::Stopped) | |
|
43 | stop(); | |
|
44 | ||
|
45 | //qDebug() << "PieSliceAnimation::updateValue()" << endValue.m_data->label() << currentSliceValue().m_startAngle << endValue.m_startAngle; | |
|
46 | ||
|
47 | setKeyValueAt(0.0, qVariantFromValue(currentSliceValue())); | |
|
48 | setKeyValueAt(1.0, qVariantFromValue(endValue)); | |
|
49 | } | |
|
50 | ||
|
51 | PieSliceLayout PieSliceAnimation::currentSliceValue() | |
|
52 | { | |
|
53 | return qVariantValue<PieSliceLayout>(currentValue()); | |
|
54 | } | |
|
55 | ||
|
56 | QVariant PieSliceAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const | |
|
57 | { | |
|
58 | PieSliceLayout startValue = qVariantValue<PieSliceLayout>(start); | |
|
59 | PieSliceLayout endValue = qVariantValue<PieSliceLayout>(end); | |
|
60 | ||
|
61 | PieSliceLayout result; | |
|
62 | result = endValue; | |
|
63 | result.m_center = linearPos(startValue.m_center, endValue.m_center, progress); | |
|
64 | result.m_radius = linearPos(startValue.m_radius, endValue.m_radius, progress); | |
|
65 | result.m_startAngle = linearPos(startValue.m_startAngle, endValue.m_startAngle, progress); | |
|
66 | result.m_angleSpan = linearPos(startValue.m_angleSpan, endValue.m_angleSpan, progress); | |
|
67 | ||
|
68 | return qVariantFromValue(result); | |
|
69 | } | |
|
70 | ||
|
71 | void PieSliceAnimation::updateCurrentValue(const QVariant &value) | |
|
72 | { | |
|
73 | if (state() != QAbstractAnimation::Stopped) //workaround | |
|
74 | m_item->setLayout(qVariantValue<PieSliceLayout>(value)); | |
|
75 | } | |
|
76 | ||
|
77 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -0,0 +1,30 | |||
|
1 | #ifndef PIESLICEANIMATION_P_H_ | |
|
2 | #define PIESLICEANIMATION_P_H_ | |
|
3 | ||
|
4 | #include "piechartitem_p.h" | |
|
5 | #include <QVariantAnimation> | |
|
6 | ||
|
7 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
|
8 | ||
|
9 | class PieChartItem; | |
|
10 | ||
|
11 | class PieSliceAnimation : public QVariantAnimation | |
|
12 | { | |
|
13 | public: | |
|
14 | PieSliceAnimation(PieChartItem *item); | |
|
15 | ~PieSliceAnimation(); | |
|
16 | void setValue(PieSliceLayout& startValue, PieSliceLayout& endValue); | |
|
17 | void updateValue(PieSliceLayout& endValue); | |
|
18 | PieSliceLayout currentSliceValue(); | |
|
19 | ||
|
20 | protected: | |
|
21 | QVariant interpolated(const QVariant &start, const QVariant &end, qreal progress) const; | |
|
22 | void updateCurrentValue(const QVariant &value); | |
|
23 | ||
|
24 | private: | |
|
25 | PieChartItem *m_item; | |
|
26 | }; | |
|
27 | ||
|
28 | QTCOMMERCIALCHART_END_NAMESPACE | |
|
29 | ||
|
30 | #endif |
@@ -287,6 +287,7 public: | |||
|
287 | 287 | // create chart |
|
288 | 288 | m_chartView = new QChartView(); |
|
289 | 289 | m_chartView->setChartTitle("Piechart customization"); |
|
290 | m_chartView->setAnimationOptions(QChart::AllAnimations); | |
|
290 | 291 | |
|
291 | 292 | // create series |
|
292 | 293 | m_series = new QPieSeries(); |
@@ -349,12 +350,15 public: | |||
|
349 | 350 | m_endAngle->setValue(m_series->pieEndAngle()); |
|
350 | 351 | m_endAngle->setSingleStep(1); |
|
351 | 352 | |
|
353 | QPushButton *addSlice = new QPushButton("Add slice"); | |
|
354 | ||
|
352 | 355 | QFormLayout* seriesSettingsLayout = new QFormLayout(); |
|
353 | 356 | seriesSettingsLayout->addRow("Horizontal position", m_hPosition); |
|
354 | 357 | seriesSettingsLayout->addRow("Vertical position", m_vPosition); |
|
355 | 358 | seriesSettingsLayout->addRow("Size factor", m_sizeFactor); |
|
356 | 359 | seriesSettingsLayout->addRow("Start angle", m_startAngle); |
|
357 | 360 | seriesSettingsLayout->addRow("End angle", m_endAngle); |
|
361 | seriesSettingsLayout->addRow(addSlice); | |
|
358 | 362 | QGroupBox* seriesSettings = new QGroupBox("Series"); |
|
359 | 363 | seriesSettings->setLayout(seriesSettingsLayout); |
|
360 | 364 | |
@@ -363,6 +367,7 public: | |||
|
363 | 367 | connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); |
|
364 | 368 | connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); |
|
365 | 369 | connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); |
|
370 | connect(addSlice, SIGNAL(clicked()), this, SLOT(addSlice())); | |
|
366 | 371 | |
|
367 | 372 | // slice settings |
|
368 | 373 | m_sliceName = new QLabel("<click a slice>"); |
@@ -381,6 +386,7 public: | |||
|
381 | 386 | m_font = new QPushButton(); |
|
382 | 387 | m_labelArmPen = new QPushButton(); |
|
383 | 388 | m_labelArmPenTool = new PenTool("Label arm pen", this); |
|
389 | QPushButton *removeSlice = new QPushButton("Remove slice"); | |
|
384 | 390 | |
|
385 | 391 | QFormLayout* sliceSettingsLayout = new QFormLayout(); |
|
386 | 392 | sliceSettingsLayout->addRow("Selected", m_sliceName); |
@@ -393,6 +399,7 public: | |||
|
393 | 399 | sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor); |
|
394 | 400 | sliceSettingsLayout->addRow("Exploded", m_sliceExploded); |
|
395 | 401 | sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor); |
|
402 | sliceSettingsLayout->addRow(removeSlice); | |
|
396 | 403 | QGroupBox* sliceSettings = new QGroupBox("Slice"); |
|
397 | 404 | sliceSettings->setLayout(sliceSettingsLayout); |
|
398 | 405 | |
@@ -409,6 +416,7 public: | |||
|
409 | 416 | connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); |
|
410 | 417 | connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings())); |
|
411 | 418 | connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); |
|
419 | connect(removeSlice, SIGNAL(clicked()), this, SLOT(removeSlice())); | |
|
412 | 420 | |
|
413 | 421 | // create main layout |
|
414 | 422 | QVBoxLayout *settingsLayout = new QVBoxLayout(); |
@@ -513,6 +521,20 public Q_SLOTS: | |||
|
513 | 521 | m_font->setText(dialog.currentFont().toString()); |
|
514 | 522 | } |
|
515 | 523 | |
|
524 | void addSlice() | |
|
525 | { | |
|
526 | *m_series << new CustomSlice(10.0, "Slice " + QString::number(m_series->count())); | |
|
527 | } | |
|
528 | ||
|
529 | void removeSlice() | |
|
530 | { | |
|
531 | if (!m_slice) | |
|
532 | return; | |
|
533 | ||
|
534 | m_series->remove(m_slice); | |
|
535 | m_slice = 0; | |
|
536 | } | |
|
537 | ||
|
516 | 538 | private: |
|
517 | 539 | QComboBox *m_themeComboBox; |
|
518 | 540 | QCheckBox *m_aaCheckBox; |
@@ -4,10 +4,14 DEPENDPATH += $$PWD | |||
|
4 | 4 | SOURCES += \ |
|
5 | 5 | $$PWD/axisanimation.cpp \ |
|
6 | 6 | $$PWD/chartanimator.cpp \ |
|
7 | $$PWD/xyanimation.cpp | |
|
7 | $$PWD/xyanimation.cpp \ | |
|
8 | $$PWD/pieanimation.cpp \ | |
|
9 | $$PWD/piesliceanimation.cpp | |
|
8 | 10 | |
|
9 | 11 | PRIVATE_HEADERS += \ |
|
10 | 12 | $$PWD/axisanimation_p.h \ |
|
11 | 13 | $$PWD/chartanimator_p.h \ |
|
12 | 14 | $$PWD/chartanimation_p.h \ |
|
13 | $$PWD/xyanimation_p.h No newline at end of file | |
|
15 | $$PWD/xyanimation_p.h \ | |
|
16 | $$PWD/pieanimation_p.h \ | |
|
17 | $$PWD/piesliceanimation_p.h |
@@ -2,6 +2,7 | |||
|
2 | 2 | #include "axisanimation_p.h" |
|
3 | 3 | #include "xyanimation_p.h" |
|
4 | 4 | #include "xychartitem_p.h" |
|
5 | #include "pieanimation_p.h" | |
|
5 | 6 | #include "areachartitem_p.h" |
|
6 | 7 | #include <QTimer> |
|
7 | 8 | |
@@ -44,6 +45,18 void ChartAnimator::addAnimation(XYChartItem* item) | |||
|
44 | 45 | item->setAnimator(this); |
|
45 | 46 | } |
|
46 | 47 | |
|
48 | void ChartAnimator::addAnimation(PieChartItem* item) | |
|
49 | { | |
|
50 | ChartAnimation* animation = m_animations.value(item); | |
|
51 | ||
|
52 | if(!animation) { | |
|
53 | animation = new PieAnimation(item); | |
|
54 | m_animations.insert(item,animation); | |
|
55 | } | |
|
56 | ||
|
57 | item->setAnimator(this); | |
|
58 | } | |
|
59 | ||
|
47 | 60 | void ChartAnimator::removeAnimation(ChartItem* item) |
|
48 | 61 | { |
|
49 | 62 | item->setAnimator(0); |
@@ -171,6 +184,20 void ChartAnimator::updateLayout(XYChartItem* item, QVector<QPointF>& newPoints) | |||
|
171 | 184 | QTimer::singleShot(0,animation,SLOT(start())); |
|
172 | 185 | } |
|
173 | 186 | |
|
187 | void ChartAnimator::applyLayout(PieChartItem* item, QVector<PieSliceLayout> &layout) | |
|
188 | { | |
|
189 | PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item)); | |
|
190 | Q_ASSERT(animation); | |
|
191 | animation->setValues(layout); | |
|
192 | } | |
|
193 | ||
|
194 | void ChartAnimator::updateLayout(PieChartItem* item, PieSliceLayout &layout) | |
|
195 | { | |
|
196 | PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item)); | |
|
197 | Q_ASSERT(animation); | |
|
198 | animation->updateValue(layout); | |
|
199 | } | |
|
200 | ||
|
174 | 201 | void ChartAnimator::setState(State state,const QPointF& point) |
|
175 | 202 | { |
|
176 | 203 | m_state=state; |
@@ -2,6 +2,7 | |||
|
2 | 2 | #define CHARTANIMATOR_P_H_ |
|
3 | 3 | #include "qchartglobal.h" |
|
4 | 4 | #include "chartanimation_p.h" |
|
5 | #include "piechartitem_p.h" | |
|
5 | 6 | #include <QPointF> |
|
6 | 7 | |
|
7 | 8 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
@@ -22,6 +23,7 public: | |||
|
22 | 23 | |
|
23 | 24 | void addAnimation(AxisItem* item); |
|
24 | 25 | void addAnimation(XYChartItem* item); |
|
26 | void addAnimation(PieChartItem* item); | |
|
25 | 27 | |
|
26 | 28 | void removeAnimation(ChartItem* item); |
|
27 | 29 | |
@@ -30,6 +32,9 public: | |||
|
30 | 32 | void updateLayout(XYChartItem* item, QVector<QPointF>& layout); |
|
31 | 33 | void applyLayout(AxisItem* item, QVector<qreal>& layout); |
|
32 | 34 | |
|
35 | void applyLayout(PieChartItem* item, QVector<PieSliceLayout> &layout); | |
|
36 | void updateLayout(PieChartItem* item, PieSliceLayout &layout); | |
|
37 | ||
|
33 | 38 | void setState(State state,const QPointF& point = QPointF()); |
|
34 | 39 | |
|
35 | 40 | private: |
@@ -224,7 +224,7 void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain) | |||
|
224 | 224 | QPieSeries *pieSeries = static_cast<QPieSeries *>(series); |
|
225 | 225 | PieChartItem* pie = new PieChartItem(m_chart, pieSeries); |
|
226 | 226 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
227 |
|
|
|
227 | m_animator->addAnimation(pie); | |
|
228 | 228 | } |
|
229 | 229 | m_chartTheme->decorate(pieSeries, m_dataset->seriesIndex(series)); |
|
230 | 230 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&))); |
@@ -3,6 +3,7 | |||
|
3 | 3 | #include "qpieslice.h" |
|
4 | 4 | #include "qpieseries.h" |
|
5 | 5 | #include "chartpresenter_p.h" |
|
6 | #include "chartanimator_p.h" | |
|
6 | 7 | #include <QDebug> |
|
7 | 8 | #include <QPainter> |
|
8 | 9 | |
@@ -36,16 +37,24 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QW | |||
|
36 | 37 | |
|
37 | 38 | void PieChartItem::handleSeriesChanged() |
|
38 | 39 | { |
|
39 |
QVector<PieSliceLayout> |
|
|
40 |
applyLayout( |
|
|
40 | QVector<PieSliceLayout> layout = calculateLayout(); | |
|
41 | applyLayout(layout); | |
|
41 | 42 | update(); |
|
42 | 43 | } |
|
43 | 44 | |
|
44 | 45 | void PieChartItem::handleSliceChanged() |
|
45 | 46 | { |
|
46 | // TODO: optimize don't need to handle all slices | |
|
47 | QVector<PieSliceLayout> sliceLayout = calculateLayout(); | |
|
48 | applyLayout(sliceLayout); | |
|
47 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | |
|
48 | Q_ASSERT(m_slices.contains(slice)); | |
|
49 | ||
|
50 | //qDebug() << "PieChartItem::handleSliceChanged" << slice->label(); | |
|
51 | ||
|
52 | // TODO: Optimize. No need to calculate everything. | |
|
53 | QVector<PieSliceLayout> layout = calculateLayout(); | |
|
54 | foreach (PieSliceLayout sl, layout) { | |
|
55 | if (sl.m_data == slice) | |
|
56 | updateLayout(sl); | |
|
57 | } | |
|
49 | 58 | update(); |
|
50 | 59 | } |
|
51 | 60 | |
@@ -93,15 +102,23 QVector<PieSliceLayout> PieChartItem::calculateLayout() | |||
|
93 | 102 | return layout; |
|
94 | 103 | } |
|
95 | 104 | |
|
96 |
void PieChartItem::applyLayout( |
|
|
105 | void PieChartItem::applyLayout(QVector<PieSliceLayout> &layout) | |
|
97 | 106 | { |
|
98 |
|
|
|
99 |
|
|
|
100 |
|
|
|
101 | setLayout(layout); | |
|
107 | if (m_animator) | |
|
108 | m_animator->applyLayout(this, layout); | |
|
109 | else | |
|
110 | setLayout(layout); | |
|
102 | 111 | } |
|
103 | 112 | |
|
104 |
void PieChartItem:: |
|
|
113 | void PieChartItem::updateLayout(PieSliceLayout &layout) | |
|
114 | { | |
|
115 | if (m_animator) | |
|
116 | m_animator->updateLayout(this, layout); | |
|
117 | else | |
|
118 | setLayout(layout); | |
|
119 | } | |
|
120 | ||
|
121 | void PieChartItem::setLayout(QVector<PieSliceLayout> &layout) | |
|
105 | 122 | { |
|
106 | 123 | foreach (PieSliceLayout l, layout) { |
|
107 | 124 | |
@@ -135,8 +152,32 void PieChartItem::setLayout(const QVector<PieSliceLayout> &layout) | |||
|
135 | 152 | } |
|
136 | 153 | |
|
137 | 154 | if (!found) |
|
138 |
de |
|
|
155 | destroySlice(s); | |
|
156 | } | |
|
157 | } | |
|
158 | ||
|
159 | void PieChartItem::setLayout(PieSliceLayout &layout) | |
|
160 | { | |
|
161 | // find slice | |
|
162 | PieSlice *slice = m_slices.value(layout.m_data); | |
|
163 | if (!slice) { | |
|
164 | slice = new PieSlice(this); | |
|
165 | m_slices.insert(layout.m_data, slice); | |
|
166 | connect(layout.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged())); | |
|
167 | connect(slice, SIGNAL(clicked()), layout.m_data, SIGNAL(clicked())); | |
|
168 | connect(slice, SIGNAL(hoverEnter()), layout.m_data, SIGNAL(hoverEnter())); | |
|
169 | connect(slice, SIGNAL(hoverLeave()), layout.m_data, SIGNAL(hoverLeave())); | |
|
139 | 170 | } |
|
171 | slice->setLayout(layout); | |
|
172 | if (m_series->m_slices.contains(layout.m_data)) // Slice has been deleted if not found. Animations ongoing... | |
|
173 | slice->updateData(layout.m_data); | |
|
174 | slice->updateGeometry(); | |
|
175 | slice->update(); | |
|
176 | } | |
|
177 | ||
|
178 | void PieChartItem::destroySlice(QPieSlice *slice) | |
|
179 | { | |
|
180 | delete m_slices.take(slice); | |
|
140 | 181 | } |
|
141 | 182 | |
|
142 | 183 | #include "moc_piechartitem_p.cpp" |
@@ -28,10 +28,13 public Q_SLOTS: | |||
|
28 | 28 | void handleDomainChanged(qreal, qreal, qreal, qreal); |
|
29 | 29 | void handleGeometryChanged(const QRectF& rect); |
|
30 | 30 | |
|
31 | private: | |
|
31 | public: | |
|
32 | 32 | QVector<PieSliceLayout> calculateLayout(); |
|
33 |
void applyLayout( |
|
|
34 |
void |
|
|
33 | void applyLayout(QVector<PieSliceLayout> &layout); | |
|
34 | void updateLayout(PieSliceLayout &layout); | |
|
35 | void setLayout(QVector<PieSliceLayout> &layout); | |
|
36 | void setLayout(PieSliceLayout &layout); | |
|
37 | void destroySlice(QPieSlice *slice); | |
|
35 | 38 | |
|
36 | 39 | private: |
|
37 | 40 | friend class PieSlice; |
@@ -22,8 +22,6 QPointF offset(qreal angle, qreal length) | |||
|
22 | 22 | |
|
23 | 23 | PieSlice::PieSlice(QGraphicsItem* parent) |
|
24 | 24 | :QGraphicsObject(parent), |
|
25 | m_startAngle(0), | |
|
26 | m_angleSpan(0), | |
|
27 | 25 | m_isExploded(false), |
|
28 | 26 | m_explodeDistanceFactor(0), |
|
29 | 27 | m_labelVisible(false), |
@@ -41,7 +39,7 PieSlice::~PieSlice() | |||
|
41 | 39 | |
|
42 | 40 | QRectF PieSlice::boundingRect() const |
|
43 | 41 | { |
|
44 | return m_slicePath.boundingRect(); | |
|
42 | return m_slicePath.boundingRect().united(m_labelTextRect); | |
|
45 | 43 | } |
|
46 | 44 | |
|
47 | 45 | QPainterPath PieSlice::shape() const |
@@ -90,7 +88,6 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/) | |||
|
90 | 88 | void PieSlice::setLayout(PieSliceLayout layout) |
|
91 | 89 | { |
|
92 | 90 | m_layout = layout; |
|
93 | updateData(layout.m_data); | |
|
94 | 91 | } |
|
95 | 92 | |
|
96 | 93 | void PieSlice::updateGeometry() |
@@ -103,7 +100,7 void PieSlice::updateGeometry() | |||
|
103 | 100 | // update slice path |
|
104 | 101 | qreal centerAngle; |
|
105 | 102 | QPointF armStart; |
|
106 | m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_startAngle, m_angleSpan, ¢erAngle, &armStart); | |
|
103 | m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_layout.m_startAngle, m_layout.m_angleSpan, ¢erAngle, &armStart); | |
|
107 | 104 | |
|
108 | 105 | // update text rect |
|
109 | 106 | m_labelTextRect = labelTextRect(m_labelFont, m_labelText); |
@@ -122,8 +119,6 void PieSlice::updateData(const QPieSlice* sliceData) | |||
|
122 | 119 | { |
|
123 | 120 | // TODO: compare what has changes to avoid unneccesary geometry updates |
|
124 | 121 | |
|
125 | m_startAngle = sliceData->startAngle(); | |
|
126 | m_angleSpan = sliceData->m_angleSpan; | |
|
127 | 122 | m_isExploded = sliceData->isExploded(); |
|
128 | 123 | m_explodeDistanceFactor = sliceData->explodeDistanceFactor(); |
|
129 | 124 | m_slicePen = sliceData->slicePen(); |
@@ -19,7 +19,7 class QPieSlice; | |||
|
19 | 19 | class PieSliceLayout |
|
20 | 20 | { |
|
21 | 21 | public: |
|
22 | QPieSlice* m_data; | |
|
22 | QPieSlice* m_data; // TODO: get rid of this | |
|
23 | 23 | QPointF m_center; |
|
24 | 24 | qreal m_radius; |
|
25 | 25 | qreal m_startAngle; |
@@ -60,8 +60,6 private: | |||
|
60 | 60 | PieSliceLayout m_layout; |
|
61 | 61 | |
|
62 | 62 | QPainterPath m_slicePath; |
|
63 | qreal m_startAngle; | |
|
64 | qreal m_angleSpan; | |
|
65 | 63 | bool m_isExploded; |
|
66 | 64 | qreal m_explodeDistanceFactor; |
|
67 | 65 | bool m_labelVisible; |
@@ -511,6 +511,8 void QPieSeries::updateDerivativeData() | |||
|
511 | 511 | foreach (QPieSlice* s, m_slices) |
|
512 | 512 | m_total += s->value(); |
|
513 | 513 | |
|
514 | // TODO: emit totalChanged? | |
|
515 | ||
|
514 | 516 | // we must have some values |
|
515 | 517 | if (m_total == 0) { |
|
516 | 518 | qDebug() << "QPieSeries::updateDerivativeData() total == 0"; |
@@ -520,31 +522,35 void QPieSeries::updateDerivativeData() | |||
|
520 | 522 | // update slice attributes |
|
521 | 523 | qreal sliceAngle = m_pieStartAngle; |
|
522 | 524 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; |
|
525 | QVector<QPieSlice*> changed; | |
|
523 | 526 | foreach (QPieSlice* s, m_slices) { |
|
524 | 527 | |
|
525 |
bool |
|
|
528 | bool isChanged = false; | |
|
526 | 529 | |
|
527 | 530 | qreal percentage = s->value() / m_total; |
|
528 | 531 | if (s->m_percentage != percentage) { |
|
529 | 532 | s->m_percentage = percentage; |
|
530 |
|
|
|
533 | isChanged = true; | |
|
531 | 534 | } |
|
532 | 535 | |
|
533 | 536 | qreal sliceSpan = pieSpan * percentage; |
|
534 | 537 | if (s->m_angleSpan != sliceSpan) { |
|
535 | 538 | s->m_angleSpan = sliceSpan; |
|
536 |
|
|
|
539 | isChanged = true; | |
|
537 | 540 | } |
|
538 | 541 | |
|
539 | 542 | if (s->m_startAngle != sliceAngle) { |
|
540 | 543 | s->m_startAngle = sliceAngle; |
|
541 |
|
|
|
544 | isChanged = true; | |
|
542 | 545 | } |
|
543 | 546 | sliceAngle += sliceSpan; |
|
544 | 547 | |
|
545 |
if ( |
|
|
546 |
|
|
|
548 | if (isChanged) | |
|
549 | changed << s; | |
|
547 | 550 | } |
|
551 | ||
|
552 | foreach (QPieSlice* s, changed) | |
|
553 | emit s->changed(); | |
|
548 | 554 | } |
|
549 | 555 | |
|
550 | 556 | bool QPieSeries::setModel(QAbstractItemModel* model) |
@@ -124,6 +124,7 private: | |||
|
124 | 124 | // TODO: use PIML |
|
125 | 125 | friend class PieChartItem; |
|
126 | 126 | friend class PieSlice; |
|
127 | friend class QPieSlice; | |
|
127 | 128 | |
|
128 | 129 | QList<QPieSlice*> m_slices; |
|
129 | 130 | qreal m_pieRelativeHorPos; |
@@ -1,4 +1,5 | |||
|
1 | 1 | #include "qpieslice.h" |
|
2 | #include "qpieseries.h" | |
|
2 | 3 | |
|
3 | 4 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
4 | 5 | |
@@ -266,7 +267,12 void QPieSlice::setValue(qreal value) | |||
|
266 | 267 | { |
|
267 | 268 | if (m_value != value) { |
|
268 | 269 | m_value = value; |
|
269 | emit changed(); | |
|
270 | ||
|
271 | QPieSeries *series = qobject_cast<QPieSeries*>(parent()); | |
|
272 | if (series) | |
|
273 | series->updateDerivativeData(); // will emit changed() | |
|
274 | else | |
|
275 | emit changed(); | |
|
270 | 276 | } |
|
271 | 277 | } |
|
272 | 278 |
@@ -8,6 +8,7 | |||
|
8 | 8 | #include <QFont> |
|
9 | 9 | |
|
10 | 10 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
11 | class QPieSeries; | |
|
11 | 12 | |
|
12 | 13 | class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject |
|
13 | 14 | { |
@@ -29,8 +30,6 public: | |||
|
29 | 30 | bool isLabelVisible() const; |
|
30 | 31 | void setExploded(bool exploded); |
|
31 | 32 | bool isExploded() const; |
|
32 | void setExplodeDistanceFactor(qreal factor); | |
|
33 | qreal explodeDistanceFactor() const; | |
|
34 | 33 | |
|
35 | 34 | // generated data |
|
36 | 35 | qreal percentage() const; |
@@ -48,10 +47,8 public: | |||
|
48 | 47 | QFont labelFont() const; |
|
49 | 48 | void setLabelArmLengthFactor(qreal factor); |
|
50 | 49 | qreal labelArmLengthFactor() const; |
|
51 | ||
|
52 | // TODO: label position in general | |
|
53 | // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???) | |
|
54 | // setLabelOrientation(horizontal|vertical|same as slice center angle|???) | |
|
50 | void setExplodeDistanceFactor(qreal factor); | |
|
51 | qreal explodeDistanceFactor() const; | |
|
55 | 52 | |
|
56 | 53 | Q_SIGNALS: |
|
57 | 54 | void clicked(); |
General Comments 0
You need to be logged in to leave comments.
Login now