@@ -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 | // create chart |
|
287 | // create chart | |
288 | m_chartView = new QChartView(); |
|
288 | m_chartView = new QChartView(); | |
289 | m_chartView->setChartTitle("Piechart customization"); |
|
289 | m_chartView->setChartTitle("Piechart customization"); | |
|
290 | m_chartView->setAnimationOptions(QChart::AllAnimations); | |||
290 |
|
291 | |||
291 | // create series |
|
292 | // create series | |
292 | m_series = new QPieSeries(); |
|
293 | m_series = new QPieSeries(); | |
@@ -349,12 +350,15 public: | |||||
349 | m_endAngle->setValue(m_series->pieEndAngle()); |
|
350 | m_endAngle->setValue(m_series->pieEndAngle()); | |
350 | m_endAngle->setSingleStep(1); |
|
351 | m_endAngle->setSingleStep(1); | |
351 |
|
352 | |||
|
353 | QPushButton *addSlice = new QPushButton("Add slice"); | |||
|
354 | ||||
352 | QFormLayout* seriesSettingsLayout = new QFormLayout(); |
|
355 | QFormLayout* seriesSettingsLayout = new QFormLayout(); | |
353 | seriesSettingsLayout->addRow("Horizontal position", m_hPosition); |
|
356 | seriesSettingsLayout->addRow("Horizontal position", m_hPosition); | |
354 | seriesSettingsLayout->addRow("Vertical position", m_vPosition); |
|
357 | seriesSettingsLayout->addRow("Vertical position", m_vPosition); | |
355 | seriesSettingsLayout->addRow("Size factor", m_sizeFactor); |
|
358 | seriesSettingsLayout->addRow("Size factor", m_sizeFactor); | |
356 | seriesSettingsLayout->addRow("Start angle", m_startAngle); |
|
359 | seriesSettingsLayout->addRow("Start angle", m_startAngle); | |
357 | seriesSettingsLayout->addRow("End angle", m_endAngle); |
|
360 | seriesSettingsLayout->addRow("End angle", m_endAngle); | |
|
361 | seriesSettingsLayout->addRow(addSlice); | |||
358 | QGroupBox* seriesSettings = new QGroupBox("Series"); |
|
362 | QGroupBox* seriesSettings = new QGroupBox("Series"); | |
359 | seriesSettings->setLayout(seriesSettingsLayout); |
|
363 | seriesSettings->setLayout(seriesSettingsLayout); | |
360 |
|
364 | |||
@@ -363,6 +367,7 public: | |||||
363 | connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); |
|
367 | connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); | |
364 | connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); |
|
368 | connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); | |
365 | connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); |
|
369 | connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings())); | |
|
370 | connect(addSlice, SIGNAL(clicked()), this, SLOT(addSlice())); | |||
366 |
|
371 | |||
367 | // slice settings |
|
372 | // slice settings | |
368 | m_sliceName = new QLabel("<click a slice>"); |
|
373 | m_sliceName = new QLabel("<click a slice>"); | |
@@ -381,6 +386,7 public: | |||||
381 | m_font = new QPushButton(); |
|
386 | m_font = new QPushButton(); | |
382 | m_labelArmPen = new QPushButton(); |
|
387 | m_labelArmPen = new QPushButton(); | |
383 | m_labelArmPenTool = new PenTool("Label arm pen", this); |
|
388 | m_labelArmPenTool = new PenTool("Label arm pen", this); | |
|
389 | QPushButton *removeSlice = new QPushButton("Remove slice"); | |||
384 |
|
390 | |||
385 | QFormLayout* sliceSettingsLayout = new QFormLayout(); |
|
391 | QFormLayout* sliceSettingsLayout = new QFormLayout(); | |
386 | sliceSettingsLayout->addRow("Selected", m_sliceName); |
|
392 | sliceSettingsLayout->addRow("Selected", m_sliceName); | |
@@ -393,6 +399,7 public: | |||||
393 | sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor); |
|
399 | sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor); | |
394 | sliceSettingsLayout->addRow("Exploded", m_sliceExploded); |
|
400 | sliceSettingsLayout->addRow("Exploded", m_sliceExploded); | |
395 | sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor); |
|
401 | sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor); | |
|
402 | sliceSettingsLayout->addRow(removeSlice); | |||
396 | QGroupBox* sliceSettings = new QGroupBox("Slice"); |
|
403 | QGroupBox* sliceSettings = new QGroupBox("Slice"); | |
397 | sliceSettings->setLayout(sliceSettingsLayout); |
|
404 | sliceSettings->setLayout(sliceSettingsLayout); | |
398 |
|
405 | |||
@@ -409,6 +416,7 public: | |||||
409 | connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); |
|
416 | connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); | |
410 | connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings())); |
|
417 | connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings())); | |
411 | connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); |
|
418 | connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings())); | |
|
419 | connect(removeSlice, SIGNAL(clicked()), this, SLOT(removeSlice())); | |||
412 |
|
420 | |||
413 | // create main layout |
|
421 | // create main layout | |
414 | QVBoxLayout *settingsLayout = new QVBoxLayout(); |
|
422 | QVBoxLayout *settingsLayout = new QVBoxLayout(); | |
@@ -513,6 +521,20 public Q_SLOTS: | |||||
513 | m_font->setText(dialog.currentFont().toString()); |
|
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 | private: |
|
538 | private: | |
517 | QComboBox *m_themeComboBox; |
|
539 | QComboBox *m_themeComboBox; | |
518 | QCheckBox *m_aaCheckBox; |
|
540 | QCheckBox *m_aaCheckBox; |
@@ -4,10 +4,14 DEPENDPATH += $$PWD | |||||
4 | SOURCES += \ |
|
4 | SOURCES += \ | |
5 | $$PWD/axisanimation.cpp \ |
|
5 | $$PWD/axisanimation.cpp \ | |
6 | $$PWD/chartanimator.cpp \ |
|
6 | $$PWD/chartanimator.cpp \ | |
7 | $$PWD/xyanimation.cpp |
|
7 | $$PWD/xyanimation.cpp \ | |
|
8 | $$PWD/pieanimation.cpp \ | |||
|
9 | $$PWD/piesliceanimation.cpp | |||
8 |
|
10 | |||
9 | PRIVATE_HEADERS += \ |
|
11 | PRIVATE_HEADERS += \ | |
10 | $$PWD/axisanimation_p.h \ |
|
12 | $$PWD/axisanimation_p.h \ | |
11 | $$PWD/chartanimator_p.h \ |
|
13 | $$PWD/chartanimator_p.h \ | |
12 | $$PWD/chartanimation_p.h \ |
|
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 | #include "axisanimation_p.h" |
|
2 | #include "axisanimation_p.h" | |
3 | #include "xyanimation_p.h" |
|
3 | #include "xyanimation_p.h" | |
4 | #include "xychartitem_p.h" |
|
4 | #include "xychartitem_p.h" | |
|
5 | #include "pieanimation_p.h" | |||
5 | #include "areachartitem_p.h" |
|
6 | #include "areachartitem_p.h" | |
6 | #include <QTimer> |
|
7 | #include <QTimer> | |
7 |
|
8 | |||
@@ -44,6 +45,18 void ChartAnimator::addAnimation(XYChartItem* item) | |||||
44 | item->setAnimator(this); |
|
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 | void ChartAnimator::removeAnimation(ChartItem* item) |
|
60 | void ChartAnimator::removeAnimation(ChartItem* item) | |
48 | { |
|
61 | { | |
49 | item->setAnimator(0); |
|
62 | item->setAnimator(0); | |
@@ -171,6 +184,20 void ChartAnimator::updateLayout(XYChartItem* item, QVector<QPointF>& newPoints) | |||||
171 | QTimer::singleShot(0,animation,SLOT(start())); |
|
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 | void ChartAnimator::setState(State state,const QPointF& point) |
|
201 | void ChartAnimator::setState(State state,const QPointF& point) | |
175 | { |
|
202 | { | |
176 | m_state=state; |
|
203 | m_state=state; |
@@ -2,6 +2,7 | |||||
2 | #define CHARTANIMATOR_P_H_ |
|
2 | #define CHARTANIMATOR_P_H_ | |
3 | #include "qchartglobal.h" |
|
3 | #include "qchartglobal.h" | |
4 | #include "chartanimation_p.h" |
|
4 | #include "chartanimation_p.h" | |
|
5 | #include "piechartitem_p.h" | |||
5 | #include <QPointF> |
|
6 | #include <QPointF> | |
6 |
|
7 | |||
7 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
8 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
@@ -22,6 +23,7 public: | |||||
22 |
|
23 | |||
23 | void addAnimation(AxisItem* item); |
|
24 | void addAnimation(AxisItem* item); | |
24 | void addAnimation(XYChartItem* item); |
|
25 | void addAnimation(XYChartItem* item); | |
|
26 | void addAnimation(PieChartItem* item); | |||
25 |
|
27 | |||
26 | void removeAnimation(ChartItem* item); |
|
28 | void removeAnimation(ChartItem* item); | |
27 |
|
29 | |||
@@ -30,6 +32,9 public: | |||||
30 | void updateLayout(XYChartItem* item, QVector<QPointF>& layout); |
|
32 | void updateLayout(XYChartItem* item, QVector<QPointF>& layout); | |
31 | void applyLayout(AxisItem* item, QVector<qreal>& layout); |
|
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 | void setState(State state,const QPointF& point = QPointF()); |
|
38 | void setState(State state,const QPointF& point = QPointF()); | |
34 |
|
39 | |||
35 | private: |
|
40 | private: |
@@ -224,7 +224,7 void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain) | |||||
224 | QPieSeries *pieSeries = static_cast<QPieSeries *>(series); |
|
224 | QPieSeries *pieSeries = static_cast<QPieSeries *>(series); | |
225 | PieChartItem* pie = new PieChartItem(m_chart, pieSeries); |
|
225 | PieChartItem* pie = new PieChartItem(m_chart, pieSeries); | |
226 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
226 | if(m_options.testFlag(QChart::SeriesAnimations)) { | |
227 |
|
|
227 | m_animator->addAnimation(pie); | |
228 | } |
|
228 | } | |
229 | m_chartTheme->decorate(pieSeries, m_dataset->seriesIndex(series)); |
|
229 | m_chartTheme->decorate(pieSeries, m_dataset->seriesIndex(series)); | |
230 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&))); |
|
230 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&))); |
@@ -3,6 +3,7 | |||||
3 | #include "qpieslice.h" |
|
3 | #include "qpieslice.h" | |
4 | #include "qpieseries.h" |
|
4 | #include "qpieseries.h" | |
5 | #include "chartpresenter_p.h" |
|
5 | #include "chartpresenter_p.h" | |
|
6 | #include "chartanimator_p.h" | |||
6 | #include <QDebug> |
|
7 | #include <QDebug> | |
7 | #include <QPainter> |
|
8 | #include <QPainter> | |
8 |
|
9 | |||
@@ -36,16 +37,24 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QW | |||||
36 |
|
37 | |||
37 | void PieChartItem::handleSeriesChanged() |
|
38 | void PieChartItem::handleSeriesChanged() | |
38 | { |
|
39 | { | |
39 |
QVector<PieSliceLayout> |
|
40 | QVector<PieSliceLayout> layout = calculateLayout(); | |
40 |
applyLayout( |
|
41 | applyLayout(layout); | |
41 | update(); |
|
42 | update(); | |
42 | } |
|
43 | } | |
43 |
|
44 | |||
44 | void PieChartItem::handleSliceChanged() |
|
45 | void PieChartItem::handleSliceChanged() | |
45 | { |
|
46 | { | |
46 | // TODO: optimize don't need to handle all slices |
|
47 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | |
47 | QVector<PieSliceLayout> sliceLayout = calculateLayout(); |
|
48 | Q_ASSERT(m_slices.contains(slice)); | |
48 | applyLayout(sliceLayout); |
|
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 | update(); |
|
58 | update(); | |
50 | } |
|
59 | } | |
51 |
|
60 | |||
@@ -93,15 +102,23 QVector<PieSliceLayout> PieChartItem::calculateLayout() | |||||
93 | return layout; |
|
102 | return layout; | |
94 | } |
|
103 | } | |
95 |
|
104 | |||
96 |
void PieChartItem::applyLayout( |
|
105 | void PieChartItem::applyLayout(QVector<PieSliceLayout> &layout) | |
97 | { |
|
106 | { | |
98 |
|
|
107 | if (m_animator) | |
99 |
|
|
108 | m_animator->applyLayout(this, layout); | |
100 |
|
|
109 | else | |
101 | setLayout(layout); |
|
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 | foreach (PieSliceLayout l, layout) { |
|
123 | foreach (PieSliceLayout l, layout) { | |
107 |
|
124 | |||
@@ -135,8 +152,32 void PieChartItem::setLayout(const QVector<PieSliceLayout> &layout) | |||||
135 | } |
|
152 | } | |
136 |
|
153 | |||
137 | if (!found) |
|
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 | #include "moc_piechartitem_p.cpp" |
|
183 | #include "moc_piechartitem_p.cpp" |
@@ -28,10 +28,13 public Q_SLOTS: | |||||
28 | void handleDomainChanged(qreal, qreal, qreal, qreal); |
|
28 | void handleDomainChanged(qreal, qreal, qreal, qreal); | |
29 | void handleGeometryChanged(const QRectF& rect); |
|
29 | void handleGeometryChanged(const QRectF& rect); | |
30 |
|
30 | |||
31 | private: |
|
31 | public: | |
32 | QVector<PieSliceLayout> calculateLayout(); |
|
32 | QVector<PieSliceLayout> calculateLayout(); | |
33 |
void applyLayout( |
|
33 | void applyLayout(QVector<PieSliceLayout> &layout); | |
34 |
void |
|
34 | void updateLayout(PieSliceLayout &layout); | |
|
35 | void setLayout(QVector<PieSliceLayout> &layout); | |||
|
36 | void setLayout(PieSliceLayout &layout); | |||
|
37 | void destroySlice(QPieSlice *slice); | |||
35 |
|
38 | |||
36 | private: |
|
39 | private: | |
37 | friend class PieSlice; |
|
40 | friend class PieSlice; |
@@ -22,8 +22,6 QPointF offset(qreal angle, qreal length) | |||||
22 |
|
22 | |||
23 | PieSlice::PieSlice(QGraphicsItem* parent) |
|
23 | PieSlice::PieSlice(QGraphicsItem* parent) | |
24 | :QGraphicsObject(parent), |
|
24 | :QGraphicsObject(parent), | |
25 | m_startAngle(0), |
|
|||
26 | m_angleSpan(0), |
|
|||
27 | m_isExploded(false), |
|
25 | m_isExploded(false), | |
28 | m_explodeDistanceFactor(0), |
|
26 | m_explodeDistanceFactor(0), | |
29 | m_labelVisible(false), |
|
27 | m_labelVisible(false), | |
@@ -41,7 +39,7 PieSlice::~PieSlice() | |||||
41 |
|
39 | |||
42 | QRectF PieSlice::boundingRect() const |
|
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 | QPainterPath PieSlice::shape() const |
|
45 | QPainterPath PieSlice::shape() const | |
@@ -90,7 +88,6 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/) | |||||
90 | void PieSlice::setLayout(PieSliceLayout layout) |
|
88 | void PieSlice::setLayout(PieSliceLayout layout) | |
91 | { |
|
89 | { | |
92 | m_layout = layout; |
|
90 | m_layout = layout; | |
93 | updateData(layout.m_data); |
|
|||
94 | } |
|
91 | } | |
95 |
|
92 | |||
96 | void PieSlice::updateGeometry() |
|
93 | void PieSlice::updateGeometry() | |
@@ -103,7 +100,7 void PieSlice::updateGeometry() | |||||
103 | // update slice path |
|
100 | // update slice path | |
104 | qreal centerAngle; |
|
101 | qreal centerAngle; | |
105 | QPointF armStart; |
|
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 | // update text rect |
|
105 | // update text rect | |
109 | m_labelTextRect = labelTextRect(m_labelFont, m_labelText); |
|
106 | m_labelTextRect = labelTextRect(m_labelFont, m_labelText); | |
@@ -122,8 +119,6 void PieSlice::updateData(const QPieSlice* sliceData) | |||||
122 | { |
|
119 | { | |
123 | // TODO: compare what has changes to avoid unneccesary geometry updates |
|
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 | m_isExploded = sliceData->isExploded(); |
|
122 | m_isExploded = sliceData->isExploded(); | |
128 | m_explodeDistanceFactor = sliceData->explodeDistanceFactor(); |
|
123 | m_explodeDistanceFactor = sliceData->explodeDistanceFactor(); | |
129 | m_slicePen = sliceData->slicePen(); |
|
124 | m_slicePen = sliceData->slicePen(); |
@@ -19,7 +19,7 class QPieSlice; | |||||
19 | class PieSliceLayout |
|
19 | class PieSliceLayout | |
20 | { |
|
20 | { | |
21 | public: |
|
21 | public: | |
22 | QPieSlice* m_data; |
|
22 | QPieSlice* m_data; // TODO: get rid of this | |
23 | QPointF m_center; |
|
23 | QPointF m_center; | |
24 | qreal m_radius; |
|
24 | qreal m_radius; | |
25 | qreal m_startAngle; |
|
25 | qreal m_startAngle; | |
@@ -60,8 +60,6 private: | |||||
60 | PieSliceLayout m_layout; |
|
60 | PieSliceLayout m_layout; | |
61 |
|
61 | |||
62 | QPainterPath m_slicePath; |
|
62 | QPainterPath m_slicePath; | |
63 | qreal m_startAngle; |
|
|||
64 | qreal m_angleSpan; |
|
|||
65 | bool m_isExploded; |
|
63 | bool m_isExploded; | |
66 | qreal m_explodeDistanceFactor; |
|
64 | qreal m_explodeDistanceFactor; | |
67 | bool m_labelVisible; |
|
65 | bool m_labelVisible; |
@@ -511,6 +511,8 void QPieSeries::updateDerivativeData() | |||||
511 | foreach (QPieSlice* s, m_slices) |
|
511 | foreach (QPieSlice* s, m_slices) | |
512 | m_total += s->value(); |
|
512 | m_total += s->value(); | |
513 |
|
513 | |||
|
514 | // TODO: emit totalChanged? | |||
|
515 | ||||
514 | // we must have some values |
|
516 | // we must have some values | |
515 | if (m_total == 0) { |
|
517 | if (m_total == 0) { | |
516 | qDebug() << "QPieSeries::updateDerivativeData() total == 0"; |
|
518 | qDebug() << "QPieSeries::updateDerivativeData() total == 0"; | |
@@ -520,31 +522,35 void QPieSeries::updateDerivativeData() | |||||
520 | // update slice attributes |
|
522 | // update slice attributes | |
521 | qreal sliceAngle = m_pieStartAngle; |
|
523 | qreal sliceAngle = m_pieStartAngle; | |
522 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; |
|
524 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; | |
|
525 | QVector<QPieSlice*> changed; | |||
523 | foreach (QPieSlice* s, m_slices) { |
|
526 | foreach (QPieSlice* s, m_slices) { | |
524 |
|
527 | |||
525 |
bool |
|
528 | bool isChanged = false; | |
526 |
|
529 | |||
527 | qreal percentage = s->value() / m_total; |
|
530 | qreal percentage = s->value() / m_total; | |
528 | if (s->m_percentage != percentage) { |
|
531 | if (s->m_percentage != percentage) { | |
529 | s->m_percentage = percentage; |
|
532 | s->m_percentage = percentage; | |
530 |
|
|
533 | isChanged = true; | |
531 | } |
|
534 | } | |
532 |
|
535 | |||
533 | qreal sliceSpan = pieSpan * percentage; |
|
536 | qreal sliceSpan = pieSpan * percentage; | |
534 | if (s->m_angleSpan != sliceSpan) { |
|
537 | if (s->m_angleSpan != sliceSpan) { | |
535 | s->m_angleSpan = sliceSpan; |
|
538 | s->m_angleSpan = sliceSpan; | |
536 |
|
|
539 | isChanged = true; | |
537 | } |
|
540 | } | |
538 |
|
541 | |||
539 | if (s->m_startAngle != sliceAngle) { |
|
542 | if (s->m_startAngle != sliceAngle) { | |
540 | s->m_startAngle = sliceAngle; |
|
543 | s->m_startAngle = sliceAngle; | |
541 |
|
|
544 | isChanged = true; | |
542 | } |
|
545 | } | |
543 | sliceAngle += sliceSpan; |
|
546 | sliceAngle += sliceSpan; | |
544 |
|
547 | |||
545 |
if ( |
|
548 | if (isChanged) | |
546 |
|
|
549 | changed << s; | |
547 | } |
|
550 | } | |
|
551 | ||||
|
552 | foreach (QPieSlice* s, changed) | |||
|
553 | emit s->changed(); | |||
548 | } |
|
554 | } | |
549 |
|
555 | |||
550 | bool QPieSeries::setModel(QAbstractItemModel* model) |
|
556 | bool QPieSeries::setModel(QAbstractItemModel* model) |
@@ -124,6 +124,7 private: | |||||
124 | // TODO: use PIML |
|
124 | // TODO: use PIML | |
125 | friend class PieChartItem; |
|
125 | friend class PieChartItem; | |
126 | friend class PieSlice; |
|
126 | friend class PieSlice; | |
|
127 | friend class QPieSlice; | |||
127 |
|
128 | |||
128 | QList<QPieSlice*> m_slices; |
|
129 | QList<QPieSlice*> m_slices; | |
129 | qreal m_pieRelativeHorPos; |
|
130 | qreal m_pieRelativeHorPos; |
@@ -1,4 +1,5 | |||||
1 | #include "qpieslice.h" |
|
1 | #include "qpieslice.h" | |
|
2 | #include "qpieseries.h" | |||
2 |
|
3 | |||
3 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
4 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
4 |
|
5 | |||
@@ -266,7 +267,12 void QPieSlice::setValue(qreal value) | |||||
266 | { |
|
267 | { | |
267 | if (m_value != value) { |
|
268 | if (m_value != value) { | |
268 | m_value = value; |
|
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 | #include <QFont> |
|
8 | #include <QFont> | |
9 |
|
9 | |||
10 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
10 | QTCOMMERCIALCHART_BEGIN_NAMESPACE | |
|
11 | class QPieSeries; | |||
11 |
|
12 | |||
12 | class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject |
|
13 | class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject | |
13 | { |
|
14 | { | |
@@ -29,8 +30,6 public: | |||||
29 | bool isLabelVisible() const; |
|
30 | bool isLabelVisible() const; | |
30 | void setExploded(bool exploded); |
|
31 | void setExploded(bool exploded); | |
31 | bool isExploded() const; |
|
32 | bool isExploded() const; | |
32 | void setExplodeDistanceFactor(qreal factor); |
|
|||
33 | qreal explodeDistanceFactor() const; |
|
|||
34 |
|
33 | |||
35 | // generated data |
|
34 | // generated data | |
36 | qreal percentage() const; |
|
35 | qreal percentage() const; | |
@@ -48,10 +47,8 public: | |||||
48 | QFont labelFont() const; |
|
47 | QFont labelFont() const; | |
49 | void setLabelArmLengthFactor(qreal factor); |
|
48 | void setLabelArmLengthFactor(qreal factor); | |
50 | qreal labelArmLengthFactor() const; |
|
49 | qreal labelArmLengthFactor() const; | |
51 |
|
50 | void setExplodeDistanceFactor(qreal factor); | ||
52 | // TODO: label position in general |
|
51 | qreal explodeDistanceFactor() const; | |
53 | // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???) |
|
|||
54 | // setLabelOrientation(horizontal|vertical|same as slice center angle|???) |
|
|||
55 |
|
52 | |||
56 | Q_SIGNALS: |
|
53 | Q_SIGNALS: | |
57 | void clicked(); |
|
54 | void clicked(); |
General Comments 0
You need to be logged in to leave comments.
Login now