##// END OF EJS Templates
Fix piechart clipping bug
Jani Honkonen -
r905:d59d388cc788
parent child
Show More
@@ -1,215 +1,211
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "piechartitem_p.h"
21 #include "piechartitem_p.h"
22 #include "piesliceitem_p.h"
22 #include "piesliceitem_p.h"
23 #include "qpieslice.h"
23 #include "qpieslice.h"
24 #include "qpieseries.h"
24 #include "qpieseries.h"
25 #include "chartpresenter_p.h"
25 #include "chartpresenter_p.h"
26 #include "chartdataset_p.h"
26 #include "chartdataset_p.h"
27 #include "chartanimator_p.h"
27 #include "chartanimator_p.h"
28 #include <QDebug>
28 #include <QDebug>
29 #include <QPainter>
29 #include <QPainter>
30 #include <QTimer>
30 #include <QTimer>
31
31
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33
33
34 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
34 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
35 :ChartItem(presenter),
35 :ChartItem(presenter),
36 m_series(series)
36 m_series(series)
37 {
37 {
38 Q_ASSERT(series);
38 Q_ASSERT(series);
39 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
39 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
40 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
40 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
41 connect(series, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged()));
41 connect(series, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged()));
42 connect(series, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged()));
42 connect(series, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged()));
43
43
44 QTimer::singleShot(0, this, SLOT(initialize()));
44 QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this
45
45
46 // Note: the following does not affect as long as the item does not have anything to paint
46 // Note: the following does not affect as long as the item does not have anything to paint
47 setZValue(ChartPresenter::PieSeriesZValue);
47 setZValue(ChartPresenter::PieSeriesZValue);
48
49 // If enabled slice boundingrect() is called instead of shape().
50 // And this causes severe issues with mouse click & hover decection.
51 //setFlags(QGraphicsItem::ItemClipsChildrenToShape);
52 }
48 }
53
49
54 PieChartItem::~PieChartItem()
50 PieChartItem::~PieChartItem()
55 {
51 {
56 // slices deleted automatically through QGraphicsItem
52 // slices deleted automatically through QGraphicsItem
57 }
53 }
58
54
59 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
55 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
60 {
56 {
61 Q_UNUSED(painter)
57 Q_UNUSED(painter)
62 // TODO: paint shadows for all components
58 // TODO: paint shadows for all components
63 // - get paths from items & merge & offset and draw with shadow color?
59 // - get paths from items & merge & offset and draw with shadow color?
64 //painter->setBrush(QBrush(Qt::red));
60 //painter->setBrush(QBrush(Qt::red));
65 //painter->drawRect(m_debugRect);
61 //painter->drawRect(m_debugRect);
66 }
62 }
67
63
68 void PieChartItem::initialize()
64 void PieChartItem::initialize()
69 {
65 {
70 handleSlicesAdded(m_series->slices());
66 handleSlicesAdded(m_series->slices());
71 }
67 }
72
68
73 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
69 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
74 {
70 {
75 bool isEmpty = m_slices.isEmpty();
71 bool isEmpty = m_slices.isEmpty();
76
72
77 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series), false);
73 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series), false);
78
74
79 foreach (QPieSlice *s, slices) {
75 foreach (QPieSlice *s, slices) {
80 PieSliceItem* item = new PieSliceItem(this);
76 PieSliceItem* item = new PieSliceItem(this);
81 m_slices.insert(s, item);
77 m_slices.insert(s, item);
82 connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
78 connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
83 connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked(Qt::MouseButtons)));
79 connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked(Qt::MouseButtons)));
84 connect(item, SIGNAL(hoverEnter()), s, SIGNAL(hoverEnter()));
80 connect(item, SIGNAL(hoverEnter()), s, SIGNAL(hoverEnter()));
85 connect(item, SIGNAL(hoverLeave()), s, SIGNAL(hoverLeave()));
81 connect(item, SIGNAL(hoverLeave()), s, SIGNAL(hoverLeave()));
86
82
87 PieSliceData data = sliceData(s);
83 PieSliceData data = sliceData(s);
88
84
89 if (animator())
85 if (animator())
90 animator()->addAnimation(this, s, data, isEmpty);
86 animator()->addAnimation(this, s, data, isEmpty);
91 else
87 else
92 setLayout(s, data);
88 setLayout(s, data);
93 }
89 }
94 }
90 }
95
91
96 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
92 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
97 {
93 {
98 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series), false);
94 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series), false);
99
95
100 foreach (QPieSlice *s, slices) {
96 foreach (QPieSlice *s, slices) {
101 if (animator())
97 if (animator())
102 animator()->removeAnimation(this, s);
98 animator()->removeAnimation(this, s);
103 else
99 else
104 destroySlice(s);
100 destroySlice(s);
105 }
101 }
106 }
102 }
107
103
108 void PieChartItem::handlePieLayoutChanged()
104 void PieChartItem::handlePieLayoutChanged()
109 {
105 {
110 PieLayout layout = calculateLayout();
106 PieLayout layout = calculateLayout();
111 applyLayout(layout);
107 applyLayout(layout);
112 update();
108 update();
113 }
109 }
114
110
115 void PieChartItem::handleSliceChanged()
111 void PieChartItem::handleSliceChanged()
116 {
112 {
117 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
113 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
118 Q_ASSERT(m_slices.contains(slice));
114 Q_ASSERT(m_slices.contains(slice));
119 PieSliceData data = sliceData(slice);
115 PieSliceData data = sliceData(slice);
120 updateLayout(slice, data);
116 updateLayout(slice, data);
121 update();
117 update();
122 }
118 }
123
119
124 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
120 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
125 {
121 {
126 // TODO
122 // TODO
127 }
123 }
128
124
129 void PieChartItem::handleGeometryChanged(const QRectF& rect)
125 void PieChartItem::handleGeometryChanged(const QRectF& rect)
130 {
126 {
131 prepareGeometryChange();
127 prepareGeometryChange();
132 m_rect = rect;
128 m_rect = rect;
133 handlePieLayoutChanged();
129 handlePieLayoutChanged();
134 }
130 }
135
131
136 void PieChartItem::calculatePieLayout()
132 void PieChartItem::calculatePieLayout()
137 {
133 {
138 // find pie center coordinates
134 // find pie center coordinates
139 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
135 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
140 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
136 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
141
137
142 // find maximum radius for pie
138 // find maximum radius for pie
143 m_pieRadius = m_rect.height() / 2;
139 m_pieRadius = m_rect.height() / 2;
144 if (m_rect.width() < m_rect.height())
140 if (m_rect.width() < m_rect.height())
145 m_pieRadius = m_rect.width() / 2;
141 m_pieRadius = m_rect.width() / 2;
146
142
147 // apply size factor
143 // apply size factor
148 m_pieRadius *= m_series->pieSize();
144 m_pieRadius *= m_series->pieSize();
149 }
145 }
150
146
151 PieSliceData PieChartItem::sliceData(QPieSlice *slice)
147 PieSliceData PieChartItem::sliceData(QPieSlice *slice)
152 {
148 {
153 // TODO: This function is kid of useless now. Refactor.
149 // TODO: This function is kid of useless now. Refactor.
154 PieSliceData sliceData = PieSliceData::data(slice);
150 PieSliceData sliceData = PieSliceData::data(slice);
155 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
151 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
156 sliceData.m_radius = m_pieRadius;
152 sliceData.m_radius = m_pieRadius;
157 return sliceData;
153 return sliceData;
158 }
154 }
159
155
160 PieLayout PieChartItem::calculateLayout()
156 PieLayout PieChartItem::calculateLayout()
161 {
157 {
162 calculatePieLayout();
158 calculatePieLayout();
163 PieLayout layout;
159 PieLayout layout;
164 foreach (QPieSlice* s, m_series->slices()) {
160 foreach (QPieSlice* s, m_series->slices()) {
165 if (m_slices.contains(s)) // calculate layout only for those slices that are already visible
161 if (m_slices.contains(s)) // calculate layout only for those slices that are already visible
166 layout.insert(s, sliceData(s));
162 layout.insert(s, sliceData(s));
167 }
163 }
168 return layout;
164 return layout;
169 }
165 }
170
166
171 void PieChartItem::applyLayout(const PieLayout &layout)
167 void PieChartItem::applyLayout(const PieLayout &layout)
172 {
168 {
173 if (animator())
169 if (animator())
174 animator()->updateLayout(this, layout);
170 animator()->updateLayout(this, layout);
175 else
171 else
176 setLayout(layout);
172 setLayout(layout);
177 }
173 }
178
174
179 void PieChartItem::updateLayout(QPieSlice *slice, const PieSliceData &sliceData)
175 void PieChartItem::updateLayout(QPieSlice *slice, const PieSliceData &sliceData)
180 {
176 {
181 if (animator())
177 if (animator())
182 animator()->updateLayout(this, slice, sliceData);
178 animator()->updateLayout(this, slice, sliceData);
183 else
179 else
184 setLayout(slice, sliceData);
180 setLayout(slice, sliceData);
185 }
181 }
186
182
187 void PieChartItem::setLayout(const PieLayout &layout)
183 void PieChartItem::setLayout(const PieLayout &layout)
188 {
184 {
189 foreach (QPieSlice *slice, layout.keys()) {
185 foreach (QPieSlice *slice, layout.keys()) {
190 PieSliceItem *item = m_slices.value(slice);
186 PieSliceItem *item = m_slices.value(slice);
191 Q_ASSERT(item);
187 Q_ASSERT(item);
192 item->setSliceData(layout.value(slice));
188 item->setSliceData(layout.value(slice));
193 item->updateGeometry();
189 item->updateGeometry();
194 item->update();
190 item->update();
195 }
191 }
196 }
192 }
197
193
198 void PieChartItem::setLayout(QPieSlice *slice, const PieSliceData &sliceData)
194 void PieChartItem::setLayout(QPieSlice *slice, const PieSliceData &sliceData)
199 {
195 {
200 // find slice
196 // find slice
201 PieSliceItem *item = m_slices.value(slice);
197 PieSliceItem *item = m_slices.value(slice);
202 Q_ASSERT(item);
198 Q_ASSERT(item);
203 item->setSliceData(sliceData);
199 item->setSliceData(sliceData);
204 item->updateGeometry();
200 item->updateGeometry();
205 item->update();
201 item->update();
206 }
202 }
207
203
208 void PieChartItem::destroySlice(QPieSlice *slice)
204 void PieChartItem::destroySlice(QPieSlice *slice)
209 {
205 {
210 delete m_slices.take(slice);
206 delete m_slices.take(slice);
211 }
207 }
212
208
213 #include "moc_piechartitem_p.cpp"
209 #include "moc_piechartitem_p.cpp"
214
210
215 QTCOMMERCIALCHART_END_NAMESPACE
211 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,204 +1,205
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "piesliceitem_p.h"
21 #include "piesliceitem_p.h"
22 #include "piechartitem_p.h"
22 #include "piechartitem_p.h"
23 #include "qpieseries.h"
23 #include "qpieseries.h"
24 #include "qpieslice.h"
24 #include "qpieslice.h"
25 #include "chartpresenter_p.h"
25 #include "chartpresenter_p.h"
26 #include <QPainter>
26 #include <QPainter>
27 #include <QDebug>
27 #include <QDebug>
28 #include <qmath.h>
28 #include <qmath.h>
29 #include <QGraphicsSceneEvent>
29 #include <QGraphicsSceneEvent>
30 #include <QTime>
30 #include <QTime>
31
31
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33
33
34 #define PI 3.14159265 // TODO: is this defined in some header?
34 #define PI 3.14159265 // TODO: is this defined in some header?
35
35
36 QPointF offset(qreal angle, qreal length)
36 QPointF offset(qreal angle, qreal length)
37 {
37 {
38 qreal dx = qSin(angle*(PI/180)) * length;
38 qreal dx = qSin(angle*(PI/180)) * length;
39 qreal dy = qCos(angle*(PI/180)) * length;
39 qreal dy = qCos(angle*(PI/180)) * length;
40 return QPointF(dx, -dy);
40 return QPointF(dx, -dy);
41 }
41 }
42
42
43 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
43 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
44 :QGraphicsObject(parent)
44 :QGraphicsObject(parent)
45 {
45 {
46 setAcceptHoverEvents(true);
46 setAcceptHoverEvents(true);
47 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 setAcceptedMouseButtons(Qt::MouseButtonMask);
48 setZValue(ChartPresenter::PieSeriesZValue);
48 setZValue(ChartPresenter::PieSeriesZValue);
49 }
49 }
50
50
51 PieSliceItem::~PieSliceItem()
51 PieSliceItem::~PieSliceItem()
52 {
52 {
53
53
54 }
54 }
55
55
56 QRectF PieSliceItem::boundingRect() const
56 QRectF PieSliceItem::boundingRect() const
57 {
57 {
58 return m_boundingRect;
58 return m_boundingRect;
59 }
59 }
60
60
61 QPainterPath PieSliceItem::shape() const
61 QPainterPath PieSliceItem::shape() const
62 {
62 {
63 // Don't include the label and label arm.
63 // Don't include the label and label arm.
64 // This is used to detect a mouse clicks. We do not want clicks from label.
64 // This is used to detect a mouse clicks. We do not want clicks from label.
65 return m_slicePath;
65 return m_slicePath;
66 }
66 }
67
67
68 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
68 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
69 {
69 {
70 painter->save();
70 painter->save();
71 painter->setClipRect(parentItem()->boundingRect());
71 painter->setClipRect(parentItem()->boundingRect());
72 painter->setPen(m_data.m_slicePen);
72 painter->setPen(m_data.m_slicePen);
73 painter->setBrush(m_data.m_sliceBrush);
73 painter->setBrush(m_data.m_sliceBrush);
74 painter->drawPath(m_slicePath);
74 painter->drawPath(m_slicePath);
75 painter->restore();
75 painter->restore();
76
76
77 if (m_data.m_isLabelVisible) {
77 if (m_data.m_isLabelVisible) {
78 painter->setClipRect(parentItem()->boundingRect());
78 painter->setPen(m_data.m_labelPen);
79 painter->setPen(m_data.m_labelPen);
79 painter->drawPath(m_labelArmPath);
80 painter->drawPath(m_labelArmPath);
80 // the pen color will affect the font color as well
81 // the pen color will affect the font color as well
81 painter->setFont(m_data.m_labelFont);
82 painter->setFont(m_data.m_labelFont);
82 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
83 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
83 }
84 }
84 }
85 }
85
86
86 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
87 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
87 {
88 {
88 emit hoverEnter();
89 emit hoverEnter();
89 }
90 }
90
91
91 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
92 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
92 {
93 {
93 emit hoverLeave();
94 emit hoverLeave();
94 }
95 }
95
96
96 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
97 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
97 {
98 {
98 emit clicked(event->buttons());
99 emit clicked(event->buttons());
99 }
100 }
100
101
101 void PieSliceItem::setSliceData(PieSliceData sliceData)
102 void PieSliceItem::setSliceData(PieSliceData sliceData)
102 {
103 {
103 m_data = sliceData;
104 m_data = sliceData;
104 }
105 }
105
106
106 void PieSliceItem::updateGeometry()
107 void PieSliceItem::updateGeometry()
107 {
108 {
108 if (m_data.m_radius <= 0)
109 if (m_data.m_radius <= 0)
109 return;
110 return;
110
111
111 prepareGeometryChange();
112 prepareGeometryChange();
112
113
113 // update slice path
114 // update slice path
114 qreal centerAngle;
115 qreal centerAngle;
115 QPointF armStart;
116 QPointF armStart;
116 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
117 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
117
118
118 // update text rect
119 // update text rect
119 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
120 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
120
121
121 // update label arm path
122 // update label arm path
122 QPointF labelTextStart;
123 QPointF labelTextStart;
123 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
124 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
124
125
125 // update text position
126 // update text position
126 m_labelTextRect.moveBottomLeft(labelTextStart);
127 m_labelTextRect.moveBottomLeft(labelTextStart);
127
128
128 // update bounding rect
129 // update bounding rect
129 if (m_data.m_isLabelVisible)
130 if (m_data.m_isLabelVisible)
130 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
131 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
131 else
132 else
132 m_boundingRect = m_slicePath.boundingRect();
133 m_boundingRect = m_slicePath.boundingRect();
133 }
134 }
134
135
135 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
136 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
136 {
137 {
137 if (slice->isExploded()) {
138 if (slice->isExploded()) {
138 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
139 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
139 qreal len = radius * slice->explodeDistanceFactor();
140 qreal len = radius * slice->explodeDistanceFactor();
140 qreal dx = qSin(centerAngle*(PI/180)) * len;
141 qreal dx = qSin(centerAngle*(PI/180)) * len;
141 qreal dy = -qCos(centerAngle*(PI/180)) * len;
142 qreal dy = -qCos(centerAngle*(PI/180)) * len;
142 point += QPointF(dx, dy);
143 point += QPointF(dx, dy);
143 }
144 }
144 return point;
145 return point;
145 }
146 }
146
147
147 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
148 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
148 {
149 {
149 // calculate center angle
150 // calculate center angle
150 *centerAngle = startAngle + (angleSpan/2);
151 *centerAngle = startAngle + (angleSpan/2);
151
152
152 // calculate slice rectangle
153 // calculate slice rectangle
153 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
154 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
154
155
155 // slice path
156 // slice path
156 // TODO: draw the shape so that it might have a hole in the center
157 // TODO: draw the shape so that it might have a hole in the center
157 QPainterPath path;
158 QPainterPath path;
158 path.moveTo(rect.center());
159 path.moveTo(rect.center());
159 path.arcTo(rect, -startAngle + 90, -angleSpan);
160 path.arcTo(rect, -startAngle + 90, -angleSpan);
160 path.closeSubpath();
161 path.closeSubpath();
161
162
162 // calculate label arm start point
163 // calculate label arm start point
163 *armStart = center;
164 *armStart = center;
164 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
165 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
165
166
166 return path;
167 return path;
167 }
168 }
168
169
169 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
170 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
170 {
171 {
171 qreal dx = qSin(angle*(PI/180)) * length;
172 qreal dx = qSin(angle*(PI/180)) * length;
172 qreal dy = -qCos(angle*(PI/180)) * length;
173 qreal dy = -qCos(angle*(PI/180)) * length;
173 QPointF parm1 = start + QPointF(dx, dy);
174 QPointF parm1 = start + QPointF(dx, dy);
174
175
175 QPointF parm2 = parm1;
176 QPointF parm2 = parm1;
176 if (angle < 180) { // arm swings the other way on the left side
177 if (angle < 180) { // arm swings the other way on the left side
177 parm2 += QPointF(textWidth, 0);
178 parm2 += QPointF(textWidth, 0);
178 *textStart = parm1;
179 *textStart = parm1;
179 }
180 }
180 else {
181 else {
181 parm2 += QPointF(-textWidth,0);
182 parm2 += QPointF(-textWidth,0);
182 *textStart = parm2;
183 *textStart = parm2;
183 }
184 }
184
185
185 // elevate the text position a bit so that it does not hit the line
186 // elevate the text position a bit so that it does not hit the line
186 *textStart += QPointF(0, -5);
187 *textStart += QPointF(0, -5);
187
188
188 QPainterPath path;
189 QPainterPath path;
189 path.moveTo(start);
190 path.moveTo(start);
190 path.lineTo(parm1);
191 path.lineTo(parm1);
191 path.lineTo(parm2);
192 path.lineTo(parm2);
192
193
193 return path;
194 return path;
194 }
195 }
195
196
196 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
197 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
197 {
198 {
198 QFontMetricsF fm(font);
199 QFontMetricsF fm(font);
199 return fm.boundingRect(text);
200 return fm.boundingRect(text);
200 }
201 }
201
202
202 #include "moc_piesliceitem_p.cpp"
203 #include "moc_piesliceitem_p.cpp"
203
204
204 QTCOMMERCIALCHART_END_NAMESPACE
205 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now