@@ -1,120 +1,121 | |||
|
1 | 1 | #include "areachartitem_p.h" |
|
2 | 2 | #include "qareaseries.h" |
|
3 | 3 | #include "qlineseries.h" |
|
4 | 4 | #include "chartpresenter_p.h" |
|
5 | 5 | #include <QPainter> |
|
6 | 6 | #include <QGraphicsSceneMouseEvent> |
|
7 | 7 | |
|
8 | 8 | |
|
9 | 9 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
10 | 10 | |
|
11 | 11 | //TODO: optimize : remove points which are not visible |
|
12 | 12 | |
|
13 | 13 | AreaChartItem::AreaChartItem(QAreaSeries* areaSeries,QGraphicsItem *parent):ChartItem(parent), |
|
14 | 14 | m_series(areaSeries), |
|
15 | 15 | m_upper(0), |
|
16 | 16 | m_lower(0), |
|
17 | 17 | m_pointsVisible(false) |
|
18 | 18 | { |
|
19 | 19 | setZValue(ChartPresenter::LineChartZValue); |
|
20 | 20 | m_upper = new AreaBoundItem(this,m_series->upperSeries()); |
|
21 | 21 | if(m_series->lowerSeries()){ |
|
22 | 22 | m_lower = new AreaBoundItem(this,m_series->lowerSeries()); |
|
23 | 23 | } |
|
24 | 24 | |
|
25 | 25 | QObject::connect(areaSeries,SIGNAL(updated()),this,SLOT(handleUpdated())); |
|
26 | 26 | QObject::connect(this,SIGNAL(clicked(const QPointF&)),areaSeries,SIGNAL(clicked(const QPointF&))); |
|
27 | 27 | |
|
28 | 28 | handleUpdated(); |
|
29 | 29 | } |
|
30 | 30 | |
|
31 | 31 | AreaChartItem::~AreaChartItem() |
|
32 | 32 | { |
|
33 | 33 | delete m_upper; |
|
34 | 34 | delete m_lower; |
|
35 | 35 | }; |
|
36 | 36 | |
|
37 | 37 | QRectF AreaChartItem::boundingRect() const |
|
38 | 38 | { |
|
39 | 39 | return m_rect; |
|
40 | 40 | } |
|
41 | 41 | |
|
42 | 42 | QPainterPath AreaChartItem::shape() const |
|
43 | 43 | { |
|
44 | 44 | return m_path; |
|
45 | 45 | } |
|
46 | 46 | |
|
47 | 47 | void AreaChartItem::updatePath() |
|
48 | 48 | { |
|
49 | 49 | QPainterPath path; |
|
50 | 50 | |
|
51 | 51 | path.connectPath(m_upper->shape()); |
|
52 | 52 | if(m_lower){ |
|
53 | 53 | path.connectPath(m_lower->shape().toReversed()); |
|
54 | 54 | } |
|
55 | 55 | else{ |
|
56 | 56 | QPointF first = path.pointAtPercent(0); |
|
57 | 57 | QPointF last = path.pointAtPercent(1); |
|
58 | 58 | path.lineTo(last.x(),m_clipRect.bottom()); |
|
59 | 59 | path.lineTo(first.x(),m_clipRect.bottom()); |
|
60 | 60 | } |
|
61 | 61 | path.closeSubpath(); |
|
62 | 62 | prepareGeometryChange(); |
|
63 | 63 | m_path=path; |
|
64 | 64 | m_rect=path.boundingRect(); |
|
65 | 65 | update(); |
|
66 | 66 | } |
|
67 | 67 | |
|
68 | 68 | void AreaChartItem::handleUpdated() |
|
69 | 69 | { |
|
70 | 70 | m_pointsVisible = m_series->pointsVisible(); |
|
71 | 71 | m_linePen = m_series->pen(); |
|
72 | 72 | m_brush = m_series->brush(); |
|
73 | 73 | m_pointPen = m_series->pen(); |
|
74 | 74 | m_pointPen.setWidthF(2*m_pointPen.width()); |
|
75 | 75 | |
|
76 | 76 | update(); |
|
77 | 77 | } |
|
78 | 78 | |
|
79 | 79 | void AreaChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY) |
|
80 | 80 | { |
|
81 | 81 | m_upper->handleDomainChanged(minX,maxX,minY,maxY); |
|
82 | 82 | if(m_lower) |
|
83 | 83 | m_lower->handleDomainChanged(minX,maxX,minY,maxY); |
|
84 | 84 | } |
|
85 | 85 | |
|
86 | 86 | void AreaChartItem::handleGeometryChanged(const QRectF& rect) |
|
87 | 87 | { |
|
88 | 88 | m_clipRect=rect.translated(-rect.topLeft()); |
|
89 | 89 | setPos(rect.topLeft()); |
|
90 | 90 | m_upper->handleGeometryChanged(rect); |
|
91 | 91 | if(m_lower) |
|
92 | 92 | m_lower->handleGeometryChanged(rect); |
|
93 | 93 | } |
|
94 | 94 | //painter |
|
95 | 95 | |
|
96 | 96 | void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
97 | 97 | { |
|
98 |
Q_UNUSED(widget) |
|
|
99 |
Q_UNUSED(option) |
|
|
98 | Q_UNUSED(widget) | |
|
99 | Q_UNUSED(option) | |
|
100 | ||
|
100 | 101 | painter->save(); |
|
101 | 102 | painter->setPen(m_linePen); |
|
102 | 103 | painter->setBrush(m_brush); |
|
103 | 104 | painter->setClipRect(m_clipRect); |
|
104 | 105 | painter->drawPath(m_path); |
|
105 | 106 | if(m_pointsVisible){ |
|
106 | 107 | painter->setPen(m_pointPen); |
|
107 | 108 | painter->drawPoints(m_upper->points()); |
|
108 | 109 | if(m_lower) painter->drawPoints(m_lower->points()); |
|
109 | 110 | } |
|
110 | 111 | painter->restore(); |
|
111 | 112 | } |
|
112 | 113 | |
|
113 | 114 | void AreaChartItem::mousePressEvent( QGraphicsSceneMouseEvent * event ) |
|
114 | 115 | { |
|
115 | 116 | emit clicked(m_upper->calculateDomainPoint(event->pos())); |
|
116 | 117 | } |
|
117 | 118 | |
|
118 | 119 | #include "moc_areachartitem_p.cpp" |
|
119 | 120 | |
|
120 | 121 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,406 +1,406 | |||
|
1 | 1 | #include "axisitem_p.h" |
|
2 | 2 | #include "qchartaxis.h" |
|
3 | 3 | #include "chartpresenter_p.h" |
|
4 | 4 | #include "chartanimator_p.h" |
|
5 | 5 | #include <QPainter> |
|
6 | 6 | #include <QDebug> |
|
7 | 7 | |
|
8 | 8 | static int label_padding = 5; |
|
9 | 9 | |
|
10 | 10 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
11 | 11 | |
|
12 | 12 | AxisItem::AxisItem(QChartAxis* axis,ChartPresenter* presenter,AxisType type,QGraphicsItem* parent) : |
|
13 | 13 | ChartItem(parent), |
|
14 | 14 | m_presenter(presenter), |
|
15 | 15 | m_chartAxis(axis), |
|
16 | 16 | m_type(type), |
|
17 | 17 | m_labelsAngle(0), |
|
18 | 18 | m_grid(parent), |
|
19 | 19 | m_shades(parent), |
|
20 | 20 | m_labels(parent), |
|
21 | 21 | m_axis(parent), |
|
22 | 22 | m_min(0), |
|
23 | 23 | m_max(0), |
|
24 | 24 | m_ticksCount(0) |
|
25 | 25 | { |
|
26 | 26 | //initial initialization |
|
27 | 27 | m_axis.setZValue(ChartPresenter::AxisZValue); |
|
28 | 28 | m_shades.setZValue(ChartPresenter::ShadesZValue); |
|
29 | 29 | m_grid.setZValue(ChartPresenter::GridZValue); |
|
30 | 30 | setFlags(QGraphicsItem::ItemHasNoContents); |
|
31 | 31 | |
|
32 | 32 | QObject::connect(m_chartAxis,SIGNAL(updated()),this,SLOT(handleAxisUpdated())); |
|
33 | 33 | QObject::connect(m_chartAxis->categories(),SIGNAL(updated()),this,SLOT(handleAxisCategoriesUpdated())); |
|
34 | 34 | |
|
35 | 35 | handleAxisUpdated(); |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | AxisItem::~AxisItem() |
|
39 | 39 | { |
|
40 | 40 | } |
|
41 | 41 | |
|
42 | 42 | QRectF AxisItem::boundingRect() const |
|
43 | 43 | { |
|
44 | 44 | return QRectF(); |
|
45 | 45 | } |
|
46 | 46 | |
|
47 | 47 | void AxisItem::createItems(int count) |
|
48 | 48 | { |
|
49 | 49 | |
|
50 | 50 | if(m_axis.children().size()==0) |
|
51 | 51 | m_axis.addToGroup(new QGraphicsLineItem()); |
|
52 | 52 | for (int i = 0; i < count; ++i) { |
|
53 | 53 | m_grid.addToGroup(new QGraphicsLineItem()); |
|
54 | 54 | m_labels.addToGroup(new QGraphicsSimpleTextItem()); |
|
55 | 55 | m_axis.addToGroup(new QGraphicsLineItem()); |
|
56 | 56 | if((m_grid.childItems().size())%2 && m_grid.childItems().size()>2) m_shades.addToGroup(new QGraphicsRectItem()); |
|
57 | 57 | } |
|
58 | 58 | } |
|
59 | 59 | |
|
60 | 60 | void AxisItem::deleteItems(int count) |
|
61 | 61 | { |
|
62 | 62 | QList<QGraphicsItem *> lines = m_grid.childItems(); |
|
63 | 63 | QList<QGraphicsItem *> labels = m_labels.childItems(); |
|
64 | 64 | QList<QGraphicsItem *> shades = m_shades.childItems(); |
|
65 | 65 | QList<QGraphicsItem *> axis = m_axis.childItems(); |
|
66 | 66 | |
|
67 | 67 | for (int i = 0; i < count; ++i) { |
|
68 | 68 | if(lines.size()%2 && lines.size()>1) delete(shades.takeLast()); |
|
69 | 69 | delete(lines.takeLast()); |
|
70 | 70 | delete(labels.takeLast()); |
|
71 | 71 | delete(axis.takeLast()); |
|
72 | 72 | } |
|
73 | 73 | } |
|
74 | 74 | |
|
75 | 75 | void AxisItem::updateLayout(QVector<qreal>& layout) |
|
76 | 76 | { |
|
77 | 77 | if(m_animator){ |
|
78 | 78 | m_animator->applyLayout(this,layout); |
|
79 | 79 | } |
|
80 | 80 | else setLayout(layout); |
|
81 | 81 | } |
|
82 | 82 | |
|
83 | 83 | QStringList AxisItem::createLabels(int ticks, qreal min, qreal max) const |
|
84 | 84 | { |
|
85 | 85 | Q_ASSERT(max>=min); |
|
86 | 86 | Q_ASSERT(ticks>0); |
|
87 | 87 | |
|
88 | 88 | QStringList labels; |
|
89 | 89 | |
|
90 | 90 | QChartAxisCategories* categories = m_chartAxis->categories(); |
|
91 | 91 | |
|
92 | 92 | for(int i=0; i< ticks; i++) { |
|
93 | 93 | qreal value = min + (i * (max - min)/ (ticks-1)); |
|
94 | 94 | if(categories->count()==0) { |
|
95 | 95 | labels << QString::number(value); |
|
96 | 96 | } |
|
97 | 97 | else { |
|
98 | 98 | |
|
99 | 99 | QString label = categories->label(value); |
|
100 | 100 | labels << label; |
|
101 | 101 | } |
|
102 | 102 | } |
|
103 | 103 | return labels; |
|
104 | 104 | } |
|
105 | 105 | |
|
106 | 106 | void AxisItem::setAxisOpacity(qreal opacity) |
|
107 | 107 | { |
|
108 | 108 | m_axis.setOpacity(opacity); |
|
109 | 109 | } |
|
110 | 110 | |
|
111 | 111 | qreal AxisItem::axisOpacity() const |
|
112 | 112 | { |
|
113 | 113 | return m_axis.opacity(); |
|
114 | 114 | } |
|
115 | 115 | |
|
116 | 116 | void AxisItem::setGridOpacity(qreal opacity) |
|
117 | 117 | { |
|
118 | 118 | m_grid.setOpacity(opacity); |
|
119 | 119 | } |
|
120 | 120 | |
|
121 | 121 | qreal AxisItem::gridOpacity() const |
|
122 | 122 | { |
|
123 | 123 | return m_grid.opacity(); |
|
124 | 124 | } |
|
125 | 125 | |
|
126 | 126 | void AxisItem::setLabelsOpacity(qreal opacity) |
|
127 | 127 | { |
|
128 | 128 | m_labels.setOpacity(opacity); |
|
129 | 129 | } |
|
130 | 130 | |
|
131 | 131 | qreal AxisItem::labelsOpacity() const |
|
132 | 132 | { |
|
133 | 133 | return m_labels.opacity(); |
|
134 | 134 | } |
|
135 | 135 | |
|
136 | 136 | void AxisItem::setShadesOpacity(qreal opacity) |
|
137 | 137 | { |
|
138 | 138 | m_shades.setOpacity(opacity); |
|
139 | 139 | } |
|
140 | 140 | |
|
141 | 141 | qreal AxisItem::shadesOpacity() const |
|
142 | 142 | { |
|
143 | 143 | return m_shades.opacity(); |
|
144 | 144 | } |
|
145 | 145 | |
|
146 | 146 | void AxisItem::setLabelsAngle(int angle) |
|
147 | 147 | { |
|
148 | 148 | foreach(QGraphicsItem* item , m_labels.childItems()) { |
|
149 | 149 | QPointF center = item->boundingRect().center(); |
|
150 | 150 | item->setRotation(angle); |
|
151 | 151 | } |
|
152 | 152 | |
|
153 | 153 | m_labelsAngle=angle; |
|
154 | 154 | } |
|
155 | 155 | |
|
156 | 156 | void AxisItem::setLabelsPen(const QPen& pen) |
|
157 | 157 | { |
|
158 | 158 | foreach(QGraphicsItem* item , m_labels.childItems()) { |
|
159 | 159 | static_cast<QGraphicsSimpleTextItem*>(item)->setPen(pen); |
|
160 | 160 | } |
|
161 | 161 | } |
|
162 | 162 | |
|
163 | 163 | void AxisItem::setLabelsBrush(const QBrush& brush) |
|
164 | 164 | { |
|
165 | 165 | foreach(QGraphicsItem* item , m_labels.childItems()) { |
|
166 | 166 | static_cast<QGraphicsSimpleTextItem*>(item)->setBrush(brush); |
|
167 | 167 | } |
|
168 | 168 | } |
|
169 | 169 | |
|
170 | 170 | void AxisItem::setLabelsFont(const QFont& font) |
|
171 | 171 | { |
|
172 | 172 | foreach(QGraphicsItem* item , m_labels.childItems()) { |
|
173 | 173 | static_cast<QGraphicsSimpleTextItem*>(item)->setFont(font); |
|
174 | 174 | } |
|
175 | 175 | } |
|
176 | 176 | |
|
177 | 177 | void AxisItem::setShadesBrush(const QBrush& brush) |
|
178 | 178 | { |
|
179 | 179 | foreach(QGraphicsItem* item , m_shades.childItems()) { |
|
180 | 180 | static_cast<QGraphicsRectItem*>(item)->setBrush(brush); |
|
181 | 181 | } |
|
182 | 182 | } |
|
183 | 183 | |
|
184 | 184 | void AxisItem::setShadesPen(const QPen& pen) |
|
185 | 185 | { |
|
186 | 186 | foreach(QGraphicsItem* item , m_shades.childItems()) { |
|
187 | 187 | static_cast<QGraphicsRectItem*>(item)->setPen(pen); |
|
188 | 188 | } |
|
189 | 189 | } |
|
190 | 190 | |
|
191 | 191 | void AxisItem::setAxisPen(const QPen& pen) |
|
192 | 192 | { |
|
193 | 193 | foreach(QGraphicsItem* item , m_axis.childItems()) { |
|
194 | 194 | static_cast<QGraphicsLineItem*>(item)->setPen(pen); |
|
195 | 195 | } |
|
196 | 196 | } |
|
197 | 197 | |
|
198 | 198 | void AxisItem::setGridPen(const QPen& pen) |
|
199 | 199 | { |
|
200 | 200 | foreach(QGraphicsItem* item , m_grid.childItems()) { |
|
201 | 201 | static_cast<QGraphicsLineItem*>(item)->setPen(pen); |
|
202 | 202 | } |
|
203 | 203 | } |
|
204 | 204 | |
|
205 | 205 | QVector<qreal> AxisItem::calculateLayout() const |
|
206 | 206 | { |
|
207 | 207 | Q_ASSERT(m_ticksCount>=2); |
|
208 | 208 | |
|
209 | 209 | QVector<qreal> points; |
|
210 | 210 | points.resize(m_ticksCount); |
|
211 | 211 | |
|
212 | 212 | switch (m_type) |
|
213 | 213 | { |
|
214 | 214 | case X_AXIS: |
|
215 | 215 | { |
|
216 | 216 | const qreal deltaX = m_rect.width()/(m_ticksCount-1); |
|
217 | 217 | for (int i = 0; i < m_ticksCount; ++i) { |
|
218 | 218 | int x = i * deltaX + m_rect.left(); |
|
219 | 219 | points[i] = x; |
|
220 | 220 | } |
|
221 | 221 | } |
|
222 | 222 | break; |
|
223 | 223 | case Y_AXIS: |
|
224 | 224 | { |
|
225 | 225 | const qreal deltaY = m_rect.height()/(m_ticksCount-1); |
|
226 | 226 | for (int i = 0; i < m_ticksCount; ++i) { |
|
227 | 227 | int y = i * -deltaY + m_rect.bottom(); |
|
228 | 228 | points[i] = y; |
|
229 | 229 | } |
|
230 | 230 | } |
|
231 | 231 | break; |
|
232 | 232 | } |
|
233 | 233 | return points; |
|
234 | 234 | } |
|
235 | 235 | |
|
236 | 236 | void AxisItem::setLayout(QVector<qreal>& layout) |
|
237 | 237 | { |
|
238 | 238 | int diff = m_layoutVector.size() - layout.size(); |
|
239 | 239 | |
|
240 | 240 | if(diff>0) { |
|
241 | 241 | deleteItems(diff); |
|
242 | 242 | } |
|
243 | 243 | else if(diff<0) { |
|
244 | 244 | createItems(-diff); |
|
245 | 245 | } |
|
246 | 246 | |
|
247 | 247 | if(diff!=0) handleAxisUpdated(); |
|
248 | 248 | |
|
249 | 249 | QStringList ticksList = createLabels(layout.size(),m_min,m_max); |
|
250 | 250 | |
|
251 | 251 | QList<QGraphicsItem *> lines = m_grid.childItems(); |
|
252 | 252 | QList<QGraphicsItem *> labels = m_labels.childItems(); |
|
253 | 253 | QList<QGraphicsItem *> shades = m_shades.childItems(); |
|
254 | 254 | QList<QGraphicsItem *> axis = m_axis.childItems(); |
|
255 | 255 | |
|
256 | 256 | Q_ASSERT(labels.size() == ticksList.size()); |
|
257 | 257 | Q_ASSERT(layout.size() == ticksList.size()); |
|
258 | 258 | |
|
259 | 259 | switch (m_type) |
|
260 | 260 | { |
|
261 | 261 | case X_AXIS: |
|
262 | 262 | { |
|
263 | 263 | QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(axis.at(0)); |
|
264 | 264 | lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); |
|
265 | 265 | |
|
266 | 266 | for (int i = 0; i < layout.size(); ++i) { |
|
267 | 267 | QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(lines.at(i)); |
|
268 | 268 | lineItem->setLine(layout[i], m_rect.top(), layout[i], m_rect.bottom()); |
|
269 | 269 | QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem*>(labels.at(i)); |
|
270 | 270 | labelItem->setText(ticksList.at(i)); |
|
271 | 271 | QPointF center = labelItem->boundingRect().center(); |
|
272 | 272 | labelItem->setTransformOriginPoint(center.x(), center.y()); |
|
273 | 273 | labelItem->setPos(layout[i] - center.x(), m_rect.bottom() + label_padding); |
|
274 | 274 | if((i+1)%2 && i>1) { |
|
275 | 275 | QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem*>(shades.at(i/2-1)); |
|
276 | 276 | rectItem->setRect(layout[i-1],m_rect.top(),layout[i]-layout[i-1],m_rect.height()); |
|
277 | 277 | } |
|
278 | 278 | lineItem = static_cast<QGraphicsLineItem*>(axis.at(i+1)); |
|
279 | 279 | lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); |
|
280 | 280 | } |
|
281 | 281 | } |
|
282 | 282 | break; |
|
283 | 283 | |
|
284 | 284 | case Y_AXIS: |
|
285 | 285 | { |
|
286 | 286 | QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(axis.at(0)); |
|
287 | 287 | lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); |
|
288 | 288 | |
|
289 | 289 | for (int i = 0; i < layout.size(); ++i) { |
|
290 | 290 | QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem*>(lines.at(i)); |
|
291 | 291 | lineItem->setLine(m_rect.left() , layout[i], m_rect.right(), layout[i]); |
|
292 | 292 | QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem*>(labels.at(i)); |
|
293 | 293 | labelItem->setText(ticksList.at(i)); |
|
294 | 294 | QPointF center = labelItem->boundingRect().center(); |
|
295 | 295 | labelItem->setTransformOriginPoint(center.x(), center.y()); |
|
296 | 296 | labelItem->setPos(m_rect.left() - labelItem->boundingRect().width() - label_padding , layout[i]-center.y()); |
|
297 | 297 | if((i+1)%2 && i>1) { |
|
298 | 298 | QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem*>(shades.at(i/2-1)); |
|
299 | 299 | rectItem->setRect(m_rect.left(),layout[i],m_rect.width(),layout[i-1]-layout[i]); |
|
300 | 300 | } |
|
301 | 301 | lineItem = static_cast<QGraphicsLineItem*>(axis.at(i+1)); |
|
302 | 302 | lineItem->setLine(m_rect.left()-5,layout[i],m_rect.left(),layout[i]); |
|
303 | 303 | } |
|
304 | 304 | } |
|
305 | 305 | break; |
|
306 | 306 | default: |
|
307 | 307 | qDebug()<<"Unknown axis type"; |
|
308 | 308 | break; |
|
309 | 309 | } |
|
310 | 310 | |
|
311 | 311 | m_layoutVector=layout; |
|
312 | 312 | } |
|
313 | 313 | |
|
314 | 314 | bool AxisItem::isEmpty() |
|
315 | 315 | { |
|
316 | 316 | return m_rect.isEmpty() || m_min==m_max || m_ticksCount==0; |
|
317 | 317 | } |
|
318 | 318 | |
|
319 | 319 | //handlers |
|
320 | 320 | |
|
321 | 321 | void AxisItem::handleAxisCategoriesUpdated() |
|
322 | 322 | { |
|
323 | 323 | if(isEmpty()) return; |
|
324 | 324 | updateLayout(m_layoutVector); |
|
325 | 325 | } |
|
326 | 326 | |
|
327 | 327 | void AxisItem::handleAxisUpdated() |
|
328 | 328 | { |
|
329 | 329 | |
|
330 | 330 | if(isEmpty()) return; |
|
331 | 331 | |
|
332 | 332 | if(m_chartAxis->isAxisVisible()) { |
|
333 | 333 | setAxisOpacity(100); |
|
334 | 334 | } |
|
335 | 335 | else { |
|
336 | 336 | setAxisOpacity(0); |
|
337 | 337 | } |
|
338 | 338 | |
|
339 | 339 | if(m_chartAxis->isGridLineVisible()) { |
|
340 | 340 | setGridOpacity(100); |
|
341 | 341 | } |
|
342 | 342 | else { |
|
343 | 343 | setGridOpacity(0); |
|
344 | 344 | } |
|
345 | 345 | |
|
346 | 346 | if(m_chartAxis->labelsVisible()) |
|
347 | 347 | { |
|
348 | 348 | setLabelsOpacity(100); |
|
349 | 349 | } |
|
350 | 350 | else { |
|
351 | 351 | setLabelsOpacity(0); |
|
352 | 352 | } |
|
353 | 353 | |
|
354 | 354 | if(m_chartAxis->shadesVisible()) { |
|
355 | 355 | setShadesOpacity(m_chartAxis->shadesOpacity()); |
|
356 | 356 | } |
|
357 | 357 | else { |
|
358 | 358 | setShadesOpacity(0); |
|
359 | 359 | } |
|
360 | 360 | |
|
361 | 361 | setLabelsAngle(m_chartAxis->labelsAngle()); |
|
362 | 362 | setAxisPen(m_chartAxis->axisPen()); |
|
363 | 363 | setLabelsPen(m_chartAxis->labelsPen()); |
|
364 | 364 | setLabelsBrush(m_chartAxis->labelsBrush()); |
|
365 | 365 | setLabelsFont(m_chartAxis->labelsFont()); |
|
366 | 366 | setGridPen(m_chartAxis->gridLinePen()); |
|
367 | 367 | setShadesPen(m_chartAxis->shadesPen()); |
|
368 | 368 | setShadesBrush(m_chartAxis->shadesBrush()); |
|
369 | 369 | |
|
370 | 370 | } |
|
371 | 371 | |
|
372 | 372 | void AxisItem::handleRangeChanged(qreal min, qreal max,int tickCount) |
|
373 | 373 | { |
|
374 | 374 | if(min==max || tickCount<2) return; |
|
375 | 375 | |
|
376 | 376 | m_min = min; |
|
377 | 377 | m_max = max; |
|
378 | 378 | m_ticksCount= tickCount; |
|
379 | 379 | |
|
380 | 380 | if(isEmpty()) return; |
|
381 | 381 | QVector<qreal> layout = calculateLayout(); |
|
382 | 382 | updateLayout(layout); |
|
383 | 383 | |
|
384 | 384 | } |
|
385 | 385 | |
|
386 | 386 | void AxisItem::handleGeometryChanged(const QRectF& rect) |
|
387 | 387 | { |
|
388 | 388 | m_rect = rect; |
|
389 | 389 | if(isEmpty()) return; |
|
390 | 390 | QVector<qreal> layout = calculateLayout(); |
|
391 | 391 | updateLayout(layout); |
|
392 | 392 | } |
|
393 | 393 | |
|
394 | 394 | //painter |
|
395 | 395 | |
|
396 | 396 | void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
397 | 397 | { |
|
398 |
Q_UNUSED(painter) |
|
|
399 |
Q_UNUSED(option) |
|
|
400 |
Q_UNUSED(widget) |
|
|
398 | Q_UNUSED(painter) | |
|
399 | Q_UNUSED(option) | |
|
400 | Q_UNUSED(widget) | |
|
401 | 401 | } |
|
402 | 402 | |
|
403 | 403 | //TODO "nice numbers algorithm" |
|
404 | 404 | #include "moc_axisitem_p.cpp" |
|
405 | 405 | |
|
406 | 406 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,93 +1,96 | |||
|
1 | 1 | #include "bar_p.h" |
|
2 | 2 | #include <QDebug> |
|
3 | 3 | #include <QPainter> |
|
4 | 4 | #include <QGraphicsSceneEvent> |
|
5 | 5 | |
|
6 | 6 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
7 | 7 | |
|
8 | 8 | Bar::Bar(QString category, QGraphicsItem *parent) |
|
9 | 9 | : QGraphicsObject(parent), |
|
10 | 10 | mXpos(0), |
|
11 | 11 | mYpos(0), |
|
12 | 12 | mWidth(0), |
|
13 | 13 | mHeight(0), |
|
14 | 14 | mCategory(category) |
|
15 | 15 | { |
|
16 | 16 | setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); |
|
17 | 17 | setAcceptHoverEvents(true); |
|
18 | 18 | } |
|
19 | 19 | |
|
20 | 20 | void Bar::setSize(const QSizeF& size) |
|
21 | 21 | { |
|
22 | 22 | mWidth = size.width(); |
|
23 | 23 | mHeight = size.height(); |
|
24 | 24 | } |
|
25 | 25 | |
|
26 | 26 | |
|
27 | 27 | void Bar::resize( qreal w, qreal h ) |
|
28 | 28 | { |
|
29 | 29 | mWidth = w; |
|
30 | 30 | mHeight = h; |
|
31 | 31 | } |
|
32 | 32 | |
|
33 | 33 | void Bar::setPos(qreal x, qreal y) |
|
34 | 34 | { |
|
35 | 35 | mXpos = x; |
|
36 | 36 | mYpos = y; |
|
37 | 37 | } |
|
38 | 38 | |
|
39 | 39 | void Bar::setPen(QPen pen) |
|
40 | 40 | { |
|
41 | 41 | mPen = pen; |
|
42 | 42 | } |
|
43 | 43 | |
|
44 | 44 | void Bar::setBrush(QBrush brush) |
|
45 | 45 | { |
|
46 | 46 | mBrush = brush; |
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | void Bar::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
50 | 50 | { |
|
51 | Q_UNUSED(option) | |
|
52 | Q_UNUSED(widget) | |
|
53 | ||
|
51 | 54 | if (0 == mHeight) { |
|
52 | 55 | return; |
|
53 | 56 | } |
|
54 | 57 | painter->setBrush(mBrush); |
|
55 | 58 | |
|
56 | 59 | // This compensates for rounding errors. drawRect takes ints and cumulative error of pos + size may be over 1. |
|
57 | 60 | int x0 = mXpos; |
|
58 | 61 | int x1 = (mXpos + mWidth); |
|
59 | 62 | int w = x1-x0; |
|
60 | 63 | int y0 = mYpos; |
|
61 | 64 | int y1 = (mYpos + mHeight); |
|
62 | 65 | int h = y1-y0; |
|
63 | 66 | painter->drawRect(x0, y0 ,w ,h); |
|
64 | 67 | } |
|
65 | 68 | |
|
66 | 69 | QRectF Bar::boundingRect() const |
|
67 | 70 | { |
|
68 | 71 | QRectF r(mXpos, mYpos, mWidth, mHeight); |
|
69 | 72 | return r; |
|
70 | 73 | } |
|
71 | 74 | |
|
72 | 75 | void Bar::mousePressEvent(QGraphicsSceneMouseEvent* event) |
|
73 | 76 | { |
|
74 | 77 | if (event->button() == Qt::LeftButton) { |
|
75 | 78 | emit clicked(mCategory); |
|
76 | 79 | } else if (event->button() == Qt::RightButton) { |
|
77 | 80 | emit rightClicked(mCategory); |
|
78 | 81 | } |
|
79 | 82 | } |
|
80 | 83 | |
|
81 | 84 | void Bar::hoverEnterEvent(QGraphicsSceneHoverEvent* event) |
|
82 | 85 | { |
|
83 | 86 | emit hoverEntered(event->lastScreenPos()); |
|
84 | 87 | } |
|
85 | 88 | |
|
86 | 89 | void Bar::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/) |
|
87 | 90 | { |
|
88 | 91 | emit hoverLeaved(); |
|
89 | 92 | } |
|
90 | 93 | |
|
91 | 94 | #include "moc_bar_p.cpp" |
|
92 | 95 | |
|
93 | 96 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,184 +1,189 | |||
|
1 | 1 | #include "barpresenterbase_p.h" |
|
2 | 2 | #include "bar_p.h" |
|
3 | 3 | #include "barvalue_p.h" |
|
4 | 4 | #include "separator_p.h" |
|
5 | 5 | #include "qbarset.h" |
|
6 | 6 | #include "qbarseries.h" |
|
7 | 7 | #include "qchart.h" |
|
8 | 8 | #include "qchartaxis.h" |
|
9 | 9 | #include "qchartaxiscategories.h" |
|
10 | 10 | #include "chartpresenter_p.h" |
|
11 | 11 | #include <QDebug> |
|
12 | 12 | #include <QToolTip> |
|
13 | 13 | |
|
14 | 14 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
15 | 15 | |
|
16 | 16 | BarPresenterBase::BarPresenterBase(QBarSeries *series, QChart *parent) : |
|
17 | 17 | ChartItem(parent), |
|
18 | 18 | mHeight(0), |
|
19 | 19 | mWidth(0), |
|
20 | 20 | mLayoutSet(false), |
|
21 | 21 | mSeries(series), |
|
22 | 22 | mChart(parent) |
|
23 | 23 | { |
|
24 | 24 | connect(series,SIGNAL(showToolTip(QPoint,QString)),this,SLOT(showToolTip(QPoint,QString))); |
|
25 | 25 | // connect(series,SIGNAL(enableSeparators(bool)),this,SLOT(enableSeparators(bool))); |
|
26 | 26 | // enableSeparators(series->separatorsVisible()); |
|
27 | 27 | setZValue(ChartPresenter::BarSeriesZValue); |
|
28 | 28 | initAxisLabels(); |
|
29 | 29 | dataChanged(); |
|
30 | 30 | } |
|
31 | 31 | |
|
32 | 32 | BarPresenterBase::~BarPresenterBase() |
|
33 | 33 | { |
|
34 | 34 | disconnect(this,SLOT(showToolTip(QPoint,QString))); |
|
35 | 35 | disconnect(this,SLOT(enableSeparators(bool))); |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | void BarPresenterBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
39 | 39 | { |
|
40 | 40 | if (!mLayoutSet) { |
|
41 | 41 | qDebug() << "BarPresenterBase::paint called without layout set. Aborting."; |
|
42 | 42 | return; |
|
43 | 43 | } |
|
44 | 44 | foreach(QGraphicsItem* i, childItems()) { |
|
45 | 45 | i->paint(painter,option,widget); |
|
46 | 46 | } |
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | QRectF BarPresenterBase::boundingRect() const |
|
50 | 50 | { |
|
51 | 51 | return QRectF(0, 0, mWidth, mHeight); |
|
52 | 52 | } |
|
53 | 53 | |
|
54 | 54 | void BarPresenterBase::dataChanged() |
|
55 | 55 | { |
|
56 | 56 | // TODO: performance optimizations. Do we really need to delete and create items every time data is changed or can we reuse them? |
|
57 | 57 | // Delete old bars |
|
58 | 58 | foreach (QGraphicsItem* item, childItems()) { |
|
59 | 59 | delete item; |
|
60 | 60 | } |
|
61 | 61 | |
|
62 | 62 | mBars.clear(); |
|
63 | 63 | // mSeparators.clear(); |
|
64 | 64 | mFloatingValues.clear(); |
|
65 | 65 | |
|
66 | 66 | // Create new graphic items for bars |
|
67 | 67 | for (int c=0; c<mSeries->categoryCount(); c++) { |
|
68 | 68 | QString category = mSeries->categoryName(c); |
|
69 | 69 | for (int s=0; s<mSeries->barsetCount(); s++) { |
|
70 | 70 | QBarSet *set = mSeries->barsetAt(s); |
|
71 | 71 | Bar *bar = new Bar(category,this); |
|
72 | 72 | childItems().append(bar); |
|
73 | 73 | mBars.append(bar); |
|
74 | 74 | connect(bar,SIGNAL(clicked(QString)),set,SIGNAL(clicked(QString))); |
|
75 | 75 | connect(bar,SIGNAL(rightClicked(QString)),set,SIGNAL(rightClicked(QString))); |
|
76 | 76 | connect(bar,SIGNAL(hoverEntered(QPoint)),set,SLOT(barHoverEnterEvent(QPoint))); |
|
77 | 77 | connect(bar,SIGNAL(hoverLeaved()),set,SLOT(barHoverLeaveEvent())); |
|
78 | 78 | } |
|
79 | 79 | } |
|
80 | 80 | /* |
|
81 | 81 | // Create separators |
|
82 | 82 | int count = mSeries->categoryCount() - 1; // There is one less separator than columns |
|
83 | 83 | for (int i=0; i<count; i++) { |
|
84 | 84 | Separator* sep = new Separator(this); |
|
85 | 85 | sep->setVisible(mSeries->separatorsVisible()); |
|
86 | 86 | childItems().append(sep); |
|
87 | 87 | mSeparators.append(sep); |
|
88 | 88 | } |
|
89 | 89 | */ |
|
90 | 90 | // Create floating values |
|
91 | 91 | for (int category=0; category<mSeries->categoryCount(); category++) { |
|
92 | 92 | for (int s=0; s<mSeries->barsetCount(); s++) { |
|
93 | 93 | QBarSet *set = mSeries->barsetAt(s); |
|
94 | 94 | BarValue *value = new BarValue(*set, this); |
|
95 | 95 | childItems().append(value); |
|
96 | 96 | mFloatingValues.append(value); |
|
97 | 97 | connect(set,SIGNAL(toggleFloatingValues()),value,SLOT(toggleVisible())); |
|
98 | 98 | } |
|
99 | 99 | } |
|
100 | 100 | } |
|
101 | 101 | |
|
102 | 102 | void BarPresenterBase::initAxisLabels() |
|
103 | 103 | { |
|
104 | 104 | int count = mSeries->categoryCount(); |
|
105 | 105 | if (0 == count) { |
|
106 | 106 | return; |
|
107 | 107 | } |
|
108 | 108 | |
|
109 | 109 | mChart->axisX()->setTicksCount(count+2); |
|
110 | 110 | |
|
111 | 111 | qreal min = 0; |
|
112 | 112 | qreal max = count+1; |
|
113 | 113 | |
|
114 | 114 | mChart->axisX()->setMin(min); |
|
115 | 115 | mChart->axisX()->setMax(max); |
|
116 | 116 | |
|
117 | 117 | QChartAxisCategories* categories = mChart->axisX()->categories(); |
|
118 | 118 | categories->clear(); |
|
119 | 119 | for (int i=0; i<count; i++) { |
|
120 | 120 | categories->insert(i+1,mSeries->categoryName(i)); |
|
121 | 121 | } |
|
122 | 122 | |
|
123 | 123 | |
|
124 | 124 | |
|
125 | 125 | mChart->axisX()->setLabelsVisible(true); |
|
126 | 126 | } |
|
127 | 127 | |
|
128 | 128 | //handlers |
|
129 | 129 | |
|
130 | 130 | void BarPresenterBase::handleModelChanged(int index) |
|
131 | 131 | { |
|
132 | // qDebug() << "BarPresenterBase::handleModelChanged" << index; | |
|
132 | Q_UNUSED(index) | |
|
133 | 133 | dataChanged(); |
|
134 | 134 | } |
|
135 | 135 | |
|
136 |
void BarPresenterBase::handleDomainChanged( |
|
|
136 | void BarPresenterBase::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY) | |
|
137 | 137 | { |
|
138 | qDebug() << "BarPresenterBase::handleDomainChanged"; | |
|
138 | // TODO: | |
|
139 | Q_UNUSED(minX) | |
|
140 | Q_UNUSED(maxX) | |
|
141 | Q_UNUSED(minY) | |
|
142 | Q_UNUSED(maxY) | |
|
143 | ||
|
139 | 144 | /* |
|
140 | 145 | int count = mSeries->categoryCount(); |
|
141 | 146 | if (0 == count) { |
|
142 | 147 | return; |
|
143 | 148 | } |
|
144 | 149 | |
|
145 | 150 | // Position labels to domain |
|
146 | 151 | qreal min = domain.minX(); |
|
147 | 152 | qreal max = domain.maxX(); |
|
148 | 153 | qreal step = (max-min)/count; |
|
149 | 154 | QChartAxisCategories& categories = mChart->axisX()->categories(); |
|
150 | 155 | categories.clear(); |
|
151 | 156 | for (int i=0; i<count; i++) { |
|
152 | 157 | categories.insert(min,mSeries->categoryName(i)); |
|
153 | 158 | min += step; |
|
154 | 159 | } |
|
155 | 160 | */ |
|
156 | 161 | } |
|
157 | 162 | |
|
158 | 163 | void BarPresenterBase::handleGeometryChanged(const QRectF& rect) |
|
159 | 164 | { |
|
160 | 165 | mWidth = rect.width(); |
|
161 | 166 | mHeight = rect.height(); |
|
162 | 167 | layoutChanged(); |
|
163 | 168 | mLayoutSet = true; |
|
164 | 169 | setPos(rect.topLeft()); |
|
165 | 170 | } |
|
166 | 171 | |
|
167 | 172 | void BarPresenterBase::showToolTip(QPoint pos, QString tip) |
|
168 | 173 | { |
|
169 | 174 | // TODO: cool tooltip instead of default |
|
170 | 175 | QToolTip::showText(pos,tip); |
|
171 | 176 | } |
|
172 | 177 | |
|
173 | 178 | /* |
|
174 | 179 | void BarPresenterBase::enableSeparators(bool enabled) |
|
175 | 180 | { |
|
176 | 181 | for (int i=0; i<mSeparators.count(); i++) { |
|
177 | 182 | mSeparators.at(i)->setVisible(enabled); |
|
178 | 183 | } |
|
179 | 184 | } |
|
180 | 185 | */ |
|
181 | 186 | |
|
182 | 187 | #include "moc_barpresenterbase_p.cpp" |
|
183 | 188 | |
|
184 | 189 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,67 +1,67 | |||
|
1 | 1 | #ifndef BARPRESENTERBASE_H |
|
2 | 2 | #define BARPRESENTERBASE_H |
|
3 | 3 | |
|
4 | 4 | #include "chartitem_p.h" |
|
5 | 5 | #include "qbarseries.h" |
|
6 | 6 | #include <QPen> |
|
7 | 7 | #include <QBrush> |
|
8 | 8 | #include <QGraphicsItem> |
|
9 | 9 | |
|
10 | 10 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
11 | 11 | |
|
12 | 12 | class Bar; |
|
13 | 13 | class Separator; |
|
14 | 14 | class BarValue; |
|
15 | 15 | class QChartAxisCategories; |
|
16 | 16 | class QChart; |
|
17 | 17 | |
|
18 | 18 | // Common implemantation of different presenters. Not to be instantiated. |
|
19 | 19 | // TODO: combine this with BarPresenter and derive other presenters from it? |
|
20 | 20 | class BarPresenterBase : public QObject, public ChartItem |
|
21 | 21 | { |
|
22 | 22 | Q_OBJECT |
|
23 | 23 | public: |
|
24 | 24 | BarPresenterBase(QBarSeries *series, QChart *parent = 0); |
|
25 | 25 | virtual ~BarPresenterBase(); |
|
26 | 26 | |
|
27 | 27 | public: |
|
28 | 28 | // From QGraphicsItem |
|
29 | 29 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); |
|
30 | 30 | QRectF boundingRect() const; |
|
31 | 31 | |
|
32 | 32 | // TODO: Consider the domain for layoutChanged. May be use case, may not be. If it is, then the derived classes need to implement it |
|
33 | 33 | virtual void dataChanged(); // data of series has changed -> need to recalculate bar sizes |
|
34 | 34 | virtual void layoutChanged() = 0; // layout has changed -> need to recalculate bar sizes |
|
35 | 35 | |
|
36 | 36 | protected: |
|
37 | 37 | void initAxisLabels(); |
|
38 | 38 | |
|
39 | 39 | public slots: |
|
40 | 40 | void handleModelChanged(int index); |
|
41 |
void handleDomainChanged( |
|
|
41 | void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY); | |
|
42 | 42 | void handleGeometryChanged(const QRectF& size); |
|
43 | 43 | |
|
44 | 44 | // Internal slots |
|
45 | 45 | void showToolTip(QPoint pos, QString tip); // shows tooltip (if enabled) |
|
46 | 46 | // void enableSeparators(bool enabled); |
|
47 | 47 | |
|
48 | 48 | protected: |
|
49 | 49 | |
|
50 | 50 | // TODO: consider these. |
|
51 | 51 | int mHeight; // Layout spesific |
|
52 | 52 | int mWidth; |
|
53 | 53 | qreal mBarWidth; |
|
54 | 54 | |
|
55 | 55 | bool mLayoutSet; // True, if component has been laid out. |
|
56 | 56 | |
|
57 | 57 | // Not owned. |
|
58 | 58 | QBarSeries* mSeries; |
|
59 | 59 | QList<Bar*> mBars; |
|
60 | 60 | // QList<Separator*> mSeparators; |
|
61 | 61 | QList<BarValue*> mFloatingValues; |
|
62 | 62 | QChart* mChart; |
|
63 | 63 | }; |
|
64 | 64 | |
|
65 | 65 | QTCOMMERCIALCHART_END_NAMESPACE |
|
66 | 66 | |
|
67 | 67 | #endif // BARPRESENTERBASE_H |
@@ -1,70 +1,73 | |||
|
1 | 1 | #include "barvalue_p.h" |
|
2 | 2 | #include <QPainter> |
|
3 | 3 | #include <QPen> |
|
4 | 4 | |
|
5 | 5 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
6 | 6 | |
|
7 | 7 | BarValue::BarValue(QBarSet &set, QGraphicsItem *parent) |
|
8 | 8 | : QGraphicsObject(parent), |
|
9 | 9 | mBarSet(set), |
|
10 | 10 | mXpos(0), |
|
11 | 11 | mYpos(0), |
|
12 | 12 | mWidth(0), |
|
13 | 13 | mHeight(0) |
|
14 | 14 | { |
|
15 | 15 | setVisible(false); |
|
16 | 16 | } |
|
17 | 17 | |
|
18 | 18 | void BarValue::setValueString(QString str) |
|
19 | 19 | { |
|
20 | 20 | mValueString = str; |
|
21 | 21 | } |
|
22 | 22 | |
|
23 | 23 | QString BarValue::valueString() |
|
24 | 24 | { |
|
25 | 25 | return mValueString; |
|
26 | 26 | } |
|
27 | 27 | |
|
28 | 28 | void BarValue::setPen(const QPen pen) |
|
29 | 29 | { |
|
30 | 30 | mPen = pen; |
|
31 | 31 | } |
|
32 | 32 | |
|
33 | 33 | QPen BarValue::pen() const |
|
34 | 34 | { |
|
35 | 35 | return mPen; |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | void BarValue::resize(qreal w, qreal h) |
|
39 | 39 | { |
|
40 | 40 | mWidth = w; |
|
41 | 41 | mHeight = h; |
|
42 | 42 | } |
|
43 | 43 | |
|
44 | 44 | void BarValue::setPos(qreal x, qreal y) |
|
45 | 45 | { |
|
46 | 46 | mXpos = x; |
|
47 | 47 | mYpos = y; |
|
48 | 48 | } |
|
49 | 49 | |
|
50 | 50 | void BarValue::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
51 | 51 | { |
|
52 | Q_UNUSED(option) | |
|
53 | Q_UNUSED(widget) | |
|
54 | ||
|
52 | 55 | if (isVisible()) { |
|
53 | 56 | painter->setPen(mPen); |
|
54 | 57 | painter->drawText(boundingRect(),mValueString); |
|
55 | 58 | } |
|
56 | 59 | } |
|
57 | 60 | |
|
58 | 61 | QRectF BarValue::boundingRect() const |
|
59 | 62 | { |
|
60 | 63 | QRectF r(mXpos, mYpos, mWidth, mHeight); |
|
61 | 64 | return r; |
|
62 | 65 | } |
|
63 | 66 | |
|
64 | 67 | void BarValue::toggleVisible() |
|
65 | 68 | { |
|
66 | 69 | setVisible(!isVisible()); |
|
67 | 70 | } |
|
68 | 71 | |
|
69 | 72 | #include "moc_barvalue_p.cpp" |
|
70 | 73 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,242 +1,242 | |||
|
1 | 1 | #include <QDebug> |
|
2 | 2 | #include "qbarseries.h" |
|
3 | 3 | #include "qbarset.h" |
|
4 | 4 | #include "barchartmodel_p.h" |
|
5 | 5 | |
|
6 | 6 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
7 | 7 | |
|
8 | 8 | /*! |
|
9 | 9 | \class QBarSeries |
|
10 | 10 | \brief part of QtCommercial chart API. |
|
11 | 11 | |
|
12 | 12 | QBarSeries represents a series of data shown as bars. One QBarSeries can contain multible |
|
13 | 13 | QBarSet data sets. QBarSeries groups the data from sets to categories, which are defined |
|
14 | 14 | by QStringList. |
|
15 | 15 | |
|
16 | 16 | \mainclass |
|
17 | 17 | |
|
18 | 18 | \sa QBarSet, QStackedBarSeries, QPercentBarSeries |
|
19 | 19 | */ |
|
20 | 20 | |
|
21 | 21 | /*! |
|
22 | 22 | \fn virtual QSeriesType QBarSeries::type() const |
|
23 | 23 | \brief Returns type of series. |
|
24 | 24 | \sa QSeries, QSeriesType |
|
25 | 25 | */ |
|
26 | 26 | |
|
27 | 27 | /*! |
|
28 | 28 | \fn void QBarSeries::showToolTip(QPoint pos, QString tip) |
|
29 | 29 | \brief \internal \a pos \a tip |
|
30 | 30 | */ |
|
31 | 31 | |
|
32 | 32 | /*! |
|
33 | 33 | Constructs empty QBarSeries. Parameter \a categories defines the categories for chart. |
|
34 | 34 | QBarSeries is QObject which is a child of a \a parent. |
|
35 | 35 | */ |
|
36 | 36 | QBarSeries::QBarSeries(QStringList categories, QObject *parent) |
|
37 | 37 | : QSeries(parent) |
|
38 | 38 | ,mModel(new BarChartModel(categories, this)) |
|
39 | 39 | { |
|
40 | 40 | m_model = NULL; |
|
41 | 41 | m_mapCategories = -1; |
|
42 | 42 | m_mapBarBottom = -1; |
|
43 | 43 | m_mapBarTop = -1; |
|
44 | 44 | } |
|
45 | 45 | |
|
46 | 46 | /*! |
|
47 | 47 | Adds a set of bars to series. Takes ownership of \a set. |
|
48 | 48 | Connects the clicked(QString) and rightClicked(QString) signals |
|
49 | 49 | of \a set to this series |
|
50 | 50 | */ |
|
51 | 51 | void QBarSeries::addBarSet(QBarSet *set) |
|
52 | 52 | { |
|
53 | 53 | mModel->addBarSet(set); |
|
54 | 54 | connect(set,SIGNAL(clicked(QString)),this,SLOT(barsetClicked(QString))); |
|
55 | 55 | connect(set,SIGNAL(rightClicked(QString)),this,SLOT(barsetRightClicked(QString))); |
|
56 | 56 | } |
|
57 | 57 | |
|
58 | 58 | /*! |
|
59 | 59 | Removes a set of bars from series. Releases ownership of \a set. Doesnt delete \a set. |
|
60 | 60 | Disconnects the clicked(QString) and rightClicked(QString) signals |
|
61 | 61 | of \a set from this series |
|
62 | 62 | */ |
|
63 | 63 | void QBarSeries::removeBarSet(QBarSet *set) |
|
64 | 64 | { |
|
65 | 65 | disconnect(set,SIGNAL(clicked(QString)),this,SLOT(barsetClicked(QString))); |
|
66 | 66 | disconnect(set,SIGNAL(rightClicked(QString)),this,SLOT(barsetRightClicked(QString))); |
|
67 | 67 | mModel->removeBarSet(set); |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | 70 | /*! |
|
71 | 71 | Returns number of sets in series. |
|
72 | 72 | */ |
|
73 | 73 | int QBarSeries::barsetCount() |
|
74 | 74 | { |
|
75 | 75 | if(m_model) |
|
76 | 76 | return m_mapBarTop - m_mapBarBottom; |
|
77 | 77 | else |
|
78 | 78 | return mModel->barsetCount(); |
|
79 | 79 | } |
|
80 | 80 | |
|
81 | 81 | /*! |
|
82 | 82 | Returns number of categories in series |
|
83 | 83 | */ |
|
84 | 84 | int QBarSeries::categoryCount() |
|
85 | 85 | { |
|
86 | 86 | return mModel->categoryCount(); |
|
87 | 87 | } |
|
88 | 88 | |
|
89 | 89 | /*! |
|
90 | 90 | Returns a list of sets in series. Keeps ownership of sets. |
|
91 | 91 | */ |
|
92 | 92 | QList<QBarSet*> QBarSeries::barSets() |
|
93 | 93 | { |
|
94 | 94 | return mModel->barSets(); |
|
95 | 95 | } |
|
96 | 96 | |
|
97 | 97 | /*! |
|
98 | 98 | \internal \a index |
|
99 | 99 | */ |
|
100 | 100 | QBarSet* QBarSeries::barsetAt(int index) |
|
101 | 101 | { |
|
102 | 102 | return mModel->setAt(index); |
|
103 | 103 | } |
|
104 | 104 | |
|
105 | 105 | /*! |
|
106 | 106 | \internal \a category |
|
107 | 107 | */ |
|
108 | 108 | QString QBarSeries::categoryName(int category) |
|
109 | 109 | { |
|
110 | 110 | return mModel->categoryName(category); |
|
111 | 111 | } |
|
112 | 112 | |
|
113 | 113 | /*! |
|
114 | 114 | Enables or disables tooltip depending on parameter \a enabled. |
|
115 | 115 | Tooltip shows the name of set, when mouse is hovering on top of bar. |
|
116 | 116 | Calling without parameter \a enabled, enables the tooltip |
|
117 | 117 | */ |
|
118 | 118 | void QBarSeries::setToolTipEnabled(bool enabled) |
|
119 | 119 | { |
|
120 | 120 | // TODO: what if we add sets after call to this function? Those sets won't have tooltip enabled. |
|
121 | 121 | if (enabled) { |
|
122 | 122 | for (int i=0; i<mModel->barsetCount(); i++) { |
|
123 | 123 | QBarSet *set = mModel->setAt(i); |
|
124 | 124 | connect(set,SIGNAL(showToolTip(QPoint,QString)),this,SIGNAL(showToolTip(QPoint,QString))); |
|
125 | 125 | } |
|
126 | 126 | } else { |
|
127 | 127 | for (int i=0; i<mModel->barsetCount(); i++) { |
|
128 | 128 | QBarSet *set = mModel->setAt(i); |
|
129 | 129 | disconnect(set,SIGNAL(showToolTip(QPoint,QString)),this,SIGNAL(showToolTip(QPoint,QString))); |
|
130 | 130 | } |
|
131 | 131 | } |
|
132 | 132 | } |
|
133 | 133 | |
|
134 | 134 | /*! |
|
135 | 135 | Enables or disables separators depending on parameter \a enabled. |
|
136 | 136 | Separators are visual elements that are drawn between categories. |
|
137 | 137 | Calling without parameter \a enabled, enables the separators |
|
138 | 138 | */ |
|
139 | 139 | void QBarSeries::setSeparatorsVisible(bool visible) |
|
140 | 140 | { |
|
141 | 141 | mSeparatorsVisible = visible; |
|
142 | 142 | emit enableSeparators(visible); |
|
143 | 143 | } |
|
144 | 144 | |
|
145 | 145 | |
|
146 | 146 | /*! |
|
147 | 147 | \internal \a category |
|
148 | 148 | */ |
|
149 | 149 | void QBarSeries::barsetClicked(QString category) |
|
150 | 150 | { |
|
151 | 151 | emit clicked(qobject_cast<QBarSet*>(sender()), category); |
|
152 | 152 | } |
|
153 | 153 | |
|
154 | 154 | /*! |
|
155 | 155 | \internal \a category |
|
156 | 156 | */ |
|
157 | 157 | void QBarSeries::barsetRightClicked(QString category) |
|
158 | 158 | { |
|
159 | 159 | emit rightClicked(qobject_cast<QBarSet*>(sender()), category); |
|
160 | 160 | } |
|
161 | 161 | |
|
162 | 162 | |
|
163 | 163 | /*! |
|
164 | 164 | \internal |
|
165 | 165 | */ |
|
166 | 166 | qreal QBarSeries::min() |
|
167 | 167 | { |
|
168 | 168 | return mModel->min(); |
|
169 | 169 | } |
|
170 | 170 | |
|
171 | 171 | /*! |
|
172 | 172 | \internal |
|
173 | 173 | */ |
|
174 | 174 | qreal QBarSeries::max() |
|
175 | 175 | { |
|
176 | 176 | return mModel->max(); |
|
177 | 177 | } |
|
178 | 178 | |
|
179 | 179 | /*! |
|
180 | 180 | \internal \a set \a category |
|
181 | 181 | */ |
|
182 | 182 | qreal QBarSeries::valueAt(int set, int category) |
|
183 | 183 | { |
|
184 | 184 | return mModel->valueAt(set,category); |
|
185 | 185 | } |
|
186 | 186 | |
|
187 | 187 | /*! |
|
188 | 188 | \internal \a set \a category |
|
189 | 189 | */ |
|
190 | 190 | qreal QBarSeries::percentageAt(int set, int category) |
|
191 | 191 | { |
|
192 | 192 | return mModel->percentageAt(set,category); |
|
193 | 193 | } |
|
194 | 194 | |
|
195 | 195 | /*! |
|
196 | 196 | \internal \a category |
|
197 | 197 | */ |
|
198 | 198 | qreal QBarSeries::categorySum(int category) |
|
199 | 199 | { |
|
200 | 200 | return mModel->categorySum(category); |
|
201 | 201 | } |
|
202 | 202 | |
|
203 | 203 | /*! |
|
204 | 204 | \internal |
|
205 | 205 | */ |
|
206 | 206 | qreal QBarSeries::maxCategorySum() |
|
207 | 207 | { |
|
208 | 208 | return mModel->maxCategorySum(); |
|
209 | 209 | } |
|
210 | 210 | |
|
211 | 211 | /*! |
|
212 | 212 | \internal |
|
213 | 213 | */ |
|
214 | 214 | BarChartModel& QBarSeries::model() |
|
215 | 215 | { |
|
216 | 216 | return *mModel; |
|
217 | 217 | } |
|
218 | 218 | |
|
219 | 219 | bool QBarSeries::separatorsVisible() |
|
220 | 220 | { |
|
221 | 221 | return mSeparatorsVisible; |
|
222 | 222 | } |
|
223 | 223 | |
|
224 | 224 | bool QBarSeries::setModel(QAbstractItemModel* model) |
|
225 | 225 | { |
|
226 | 226 | m_model = model; |
|
227 | 227 | return true; |
|
228 | 228 | } |
|
229 | 229 | |
|
230 | void QBarSeries::setModelMappingCategories(int modelColumn) | |
|
230 | // TODO | |
|
231 | void QBarSeries::setModelMappingCategories(int /*modelColumn*/) | |
|
231 | 232 | { |
|
232 | // | |
|
233 | 233 | } |
|
234 | 234 | |
|
235 | void QBarSeries::setModelMappingBarRange(int bottomBoundry, int topBoundry) | |
|
235 | // TODO | |
|
236 | void QBarSeries::setModelMappingBarRange(int /*bottomBoundry*/, int /*topBoundry*/) | |
|
236 | 237 | { |
|
237 | // | |
|
238 | 238 | } |
|
239 | 239 | |
|
240 | 240 | #include "moc_qbarseries.cpp" |
|
241 | 241 | |
|
242 | 242 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,45 +1,48 | |||
|
1 | 1 | #include "separator_p.h" |
|
2 | 2 | #include <QDebug> |
|
3 | 3 | #include <QPainter> |
|
4 | 4 | |
|
5 | 5 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
6 | 6 | |
|
7 | 7 | Separator::Separator(QGraphicsItem *parent) |
|
8 | 8 | : ChartItem(parent) |
|
9 | 9 | { |
|
10 | 10 | } |
|
11 | 11 | |
|
12 | 12 | void Separator::setPos(qreal x, qreal y) |
|
13 | 13 | { |
|
14 | 14 | mXpos = x; |
|
15 | 15 | mYpos = y; |
|
16 | 16 | } |
|
17 | 17 | |
|
18 | 18 | void Separator::setColor(QColor color) |
|
19 | 19 | { |
|
20 | 20 | mColor = color; |
|
21 | 21 | } |
|
22 | 22 | |
|
23 | 23 | void Separator::setSize(const QSizeF &size) |
|
24 | 24 | { |
|
25 | 25 | mWidth = size.width(); |
|
26 | 26 | mHeight = size.height(); |
|
27 | 27 | } |
|
28 | 28 | |
|
29 | 29 | void Separator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
30 | 30 | { |
|
31 | Q_UNUSED(option) | |
|
32 | Q_UNUSED(widget) | |
|
33 | ||
|
31 | 34 | if (isVisible()) { |
|
32 | 35 | QPen pen(mColor); |
|
33 | 36 | painter->setPen(pen); |
|
34 | 37 | painter->drawLine(mXpos,mYpos,mXpos,mHeight); |
|
35 | 38 | } |
|
36 | 39 | } |
|
37 | 40 | |
|
38 | 41 | QRectF Separator::boundingRect() const |
|
39 | 42 | { |
|
40 | 43 | QRectF r(mXpos,mYpos,mWidth,mHeight); |
|
41 | 44 | return r; |
|
42 | 45 | } |
|
43 | 46 | |
|
44 | 47 | |
|
45 | 48 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,401 +1,401 | |||
|
1 | 1 | #include "qchart.h" |
|
2 | 2 | #include "qchartaxis.h" |
|
3 | 3 | #include "chartpresenter_p.h" |
|
4 | 4 | #include "chartdataset_p.h" |
|
5 | 5 | #include "charttheme_p.h" |
|
6 | 6 | #include "chartanimator_p.h" |
|
7 | 7 | //series |
|
8 | 8 | #include "qbarseries.h" |
|
9 | 9 | #include "qstackedbarseries.h" |
|
10 | 10 | #include "qpercentbarseries.h" |
|
11 | 11 | #include "qlineseries.h" |
|
12 | 12 | #include "qareaseries.h" |
|
13 | 13 | #include "qpieseries.h" |
|
14 | 14 | #include "qscatterseries.h" |
|
15 | 15 | #include "qsplineseries.h" |
|
16 | 16 | //items |
|
17 | 17 | #include "axisitem_p.h" |
|
18 | 18 | #include "areachartitem_p.h" |
|
19 | 19 | #include "barpresenter_p.h" |
|
20 | 20 | #include "stackedbarpresenter_p.h" |
|
21 | 21 | #include "percentbarpresenter_p.h" |
|
22 | 22 | #include "linechartitem_p.h" |
|
23 | 23 | #include "piechartitem_p.h" |
|
24 | 24 | #include "scatterchartitem_p.h" |
|
25 | 25 | #include "splinechartitem_p.h" |
|
26 | 26 | |
|
27 | 27 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
28 | 28 | |
|
29 | 29 | ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart), |
|
30 | 30 | m_chart(chart), |
|
31 | 31 | m_animator(0), |
|
32 | 32 | m_dataset(dataset), |
|
33 | 33 | m_chartTheme(0), |
|
34 | 34 | m_zoomIndex(0), |
|
35 | 35 | m_marginSize(0), |
|
36 | 36 | m_rect(QRectF(QPoint(0,0),m_chart->size())), |
|
37 | 37 | m_options(QChart::NoAnimation) |
|
38 | 38 | { |
|
39 | 39 | createConnections(); |
|
40 | 40 | setChartTheme(QChart::ChartThemeDefault); |
|
41 | 41 | } |
|
42 | 42 | |
|
43 | 43 | ChartPresenter::~ChartPresenter() |
|
44 | 44 | { |
|
45 | 45 | delete m_chartTheme; |
|
46 | 46 | } |
|
47 | 47 | |
|
48 | 48 | void ChartPresenter::createConnections() |
|
49 | 49 | { |
|
50 | 50 | QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged())); |
|
51 | 51 | QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),this,SLOT(handleSeriesAdded(QSeries*,Domain*))); |
|
52 | 52 | QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*))); |
|
53 | 53 | QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*,Domain*)),this,SLOT(handleAxisAdded(QChartAxis*,Domain*))); |
|
54 | 54 | QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*))); |
|
55 | 55 | } |
|
56 | 56 | |
|
57 | 57 | |
|
58 | 58 | QRectF ChartPresenter::geometry() const |
|
59 | 59 | { |
|
60 | 60 | return m_rect; |
|
61 | 61 | } |
|
62 | 62 | |
|
63 | 63 | void ChartPresenter::handleGeometryChanged() |
|
64 | 64 | { |
|
65 | 65 | QRectF rect(QPoint(0,0),m_chart->size()); |
|
66 | 66 | rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize); |
|
67 | 67 | |
|
68 | 68 | //rewrite zoom stack |
|
69 | 69 | for(int i=0;i<m_zoomStack.count();i++){ |
|
70 | 70 | QRectF r = m_zoomStack[i]; |
|
71 | 71 | qreal w = rect.width()/m_rect.width(); |
|
72 | 72 | qreal h = rect.height()/m_rect.height(); |
|
73 | 73 | QPointF tl = r.topLeft(); |
|
74 | 74 | tl.setX(tl.x()*w); |
|
75 | 75 | tl.setY(tl.y()*h); |
|
76 | 76 | QPointF br = r.bottomRight(); |
|
77 | 77 | br.setX(br.x()*w); |
|
78 | 78 | br.setY(br.y()*h); |
|
79 | 79 | r.setTopLeft(tl); |
|
80 | 80 | r.setBottomRight(br); |
|
81 | 81 | m_zoomStack[i]=r; |
|
82 | 82 | } |
|
83 | 83 | |
|
84 | 84 | m_rect = rect; |
|
85 | 85 | Q_ASSERT(m_rect.isValid()); |
|
86 | 86 | emit geometryChanged(m_rect); |
|
87 | 87 | } |
|
88 | 88 | |
|
89 | 89 | int ChartPresenter::margin() const |
|
90 | 90 | { |
|
91 | 91 | return m_marginSize; |
|
92 | 92 | } |
|
93 | 93 | |
|
94 | 94 | void ChartPresenter::setMargin(int margin) |
|
95 | 95 | { |
|
96 | 96 | m_marginSize = margin; |
|
97 | 97 | } |
|
98 | 98 | |
|
99 | 99 | void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain) |
|
100 | 100 | { |
|
101 | 101 | AxisItem* item = new AxisItem(axis,this,axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart); |
|
102 | 102 | |
|
103 | 103 | if(m_options.testFlag(QChart::GridAxisAnimations)){ |
|
104 | 104 | m_animator->addAnimation(item); |
|
105 | 105 | } |
|
106 | 106 | |
|
107 | 107 | if(axis==m_dataset->axisX()){ |
|
108 | 108 | m_chartTheme->decorate(axis,true); |
|
109 | 109 | QObject::connect(domain,SIGNAL(rangeXChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int))); |
|
110 | 110 | //initialize |
|
111 | 111 | item->handleRangeChanged(domain->minX(),domain->maxX(),domain->tickXCount()); |
|
112 | 112 | |
|
113 | 113 | } |
|
114 | 114 | else{ |
|
115 | 115 | m_chartTheme->decorate(axis,false); |
|
116 | 116 | QObject::connect(domain,SIGNAL(rangeYChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int))); |
|
117 | 117 | //initialize |
|
118 | 118 | item->handleRangeChanged(domain->minY(),domain->maxY(),domain->tickYCount()); |
|
119 | 119 | } |
|
120 | 120 | |
|
121 | 121 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&))); |
|
122 | 122 | //initialize |
|
123 | 123 | item->handleGeometryChanged(m_rect); |
|
124 | 124 | m_axisItems.insert(axis, item); |
|
125 | 125 | } |
|
126 | 126 | |
|
127 | 127 | void ChartPresenter::handleAxisRemoved(QChartAxis* axis) |
|
128 | 128 | { |
|
129 | 129 | AxisItem* item = m_axisItems.take(axis); |
|
130 | 130 | Q_ASSERT(item); |
|
131 | 131 | if(m_animator) m_animator->removeAnimation(item); |
|
132 | 132 | delete item; |
|
133 | 133 | } |
|
134 | 134 | |
|
135 | 135 | |
|
136 | 136 | void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain) |
|
137 | 137 | { |
|
138 | 138 | ChartItem *item = 0 ; |
|
139 | 139 | |
|
140 | 140 | switch(series->type()) |
|
141 | 141 | { |
|
142 | 142 | case QSeries::SeriesTypeLine: { |
|
143 | 143 | |
|
144 | 144 | QLineSeries* lineSeries = static_cast<QLineSeries*>(series); |
|
145 | 145 | LineChartItem* line = new LineChartItem(lineSeries,m_chart); |
|
146 | 146 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
147 | 147 | m_animator->addAnimation(line); |
|
148 | 148 | } |
|
149 | 149 | m_chartTheme->decorate(lineSeries, m_dataset->seriesIndex(series)); |
|
150 | 150 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),line,SLOT(handleGeometryChanged(const QRectF&))); |
|
151 | 151 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),line,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
152 | 152 | item = line; |
|
153 | 153 | break; |
|
154 | 154 | } |
|
155 | 155 | |
|
156 | 156 | case QSeries::SeriesTypeArea: { |
|
157 | 157 | |
|
158 | 158 | QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series); |
|
159 | 159 | AreaChartItem* area = new AreaChartItem(areaSeries,m_chart); |
|
160 | 160 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
161 | 161 | m_animator->addAnimation(area->upperLineItem()); |
|
162 | 162 | if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem()); |
|
163 | 163 | } |
|
164 | 164 | m_chartTheme->decorate(areaSeries, m_dataset->seriesIndex(series)); |
|
165 | 165 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),area,SLOT(handleGeometryChanged(const QRectF&))); |
|
166 | 166 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),area,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
167 | 167 | item=area; |
|
168 | 168 | break; |
|
169 | 169 | } |
|
170 | 170 | |
|
171 | 171 | case QSeries::SeriesTypeBar: { |
|
172 | 172 | QBarSeries* barSeries = static_cast<QBarSeries*>(series); |
|
173 | 173 | BarPresenter* bar = new BarPresenter(barSeries,m_chart); |
|
174 | 174 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
175 | 175 | // m_animator->addAnimation(bar); |
|
176 | 176 | } |
|
177 |
m_chartTheme->decorate( |
|
|
177 | m_chartTheme->decorate(barSeries, m_dataset->seriesIndex(barSeries)); | |
|
178 | 178 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&))); |
|
179 | 179 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
180 | 180 | item=bar; |
|
181 | 181 | break; |
|
182 | 182 | } |
|
183 | 183 | |
|
184 | 184 | case QSeries::SeriesTypeStackedBar: { |
|
185 | 185 | QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series); |
|
186 | 186 | StackedBarPresenter* bar = new StackedBarPresenter(stackedBarSeries,m_chart); |
|
187 | 187 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
188 | 188 | // m_animator->addAnimation(bar); |
|
189 | 189 | } |
|
190 |
m_chartTheme->decorate( |
|
|
190 | m_chartTheme->decorate(stackedBarSeries, m_dataset->seriesIndex(stackedBarSeries)); | |
|
191 | 191 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&))); |
|
192 | 192 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
193 | 193 | item=bar; |
|
194 | 194 | break; |
|
195 | 195 | } |
|
196 | 196 | |
|
197 | 197 | case QSeries::SeriesTypePercentBar: { |
|
198 | 198 | QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series); |
|
199 | 199 | PercentBarPresenter* bar = new PercentBarPresenter(percentBarSeries,m_chart); |
|
200 | 200 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
201 | 201 | // m_animator->addAnimation(bar); |
|
202 | 202 | } |
|
203 |
m_chartTheme->decorate( |
|
|
203 | m_chartTheme->decorate(percentBarSeries, m_dataset->seriesIndex(percentBarSeries)); | |
|
204 | 204 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&))); |
|
205 | 205 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
206 | 206 | item=bar; |
|
207 | 207 | break; |
|
208 | 208 | } |
|
209 | 209 | |
|
210 | 210 | case QSeries::SeriesTypeScatter: { |
|
211 | 211 | QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series); |
|
212 | 212 | ScatterChartItem *scatter = new ScatterChartItem(scatterSeries, m_chart); |
|
213 | 213 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
214 | 214 | m_animator->addAnimation(scatter); |
|
215 | 215 | } |
|
216 | 216 | m_chartTheme->decorate(scatterSeries, m_dataset->seriesIndex(series)); |
|
217 | 217 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),scatter,SLOT(handleGeometryChanged(const QRectF&))); |
|
218 | 218 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),scatter,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
219 | 219 | item = scatter; |
|
220 | 220 | break; |
|
221 | 221 | } |
|
222 | 222 | |
|
223 | 223 | case QSeries::SeriesTypePie: { |
|
224 | 224 | QPieSeries *pieSeries = static_cast<QPieSeries *>(series); |
|
225 | 225 | PieChartItem* pie = new PieChartItem(m_chart, pieSeries); |
|
226 | 226 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
227 | 227 | // m_animator->addAnimation(pie); |
|
228 | 228 | } |
|
229 |
m_chartTheme->decorate( |
|
|
229 | m_chartTheme->decorate(pieSeries, m_dataset->seriesIndex(series)); | |
|
230 | 230 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&))); |
|
231 | 231 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),pie,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
232 | 232 | // Hide all from background when there is only piechart |
|
233 | 233 | // TODO: refactor this ugly code... should be one setting for this |
|
234 | 234 | if (m_chartItems.count() == 0) { |
|
235 | 235 | m_chart->axisX()->hide(); |
|
236 | 236 | m_chart->axisY()->hide(); |
|
237 | 237 | m_chart->setChartBackgroundBrush(Qt::transparent); |
|
238 | 238 | } |
|
239 | 239 | item=pie; |
|
240 | 240 | break; |
|
241 | 241 | } |
|
242 | 242 | |
|
243 | 243 | case QSeries::SeriesTypeSpline: { |
|
244 | 244 | QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series); |
|
245 | 245 | SplineChartItem* spline = new SplineChartItem(splineSeries, m_chart); |
|
246 | 246 | if(m_options.testFlag(QChart::SeriesAnimations)) { |
|
247 | 247 | m_animator->addAnimation(spline); |
|
248 | 248 | } |
|
249 | 249 | m_chartTheme->decorate(splineSeries, m_dataset->seriesIndex(series)); |
|
250 | 250 | QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),spline,SLOT(handleGeometryChanged(const QRectF&))); |
|
251 | 251 | QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),spline,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); |
|
252 | 252 | item=spline; |
|
253 | 253 | break; |
|
254 | 254 | } |
|
255 | 255 | default: { |
|
256 | 256 | qDebug()<< "Series type" << series->type() << "not implemented."; |
|
257 | 257 | break; |
|
258 | 258 | } |
|
259 | 259 | } |
|
260 | 260 | |
|
261 | 261 | //initialize |
|
262 | 262 | item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY()); |
|
263 | 263 | if(m_rect.isValid()) item->handleGeometryChanged(m_rect); |
|
264 | 264 | m_chartItems.insert(series,item); |
|
265 | 265 | zoomReset(); |
|
266 | 266 | } |
|
267 | 267 | |
|
268 | 268 | void ChartPresenter::handleSeriesRemoved(QSeries* series) |
|
269 | 269 | { |
|
270 | 270 | ChartItem* item = m_chartItems.take(series); |
|
271 | 271 | Q_ASSERT(item); |
|
272 | 272 | if(m_animator) { |
|
273 | 273 | //small hack to handle area animations |
|
274 | 274 | if(series->type()==QSeries::SeriesTypeArea){ |
|
275 | 275 | QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series); |
|
276 | 276 | AreaChartItem* area = static_cast<AreaChartItem*>(item); |
|
277 | 277 | m_animator->removeAnimation(area->upperLineItem()); |
|
278 | 278 | if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem()); |
|
279 | 279 | }else |
|
280 | 280 | m_animator->removeAnimation(item); |
|
281 | 281 | } |
|
282 | 282 | delete item; |
|
283 | 283 | } |
|
284 | 284 | |
|
285 | 285 | void ChartPresenter::setChartTheme(QChart::ChartTheme theme) |
|
286 | 286 | { |
|
287 | 287 | if(m_chartTheme && m_chartTheme->id() == theme) return; |
|
288 | 288 | delete m_chartTheme; |
|
289 | 289 | m_chartTheme = ChartTheme::createTheme(theme); |
|
290 | 290 | m_chartTheme->decorate(m_chart); |
|
291 | 291 | m_chartTheme->decorate(m_chart->legend()); |
|
292 | 292 | resetAllElements(); |
|
293 | 293 | } |
|
294 | 294 | |
|
295 | 295 | QChart::ChartTheme ChartPresenter::chartTheme() |
|
296 | 296 | { |
|
297 | 297 | return m_chartTheme->id(); |
|
298 | 298 | } |
|
299 | 299 | |
|
300 | 300 | void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options) |
|
301 | 301 | { |
|
302 | 302 | if(m_options!=options) { |
|
303 | 303 | |
|
304 | 304 | m_options=options; |
|
305 | 305 | |
|
306 | 306 | if(m_options!=QChart::NoAnimation && !m_animator) { |
|
307 | 307 | m_animator= new ChartAnimator(this); |
|
308 | 308 | |
|
309 | 309 | } |
|
310 | 310 | resetAllElements(); |
|
311 | 311 | } |
|
312 | 312 | |
|
313 | 313 | } |
|
314 | 314 | |
|
315 | 315 | void ChartPresenter::resetAllElements() |
|
316 | 316 | { |
|
317 | 317 | QList<QChartAxis*> axisList = m_axisItems.uniqueKeys(); |
|
318 | 318 | QList<QSeries*> seriesList = m_chartItems.uniqueKeys(); |
|
319 | 319 | |
|
320 | 320 | foreach(QChartAxis* axis, axisList) { |
|
321 | 321 | handleAxisRemoved(axis); |
|
322 | 322 | handleAxisAdded(axis,m_dataset->domain(axis)); |
|
323 | 323 | } |
|
324 | 324 | foreach(QSeries* series, seriesList) { |
|
325 | 325 | handleSeriesRemoved(series); |
|
326 | 326 | handleSeriesAdded(series,m_dataset->domain(series)); |
|
327 | 327 | } |
|
328 | 328 | } |
|
329 | 329 | |
|
330 | 330 | void ChartPresenter::zoomIn() |
|
331 | 331 | { |
|
332 | 332 | QRectF rect = geometry(); |
|
333 | 333 | rect.setWidth(rect.width()/2); |
|
334 | 334 | rect.setHeight(rect.height()/2); |
|
335 | 335 | rect.moveCenter(geometry().center()); |
|
336 | 336 | zoomIn(rect); |
|
337 | 337 | } |
|
338 | 338 | |
|
339 | 339 | void ChartPresenter::zoomIn(const QRectF& rect) |
|
340 | 340 | { |
|
341 | 341 | QRectF r = rect.normalized(); |
|
342 | 342 | r.translate(-m_marginSize, -m_marginSize); |
|
343 | 343 | if(m_animator) { |
|
344 | 344 | |
|
345 | 345 | QPointF point(r.center().x()/geometry().width(),r.center().y()/geometry().height()); |
|
346 | 346 | m_animator->setState(ChartAnimator::ZoomInState,point); |
|
347 | 347 | } |
|
348 | 348 | m_dataset->zoomInDomain(r,geometry().size()); |
|
349 | 349 | m_zoomStack<<r; |
|
350 | 350 | m_zoomIndex++; |
|
351 | 351 | if(m_animator) { |
|
352 | 352 | m_animator->setState(ChartAnimator::ShowState); |
|
353 | 353 | } |
|
354 | 354 | } |
|
355 | 355 | |
|
356 | 356 | void ChartPresenter::zoomOut() |
|
357 | 357 | { |
|
358 | 358 | if(m_zoomIndex==0) return; |
|
359 | 359 | if(m_animator) |
|
360 | 360 | { |
|
361 | 361 | m_animator->setState(ChartAnimator::ZoomOutState); |
|
362 | 362 | } |
|
363 | 363 | m_dataset->zoomOutDomain(m_zoomStack[m_zoomIndex-1],geometry().size()); |
|
364 | 364 | m_zoomIndex--; |
|
365 | 365 | m_zoomStack.resize(m_zoomIndex); |
|
366 | 366 | if(m_animator){ |
|
367 | 367 | m_animator->setState(ChartAnimator::ShowState); |
|
368 | 368 | } |
|
369 | 369 | } |
|
370 | 370 | |
|
371 | 371 | void ChartPresenter::zoomReset() |
|
372 | 372 | { |
|
373 | 373 | m_zoomIndex=0; |
|
374 | 374 | m_zoomStack.resize(m_zoomIndex); |
|
375 | 375 | } |
|
376 | 376 | |
|
377 | 377 | void ChartPresenter::scroll(int dx,int dy) |
|
378 | 378 | { |
|
379 | 379 | if(m_animator){ |
|
380 | 380 | if(dx<0) m_animator->setState(ChartAnimator::ScrollLeftState,QPointF()); |
|
381 | 381 | if(dx>0) m_animator->setState(ChartAnimator::ScrollRightState,QPointF()); |
|
382 | 382 | if(dy<0) m_animator->setState(ChartAnimator::ScrollUpState,QPointF()); |
|
383 | 383 | if(dy>0) m_animator->setState(ChartAnimator::ScrollDownState,QPointF()); |
|
384 | 384 | } |
|
385 | 385 | |
|
386 | 386 | m_dataset->scrollDomain(dx,dy,geometry().size()); |
|
387 | 387 | |
|
388 | 388 | if(m_animator){ |
|
389 | 389 | m_animator->setState(ChartAnimator::ShowState); |
|
390 | 390 | } |
|
391 | 391 | } |
|
392 | 392 | |
|
393 | 393 | QChart::AnimationOptions ChartPresenter::animationOptions() const |
|
394 | 394 | { |
|
395 | 395 | return m_options; |
|
396 | 396 | } |
|
397 | 397 | |
|
398 | 398 | |
|
399 | 399 | #include "moc_chartpresenter_p.cpp" |
|
400 | 400 | |
|
401 | 401 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,314 +1,314 | |||
|
1 | 1 | #include "charttheme_p.h" |
|
2 | 2 | #include "qchart.h" |
|
3 | 3 | #include "qchartview.h" |
|
4 | 4 | #include "qlegend.h" |
|
5 | 5 | #include "qchartaxis.h" |
|
6 | 6 | #include <QTime> |
|
7 | 7 | |
|
8 | 8 | //series |
|
9 | 9 | #include "qbarset.h" |
|
10 | 10 | #include "qbarseries.h" |
|
11 | 11 | #include "qstackedbarseries.h" |
|
12 | 12 | #include "qpercentbarseries.h" |
|
13 | 13 | #include "qlineseries.h" |
|
14 | 14 | #include "qareaseries.h" |
|
15 | 15 | #include "qscatterseries.h" |
|
16 | 16 | #include "qpieseries.h" |
|
17 | 17 | #include "qpieslice.h" |
|
18 | 18 | #include "qsplineseries.h" |
|
19 | 19 | |
|
20 | 20 | //items |
|
21 | 21 | #include "axisitem_p.h" |
|
22 | 22 | #include "barpresenter_p.h" |
|
23 | 23 | #include "stackedbarpresenter_p.h" |
|
24 | 24 | #include "percentbarpresenter_p.h" |
|
25 | 25 | #include "linechartitem_p.h" |
|
26 | 26 | #include "areachartitem_p.h" |
|
27 | 27 | #include "scatterchartitem_p.h" |
|
28 | 28 | #include "piechartitem_p.h" |
|
29 | 29 | #include "splinechartitem_p.h" |
|
30 | 30 | |
|
31 | 31 | //themes |
|
32 | 32 | #include "chartthemedefault_p.h" |
|
33 | 33 | #include "chartthemevanilla_p.h" |
|
34 | 34 | #include "chartthemeicy_p.h" |
|
35 | 35 | #include "chartthemegrayscale_p.h" |
|
36 | 36 | #include "chartthemescientific_p.h" |
|
37 | 37 | #include "chartthemebluecerulean_p.h" |
|
38 | 38 | #include "chartthemelight_p.h" |
|
39 | 39 | |
|
40 | 40 | |
|
41 | 41 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
42 | 42 | |
|
43 | 43 | ChartTheme::ChartTheme(QChart::ChartTheme id) |
|
44 | 44 | { |
|
45 | 45 | m_id = id; |
|
46 | 46 | qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); |
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | |
|
50 | 50 | ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme) |
|
51 | 51 | { |
|
52 | 52 | switch(theme) { |
|
53 | 53 | case QChart::ChartThemeVanilla: |
|
54 | 54 | return new ChartThemeVanilla(); |
|
55 | 55 | case QChart::ChartThemeIcy: |
|
56 | 56 | return new ChartThemeIcy(); |
|
57 | 57 | case QChart::ChartThemeGrayscale: |
|
58 | 58 | return new ChartThemeGrayscale(); |
|
59 | 59 | case QChart::ChartThemeScientific: |
|
60 | 60 | return new ChartThemeScientific(); |
|
61 | 61 | case QChart::ChartThemeBlueCerulean: |
|
62 | 62 | return new ChartThemeBlueCerulean(); |
|
63 | 63 | case QChart::ChartThemeLight: |
|
64 | 64 | return new ChartThemeLight(); |
|
65 | 65 | default: |
|
66 | 66 | return new ChartThemeDefault(); |
|
67 | 67 | } |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | 70 | void ChartTheme::decorate(QChart* chart) |
|
71 | 71 | { |
|
72 | 72 | if (m_backgroundShades == BackgroundShadesNone) { |
|
73 | 73 | chart->setChartBackgroundBrush(m_chartBackgroundGradient); |
|
74 | 74 | } else { |
|
75 | 75 | chart->setChartBackgroundBrush(Qt::NoBrush); |
|
76 | 76 | } |
|
77 | 77 | chart->setChartTitleFont(m_masterFont); |
|
78 | 78 | } |
|
79 | 79 | |
|
80 | 80 | void ChartTheme::decorate(QLegend* legend) |
|
81 | 81 | { |
|
82 | 82 | legend->setBackgroundBrush(m_chartBackgroundGradient); |
|
83 | 83 | } |
|
84 | 84 | |
|
85 | 85 | void ChartTheme::decorate(QAreaSeries* series, int index) |
|
86 | 86 | { |
|
87 | 87 | QPen pen; |
|
88 | 88 | QBrush brush; |
|
89 | 89 | |
|
90 | 90 | if (pen == series->pen()){ |
|
91 | 91 | pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1.0)); |
|
92 | 92 | pen.setWidthF(2); |
|
93 | 93 | series->setPen(pen); |
|
94 | 94 | } |
|
95 | 95 | |
|
96 | 96 | if (brush == series->brush()) { |
|
97 | 97 | QBrush brush(m_seriesColors.at(index % m_seriesColors.size())); |
|
98 | 98 | series->setBrush(brush); |
|
99 | 99 | } |
|
100 | 100 | } |
|
101 | 101 | |
|
102 | 102 | |
|
103 | 103 | void ChartTheme::decorate(QLineSeries* series,int index) |
|
104 | 104 | { |
|
105 | 105 | QPen pen; |
|
106 | 106 | if(pen == series->pen()){ |
|
107 | 107 | pen.setColor(m_seriesColors.at(index%m_seriesColors.size())); |
|
108 | 108 | pen.setWidthF(2); |
|
109 | 109 | series->setPen(pen); |
|
110 | 110 | } |
|
111 | 111 | } |
|
112 | 112 | |
|
113 |
void ChartTheme::decorate( |
|
|
113 | void ChartTheme::decorate(QBarSeries* series,int index) | |
|
114 | 114 | { |
|
115 | 115 | QList<QBarSet*> sets = series->barSets(); |
|
116 | 116 | for (int i=0; i<sets.count(); i++) { |
|
117 | 117 | qreal pos = 0.5; |
|
118 | 118 | if (sets.count() > 1) |
|
119 | 119 | pos = (qreal) i / (qreal) (sets.count() - 1); |
|
120 | 120 | QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos); |
|
121 | 121 | sets.at(i)->setBrush(QBrush(c)); |
|
122 | 122 | |
|
123 | 123 | // Pick label color as far as possible from bar color (within gradient). |
|
124 | 124 | // 0.3 is magic number that was picked as value that gave enough contrast with icy theme gradient :) |
|
125 | 125 | // TODO: better picking of label color? |
|
126 | 126 | if (pos < 0.3) { |
|
127 | 127 | c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1); |
|
128 | 128 | } else { |
|
129 | 129 | c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0); |
|
130 | 130 | } |
|
131 | 131 | sets.at(i)->setFloatingValuePen(QPen(c)); |
|
132 | 132 | } |
|
133 | 133 | } |
|
134 | 134 | |
|
135 |
void ChartTheme::decorate( |
|
|
135 | void ChartTheme::decorate(QStackedBarSeries* series,int index) | |
|
136 | 136 | { |
|
137 | 137 | QList<QBarSet*> sets = series->barSets(); |
|
138 | 138 | for (int i=0; i<sets.count(); i++) { |
|
139 | 139 | qreal pos = 0.5; |
|
140 | 140 | if (sets.count() > 1) |
|
141 | 141 | pos = (qreal) i / (qreal) (sets.count() - 1); |
|
142 | 142 | QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos); |
|
143 | 143 | sets.at(i)->setBrush(QBrush(c)); |
|
144 | 144 | |
|
145 | 145 | if (pos < 0.3) { |
|
146 | 146 | c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1); |
|
147 | 147 | } else { |
|
148 | 148 | c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0); |
|
149 | 149 | } |
|
150 | 150 | sets.at(i)->setFloatingValuePen(QPen(c)); |
|
151 | 151 | } |
|
152 | 152 | } |
|
153 | 153 | |
|
154 |
void ChartTheme::decorate( |
|
|
154 | void ChartTheme::decorate(QPercentBarSeries* series,int index) | |
|
155 | 155 | { |
|
156 | 156 | QList<QBarSet*> sets = series->barSets(); |
|
157 | 157 | for (int i=0; i<sets.count(); i++) { |
|
158 | 158 | qreal pos = 0.5; |
|
159 | 159 | if (sets.count() > 1) |
|
160 | 160 | pos = (qreal) i / (qreal) (sets.count() - 1); |
|
161 | 161 | QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos); |
|
162 | 162 | sets.at(i)->setBrush(QBrush(c)); |
|
163 | 163 | |
|
164 | 164 | if (pos < 0.3) { |
|
165 | 165 | c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1); |
|
166 | 166 | } else { |
|
167 | 167 | c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0); |
|
168 | 168 | } |
|
169 | 169 | sets.at(i)->setFloatingValuePen(QPen(c)); |
|
170 | 170 | } |
|
171 | 171 | } |
|
172 | 172 | |
|
173 | 173 | void ChartTheme::decorate(QScatterSeries* series, int index) |
|
174 | 174 | { |
|
175 | 175 | |
|
176 | 176 | QPen pen; |
|
177 | 177 | QBrush brush; |
|
178 | 178 | |
|
179 | 179 | if (pen == series->pen()) { |
|
180 | 180 | pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1.0)); |
|
181 | 181 | pen.setWidthF(2); |
|
182 | 182 | series->setPen(pen); |
|
183 | 183 | } |
|
184 | 184 | |
|
185 | 185 | if (brush == series->brush()) { |
|
186 | 186 | QBrush brush(m_seriesColors.at(index % m_seriesColors.size())); |
|
187 | 187 | series->setBrush(brush); |
|
188 | 188 | } |
|
189 | 189 | } |
|
190 | 190 | |
|
191 |
void ChartTheme::decorate( |
|
|
191 | void ChartTheme::decorate(QPieSeries* series, int index) | |
|
192 | 192 | { |
|
193 | 193 | // Get color for a slice from a gradient linearly, beginning from the start of the gradient |
|
194 | 194 | for (int i(0); i < series->slices().count(); i++) { |
|
195 | 195 | qreal pos = (qreal) i / (qreal) series->count(); |
|
196 | 196 | QColor penColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.1); |
|
197 | 197 | series->slices().at(i)->setSlicePen(penColor); |
|
198 | 198 | QColor brushColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos); |
|
199 | 199 | series->slices().at(i)->setSliceBrush(brushColor); |
|
200 | 200 | } |
|
201 | 201 | } |
|
202 | 202 | |
|
203 | 203 | void ChartTheme::decorate(QSplineSeries* series, int index) |
|
204 | 204 | { |
|
205 | 205 | QPen pen; |
|
206 | 206 | if(pen == series->pen()){ |
|
207 | 207 | pen.setColor(m_seriesColors.at(index%m_seriesColors.size())); |
|
208 | 208 | pen.setWidthF(2); |
|
209 | 209 | series->setPen(pen); |
|
210 | 210 | } |
|
211 | 211 | } |
|
212 | 212 | |
|
213 | 213 | void ChartTheme::decorate(QChartAxis* axis,bool axisX) |
|
214 | 214 | { |
|
215 | 215 | if (axis->isAxisVisible()) { |
|
216 | 216 | axis->setLabelsBrush(m_axisLabelBrush); |
|
217 | 217 | axis->setLabelsPen(m_axisLabelPen); |
|
218 | 218 | if (m_backgroundShades == BackgroundShadesBoth |
|
219 | 219 | || (m_backgroundShades == BackgroundShadesVertical && axisX) |
|
220 | 220 | || (m_backgroundShades == BackgroundShadesHorizontal && !axisX)) { |
|
221 | 221 | axis->setShadesPen(m_backgroundShadesPen); |
|
222 | 222 | axis->setShadesBrush(m_backgroundShadesBrush); |
|
223 | 223 | } else { |
|
224 | 224 | // The shades not supposed to be shown for this axis, clear possible brush and pen |
|
225 | 225 | axis->setShadesPen(Qt::NoPen); |
|
226 | 226 | axis->setShadesBrush(Qt::NoBrush); |
|
227 | 227 | } |
|
228 | 228 | axis->setAxisPen(m_axisLinePen); |
|
229 | 229 | axis->setGridLinePen(m_gridLinePen); |
|
230 | 230 | axis->setLabelsFont(m_masterFont); |
|
231 | 231 | } |
|
232 | 232 | } |
|
233 | 233 | |
|
234 | 234 | void ChartTheme::generateSeriesGradients() |
|
235 | 235 | { |
|
236 | 236 | // Generate gradients in HSV color space |
|
237 | 237 | foreach (QColor color, m_seriesColors) { |
|
238 | 238 | QLinearGradient g; |
|
239 | 239 | qreal h = color.hsvHueF(); |
|
240 | 240 | qreal s = color.hsvSaturationF(); |
|
241 | 241 | |
|
242 | 242 | // TODO: tune the algorithm to give nice results with most base colors defined in |
|
243 | 243 | // most themes. The rest of the gradients we can define manually in theme specific |
|
244 | 244 | // implementation. |
|
245 | 245 | QColor start = color; |
|
246 | 246 | start.setHsvF(h, 0.05, 0.95); |
|
247 | 247 | g.setColorAt(0.0, start); |
|
248 | 248 | |
|
249 | 249 | g.setColorAt(0.5, color); |
|
250 | 250 | |
|
251 | 251 | QColor end = color; |
|
252 | 252 | end.setHsvF(h, s, 0.25); |
|
253 | 253 | g.setColorAt(1.0, end); |
|
254 | 254 | |
|
255 | 255 | m_seriesGradients << g; |
|
256 | 256 | } |
|
257 | 257 | } |
|
258 | 258 | |
|
259 | 259 | |
|
260 | 260 | QColor ChartTheme::colorAt(const QColor &start, const QColor &end, qreal pos) |
|
261 | 261 | { |
|
262 | 262 | Q_ASSERT(pos >=0.0 && pos <= 1.0); |
|
263 | 263 | qreal r = start.redF() + ((end.redF() - start.redF()) * pos); |
|
264 | 264 | qreal g = start.greenF() + ((end.greenF() - start.greenF()) * pos); |
|
265 | 265 | qreal b = start.blueF() + ((end.blueF() - start.blueF()) * pos); |
|
266 | 266 | QColor c; |
|
267 | 267 | c.setRgbF(r, g, b); |
|
268 | 268 | return c; |
|
269 | 269 | } |
|
270 | 270 | |
|
271 | 271 | QColor ChartTheme::colorAt(const QGradient &gradient, qreal pos) |
|
272 | 272 | { |
|
273 | 273 | Q_ASSERT(pos >=0 && pos <= 1.0); |
|
274 | 274 | |
|
275 | 275 | // another possibility: |
|
276 | 276 | // http://stackoverflow.com/questions/3306786/get-intermediate-color-from-a-gradient |
|
277 | 277 | |
|
278 | 278 | QGradientStops stops = gradient.stops(); |
|
279 | 279 | int count = stops.count(); |
|
280 | 280 | |
|
281 | 281 | // find previous stop relative to position |
|
282 | 282 | QGradientStop prev = stops.first(); |
|
283 | 283 | for (int i=0; i<count; i++) { |
|
284 | 284 | QGradientStop stop = stops.at(i); |
|
285 | 285 | if (pos > stop.first) |
|
286 | 286 | prev = stop; |
|
287 | 287 | |
|
288 | 288 | // given position is actually a stop position? |
|
289 | 289 | if (pos == stop.first) { |
|
290 | 290 | //qDebug() << "stop color" << pos; |
|
291 | 291 | return stop.second; |
|
292 | 292 | } |
|
293 | 293 | } |
|
294 | 294 | |
|
295 | 295 | // find next stop relative to position |
|
296 | 296 | QGradientStop next = stops.last(); |
|
297 | 297 | for (int i=count-1; i>=0; i--) { |
|
298 | 298 | QGradientStop stop = stops.at(i); |
|
299 | 299 | if (pos < stop.first) |
|
300 | 300 | next = stop; |
|
301 | 301 | } |
|
302 | 302 | |
|
303 | 303 | //qDebug() << "prev" << prev.first << "pos" << pos << "next" << next.first; |
|
304 | 304 | |
|
305 | 305 | qreal range = next.first - prev.first; |
|
306 | 306 | qreal posDelta = pos - prev.first; |
|
307 | 307 | qreal relativePos = posDelta / range; |
|
308 | 308 | |
|
309 | 309 | //qDebug() << "range" << range << "posDelta" << posDelta << "relativePos" << relativePos; |
|
310 | 310 | |
|
311 | 311 | return colorAt(prev.second, next.second, relativePos); |
|
312 | 312 | } |
|
313 | 313 | |
|
314 | 314 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,81 +1,81 | |||
|
1 | 1 | #ifndef CHARTTHEME_H |
|
2 | 2 | #define CHARTTHEME_H |
|
3 | 3 | |
|
4 | 4 | #include "qchartglobal.h" |
|
5 | 5 | #include "qchart.h" |
|
6 | 6 | #include <QColor> |
|
7 | 7 | #include <QGradientStops> |
|
8 | 8 | |
|
9 | 9 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
10 | 10 | |
|
11 | 11 | class ChartItem; |
|
12 | 12 | class QSeries; |
|
13 | 13 | class LineChartItem; |
|
14 | 14 | class QLineSeries; |
|
15 | 15 | class BarPresenter; |
|
16 | 16 | class QBarSeries; |
|
17 | 17 | class StackedBarPresenter; |
|
18 | 18 | class QStackedBarSeries; |
|
19 | 19 | class QPercentBarSeries; |
|
20 | 20 | class PercentBarPresenter; |
|
21 | 21 | class QScatterSeries; |
|
22 | 22 | class ScatterChartItem; |
|
23 | 23 | class PieChartItem; |
|
24 | 24 | class QPieSeries; |
|
25 | 25 | class SplineChartItem; |
|
26 | 26 | class QSplineSeries; |
|
27 | 27 | class AreaChartItem; |
|
28 | 28 | class QAreaSeries; |
|
29 | 29 | |
|
30 | 30 | class ChartTheme |
|
31 | 31 | { |
|
32 | 32 | public: |
|
33 | 33 | enum BackgroundShadesMode { |
|
34 | 34 | BackgroundShadesNone = 0, |
|
35 | 35 | BackgroundShadesVertical, |
|
36 | 36 | BackgroundShadesHorizontal, |
|
37 | 37 | BackgroundShadesBoth |
|
38 | 38 | }; |
|
39 | 39 | |
|
40 | 40 | protected: |
|
41 | 41 | explicit ChartTheme(QChart::ChartTheme id = QChart::ChartThemeDefault); |
|
42 | 42 | public: |
|
43 | 43 | static ChartTheme* createTheme(QChart::ChartTheme theme); |
|
44 | 44 | QChart::ChartTheme id() const {return m_id;} |
|
45 | 45 | void decorate(QChart* chart); |
|
46 | 46 | void decorate(QLegend* legend); |
|
47 | 47 | //void decorate(ChartItem* item, QSeries* series,int index); |
|
48 |
void decorate( |
|
|
49 |
void decorate( |
|
|
50 |
void decorate( |
|
|
48 | void decorate(QBarSeries* series, int index); | |
|
49 | void decorate(QStackedBarSeries* series, int index); | |
|
50 | void decorate(QPercentBarSeries* series, int index); | |
|
51 | 51 | void decorate(QLineSeries* series, int index); |
|
52 | 52 | void decorate(QAreaSeries* series, int index); |
|
53 | 53 | void decorate(QScatterSeries* series, int index); |
|
54 |
void decorate( |
|
|
54 | void decorate(QPieSeries* series, int index); | |
|
55 | 55 | void decorate(QSplineSeries* series, int index); |
|
56 | 56 | void decorate(QChartAxis* axis, bool axisX); |
|
57 | 57 | |
|
58 | 58 | public: // utils |
|
59 | 59 | void generateSeriesGradients(); |
|
60 | 60 | static QColor colorAt(const QColor &start, const QColor &end, qreal pos); |
|
61 | 61 | static QColor colorAt(const QGradient &gradient, qreal pos); |
|
62 | 62 | |
|
63 | 63 | protected: |
|
64 | 64 | QChart::ChartTheme m_id; |
|
65 | 65 | QList<QColor> m_seriesColors; |
|
66 | 66 | QList<QGradient> m_seriesGradients; |
|
67 | 67 | QLinearGradient m_chartBackgroundGradient; |
|
68 | 68 | |
|
69 | 69 | QFont m_masterFont; |
|
70 | 70 | QPen m_axisLinePen; |
|
71 | 71 | QBrush m_axisLabelBrush; |
|
72 | 72 | QPen m_axisLabelPen; |
|
73 | 73 | QPen m_backgroundShadesPen; |
|
74 | 74 | QBrush m_backgroundShadesBrush; |
|
75 | 75 | BackgroundShadesMode m_backgroundShades; |
|
76 | 76 | QPen m_gridLinePen; |
|
77 | 77 | }; |
|
78 | 78 | |
|
79 | 79 | QTCOMMERCIALCHART_END_NAMESPACE |
|
80 | 80 | |
|
81 | 81 | #endif // CHARTTHEME_H |
@@ -1,144 +1,147 | |||
|
1 | 1 | #include "qchartglobal.h" |
|
2 | 2 | #include "legendmarker_p.h" |
|
3 | 3 | #include <qpieslice.h> |
|
4 | 4 | #include <qbarset.h> |
|
5 | 5 | #include <QPainter> |
|
6 | 6 | #include <QGraphicsSceneEvent> |
|
7 | 7 | |
|
8 | 8 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
9 | 9 | |
|
10 | 10 | LegendMarker::LegendMarker(QSeries* series, QGraphicsItem *parent) |
|
11 | 11 | : QGraphicsObject(parent) |
|
12 | 12 | ,mBoundingRect(0,0,1,1) |
|
13 | 13 | ,mMarkerBoundingRect(0,0,1,1) |
|
14 | 14 | ,mSeries(series) |
|
15 | 15 | ,mBarset(0) |
|
16 | 16 | ,mPieslice(0) |
|
17 | 17 | ,mType(LegendMarkerTypeSeries) |
|
18 | 18 | ,mTextItem(new QGraphicsSimpleTextItem(this)) |
|
19 | 19 | { |
|
20 | 20 | setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); |
|
21 | 21 | } |
|
22 | 22 | |
|
23 | 23 | LegendMarker::LegendMarker(QSeries *series, QBarSet *barset, QGraphicsItem *parent) |
|
24 | 24 | : QGraphicsObject(parent) |
|
25 | 25 | ,mBoundingRect(0,0,1,1) |
|
26 | 26 | ,mMarkerBoundingRect(0,0,1,1) |
|
27 | 27 | ,mSeries(series) |
|
28 | 28 | ,mBarset(barset) |
|
29 | 29 | ,mPieslice(0) |
|
30 | 30 | ,mType(LegendMarkerTypeBarset) |
|
31 | 31 | ,mTextItem(new QGraphicsSimpleTextItem(this)) |
|
32 | 32 | { |
|
33 | 33 | setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); |
|
34 | 34 | } |
|
35 | 35 | |
|
36 | 36 | LegendMarker::LegendMarker(QSeries *series, QPieSlice *pieslice, QGraphicsItem *parent) |
|
37 | 37 | : QGraphicsObject(parent) |
|
38 | 38 | ,mBoundingRect(0,0,1,1) |
|
39 | 39 | ,mMarkerBoundingRect(0,0,1,1) |
|
40 | 40 | ,mSeries(series) |
|
41 | 41 | ,mBarset(0) |
|
42 | 42 | ,mPieslice(pieslice) |
|
43 | 43 | ,mType(LegendMarkerTypePieslice) |
|
44 | 44 | ,mTextItem(new QGraphicsSimpleTextItem(this)) |
|
45 | 45 | { |
|
46 | 46 | setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); |
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | void LegendMarker::setBoundingRect(const QRectF rect) |
|
50 | 50 | { |
|
51 | 51 | mBoundingRect = rect; |
|
52 | 52 | // Calculate Marker pos |
|
53 | 53 | |
|
54 | 54 | // TODO: remove hard coding. 5 is marigin around marker |
|
55 | 55 | QSizeF markerSize(10,10); |
|
56 | 56 | qreal x = mBoundingRect.x() + 5; |
|
57 | 57 | qreal y = mBoundingRect.y() + (mBoundingRect.height() - markerSize.height())/2; |
|
58 | 58 | mMarkerBoundingRect = QRectF(x,y,markerSize.width(),markerSize.height()); |
|
59 | 59 | |
|
60 | 60 | mTextItem.setPos(mBoundingRect.x() + markerSize.width() + 10, y ); |
|
61 | 61 | } |
|
62 | 62 | |
|
63 | 63 | void LegendMarker::setBrush(const QBrush brush) |
|
64 | 64 | { |
|
65 | 65 | mBrush = brush; |
|
66 | 66 | } |
|
67 | 67 | |
|
68 | 68 | QBrush LegendMarker::brush() const |
|
69 | 69 | { |
|
70 | 70 | return mBrush; |
|
71 | 71 | } |
|
72 | 72 | |
|
73 | 73 | void LegendMarker::setName(const QString name) |
|
74 | 74 | { |
|
75 | 75 | mTextItem.setText(name); |
|
76 | 76 | } |
|
77 | 77 | |
|
78 | 78 | QString LegendMarker::name() const |
|
79 | 79 | { |
|
80 | 80 | return mTextItem.text(); |
|
81 | 81 | } |
|
82 | 82 | |
|
83 | 83 | QSeries* LegendMarker::series() const |
|
84 | 84 | { |
|
85 | 85 | return mSeries; |
|
86 | 86 | } |
|
87 | 87 | |
|
88 | 88 | void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
89 | 89 | { |
|
90 | Q_UNUSED(option) | |
|
91 | Q_UNUSED(widget) | |
|
92 | ||
|
90 | 93 | painter->setBrush(mBrush); |
|
91 | 94 | painter->drawRect(mMarkerBoundingRect); |
|
92 | 95 | } |
|
93 | 96 | |
|
94 | 97 | QRectF LegendMarker::boundingRect() const |
|
95 | 98 | { |
|
96 | 99 | return mBoundingRect; |
|
97 | 100 | } |
|
98 | 101 | |
|
99 | 102 | void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event) |
|
100 | 103 | { |
|
101 | 104 | switch (mType) |
|
102 | 105 | { |
|
103 | 106 | case LegendMarkerTypeSeries: { |
|
104 | 107 | emit clicked(mSeries,event->button()); |
|
105 | 108 | break; |
|
106 | 109 | } |
|
107 | 110 | case LegendMarkerTypeBarset: { |
|
108 | 111 | emit clicked(mBarset,event->button()); |
|
109 | 112 | break; |
|
110 | 113 | } |
|
111 | 114 | case LegendMarkerTypePieslice: { |
|
112 | 115 | emit clicked(mPieslice,event->button()); |
|
113 | 116 | break; |
|
114 | 117 | } |
|
115 | 118 | default: { |
|
116 | 119 | break; |
|
117 | 120 | } |
|
118 | 121 | } |
|
119 | 122 | } |
|
120 | 123 | |
|
121 | 124 | void LegendMarker::changed() |
|
122 | 125 | { |
|
123 | 126 | switch (mType) |
|
124 | 127 | { |
|
125 | 128 | case LegendMarkerTypeSeries: { |
|
126 | 129 | // TODO: |
|
127 | 130 | break; |
|
128 | 131 | } |
|
129 | 132 | case LegendMarkerTypeBarset: { |
|
130 | 133 | setBrush(mBarset->brush()); |
|
131 | 134 | setName(mBarset->name()); |
|
132 | 135 | break; |
|
133 | 136 | } |
|
134 | 137 | case LegendMarkerTypePieslice: { |
|
135 | 138 | setBrush(mPieslice->sliceBrush()); |
|
136 | 139 | setName(mPieslice->label()); |
|
137 | 140 | break; |
|
138 | 141 | } |
|
139 | 142 | } |
|
140 | 143 | } |
|
141 | 144 | |
|
142 | 145 | #include "moc_legendmarker_p.cpp" |
|
143 | 146 | |
|
144 | 147 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,81 +1,82 | |||
|
1 | 1 | #include "linechartitem_p.h" |
|
2 | 2 | #include "qlineseries.h" |
|
3 | 3 | #include "chartpresenter_p.h" |
|
4 | 4 | #include <QPainter> |
|
5 | 5 | |
|
6 | 6 | |
|
7 | 7 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
8 | 8 | |
|
9 | 9 | //TODO: optimize : remove points which are not visible |
|
10 | 10 | |
|
11 | 11 | LineChartItem::LineChartItem(QLineSeries* series,QGraphicsItem *parent):XYChartItem(series,parent), |
|
12 | 12 | m_series(series), |
|
13 | 13 | m_pointsVisible(false) |
|
14 | 14 | { |
|
15 | 15 | setZValue(ChartPresenter::LineChartZValue); |
|
16 | 16 | QObject::connect(series,SIGNAL(updated()),this,SLOT(handleUpdated())); |
|
17 | 17 | handleUpdated(); |
|
18 | 18 | } |
|
19 | 19 | |
|
20 | 20 | QRectF LineChartItem::boundingRect() const |
|
21 | 21 | { |
|
22 | 22 | return m_rect; |
|
23 | 23 | } |
|
24 | 24 | |
|
25 | 25 | QPainterPath LineChartItem::shape() const |
|
26 | 26 | { |
|
27 | 27 | return m_path; |
|
28 | 28 | } |
|
29 | 29 | |
|
30 | 30 | void LineChartItem::setLayout(QVector<QPointF>& points) |
|
31 | 31 | { |
|
32 | 32 | if(points.size()==0) |
|
33 | 33 | { |
|
34 | 34 | XYChartItem::setLayout(points); |
|
35 | 35 | return; |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | QList<QGraphicsItem*> items = m_items.childItems(); |
|
39 | 39 | |
|
40 | 40 | QPainterPath linePath(points.at(0)); |
|
41 | 41 | |
|
42 | 42 | for(int i=1; i< points.size();i++) { |
|
43 | 43 | linePath.lineTo(points.at(i)); |
|
44 | 44 | } |
|
45 | 45 | |
|
46 | 46 | prepareGeometryChange(); |
|
47 | 47 | m_path = linePath; |
|
48 | 48 | m_rect = linePath.boundingRect(); |
|
49 | 49 | |
|
50 | 50 | XYChartItem::setLayout(points); |
|
51 | 51 | } |
|
52 | 52 | |
|
53 | 53 | void LineChartItem::handleUpdated() |
|
54 | 54 | { |
|
55 | 55 | m_pointsVisible = m_series->pointsVisible(); |
|
56 | 56 | m_linePen = m_series->pen(); |
|
57 | 57 | m_pointPen = m_series->pen(); |
|
58 | 58 | m_pointPen.setWidthF(2*m_pointPen.width()); |
|
59 | 59 | update(); |
|
60 | 60 | } |
|
61 | 61 | |
|
62 | 62 | //painter |
|
63 | 63 | |
|
64 | 64 | void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
65 | 65 | { |
|
66 |
Q_UNUSED(widget) |
|
|
67 |
Q_UNUSED(option) |
|
|
66 | Q_UNUSED(widget) | |
|
67 | Q_UNUSED(option) | |
|
68 | ||
|
68 | 69 | painter->save(); |
|
69 | 70 | painter->setPen(m_linePen); |
|
70 | 71 | painter->setClipRect(clipRect()); |
|
71 | 72 | painter->drawPath(m_path); |
|
72 | 73 | if(m_pointsVisible){ |
|
73 | 74 | painter->setPen(m_pointPen); |
|
74 | 75 | painter->drawPoints(points()); |
|
75 | 76 | } |
|
76 | 77 | painter->restore(); |
|
77 | 78 | } |
|
78 | 79 | |
|
79 | 80 | #include "moc_linechartitem_p.cpp" |
|
80 | 81 | |
|
81 | 82 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,143 +1,144 | |||
|
1 | 1 | #include "piechartitem_p.h" |
|
2 | 2 | #include "pieslice_p.h" |
|
3 | 3 | #include "qpieslice.h" |
|
4 | 4 | #include "qpieseries.h" |
|
5 | 5 | #include "chartpresenter_p.h" |
|
6 | 6 | #include <QDebug> |
|
7 | 7 | #include <QPainter> |
|
8 | 8 | |
|
9 | 9 | |
|
10 | 10 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
11 | 11 | |
|
12 | 12 | PieChartItem::PieChartItem(QGraphicsItem *parent, QPieSeries *series) |
|
13 | 13 | :ChartItem(parent), |
|
14 | 14 | m_series(series) |
|
15 | 15 | { |
|
16 | 16 | Q_ASSERT(series); |
|
17 | 17 | connect(series, SIGNAL(changed()), this, SLOT(handleSeriesChanged())); |
|
18 | 18 | |
|
19 | 19 | // Note: the following does not affect as long as the item does not have anything to paint |
|
20 | 20 | setZValue(ChartPresenter::PieSeriesZValue); |
|
21 | 21 | } |
|
22 | 22 | |
|
23 | 23 | PieChartItem::~PieChartItem() |
|
24 | 24 | { |
|
25 | 25 | // slices deleted automatically through QGraphicsItem |
|
26 | 26 | } |
|
27 | 27 | |
|
28 | 28 | void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) |
|
29 | 29 | { |
|
30 | Q_UNUSED(painter) | |
|
30 | 31 | // TODO: paint shadows for all components |
|
31 | 32 | // - get paths from items & merge & offset and draw with shadow color? |
|
32 | 33 | //painter->setBrush(QBrush(Qt::red)); |
|
33 | 34 | //painter->drawRect(m_debugRect); |
|
34 | 35 | } |
|
35 | 36 | |
|
36 | 37 | void PieChartItem::handleSeriesChanged() |
|
37 | 38 | { |
|
38 | 39 | QVector<PieSliceLayout> sliceLayout = calculateLayout(); |
|
39 | 40 | applyLayout(sliceLayout); |
|
40 | 41 | update(); |
|
41 | 42 | } |
|
42 | 43 | |
|
43 | 44 | void PieChartItem::handleSliceChanged() |
|
44 | 45 | { |
|
45 | 46 | // TODO: optimize don't need to handle all slices |
|
46 | 47 | QVector<PieSliceLayout> sliceLayout = calculateLayout(); |
|
47 | 48 | applyLayout(sliceLayout); |
|
48 | 49 | update(); |
|
49 | 50 | } |
|
50 | 51 | |
|
51 | 52 | void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal) |
|
52 | 53 | { |
|
53 | 54 | // TODO |
|
54 | 55 | } |
|
55 | 56 | |
|
56 | 57 | void PieChartItem::handleGeometryChanged(const QRectF& rect) |
|
57 | 58 | { |
|
58 | 59 | prepareGeometryChange(); |
|
59 | 60 | m_rect = rect; |
|
60 | 61 | QVector<PieSliceLayout> sliceLayout = calculateLayout(); |
|
61 | 62 | applyLayout(sliceLayout); |
|
62 | 63 | update(); |
|
63 | 64 | } |
|
64 | 65 | |
|
65 | 66 | |
|
66 | 67 | QVector<PieSliceLayout> PieChartItem::calculateLayout() |
|
67 | 68 | { |
|
68 | 69 | // find pie center coordinates |
|
69 | 70 | QPointF center; |
|
70 | 71 | center.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition())); |
|
71 | 72 | center.setY(m_rect.top() + (m_rect.height() * m_series->pieVerticalPosition())); |
|
72 | 73 | |
|
73 | 74 | // find maximum radius for pie |
|
74 | 75 | qreal radius = m_rect.height() / 2; |
|
75 | 76 | if (m_rect.width() < m_rect.height()) |
|
76 | 77 | radius = m_rect.width() / 2; |
|
77 | 78 | |
|
78 | 79 | // apply size factor |
|
79 | 80 | radius *= m_series->pieSize(); |
|
80 | 81 | |
|
81 | 82 | QVector<PieSliceLayout> layout; |
|
82 | 83 | foreach (QPieSlice* s, m_series->slices()) { |
|
83 | 84 | PieSliceLayout sliceLayout; |
|
84 | 85 | sliceLayout.m_data = s; |
|
85 | 86 | sliceLayout.m_center = PieSlice::sliceCenter(center, radius, s); |
|
86 | 87 | sliceLayout.m_radius = radius; |
|
87 | 88 | sliceLayout.m_startAngle = s->startAngle(); |
|
88 | 89 | sliceLayout.m_angleSpan = s->m_angleSpan; |
|
89 | 90 | layout << sliceLayout; |
|
90 | 91 | } |
|
91 | 92 | |
|
92 | 93 | return layout; |
|
93 | 94 | } |
|
94 | 95 | |
|
95 | 96 | void PieChartItem::applyLayout(const QVector<PieSliceLayout> &layout) |
|
96 | 97 | { |
|
97 | 98 | //if(m_animator) |
|
98 | 99 | // m_animator->applyLayout(this,points); |
|
99 | 100 | //else |
|
100 | 101 | setLayout(layout); |
|
101 | 102 | } |
|
102 | 103 | |
|
103 | 104 | void PieChartItem::setLayout(const QVector<PieSliceLayout> &layout) |
|
104 | 105 | { |
|
105 | 106 | foreach (PieSliceLayout l, layout) { |
|
106 | 107 | |
|
107 | 108 | // find slice |
|
108 | 109 | PieSlice *slice = m_slices.value(l.m_data); |
|
109 | 110 | if (!slice) { |
|
110 | 111 | // add a new slice |
|
111 | 112 | slice = new PieSlice(this); |
|
112 | 113 | m_slices.insert(l.m_data, slice); |
|
113 | 114 | |
|
114 | 115 | // connect signals |
|
115 | 116 | connect(l.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged())); |
|
116 | 117 | connect(slice, SIGNAL(clicked()), l.m_data, SIGNAL(clicked())); |
|
117 | 118 | connect(slice, SIGNAL(hoverEnter()), l.m_data, SIGNAL(hoverEnter())); |
|
118 | 119 | connect(slice, SIGNAL(hoverLeave()), l.m_data, SIGNAL(hoverLeave())); |
|
119 | 120 | } |
|
120 | 121 | |
|
121 | 122 | // update |
|
122 | 123 | slice->setLayout(l); |
|
123 | 124 | slice->updateGeometry(); |
|
124 | 125 | slice->update(); |
|
125 | 126 | } |
|
126 | 127 | |
|
127 | 128 | // delete slices |
|
128 | 129 | foreach (QPieSlice *s, m_slices.keys()) { |
|
129 | 130 | |
|
130 | 131 | bool found = false; |
|
131 | 132 | foreach (PieSliceLayout l, layout) { |
|
132 | 133 | if (l.m_data == s) |
|
133 | 134 | found = true; |
|
134 | 135 | } |
|
135 | 136 | |
|
136 | 137 | if (!found) |
|
137 | 138 | delete m_slices.take(s); |
|
138 | 139 | } |
|
139 | 140 | } |
|
140 | 141 | |
|
141 | 142 | #include "moc_piechartitem_p.cpp" |
|
142 | 143 | |
|
143 | 144 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,636 +1,643 | |||
|
1 | 1 | #include "qpieseries.h" |
|
2 | 2 | #include "qpieslice.h" |
|
3 | 3 | #include <QDebug> |
|
4 | 4 | |
|
5 | 5 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
6 | 6 | |
|
7 | 7 | |
|
8 | 8 | /*! |
|
9 | 9 | \class QPieSeries::ChangeSet |
|
10 | 10 | \brief Defines the changes in the series. |
|
11 | 11 | |
|
12 | 12 | Contains the changes that have occurred in the series. Lists of added, changed and removed slices. |
|
13 | 13 | |
|
14 | 14 | \sa QPieSeries::changed() |
|
15 | 15 | */ |
|
16 | 16 | |
|
17 | 17 | /*! |
|
18 | 18 | \internal |
|
19 | 19 | */ |
|
20 | 20 | void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice) |
|
21 | 21 | { |
|
22 | 22 | if (!m_added.contains(slice)) |
|
23 | 23 | m_added << slice; |
|
24 | 24 | } |
|
25 | 25 | |
|
26 | 26 | /*! |
|
27 | 27 | \internal |
|
28 | 28 | */ |
|
29 | 29 | void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices) |
|
30 | 30 | { |
|
31 | 31 | foreach (QPieSlice* s, slices) |
|
32 | 32 | appendAdded(s); |
|
33 | 33 | } |
|
34 | 34 | |
|
35 | 35 | /*! |
|
36 | 36 | \internal |
|
37 | 37 | */ |
|
38 | 38 | void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice) |
|
39 | 39 | { |
|
40 | 40 | if (!m_changed.contains(slice)) |
|
41 | 41 | m_changed << slice; |
|
42 | 42 | } |
|
43 | 43 | |
|
44 | 44 | /*! |
|
45 | 45 | \internal |
|
46 | 46 | */ |
|
47 | 47 | void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice) |
|
48 | 48 | { |
|
49 | 49 | if (!m_removed.contains(slice)) |
|
50 | 50 | m_removed << slice; |
|
51 | 51 | } |
|
52 | 52 | |
|
53 | 53 | /*! |
|
54 | 54 | Returns a list of slices that have been added to the series. |
|
55 | 55 | \sa QPieSeries::changed() |
|
56 | 56 | */ |
|
57 | 57 | QList<QPieSlice*> QPieSeries::ChangeSet::added() const |
|
58 | 58 | { |
|
59 | 59 | return m_added; |
|
60 | 60 | } |
|
61 | 61 | |
|
62 | 62 | /*! |
|
63 | 63 | Returns a list of slices that have been changed in the series. |
|
64 | 64 | \sa QPieSeries::changed() |
|
65 | 65 | */ |
|
66 | 66 | QList<QPieSlice*> QPieSeries::ChangeSet::changed() const |
|
67 | 67 | { |
|
68 | 68 | return m_changed; |
|
69 | 69 | } |
|
70 | 70 | |
|
71 | 71 | /*! |
|
72 | 72 | Returns a list of slices that have been removed from the series. |
|
73 | 73 | \sa QPieSeries::changed() |
|
74 | 74 | */ |
|
75 | 75 | QList<QPieSlice*> QPieSeries::ChangeSet::removed() const |
|
76 | 76 | { |
|
77 | 77 | return m_removed; |
|
78 | 78 | } |
|
79 | 79 | |
|
80 | 80 | |
|
81 | 81 | /*! |
|
82 | 82 | Returns true if there are no added/changed or removed slices in the change set. |
|
83 | 83 | */ |
|
84 | 84 | bool QPieSeries::ChangeSet::isEmpty() const |
|
85 | 85 | { |
|
86 | 86 | if (m_added.count() || m_changed.count() || m_removed.count()) |
|
87 | 87 | return false; |
|
88 | 88 | return true; |
|
89 | 89 | } |
|
90 | 90 | |
|
91 | 91 | /*! |
|
92 | 92 | \class QPieSeries |
|
93 | 93 | \brief Pie series API for QtCommercial Charts |
|
94 | 94 | |
|
95 | 95 | The pie series defines a pie chart which consists of pie slices which are QPieSlice objects. |
|
96 | 96 | The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices. |
|
97 | 97 | The actual slice size is determined by that relative value. |
|
98 | 98 | |
|
99 | 99 | By default the pie is defined as a full pie but it can be a partial pie. |
|
100 | 100 | This can be done by setting a starting angle and angle span to the series. |
|
101 | 101 | */ |
|
102 | 102 | |
|
103 | 103 | /*! |
|
104 | 104 | Constructs a series object which is a child of \a parent. |
|
105 | 105 | */ |
|
106 | 106 | QPieSeries::QPieSeries(QObject *parent) : |
|
107 | 107 | QSeries(parent), |
|
108 | 108 | m_pieRelativeHorPos(0.5), |
|
109 | 109 | m_pieRelativeVerPos(0.5), |
|
110 | 110 | m_pieRelativeSize(0.7), |
|
111 | 111 | m_pieStartAngle(0), |
|
112 | 112 | m_pieEndAngle(360), |
|
113 | 113 | m_total(0) |
|
114 | 114 | { |
|
115 | 115 | |
|
116 | 116 | } |
|
117 | 117 | |
|
118 | 118 | /*! |
|
119 | 119 | Destroys the object. Note that adding series to QChart transfers the ownership to the chart. |
|
120 | 120 | */ |
|
121 | 121 | QPieSeries::~QPieSeries() |
|
122 | 122 | { |
|
123 | 123 | |
|
124 | 124 | } |
|
125 | 125 | |
|
126 | 126 | /*! |
|
127 | 127 | Returns QChartSeries::SeriesTypePie. |
|
128 | 128 | */ |
|
129 | 129 | QSeries::QSeriesType QPieSeries::type() const |
|
130 | 130 | { |
|
131 | 131 | return QSeries::SeriesTypePie; |
|
132 | 132 | } |
|
133 | 133 | |
|
134 | 134 | /*! |
|
135 | 135 | Sets an array of \a slices to the series replacing the existing slices. |
|
136 | 136 | Slice ownership is passed to the series. |
|
137 | 137 | */ |
|
138 | 138 | void QPieSeries::replace(QList<QPieSlice*> slices) |
|
139 | 139 | { |
|
140 | 140 | clear(); |
|
141 | 141 | add(slices); |
|
142 | 142 | } |
|
143 | 143 | |
|
144 | 144 | /*! |
|
145 | 145 | Adds an array of \a slices to the series. |
|
146 | 146 | Slice ownership is passed to the series. |
|
147 | 147 | */ |
|
148 | 148 | void QPieSeries::add(QList<QPieSlice*> slices) |
|
149 | 149 | { |
|
150 | 150 | foreach (QPieSlice* s, slices) { |
|
151 | 151 | s->setParent(this); |
|
152 | 152 | m_slices << s; |
|
153 | 153 | } |
|
154 | 154 | |
|
155 | 155 | updateDerivativeData(); |
|
156 | 156 | |
|
157 | 157 | foreach (QPieSlice* s, slices) { |
|
158 | 158 | connect(s, SIGNAL(changed()), this, SLOT(sliceChanged())); |
|
159 | 159 | connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked())); |
|
160 | 160 | connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter())); |
|
161 | 161 | connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave())); |
|
162 | 162 | } |
|
163 | 163 | |
|
164 | 164 | emit changed(); |
|
165 | 165 | } |
|
166 | 166 | |
|
167 | 167 | /*! |
|
168 | 168 | Adds a single \a slice to the series. |
|
169 | 169 | Slice ownership is passed to the series. |
|
170 | 170 | */ |
|
171 | 171 | void QPieSeries::add(QPieSlice* slice) |
|
172 | 172 | { |
|
173 | 173 | add(QList<QPieSlice*>() << slice); |
|
174 | 174 | } |
|
175 | 175 | |
|
176 | 176 | /*! |
|
177 | 177 | Adds a single \a slice to the series and returns a reference to the series. |
|
178 | 178 | Slice ownership is passed to the series. |
|
179 | 179 | */ |
|
180 | 180 | QPieSeries& QPieSeries::operator << (QPieSlice* slice) |
|
181 | 181 | { |
|
182 | 182 | add(slice); |
|
183 | 183 | return *this; |
|
184 | 184 | } |
|
185 | 185 | |
|
186 | 186 | |
|
187 | 187 | /*! |
|
188 | 188 | Adds a single slice to the series with give \a value and \a name. |
|
189 | 189 | Slice ownership is passed to the series. |
|
190 | 190 | */ |
|
191 | 191 | QPieSlice* QPieSeries::add(qreal value, QString name) |
|
192 | 192 | { |
|
193 | 193 | QPieSlice* slice = new QPieSlice(value, name); |
|
194 | 194 | add(slice); |
|
195 | 195 | return slice; |
|
196 | 196 | } |
|
197 | 197 | |
|
198 | 198 | void QPieSeries::insert(int i, QPieSlice* slice) |
|
199 | 199 | { |
|
200 | 200 | Q_ASSERT(i <= m_slices.count()); |
|
201 | 201 | slice->setParent(this); |
|
202 | 202 | m_slices.insert(i, slice); |
|
203 | 203 | |
|
204 | 204 | updateDerivativeData(); |
|
205 | 205 | |
|
206 | 206 | connect(slice, SIGNAL(changed()), this, SLOT(sliceChanged())); |
|
207 | 207 | connect(slice, SIGNAL(clicked()), this, SLOT(sliceClicked())); |
|
208 | 208 | connect(slice, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter())); |
|
209 | 209 | connect(slice, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave())); |
|
210 | 210 | |
|
211 | 211 | emit changed(); |
|
212 | 212 | } |
|
213 | 213 | |
|
214 | 214 | /*! |
|
215 | 215 | Removes a single \a slice from the series and deletes the slice. |
|
216 | 216 | |
|
217 | 217 | Do not reference this pointer after this call. |
|
218 | 218 | */ |
|
219 | 219 | void QPieSeries::remove(QPieSlice* slice) |
|
220 | 220 | { |
|
221 | 221 | if (!m_slices.removeOne(slice)) { |
|
222 | 222 | Q_ASSERT(0); // TODO: how should this be reported? |
|
223 | 223 | return; |
|
224 | 224 | } |
|
225 | 225 | emit changed(); |
|
226 | 226 | |
|
227 | 227 | updateDerivativeData(); |
|
228 | 228 | |
|
229 | 229 | delete slice; |
|
230 | 230 | slice = NULL; |
|
231 | 231 | } |
|
232 | 232 | |
|
233 | 233 | /*! |
|
234 | 234 | Clears all slices from the series. |
|
235 | 235 | */ |
|
236 | 236 | void QPieSeries::clear() |
|
237 | 237 | { |
|
238 | 238 | if (m_slices.count() == 0) |
|
239 | 239 | return; |
|
240 | 240 | |
|
241 | 241 | foreach (QPieSlice* s, m_slices) { |
|
242 | 242 | m_slices.removeOne(s); |
|
243 | 243 | delete s; |
|
244 | 244 | } |
|
245 | 245 | |
|
246 | 246 | emit changed(); |
|
247 | 247 | |
|
248 | 248 | updateDerivativeData(); |
|
249 | 249 | } |
|
250 | 250 | |
|
251 | 251 | /*! |
|
252 | 252 | Counts the number of the slices in this series. |
|
253 | 253 | */ |
|
254 | 254 | int QPieSeries::count() const |
|
255 | 255 | { |
|
256 | 256 | return m_slices.count(); |
|
257 | 257 | } |
|
258 | 258 | |
|
259 | 259 | /*! |
|
260 | 260 | Returns a list of slices that belong to this series. |
|
261 | 261 | */ |
|
262 | 262 | QList<QPieSlice*> QPieSeries::slices() const |
|
263 | 263 | { |
|
264 | 264 | return m_slices; |
|
265 | 265 | } |
|
266 | 266 | |
|
267 | 267 | /*! |
|
268 | 268 | Sets the center position of the pie by \a relativeHorizontalPosition and \a relativeVerticalPosition. |
|
269 | 269 | |
|
270 | 270 | The factors are relative to the chart rectangle where: |
|
271 | 271 | |
|
272 | 272 | \a relativeHorizontalPosition 0.0 means the absolute left. |
|
273 | 273 | \a relativeHorizontalPosition 1.0 means the absolute right. |
|
274 | 274 | \a relativeVerticalPosition 0.0 means the absolute top. |
|
275 | 275 | \a relativeVerticalPosition 1.0 means the absolute bottom. |
|
276 | 276 | |
|
277 | 277 | By default both values are 0.5 which puts the pie in the middle of the chart rectangle. |
|
278 | 278 | |
|
279 | 279 | \sa pieHorizontalPosition(), pieVerticalPosition(), setPieSize() |
|
280 | 280 | */ |
|
281 | 281 | void QPieSeries::setPiePosition(qreal relativeHorizontalPosition, qreal relativeVerticalPosition) |
|
282 | 282 | { |
|
283 | 283 | if (relativeHorizontalPosition < 0.0 || relativeHorizontalPosition > 1.0 || |
|
284 | 284 | relativeVerticalPosition < 0.0 || relativeVerticalPosition > 1.0) |
|
285 | 285 | return; |
|
286 | 286 | |
|
287 | 287 | if (m_pieRelativeHorPos != relativeHorizontalPosition || m_pieRelativeVerPos != relativeVerticalPosition) { |
|
288 | 288 | m_pieRelativeHorPos = relativeHorizontalPosition; |
|
289 | 289 | m_pieRelativeVerPos = relativeVerticalPosition; |
|
290 | 290 | emit changed(); |
|
291 | 291 | } |
|
292 | 292 | } |
|
293 | 293 | |
|
294 | 294 | /*! |
|
295 | 295 | Gets the horizontal position of the pie. |
|
296 | 296 | |
|
297 | 297 | The returned value is relative to the chart rectangle where: |
|
298 | 298 | |
|
299 | 299 | 0.0 means the absolute left. |
|
300 | 300 | 1.0 means the absolute right. |
|
301 | 301 | |
|
302 | 302 | By default it is 0.5 which puts the pie in the horizontal middle of the chart rectangle. |
|
303 | 303 | |
|
304 | 304 | \sa setPiePosition(), pieVerticalPosition(), setPieSize() |
|
305 | 305 | */ |
|
306 | 306 | qreal QPieSeries::pieHorizontalPosition() const |
|
307 | 307 | { |
|
308 | 308 | return m_pieRelativeHorPos; |
|
309 | 309 | } |
|
310 | 310 | |
|
311 | 311 | /*! |
|
312 | 312 | Gets the vertical position position of the pie. |
|
313 | 313 | |
|
314 | 314 | The returned value is relative to the chart rectangle where: |
|
315 | 315 | |
|
316 | 316 | 0.0 means the absolute top. |
|
317 | 317 | 1.0 means the absolute bottom. |
|
318 | 318 | |
|
319 | 319 | By default it is 0.5 which puts the pie in the vertical middle of the chart rectangle. |
|
320 | 320 | |
|
321 | 321 | \sa setPiePosition(), pieHorizontalPosition(), setPieSize() |
|
322 | 322 | */ |
|
323 | 323 | qreal QPieSeries::pieVerticalPosition() const |
|
324 | 324 | { |
|
325 | 325 | return m_pieRelativeVerPos; |
|
326 | 326 | } |
|
327 | 327 | |
|
328 | 328 | /*! |
|
329 | 329 | Sets the relative size of the pie. |
|
330 | 330 | |
|
331 | 331 | The \a relativeSize is defined so that the 1.0 is the maximum that can fit the given chart rectangle. |
|
332 | 332 | |
|
333 | 333 | Default value is 0.7. |
|
334 | 334 | |
|
335 | 335 | \sa pieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition() |
|
336 | 336 | */ |
|
337 | 337 | void QPieSeries::setPieSize(qreal relativeSize) |
|
338 | 338 | { |
|
339 | 339 | if (relativeSize < 0.0 || relativeSize > 1.0) |
|
340 | 340 | return; |
|
341 | 341 | |
|
342 | 342 | if (m_pieRelativeSize != relativeSize) { |
|
343 | 343 | m_pieRelativeSize = relativeSize; |
|
344 | 344 | emit changed(); |
|
345 | 345 | } |
|
346 | 346 | } |
|
347 | 347 | |
|
348 | 348 | /*! |
|
349 | 349 | Gets the relative size of the pie. |
|
350 | 350 | |
|
351 | 351 | The size is defined so that the 1.0 is the maximum that can fit the given chart rectangle. |
|
352 | 352 | |
|
353 | 353 | Default value is 0.7. |
|
354 | 354 | |
|
355 | 355 | \sa setPieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition() |
|
356 | 356 | */ |
|
357 | 357 | qreal QPieSeries::pieSize() const |
|
358 | 358 | { |
|
359 | 359 | return m_pieRelativeSize; |
|
360 | 360 | } |
|
361 | 361 | |
|
362 | 362 | |
|
363 | 363 | /*! |
|
364 | 364 | Sets the end angle of the pie. |
|
365 | 365 | |
|
366 | 366 | Full pie is 360 degrees where 0 degrees is at 12 a'clock. |
|
367 | 367 | |
|
368 | 368 | \a angle must be less than pie end angle. Default value is 0. |
|
369 | 369 | |
|
370 | 370 | \sa pieStartAngle(), pieEndAngle(), setPieEndAngle() |
|
371 | 371 | */ |
|
372 | 372 | void QPieSeries::setPieStartAngle(qreal angle) |
|
373 | 373 | { |
|
374 | 374 | if (angle >= 0 && angle <= 360 && angle != m_pieStartAngle && angle <= m_pieEndAngle) { |
|
375 | 375 | m_pieStartAngle = angle; |
|
376 | 376 | updateDerivativeData(); |
|
377 | 377 | } |
|
378 | 378 | } |
|
379 | 379 | |
|
380 | 380 | /*! |
|
381 | 381 | Gets the start angle of the pie. |
|
382 | 382 | |
|
383 | 383 | Full pie is 360 degrees where 0 degrees is at 12 a'clock. Default value is 360. |
|
384 | 384 | |
|
385 | 385 | \sa setPieStartAngle(), pieEndAngle(), setPieEndAngle() |
|
386 | 386 | */ |
|
387 | 387 | qreal QPieSeries::pieStartAngle() const |
|
388 | 388 | { |
|
389 | 389 | return m_pieStartAngle; |
|
390 | 390 | } |
|
391 | 391 | |
|
392 | 392 | /*! |
|
393 | 393 | Sets the end angle of the pie. |
|
394 | 394 | |
|
395 | 395 | Full pie is 360 degrees where 0 degrees is at 12 a'clock. |
|
396 | 396 | |
|
397 | 397 | \a angle must be greater than start angle. |
|
398 | 398 | |
|
399 | 399 | \sa pieEndAngle(), pieStartAngle(), setPieStartAngle() |
|
400 | 400 | */ |
|
401 | 401 | void QPieSeries::setPieEndAngle(qreal angle) |
|
402 | 402 | { |
|
403 | 403 | if (angle >= 0 && angle <= 360 && angle != m_pieEndAngle && angle >= m_pieStartAngle) { |
|
404 | 404 | m_pieEndAngle = angle; |
|
405 | 405 | updateDerivativeData(); |
|
406 | 406 | } |
|
407 | 407 | } |
|
408 | 408 | |
|
409 | 409 | /*! |
|
410 | 410 | Returns the end angle of the pie. |
|
411 | 411 | |
|
412 | 412 | Full pie is 360 degrees where 0 degrees is at 12 a'clock. |
|
413 | 413 | |
|
414 | 414 | \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle() |
|
415 | 415 | */ |
|
416 | 416 | qreal QPieSeries::pieEndAngle() const |
|
417 | 417 | { |
|
418 | 418 | return m_pieEndAngle; |
|
419 | 419 | } |
|
420 | 420 | |
|
421 | 421 | /*! |
|
422 | 422 | Sets the all the slice labels \a visible or invisible. |
|
423 | 423 | |
|
424 | 424 | \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible() |
|
425 | 425 | */ |
|
426 | 426 | void QPieSeries::setLabelsVisible(bool visible) |
|
427 | 427 | { |
|
428 | 428 | foreach (QPieSlice* s, m_slices) |
|
429 | 429 | s->setLabelVisible(visible); |
|
430 | 430 | } |
|
431 | 431 | |
|
432 | 432 | /*! |
|
433 | 433 | Returns the sum of all slice values in this series. |
|
434 | 434 | |
|
435 | 435 | \sa QPieSlice::value(), QPieSlice::setValue() |
|
436 | 436 | */ |
|
437 | 437 | qreal QPieSeries::total() const |
|
438 | 438 | { |
|
439 | 439 | return m_total; |
|
440 | 440 | } |
|
441 | 441 | |
|
442 | 442 | /*! |
|
443 | 443 | \fn void QPieSeries::changed() |
|
444 | 444 | |
|
445 | 445 | This signal emitted when something has changed in the series. |
|
446 | 446 | |
|
447 | 447 | \sa QPieSeries::ChangeSet, QPieSlice::changed() |
|
448 | 448 | */ |
|
449 | 449 | |
|
450 | 450 | /*! |
|
451 | 451 | \fn void QPieSeries::clicked(QPieSlice* slice) |
|
452 | 452 | |
|
453 | 453 | This signal is emitted when a \a slice has been clicked. |
|
454 | 454 | |
|
455 | 455 | \sa QPieSlice::clicked() |
|
456 | 456 | */ |
|
457 | 457 | |
|
458 | 458 | /*! |
|
459 | 459 | \fn void QPieSeries::hoverEnter(QPieSlice* slice) |
|
460 | 460 | |
|
461 | 461 | This signal is emitted when user has hovered over a \a slice. |
|
462 | 462 | |
|
463 | 463 | \sa QPieSlice::hoverEnter() |
|
464 | 464 | */ |
|
465 | 465 | |
|
466 | 466 | /*! |
|
467 | 467 | \fn void QPieSeries::hoverLeave(QPieSlice* slice) |
|
468 | 468 | |
|
469 | 469 | This signal is emitted when user has hovered away from a \a slice. |
|
470 | 470 | |
|
471 | 471 | \sa QPieSlice::hoverLeave() |
|
472 | 472 | */ |
|
473 | 473 | |
|
474 | 474 | void QPieSeries::sliceChanged() |
|
475 | 475 | { |
|
476 | 476 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); |
|
477 | 477 | Q_ASSERT(m_slices.contains(slice)); |
|
478 | 478 | updateDerivativeData(); |
|
479 | 479 | } |
|
480 | 480 | |
|
481 | 481 | void QPieSeries::sliceClicked() |
|
482 | 482 | { |
|
483 | 483 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); |
|
484 | 484 | Q_ASSERT(m_slices.contains(slice)); |
|
485 | 485 | emit clicked(slice); |
|
486 | 486 | } |
|
487 | 487 | |
|
488 | 488 | void QPieSeries::sliceHoverEnter() |
|
489 | 489 | { |
|
490 | 490 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); |
|
491 | 491 | Q_ASSERT(m_slices.contains(slice)); |
|
492 | 492 | emit hoverEnter(slice); |
|
493 | 493 | } |
|
494 | 494 | |
|
495 | 495 | void QPieSeries::sliceHoverLeave() |
|
496 | 496 | { |
|
497 | 497 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); |
|
498 | 498 | Q_ASSERT(m_slices.contains(slice)); |
|
499 | 499 | emit hoverLeave(slice); |
|
500 | 500 | } |
|
501 | 501 | |
|
502 | 502 | void QPieSeries::updateDerivativeData() |
|
503 | 503 | { |
|
504 | 504 | m_total = 0; |
|
505 | 505 | |
|
506 | 506 | // nothing to do? |
|
507 | 507 | if (m_slices.count() == 0) |
|
508 | 508 | return; |
|
509 | 509 | |
|
510 | 510 | // calculate total |
|
511 | 511 | foreach (QPieSlice* s, m_slices) |
|
512 | 512 | m_total += s->value(); |
|
513 | 513 | |
|
514 | 514 | // we must have some values |
|
515 | 515 | if (m_total == 0) { |
|
516 | 516 | qDebug() << "QPieSeries::updateDerivativeData() total == 0"; |
|
517 | 517 | Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this? |
|
518 | 518 | } |
|
519 | 519 | |
|
520 | 520 | // update slice attributes |
|
521 | 521 | qreal sliceAngle = m_pieStartAngle; |
|
522 | 522 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; |
|
523 | 523 | foreach (QPieSlice* s, m_slices) { |
|
524 | 524 | |
|
525 | 525 | bool changed = false; |
|
526 | 526 | |
|
527 | 527 | qreal percentage = s->value() / m_total; |
|
528 | 528 | if (s->m_percentage != percentage) { |
|
529 | 529 | s->m_percentage = percentage; |
|
530 | 530 | changed = true; |
|
531 | 531 | } |
|
532 | 532 | |
|
533 | 533 | qreal sliceSpan = pieSpan * percentage; |
|
534 | 534 | if (s->m_angleSpan != sliceSpan) { |
|
535 | 535 | s->m_angleSpan = sliceSpan; |
|
536 | 536 | changed = true; |
|
537 | 537 | } |
|
538 | 538 | |
|
539 | 539 | if (s->m_startAngle != sliceAngle) { |
|
540 | 540 | s->m_startAngle = sliceAngle; |
|
541 | 541 | changed = true; |
|
542 | 542 | } |
|
543 | 543 | sliceAngle += sliceSpan; |
|
544 | 544 | |
|
545 | 545 | if (changed) |
|
546 | 546 | emit s->changed(); |
|
547 | 547 | } |
|
548 | 548 | } |
|
549 | 549 | |
|
550 | 550 | bool QPieSeries::setModel(QAbstractItemModel* model) |
|
551 | 551 | { |
|
552 | 552 | // disconnect signals from old model |
|
553 | 553 | if(m_model) |
|
554 | 554 | { |
|
555 | 555 | disconnect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0, 0); |
|
556 | 556 | disconnect(m_model,SIGNAL(rowsInserted(QModelIndex, int, int)), 0, 0); |
|
557 | 557 | disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), 0, 0); |
|
558 | 558 | } |
|
559 | 559 | |
|
560 | 560 | // set new model if not NULL and connect necessary signals from it |
|
561 | 561 | if(model) |
|
562 | 562 | { |
|
563 | 563 | m_model = model; |
|
564 | 564 | connect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex, QModelIndex))); |
|
565 | 565 | connect(m_model,SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(modelDataAdded(QModelIndex,int,int))); |
|
566 | 566 | connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(modelDataRemoved(QModelIndex,int,int))); |
|
567 | 567 | } |
|
568 | 568 | |
|
569 | 569 | return true; |
|
570 | 570 | } |
|
571 | 571 | |
|
572 | 572 | void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation) |
|
573 | 573 | { |
|
574 | 574 | m_mapValues = modelValuesLine; |
|
575 | 575 | m_mapLabels = modelLabelsLine; |
|
576 | 576 | m_mapOrientation = orientation; |
|
577 | 577 | |
|
578 | 578 | if (m_model == NULL) |
|
579 | 579 | return; |
|
580 | 580 | |
|
581 | 581 | if (m_mapOrientation == Qt::Vertical) |
|
582 | 582 | for (int i = 0; i < m_model->rowCount(); i++) |
|
583 | 583 | add(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); |
|
584 | 584 | else |
|
585 | 585 | for (int i = 0; i < m_model->columnCount(); i++) |
|
586 | 586 | add(m_model->data(m_model->index(m_mapValues, i), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(m_mapLabels, i), Qt::DisplayRole).toString()); |
|
587 | 587 | |
|
588 | 588 | |
|
589 | 589 | } |
|
590 | 590 | |
|
591 | 591 | void QPieSeries::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight) |
|
592 | 592 | { |
|
593 | Q_UNUSED(bottomRight) | |
|
594 | ||
|
593 | 595 | if (m_mapOrientation == Qt::Vertical) |
|
594 | 596 | { |
|
595 | 597 | // slices().at(topLeft.row())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble()); |
|
596 | 598 | if (topLeft.column() == m_mapValues) |
|
597 | 599 | slices().at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble()); |
|
598 | 600 | else if (topLeft.column() == m_mapLabels) |
|
599 | 601 | slices().at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString()); |
|
600 | 602 | } |
|
601 | 603 | else |
|
602 | 604 | { |
|
603 | 605 | // slices().at(topLeft.column())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble()); |
|
604 | 606 | if (topLeft.column() == m_mapValues) |
|
605 | 607 | slices().at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble()); |
|
606 | 608 | else if (topLeft.column() == m_mapLabels) |
|
607 | 609 | slices().at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString()); |
|
608 | 610 | } |
|
609 | 611 | } |
|
610 | 612 | |
|
611 | 613 | void QPieSeries::modelDataAdded(QModelIndex parent, int start, int end) |
|
612 | 614 | { |
|
615 | Q_UNUSED(parent) | |
|
616 | Q_UNUSED(end) | |
|
617 | ||
|
613 | 618 | QPieSlice* newSlice = new QPieSlice; |
|
614 | 619 | newSlice->setLabelVisible(true); |
|
615 | 620 | if (m_mapOrientation == Qt::Vertical) |
|
616 | 621 | { |
|
617 | 622 | newSlice->setValue(m_model->data(m_model->index(start, m_mapValues), Qt::DisplayRole).toDouble()); |
|
618 | 623 | newSlice->setLabel(m_model->data(m_model->index(start, m_mapLabels), Qt::DisplayRole).toString()); |
|
619 | 624 | } |
|
620 | 625 | else |
|
621 | 626 | { |
|
622 | 627 | newSlice->setValue(m_model->data(m_model->index(m_mapValues, start), Qt::DisplayRole).toDouble()); |
|
623 | 628 | newSlice->setLabel(m_model->data(m_model->index(m_mapLabels, start), Qt::DisplayRole).toString()); |
|
624 | 629 | } |
|
625 | 630 | |
|
626 | 631 | insert(start, newSlice); |
|
627 | 632 | } |
|
628 | 633 | |
|
629 | 634 | void QPieSeries::modelDataRemoved(QModelIndex parent, int start, int end) |
|
630 | 635 | { |
|
636 | Q_UNUSED(parent) | |
|
637 | Q_UNUSED(end) | |
|
631 | 638 | remove(slices().at(start)); |
|
632 | 639 | } |
|
633 | 640 | |
|
634 | 641 | #include "moc_qpieseries.cpp" |
|
635 | 642 | |
|
636 | 643 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,217 +1,222 | |||
|
1 | 1 | #include "qchartglobal.h" |
|
2 | 2 | #include "qlegend.h" |
|
3 | 3 | #include "qseries.h" |
|
4 | 4 | #include "legendmarker_p.h" |
|
5 | 5 | #include "qxyseries.h" |
|
6 | 6 | #include "qlineseries.h" |
|
7 | 7 | #include "qareaseries.h" |
|
8 | 8 | #include "qscatterseries.h" |
|
9 | 9 | #include "qsplineseries.h" |
|
10 | 10 | #include "qbarseries.h" |
|
11 | 11 | #include "qstackedbarseries.h" |
|
12 | 12 | #include "qpercentbarseries.h" |
|
13 | 13 | #include "qbarset.h" |
|
14 | 14 | #include "qpieseries.h" |
|
15 | 15 | #include "qpieslice.h" |
|
16 | 16 | #include <QPainter> |
|
17 | 17 | #include <QPen> |
|
18 | 18 | |
|
19 | 19 | #include <QGraphicsSceneEvent> |
|
20 | 20 | |
|
21 | 21 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
22 | 22 | |
|
23 | 23 | QLegend::QLegend(QGraphicsItem *parent) |
|
24 | 24 | : QGraphicsObject(parent) |
|
25 | 25 | ,mBoundingRect(0,0,1,1) |
|
26 | 26 | ,mBackgroundBrush(Qt::darkGray) // TODO: from theme? |
|
27 | 27 | ,mMinimumSize(50,20) // TODO: magic numbers |
|
28 | 28 | { |
|
29 | 29 | setVisible(false); |
|
30 | 30 | } |
|
31 | 31 | |
|
32 | 32 | void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
33 | 33 | { |
|
34 | Q_UNUSED(option) | |
|
35 | Q_UNUSED(widget) | |
|
36 | ||
|
34 | 37 | painter->setBrush(mBackgroundBrush); |
|
35 | 38 | painter->drawRect(mBoundingRect); |
|
36 | 39 | } |
|
37 | 40 | |
|
38 | 41 | QRectF QLegend::boundingRect() const |
|
39 | 42 | { |
|
40 | 43 | return mBoundingRect; |
|
41 | 44 | } |
|
42 | 45 | |
|
43 | 46 | void QLegend::setBackgroundBrush(const QBrush& brush) |
|
44 | 47 | { |
|
45 | 48 | mBackgroundBrush = brush; |
|
46 | 49 | } |
|
47 | 50 | |
|
48 | 51 | QBrush QLegend::backgroundBrush() const |
|
49 | 52 | { |
|
50 | 53 | return mBackgroundBrush; |
|
51 | 54 | } |
|
52 | 55 | |
|
53 | 56 | QSizeF QLegend::minimumSize() const |
|
54 | 57 | { |
|
55 | 58 | return mMinimumSize; |
|
56 | 59 | } |
|
57 | 60 | |
|
58 | 61 | void QLegend::setMinimumSize(const QSizeF size) |
|
59 | 62 | { |
|
60 | 63 | mMinimumSize = size; |
|
61 | 64 | } |
|
62 | 65 | |
|
63 | 66 | void QLegend::handleSeriesAdded(QSeries* series,Domain* domain) |
|
64 | 67 | { |
|
68 | Q_UNUSED(domain) | |
|
69 | ||
|
65 | 70 | mSeriesList.append(series); |
|
66 | 71 | createMarkers(series); |
|
67 | 72 | layoutChanged(); |
|
68 | 73 | } |
|
69 | 74 | |
|
70 | 75 | void QLegend::handleSeriesRemoved(QSeries* series) |
|
71 | 76 | { |
|
72 | 77 | if (series->type() == QSeries::SeriesTypeArea) |
|
73 | 78 | { |
|
74 | 79 | // This is special case. Area series has upper and lower series, which each have markers |
|
75 | 80 | QAreaSeries* s = static_cast<QAreaSeries*> (series); |
|
76 | 81 | deleteMarkers(s->upperSeries()); |
|
77 | 82 | deleteMarkers(s->lowerSeries()); |
|
78 | 83 | } else { |
|
79 | 84 | deleteMarkers(series); |
|
80 | 85 | } |
|
81 | 86 | |
|
82 | 87 | mSeriesList.removeOne(series); |
|
83 | 88 | layoutChanged(); |
|
84 | 89 | } |
|
85 | 90 | |
|
86 | 91 | void QLegend::handleGeometryChanged(const QRectF& size) |
|
87 | 92 | { |
|
88 | 93 | mBoundingRect = size; |
|
89 | 94 | layoutChanged(); |
|
90 | 95 | } |
|
91 | 96 | |
|
92 | 97 | void QLegend::createMarkers(QSeries *series) |
|
93 | 98 | { |
|
94 | 99 | switch (series->type()) |
|
95 | 100 | { |
|
96 | 101 | case QSeries::SeriesTypeLine: { |
|
97 | 102 | QLineSeries* lineSeries = static_cast<QLineSeries*>(series); |
|
98 | 103 | appendMarkers(lineSeries); |
|
99 | 104 | break; |
|
100 | 105 | } |
|
101 | 106 | case QSeries::SeriesTypeArea: { |
|
102 | 107 | QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series); |
|
103 | 108 | appendMarkers(areaSeries->upperSeries()); |
|
104 | 109 | if(areaSeries->lowerSeries()) |
|
105 | 110 | appendMarkers(areaSeries->lowerSeries()); |
|
106 | 111 | break; |
|
107 | 112 | } |
|
108 | 113 | |
|
109 | 114 | case QSeries::SeriesTypeBar: { |
|
110 | 115 | QBarSeries* barSeries = static_cast<QBarSeries*>(series); |
|
111 | 116 | appendMarkers(barSeries); |
|
112 | 117 | break; |
|
113 | 118 | } |
|
114 | 119 | |
|
115 | 120 | case QSeries::SeriesTypeStackedBar: { |
|
116 | 121 | QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series); |
|
117 | 122 | appendMarkers(stackedBarSeries); |
|
118 | 123 | break; |
|
119 | 124 | } |
|
120 | 125 | |
|
121 | 126 | case QSeries::SeriesTypePercentBar: { |
|
122 | 127 | QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series); |
|
123 | 128 | appendMarkers(percentBarSeries); |
|
124 | 129 | break; |
|
125 | 130 | } |
|
126 | 131 | |
|
127 | 132 | case QSeries::SeriesTypeScatter: { |
|
128 | 133 | QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series); |
|
129 | 134 | appendMarkers(scatterSeries); |
|
130 | 135 | break; |
|
131 | 136 | } |
|
132 | 137 | |
|
133 | 138 | case QSeries::SeriesTypePie: { |
|
134 | 139 | QPieSeries *pieSeries = static_cast<QPieSeries *>(series); |
|
135 | 140 | appendMarkers(pieSeries); |
|
136 | 141 | break; |
|
137 | 142 | } |
|
138 | 143 | |
|
139 | 144 | case QSeries::SeriesTypeSpline: { |
|
140 | 145 | QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series); |
|
141 | 146 | appendMarkers(splineSeries); |
|
142 | 147 | break; |
|
143 | 148 | } |
|
144 | 149 | default: { |
|
145 | 150 | qDebug()<< "QLegend::createMarkers" << series->type() << "not implemented."; |
|
146 | 151 | break; |
|
147 | 152 | } |
|
148 | 153 | } |
|
149 | 154 | } |
|
150 | 155 | |
|
151 | 156 | void QLegend::appendMarkers(QXYSeries* series) |
|
152 | 157 | { |
|
153 | 158 | LegendMarker* marker = new LegendMarker(series,this); |
|
154 | 159 | marker->setName(series->name()); |
|
155 | 160 | marker->setBrush(series->brush()); |
|
156 | 161 | connect(marker,SIGNAL(clicked(QSeries*,Qt::MouseButton)),this,SIGNAL(clicked(QSeries*,Qt::MouseButton))); |
|
157 | 162 | mMarkers.append(marker); |
|
158 | 163 | childItems().append(marker); |
|
159 | 164 | } |
|
160 | 165 | |
|
161 | 166 | void QLegend::appendMarkers(QBarSeries *series) |
|
162 | 167 | { |
|
163 | 168 | foreach(QBarSet* s, series->barSets()) { |
|
164 | 169 | LegendMarker* marker = new LegendMarker(series,s,this); |
|
165 | 170 | marker->setName(s->name()); |
|
166 | 171 | marker->setBrush(s->brush()); |
|
167 | 172 | connect(marker,SIGNAL(clicked(QBarSet*,Qt::MouseButton)),this,SIGNAL(clicked(QBarSet*,Qt::MouseButton))); |
|
168 | 173 | connect(s,SIGNAL(changed()),marker,SLOT(changed())); |
|
169 | 174 | mMarkers.append(marker); |
|
170 | 175 | childItems().append(marker); |
|
171 | 176 | } |
|
172 | 177 | } |
|
173 | 178 | |
|
174 | 179 | void QLegend::appendMarkers(QPieSeries *series) |
|
175 | 180 | { |
|
176 | 181 | foreach(QPieSlice* s, series->slices()) { |
|
177 | 182 | LegendMarker* marker = new LegendMarker(series,s,this); |
|
178 | 183 | marker->setName(s->label()); |
|
179 | 184 | marker->setBrush(s->sliceBrush()); |
|
180 | 185 | connect(marker,SIGNAL(clicked(QPieSlice*,Qt::MouseButton)),this,SIGNAL(clicked(QPieSlice*,Qt::MouseButton))); |
|
181 | 186 | connect(s,SIGNAL(changed()),marker,SLOT(changed())); |
|
182 | 187 | mMarkers.append(marker); |
|
183 | 188 | childItems().append(marker); |
|
184 | 189 | } |
|
185 | 190 | } |
|
186 | 191 | |
|
187 | 192 | void QLegend::deleteMarkers(QSeries *series) |
|
188 | 193 | { |
|
189 | 194 | // Search all markers that belong to given series and delete them. |
|
190 | 195 | foreach (LegendMarker *m, mMarkers) { |
|
191 | 196 | if (m->series() == series) { |
|
192 | 197 | mMarkers.removeOne(m); |
|
193 | 198 | delete m; |
|
194 | 199 | } |
|
195 | 200 | } |
|
196 | 201 | } |
|
197 | 202 | |
|
198 | 203 | void QLegend::layoutChanged() |
|
199 | 204 | { |
|
200 | 205 | // Calculate layout for markers and text |
|
201 | 206 | if (mMarkers.count() <= 0) { |
|
202 | 207 | // Nothing to do |
|
203 | 208 | return; |
|
204 | 209 | } |
|
205 | 210 | |
|
206 | 211 | qreal steps = mMarkers.count(); |
|
207 | 212 | qreal xStep = mBoundingRect.width() / steps; |
|
208 | 213 | qreal x=mBoundingRect.x(); |
|
209 | 214 | qreal y = mBoundingRect.y() + (mBoundingRect.height()/4); |
|
210 | 215 | foreach (LegendMarker* m, mMarkers) { |
|
211 | 216 | m->setBoundingRect(QRectF(x,y,xStep,mBoundingRect.height()/2)); |
|
212 | 217 | x += xStep; |
|
213 | 218 | } |
|
214 | 219 | } |
|
215 | 220 | |
|
216 | 221 | #include "moc_qlegend.cpp" |
|
217 | 222 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,184 +1,180 | |||
|
1 | 1 | #include "scatterchartitem_p.h" |
|
2 | 2 | #include "qscatterseries.h" |
|
3 | 3 | #include "chartpresenter_p.h" |
|
4 | 4 | #include <QPainter> |
|
5 | 5 | #include <QGraphicsScene> |
|
6 | 6 | |
|
7 | 7 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
8 | 8 | |
|
9 | 9 | |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | |
|
13 | 13 | |
|
14 | 14 | |
|
15 | 15 | ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *parent) : |
|
16 | 16 | XYChartItem(series,parent), |
|
17 | 17 | m_series(series), |
|
18 | 18 | m_items(this), |
|
19 | 19 | m_shape(QScatterSeries::MarkerShapeRectangle), |
|
20 | 20 | m_size(10) |
|
21 | 21 | |
|
22 | 22 | { |
|
23 | 23 | Q_ASSERT(parent); |
|
24 | 24 | Q_ASSERT(series); |
|
25 | 25 | |
|
26 | 26 | QObject::connect(m_series,SIGNAL(updated()), this, SLOT(handleUpdated())); |
|
27 | 27 | |
|
28 | 28 | setZValue(ChartPresenter::ScatterSeriesZValue); |
|
29 | 29 | setFlags(QGraphicsItem::ItemHasNoContents); |
|
30 | 30 | setFlags(QGraphicsItem::ItemClipsChildrenToShape); |
|
31 | 31 | |
|
32 | 32 | handleUpdated(); |
|
33 | 33 | |
|
34 | 34 | m_items.setHandlesChildEvents(false); |
|
35 | 35 | |
|
36 | 36 | // TODO: how to draw a drop shadow? |
|
37 | 37 | // QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect(); |
|
38 | 38 | // dropShadow->setOffset(2.0); |
|
39 | 39 | // dropShadow->setBlurRadius(2.0); |
|
40 | 40 | // setGraphicsEffect(dropShadow); |
|
41 | 41 | } |
|
42 | 42 | |
|
43 | 43 | |
|
44 | 44 | QRectF ScatterChartItem::boundingRect() const |
|
45 | 45 | { |
|
46 | 46 | return m_rect; |
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | void ScatterChartItem::createPoints(int count) |
|
50 | 50 | { |
|
51 | 51 | for (int i = 0; i < count; ++i) { |
|
52 | 52 | |
|
53 | 53 | QGraphicsItem *item; |
|
54 | 54 | |
|
55 | 55 | switch (m_shape) { |
|
56 | 56 | case QScatterSeries::MarkerShapeCircle:{ |
|
57 | 57 | QGraphicsEllipseItem* i = new QGraphicsEllipseItem(0,0,m_size,m_size); |
|
58 | 58 | const QRectF& rect = i->boundingRect(); |
|
59 | 59 | i->setPos(-rect.width()/2,-rect.height()/2); |
|
60 | 60 | item = new Marker(i,this); |
|
61 | 61 | break; |
|
62 | 62 | } |
|
63 | 63 | case QScatterSeries::MarkerShapeRectangle:{ |
|
64 | 64 | QGraphicsRectItem* i = new QGraphicsRectItem(0,0,m_size,m_size); |
|
65 | 65 | i->setPos(-m_size/2,-m_size/2); |
|
66 | 66 | item = new Marker(i,this); |
|
67 | 67 | break; |
|
68 | 68 | } |
|
69 | 69 | default: |
|
70 | 70 | qWarning()<<"Unsupported marker type"; |
|
71 | 71 | break; |
|
72 | 72 | |
|
73 | 73 | } |
|
74 | 74 | m_items.addToGroup(item); |
|
75 | 75 | } |
|
76 | 76 | } |
|
77 | 77 | |
|
78 | 78 | void ScatterChartItem::deletePoints(int count) |
|
79 | 79 | { |
|
80 | 80 | QList<QGraphicsItem *> items = m_items.childItems(); |
|
81 | 81 | |
|
82 | 82 | for (int i = 0; i < count; ++i) { |
|
83 | 83 | delete(items.takeLast()); |
|
84 | 84 | } |
|
85 | 85 | } |
|
86 | 86 | |
|
87 | 87 | void ScatterChartItem::markerSelected(Marker* marker) |
|
88 | 88 | { |
|
89 | 89 | emit XYChartItem::clicked(QPointF(m_series->x(marker->index()), m_series->y(marker->index()))); |
|
90 | 90 | } |
|
91 | 91 | |
|
92 | 92 | void ScatterChartItem::setLayout(QVector<QPointF>& points) |
|
93 | 93 | { |
|
94 | 94 | if(points.size()==0) |
|
95 | 95 | { |
|
96 | 96 | XYChartItem::setLayout(points); |
|
97 | 97 | return; |
|
98 | 98 | } |
|
99 | 99 | |
|
100 | 100 | int diff = XYChartItem::points().size() - points.size(); |
|
101 | 101 | |
|
102 | 102 | if(diff>0) { |
|
103 | 103 | deletePoints(diff); |
|
104 | 104 | } |
|
105 | 105 | else if(diff<0) { |
|
106 | 106 | createPoints(-diff); |
|
107 | 107 | } |
|
108 | 108 | |
|
109 | 109 | if(diff!=0) handleUpdated(); |
|
110 | 110 | |
|
111 | 111 | QList<QGraphicsItem*> items = m_items.childItems(); |
|
112 | 112 | |
|
113 | 113 | for(int i=0; i< points.size();i++) { |
|
114 | 114 | Marker* item = static_cast<Marker*>(items.at(i)); |
|
115 | 115 | const QPointF& point = points.at(i); |
|
116 | 116 | const QRectF& rect = item->boundingRect(); |
|
117 | 117 | item->setIndex(i); |
|
118 | 118 | item->setPos(point.x()-rect.width()/2,point.y()-rect.height()/2); |
|
119 | 119 | if(!clipRect().contains(point)) { |
|
120 | 120 | item->setVisible(false); |
|
121 | 121 | } |
|
122 | 122 | else { |
|
123 | 123 | item->setVisible(true); |
|
124 | 124 | } |
|
125 | 125 | } |
|
126 | 126 | |
|
127 | 127 | prepareGeometryChange(); |
|
128 | 128 | m_rect = clipRect(); |
|
129 | 129 | XYChartItem::setLayout(points); |
|
130 | 130 | } |
|
131 | 131 | |
|
132 | 132 | |
|
133 | 133 | void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
134 | 134 | { |
|
135 |
Q_UNUSED(painter) |
|
|
136 |
Q_UNUSED(option) |
|
|
137 |
Q_UNUSED(widget) |
|
|
135 | Q_UNUSED(painter) | |
|
136 | Q_UNUSED(option) | |
|
137 | Q_UNUSED(widget) | |
|
138 | 138 | } |
|
139 | 139 | |
|
140 | 140 | void ScatterChartItem::setPen(const QPen& pen) |
|
141 | 141 | { |
|
142 | 142 | foreach(QGraphicsItem* item , m_items.childItems()) { |
|
143 | 143 | static_cast<Marker*>(item)->setPen(pen); |
|
144 | 144 | } |
|
145 | 145 | } |
|
146 | 146 | |
|
147 | 147 | void ScatterChartItem::setBrush(const QBrush& brush) |
|
148 | 148 | { |
|
149 | 149 | foreach(QGraphicsItem* item , m_items.childItems()) { |
|
150 | 150 | static_cast<Marker*>(item)->setBrush(brush); |
|
151 | 151 | } |
|
152 | 152 | } |
|
153 | 153 | |
|
154 | 154 | void ScatterChartItem::handleUpdated() |
|
155 | 155 | { |
|
156 | 156 | |
|
157 | 157 | int count = m_items.childItems().count(); |
|
158 | 158 | |
|
159 | 159 | if(count==0) return; |
|
160 | 160 | |
|
161 | 161 | bool recreate = m_size != m_series->size() || m_shape != m_series->shape(); |
|
162 | 162 | |
|
163 | 163 | //TODO: only rewrite on size change |
|
164 | 164 | |
|
165 | 165 | m_size = m_series->size(); |
|
166 | 166 | m_shape = m_series->shape(); |
|
167 | 167 | |
|
168 | 168 | if(recreate){ |
|
169 | 169 | deletePoints(count); |
|
170 | 170 | createPoints(count); |
|
171 | 171 | } |
|
172 | 172 | |
|
173 | 173 | setPen(m_series->pen()); |
|
174 | 174 | setBrush(m_series->brush()); |
|
175 | 175 | |
|
176 | 176 | } |
|
177 | 177 | |
|
178 | void ScatterChartItem::mousePressEvent( QGraphicsSceneMouseEvent * event ) | |
|
179 | { | |
|
180 | } | |
|
181 | ||
|
182 | 178 | #include "moc_scatterchartitem_p.cpp" |
|
183 | 179 | |
|
184 | 180 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,120 +1,121 | |||
|
1 | 1 | #ifndef SCATTERPRESENTER_H |
|
2 | 2 | #define SCATTERPRESENTER_H |
|
3 | 3 | |
|
4 | 4 | #include "qchartglobal.h" |
|
5 | 5 | #include "xychartitem_p.h" |
|
6 | 6 | #include <QGraphicsEllipseItem> |
|
7 | 7 | #include <QPen> |
|
8 | 8 | |
|
9 | 9 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
10 | 10 | |
|
11 | 11 | class QScatterSeries; |
|
12 | 12 | class Marker; |
|
13 | 13 | |
|
14 | 14 | class ScatterChartItem : public XYChartItem |
|
15 | 15 | { |
|
16 | 16 | Q_OBJECT |
|
17 | 17 | public: |
|
18 | 18 | explicit ScatterChartItem(QScatterSeries *series, QGraphicsItem *parent = 0); |
|
19 | 19 | |
|
20 | 20 | public: |
|
21 | 21 | //from QGraphicsItem |
|
22 | 22 | QRectF boundingRect() const; |
|
23 | 23 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); |
|
24 | 24 | |
|
25 | 25 | void setPen(const QPen& pen); |
|
26 | 26 | void setBrush(const QBrush& brush); |
|
27 | 27 | |
|
28 | 28 | void markerSelected(Marker* item); |
|
29 | 29 | |
|
30 | 30 | public slots: |
|
31 | 31 | void handleUpdated(); |
|
32 | 32 | |
|
33 | 33 | private: |
|
34 | 34 | void createPoints(int count); |
|
35 | 35 | void deletePoints(int count); |
|
36 | 36 | |
|
37 | 37 | protected: |
|
38 | 38 | void setLayout(QVector<QPointF>& points); |
|
39 | 39 | void mousePressEvent( QGraphicsSceneMouseEvent * event ); |
|
40 | 40 | |
|
41 | 41 | private: |
|
42 | 42 | QScatterSeries *m_series; |
|
43 | 43 | QGraphicsItemGroup m_items; |
|
44 | 44 | int m_shape; |
|
45 | 45 | int m_size; |
|
46 | 46 | QRectF m_rect; |
|
47 | 47 | |
|
48 | 48 | }; |
|
49 | 49 | |
|
50 | 50 | |
|
51 | 51 | class Marker: public QAbstractGraphicsShapeItem |
|
52 | 52 | { |
|
53 | 53 | |
|
54 | 54 | public: |
|
55 | 55 | |
|
56 | 56 | Marker(QAbstractGraphicsShapeItem* item , ScatterChartItem* parent):QAbstractGraphicsShapeItem(0),m_item(item),m_parent(parent) |
|
57 | 57 | { |
|
58 | 58 | }; |
|
59 | 59 | |
|
60 | 60 | ~Marker() |
|
61 | 61 | { |
|
62 | 62 | delete m_item; |
|
63 | 63 | } |
|
64 | 64 | |
|
65 | 65 | void setIndex(int index) |
|
66 | 66 | { |
|
67 | 67 | m_index=index; |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | 70 | int index() const |
|
71 | 71 | { |
|
72 | 72 | return m_index; |
|
73 | 73 | } |
|
74 | 74 | |
|
75 | 75 | QPainterPath shape() const |
|
76 | 76 | { |
|
77 | 77 | return m_item->shape(); |
|
78 | 78 | } |
|
79 | 79 | |
|
80 | 80 | QRectF boundingRect() const |
|
81 | 81 | { |
|
82 | 82 | return m_item->boundingRect(); |
|
83 | 83 | } |
|
84 | 84 | |
|
85 | 85 | bool contains(const QPointF &point) const |
|
86 | 86 | { |
|
87 | 87 | return m_item->contains(point); |
|
88 | 88 | } |
|
89 | 89 | |
|
90 | 90 | void setPen(const QPen& pen) |
|
91 | 91 | { |
|
92 | 92 | m_item->setPen(pen); |
|
93 | 93 | } |
|
94 | 94 | |
|
95 | 95 | void setBrush(const QBrush& brush) |
|
96 | 96 | { |
|
97 | 97 | m_item->setBrush(brush); |
|
98 | 98 | } |
|
99 | 99 | |
|
100 | 100 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
101 | 101 | { |
|
102 | 102 | m_item->paint(painter,option,widget); |
|
103 | 103 | } |
|
104 | 104 | |
|
105 | 105 | protected: |
|
106 | 106 | |
|
107 | 107 |
void mousePressEvent( |
|
108 | 108 | { |
|
109 | Q_UNUSED(event) | |
|
109 | 110 | m_parent->markerSelected(this); |
|
110 | 111 | } |
|
111 | 112 | |
|
112 | 113 | private: |
|
113 | 114 | QAbstractGraphicsShapeItem* m_item; |
|
114 | 115 | ScatterChartItem* m_parent; |
|
115 | 116 | int m_index; |
|
116 | 117 | }; |
|
117 | 118 | |
|
118 | 119 | QTCOMMERCIALCHART_END_NAMESPACE |
|
119 | 120 | |
|
120 | 121 | #endif // SCATTERPRESENTER_H |
@@ -1,89 +1,90 | |||
|
1 | 1 | #include "splinechartitem_p.h" |
|
2 | 2 | #include "chartpresenter_p.h" |
|
3 | 3 | #include <QPainter> |
|
4 | 4 | |
|
5 | 5 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
6 | 6 | |
|
7 | 7 | SplineChartItem::SplineChartItem(QSplineSeries* series, QGraphicsItem *parent) : |
|
8 | 8 | XYChartItem(series, parent), |
|
9 | 9 | m_series(series), |
|
10 | 10 | m_pointsVisible(false) |
|
11 | 11 | { |
|
12 | 12 | setZValue(ChartPresenter::LineChartZValue); |
|
13 | 13 | QObject::connect(series,SIGNAL(updated()),this,SLOT(handleUpdated())); |
|
14 | 14 | handleUpdated(); |
|
15 | 15 | } |
|
16 | 16 | |
|
17 | 17 | QRectF SplineChartItem::boundingRect() const |
|
18 | 18 | { |
|
19 | 19 | return m_rect; |
|
20 | 20 | } |
|
21 | 21 | |
|
22 | 22 | QPainterPath SplineChartItem::shape() const |
|
23 | 23 | { |
|
24 | 24 | return m_path; |
|
25 | 25 | } |
|
26 | 26 | |
|
27 | 27 | QPointF SplineChartItem::calculateGeometryControlPoint(int index) const |
|
28 | 28 | { |
|
29 | 29 | return XYChartItem::calculateGeometryPoint(m_series->controlPoint(index)); |
|
30 | 30 | } |
|
31 | 31 | |
|
32 | 32 | void SplineChartItem::setLayout(QVector<QPointF>& points) |
|
33 | 33 | { |
|
34 | 34 | |
|
35 | 35 | if(points.size()==0) |
|
36 | 36 | { |
|
37 | 37 | XYChartItem::setLayout(points); |
|
38 | 38 | return; |
|
39 | 39 | } |
|
40 | 40 | |
|
41 | 41 | QPainterPath splinePath; |
|
42 | 42 | const QPointF& point = points.at(0); |
|
43 | 43 | splinePath.moveTo(point); |
|
44 | 44 | |
|
45 | 45 | for (int i = 0; i < points.size() - 1; i++) |
|
46 | 46 | { |
|
47 | 47 | const QPointF& point = points.at(i + 1); |
|
48 | 48 | splinePath.cubicTo(calculateGeometryControlPoint(2 * i), calculateGeometryControlPoint(2 * i + 1), point); |
|
49 | 49 | } |
|
50 | 50 | |
|
51 | 51 | prepareGeometryChange(); |
|
52 | 52 | m_path = splinePath; |
|
53 | 53 | m_rect = splinePath.boundingRect(); |
|
54 | 54 | XYChartItem::setLayout(points); |
|
55 | 55 | } |
|
56 | 56 | |
|
57 | 57 | //handlers |
|
58 | 58 | |
|
59 | 59 | void SplineChartItem::handleUpdated() |
|
60 | 60 | { |
|
61 | 61 | m_pointsVisible = m_series->pointsVisible(); |
|
62 | 62 | m_linePen = m_series->pen(); |
|
63 | 63 | m_pointPen = m_series->pen(); |
|
64 | 64 | m_pointPen.setWidthF(2*m_pointPen.width()); |
|
65 | 65 | update(); |
|
66 | 66 | } |
|
67 | 67 | |
|
68 | 68 | //painter |
|
69 | 69 | |
|
70 | 70 | void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
|
71 | 71 | { |
|
72 |
Q_UNUSED(widget) |
|
|
73 |
Q_UNUSED(option) |
|
|
72 | Q_UNUSED(widget) | |
|
73 | Q_UNUSED(option) | |
|
74 | ||
|
74 | 75 | painter->save(); |
|
75 | 76 | painter->setClipRect(clipRect()); |
|
76 | 77 | painter->setPen(m_linePen); |
|
77 | 78 | painter->drawPath(m_path); |
|
78 | 79 | if(m_pointsVisible){ |
|
79 | 80 | painter->setPen(m_pointPen); |
|
80 | 81 | painter->drawPoints(points()); |
|
81 | 82 | } |
|
82 | 83 | painter->restore(); |
|
83 | 84 | } |
|
84 | 85 | |
|
85 | 86 | |
|
86 | 87 | |
|
87 | 88 | #include "moc_splinechartitem_p.cpp" |
|
88 | 89 | |
|
89 | 90 | QTCOMMERCIALCHART_END_NAMESPACE |
@@ -1,312 +1,318 | |||
|
1 | 1 | #include "qxyseries.h" |
|
2 | 2 | |
|
3 | 3 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
4 | 4 | |
|
5 | 5 | /*! |
|
6 | 6 | \class QXYSeries |
|
7 | 7 | \brief The QXYSeries class is a base class for line, spline and scatter series. |
|
8 | 8 | */ |
|
9 | 9 | |
|
10 | 10 | /*! |
|
11 | 11 | \fn QPen QXYSeries::pen() const |
|
12 | 12 | \brief Returns pen used to draw points for series. |
|
13 | 13 | \sa setPen() |
|
14 | 14 | */ |
|
15 | 15 | |
|
16 | 16 | /*! |
|
17 | 17 | \fn QBrush QXYSeries::brush() const |
|
18 | 18 | \brief Returns brush used to draw points for series. |
|
19 | 19 | \sa setBrush() |
|
20 | 20 | */ |
|
21 | 21 | |
|
22 | 22 | /*! |
|
23 | 23 | \fn void QXYSeries::clicked(const QPointF& point) |
|
24 | 24 | \brief Signal is emitted when user clicks the \a point on chart. |
|
25 | 25 | */ |
|
26 | 26 | |
|
27 | 27 | /*! |
|
28 | 28 | \fn void QXYSeries::pointReplaced(int index) |
|
29 | 29 | \brief \internal \a index |
|
30 | 30 | */ |
|
31 | 31 | |
|
32 | 32 | /*! |
|
33 | 33 | \fn void QXYSeries::pointAdded(int index) |
|
34 | 34 | \brief \internal \a index |
|
35 | 35 | */ |
|
36 | 36 | |
|
37 | 37 | /*! |
|
38 | 38 | \fn void QXYSeries::pointRemoved(int index) |
|
39 | 39 | \brief \internal \a index |
|
40 | 40 | */ |
|
41 | 41 | |
|
42 | 42 | /*! |
|
43 | 43 | \fn void QXYSeries::updated() |
|
44 | 44 | \brief \internal |
|
45 | 45 | */ |
|
46 | 46 | |
|
47 | 47 | /*! |
|
48 | 48 | Constructs empty series object which is a child of \a parent. |
|
49 | 49 | When series object is added to QChartView or QChart instance ownerships is transfered. |
|
50 | 50 | */ |
|
51 | 51 | QXYSeries::QXYSeries(QObject* parent):QSeries(parent) |
|
52 | 52 | { |
|
53 | 53 | m_mapX = -1; |
|
54 | 54 | m_mapY = -1; |
|
55 | 55 | m_mapOrientation = Qt::Vertical; |
|
56 | 56 | // m_mapYOrientation = Qt::Vertical; |
|
57 | 57 | } |
|
58 | 58 | /*! |
|
59 | 59 | Destroys the object. Series added to QChartView or QChart instances are owned by those, |
|
60 | 60 | and are deleted when mentioned object are destroyed. |
|
61 | 61 | */ |
|
62 | 62 | QXYSeries::~QXYSeries() |
|
63 | 63 | { |
|
64 | 64 | } |
|
65 | 65 | |
|
66 | 66 | /*! |
|
67 | 67 | Adds data point \a x \a y to the series. Points are connected with lines on the chart. |
|
68 | 68 | */ |
|
69 | 69 | void QXYSeries::add(qreal x,qreal y) |
|
70 | 70 | { |
|
71 | 71 | Q_ASSERT(m_x.size() == m_y.size()); |
|
72 | 72 | m_x<<x; |
|
73 | 73 | m_y<<y; |
|
74 | 74 | emit pointAdded(m_x.size()-1); |
|
75 | 75 | } |
|
76 | 76 | |
|
77 | 77 | /*! |
|
78 | 78 | This is an overloaded function. |
|
79 | 79 | Adds data \a point to the series. Points are connected with lines on the chart. |
|
80 | 80 | */ |
|
81 | 81 | void QXYSeries::add(const QPointF& point) |
|
82 | 82 | { |
|
83 | 83 | add(point.x(),point.y()); |
|
84 | 84 | } |
|
85 | 85 | |
|
86 | 86 | /*! |
|
87 | 87 | This is an overloaded function. |
|
88 | 88 | Adds list of data \a points to the series. Points are connected with lines on the chart. |
|
89 | 89 | */ |
|
90 | 90 | void QXYSeries::add(const QList<QPointF> points) |
|
91 | 91 | { |
|
92 | 92 | foreach(const QPointF& point , points) { |
|
93 | 93 | add(point.x(),point.y()); |
|
94 | 94 | } |
|
95 | 95 | } |
|
96 | 96 | |
|
97 | 97 | /*! |
|
98 | 98 | Modifies \a y value for given \a x a value. |
|
99 | 99 | */ |
|
100 | 100 | void QXYSeries::replace(qreal x,qreal y) |
|
101 | 101 | { |
|
102 | 102 | int index = m_x.indexOf(x); |
|
103 | 103 | m_x[index]=x; |
|
104 | 104 | m_y[index]=y; |
|
105 | 105 | emit pointReplaced(index); |
|
106 | 106 | } |
|
107 | 107 | |
|
108 | 108 | /*! |
|
109 | 109 | This is an overloaded function. |
|
110 | 110 | Replaces current y value of for given \a point x value with \a point y value. |
|
111 | 111 | */ |
|
112 | 112 | void QXYSeries::replace(const QPointF& point) |
|
113 | 113 | { |
|
114 | 114 | replace(point.x(),point.y()); |
|
115 | 115 | } |
|
116 | 116 | |
|
117 | 117 | /*! |
|
118 | 118 | Removes current \a x and \a y value. |
|
119 | 119 | */ |
|
120 | 120 | void QXYSeries::remove(qreal x,qreal y) |
|
121 | 121 | { |
|
122 | 122 | int index =-1; |
|
123 | 123 | do{ |
|
124 | 124 | index = m_x.indexOf(x,index+1); |
|
125 | 125 | }while(index !=-1 && m_y.at(index)!=y); |
|
126 | 126 | |
|
127 | 127 | if(index==-1) return; |
|
128 | 128 | |
|
129 | 129 | m_x.remove(index); |
|
130 | 130 | m_y.remove(index); |
|
131 | 131 | emit pointRemoved(index); |
|
132 | 132 | } |
|
133 | 133 | |
|
134 | 134 | /*! |
|
135 | 135 | Removes current \a point x value. Note \a point y value is ignored. |
|
136 | 136 | */ |
|
137 | 137 | void QXYSeries::remove(const QPointF& point) |
|
138 | 138 | { |
|
139 | 139 | remove(point.x(),point.y()); |
|
140 | 140 | } |
|
141 | 141 | |
|
142 | 142 | /*! |
|
143 | 143 | Removes all data points from the series. |
|
144 | 144 | */ |
|
145 | 145 | void QXYSeries::removeAll() |
|
146 | 146 | { |
|
147 | 147 | m_x.clear(); |
|
148 | 148 | m_y.clear(); |
|
149 | 149 | } |
|
150 | 150 | |
|
151 | 151 | /*! |
|
152 | 152 | \internal \a pos |
|
153 | 153 | */ |
|
154 | 154 | qreal QXYSeries::x(int pos) const |
|
155 | 155 | { |
|
156 | 156 | if (m_model) |
|
157 | 157 | if (m_mapOrientation == Qt::Vertical) |
|
158 | 158 | // consecutive data is read from model's column |
|
159 | 159 | return m_model->data(m_model->index(pos, m_mapX), Qt::DisplayRole).toDouble(); |
|
160 | 160 | else |
|
161 | 161 | // consecutive data is read from model's row |
|
162 | 162 | return m_model->data(m_model->index(m_mapX, pos), Qt::DisplayRole).toDouble(); |
|
163 | 163 | else |
|
164 | 164 | // model is not specified, return the data from series' internal data store |
|
165 | 165 | return m_x.at(pos); |
|
166 | 166 | } |
|
167 | 167 | |
|
168 | 168 | /*! |
|
169 | 169 | \internal \a pos |
|
170 | 170 | */ |
|
171 | 171 | qreal QXYSeries::y(int pos) const |
|
172 | 172 | { |
|
173 | 173 | if (m_model) |
|
174 | 174 | if (m_mapOrientation == Qt::Vertical) |
|
175 | 175 | // consecutive data is read from model's column |
|
176 | 176 | return m_model->data(m_model->index(pos, m_mapY), Qt::DisplayRole).toDouble(); |
|
177 | 177 | else |
|
178 | 178 | // consecutive data is read from model's row |
|
179 | 179 | return m_model->data(m_model->index(m_mapY, pos), Qt::DisplayRole).toDouble(); |
|
180 | 180 | else |
|
181 | 181 | // model is not specified, return the data from series' internal data store |
|
182 | 182 | return m_y.at(pos); |
|
183 | 183 | } |
|
184 | 184 | |
|
185 | 185 | /*! |
|
186 | 186 | Returns number of data points within series. |
|
187 | 187 | */ |
|
188 | 188 | int QXYSeries::count() const |
|
189 | 189 | { |
|
190 | 190 | Q_ASSERT(m_x.size() == m_y.size()); |
|
191 | 191 | |
|
192 | 192 | if (m_model) { |
|
193 | 193 | if (m_mapOrientation == Qt::Vertical) |
|
194 | 194 | // data is in a column, so return the number of items in single column |
|
195 | 195 | return m_model->rowCount(); |
|
196 | 196 | else |
|
197 | 197 | // data is in a row, so return the number of items in single row |
|
198 | 198 | return m_model->columnCount(); |
|
199 | 199 | } |
|
200 | 200 | |
|
201 | 201 | // model is not specified, return the number of points in the series internal data store |
|
202 | 202 | return m_x.size(); |
|
203 | 203 | } |
|
204 | 204 | |
|
205 | 205 | /*! |
|
206 | 206 | Returns the data points of the series. |
|
207 | 207 | */ |
|
208 | 208 | QList<QPointF> QXYSeries::data() |
|
209 | 209 | { |
|
210 | 210 | QList<QPointF> data; |
|
211 | 211 | for (int i(0); i < m_x.count() && i < m_y.count(); i++) |
|
212 | 212 | data.append(QPointF(m_x.at(i), m_y.at(i))); |
|
213 | 213 | return data; |
|
214 | 214 | } |
|
215 | 215 | |
|
216 | 216 | |
|
217 | 217 | /*! |
|
218 | 218 | Sets \a pen used for drawing points on the chart. If the pen is not defined, the |
|
219 | 219 | pen from chart theme is used. |
|
220 | 220 | \sa QChart::setChartTheme() |
|
221 | 221 | */ |
|
222 | 222 | void QXYSeries::setPen(const QPen& pen) |
|
223 | 223 | { |
|
224 | 224 | if(pen!=m_pen){ |
|
225 | 225 | m_pen=pen; |
|
226 | 226 | emit updated(); |
|
227 | 227 | } |
|
228 | 228 | } |
|
229 | 229 | |
|
230 | 230 | /*! |
|
231 | 231 | Sets \a brush used for drawing points on the chart. If the brush is not defined, brush |
|
232 | 232 | from chart theme setting is used. |
|
233 | 233 | \sa QChart::setChartTheme() |
|
234 | 234 | */ |
|
235 | 235 | |
|
236 | 236 | void QXYSeries::setBrush(const QBrush& brush) |
|
237 | 237 | { |
|
238 | 238 | if(brush!=m_brush){ |
|
239 | 239 | m_brush=brush; |
|
240 | 240 | emit updated(); |
|
241 | 241 | } |
|
242 | 242 | } |
|
243 | 243 | |
|
244 | 244 | |
|
245 | 245 | /*! |
|
246 | 246 | Stream operator for adding a data \a point to the series. |
|
247 | 247 | \sa add() |
|
248 | 248 | */ |
|
249 | 249 | |
|
250 | 250 | QXYSeries& QXYSeries::operator<< (const QPointF &point) |
|
251 | 251 | { |
|
252 | 252 | add(point); |
|
253 | 253 | return *this; |
|
254 | 254 | } |
|
255 | 255 | |
|
256 | 256 | |
|
257 | 257 | /*! |
|
258 | 258 | Stream operator for adding a list of \a points to the series. |
|
259 | 259 | \sa add() |
|
260 | 260 | */ |
|
261 | 261 | |
|
262 | 262 | QXYSeries& QXYSeries::operator<< (const QList<QPointF> points) |
|
263 | 263 | { |
|
264 | 264 | add(points); |
|
265 | 265 | return *this; |
|
266 | 266 | } |
|
267 | 267 | |
|
268 | 268 | |
|
269 | 269 | void QXYSeries::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight) |
|
270 | 270 | { |
|
271 | Q_UNUSED(bottomRight) | |
|
272 | ||
|
271 | 273 | if (m_mapOrientation == Qt::Vertical) |
|
272 | 274 | emit pointReplaced(topLeft.row()); |
|
273 | 275 | else |
|
274 | 276 | emit pointReplaced(topLeft.column()); |
|
275 | 277 | } |
|
276 | 278 | |
|
277 | 279 | void QXYSeries::modelDataAdded(QModelIndex parent, int start, int end) |
|
278 | 280 | { |
|
281 | Q_UNUSED(parent) | |
|
282 | Q_UNUSED(end) | |
|
279 | 283 | emit pointAdded(start); |
|
280 | 284 | } |
|
281 | 285 | |
|
282 | 286 | void QXYSeries::modelDataRemoved(QModelIndex parent, int start, int end) |
|
283 | 287 | { |
|
288 | Q_UNUSED(parent) | |
|
289 | Q_UNUSED(end) | |
|
284 | 290 | emit pointRemoved(start); |
|
285 | 291 | } |
|
286 | 292 | |
|
287 | 293 | bool QXYSeries::setModel(QAbstractItemModel* model) { |
|
288 | 294 | m_model = model; |
|
289 | 295 | // for (int i = 0; i < m_model->rowCount(); i++) |
|
290 | 296 | // emit pointAdded(i); |
|
291 | 297 | connect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex, QModelIndex))); |
|
292 | 298 | connect(m_model,SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(modelDataAdded(QModelIndex,int,int))); |
|
293 | 299 | connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(modelDataRemoved(QModelIndex,int,int))); |
|
294 | 300 | return true; |
|
295 | 301 | } |
|
296 | 302 | |
|
297 | 303 | void QXYSeries::setModelMapping(int modelX, int modelY, Qt::Orientation orientation) |
|
298 | 304 | { |
|
299 | 305 | m_mapX = modelX; |
|
300 | 306 | m_mapY = modelY; |
|
301 | 307 | m_mapOrientation = orientation; |
|
302 | 308 | } |
|
303 | 309 | |
|
304 | 310 | //void QXYSeries::setModelMappingY(int modelLineIndex, Qt::Orientation orientation) |
|
305 | 311 | //{ |
|
306 | 312 | // m_mapY = modelLineIndex; |
|
307 | 313 | // m_mapYOrientation = orientation; |
|
308 | 314 | //} |
|
309 | 315 | |
|
310 | 316 | #include "moc_qxyseries.cpp" |
|
311 | 317 | |
|
312 | 318 | QTCOMMERCIALCHART_END_NAMESPACE |
General Comments 0
You need to be logged in to leave comments.
Login now