##// END OF EJS Templates
Added size customization to QScatterSeries
Tero Ahola -
r397:e3d058df67ba
parent child
Show More
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
@@ -1,59 +1,51
1 1 #include <QtGui/QApplication>
2 2 #include <QMainWindow>
3 3 #include <qchartglobal.h>
4 4 #include <qchartview.h>
5 5 #include <qscatterseries.h>
6 6
7 7 QTCOMMERCIALCHART_USE_NAMESPACE
8 8
9 9 int main(int argc, char *argv[])
10 10 {
11 11 QApplication a(argc, argv);
12 12
13 13 //! [1]
14 14 // Create chart view
15 15 QChartView *chartView = new QChartView();
16 chartView->setChartTheme(QChart::ChartThemeIcy);
17 // Add scatter series with simple test data
16 chartView->setRenderHint(QPainter::Antialiasing);
17 chartView->setChartTheme(QChart::ChartThemeScientific);
18 // Add scatter series with linear test data with random "noise"
18 19 QScatterSeries *scatter = new QScatterSeries();
19 *scatter << QPointF(0.5, 5.0) << QPointF(1.0, 4.5) << QPointF(1.0, 5.5) << QPointF(1.5, 5.0);
20 for (qreal i(0.0); i < 20; i += 0.25) {
21 qreal x = i + (qreal)(rand() % 100) / 100.0;
22 qreal y = i + (qreal)(rand() % 100) / 100.0;
23 (*scatter) << QPointF(x, y);
24 }
20 25 // Chart takes ownership
21 26 chartView->addSeries(scatter);
22 27 //! [1]
23 // scatter->replace(0, QPointF(0.75, 5.0));
24 28
25 29 // And more
26 //! [3]
27 *scatter << QPointF(2.0, 5.5) << QPointF(2.2, 5.4);
28 //! [3]
30 //! [2]
31 //*scatter << QPointF(2.0, 5.5) << QPointF(2.2, 5.4);
32 //! [2]
29 33
30 // Add another scatter series (re-use the previous pointer because the code used as snippets
31 // in the docs)
32 // - more data with random component
33 scatter = new QScatterSeries();
34 for (qreal i(0.0); i < 20; i += 0.15) {
35 (*scatter) << QPointF(i + (qreal)(rand() % 100) / 100.0,
36 i + (qreal)(rand() % 100) / 100.0);
37 }
38 //! [4]
39 QBrush brush(QColor(255, 0, 0, 100), Qt::SolidPattern);
34 //! [3]
35 QBrush brush(QColor(255, 0, 0, 80), Qt::SolidPattern);
40 36 scatter->setBrush(brush);
41 //! [4]
42 //! [5]
43 QPen pen(QColor(0, 255, 0, 80), 3);
37 QPen pen(QColor(0, 255, 0, 60), 3);
44 38 scatter->setPen(pen);
45 //! [5]
46 //! [6]
47 39 scatter->setShape(QScatterSeries::MarkerShapeRectangle);
48 //! [6]
49 chartView->addSeries(scatter);
40 scatter->setSize(15.0);
41 //! [3]
50 42
51 43 // Use the chart widget as the central widget
52 44 QMainWindow w;
53 45 w.resize(400, 300);
54 46 w.setCentralWidget(chartView);
55 47 w.setWindowFlags(Qt::FramelessWindowHint);
56 48 w.show();
57 49
58 50 return a.exec();
59 51 }
@@ -1,291 +1,298
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
18 To customize the graphical representation of the series, you can modify pen, brush, shape and
19 size of the marker items. For example:
20
21 \snippet ../example/scatter/main.cpp 3
22
23 Would present your scatter markers as big rectangles with opaque, uglyish green outlines and
24 opaque red filling instead of the beatiful markers defined by the chart's theme:
25 \image scatter_example_custom.jpg
17 26 */
18 27
19 28 /*!
20 29 \enum QScatterSeries::MarkerShape
21 30
22 31 This enum describes the shape used when rendering marker items.
23 32
24 33 \value MarkerShapeDefault
25 \value MarkerShapePoint
26 34 \value MarkerShapeX
27 35 \value MarkerShapeRectangle
28 36 \value MarkerShapeTiltedRectangle
29 37 \value MarkerShapeTriangle
30 38 \value MarkerShapeCircle
31 39 */
32 40
33 41 /*!
34 42 \fn QChartSeriesType QScatterSeries::type() const
35 43 \brief Returns QChartSeries::SeriesTypeScatter.
36 44 */
37 45
38 46 /*!
39 47 \fn void QScatterSeries::clicked(QPointF coordinate)
40 48 User clicked the scatter series. Note that the \a coordinate is the chart coordinate that the
41 49 click occurred on; not necessarily a data point coordinate. To find the corresponding (closest)
42 50 data point you can use closestPoint().
43 51 */
44 52
45 53 /*!
46 54 \fn void QScatterSeries::changed()
47 55 \brief TODO
48 56 */
49 57
50 58 QTCOMMERCIALCHART_BEGIN_NAMESPACE
51 59
52 60 QScatterSeriesPrivate::QScatterSeriesPrivate() :
53 61 m_data(QList<QPointF>()),
54 62 m_markerPen(QPen(QColor::Invalid)),
55 63 m_markerBrush(QBrush(QColor::Invalid)),
56 m_markerShape(QScatterSeries::MarkerShapeDefault)
64 m_markerShape(QScatterSeries::MarkerShapeDefault),
65 m_markerSize(9.0)
57 66 {
58 67 }
59 68
60 69 /*!
61 70 Constructs a series object which is a child of \a parent.
62 71 */
63 72 QScatterSeries::QScatterSeries(QObject *parent) :
64 73 QSeries(parent),
65 74 d(new QScatterSeriesPrivate())
66 75 {
67 76 }
68 77
69 78 /*!
70 79 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
71 80 */
72 81 QScatterSeries::~QScatterSeries()
73 82 {
74 83 delete d;
75 84 }
76 85
77 86 /*!
78 87 Add single data point with \a x and \a y coordinates to the series.
79 88 */
80 89 void QScatterSeries::add(qreal x, qreal y)
81 90 {
82 91 d->m_data.append(QPointF(x, y));
83 92 emit changed();
84 93 }
85 94
86 95 /*!
87 96 Add single data point with \a value to the series.
88 97 */
89 98 void QScatterSeries::add(QPointF value)
90 99 {
91 100 d->m_data.append(value);
92 101 emit changed();
93 102 }
94 103
95 104 /*!
96 105 Add list of \a points to the series.
97 106 */
98 107 void QScatterSeries::add(QList<QPointF> points)
99 108 {
100 109 d->m_data.append(points);
101 110 emit changed();
102 111 }
103 112
104 113 /*!
105 114 Stream operator for adding a data point with \a value to the series.
106 115 \sa add()
107 116
108 117 For example:
109 \snippet ../example/scatter/main.cpp 3
118 \snippet ../example/scatter/main.cpp 2
110 119 */
111 120 QScatterSeries& QScatterSeries::operator << (const QPointF &value)
112 121 {
113 122 d->m_data.append(value);
114 123 emit changed();
115 124 return *this;
116 125 }
117 126
118 127 /*!
119 128 Stream operator for adding a list of points to the series.
120 129 \sa add()
121 130 */
122 131 QScatterSeries& QScatterSeries::operator << (QList<QPointF> value)
123 132 {
124 133 d->m_data.append(value);
125 134 emit changed();
126 135 return *this;
127 136 }
128 137
129 138 /*!
130 139 Replaces the data of the series with the given list of data \a points.
131 140 */
132 141 void QScatterSeries::setData(QList<QPointF> points)
133 142 {
134 143 d->m_data = points;
135 144 emit changed();
136 145 }
137 146
138 147 /*!
139 148 Returns the current list of data points of the series.
140 149 */
141 150 QList<QPointF> QScatterSeries::data()
142 151 {
143 152 return d->m_data;
144 153 }
145 154
146 155 /*!
147 156 Replaces the point at \a index with \a newPoint. Returns true if \a index is a valid position
148 157 in the series data, false otherwise.
149 158 */
150 159 bool QScatterSeries::replace(int index, QPointF newPoint)
151 160 {
152 161 if (index >= 0 && index < d->m_data.count()) {
153 162 d->m_data.replace(index, newPoint);
154 163 emit changed();
155 164 return true;
156 165 }
157 166 return false;
158 167 }
159 168
160 169 /*!
161 170 Remove the data point at \a index. Returns true if a point was removed, false if the point
162 171 at \a index does not exist on the series.
163 172 */
164 173 bool QScatterSeries::removeAt(int index)
165 174 {
166 175 if (index >=0 && index < d->m_data.count()) {
167 176 d->m_data.removeAt(index);
168 177 emit changed();
169 178 return true;
170 179 }
171 180 return false;
172 181 }
173 182
174 183 /*!
175 184 Remove all occurrences of \a point from the series and returns the number of points removed.
176 185 */
177 186 int QScatterSeries::removeAll(QPointF point)
178 187 {
179 188 int count = d->m_data.removeAll(point);
180 189 emit changed();
181 190 return count;
182 191 }
183 192
184 193 /*!
185 194 Remove all data points from the series.
186 195 */
187 196 void QScatterSeries::clear()
188 197 {
189 198 d->m_data.clear();
190 199 emit changed();
191 200 }
192 201
193 202 /*!
194 203 Returns the index of the data point that is closest to \a coordinate. If several data points
195 204 are at the same distance from the \a coordinate, returns the last one. If no points exist,
196 205 returns -1.
197 206 */
198 207 int QScatterSeries::closestPoint(QPointF coordinate)
199 208 {
200 209 qreal distance(-1);
201 210 int pointIndex(-1);
202 211 for (int i(0); i < d->m_data.count(); i++) {
203 212 QPointF dataPoint = d->m_data.at(i);
204 213 QPointF difference = dataPoint - coordinate;
205 214 if (i == 0 || difference.manhattanLength() <= distance) {
206 215 distance = difference.manhattanLength();
207 216 pointIndex = i;
208 217 }
209 218 }
210 219 return pointIndex;
211 220 }
212 221
213 222 /*!
214 223 Overrides the default pen used for drawing a marker item with a user defined \a pen. The
215 224 default pen is defined by chart theme setting.
216 225
217 For example:
218 \snippet ../example/scatter/main.cpp 5
219
220 Would present your scatter markers with an opaque, uglyish green outlines instead of the
221 beatiful markers defined by the chart's theme:
222 \image scatter_example_pen.jpg
223
224 226 \sa setBrush()
225 227 \sa QChart::setChartTheme()
226 228 */
227 229 void QScatterSeries::setPen(QPen pen)
228 230 {
229 231 d->m_markerPen = pen;
230 232 }
231 233
232 234 /*!
233 235 Returns the pen used for drawing markers.
234 236 */
235 237 QPen QScatterSeries::pen()
236 238 {
237 239 return d->m_markerPen;
238 240 }
239 241
240 242 /*!
241 243 Overrides the default brush of the marker items with a user defined \a brush. The default brush
242 244 is defined by chart theme setting.
243 245
244 For example:
245 \snippet ../example/scatter/main.cpp 4
246
247 Would fill your scatter markers with an opaque red color:
248 \image scatter_example_brush.jpg
249
250 246 \sa setPen()
251 247 \sa QChart::setChartTheme()
252 248 */
253 249 void QScatterSeries::setBrush(QBrush brush)
254 250 {
255 251 d->m_markerBrush = brush;
256 252 }
257 253
258 254 /*!
259 255 Returns the brush used for drawing markers.
260 256 */
261 257 QBrush QScatterSeries::brush()
262 258 {
263 259 return d->m_markerBrush;
264 260 }
265 261
266 262 /*!
267 263 Overrides the default shape of the marker items with a user defined \a shape. The default shape
268 264 is defined by chart theme setting.
269
270 For example:
271 \snippet ../example/scatter/main.cpp 6
272
273 Would make your scatter marker items rectangle:
274 \image scatter_example_shape.jpg
275 265 */
276 266 void QScatterSeries::setShape(MarkerShape shape)
277 267 {
278 268 d->m_markerShape = shape;
279 269 }
280 270
281 271 /*!
282 272 Returns the shape used for drawing markers.
283 273 */
284 274 QScatterSeries::MarkerShape QScatterSeries::shape()
285 275 {
286 276 return (QScatterSeries::MarkerShape) d->m_markerShape;
287 277 }
288 278
279 /*!
280 Returns the size of the marker items.
281 */
282 qreal QScatterSeries::size()
283 {
284 return d->m_markerSize;
285 }
286
287 /*!
288 Set the \a size of the marker items. The default size is 9.0.
289 */
290 void QScatterSeries::setSize(qreal size)
291 {
292 d->m_markerSize = size;
293 emit changed();
294 }
295
289 296 #include "moc_qscatterseries.cpp"
290 297
291 298 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,73 +1,73
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 MarkerShapePoint,
21 20 MarkerShapeX,
22 21 MarkerShapeRectangle,
23 22 MarkerShapeTiltedRectangle,
24 23 MarkerShapeTriangle,
25 24 MarkerShapeCircle
26 25 };
27 26
28 27 public:
29 28 QScatterSeries(QObject *parent = 0);
30 29 ~QScatterSeries();
31 30
32 31 public: // from QChartSeries
33 32 QSeriesType type() const { return QSeries::SeriesTypeScatter; }
34 33
35 34 public:
36 35 void add(qreal x, qreal y);
37 36 void add(QPointF value);
38 37 void add(QList<QPointF> points);
39 38 void setData(QList<QPointF> points);
40 39 QScatterSeries& operator << (const QPointF &value);
41 40 QScatterSeries& operator << (QList<QPointF> points);
42 41 QList<QPointF> data();
43 42 bool replace(int index, QPointF newPoint);
44 43 bool removeAt(int index);
45 44 int removeAll(QPointF point);
46 45 void clear();
47 46 int closestPoint(QPointF coordinate);
48 47 //TODO: insert, replace...?
49 48
50 49 QPen pen();
51 50 void setPen(QPen pen);
52 51 QBrush brush();
53 52 void setBrush(QBrush brush);
54 53 MarkerShape shape();
55 54 void setShape(MarkerShape shape);
56 // TODO: marker size?
55 qreal size();
56 void setSize(qreal size);
57 57
58 58 Q_SIGNALS:
59 59 void clicked(QPointF coordinate);
60 60 // TODO: move to PIMPL for simplicity or does the user ever need changed signals?
61 61 // TODO: more finegrained signaling for performance reasons
62 62 // (check QPieSeries implementation with change sets)
63 63 void changed();
64 64
65 65 private:
66 66 Q_DECLARE_PRIVATE(QScatterSeries)
67 67 Q_DISABLE_COPY(QScatterSeries)
68 68 QScatterSeriesPrivate *const d;
69 69 };
70 70
71 71 QTCOMMERCIALCHART_END_NAMESPACE
72 72
73 73 #endif // QSCATTERSERIES_H
@@ -1,153 +1,150
1 1 #include "scatterpresenter_p.h"
2 2 #include "qscatterseries.h"
3 3 #include "chartpresenter_p.h"
4 4 #include <QPen>
5 5 #include <QPainter>
6 6 #include <QGraphicsScene>
7 7 #include <QGraphicsSceneMouseEvent>
8 8 #include <QGraphicsDropShadowEffect>
9 9 #include <QDebug>
10 10 #include <QTime>
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent) :
15 15 ChartItem(parent),
16 16 m_series(series),
17 17 m_boundingRect(),
18 18 m_visibleChartArea()
19 19 {
20 20 if (parent)
21 21 m_boundingRect = parent->boundingRect();
22 22
23 23 if (series) {
24 24 connect(series, SIGNAL(changed()), this, SLOT(handleModelChanged()));
25 25 }
26 26
27 27 setZValue(ChartPresenter::ScatterSeriesZValue);
28 28
29 29 // TODO: how to draw a drop shadow?
30 30 // QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect();
31 31 // dropShadow->setOffset(2.0);
32 32 // dropShadow->setBlurRadius(2.0);
33 33 // setGraphicsEffect(dropShadow);
34 34 }
35 35
36 36 void ScatterPresenter::handleDomainChanged(const Domain& domain)
37 37 {
38 38 m_visibleChartArea = domain;
39 39 changeGeometry();
40 40 }
41 41
42 42 void ScatterPresenter::handleGeometryChanged(const QRectF& rect)
43 43 {
44 44 m_boundingRect = rect.translated(-rect.topLeft());
45 45 changeGeometry();
46 46 setPos(rect.topLeft());
47 47 }
48 48
49 49 void ScatterPresenter::handleModelChanged()
50 50 {
51 51 // TODO: more fine grained modelChanged signaling
52 52 changeGeometry();
53 53 }
54 54
55 55 void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
56 56 {
57 57 painter->save();
58 58 painter->setClipRect(m_boundingRect);
59 59
60 60 // TODO: how to draw a drop shadow?
61 61 // Now using a custom implementation for drop shadow instead of QGraphicsDropShadowEffect.
62 62 // It seems QGraphicsDropShadowEffect is quite heavy, at least on windows without open gl.
63 63 QPen dropShadowPen(QColor(0, 0, 0, 70));
64 64 dropShadowPen.setWidth(3);
65 65 painter->setPen(dropShadowPen);
66 66 painter->setBrush(dropShadowPen.color());
67 67 // painter->setRenderHint(QPainter::Antialiasing);
68 68 painter->drawPath(m_path.translated(2, 2));
69 69
70 70 // Paint the shape
71 71 // The custom settings in series override those defined by the theme
72 72 QPen pen = m_markerPen;
73 73 if (m_series->pen().color().isValid())
74 74 pen = m_series->pen();
75 75 painter->setPen(pen);
76 76 if (m_series->brush().color().isValid())
77 77 painter->setBrush(m_series->brush());
78 78 else
79 79 painter->setBrush(m_markerBrush);
80 80
81 81 // If either pen or brush is opaque, we need to draw the polygons one-by-one
82 82 if (painter->pen().color().alpha() < 255 || painter->brush().color().alpha() < 255) {
83 83 foreach (QPolygonF pol, m_path.toSubpathPolygons())
84 84 painter->drawPolygon(pol);
85 85 } else {
86 86 painter->drawPath(m_path);
87 87 }
88 88
89 89 painter->restore();
90 90 }
91 91
92 92 void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event)
93 93 {
94 94 // Empty implementation to grab mouse release events for this item
95 95 Q_UNUSED(event)
96 96 }
97 97
98 98 void ScatterPresenter::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
99 99 {
100 100 QPointF clickedPoint(
101 101 m_visibleChartArea.m_minX + (event->lastPos().x() / m_boundingRect.width()) * m_visibleChartArea.spanX(),
102 102 m_visibleChartArea.m_maxY - (event->lastPos().y() / m_boundingRect.height()) * m_visibleChartArea.spanY());
103 103 emit clicked(clickedPoint);
104 104 }
105 105
106 106 void ScatterPresenter::changeGeometry()
107 107 {
108 108 if (m_boundingRect.isValid()) {
109 109 prepareGeometryChange();
110 110 qreal scalex = m_boundingRect.width() / m_visibleChartArea.spanX();
111 111 qreal scaley = m_boundingRect.height() / m_visibleChartArea.spanY();
112 112
113 113 int shape = m_series->shape();
114 114 m_path = QPainterPath();
115 115 m_path.setFillRule(Qt::WindingFill);
116 const qreal size(9); // TODO: user defined size?
116 const qreal size = m_series->size();
117 117
118 118 foreach (QPointF point, m_series->data()) {
119 119 // Convert relative coordinates to absolute pixel coordinates that can be used for drawing
120 120 qreal x = point.x() * scalex - m_visibleChartArea.m_minX * scalex - size / 2;
121 121 qreal y = m_boundingRect.height() - point.y() * scaley + m_visibleChartArea.m_minY * scaley - size / 2;
122 122
123 123 if (x < scene()->width() && y < scene()->height()) {
124 124 switch (shape) {
125 125 case QScatterSeries::MarkerShapeDefault:
126 126 // Fallthrough, defaults to circle
127 127 case QScatterSeries::MarkerShapeCircle:
128 128 m_path.addEllipse(x, y, size, size);
129 129 break;
130 case QScatterSeries::MarkerShapePoint:
131 m_path.addEllipse(x, y, 2, 2);
132 break;
133 130 case QScatterSeries::MarkerShapeRectangle:
134 131 m_path.addRect(x, y, size, size);
135 132 break;
136 133 case QScatterSeries::MarkerShapeTiltedRectangle: {
137 134 // TODO: tilt the rectangle
138 135 m_path.addRect(x, y, size, size);
139 136 break;
140 137 }
141 138 default:
142 139 // TODO: implement the rest of the shapes
143 140 Q_ASSERT(false);
144 141 break;
145 142 }
146 143 }
147 144 }
148 145 }
149 146 }
150 147
151 148 #include "moc_scatterpresenter_p.cpp"
152 149
153 150 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,27 +1,28
1 1 #ifndef QSCATTERSERIESPRIVATE_H
2 2 #define QSCATTERSERIESPRIVATE_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "qseries.h"
6 6 #include <QPen>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 /*!
11 11 * The PIMPL class of QScatterSeries.
12 12 */
13 13 class QScatterSeriesPrivate
14 14 {
15 15 public:
16 16 QScatterSeriesPrivate();
17 17
18 18 public:
19 19 QList<QPointF> m_data;
20 20 QPen m_markerPen;
21 21 QBrush m_markerBrush;
22 22 int m_markerShape;
23 qreal m_markerSize;
23 24 };
24 25
25 26 QTCOMMERCIALCHART_END_NAMESPACE
26 27
27 28 #endif // QSCATTERSERIESPRIVATE_H
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
General Comments 0
You need to be logged in to leave comments. Login now