##// END OF EJS Templates
Marek Rosa -
r461:5973afc43f62 merge
parent child
Show More
1 NO CONTENT: modified file, binary diff hidden
@@ -1,373 +1,371
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 //series
7 7 #include "qbarseries.h"
8 8 #include "qstackedbarseries.h"
9 9 #include "qpercentbarseries.h"
10 10 #include "qlineseries.h"
11 11 #include "qareaseries.h"
12 12 #include "qpieseries.h"
13 13 #include "qscatterseries.h"
14 14 #include "qsplineseries.h"
15 15 //items
16 16 #include "axisitem_p.h"
17 17 #include "axisanimationitem_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 "linechartanimationitem_p.h"
24 24 #include "piepresenter_p.h"
25 25 #include "scatterpresenter_p.h"
26 26 #include "splinechartitem_p.h"
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart),
31 31 m_chart(chart),
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 }
46 46
47 47 void ChartPresenter::createConnections()
48 48 {
49 49 QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged()));
50 50 QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),this,SLOT(handleSeriesAdded(QSeries*,Domain*)));
51 51 QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*)));
52 52 QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*,Domain*)),this,SLOT(handleAxisAdded(QChartAxis*,Domain*)));
53 53 QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*)));
54 54 }
55 55
56 56
57 57 QRectF ChartPresenter::geometry() const
58 58 {
59 59 return m_rect;
60 60 }
61 61
62 62 void ChartPresenter::handleGeometryChanged()
63 63 {
64 64 QRectF rect(QPoint(0,0),m_chart->size());
65 65 rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
66 66
67 67 //rewrite zoom stack
68 68 for(int i=0;i<m_zoomStack.count();i++){
69 69 QRectF r = m_zoomStack[i];
70 70 qreal w = rect.width()/m_rect.width();
71 71 qreal h = rect.height()/m_rect.height();
72 72 QPointF tl = r.topLeft();
73 73 tl.setX(tl.x()*w);
74 74 tl.setY(tl.y()*h);
75 75 QPointF br = r.bottomRight();
76 76 br.setX(br.x()*w);
77 77 br.setY(br.y()*h);
78 78 r.setTopLeft(tl);
79 79 r.setBottomRight(br);
80 80 m_zoomStack[i]=r;
81 81 }
82 82
83 83 m_rect = rect;
84 84 Q_ASSERT(m_rect.isValid());
85 85 emit geometryChanged(m_rect);
86 86 }
87 87
88 88 int ChartPresenter::margin() const
89 89 {
90 90 return m_marginSize;
91 91 }
92 92
93 93 void ChartPresenter::setMargin(int margin)
94 94 {
95 95 m_marginSize = margin;
96 96 }
97 97
98 98 void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain)
99 99 {
100 100
101 101 AxisItem* item ;
102 102
103 103 if(!m_options.testFlag(QChart::GridAxisAnimations))
104 104 {
105 105 item = new AxisItem(axis,axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
106 106 }else{
107 107 item = new AxisAnimationItem(axis,axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
108 108 }
109 109 if(axis==m_dataset->axisX()){
110 110 QObject::connect(domain,SIGNAL(rangeXChanged(qreal,qreal)),item,SLOT(handleRangeChanged(qreal,qreal)));
111 111 //initialize
112 112 item->handleRangeChanged(domain->minX(),domain->maxX());
113 113 item->handleTicksCountChanged(4);
114 114 }
115 115 else{
116 116 QObject::connect(domain,SIGNAL(rangeYChanged(qreal,qreal)),item,SLOT(handleRangeChanged(qreal,qreal)));
117 117 //initialize
118 118 item->handleRangeChanged(domain->minY(),domain->maxY());
119 119 item->handleTicksCountChanged(4);
120 120 }
121 121
122 122 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
123 123 //initialize
124 124 item->handleGeometryChanged(m_rect);
125 125 m_chartTheme->decorate(axis,item);
126 126 m_axisItems.insert(axis,item);
127 127 }
128 128
129 129 void ChartPresenter::handleAxisRemoved(QChartAxis* axis)
130 130 {
131 131 AxisItem* item = m_axisItems.take(axis);
132 132 Q_ASSERT(item);
133 133 delete item;
134 134 }
135 135
136 136
137 137 void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain)
138 138 {
139 139 switch(series->type())
140 140 {
141 141 case QSeries::SeriesTypeLine: {
142 142
143 143 QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
144 144 LineChartItem* item;
145 145 if(m_options.testFlag(QChart::SeriesAnimations)){
146 146 item = new LineChartAnimationItem(lineSeries,m_chart);
147 147 }else{
148 148 item = new LineChartItem(lineSeries,m_chart);
149 149 }
150 150 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
151 151 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),item,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
152 152 //initialize
153 153 item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY());
154 154 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
155 155 //decorate
156 156 m_chartTheme->decorate(item,lineSeries,m_chartItems.count());
157 157 m_chartItems.insert(series,item);
158 158 break;
159 159 }
160 160
161 161 case QSeries::SeriesTypeArea: {
162 162
163 163 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
164 164 AreaChartItem* item;
165 165 if(m_options.testFlag(QChart::SeriesAnimations)) {
166 166 item = new AreaChartItem(areaSeries,m_chart);
167 167 }
168 168 else {
169 169 item = new AreaChartItem(areaSeries,m_chart);
170 170 }
171 171 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
172 172 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),item,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
173 173 //initialize
174 174 item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY());
175 175 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
176 176 //decorate
177 177 m_chartTheme->decorate(item,areaSeries,m_chartItems.count());
178 178 m_chartItems.insert(series,item);
179 179 break;
180 180 }
181 181
182 182 case QSeries::SeriesTypeBar: {
183 183 QBarSeries* barSeries = static_cast<QBarSeries*>(series);
184 184 BarPresenter* item = new BarPresenter(barSeries,m_chart);
185 185 m_chartTheme->decorate(item,barSeries,m_chartItems.count());
186 186 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
187 187 // QObject::connect(barSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
188 188 m_chartItems.insert(series,item);
189 189 // m_axisXItem->setVisible(false);
190 190 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
191 191 break;
192 192 }
193 193
194 194 case QSeries::SeriesTypeStackedBar: {
195 195
196 196 QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
197 197 StackedBarPresenter* item = new StackedBarPresenter(stackedBarSeries,m_chart);
198 198 m_chartTheme->decorate(item,stackedBarSeries,m_chartItems.count());
199 199 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
200 200 // QObject::connect(stackedBarSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
201 201 m_chartItems.insert(series,item);
202 202 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
203 203 break;
204 204 }
205 205
206 206 case QSeries::SeriesTypePercentBar: {
207 207
208 208 QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
209 209 PercentBarPresenter* item = new PercentBarPresenter(percentBarSeries,m_chart);
210 210 m_chartTheme->decorate(item,percentBarSeries ,m_chartItems.count());
211 211 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
212 212 // QObject::connect(percentBarSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
213 213 m_chartItems.insert(series,item);
214 214 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
215 215 break;
216 216 }
217 217 case QSeries::SeriesTypeScatter: {
218 218 QScatterSeries *scatterSeries = qobject_cast<QScatterSeries *>(series);
219 219 ScatterPresenter *scatterPresenter = new ScatterPresenter(scatterSeries, m_chart);
220 QObject::connect(scatterPresenter, SIGNAL(clicked(QPointF)),
221 scatterSeries, SIGNAL(clicked(QPointF)));
222 220 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)),
223 221 scatterPresenter, SLOT(handleGeometryChanged(const QRectF&)));
224 222 QObject::connect(domain, SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),
225 223 scatterPresenter, SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
226 224 m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count());
227 225 m_chartItems.insert(scatterSeries, scatterPresenter);
228 226 if (m_rect.isValid())
229 227 scatterPresenter->handleGeometryChanged(m_rect);
230 228 scatterPresenter->handleDomainChanged(domain->minX(), domain->maxX(), domain->minY(), domain->maxY());
231 229 break;
232 230 }
233 231 case QSeries::SeriesTypePie: {
234 232 QPieSeries *s = qobject_cast<QPieSeries *>(series);
235 233 PiePresenter* pie = new PiePresenter(m_chart, s);
236 234 m_chartTheme->decorate(pie, s, m_chartItems.count());
237 235 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), pie, SLOT(handleGeometryChanged(const QRectF&)));
238 236
239 237 // Hide all from background when there is only piechart
240 238 // TODO: refactor this ugly code... should be one setting for this
241 239 if (m_chartItems.count() == 0) {
242 240 m_chart->axisX()->setAxisVisible(false);
243 241 m_chart->axisY()->setAxisVisible(false);
244 242 m_chart->axisX()->setGridVisible(false);
245 243 m_chart->axisY()->setGridVisible(false);
246 244 m_chart->axisX()->setLabelsVisible(false);
247 245 m_chart->axisY()->setLabelsVisible(false);
248 246 m_chart->axisX()->setShadesVisible(false);
249 247 m_chart->axisY()->setShadesVisible(false);
250 248 m_chart->setChartBackgroundBrush(Qt::transparent);
251 249 }
252 250
253 251 m_chartItems.insert(series, pie);
254 252 pie->handleGeometryChanged(m_rect);
255 253 break;
256 254 }
257 255
258 256 case QSeries::SeriesTypeSpline: {
259 257 QSplineSeries* splineSeries = qobject_cast<QSplineSeries*>(series);
260 258 SplineChartItem* splinePresenter = new SplineChartItem(splineSeries, m_chart);
261 259 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), splinePresenter, SLOT(handleGeometryChanged(const QRectF&)));
262 260 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),splinePresenter,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
263 261 //initialize
264 262 splinePresenter->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY());
265 263 m_chartTheme->decorate(splinePresenter, splineSeries, m_chartItems.count());
266 264 m_chartItems.insert(splineSeries, splinePresenter);
267 265 break;
268 266 }
269 267 default: {
270 268 qDebug()<< "Series type" << series->type() << "not implemented.";
271 269 break;
272 270 }
273 271 }
274 272
275 273 zoomReset();
276 274 }
277 275
278 276 void ChartPresenter::handleSeriesRemoved(QSeries* series)
279 277 {
280 278 ChartItem* item = m_chartItems.take(series);
281 279 delete item;
282 280 }
283 281
284 282 void ChartPresenter::setChartTheme(QChart::ChartTheme theme)
285 283 {
286 284 delete m_chartTheme;
287 285
288 286 m_chartTheme = ChartTheme::createTheme(theme);
289 287
290 288 m_chartTheme->decorate(m_chart);
291 289 QMapIterator<QSeries*,ChartItem*> i(m_chartItems);
292 290
293 291 int index=0;
294 292 while (i.hasNext()) {
295 293 i.next();
296 294 m_chartTheme->decorate(i.value(),i.key(),index);
297 295 index++;
298 296 }
299 297
300 298 QMapIterator<QChartAxis*,AxisItem*> j(m_axisItems);
301 299 while (j.hasNext()) {
302 300 j.next();
303 301 m_chartTheme->decorate(j.key(),j.value());
304 302 }
305 303 }
306 304
307 305 QChart::ChartTheme ChartPresenter::chartTheme()
308 306 {
309 307 return m_chartTheme->id();
310 308 }
311 309
312 310 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
313 311 {
314 312 if(m_options!=options) {
315 313
316 314 m_options=options;
317 315
318 316 //recreate elements
319 317 QList<QChartAxis*> axisList = m_axisItems.uniqueKeys();
320 318 QList<QSeries*> seriesList = m_chartItems.uniqueKeys();
321 319
322 320 foreach(QChartAxis* axis, axisList) {
323 321 handleAxisRemoved(axis);
324 322 handleAxisAdded(axis,m_dataset->domain(axis));
325 323 }
326 324 foreach(QSeries* series, seriesList) {
327 325 handleSeriesRemoved(series);
328 326 handleSeriesAdded(series,m_dataset->domain(series));
329 327 }
330 328 }
331 329 }
332 330
333 331 void ChartPresenter::zoomIn()
334 332 {
335 333 QRectF rect = geometry();
336 334 rect.setWidth(rect.width()/2);
337 335 rect.setHeight(rect.height()/2);
338 336 rect.moveCenter(geometry().center());
339 337 zoomIn(rect);
340 338 }
341 339
342 340 void ChartPresenter::zoomIn(const QRectF& rect)
343 341 {
344 342 QRectF r = rect.normalized();
345 343 r.translate(-m_marginSize, -m_marginSize);
346 344 m_dataset->zoomInDomain(r,geometry().size());
347 345 m_zoomStack<<r;
348 346 m_zoomIndex++;
349 347 }
350 348
351 349 void ChartPresenter::zoomOut()
352 350 {
353 351 if(m_zoomIndex==0) return;
354 352 m_dataset->zoomOutDomain(m_zoomStack[m_zoomIndex-1],geometry().size());
355 353 m_zoomIndex--;
356 354 m_zoomStack.resize(m_zoomIndex);
357 355 }
358 356
359 357 void ChartPresenter::zoomReset()
360 358 {
361 359 m_zoomIndex=0;
362 360 m_zoomStack.resize(m_zoomIndex);
363 361 }
364 362
365 363 QChart::AnimationOptions ChartPresenter::animationOptions() const
366 364 {
367 365 return m_options;
368 366 }
369 367
370 368
371 369 #include "moc_chartpresenter_p.cpp"
372 370
373 371 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,298 +1,305
1 1 #include "qscatterseries.h"
2 2 #include "scatterseries_p.h"
3 3 #include "qchart.h"
4 4
5 5 /*!
6 6 \class QScatterSeries
7 7 \brief QtCommercial Chart series API for showing scatter series.
8 8
9 9 \mainclass
10 10
11 11 Example on how to create a chart with scatter series:
12 12 \snippet ../example/scatter/main.cpp 1
13 13
14 14 The example code would result the following:
15 15
16 16 \image scatter_example1.jpg
17 17
18 18 To customize the graphical representation of the series, you can modify pen, brush, shape and
19 19 size of the marker items. For example:
20 20
21 21 \snippet ../example/scatter/main.cpp 3
22 22
23 23 Would present your scatter markers as big rectangles with opaque, uglyish green outlines and
24 24 opaque red filling instead of the beatiful markers defined by the chart's theme:
25 25 \image scatter_example_custom.jpg
26 26 */
27 27
28 28 /*!
29 29 \enum QScatterSeries::MarkerShape
30 30
31 31 This enum describes the shape used when rendering marker items.
32 32
33 33 \value MarkerShapeDefault
34 34 \value MarkerShapeX
35 35 \value MarkerShapeRectangle
36 \value MarkerShapeRoundedRectangle
36 37 \value MarkerShapeTiltedRectangle
37 38 \value MarkerShapeTriangle
38 39 \value MarkerShapeCircle
39 40 */
40 41
41 42 /*!
42 43 \fn QChartSeriesType QScatterSeries::type() const
43 44 \brief Returns QChartSeries::SeriesTypeScatter.
44 45 */
45 46
46 47 /*!
47 48 \fn void QScatterSeries::clicked(QPointF coordinate)
48 49 User clicked the scatter series. Note that the \a coordinate is the chart coordinate that the
49 50 click occurred on; not necessarily a data point coordinate. To find the corresponding (closest)
50 51 data point you can use closestPoint().
51 52 */
52 53
53 /*!
54 \fn void QScatterSeries::changed()
55 \brief TODO
56 */
57
58 54 QTCOMMERCIALCHART_BEGIN_NAMESPACE
59 55
60 QScatterSeriesPrivate::QScatterSeriesPrivate() :
56 QScatterSeriesPrivate::QScatterSeriesPrivate(QObject *parent) :
57 QObject(parent),
61 58 m_data(QList<QPointF>()),
62 59 m_markerPen(QPen(QColor::Invalid)),
63 60 m_markerBrush(QBrush(QColor::Invalid)),
64 61 m_markerShape(QScatterSeries::MarkerShapeDefault),
65 62 m_markerSize(9.0)
66 63 {
67 64 }
68 65
66 void QScatterSeriesPrivate::emitChanged()
67 {
68 emit changed();
69 }
70
71 #include "moc_scatterseries_p.cpp"
72
69 73 /*!
70 74 Constructs a series object which is a child of \a parent.
71 75 */
72 76 QScatterSeries::QScatterSeries(QObject *parent) :
73 77 QSeries(parent),
74 d(new QScatterSeriesPrivate())
78 d(new QScatterSeriesPrivate(this))
75 79 {
76 80 }
77 81
78 82 /*!
79 83 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
80 84 */
81 85 QScatterSeries::~QScatterSeries()
82 86 {
83 87 delete d;
84 88 }
85 89
86 90 /*!
87 91 Add single data point with \a x and \a y coordinates to the series.
88 92 */
89 93 void QScatterSeries::add(qreal x, qreal y)
90 94 {
91 95 d->m_data.append(QPointF(x, y));
92 emit changed();
96 d->emitChanged();
93 97 }
94 98
95 99 /*!
96 100 Add single data point with \a value to the series.
97 101 */
98 102 void QScatterSeries::add(QPointF value)
99 103 {
100 104 d->m_data.append(value);
101 emit changed();
105 d->emitChanged();
102 106 }
103 107
104 108 /*!
105 109 Add list of \a points to the series.
106 110 */
107 111 void QScatterSeries::add(QList<QPointF> points)
108 112 {
109 113 d->m_data.append(points);
110 emit changed();
114 d->emitChanged();
111 115 }
112 116
113 117 /*!
114 118 Stream operator for adding a data point with \a value to the series.
115 119 \sa add()
116 120
117 121 For example:
118 122 \snippet ../example/scatter/main.cpp 2
119 123 */
120 124 QScatterSeries& QScatterSeries::operator << (const QPointF &value)
121 125 {
122 126 d->m_data.append(value);
123 emit changed();
127 d->emitChanged();
124 128 return *this;
125 129 }
126 130
127 131 /*!
128 132 Stream operator for adding a list of points to the series.
129 133 \sa add()
130 134 */
131 135 QScatterSeries& QScatterSeries::operator << (QList<QPointF> value)
132 136 {
133 137 d->m_data.append(value);
134 emit changed();
138 d->emitChanged();
135 139 return *this;
136 140 }
137 141
138 142 /*!
139 143 Replaces the data of the series with the given list of data \a points.
140 144 */
141 145 void QScatterSeries::setData(QList<QPointF> points)
142 146 {
143 147 d->m_data = points;
144 emit changed();
148 d->emitChanged();
145 149 }
146 150
147 151 /*!
148 152 Returns the current list of data points of the series.
149 153 */
150 154 QList<QPointF> QScatterSeries::data()
151 155 {
152 156 return d->m_data;
153 157 }
154 158
155 159 /*!
156 160 Replaces the point at \a index with \a newPoint. Returns true if \a index is a valid position
157 161 in the series data, false otherwise.
158 162 */
159 163 bool QScatterSeries::replace(int index, QPointF newPoint)
160 164 {
161 165 if (index >= 0 && index < d->m_data.count()) {
162 166 d->m_data.replace(index, newPoint);
163 emit changed();
167 d->emitChanged();
164 168 return true;
165 169 }
166 170 return false;
167 171 }
168 172
169 173 /*!
170 174 Remove the data point at \a index. Returns true if a point was removed, false if the point
171 175 at \a index does not exist on the series.
172 176 */
173 177 bool QScatterSeries::removeAt(int index)
174 178 {
175 179 if (index >=0 && index < d->m_data.count()) {
176 180 d->m_data.removeAt(index);
177 emit changed();
181 d->emitChanged();
178 182 return true;
179 183 }
180 184 return false;
181 185 }
182 186
183 187 /*!
184 188 Remove all occurrences of \a point from the series and returns the number of points removed.
185 189 */
186 190 int QScatterSeries::removeAll(QPointF point)
187 191 {
188 192 int count = d->m_data.removeAll(point);
189 emit changed();
193 d->emitChanged();
190 194 return count;
191 195 }
192 196
193 197 /*!
194 198 Remove all data points from the series.
195 199 */
196 200 void QScatterSeries::clear()
197 201 {
198 202 d->m_data.clear();
199 emit changed();
203 d->emitChanged();
200 204 }
201 205
202 206 /*!
203 207 Returns the index of the data point that is closest to \a coordinate. If several data points
204 208 are at the same distance from the \a coordinate, returns the last one. If no points exist,
205 209 returns -1.
206 210 */
207 211 int QScatterSeries::closestPoint(QPointF coordinate)
208 212 {
209 213 qreal distance(-1);
210 214 int pointIndex(-1);
211 215 for (int i(0); i < d->m_data.count(); i++) {
212 216 QPointF dataPoint = d->m_data.at(i);
213 217 QPointF difference = dataPoint - coordinate;
214 218 if (i == 0 || difference.manhattanLength() <= distance) {
215 219 distance = difference.manhattanLength();
216 220 pointIndex = i;
217 221 }
218 222 }
219 223 return pointIndex;
220 224 }
221 225
222 226 /*!
227 Returns the pen used for drawing markers.
228 */
229 QPen QScatterSeries::pen() const
230 {
231 return d->m_markerPen;
232 }
233
234 /*!
223 235 Overrides the default pen used for drawing a marker item with a user defined \a pen. The
224 236 default pen is defined by chart theme setting.
225 237
226 238 \sa setBrush()
227 239 \sa QChart::setChartTheme()
228 240 */
229 void QScatterSeries::setPen(QPen pen)
241 void QScatterSeries::setPen(const QPen &pen)
230 242 {
231 243 d->m_markerPen = pen;
244 d->emitChanged();
232 245 }
233 246
234 247 /*!
235 Returns the pen used for drawing markers.
248 Returns the brush used for drawing markers.
236 249 */
237 QPen QScatterSeries::pen()
250 QBrush QScatterSeries::brush() const
238 251 {
239 return d->m_markerPen;
252 return d->m_markerBrush;
240 253 }
241 254
242 255 /*!
243 256 Overrides the default brush of the marker items with a user defined \a brush. The default brush
244 257 is defined by chart theme setting.
245 258
246 259 \sa setPen()
247 260 \sa QChart::setChartTheme()
248 261 */
249 void QScatterSeries::setBrush(QBrush brush)
262 void QScatterSeries::setBrush(const QBrush &brush)
250 263 {
251 264 d->m_markerBrush = brush;
265 d->emitChanged();
252 266 }
253 267
254 268 /*!
255 Returns the brush used for drawing markers.
269 Returns the shape used for drawing markers.
256 270 */
257 QBrush QScatterSeries::brush()
271 QScatterSeries::MarkerShape QScatterSeries::shape() const
258 272 {
259 return d->m_markerBrush;
273 return (QScatterSeries::MarkerShape) d->m_markerShape;
260 274 }
261 275
262 276 /*!
263 277 Overrides the default shape of the marker items with a user defined \a shape. The default shape
264 278 is defined by chart theme setting.
265 279 */
266 280 void QScatterSeries::setShape(MarkerShape shape)
267 281 {
268 282 d->m_markerShape = shape;
269 }
270
271 /*!
272 Returns the shape used for drawing markers.
273 */
274 QScatterSeries::MarkerShape QScatterSeries::shape()
275 {
276 return (QScatterSeries::MarkerShape) d->m_markerShape;
283 d->emitChanged();
277 284 }
278 285
279 286 /*!
280 287 Returns the size of the marker items.
281 288 */
282 qreal QScatterSeries::size()
289 qreal QScatterSeries::size() const
283 290 {
284 291 return d->m_markerSize;
285 292 }
286 293
287 294 /*!
288 295 Set the \a size of the marker items. The default size is 9.0.
289 296 */
290 297 void QScatterSeries::setSize(qreal size)
291 298 {
292 299 d->m_markerSize = size;
293 emit changed();
300 d->emitChanged();
294 301 }
295 302
296 303 #include "moc_qscatterseries.cpp"
297 304
298 305 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,73 +1,71
1 1 #ifndef QSCATTERSERIES_H
2 2 #define QSCATTERSERIES_H
3 3
4 4 #include "qseries.h"
5 5 #include <QRectF>
6 6 #include <QColor>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9 class QScatterSeriesPrivate;
10 10
11 11 class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QSeries
12 12 {
13 13 Q_OBJECT
14 14
15 15 public:
16 16 enum MarkerShape {
17 17 // TODO: to be defined by the graphics design
18 18 // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot
19 19 MarkerShapeDefault = 0,
20 20 MarkerShapeX,
21 21 MarkerShapeRectangle,
22 MarkerShapeRoundedRectangle,
22 23 MarkerShapeTiltedRectangle,
23 24 MarkerShapeTriangle,
24 25 MarkerShapeCircle
25 26 };
26 27
27 28 public:
28 29 QScatterSeries(QObject *parent = 0);
29 30 ~QScatterSeries();
30 31
31 32 public: // from QChartSeries
32 33 QSeriesType type() const { return QSeries::SeriesTypeScatter; }
33 34
34 35 public:
35 36 void add(qreal x, qreal y);
36 37 void add(QPointF value);
37 38 void add(QList<QPointF> points);
38 39 void setData(QList<QPointF> points);
39 40 QScatterSeries& operator << (const QPointF &value);
40 41 QScatterSeries& operator << (QList<QPointF> points);
41 42 QList<QPointF> data();
42 43 bool replace(int index, QPointF newPoint);
43 44 bool removeAt(int index);
44 45 int removeAll(QPointF point);
45 46 void clear();
46 47 int closestPoint(QPointF coordinate);
47 48 //TODO: insert, replace...?
48 49
49 QPen pen();
50 void setPen(QPen pen);
51 QBrush brush();
52 void setBrush(QBrush brush);
53 MarkerShape shape();
50 QPen pen() const;
51 void setPen(const QPen &pen);
52 QBrush brush() const;
53 void setBrush(const QBrush &brush);
54 MarkerShape shape() const;
54 55 void setShape(MarkerShape shape);
55 qreal size();
56 qreal size() const;
56 57 void setSize(qreal size);
57 58
58 59 Q_SIGNALS:
59 60 void clicked(QPointF coordinate);
60 // TODO: move to PIMPL for simplicity or does the user ever need changed signals?
61 // TODO: more finegrained signaling for performance reasons
62 // (check QPieSeries implementation with change sets)
63 void changed();
64 61
65 62 private:
66 63 Q_DECLARE_PRIVATE(QScatterSeries)
67 64 Q_DISABLE_COPY(QScatterSeries)
68 QScatterSeriesPrivate *const d;
65 friend class ScatterPresenter;
66 QScatterSeriesPrivate *d;
69 67 };
70 68
71 69 QTCOMMERCIALCHART_END_NAMESPACE
72 70
73 71 #endif // QSCATTERSERIES_H
@@ -1,156 +1,166
1 1 #include "scatterpresenter_p.h"
2 2 #include "qscatterseries.h"
3 #include "scatterseries_p.h"
3 4 #include "chartpresenter_p.h"
4 5 #include <QPen>
5 6 #include <QPainter>
6 7 #include <QGraphicsScene>
7 8 #include <QGraphicsSceneMouseEvent>
8 9 #include <QGraphicsDropShadowEffect>
9 10 #include <QDebug>
10 11 #include <QTime>
11 12
12 13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 14
14 15 ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent) :
15 16 ChartItem(parent),
16 17 m_minX(0),
17 18 m_maxX(0),
18 19 m_minY(0),
19 20 m_maxY(0),
20 21 m_series(series),
21 22 m_clippingRect()
22 23 {
23 if (parent)
24 m_clippingRect = parent->boundingRect();
25
26 if (series) {
27 connect(series, SIGNAL(changed()), this, SLOT(handleModelChanged()));
28 }
24 Q_ASSERT(parent);
25 Q_ASSERT(series);
29 26
27 m_clippingRect = parent->boundingRect();
28 connect(series->d, SIGNAL(changed()), this, SLOT(handleModelChanged()));
29 connect(this, SIGNAL(clicked(QPointF)), series, SIGNAL(clicked(QPointF)));
30 30 setZValue(ChartPresenter::ScatterSeriesZValue);
31 31
32 32 // TODO: how to draw a drop shadow?
33 33 // QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect();
34 34 // dropShadow->setOffset(2.0);
35 35 // dropShadow->setBlurRadius(2.0);
36 36 // setGraphicsEffect(dropShadow);
37 37 }
38 38
39 39 void ScatterPresenter::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
40 40 {
41 41 m_minX = minX;
42 42 m_maxX = maxX;
43 43 m_minY = minY;
44 44 m_maxY = maxY;
45 45 changeGeometry();
46 46 }
47 47
48 48 void ScatterPresenter::handleGeometryChanged(const QRectF& rect)
49 49 {
50 50 m_clippingRect = rect.translated(-rect.topLeft());
51 51 changeGeometry();
52 52 setPos(rect.topLeft());
53 53 }
54 54
55 55 void ScatterPresenter::handleModelChanged()
56 56 {
57 57 // TODO: more fine grained modelChanged signaling
58 58 changeGeometry();
59 59 }
60 60
61 61 void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
62 62 {
63 63 painter->save();
64 64 painter->setClipRect(m_clippingRect);
65 65
66 66 // TODO: how to draw a drop shadow?
67 67 // Now using a custom implementation for drop shadow instead of QGraphicsDropShadowEffect.
68 68 // It seems QGraphicsDropShadowEffect is quite heavy, at least on windows without open gl.
69 69 QPen dropShadowPen(QColor(0, 0, 0, 70));
70 70 dropShadowPen.setWidth(3);
71 71 painter->setPen(dropShadowPen);
72 72 painter->setBrush(dropShadowPen.color());
73 73 // painter->setRenderHint(QPainter::Antialiasing);
74 74 painter->drawPath(m_path.translated(2, 2));
75 75
76 76 // Paint the shape
77 77 // The custom settings in series override those defined by the theme
78 78 QPen pen = m_markerPen;
79 79 if (m_series->pen().color().isValid())
80 80 pen = m_series->pen();
81 81 painter->setPen(pen);
82 82 if (m_series->brush().color().isValid())
83 83 painter->setBrush(m_series->brush());
84 84 else
85 85 painter->setBrush(m_markerBrush);
86 86
87 87 // If either pen or brush is opaque, we need to draw the polygons one-by-one
88 88 if (painter->pen().color().alpha() < 255 || painter->brush().color().alpha() < 255) {
89 89 foreach (QPolygonF pol, m_path.toSubpathPolygons())
90 90 painter->drawPolygon(pol);
91 91 } else {
92 92 painter->drawPath(m_path);
93 93 }
94 94
95 95 painter->restore();
96 96 }
97 97
98 98 void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event)
99 99 {
100 100 // Empty implementation to grab mouse release events for this item
101 101 Q_UNUSED(event)
102 102 }
103 103
104 104 void ScatterPresenter::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
105 105 {
106 106 QPointF clickedPoint(
107 107 m_minX + (event->lastPos().x() / m_clippingRect.width()) * (m_maxX-m_minX),
108 108 m_maxY - (event->lastPos().y() / m_clippingRect.height()) * (m_maxY-m_minY));
109 109 emit clicked(clickedPoint);
110 110 }
111 111
112 112 void ScatterPresenter::changeGeometry()
113 113 {
114 114 if (m_clippingRect.isValid()) {
115 115 prepareGeometryChange();
116 116 qreal scalex = m_clippingRect.width() / (m_maxX - m_minX);
117 117 qreal scaley = m_clippingRect.height() / (m_maxY - m_minY);
118 118
119 119 int shape = m_series->shape();
120 120 m_path = QPainterPath();
121 121 m_path.setFillRule(Qt::WindingFill);
122 122 const qreal size = m_series->size();
123 123
124 124 foreach (QPointF point, m_series->data()) {
125 125 // Convert relative coordinates to absolute pixel coordinates that can be used for drawing
126 126 qreal x = point.x() * scalex - m_minX * scalex - size / 2;
127 127 qreal y = m_clippingRect.height() - point.y() * scaley + m_minY * scaley - size / 2;
128 128
129 129 if (x < scene()->width() && y < scene()->height()) {
130 130 switch (shape) {
131 131 case QScatterSeries::MarkerShapeDefault:
132 132 // Fallthrough, defaults to circle
133 133 case QScatterSeries::MarkerShapeCircle:
134 134 m_path.addEllipse(x, y, size, size);
135 135 break;
136 136 case QScatterSeries::MarkerShapeRectangle:
137 137 m_path.addRect(x, y, size, size);
138 138 break;
139 case QScatterSeries::MarkerShapeRoundedRectangle:
140 m_path.addRoundedRect(x, y, size, size, size / 4.0, size / 4.0);
141 break;
139 142 case QScatterSeries::MarkerShapeTiltedRectangle: {
140 143 // TODO: tilt the rectangle
141 144 m_path.addRect(x, y, size, size);
142 145 break;
143 146 }
147 case QScatterSeries::MarkerShapeTriangle: {
148 QPolygonF polygon;
149 polygon << QPointF(0.0, -size) << QPointF(size / 2.0, 0.0) << QPointF(-size / 2, 0.0);
150 // TODO: the position is not exactly right...
151 m_path.addPolygon(polygon.translated(x + size / 2.0, y + size));
152 break;
153 }
144 154 default:
145 155 // TODO: implement the rest of the shapes
146 156 Q_ASSERT(false);
147 157 break;
148 158 }
149 159 }
150 160 }
151 161 }
152 162 }
153 163
154 164 #include "moc_scatterpresenter_p.cpp"
155 165
156 166 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,28 +1,37
1 1 #ifndef QSCATTERSERIESPRIVATE_H
2 2 #define QSCATTERSERIESPRIVATE_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "qseries.h"
6 #include <QObject>
6 7 #include <QPen>
7 8
8 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 10
10 11 /*!
11 12 * The PIMPL class of QScatterSeries.
12 13 */
13 class QScatterSeriesPrivate
14 class QScatterSeriesPrivate : public QObject
14 15 {
16 Q_OBJECT
17
15 18 public:
16 QScatterSeriesPrivate();
19 QScatterSeriesPrivate(QObject *parent);
20 void emitChanged();
21
22 Q_SIGNALS:
23 // TODO: more finegrained signaling for performance reasons
24 // (see for example QPieSeries implementation with change sets)
25 void changed();
17 26
18 27 public:
19 28 QList<QPointF> m_data;
20 29 QPen m_markerPen;
21 30 QBrush m_markerBrush;
22 31 int m_markerShape;
23 32 qreal m_markerSize;
24 33 };
25 34
26 35 QTCOMMERCIALCHART_END_NAMESPACE
27 36
28 37 #endif // QSCATTERSERIESPRIVATE_H
General Comments 0
You need to be logged in to leave comments. Login now