##// END OF EJS Templates
Prevent slice label pointing straight down (because it looks bad).
Jani Honkonen -
r972:23d12d63b029
parent child
Show More
@@ -1,205 +1,213
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->setClipRect(parentItem()->boundingRect());
79 painter->setPen(m_data.m_labelPen);
79 painter->setPen(m_data.m_labelPen);
80 painter->drawPath(m_labelArmPath);
80 painter->drawPath(m_labelArmPath);
81 // the pen color will affect the font color as well
81 // the pen color will affect the font color as well
82 painter->setFont(m_data.m_labelFont);
82 painter->setFont(m_data.m_labelFont);
83 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
83 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
84 }
84 }
85 }
85 }
86
86
87 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
87 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
88 {
88 {
89 emit hoverEnter(); // TODO: refactor emit hover(somebooleanvalue)
89 emit hoverEnter(); // TODO: refactor emit hover(somebooleanvalue)
90 }
90 }
91
91
92 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
92 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
93 {
93 {
94 emit hoverLeave(); // TODO: refactor emit hover(somebooleanvalue)
94 emit hoverLeave(); // TODO: refactor emit hover(somebooleanvalue)
95 }
95 }
96
96
97 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
97 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
98 {
98 {
99 emit clicked(event->buttons());
99 emit clicked(event->buttons());
100 }
100 }
101
101
102 void PieSliceItem::setSliceData(PieSliceData sliceData)
102 void PieSliceItem::setSliceData(PieSliceData sliceData)
103 {
103 {
104 m_data = sliceData;
104 m_data = sliceData;
105 }
105 }
106
106
107 void PieSliceItem::updateGeometry()
107 void PieSliceItem::updateGeometry()
108 {
108 {
109 if (m_data.m_radius <= 0)
109 if (m_data.m_radius <= 0)
110 return;
110 return;
111
111
112 prepareGeometryChange();
112 prepareGeometryChange();
113
113
114 // update slice path
114 // update slice path
115 qreal centerAngle;
115 qreal centerAngle;
116 QPointF armStart;
116 QPointF armStart;
117 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);
118
118
119 // update text rect
119 // update text rect
120 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
120 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
121
121
122 // update label arm path
122 // update label arm path
123 QPointF labelTextStart;
123 QPointF labelTextStart;
124 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);
125
125
126 // update text position
126 // update text position
127 m_labelTextRect.moveBottomLeft(labelTextStart);
127 m_labelTextRect.moveBottomLeft(labelTextStart);
128
128
129 // update bounding rect
129 // update bounding rect
130 if (m_data.m_isLabelVisible)
130 if (m_data.m_isLabelVisible)
131 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);
132 else
132 else
133 m_boundingRect = m_slicePath.boundingRect();
133 m_boundingRect = m_slicePath.boundingRect();
134 }
134 }
135
135
136 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
136 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
137 {
137 {
138 if (slice->isExploded()) {
138 if (slice->isExploded()) {
139 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
139 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
140 qreal len = radius * slice->explodeDistanceFactor();
140 qreal len = radius * slice->explodeDistanceFactor();
141 qreal dx = qSin(centerAngle*(PI/180)) * len;
141 qreal dx = qSin(centerAngle*(PI/180)) * len;
142 qreal dy = -qCos(centerAngle*(PI/180)) * len;
142 qreal dy = -qCos(centerAngle*(PI/180)) * len;
143 point += QPointF(dx, dy);
143 point += QPointF(dx, dy);
144 }
144 }
145 return point;
145 return point;
146 }
146 }
147
147
148 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)
149 {
149 {
150 // calculate center angle
150 // calculate center angle
151 *centerAngle = startAngle + (angleSpan/2);
151 *centerAngle = startAngle + (angleSpan/2);
152
152
153 // calculate slice rectangle
153 // calculate slice rectangle
154 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);
155
155
156 // slice path
156 // slice path
157 // 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
158 QPainterPath path;
158 QPainterPath path;
159 path.moveTo(rect.center());
159 path.moveTo(rect.center());
160 path.arcTo(rect, -startAngle + 90, -angleSpan);
160 path.arcTo(rect, -startAngle + 90, -angleSpan);
161 path.closeSubpath();
161 path.closeSubpath();
162
162
163 // calculate label arm start point
163 // calculate label arm start point
164 *armStart = center;
164 *armStart = center;
165 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
165 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
166
166
167 return path;
167 return path;
168 }
168 }
169
169
170 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)
171 {
171 {
172 // prevent label arm pointing straight down because it will look bad
173 if (angle < 180 && angle > 170)
174 angle = 170;
175 if (angle > 180 && angle < 190)
176 angle = 190;
177
178 // line from slice to label
172 qreal dx = qSin(angle*(PI/180)) * length;
179 qreal dx = qSin(angle*(PI/180)) * length;
173 qreal dy = -qCos(angle*(PI/180)) * length;
180 qreal dy = -qCos(angle*(PI/180)) * length;
174 QPointF parm1 = start + QPointF(dx, dy);
181 QPointF parm1 = start + QPointF(dx, dy);
175
182
183 // line to underline the label
176 QPointF parm2 = parm1;
184 QPointF parm2 = parm1;
177 if (angle < 180) { // arm swings the other way on the left side
185 if (angle < 180) { // arm swings the other way on the left side
178 parm2 += QPointF(textWidth, 0);
186 parm2 += QPointF(textWidth, 0);
179 *textStart = parm1;
187 *textStart = parm1;
180 }
188 }
181 else {
189 else {
182 parm2 += QPointF(-textWidth,0);
190 parm2 += QPointF(-textWidth,0);
183 *textStart = parm2;
191 *textStart = parm2;
184 }
192 }
185
193
186 // elevate the text position a bit so that it does not hit the line
194 // elevate the text position a bit so that it does not hit the line
187 *textStart += QPointF(0, -5);
195 *textStart += QPointF(0, -3);
188
196
189 QPainterPath path;
197 QPainterPath path;
190 path.moveTo(start);
198 path.moveTo(start);
191 path.lineTo(parm1);
199 path.lineTo(parm1);
192 path.lineTo(parm2);
200 path.lineTo(parm2);
193
201
194 return path;
202 return path;
195 }
203 }
196
204
197 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
205 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
198 {
206 {
199 QFontMetricsF fm(font);
207 QFontMetricsF fm(font);
200 return fm.boundingRect(text);
208 return fm.boundingRect(text);
201 }
209 }
202
210
203 #include "moc_piesliceitem_p.cpp"
211 #include "moc_piesliceitem_p.cpp"
204
212
205 QTCOMMERCIALCHART_END_NAMESPACE
213 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,79 +1,79
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 #ifndef PIESLICEITEM_H
21 #ifndef PIESLICEITEM_H
22 #define PIESLICEITEM_H
22 #define PIESLICEITEM_H
23
23
24 #include "qchartglobal.h"
24 #include "qchartglobal.h"
25 #include "charttheme_p.h"
25 #include "charttheme_p.h"
26 #include "qpieseries.h"
26 #include "qpieseries.h"
27 #include "pieslicedata_p.h"
27 #include "pieslicedata_p.h"
28 #include <QGraphicsItem>
28 #include <QGraphicsItem>
29 #include <QRectF>
29 #include <QRectF>
30 #include <QColor>
30 #include <QColor>
31 #include <QPen>
31 #include <QPen>
32
32
33 #define PIESLICE_LABEL_GAP 5
33 #define PIESLICE_LABEL_GAP 5
34
34
35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 class PieChartItem;
36 class PieChartItem;
37 class PieSliceLabel;
37 class PieSliceLabel;
38 class QPieSlice;
38 class QPieSlice;
39
39
40 class PieSliceItem : public QGraphicsObject
40 class PieSliceItem : public QGraphicsObject
41 {
41 {
42 Q_OBJECT
42 Q_OBJECT
43
43
44 public:
44 public:
45 PieSliceItem(QGraphicsItem* parent = 0);
45 PieSliceItem(QGraphicsItem* parent = 0);
46 ~PieSliceItem();
46 ~PieSliceItem();
47
47
48 public: // from QGraphicsItem
48 public: // from QGraphicsItem
49 QRectF boundingRect() const;
49 QRectF boundingRect() const;
50 QPainterPath shape() const;
50 QPainterPath shape() const;
51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
52 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
52 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
53 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
53 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
54 void mousePressEvent(QGraphicsSceneMouseEvent *event);
54 void mousePressEvent(QGraphicsSceneMouseEvent *event);
55
55
56 Q_SIGNALS:
56 Q_SIGNALS:
57 void clicked(Qt::MouseButtons buttons);
57 void clicked(Qt::MouseButtons buttons);
58 void hoverEnter();
58 void hoverEnter();
59 void hoverLeave();
59 void hoverLeave();
60
60
61 public:
61 public:
62 void setSliceData(PieSliceData sliceData);
62 void setSliceData(PieSliceData sliceData);
63 void updateGeometry();
63 void updateGeometry();
64 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
64 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
65 static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart);
65 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
66 static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart);
66 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
67 static QRectF labelTextRect(QFont font, QString text);
67 QRectF labelTextRect(QFont font, QString text);
68
68
69 private:
69 private:
70 PieSliceData m_data;
70 PieSliceData m_data;
71 QRectF m_boundingRect;
71 QRectF m_boundingRect;
72 QPainterPath m_slicePath;
72 QPainterPath m_slicePath;
73 QPainterPath m_labelArmPath;
73 QPainterPath m_labelArmPath;
74 QRectF m_labelTextRect;
74 QRectF m_labelTextRect;
75 };
75 };
76
76
77 QTCOMMERCIALCHART_END_NAMESPACE
77 QTCOMMERCIALCHART_END_NAMESPACE
78
78
79 #endif // PIESLICEITEM_H
79 #endif // PIESLICEITEM_H
General Comments 0
You need to be logged in to leave comments. Login now