##// END OF EJS Templates
Added basic donut chart example. Still better data needed
Marek Rosa -
r1841:e5aa797837ba
parent child
Show More
@@ -0,0 +1,5
1 !include( ../examples.pri ) {
2 error( "Couldn't find the examples.pri file!" )
3 }
4 TARGET = donutchart
5 SOURCES += main.cpp
@@ -0,0 +1,70
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
14 **
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
18 **
19 ****************************************************************************/
20
21 #include <QApplication>
22 #include <QMainWindow>
23 #include <QChartView>
24 #include <QPieSeries>
25 #include <QPieSlice>
26
27 QTCOMMERCIALCHART_USE_NAMESPACE
28
29 int main(int argc, char *argv[])
30 {
31 QApplication a(argc, argv);
32
33 //![1]
34 QPieSeries *series = new QPieSeries();
35 series->setHoleSize(0.35);
36 series->append("Jane", 1);
37 series->append("Joe", 2);
38 series->append("Andy", 3);
39 series->append("Barbara", 4);
40 series->append("Axel", 5);
41 //![1]
42
43 //![2]
44 QPieSlice *slice = series->slices().at(1);
45 slice->setExploded();
46 slice->setLabelVisible();
47 slice->setPen(QPen(Qt::darkGreen, 2));
48 slice->setBrush(Qt::green);
49 //![2]
50
51 //![3]
52 QChart* chart = new QChart();
53 chart->addSeries(series);
54 chart->setTitle("Simple donutchart example");
55 //![3]
56
57 //![4]
58 QChartView* chartView = new QChartView(chart);
59 chartView->setRenderHint(QPainter::Antialiasing);
60 //![4]
61
62 //![5]
63 QMainWindow window;
64 window.setCentralWidget(chartView);
65 window.resize(400, 300);
66 window.show();
67 //![5]
68
69 return a.exec();
70 }
@@ -1,34 +1,35
1 1 CURRENTLY_BUILDING_COMPONENTS = "examples"
2 2 !include( ../config.pri ) {
3 3 error( "Couldn't find the config.pri file!" )
4 4 }
5 5
6 6 TEMPLATE = subdirs
7 7 SUBDIRS += \
8 8 areachart \
9 9 customchart \
10 10 linechart \
11 11 percentbarchart \
12 12 piechart \
13 13 piechartdrilldown \
14 14 presenterchart \
15 15 scatterchart \
16 16 scatterinteractions \
17 17 splinechart \
18 18 stackedbarchart \
19 19 stackedbarchartdrilldown \
20 20 zoomlinechart \
21 21 modeldata \
22 22 barchart \
23 23 legend \
24 24 barmodelmapper \
25 25 qmlpiechart \
26 26 lineandbar \
27 27 horizontalbarchart \
28 28 horizontalstackedbarchart \
29 29 horizontalpercentbarchart \
30 30 donut \
31 31 donutbreakdown \
32 32 scrollchart \
33 33 datetimeaxis \
34 populationpyramid
34 populationpyramid \
35 donutchart
@@ -1,275 +1,284
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 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
88 88 switch (m_data.m_labelPosition)
89 89 {
90 90 case QPieSlice::LabelOutside:
91 91 painter->setClipRect(parentItem()->boundingRect());
92 92 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
93 93 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
94 94 break;
95 95 case QPieSlice::LabelInsideHorizontal:
96 96 painter->setClipPath(m_slicePath);
97 97 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
98 98 break;
99 99 case QPieSlice::LabelInsideTangential:
100 100 painter->setClipPath(m_slicePath);
101 101 painter->translate(m_labelTextRect.center());
102 102 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2);
103 103 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
104 104 break;
105 105 case QPieSlice::LabelInsideNormal:
106 106 painter->setClipPath(m_slicePath);
107 107 painter->translate(m_labelTextRect.center());
108 108 if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
109 109 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
110 110 else
111 111 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
112 112 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
113 113 break;
114 114 }
115 115
116 116 painter->restore();
117 117 }
118 118 }
119 119
120 120 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
121 121 {
122 122 m_hovered = true;
123 123 emit hovered(true);
124 124 }
125 125
126 126 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
127 127 {
128 128 m_hovered = false;
129 129 emit hovered(false);
130 130 }
131 131
132 132 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
133 133 {
134 134 emit clicked(event->buttons());
135 135 QGraphicsItem::mousePressEvent(event);
136 136 }
137 137
138 138 void PieSliceItem::setLayout(const PieSliceData &sliceData)
139 139 {
140 140 m_data = sliceData;
141 141 updateGeometry();
142 142 update();
143 143 }
144 144
145 145 void PieSliceItem::updateGeometry()
146 146 {
147 147 if (m_data.m_radius <= 0)
148 148 return;
149 149
150 150 prepareGeometryChange();
151 151
152 152 // slice path
153 153 qreal centerAngle;
154 154 QPointF armStart;
155 155 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
156 156
157 157 // text rect
158 158 QFontMetricsF fm(m_data.m_labelFont);
159 159 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
160 160
161 161 // label arm path
162 162 QPointF labelTextStart;
163 163 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
164 164
165 165 // text position
166 166 switch (m_data.m_labelPosition)
167 167 {
168 168 case QPieSlice::LabelOutside:
169 169 m_labelTextRect.moveBottomLeft(labelTextStart);
170 170 break;
171 171 case QPieSlice::LabelInsideHorizontal:
172 case QPieSlice::LabelInsideTangential:
172 case QPieSlice::LabelInsideTangential:{
173 QPointF textCenter;
174 if (m_data.m_holeRadius > 0)
175 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
176 else
177 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
178 m_labelTextRect.moveCenter(textCenter);
179 break;
180 }
173 181 case QPieSlice::LabelInsideNormal:{
182 // TODO: align the label text to the slice arc insead of half the radius
174 183 QPointF textCenter;
175 184 if (m_data.m_holeRadius > 0)
176 185 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
177 186 else
178 187 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
179 188 m_labelTextRect.moveCenter(textCenter);
180 189 break;
181 190 }
182 191 }
183 192
184 193 // bounding rect
185 194 if (m_data.m_isLabelVisible)
186 195 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
187 196 else
188 197 m_boundingRect = m_slicePath.boundingRect();
189 198 }
190 199
191 200 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
192 201 {
193 202 if (slice->isExploded()) {
194 203 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
195 204 qreal len = radius * slice->explodeDistanceFactor();
196 205 point += offset(centerAngle, len);
197 206 }
198 207 return point;
199 208 }
200 209
201 210 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
202 211 {
203 212 // calculate center angle
204 213 *centerAngle = startAngle + (angleSpan/2);
205 214
206 215 // calculate slice rectangle
207 216 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
208 217
209 218 // slice path
210 219 QPainterPath path;
211 220 if (m_data.m_holeRadius > 0) {
212 221 QRectF insideRect(center.x() - m_data.m_holeRadius, center.y()-m_data.m_holeRadius, m_data.m_holeRadius*2, m_data.m_holeRadius*2);
213 222 path.arcMoveTo(rect, -startAngle + 90);
214 223 path.arcTo(rect, -startAngle + 90, -angleSpan);
215 224 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
216 225 path.closeSubpath();
217 226 } else {
218 227 path.moveTo(rect.center());
219 228 path.arcTo(rect, -startAngle + 90, -angleSpan);
220 229 path.closeSubpath();
221 230 }
222 231
223 232 // calculate label arm start point
224 233 *armStart = center;
225 234 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
226 235
227 236 return path;
228 237 }
229 238
230 239 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
231 240 {
232 241 // Normalize the angle to 0-360 range
233 242 // NOTE: We are using int here on purpose. Depenging on platform and hardware
234 243 // qreal can be a double, float or something the user gives to the Qt configure
235 244 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
236 245 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
237 246 // that might break we just use int. Precision for this is just fine for our needs.
238 247 int normalized = angle * 10.0;
239 248 normalized = normalized % 3600;
240 249 if (normalized < 0)
241 250 normalized += 3600;
242 251 angle = (qreal) normalized / 10.0;
243 252
244 253 // prevent label arm pointing straight down because it will look bad
245 254 if (angle < 180 && angle > 170)
246 255 angle = 170;
247 256 if (angle > 180 && angle < 190)
248 257 angle = 190;
249 258
250 259 // line from slice to label
251 260 QPointF parm1 = start + offset(angle, length);
252 261
253 262 // line to underline the label
254 263 QPointF parm2 = parm1;
255 264 if (angle < 180) { // arm swings the other way on the left side
256 265 parm2 += QPointF(textWidth, 0);
257 266 *textStart = parm1;
258 267 }
259 268 else {
260 269 parm2 += QPointF(-textWidth,0);
261 270 *textStart = parm2;
262 271 }
263 272
264 273 QPainterPath path;
265 274 path.moveTo(start);
266 275 path.lineTo(parm1);
267 276 path.lineTo(parm2);
268 277
269 278 return path;
270 279 }
271 280
272 281 #include "moc_piesliceitem_p.cpp"
273 282
274 283 QTCOMMERCIALCHART_END_NAMESPACE
275 284
@@ -1,872 +1,871
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 "legendmarker_p.h"
29 29 #include "qabstractaxis.h"
30 30 #include "pieanimation_p.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 When setting this property the holeSize property is adjusted if necessary, to ensure that the hole size is not greater than the outer size.
136 136
137 137 Default value is 0.7.
138 138 */
139 139
140 140 /*!
141 141 \qmlproperty real PieSeries::size
142 142
143 143 Defines the pie size.
144 144
145 145 The value is a relative value to the chart rectangle where:
146 146
147 147 \list
148 148 \o 0.0 is the minimum size (pie not drawn).
149 149 \o 1.0 is the maximum size that can fit the chart.
150 150 \endlist
151 151
152 152 Default value is 0.7.
153 153 */
154 154
155 155 /*!
156 156 \property QPieSeries::holeSize
157 157 \brief Defines the donut hole size.
158 158
159 159 The value is a relative value to the chart rectangle where:
160 160
161 161 \list
162 162 \o 0.0 is the minimum size (full pie drawn, without any hole inside).
163 163 \o 1.0 is the maximum size that can fit the chart. (donut has no width)
164 164 \endlist
165 165
166 166 The value is never greater then size property.
167 167 Default value is 0.0.
168 168 */
169 169
170 170 /*!
171 171 \qmlproperty real PieSeries::holeSize
172 172
173 173 Defines the donut hole size.
174 174
175 175 The value is a relative value to the chart rectangle where:
176 176
177 177 \list
178 178 \o 0.0 is the minimum size (full pie drawn, without any hole inside).
179 179 \o 1.0 is the maximum size that can fit the chart. (donut has no width)
180 180 \endlist
181 181
182 182 When setting this property the size property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
183 183
184 184 Default value is 0.0.
185 185 */
186 186
187 187 /*!
188 188 \property QPieSeries::startAngle
189 189 \brief Defines the starting angle of the pie.
190 190
191 191 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
192 192
193 193 Default is value is 0.
194 194 */
195 195
196 196 /*!
197 197 \qmlproperty real PieSeries::startAngle
198 198
199 199 Defines the starting angle of the pie.
200 200
201 201 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
202 202
203 203 Default is value is 0.
204 204 */
205 205
206 206 /*!
207 207 \property QPieSeries::endAngle
208 208 \brief Defines the ending angle of the pie.
209 209
210 210 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
211 211
212 212 Default is value is 360.
213 213 */
214 214
215 215 /*!
216 216 \qmlproperty real PieSeries::endAngle
217 217
218 218 Defines the ending angle of the pie.
219 219
220 220 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
221 221
222 222 Default is value is 360.
223 223 */
224 224
225 225 /*!
226 226 \property QPieSeries::count
227 227
228 228 Number of slices in the series.
229 229 */
230 230
231 231 /*!
232 232 \qmlproperty int PieSeries::count
233 233
234 234 Number of slices in the series.
235 235 */
236 236
237 237 /*!
238 238 \fn void QPieSeries::countChanged()
239 239 Emitted when the slice count has changed.
240 240 \sa count
241 241 */
242 242 /*!
243 243 \qmlsignal PieSeries::onCountChanged()
244 244 Emitted when the slice count has changed.
245 245 */
246 246
247 247 /*!
248 248 \property QPieSeries::sum
249 249
250 250 Sum of all slices.
251 251
252 252 The series keeps track of the sum of all slices it holds.
253 253 */
254 254
255 255 /*!
256 256 \qmlproperty real PieSeries::sum
257 257
258 258 Sum of all slices.
259 259
260 260 The series keeps track of the sum of all slices it holds.
261 261 */
262 262
263 263 /*!
264 264 \fn void QPieSeries::sumChanged()
265 265 Emitted when the sum of all slices has changed.
266 266 \sa sum
267 267 */
268 268 /*!
269 269 \qmlsignal PieSeries::onSumChanged()
270 270 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
271 271 change value of a slice.
272 272 */
273 273
274 274 /*!
275 275 \fn void QPieSeries::added(QList<QPieSlice*> slices)
276 276
277 277 This signal is emitted when \a slices have been added to the series.
278 278
279 279 \sa append(), insert()
280 280 */
281 281 /*!
282 282 \qmlsignal PieSeries::onAdded(PieSlice slice)
283 283 Emitted when \a slice has been added to the series.
284 284 */
285 285
286 286 /*!
287 287 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
288 288 This signal is emitted when \a slices have been removed from the series.
289 289 \sa remove()
290 290 */
291 291 /*!
292 292 \qmlsignal PieSeries::onRemoved(PieSlice slice)
293 293 Emitted when \a slice has been removed from the series.
294 294 */
295 295
296 296 /*!
297 297 \fn void QPieSeries::clicked(QPieSlice* slice)
298 298 This signal is emitted when a \a slice has been clicked.
299 299 \sa QPieSlice::clicked()
300 300 */
301 301 /*!
302 302 \qmlsignal PieSeries::onClicked(PieSlice slice)
303 303 This signal is emitted when a \a slice has been clicked.
304 304 */
305 305
306 306 /*!
307 307 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
308 308 This signal is emitted when user has hovered over or away from the \a slice.
309 309 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
310 310 \sa QPieSlice::hovered()
311 311 */
312 312 /*!
313 313 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
314 314 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
315 315 over the slice and false when hover has moved away from the slice.
316 316 */
317 317
318 318 /*!
319 319 \qmlmethod PieSlice PieSeries::at(int index)
320 320 Returns slice at \a index. Returns null if the index is not valid.
321 321 */
322 322
323 323 /*!
324 324 \qmlmethod PieSlice PieSeries::find(string label)
325 325 Returns the first slice with \a label. Returns null if the index is not valid.
326 326 */
327 327
328 328 /*!
329 329 \qmlmethod PieSlice PieSeries::append(string label, real value)
330 330 Adds a new slice with \a label and \a value to the pie.
331 331 */
332 332
333 333 /*!
334 334 \qmlmethod bool PieSeries::remove(PieSlice slice)
335 335 Removes the \a slice from the pie. Returns true if the removal was successfull, false otherwise.
336 336 */
337 337
338 338 /*!
339 339 \qmlmethod PieSeries::clear()
340 340 Removes all slices from the pie.
341 341 */
342 342
343 343 /*!
344 344 Constructs a series object which is a child of \a parent.
345 345 */
346 346 QPieSeries::QPieSeries(QObject *parent) :
347 347 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
348 348 {
349 349
350 350 }
351 351
352 352 /*!
353 353 Destroys the series and its slices.
354 354 */
355 355 QPieSeries::~QPieSeries()
356 356 {
357 357 // NOTE: d_prt destroyed by QObject
358 358 }
359 359
360 360 /*!
361 361 Returns QChartSeries::SeriesTypePie.
362 362 */
363 363 QAbstractSeries::SeriesType QPieSeries::type() const
364 364 {
365 365 return QAbstractSeries::SeriesTypePie;
366 366 }
367 367
368 368 /*!
369 369 Appends a single \a slice to the series.
370 370 Slice ownership is passed to the series.
371 371
372 372 Returns true if append was succesfull.
373 373 */
374 374 bool QPieSeries::append(QPieSlice* slice)
375 375 {
376 376 return append(QList<QPieSlice*>() << slice);
377 377 }
378 378
379 379 /*!
380 380 Appends an array of \a slices to the series.
381 381 Slice ownership is passed to the series.
382 382
383 383 Returns true if append was successfull.
384 384 */
385 385 bool QPieSeries::append(QList<QPieSlice*> slices)
386 386 {
387 387 Q_D(QPieSeries);
388 388
389 389 if (slices.count() == 0)
390 390 return false;
391 391
392 392 foreach (QPieSlice* s, slices) {
393 393 if (!s || d->m_slices.contains(s))
394 394 return false;
395 395 if (s->series()) // already added to some series
396 396 return false;
397 397 }
398 398
399 399 foreach (QPieSlice* s, slices) {
400 400 s->setParent(this);
401 401 QPieSlicePrivate::fromSlice(s)->m_series = this;
402 402 d->m_slices << s;
403 403 }
404 404
405 405 d->updateDerivativeData();
406 406
407 407 foreach (QPieSlice* s, slices) {
408 408 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
409 409 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
410 410 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
411 411 }
412 412
413 413 emit added(slices);
414 414 emit countChanged();
415 415
416 416 return true;
417 417 }
418 418
419 419 /*!
420 420 Appends a single \a slice to the series and returns a reference to the series.
421 421 Slice ownership is passed to the series.
422 422 */
423 423 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
424 424 {
425 425 append(slice);
426 426 return *this;
427 427 }
428 428
429 429
430 430 /*!
431 431 Appends a single slice to the series with give \a value and \a label.
432 432 Slice ownership is passed to the series.
433 433 */
434 434 QPieSlice* QPieSeries::append(QString label, qreal value)
435 435 {
436 436 QPieSlice* slice = new QPieSlice(label, value);
437 437 append(slice);
438 438 return slice;
439 439 }
440 440
441 441 /*!
442 442 Inserts a single \a slice to the series before the slice at \a index position.
443 443 Slice ownership is passed to the series.
444 444
445 445 Returns true if insert was successfull.
446 446 */
447 447 bool QPieSeries::insert(int index, QPieSlice* slice)
448 448 {
449 449 Q_D(QPieSeries);
450 450
451 451 if (index < 0 || index > d->m_slices.count())
452 452 return false;
453 453
454 454 if (!slice || d->m_slices.contains(slice))
455 455 return false;
456 456
457 457 if (slice->series()) // already added to some series
458 458 return false;
459 459
460 460 slice->setParent(this);
461 461 QPieSlicePrivate::fromSlice(slice)->m_series = this;
462 462 d->m_slices.insert(index, slice);
463 463
464 464 d->updateDerivativeData();
465 465
466 466 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
467 467 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
468 468 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
469 469
470 470 emit added(QList<QPieSlice*>() << slice);
471 471 emit countChanged();
472 472
473 473 return true;
474 474 }
475 475
476 476 /*!
477 477 Removes a single \a slice from the series and deletes the slice.
478 478
479 479 Do not reference the pointer after this call.
480 480
481 481 Returns true if remove was successfull.
482 482 */
483 483 bool QPieSeries::remove(QPieSlice* slice)
484 484 {
485 485 Q_D(QPieSeries);
486 486
487 487 if (!d->m_slices.removeOne(slice))
488 488 return false;
489 489
490 490 d->updateDerivativeData();
491 491
492 492 emit removed(QList<QPieSlice*>() << slice);
493 493 emit countChanged();
494 494
495 495 delete slice;
496 496 slice = 0;
497 497
498 498 return true;
499 499 }
500 500
501 501 /*!
502 502 Takes a single \a slice from the series. Does not destroy the slice object.
503 503
504 504 NOTE: The series remains as the slice's parent object. You must set the
505 505 parent object to take full ownership.
506 506
507 507 Returns true if take was successfull.
508 508 */
509 509 bool QPieSeries::take(QPieSlice* slice)
510 510 {
511 511 Q_D(QPieSeries);
512 512
513 513 if (!d->m_slices.removeOne(slice))
514 514 return false;
515 515
516 516 QPieSlicePrivate::fromSlice(slice)->m_series = 0;
517 517
518 518 d->updateDerivativeData();
519 519
520 520 emit removed(QList<QPieSlice*>() << slice);
521 521 emit countChanged();
522 522
523 523 return true;
524 524 }
525 525
526 526 /*!
527 527 Clears all slices from the series.
528 528 */
529 529 void QPieSeries::clear()
530 530 {
531 531 Q_D(QPieSeries);
532 532 if (d->m_slices.count() == 0)
533 533 return;
534 534
535 535 QList<QPieSlice*> slices = d->m_slices;
536 536 foreach (QPieSlice* s, d->m_slices) {
537 537 d->m_slices.removeOne(s);
538 538 delete s;
539 539 }
540 540
541 541 d->updateDerivativeData();
542 542
543 543 emit removed(slices);
544 544 emit countChanged();
545 545 }
546 546
547 547 /*!
548 548 Returns a list of slices that belong to this series.
549 549 */
550 550 QList<QPieSlice*> QPieSeries::slices() const
551 551 {
552 552 Q_D(const QPieSeries);
553 553 return d->m_slices;
554 554 }
555 555
556 556 /*!
557 557 returns the number of the slices in this series.
558 558 */
559 559 int QPieSeries::count() const
560 560 {
561 561 Q_D(const QPieSeries);
562 562 return d->m_slices.count();
563 563 }
564 564
565 565 /*!
566 566 Returns true is the series is empty.
567 567 */
568 568 bool QPieSeries::isEmpty() const
569 569 {
570 570 Q_D(const QPieSeries);
571 571 return d->m_slices.isEmpty();
572 572 }
573 573
574 574 /*!
575 575 Returns the sum of all slice values in this series.
576 576
577 577 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
578 578 */
579 579 qreal QPieSeries::sum() const
580 580 {
581 581 Q_D(const QPieSeries);
582 582 return d->m_sum;
583 583 }
584 584
585 585 void QPieSeries::setHoleSize(qreal holeSize)
586 586 {
587 587 Q_D(QPieSeries);
588 588 holeSize = qBound((qreal)0.0, holeSize, (qreal)1.0);
589 589 d->setSizes(holeSize, qMax(d->m_pieRelativeSize, holeSize));
590 590 }
591 591
592 592 qreal QPieSeries::holeSize() const
593 593 {
594 594 Q_D(const QPieSeries);
595 595 return d->m_holeRelativeSize;
596 596 }
597 597
598 598 void QPieSeries::setHorizontalPosition(qreal relativePosition)
599 599 {
600 600 Q_D(QPieSeries);
601 601
602 602 if (relativePosition < 0.0)
603 603 relativePosition = 0.0;
604 604 if (relativePosition > 1.0)
605 605 relativePosition = 1.0;
606 606
607 607 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativePosition)) {
608 608 d->m_pieRelativeHorPos = relativePosition;
609 609 emit d->horizontalPositionChanged();
610 610 }
611 611 }
612 612
613 613 qreal QPieSeries::horizontalPosition() const
614 614 {
615 615 Q_D(const QPieSeries);
616 616 return d->m_pieRelativeHorPos;
617 617 }
618 618
619 619 void QPieSeries::setVerticalPosition(qreal relativePosition)
620 620 {
621 621 Q_D(QPieSeries);
622 622
623 623 if (relativePosition < 0.0)
624 624 relativePosition = 0.0;
625 625 if (relativePosition > 1.0)
626 626 relativePosition = 1.0;
627 627
628 628 if (!qFuzzyIsNull(d->m_pieRelativeVerPos - relativePosition)) {
629 629 d->m_pieRelativeVerPos = relativePosition;
630 630 emit d->verticalPositionChanged();
631 631 }
632 632 }
633 633
634 634 qreal QPieSeries::verticalPosition() const
635 635 {
636 636 Q_D(const QPieSeries);
637 637 return d->m_pieRelativeVerPos;
638 638 }
639 639
640 640 void QPieSeries::setPieSize(qreal relativeSize)
641 641 {
642 642 Q_D(QPieSeries);
643 643 relativeSize = qBound((qreal)0.0, relativeSize, (qreal)1.0);
644 644 d->setSizes(qMin(d->m_holeRelativeSize, relativeSize), relativeSize);
645 645
646 646 }
647 647
648 648 qreal QPieSeries::pieSize() const
649 649 {
650 650 Q_D(const QPieSeries);
651 651 return d->m_pieRelativeSize;
652 652 }
653 653
654 654
655 655 void QPieSeries::setPieStartAngle(qreal angle)
656 656 {
657 657 Q_D(QPieSeries);
658 658 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
659 659 return;
660 660 d->m_pieStartAngle = angle;
661 661 d->updateDerivativeData();
662 662 emit d->pieStartAngleChanged();
663 663 }
664 664
665 665 qreal QPieSeries::pieStartAngle() const
666 666 {
667 667 Q_D(const QPieSeries);
668 668 return d->m_pieStartAngle;
669 669 }
670 670
671 671 /*!
672 672 Sets the end angle of the pie.
673 673
674 674 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
675 675
676 676 \a angle must be greater than start angle.
677 677
678 678 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
679 679 */
680 680 void QPieSeries::setPieEndAngle(qreal angle)
681 681 {
682 682 Q_D(QPieSeries);
683 683 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
684 684 return;
685 685 d->m_pieEndAngle = angle;
686 686 d->updateDerivativeData();
687 687 emit d->pieEndAngleChanged();
688 688 }
689 689
690 690 /*!
691 691 Returns the end angle of the pie.
692 692
693 693 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
694 694
695 695 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
696 696 */
697 697 qreal QPieSeries::pieEndAngle() const
698 698 {
699 699 Q_D(const QPieSeries);
700 700 return d->m_pieEndAngle;
701 701 }
702 702
703 703 /*!
704 704 Sets the all the slice labels \a visible or invisible.
705 705
706 706 Note that this affects only the current slices in the series.
707 707 If user adds a new slice the default label visibility is false.
708 708
709 709 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
710 710 */
711 711 void QPieSeries::setLabelsVisible(bool visible)
712 712 {
713 713 Q_D(QPieSeries);
714 714 foreach (QPieSlice* s, d->m_slices)
715 715 s->setLabelVisible(visible);
716 716 }
717 717
718 718 /*!
719 719 Sets the all the slice labels \a position
720 720
721 721 Note that this affects only the current slices in the series.
722 722 If user adds a new slice the default label position is LabelOutside
723 723
724 724 \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
725 725 */
726 726 void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
727 727 {
728 728 Q_D(QPieSeries);
729 729 foreach (QPieSlice* s, d->m_slices)
730 730 s->setLabelPosition(position);
731 731 }
732 732
733 733 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
734 734
735 735
736 736 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
737 737 QAbstractSeriesPrivate(parent),
738 738 m_pieRelativeHorPos(0.5),
739 739 m_pieRelativeVerPos(0.5),
740 740 m_pieRelativeSize(0.7),
741 741 m_pieStartAngle(0),
742 742 m_pieEndAngle(360),
743 743 m_sum(0),
744 // m_donutChart(false),
745 744 m_holeRelativeSize(0.0)
746 745 {
747 746 }
748 747
749 748 QPieSeriesPrivate::~QPieSeriesPrivate()
750 749 {
751 750 }
752 751
753 752 void QPieSeriesPrivate::updateDerivativeData()
754 753 {
755 754 // calculate sum of all slices
756 755 qreal sum = 0;
757 756 foreach (QPieSlice* s, m_slices)
758 757 sum += s->value();
759 758
760 759 if (!qFuzzyIsNull(m_sum - sum)) {
761 760 m_sum = sum;
762 761 emit q_func()->sumChanged();
763 762 }
764 763
765 764 // nothing to show..
766 765 if (qFuzzyIsNull(m_sum))
767 766 return;
768 767
769 768 // update slice attributes
770 769 qreal sliceAngle = m_pieStartAngle;
771 770 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
772 771 QVector<QPieSlice*> changed;
773 772 foreach (QPieSlice* s, m_slices) {
774 773 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
775 774 d->setPercentage(s->value() / m_sum);
776 775 d->setStartAngle(sliceAngle);
777 776 d->setAngleSpan(pieSpan * s->percentage());
778 777 sliceAngle += s->angleSpan();
779 778 }
780 779
781 780
782 781 emit calculatedDataChanged();
783 782 }
784 783
785 784 void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
786 785 {
787 786 bool changed = false;
788 787
789 788 if (!qFuzzyIsNull(m_holeRelativeSize - innerSize)) {
790 789 m_holeRelativeSize = innerSize;
791 790 changed = true;
792 791 }
793 792
794 793 if (!qFuzzyIsNull(m_pieRelativeSize - outerSize)) {
795 794 m_pieRelativeSize = outerSize;
796 795 changed = true;
797 796 }
798 797
799 798 if (changed)
800 799 emit pieSizeChanged();
801 800 }
802 801
803 802 QPieSeriesPrivate* QPieSeriesPrivate::fromSeries(QPieSeries *series)
804 803 {
805 804 return series->d_func();
806 805 }
807 806
808 807 void QPieSeriesPrivate::sliceValueChanged()
809 808 {
810 809 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
811 810 updateDerivativeData();
812 811 }
813 812
814 813 void QPieSeriesPrivate::sliceClicked()
815 814 {
816 815 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
817 816 Q_ASSERT(m_slices.contains(slice));
818 817 Q_Q(QPieSeries);
819 818 emit q->clicked(slice);
820 819 }
821 820
822 821 void QPieSeriesPrivate::sliceHovered(bool state)
823 822 {
824 823 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
825 824 Q_ASSERT(m_slices.contains(slice));
826 825 Q_Q(QPieSeries);
827 826 emit q->hovered(slice, state);
828 827 }
829 828
830 829 void QPieSeriesPrivate::scaleDomain(Domain& domain)
831 830 {
832 831 Q_UNUSED(domain);
833 832 // does not apply to pie
834 833 }
835 834
836 835 ChartElement* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
837 836 {
838 837 Q_Q(QPieSeries);
839 838 PieChartItem* pie = new PieChartItem(q,presenter);
840 839 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
841 840 pie->setAnimation(new PieAnimation(pie));
842 841 }
843 842 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
844 843 return pie;
845 844 }
846 845
847 846 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
848 847 {
849 848 Q_Q(QPieSeries);
850 849 QList<LegendMarker*> markers;
851 850 foreach(QPieSlice* slice, q->slices()) {
852 851 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
853 852 markers << marker;
854 853 }
855 854 return markers;
856 855 }
857 856
858 857 void QPieSeriesPrivate::initializeAxis(QAbstractAxis* axis)
859 858 {
860 859 Q_UNUSED(axis);
861 860 }
862 861
863 862 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
864 863 {
865 864 Q_UNUSED(orientation);
866 865 return QAbstractAxis::AxisTypeNoAxis;
867 866 }
868 867
869 868 #include "moc_qpieseries.cpp"
870 869 #include "moc_qpieseries_p.cpp"
871 870
872 871 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now