##// END OF EJS Templates
Z order for pie
Tero Ahola -
r490:5facde66eb08
parent child
Show More
@@ -1,21 +1,22
1 1 TEMPLATE = subdirs
2 2 SUBDIRS += linechart \
3 3 zoomlinechart \
4 4 colorlinechart \
5 5 barchart \
6 6 stackedbarchart \
7 7 percentbarchart \
8 8 scatterchart \
9 9 piechart \
10 10 piechartcustomization \
11 11 piechartdrilldown \
12 12 dynamiclinechart \
13 13 axischart \
14 14 multichart \
15 15 gdpbarchart \
16 16 presenterchart \
17 17 chartview \
18 18 scatterinteractions \
19 19 splinechart \
20 20 areachart \
21 stackedbarchartdrilldown
21 stackedbarchartdrilldown \
22 customcolors
@@ -1,81 +1,82
1 1 #ifndef CHARTPRESENTER_H_
2 2 #define CHARTPRESENTER_H_
3 3
4 4 #include "qchartglobal.h"
5 5 #include "qchart.h" //becouse of QChart::ChartThemeId //TODO
6 6 #include "qchartaxis.h"
7 7 #include <QRectF>
8 8
9 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 10
11 11 class ChartItem;
12 12 class QSeries;
13 13 class ChartDataSet;
14 14 //class QChart;
15 15 class Domain;
16 16 class AxisItem;
17 17 class ChartTheme;
18 18
19 19 class ChartPresenter: public QObject
20 20 {
21 21 Q_OBJECT
22 22 public:
23 23 enum ZValues {
24 24 BackgroundZValue = -1,
25 25 ShadesZValue,
26 26 GridZValue,
27 27 AxisZValue,
28 28 LineChartZValue,
29 ScatterSeriesZValue
29 ScatterSeriesZValue,
30 PieSeriesZValue
30 31 };
31 32
32 33 ChartPresenter(QChart* chart,ChartDataSet *dataset);
33 34 virtual ~ChartPresenter();
34 35
35 36 void setMargin(int margin);
36 37 int margin() const;
37 38
38 39 QRectF geometry() const;
39 40
40 41 void setChartTheme(QChart::ChartTheme theme);
41 42 QChart::ChartTheme chartTheme();
42 43
43 44 void setAnimationOptions(QChart::AnimationOptions options);
44 45 QChart::AnimationOptions animationOptions() const;
45 46
46 47 void zoomIn();
47 48 void zoomIn(const QRectF& rect);
48 49 void zoomOut();
49 50 void zoomReset();
50 51
51 52
52 53 private:
53 54 void createConnections();
54 55
55 56 public slots:
56 57 void handleSeriesAdded(QSeries* series,Domain* domain);
57 58 void handleSeriesRemoved(QSeries* series);
58 59 void handleAxisAdded(QChartAxis* axis,Domain* domain);
59 60 void handleAxisRemoved(QChartAxis* axis);
60 61 void handleGeometryChanged();
61 62
62 63 signals:
63 64 void geometryChanged(const QRectF& rect);
64 65
65 66 private:
66 67 QChart* m_chart;
67 68 ChartDataSet* m_dataset;
68 69 ChartTheme *m_chartTheme;
69 70 int m_zoomIndex;
70 71 int m_marginSize;
71 72 QMap<QSeries*,ChartItem*> m_chartItems;
72 73 QMap<QChartAxis*,AxisItem*> m_axisItems;
73 74 QVector<QRectF> m_zoomStack;
74 75 QRectF m_rect;
75 76 QChart::AnimationOptions m_options;
76 77
77 78 };
78 79
79 80 QTCOMMERCIALCHART_END_NAMESPACE
80 81
81 82 #endif /* CHARTPRESENTER_H_ */
@@ -1,154 +1,158
1 1 #include "piepresenter_p.h"
2 2 #include "pieslice_p.h"
3 3 #include "qpieslice.h"
4 4 #include "qpieseries.h"
5 #include "chartpresenter_p.h"
5 6 #include <QDebug>
6 7 #include <QPainter>
7 8
8 9
9 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 11
11 12 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
12 13 :ChartItem(parent),
13 14 m_series(series)
14 15 {
15 16 Q_ASSERT(series);
16 17 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
17 18 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
18 19 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
19 20
20 21 if (m_series->count()) {
21 22 QPieSeries::ChangeSet changeSet;
22 23 changeSet.appendAdded(m_series->m_slices);
23 24 handleSeriesChanged(changeSet);
24 25 }
26
27 // Note: the following does not affect as long as the item does not have anything to paint
28 setZValue(ChartPresenter::PieSeriesZValue);
25 29 }
26 30
27 31 PiePresenter::~PiePresenter()
28 32 {
29 33 // slices deleted automatically through QGraphicsItem
30 34 }
31 35
32 36 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
33 37 {
34 38 // TODO: paint shadows for all components
35 39 // - get paths from items & merge & offset and draw with shadow color?
36 40 //painter->setBrush(QBrush(Qt::red));
37 41 //painter->drawRect(m_debugRect);
38 42 }
39 43
40 44 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
41 45 {
42 46 //qDebug() << "PiePresenter::handleSeriesChanged()";
43 47 //qDebug() << " added : " << changeSet.added();
44 48 //qDebug() << " changed: " << changeSet.changed();
45 49 //qDebug() << " removed: " << changeSet.removed();
46 50
47 51 foreach (QPieSlice* s, changeSet.added())
48 52 addSlice(s);
49 53
50 54 foreach (QPieSlice* s, changeSet.changed())
51 55 updateSlice(s);
52 56
53 57 foreach (QPieSlice* s, changeSet.removed())
54 58 deleteSlice(s);
55 59
56 60 // every change possibly changes the actual pie size
57 61 updateGeometry();
58 62 }
59 63
60 64 void PiePresenter::handleDomainChanged(const Domain& domain)
61 65 {
62 66 // TODO
63 67 }
64 68
65 69 void PiePresenter::handleGeometryChanged(const QRectF& rect)
66 70 {
67 71 m_rect = rect;
68 72 prepareGeometryChange();
69 73 updateGeometry();
70 74 }
71 75
72 76 void PiePresenter::updateGeometry()
73 77 {
74 78 if (!m_rect.isValid() || m_rect.isEmpty())
75 79 return;
76 80
77 81 // find pie center coordinates
78 82 QPointF center;
79 83 center.setX(m_rect.left() + (m_rect.width() * m_series->m_hPositionFactor));
80 84 center.setY(m_rect.top() + (m_rect.height() * m_series->m_vPositionFactor));
81 85
82 86 // find maximum radius for pie
83 87 qreal radius = m_rect.height() / 2;
84 88 if (m_rect.width() < m_rect.height())
85 89 radius = m_rect.width() / 2;
86 90
87 91 // apply size factor
88 92 radius *= m_series->m_pieSizeFactor;
89 93
90 94 // update slices
91 95 if (m_pieCenter != center || m_pieRadius != radius) {
92 96 m_pieCenter = center;
93 97 m_pieRadius = radius;
94 98 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieCenter << m_pieRadius;
95 99 foreach (PieSlice* s, m_slices.values()) {
96 100 s->setPieCenterAndRadius(center, radius);
97 101 s->updateGeometry();
98 102 s->update();
99 103 }
100 104 }
101 105
102 106 update();
103 107 }
104 108
105 109 void PiePresenter::addSlice(QPieSlice* sliceData)
106 110 {
107 111 //qDebug() << "PiePresenter::addSlice()" << sliceData;
108 112
109 113 if (m_slices.keys().contains(sliceData)) {
110 114 Q_ASSERT(0); // TODO: how to handle this nicely?
111 115 return;
112 116 }
113 117
114 118 // create slice
115 119 PieSlice *slice = new PieSlice(this);
116 120 slice->setPieCenterAndRadius(m_pieCenter, m_pieRadius);
117 121 slice->updateData(sliceData);
118 122 slice->updateGeometry();
119 123 slice->update();
120 124 m_slices.insert(sliceData, slice);
121 125
122 126 // connect signals
123 127 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
124 128 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
125 129 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
126 130 }
127 131
128 132 void PiePresenter::updateSlice(QPieSlice* sliceData)
129 133 {
130 134 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
131 135
132 136 if (!m_slices.contains(sliceData)) {
133 137 Q_ASSERT(0); // TODO: how to handle this nicely?
134 138 return;
135 139 }
136 140
137 141 m_slices[sliceData]->updateData(sliceData);
138 142 }
139 143
140 144 void PiePresenter::deleteSlice(QPieSlice* sliceData)
141 145 {
142 146 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
143 147
144 148 if (!m_slices.contains(sliceData)) {
145 149 Q_ASSERT(0); // TODO: how to handle this nicely?
146 150 return;
147 151 }
148 152
149 153 delete m_slices.take(sliceData);
150 154 }
151 155
152 156 #include "moc_piepresenter_p.cpp"
153 157
154 158 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,208 +1,210
1 1 #include "pieslice_p.h"
2 2 #include "piepresenter_p.h"
3 3 #include "qpieseries.h"
4 4 #include "qpieslice.h"
5 #include "chartpresenter_p.h"
5 6 #include <QPainter>
6 7 #include <QDebug>
7 8 #include <qmath.h>
8 9 #include <QGraphicsSceneEvent>
9 10 #include <QTime>
10 11
11 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 13
13 14 #define PI 3.14159265 // TODO: is this defined in some header?
14 15
15 16 QPointF offset(qreal angle, qreal length)
16 17 {
17 18 qreal dx = qSin(angle*(PI/180)) * length;
18 19 qreal dy = qCos(angle*(PI/180)) * length;
19 20 return QPointF(dx, -dy);
20 21 }
21 22
22 23 PieSlice::PieSlice(QGraphicsItem* parent)
23 24 :QGraphicsObject(parent),
24 25 m_pieRadius(0),
25 26 m_startAngle(0),
26 27 m_angleSpan(0),
27 28 m_isExploded(false),
28 29 m_explodeDistanceFactor(0),
29 30 m_labelVisible(false),
30 31 m_labelArmLengthFactor(0)
31 32 {
32 33 setAcceptHoverEvents(true);
33 34 setAcceptedMouseButtons(Qt::LeftButton);
35 setZValue(ChartPresenter::PieSeriesZValue);
34 36 }
35 37
36 38 PieSlice::~PieSlice()
37 39 {
38 40
39 41 }
40 42
41 43 QRectF PieSlice::boundingRect() const
42 44 {
43 45 return m_slicePath.boundingRect();
44 46 }
45 47
46 48 QPainterPath PieSlice::shape() const
47 49 {
48 50 // Don't include the label and label arm.
49 51 // This is used to detect a mouse clicks. We do not want clicks from label.
50 52 return m_slicePath;
51 53 }
52 54
53 55 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
54 56 {
55 57 painter->setClipRect(parentItem()->boundingRect());
56 58
57 59 painter->save();
58 60 painter->setPen(m_slicePen);
59 61 painter->setBrush(m_sliceBrush);
60 62 painter->drawPath(m_slicePath);
61 63 painter->restore();
62 64
63 65 if (m_labelVisible) {
64 66 painter->save();
65 67 painter->setPen(m_labelArmPen);
66 68 painter->drawPath(m_labelArmPath);
67 69 painter->restore();
68 70
69 71 painter->setFont(m_labelFont);
70 72 painter->drawText(m_labelTextRect.bottomLeft(), m_labelText);
71 73 }
72 74 }
73 75
74 76 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
75 77 {
76 78 emit hoverEnter();
77 79 }
78 80
79 81 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
80 82 {
81 83 emit hoverLeave();
82 84 }
83 85
84 86 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
85 87 {
86 88 emit clicked();
87 89 }
88 90
89 91 void PieSlice::setPieCenterAndRadius(QPointF center, qreal radius)
90 92 {
91 93 m_pieCenter = center;
92 94 m_pieRadius = radius;
93 95 }
94 96
95 97 void PieSlice::updateGeometry()
96 98 {
97 99 if (m_pieRadius <= 0)
98 100 return;
99 101
100 102 prepareGeometryChange();
101 103
102 104 // update slice path
103 105 qreal centerAngle;
104 106 QPointF armStart;
105 107 m_slicePath = slicePath(m_pieCenter, m_pieRadius, m_startAngle, m_angleSpan, m_isExploded, m_pieRadius * m_explodeDistanceFactor, &centerAngle, &armStart);
106 108
107 109 // update text rect
108 110 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
109 111
110 112 // update label arm path
111 113 QPointF labelTextStart;
112 114 m_labelArmPath = labelArmPath(armStart, centerAngle, m_pieRadius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
113 115
114 116 // update text position
115 117 m_labelTextRect.moveBottomLeft(labelTextStart);
116 118
117 119 //qDebug() << "PieSlice::updateGeometry" << m_labelText << boundingRect() << m_startAngle << m_startAngle + m_angleSpan;
118 120 }
119 121
120 122 void PieSlice::updateData(const QPieSlice* sliceData)
121 123 {
122 124 // TODO: compare what has changes to avoid unneccesary geometry updates
123 125
124 126 m_startAngle = sliceData->startAngle();
125 127 m_angleSpan = sliceData->m_angleSpan;
126 128 m_isExploded = sliceData->isExploded();
127 129 m_explodeDistanceFactor = sliceData->explodeDistanceFactor();
128 130 m_slicePen = sliceData->slicePen();
129 131 m_sliceBrush = sliceData->sliceBrush();
130 132
131 133 m_labelVisible = sliceData->isLabelVisible();
132 134 m_labelText = sliceData->label();
133 135 m_labelFont = sliceData->labelFont();
134 136 m_labelArmLengthFactor = sliceData->labelArmLengthFactor();
135 137 m_labelArmPen = sliceData->labelArmPen();
136 138
137 139 updateGeometry();
138 140 update();
139 141 }
140 142
141 143 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart)
142 144 {
143 145 // calculate center angle
144 146 *centerAngle = startAngle + (angleSpan/2);
145 147
146 148 // calculate slice rectangle
147 149 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
148 150
149 151 // adjust rect for exploding
150 152 if (exploded) {
151 153 qreal dx = qSin(*centerAngle*(PI/180)) * explodeDistance;
152 154 qreal dy = -qCos(*centerAngle*(PI/180)) * explodeDistance;
153 155 rect.translate(dx, dy);
154 156 }
155 157
156 158 // slice path
157 159 // TODO: draw the shape so that it might have a hole in the center
158 160 QPainterPath path;
159 161 path.moveTo(rect.center());
160 162 path.arcTo(rect, -startAngle + 90, -angleSpan);
161 163 path.closeSubpath();
162 164
163 165 // calculate label arm start point
164 166 *armStart = center;
165 167 if (exploded)
166 168 *armStart += offset(*centerAngle, explodeDistance + radius + PIESLICE_LABEL_GAP);
167 169 else
168 170 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
169 171
170 172 return path;
171 173 }
172 174
173 175 QPainterPath PieSlice::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
174 176 {
175 177 qreal dx = qSin(angle*(PI/180)) * length;
176 178 qreal dy = -qCos(angle*(PI/180)) * length;
177 179 QPointF parm1 = start + QPointF(dx, dy);
178 180
179 181 QPointF parm2 = parm1;
180 182 if (angle < 180) { // arm swings the other way on the left side
181 183 parm2 += QPointF(textWidth, 0);
182 184 *textStart = parm1;
183 185 }
184 186 else {
185 187 parm2 += QPointF(-textWidth,0);
186 188 *textStart = parm2;
187 189 }
188 190
189 191 // elevate the text position a bit so that it does not hit the line
190 192 *textStart += QPointF(0, -5);
191 193
192 194 QPainterPath path;
193 195 path.moveTo(start);
194 196 path.lineTo(parm1);
195 197 path.lineTo(parm2);
196 198
197 199 return path;
198 200 }
199 201
200 202 QRectF PieSlice::labelTextRect(QFont font, QString text)
201 203 {
202 204 QFontMetricsF fm(font);
203 205 return fm.boundingRect(text);
204 206 }
205 207
206 208 #include "moc_pieslice_p.cpp"
207 209
208 210 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now