##// END OF EJS Templates
Added initial donut chart support to Pie series
Marek Rosa -
r1670:5a9ca9e911f7
parent child
Show More
@@ -1,222 +1,223
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piechartitem_p.h"
22 22 #include "piesliceitem_p.h"
23 23 #include "qpieslice.h"
24 24 #include "qpieslice_p.h"
25 25 #include "qpieseries.h"
26 26 #include "qpieseries_p.h"
27 27 #include "chartpresenter_p.h"
28 28 #include "chartdataset_p.h"
29 29 #include "chartanimator_p.h"
30 30 #include <QPainter>
31 31 #include <QTimer>
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34
35 35 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
36 36 :ChartItem(presenter),
37 37 m_series(series)
38 38 {
39 39 Q_ASSERT(series);
40 40
41 41 QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
42 42 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
43 43 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
44 44 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
45 45 connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
46 46 connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
47 47 connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
48 48 connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
49 49
50 50 // Note: the following does not affect as long as the item does not have anything to paint
51 51 setZValue(ChartPresenter::PieSeriesZValue);
52 52
53 53 // Note: will not create slice items until we have a proper rectangle to draw on.
54 54 }
55 55
56 56 PieChartItem::~PieChartItem()
57 57 {
58 58 // slices deleted automatically through QGraphicsItem
59 59 }
60 60
61 61 void PieChartItem::handleGeometryChanged(const QRectF& rect)
62 62 {
63 63 prepareGeometryChange();
64 64 m_rect = rect;
65 65 updateLayout();
66 66
67 67 // This is for delayed initialization of the slice items during startup.
68 68 // It ensures that startup animation originates from the correct position.
69 69 if (m_sliceItems.isEmpty())
70 70 handleSlicesAdded(m_series->slices());
71 71 }
72 72
73 73 void PieChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
74 74 {
75 75 Q_UNUSED(minX);
76 76 Q_UNUSED(maxX);
77 77 Q_UNUSED(minY);
78 78 Q_UNUSED(maxY);
79 79 // does not apply to pie
80 80 }
81 81
82 82 void PieChartItem::rangeXChanged(qreal min, qreal max, int tickXCount)
83 83 {
84 84 Q_UNUSED(min);
85 85 Q_UNUSED(max);
86 86 Q_UNUSED(tickXCount);
87 87 // does not apply to pie
88 88 }
89 89
90 90 void PieChartItem::rangeYChanged(qreal min, qreal max, int tickYCount)
91 91 {
92 92 Q_UNUSED(min);
93 93 Q_UNUSED(max);
94 94 Q_UNUSED(tickYCount);
95 95 // does not apply to pie
96 96 }
97 97
98 98 void PieChartItem::updateLayout()
99 99 {
100 100 // find pie center coordinates
101 101 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
102 102 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
103 103
104 104 // find maximum radius for pie
105 105 m_pieRadius = m_rect.height() / 2;
106 106 if (m_rect.width() < m_rect.height())
107 107 m_pieRadius = m_rect.width() / 2;
108 108
109 109 // apply size factor
110 110 m_pieRadius *= m_series->pieSize();
111 111
112 112 // set layouts for existing slice items
113 113 foreach (QPieSlice* slice, m_series->slices()) {
114 114 PieSliceItem *sliceItem = m_sliceItems.value(slice);
115 115 if (sliceItem) {
116 116 PieSliceData sliceData = updateSliceGeometry(slice);
117 117 if (animator())
118 118 animator()->updateAnimation(this, sliceItem, sliceData);
119 119 else
120 120 sliceItem->setLayout(sliceData);
121 121 }
122 122 }
123 123
124 124 update();
125 125 }
126 126
127 127 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
128 128 {
129 129 // delay creating slice items until there is a proper rectangle
130 130 if (!m_rect.isValid() && m_sliceItems.isEmpty())
131 131 return;
132 132
133 133 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
134 134
135 135 bool startupAnimation = m_sliceItems.isEmpty();
136 136
137 137 foreach (QPieSlice *slice, slices) {
138 138 PieSliceItem* sliceItem = new PieSliceItem(this);
139 139 m_sliceItems.insert(slice, sliceItem);
140 140
141 141 // Note: no need to connect to slice valueChanged() etc.
142 142 // This is handled through calculatedDataChanged signal.
143 143 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
144 144 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
145 145 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
146 146 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
147 147 connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
148 148 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
149 149
150 150 QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
151 151 connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
152 152 connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
153 153 connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
154 154 connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
155 155
156 156 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
157 157 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
158 158
159 159 PieSliceData sliceData = updateSliceGeometry(slice);
160 160 if (animator())
161 161 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
162 162 else
163 163 sliceItem->setLayout(sliceData);
164 164 }
165 165 }
166 166
167 167 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
168 168 {
169 169 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
170 170
171 171 foreach (QPieSlice *slice, slices) {
172 172
173 173 PieSliceItem *sliceItem = m_sliceItems.value(slice);
174 174
175 175 // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
176 176 if (!sliceItem)
177 177 continue;
178 178
179 179 m_sliceItems.remove(slice);
180 180
181 181 if (animator())
182 182 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
183 183 else
184 184 delete sliceItem;
185 185 }
186 186 }
187 187
188 188 void PieChartItem::handleSliceChanged()
189 189 {
190 190 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
191 191 if (!slice) {
192 192 QPieSlicePrivate* slicep = qobject_cast<QPieSlicePrivate *>(sender());
193 193 slice = slicep->q_ptr;
194 194 }
195 195 Q_ASSERT(m_sliceItems.contains(slice));
196 196
197 197 PieSliceItem *sliceItem = m_sliceItems.value(slice);
198 198 PieSliceData sliceData = updateSliceGeometry(slice);
199 199 if (animator())
200 200 animator()->updateAnimation(this, sliceItem, sliceData);
201 201 else
202 202 sliceItem->setLayout(sliceData);
203 203
204 204 update();
205 205 }
206 206
207 207 void PieChartItem::handleSeriesVisibleChanged()
208 208 {
209 209 setVisible(m_series->isVisible());
210 210 }
211 211
212 212 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
213 213 {
214 214 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
215 215 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
216 216 sliceData.m_radius = m_pieRadius;
217 sliceData.m_donut = m_series->donut();
217 218 return sliceData;
218 219 }
219 220
220 221 #include "moc_piechartitem_p.cpp"
221 222
222 223 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,142 +1,144
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef PIESLICEDATA_P_H
31 31 #define PIESLICEDATA_P_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "qpieslice.h"
35 35 #include <QPen>
36 36 #include <QBrush>
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 template <class T>
41 41 class Themed : public T
42 42 {
43 43 public:
44 44 Themed():m_isThemed(true) {}
45 45
46 46 inline T &operator=(const T &other) { return T::operator =(other); }
47 47
48 48 inline bool operator!=(const T &other) const { return T::operator !=(other); }
49 49 inline bool operator!=(const Themed &other) const
50 50 {
51 51 if (T::operator !=(other))
52 52 return true;
53 53
54 54 if (m_isThemed != other.m_isThemed)
55 55 return true;
56 56
57 57 return false;
58 58 }
59 59
60 60 inline void setThemed(bool state) { m_isThemed = state; }
61 61 inline bool isThemed() const { return m_isThemed; }
62 62
63 63 private:
64 64 bool m_isThemed;
65 65 };
66 66
67 67 class PieSliceData
68 68 {
69 69 public:
70 70 PieSliceData()
71 71 {
72 72 m_value = 0;
73 73
74 74 m_isExploded = false;
75 75 m_explodeDistanceFactor = 0.15;
76 76
77 77 m_isLabelVisible = false;
78 78 m_labelPosition = QPieSlice::LabelOutside;
79 79 m_labelArmLengthFactor = 0.15;
80 80
81 81 m_percentage = 0;
82 82 m_radius = 0;
83 83 m_startAngle = 0;
84 84 m_angleSpan = 0;
85 m_donut = false;
85 86 }
86 87
87 88 bool operator!=(const PieSliceData &other) const
88 89 {
89 90 if (!qFuzzyIsNull(m_value - other.m_value))
90 91 return true;
91 92
92 93 if (m_slicePen != other.m_slicePen ||
93 94 m_sliceBrush != other.m_sliceBrush)
94 95 return true;
95 96
96 97 if (m_isExploded != other.m_isExploded ||
97 98 !qFuzzyIsNull(m_explodeDistanceFactor - other.m_explodeDistanceFactor))
98 99 return true;
99 100
100 101 if (m_isLabelVisible != other.m_isLabelVisible ||
101 102 m_labelText != other.m_labelText ||
102 103 m_labelFont != other.m_labelFont ||
103 104 m_labelPosition != other.m_labelPosition ||
104 105 !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) ||
105 106 m_labelBrush != other.m_labelBrush)
106 107 return true;
107 108
108 109 if (!qFuzzyIsNull(m_percentage - other.m_percentage) ||
109 110 m_center != other.m_center ||
110 111 !qFuzzyIsNull(m_radius - other.m_radius) ||
111 112 !qFuzzyIsNull(m_startAngle - other.m_startAngle) ||
112 113 !qFuzzyIsNull(m_angleSpan - other.m_angleSpan))
113 114 return true;
114 115
115 116 return false;
116 117 }
117 118
118 119 qreal m_value;
119 120
120 121 Themed<QPen> m_slicePen;
121 122 Themed<QBrush> m_sliceBrush;
122 123
123 124 bool m_isExploded;
124 125 qreal m_explodeDistanceFactor;
125 126
126 127 bool m_isLabelVisible;
127 128 QString m_labelText;
128 129 Themed<QFont> m_labelFont;
129 130 QPieSlice::LabelPosition m_labelPosition;
130 131 qreal m_labelArmLengthFactor;
131 132 Themed<QBrush> m_labelBrush;
132 133
133 134 qreal m_percentage;
134 135 QPointF m_center;
135 136 qreal m_radius;
136 137 qreal m_startAngle;
137 138 qreal m_angleSpan;
139 bool m_donut;
138 140 };
139 141
140 142 QTCOMMERCIALCHART_END_NAMESPACE
141 143
142 144 #endif // PIESLICEDATA_P_H
@@ -1,234 +1,242
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piesliceitem_p.h"
22 22 #include "piechartitem_p.h"
23 23 #include "qpieseries.h"
24 24 #include "qpieslice.h"
25 25 #include "chartpresenter_p.h"
26 26 #include <QPainter>
27 27 #include <qmath.h>
28 28 #include <QGraphicsSceneEvent>
29 29 #include <QTime>
30 30 #include <QDebug>
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 QPointF offset(qreal angle, qreal length)
35 35 {
36 36 qreal dx = qSin(angle*(M_PI/180)) * length;
37 37 qreal dy = qCos(angle*(M_PI/180)) * length;
38 38 return QPointF(dx, -dy);
39 39 }
40 40
41 41 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
42 42 :QGraphicsObject(parent),
43 m_hovered(false)
43 m_hovered(false)
44 44 {
45 45 setAcceptHoverEvents(true);
46 46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 47 setZValue(ChartPresenter::PieSeriesZValue);
48 48 }
49 49
50 50 PieSliceItem::~PieSliceItem()
51 51 {
52 52 // If user is hovering over the slice and it gets destroyed we do
53 53 // not get a hover leave event. So we must emit the signal here.
54 54 if (m_hovered)
55 55 emit hovered(false);
56 56 }
57 57
58 58 QRectF PieSliceItem::boundingRect() const
59 59 {
60 60 return m_boundingRect;
61 61 }
62 62
63 63 QPainterPath PieSliceItem::shape() const
64 64 {
65 65 // Don't include the label and label arm.
66 66 // This is used to detect a mouse clicks. We do not want clicks from label.
67 67 return m_slicePath;
68 68 }
69 69
70 70 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
71 71 {
72 72 painter->save();
73 73 painter->setClipRect(parentItem()->boundingRect());
74 74 painter->setPen(m_data.m_slicePen);
75 75 painter->setBrush(m_data.m_sliceBrush);
76 76 painter->drawPath(m_slicePath);
77 77 painter->restore();
78 78
79 79 if (m_data.m_isLabelVisible) {
80 80 painter->save();
81 81
82 82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
83 83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
84 84 painter->setPen(m_data.m_labelBrush.color());
85 85 painter->setBrush(m_data.m_labelBrush);
86 86 painter->setFont(m_data.m_labelFont);
87 87 if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
88 88 painter->setClipRect(parentItem()->boundingRect());
89 89 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
90 90 } else { // QPieSlice::LabelInside
91 91 painter->setClipPath(m_slicePath);
92 92 }
93 93 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
94 94
95 95 painter->restore();
96 96 }
97 97 }
98 98
99 99 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
100 100 {
101 101 m_hovered = true;
102 102 emit hovered(true);
103 103 }
104 104
105 105 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
106 106 {
107 107 m_hovered = false;
108 108 emit hovered(false);
109 109 }
110 110
111 111 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
112 112 {
113 113 emit clicked(event->buttons());
114 114 }
115 115
116 116 void PieSliceItem::setLayout(const PieSliceData &sliceData)
117 117 {
118 118 m_data = sliceData;
119 119 updateGeometry();
120 120 update();
121 121 }
122 122
123 123 void PieSliceItem::updateGeometry()
124 124 {
125 125 if (m_data.m_radius <= 0)
126 126 return;
127 127
128 128 prepareGeometryChange();
129 129
130 130 // slice path
131 131 qreal centerAngle;
132 132 QPointF armStart;
133 133 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
134 134
135 135 // text rect
136 136 QFontMetricsF fm(m_data.m_labelFont);
137 137 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
138 138
139 139 // label arm path
140 140 QPointF labelTextStart;
141 141 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
142 142
143 143 // text position
144 144 if (m_data.m_labelPosition == QPieSlice::LabelOutside)
145 145 m_labelTextRect.moveBottomLeft(labelTextStart);
146 146 else {// QPieSlice::LabelInside
147 147 QPointF sliceCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
148 148 m_labelTextRect.moveCenter(sliceCenter);
149 149 }
150 150
151 151 // bounding rect
152 152 if (m_data.m_isLabelVisible)
153 153 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
154 154 else
155 155 m_boundingRect = m_slicePath.boundingRect();
156 156 }
157 157
158 158 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
159 159 {
160 160 if (slice->isExploded()) {
161 161 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
162 162 qreal len = radius * slice->explodeDistanceFactor();
163 163 point += offset(centerAngle, len);
164 164 }
165 165 return point;
166 166 }
167 167
168 168 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
169 169 {
170 170 // calculate center angle
171 171 *centerAngle = startAngle + (angleSpan/2);
172 172
173 173 // calculate slice rectangle
174 174 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
175 175
176 176 // slice path
177 // TODO: draw the shape so that it might have a hole in the center
178 177 QPainterPath path;
179 path.moveTo(rect.center());
180 path.arcTo(rect, -startAngle + 90, -angleSpan);
181 path.closeSubpath();
178 if (m_data.m_donut) {
179 qreal donutFraction = 5.0;
180 QRectF insideRect = rect.adjusted(rect.width() / donutFraction, rect.height() / donutFraction, -rect.width() / donutFraction, -rect.height() / donutFraction);
181 path.arcMoveTo(rect, -startAngle + 90);
182 path.arcTo(rect, -startAngle + 90, -angleSpan);
183 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
184 path.closeSubpath();
185 } else {
186 path.moveTo(rect.center());
187 path.arcTo(rect, -startAngle + 90, -angleSpan);
188 path.closeSubpath();
189 }
182 190
183 191 // calculate label arm start point
184 192 *armStart = center;
185 193 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
186 194
187 195 return path;
188 196 }
189 197
190 198 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
191 199 {
192 200 // Normalize the angle to 0-360 range
193 201 // NOTE: We are using int here on purpose. Depenging on platform and hardware
194 202 // qreal can be a double, float or something the user gives to the Qt configure
195 203 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
196 204 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
197 205 // that might break we just use int. Precision for this is just fine for our needs.
198 206 int normalized = angle * 10.0;
199 207 normalized = normalized % 3600;
200 208 if (normalized < 0)
201 209 normalized += 3600;
202 210 angle = (qreal) normalized / 10.0;
203 211
204 212 // prevent label arm pointing straight down because it will look bad
205 213 if (angle < 180 && angle > 170)
206 214 angle = 170;
207 215 if (angle > 180 && angle < 190)
208 216 angle = 190;
209 217
210 218 // line from slice to label
211 219 QPointF parm1 = start + offset(angle, length);
212 220
213 221 // line to underline the label
214 222 QPointF parm2 = parm1;
215 223 if (angle < 180) { // arm swings the other way on the left side
216 parm2 += QPointF(textWidth, 0);
217 *textStart = parm1;
224 parm2 += QPointF(textWidth, 0);
225 *textStart = parm1;
218 226 }
219 227 else {
220 parm2 += QPointF(-textWidth,0);
221 *textStart = parm2;
228 parm2 += QPointF(-textWidth,0);
229 *textStart = parm2;
222 230 }
223 231
224 232 QPainterPath path;
225 233 path.moveTo(start);
226 234 path.lineTo(parm1);
227 235 path.lineTo(parm2);
228 236
229 237 return path;
230 238 }
231 239
232 240 #include "moc_piesliceitem_p.cpp"
233 241
234 242 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,781 +1,796
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qpieseries.h"
22 22 #include "qpieseries_p.h"
23 23 #include "qpieslice.h"
24 24 #include "qpieslice_p.h"
25 25 #include "pieslicedata_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "charttheme_p.h"
28 28 #include "chartanimator_p.h"
29 29 #include "legendmarker_p.h"
30 30 #include "qabstractaxis.h"
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 /*!
35 35 \class QPieSeries
36 36 \brief Pie series API for QtCommercial Charts
37 37
38 38 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
39 39 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
40 40 The actual slice size is determined by that relative value.
41 41
42 42 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
43 43 These relate to the actual chart rectangle.
44 44
45 45 By default the pie is defined as a full pie but it can also be a partial pie.
46 46 This can be done by setting a starting angle and angle span to the series.
47 47 Full pie is 360 degrees where 0 is at 12 a'clock.
48 48
49 49 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
50 50 \image examples_piechart.png
51 51 */
52 52 /*!
53 53 \qmlclass PieSeries QPieSeries
54 54 \inherits AbstractSeries
55 55
56 56 The following QML shows how to create a simple pie chart.
57 57
58 58 \snippet ../demos/qmlchart/qml/qmlchart/View1.qml 1
59 59
60 60 \beginfloatleft
61 61 \image demos_qmlchart1.png
62 62 \endfloat
63 63 \clearfloat
64 64 */
65 65
66 66 /*!
67 67 \property QPieSeries::horizontalPosition
68 68 \brief Defines the horizontal position of the pie.
69 69
70 70 The value is a relative value to the chart rectangle where:
71 71
72 72 \list
73 73 \o 0.0 is the absolute left.
74 74 \o 1.0 is the absolute right.
75 75 \endlist
76 76 Default value is 0.5 (center).
77 77 \sa verticalPosition
78 78 */
79 79
80 80 /*!
81 81 \qmlproperty real PieSeries::horizontalPosition
82 82
83 83 Defines the horizontal position of the pie.
84 84
85 85 The value is a relative value to the chart rectangle where:
86 86
87 87 \list
88 88 \o 0.0 is the absolute left.
89 89 \o 1.0 is the absolute right.
90 90 \endlist
91 91 Default value is 0.5 (center).
92 92 \sa verticalPosition
93 93 */
94 94
95 95 /*!
96 96 \property QPieSeries::verticalPosition
97 97 \brief Defines the vertical position of the pie.
98 98
99 99 The value is a relative value to the chart rectangle where:
100 100
101 101 \list
102 102 \o 0.0 is the absolute top.
103 103 \o 1.0 is the absolute bottom.
104 104 \endlist
105 105 Default value is 0.5 (center).
106 106 \sa horizontalPosition
107 107 */
108 108
109 109 /*!
110 110 \qmlproperty real PieSeries::verticalPosition
111 111
112 112 Defines the vertical position of the pie.
113 113
114 114 The value is a relative value to the chart rectangle where:
115 115
116 116 \list
117 117 \o 0.0 is the absolute top.
118 118 \o 1.0 is the absolute bottom.
119 119 \endlist
120 120 Default value is 0.5 (center).
121 121 \sa horizontalPosition
122 122 */
123 123
124 124 /*!
125 125 \property QPieSeries::size
126 126 \brief Defines the pie size.
127 127
128 128 The value is a relative value to the chart rectangle where:
129 129
130 130 \list
131 131 \o 0.0 is the minimum size (pie not drawn).
132 132 \o 1.0 is the maximum size that can fit the chart.
133 133 \endlist
134 134
135 135 Default value is 0.7.
136 136 */
137 137
138 138 /*!
139 139 \qmlproperty real PieSeries::size
140 140
141 141 Defines the pie size.
142 142
143 143 The value is a relative value to the chart rectangle where:
144 144
145 145 \list
146 146 \o 0.0 is the minimum size (pie not drawn).
147 147 \o 1.0 is the maximum size that can fit the chart.
148 148 \endlist
149 149
150 150 Default value is 0.7.
151 151 */
152 152
153 153 /*!
154 154 \property QPieSeries::startAngle
155 155 \brief Defines the starting angle of the pie.
156 156
157 157 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
158 158
159 159 Default is value is 0.
160 160 */
161 161
162 162 /*!
163 163 \qmlproperty real PieSeries::startAngle
164 164
165 165 Defines the starting angle of the pie.
166 166
167 167 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
168 168
169 169 Default is value is 0.
170 170 */
171 171
172 172 /*!
173 173 \property QPieSeries::endAngle
174 174 \brief Defines the ending angle of the pie.
175 175
176 176 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
177 177
178 178 Default is value is 360.
179 179 */
180 180
181 181 /*!
182 182 \qmlproperty real PieSeries::endAngle
183 183
184 184 Defines the ending angle of the pie.
185 185
186 186 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
187 187
188 188 Default is value is 360.
189 189 */
190 190
191 191 /*!
192 192 \property QPieSeries::count
193 193
194 194 Number of slices in the series.
195 195 */
196 196
197 197 /*!
198 198 \qmlproperty int PieSeries::count
199 199
200 200 Number of slices in the series.
201 201 */
202 202
203 203 /*!
204 204 \fn void QPieSeries::countChanged()
205 205 Emitted when the slice count has changed.
206 206 \sa count
207 207 */
208 208 /*!
209 209 \qmlsignal PieSeries::onCountChanged()
210 210 Emitted when the slice count has changed.
211 211 */
212 212
213 213 /*!
214 214 \property QPieSeries::sum
215 215
216 216 Sum of all slices.
217 217
218 218 The series keeps track of the sum of all slices it holds.
219 219 */
220 220
221 221 /*!
222 222 \qmlproperty real PieSeries::sum
223 223
224 224 Sum of all slices.
225 225
226 226 The series keeps track of the sum of all slices it holds.
227 227 */
228 228
229 229 /*!
230 230 \fn void QPieSeries::sumChanged()
231 231 Emitted when the sum of all slices has changed.
232 232 \sa sum
233 233 */
234 234 /*!
235 235 \qmlsignal PieSeries::onSumChanged()
236 236 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
237 237 change value of a slice.
238 238 */
239 239
240 240 /*!
241 241 \fn void QPieSeries::added(QList<QPieSlice*> slices)
242 242
243 243 This signal is emitted when \a slices have been added to the series.
244 244
245 245 \sa append(), insert()
246 246 */
247 247 /*!
248 248 \qmlsignal PieSeries::onAdded(PieSlice slice)
249 249 Emitted when \a slice has been added to the series.
250 250 */
251 251
252 252 /*!
253 253 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
254 254 This signal is emitted when \a slices have been removed from the series.
255 255 \sa remove()
256 256 */
257 257 /*!
258 258 \qmlsignal PieSeries::onRemoved(PieSlice slice)
259 259 Emitted when \a slice has been removed from the series.
260 260 */
261 261
262 262 /*!
263 263 \fn void QPieSeries::clicked(QPieSlice* slice)
264 264 This signal is emitted when a \a slice has been clicked.
265 265 \sa QPieSlice::clicked()
266 266 */
267 267 /*!
268 268 \qmlsignal PieSeries::onClicked(PieSlice slice)
269 269 This signal is emitted when a \a slice has been clicked.
270 270 */
271 271
272 272 /*!
273 273 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
274 274 This signal is emitted when user has hovered over or away from the \a slice.
275 275 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
276 276 \sa QPieSlice::hovered()
277 277 */
278 278 /*!
279 279 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
280 280 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
281 281 over the slice and false when hover has moved away from the slice.
282 282 */
283 283
284 284 /*!
285 285 \qmlmethod PieSlice PieSeries::at(int index)
286 286 Returns slice at \a index. Returns null if the index is not valid.
287 287 */
288 288
289 289 /*!
290 290 \qmlmethod PieSlice PieSeries::find(string label)
291 291 Returns the first slice with \a label. Returns null if the index is not valid.
292 292 */
293 293
294 294 /*!
295 295 \qmlmethod PieSlice PieSeries::append(string label, real value)
296 296 Adds a new slice with \a label and \a value to the pie.
297 297 */
298 298
299 299 /*!
300 300 \qmlmethod bool PieSeries::remove(PieSlice slice)
301 301 Removes the \a slice from the pie. Returns true if the removal was successfull, false otherwise.
302 302 */
303 303
304 304 /*!
305 305 \qmlmethod PieSeries::clear()
306 306 Removes all slices from the pie.
307 307 */
308 308
309 309 /*!
310 310 Constructs a series object which is a child of \a parent.
311 311 */
312 312 QPieSeries::QPieSeries(QObject *parent) :
313 313 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
314 314 {
315 315
316 316 }
317 317
318 318 /*!
319 319 Destroys the series and its slices.
320 320 */
321 321 QPieSeries::~QPieSeries()
322 322 {
323 323 // NOTE: d_prt destroyed by QObject
324 324 }
325 325
326 326 /*!
327 327 Returns QChartSeries::SeriesTypePie.
328 328 */
329 329 QAbstractSeries::SeriesType QPieSeries::type() const
330 330 {
331 331 return QAbstractSeries::SeriesTypePie;
332 332 }
333 333
334 334 /*!
335 335 Appends a single \a slice to the series.
336 336 Slice ownership is passed to the series.
337 337
338 338 Returns true if append was succesfull.
339 339 */
340 340 bool QPieSeries::append(QPieSlice* slice)
341 341 {
342 342 return append(QList<QPieSlice*>() << slice);
343 343 }
344 344
345 345 /*!
346 346 Appends an array of \a slices to the series.
347 347 Slice ownership is passed to the series.
348 348
349 349 Returns true if append was successfull.
350 350 */
351 351 bool QPieSeries::append(QList<QPieSlice*> slices)
352 352 {
353 353 Q_D(QPieSeries);
354 354
355 355 if (slices.count() == 0)
356 356 return false;
357 357
358 358 foreach (QPieSlice* s, slices) {
359 359 if (!s || d->m_slices.contains(s))
360 360 return false;
361 361 if (s->series()) // already added to some series
362 362 return false;
363 363 }
364 364
365 365 foreach (QPieSlice* s, slices) {
366 366 s->setParent(this);
367 367 QPieSlicePrivate::fromSlice(s)->m_series = this;
368 368 d->m_slices << s;
369 369 }
370 370
371 371 d->updateDerivativeData();
372 372
373 373 foreach (QPieSlice* s, slices) {
374 374 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
375 375 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
376 376 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
377 377 }
378 378
379 379 emit added(slices);
380 380 emit countChanged();
381 381
382 382 return true;
383 383 }
384 384
385 385 /*!
386 386 Appends a single \a slice to the series and returns a reference to the series.
387 387 Slice ownership is passed to the series.
388 388 */
389 389 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
390 390 {
391 391 append(slice);
392 392 return *this;
393 393 }
394 394
395 395
396 396 /*!
397 397 Appends a single slice to the series with give \a value and \a label.
398 398 Slice ownership is passed to the series.
399 399 */
400 400 QPieSlice* QPieSeries::append(QString label, qreal value)
401 401 {
402 402 QPieSlice* slice = new QPieSlice(label, value);
403 403 append(slice);
404 404 return slice;
405 405 }
406 406
407 407 /*!
408 408 Inserts a single \a slice to the series before the slice at \a index position.
409 409 Slice ownership is passed to the series.
410 410
411 411 Returns true if insert was successfull.
412 412 */
413 413 bool QPieSeries::insert(int index, QPieSlice* slice)
414 414 {
415 415 Q_D(QPieSeries);
416 416
417 417 if (index < 0 || index > d->m_slices.count())
418 418 return false;
419 419
420 420 if (!slice || d->m_slices.contains(slice))
421 421 return false;
422 422
423 423 if (slice->series()) // already added to some series
424 424 return false;
425 425
426 426 slice->setParent(this);
427 427 QPieSlicePrivate::fromSlice(slice)->m_series = this;
428 428 d->m_slices.insert(index, slice);
429 429
430 430 d->updateDerivativeData();
431 431
432 432 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
433 433 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
434 434 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
435 435
436 436 emit added(QList<QPieSlice*>() << slice);
437 437 emit countChanged();
438 438
439 439 return true;
440 440 }
441 441
442 442 /*!
443 443 Removes a single \a slice from the series and deletes the slice.
444 444
445 445 Do not reference the pointer after this call.
446 446
447 447 Returns true if remove was successfull.
448 448 */
449 449 bool QPieSeries::remove(QPieSlice* slice)
450 450 {
451 451 Q_D(QPieSeries);
452 452
453 453 if (!d->m_slices.removeOne(slice))
454 454 return false;
455 455
456 456 d->updateDerivativeData();
457 457
458 458 emit removed(QList<QPieSlice*>() << slice);
459 459 emit countChanged();
460 460
461 461 delete slice;
462 462 slice = 0;
463 463
464 464 return true;
465 465 }
466 466
467 467 /*!
468 468 Clears all slices from the series.
469 469 */
470 470 void QPieSeries::clear()
471 471 {
472 472 Q_D(QPieSeries);
473 473 if (d->m_slices.count() == 0)
474 474 return;
475 475
476 476 QList<QPieSlice*> slices = d->m_slices;
477 477 foreach (QPieSlice* s, d->m_slices) {
478 478 d->m_slices.removeOne(s);
479 479 delete s;
480 480 }
481 481
482 482 d->updateDerivativeData();
483 483
484 484 emit removed(slices);
485 485 emit countChanged();
486 486 }
487 487
488 488 /*!
489 489 Returns a list of slices that belong to this series.
490 490 */
491 491 QList<QPieSlice*> QPieSeries::slices() const
492 492 {
493 493 Q_D(const QPieSeries);
494 494 return d->m_slices;
495 495 }
496 496
497 497 /*!
498 498 returns the number of the slices in this series.
499 499 */
500 500 int QPieSeries::count() const
501 501 {
502 502 Q_D(const QPieSeries);
503 503 return d->m_slices.count();
504 504 }
505 505
506 506 /*!
507 507 Returns true is the series is empty.
508 508 */
509 509 bool QPieSeries::isEmpty() const
510 510 {
511 511 Q_D(const QPieSeries);
512 512 return d->m_slices.isEmpty();
513 513 }
514 514
515 515 /*!
516 516 Returns the sum of all slice values in this series.
517 517
518 518 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
519 519 */
520 520 qreal QPieSeries::sum() const
521 521 {
522 522 Q_D(const QPieSeries);
523 523 return d->m_sum;
524 524 }
525 525
526 void QPieSeries::setDonut(bool donut)
527 {
528 Q_D(QPieSeries);
529 d->m_donutChart = donut;
530 d->updateDerivativeData();
531 }
532
533 bool QPieSeries::donut() const
534 {
535 Q_D(const QPieSeries);
536 return d->m_donutChart;
537 }
538
526 539 void QPieSeries::setHorizontalPosition(qreal relativePosition)
527 540 {
528 541 Q_D(QPieSeries);
529 542
530 543 if (relativePosition < 0.0)
531 544 relativePosition = 0.0;
532 545 if (relativePosition > 1.0)
533 546 relativePosition = 1.0;
534 547
535 548 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativePosition)) {
536 549 d->m_pieRelativeHorPos = relativePosition;
537 550 emit d->horizontalPositionChanged();
538 551 }
539 552 }
540 553
541 554 qreal QPieSeries::horizontalPosition() const
542 555 {
543 556 Q_D(const QPieSeries);
544 557 return d->m_pieRelativeHorPos;
545 558 }
546 559
547 560 void QPieSeries::setVerticalPosition(qreal relativePosition)
548 561 {
549 562 Q_D(QPieSeries);
550 563
551 564 if (relativePosition < 0.0)
552 565 relativePosition = 0.0;
553 566 if (relativePosition > 1.0)
554 567 relativePosition = 1.0;
555 568
556 569 if (!qFuzzyIsNull(d->m_pieRelativeVerPos - relativePosition)) {
557 570 d->m_pieRelativeVerPos = relativePosition;
558 571 emit d->verticalPositionChanged();
559 572 }
560 573 }
561 574
562 575 qreal QPieSeries::verticalPosition() const
563 576 {
564 577 Q_D(const QPieSeries);
565 578 return d->m_pieRelativeVerPos;
566 579 }
567 580
568 581 void QPieSeries::setPieSize(qreal relativeSize)
569 582 {
570 583 Q_D(QPieSeries);
571 584
572 585 if (relativeSize < 0.0)
573 586 relativeSize = 0.0;
574 587 if (relativeSize > 1.0)
575 588 relativeSize = 1.0;
576 589
577 590 if (!qFuzzyIsNull(d->m_pieRelativeSize - relativeSize)) {
578 591 d->m_pieRelativeSize = relativeSize;
579 592 emit d->pieSizeChanged();
580 593 }
581 594 }
582 595
583 596 qreal QPieSeries::pieSize() const
584 597 {
585 598 Q_D(const QPieSeries);
586 599 return d->m_pieRelativeSize;
587 600 }
588 601
589 602
590 603 void QPieSeries::setPieStartAngle(qreal angle)
591 604 {
592 605 Q_D(QPieSeries);
593 606 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
594 607 return;
595 608 d->m_pieStartAngle = angle;
596 609 d->updateDerivativeData();
597 610 emit d->pieStartAngleChanged();
598 611 }
599 612
600 613 qreal QPieSeries::pieStartAngle() const
601 614 {
602 615 Q_D(const QPieSeries);
603 616 return d->m_pieStartAngle;
604 617 }
605 618
606 619 /*!
607 620 Sets the end angle of the pie.
608 621
609 622 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
610 623
611 624 \a angle must be greater than start angle.
612 625
613 626 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
614 627 */
615 628 void QPieSeries::setPieEndAngle(qreal angle)
616 629 {
617 630 Q_D(QPieSeries);
618 631 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
619 632 return;
620 633 d->m_pieEndAngle = angle;
621 634 d->updateDerivativeData();
622 635 emit d->pieEndAngleChanged();
623 636 }
624 637
625 638 /*!
626 639 Returns the end angle of the pie.
627 640
628 641 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
629 642
630 643 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
631 644 */
632 645 qreal QPieSeries::pieEndAngle() const
633 646 {
634 647 Q_D(const QPieSeries);
635 648 return d->m_pieEndAngle;
636 649 }
637 650
638 651 /*!
639 652 Sets the all the slice labels \a visible or invisible.
640 653
641 654 Note that this affects only the current slices in the series.
642 655 If user adds a new slice the default label visibility is false.
643 656
644 657 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
645 658 */
646 659 void QPieSeries::setLabelsVisible(bool visible)
647 660 {
648 661 Q_D(QPieSeries);
649 662 foreach (QPieSlice* s, d->m_slices)
650 663 s->setLabelVisible(visible);
651 664 }
652 665
653 666 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
654 667
655 668
656 669 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
657 670 QAbstractSeriesPrivate(parent),
658 671 m_pieRelativeHorPos(0.5),
659 672 m_pieRelativeVerPos(0.5),
660 673 m_pieRelativeSize(0.7),
661 674 m_pieStartAngle(0),
662 675 m_pieEndAngle(360),
663 m_sum(0)
676 m_sum(0),
677 m_donutChart(false)
664 678 {
665 679 }
666 680
667 681 QPieSeriesPrivate::~QPieSeriesPrivate()
668 682 {
669 683 }
670 684
671 685 void QPieSeriesPrivate::updateDerivativeData()
672 686 {
673 687 // calculate sum of all slices
674 688 qreal sum = 0;
675 689 foreach (QPieSlice* s, m_slices)
676 690 sum += s->value();
677 691
678 692 if (!qFuzzyIsNull(m_sum - sum)) {
679 693 m_sum = sum;
680 694 emit q_func()->sumChanged();
681 695 }
682 696
683 697 // nothing to show..
684 698 if (qFuzzyIsNull(m_sum))
685 699 return;
686 700
687 701 // update slice attributes
688 702 qreal sliceAngle = m_pieStartAngle;
689 703 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
690 704 QVector<QPieSlice*> changed;
691 705 foreach (QPieSlice* s, m_slices) {
692 706 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
693 707 d->setPercentage(s->value() / m_sum);
694 708 d->setStartAngle(sliceAngle);
695 709 d->setAngleSpan(pieSpan * s->percentage());
710 d->m_data.m_donut = m_donutChart;
696 711 sliceAngle += s->angleSpan();
697 712 }
698 713
699 714
700 715 emit calculatedDataChanged();
701 716 }
702 717
703 718 QPieSeriesPrivate* QPieSeriesPrivate::fromSeries(QPieSeries *series)
704 719 {
705 720 return series->d_func();
706 721 }
707 722
708 723 void QPieSeriesPrivate::sliceValueChanged()
709 724 {
710 725 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
711 726 updateDerivativeData();
712 727 }
713 728
714 729 void QPieSeriesPrivate::sliceClicked()
715 730 {
716 731 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
717 732 Q_ASSERT(m_slices.contains(slice));
718 733 Q_Q(QPieSeries);
719 734 emit q->clicked(slice);
720 735 }
721 736
722 737 void QPieSeriesPrivate::sliceHovered(bool state)
723 738 {
724 739 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
725 740 Q_ASSERT(m_slices.contains(slice));
726 741 Q_Q(QPieSeries);
727 742 emit q->hovered(slice, state);
728 743 }
729 744
730 745 void QPieSeriesPrivate::scaleDomain(Domain& domain)
731 746 {
732 747 Q_UNUSED(domain);
733 748 // does not apply to pie
734 749 }
735 750
736 751 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
737 752 {
738 753 Q_Q(QPieSeries);
739 754 PieChartItem* pie = new PieChartItem(q,presenter);
740 755 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
741 756 presenter->animator()->addAnimation(pie);
742 757 }
743 758 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
744 759 return pie;
745 760 }
746 761
747 762 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
748 763 {
749 764 Q_Q(QPieSeries);
750 765 QList<LegendMarker*> markers;
751 766 foreach(QPieSlice* slice, q->slices()) {
752 767 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
753 768 markers << marker;
754 769 }
755 770 return markers;
756 771 }
757 772
758 773 void QPieSeriesPrivate::initializeAxisX(QAbstractAxis* axis)
759 774 {
760 775 Q_UNUSED(axis);
761 776 }
762 777
763 778 void QPieSeriesPrivate::initializeAxisY(QAbstractAxis* axis)
764 779 {
765 780 Q_UNUSED(axis);
766 781 }
767 782
768 783 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisXType() const
769 784 {
770 785 return QAbstractAxis::AxisTypeNoAxis;
771 786 }
772 787
773 788 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisYType() const
774 789 {
775 790 return QAbstractAxis::AxisTypeNoAxis;
776 791 }
777 792
778 793 #include "moc_qpieseries.cpp"
779 794 #include "moc_qpieseries_p.cpp"
780 795
781 796 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,96 +1,99
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef PIESERIES_H
22 22 #define PIESERIES_H
23 23
24 24 #include <qabstractseries.h>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27 class QPieSeriesPrivate;
28 28 class QPieSlice;
29 29
30 30 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QAbstractSeries
31 31 {
32 32 Q_OBJECT
33 33 Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
34 34 Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
35 35 Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
36 36 Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
37 37 Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
38 38 Q_PROPERTY(int count READ count NOTIFY countChanged)
39 39 Q_PROPERTY(qreal sum READ sum NOTIFY sumChanged)
40 40
41 41 public:
42 42 explicit QPieSeries(QObject *parent = 0);
43 43 virtual ~QPieSeries();
44 44
45 45 QAbstractSeries::SeriesType type() const;
46 46
47 47 bool append(QPieSlice* slice);
48 48 bool append(QList<QPieSlice*> slices);
49 49 QPieSeries& operator << (QPieSlice* slice);
50 50 QPieSlice* append(QString label, qreal value);
51 51
52 52 bool insert(int index, QPieSlice* slice);
53 53
54 54 bool remove(QPieSlice* slice);
55 55 void clear();
56 56
57 57 QList<QPieSlice*> slices() const;
58 58 int count() const;
59 59
60 60 bool isEmpty() const;
61 61
62 62 qreal sum() const;
63 63
64 void setDonut(bool donut = true);
65 bool donut() const;
66
64 67 void setHorizontalPosition(qreal relativePosition);
65 68 qreal horizontalPosition() const;
66 69
67 70 void setVerticalPosition(qreal relativePosition);
68 71 qreal verticalPosition() const;
69 72
70 73 void setPieSize(qreal relativeSize);
71 74 qreal pieSize() const;
72 75
73 76 void setPieStartAngle(qreal startAngle);
74 77 qreal pieStartAngle() const;
75 78
76 79 void setPieEndAngle(qreal endAngle);
77 80 qreal pieEndAngle() const;
78 81
79 82 void setLabelsVisible(bool visible = true);
80 83
81 84 Q_SIGNALS:
82 85 void added(QList<QPieSlice*> slices);
83 86 void removed(QList<QPieSlice*> slices);
84 87 void clicked(QPieSlice* slice);
85 88 void hovered(QPieSlice* slice, bool state);
86 89 void countChanged();
87 90 void sumChanged();
88 91
89 92 private:
90 93 Q_DECLARE_PRIVATE(QPieSeries)
91 94 Q_DISABLE_COPY(QPieSeries)
92 95 };
93 96
94 97 QTCOMMERCIALCHART_END_NAMESPACE
95 98
96 99 #endif // PIESERIES_H
@@ -1,88 +1,89
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef QPIESERIES_P_H
31 31 #define QPIESERIES_P_H
32 32
33 33 #include "qpieseries.h"
34 34 #include "qabstractseries_p.h"
35 35
36 36 QTCOMMERCIALCHART_BEGIN_NAMESPACE
37 37 class QLegendPrivate;
38 38
39 39 class QPieSeriesPrivate : public QAbstractSeriesPrivate
40 40 {
41 41 Q_OBJECT
42 42
43 43 public:
44 44 QPieSeriesPrivate(QPieSeries *parent);
45 45 ~QPieSeriesPrivate();
46 46
47 47 void scaleDomain(Domain& domain);
48 48 Chart* createGraphics(ChartPresenter *presenter);
49 49 QList<LegendMarker*> createLegendMarker(QLegend *legend);
50 50 void initializeAxisX(QAbstractAxis* axis);
51 51 void initializeAxisY(QAbstractAxis* axis);
52 52 QAbstractAxis::AxisType defaultAxisXType() const;
53 53 QAbstractAxis::AxisType defaultAxisYType() const;
54 54
55 55 void updateDerivativeData();
56 56
57 57 static QPieSeriesPrivate* fromSeries(QPieSeries *series);
58 58
59 59 signals:
60 60 void calculatedDataChanged();
61 61 void pieSizeChanged();
62 62 void pieStartAngleChanged();
63 63 void pieEndAngleChanged();
64 64 void horizontalPositionChanged();
65 65 void verticalPositionChanged();
66 66
67 67 public Q_SLOTS:
68 68 void sliceValueChanged();
69 69 void sliceClicked();
70 70 void sliceHovered(bool state);
71 71
72 72 private:
73 73 QList<QPieSlice*> m_slices;
74 74 qreal m_pieRelativeHorPos;
75 75 qreal m_pieRelativeVerPos;
76 76 qreal m_pieRelativeSize;
77 77 qreal m_pieStartAngle;
78 78 qreal m_pieEndAngle;
79 79 qreal m_sum;
80 bool m_donutChart;
80 81
81 82 private:
82 83 friend class QLegendPrivate;
83 84 Q_DECLARE_PUBLIC(QPieSeries)
84 85 };
85 86
86 87 QTCOMMERCIALCHART_END_NAMESPACE
87 88
88 89 #endif // QPIESERIES_P_H
General Comments 0
You need to be logged in to leave comments. Login now