##// END OF EJS Templates
Fixed drawing issues in Scatter
Tero Ahola -
r375:cfa1350263ea
parent child
Show More
@@ -1,67 +1,74
1 1 #ifndef CHARTPRESENTER_H_
2 2 #define CHARTPRESENTER_H_
3 3
4 4 #include "qchartglobal.h"
5 5 #include "qchart.h" //becouse of QChart::ChartThemeId //TODO
6 6 #include "qchartaxis.h"
7 7 #include <QRectF>
8 8
9 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 10
11 11 class ChartItem;
12 12 class QSeries;
13 13 class ChartDataSet;
14 14 //class QChart;
15 15 class Domain;
16 16 class AxisItem;
17 17 class ChartTheme;
18 18
19 19 class ChartPresenter: public QObject
20 20 {
21 21 Q_OBJECT
22 22 public:
23 enum ZValues { BackgroundZValue = -1 , ShadesZValue, GridZValue, AxisZValue , LineChartZValue };
23 enum ZValues {
24 BackgroundZValue = -1,
25 ShadesZValue,
26 GridZValue,
27 AxisZValue,
28 LineChartZValue,
29 ScatterSeriesZValue
30 };
24 31
25 32 ChartPresenter(QChart* chart,ChartDataSet *dataset);
26 33 virtual ~ChartPresenter();
27 34
28 35 void setMargin(int margin);
29 36 int margin() const;
30 37
31 38 QRectF geometry() const;
32 39
33 40 void setChartTheme(QChart::ChartTheme theme);
34 41 QChart::ChartTheme chartTheme();
35 42
36 43 void setAnimationOptions(QChart::AnimationOptions options);
37 44 QChart::AnimationOptions animationOptions() const;
38 45
39 46 private:
40 47 void createConnections();
41 48
42 49 public slots:
43 50 void handleSeriesAdded(QSeries* series);
44 51 void handleSeriesRemoved(QSeries* series);
45 52 void handleAxisAdded(QChartAxis* axis);
46 53 void handleAxisRemoved(QChartAxis* axis);
47 54 void handleSeriesDomainChanged(QSeries* series, const Domain& domain);
48 55 void handleAxisLabelsChanged(QChartAxis* axis, const QStringList& labels);
49 56 void handleSeriesChanged(QSeries* series);
50 57 void handleGeometryChanged();
51 58 signals:
52 59 void geometryChanged(const QRectF& rect);
53 60 private:
54 61 QMap<QSeries*,ChartItem*> m_chartItems;
55 62 QMap<QChartAxis*,AxisItem*> m_axisItems;
56 63 QChart* m_chart;
57 64 ChartDataSet* m_dataset;
58 65 ChartTheme *m_chartTheme;
59 66 int m_marginSize;
60 67 QRectF m_rect;
61 68 QChart::AnimationOptions m_options;
62 69
63 70 };
64 71
65 72 QTCOMMERCIALCHART_END_NAMESPACE
66 73
67 74 #endif /* CHARTPRESENTER_H_ */
@@ -1,225 +1,222
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
19 19 /*!
20 20 \enum QScatterSeries::MarkerShape
21 21
22 22 This enum describes the shape used when rendering marker items.
23 23
24 24 \value MarkerShapeDefault
25 25 \value MarkerShapePoint
26 26 \value MarkerShapeX
27 27 \value MarkerShapeRectangle
28 28 \value MarkerShapeTiltedRectangle
29 29 \value MarkerShapeTriangle
30 30 \value MarkerShapeCircle
31 31 */
32 32
33 33 /*!
34 34 \fn QChartSeriesType QScatterSeries::type() const
35 35 \brief Returns QChartSeries::SeriesTypeScatter.
36 36 */
37 37
38 38 /*!
39 39 \fn void QScatterSeries::clicked()
40 40 \brief TODO
41 41 */
42 42
43 43 /*!
44 44 \fn void QScatterSeries::changed()
45 45 \brief TODO
46 46 */
47 47
48 48 QTCOMMERCIALCHART_BEGIN_NAMESPACE
49 49
50 50 QScatterSeriesPrivate::QScatterSeriesPrivate() :
51 51 m_data(QList<QPointF>()),
52 m_markerPen(QPen()),
53 m_markerBrush(QBrush()),
52 m_markerPen(QPen(QColor::Invalid)),
53 m_markerBrush(QBrush(QColor::Invalid)),
54 54 m_markerShape(QScatterSeries::MarkerShapeDefault)
55 55 {
56 // Initialize pen color to invalid to use a theme color by default
57 m_markerPen.setColor(QColor::Invalid);
58 m_markerBrush.setColor(QColor::Invalid);
59 56 }
60 57
61 58 /*!
62 59 Constructs a series object which is a child of \a parent.
63 60 */
64 61 QScatterSeries::QScatterSeries(QObject *parent) :
65 62 QSeries(parent),
66 63 d(new QScatterSeriesPrivate())
67 64 {
68 65 }
69 66
70 67 /*!
71 68 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
72 69 */
73 70 QScatterSeries::~QScatterSeries()
74 71 {
75 72 delete d;
76 73 }
77 74
78 75 /*!
79 76 Add single data point with \a x and \a y coordinates to the series.
80 77 */
81 78 void QScatterSeries::add(qreal x, qreal y)
82 79 {
83 80 d->m_data.append(QPointF(x, y));
84 81 emit changed();
85 82 }
86 83
87 84 /*!
88 85 Add single data point with \a value to the series.
89 86 */
90 87 void QScatterSeries::add(QPointF value)
91 88 {
92 89 d->m_data.append(value);
93 90 emit changed();
94 91 }
95 92
96 93 /*!
97 94 Add list of \a points to the series.
98 95 */
99 96 void QScatterSeries::add(QList<QPointF> points)
100 97 {
101 98 d->m_data.append(points);
102 99 emit changed();
103 100 }
104 101
105 102 /*!
106 103 Stream operator for adding a data point with \a value to the series.
107 104 \sa add()
108 105
109 106 For example:
110 107 \snippet ../example/scatter/main.cpp 3
111 108 */
112 109 QScatterSeries& QScatterSeries::operator << (const QPointF &value)
113 110 {
114 111 d->m_data.append(value);
115 112 emit changed();
116 113 return *this;
117 114 }
118 115
119 116 /*!
120 117 Stream operator for adding a list of points to the series.
121 118 \sa add()
122 119 */
123 120 QScatterSeries& QScatterSeries::operator << (QList<QPointF> value)
124 121 {
125 122 d->m_data.append(value);
126 123 emit changed();
127 124 return *this;
128 125 }
129 126
130 127 /*!
131 128 Replaces the data of the series with the given list of data \a points.
132 129 */
133 130 void QScatterSeries::setData(QList<QPointF> points)
134 131 {
135 132 d->m_data = points;
136 133 emit changed();
137 134 }
138 135
139 136 /*!
140 137 Returns the current list of data points of the series.
141 138 */
142 139 QList<QPointF> QScatterSeries::data()
143 140 {
144 141 return d->m_data;
145 142 }
146 143
147 144 /*!
148 145 Overrides the default pen used for drawing a marker item with a user defined \a pen. The
149 146 default pen is defined by chart theme setting.
150 147
151 148 For example:
152 149 \snippet ../example/scatter/main.cpp 5
153 150
154 151 Would present your scatter markers with an opaque, uglyish green outlines instead of the
155 152 beatiful markers defined by the chart's theme:
156 153 \image scatter_example_pen.jpg
157 154
158 155 \sa setBrush()
159 156 \sa QChart::setChartTheme()
160 157 */
161 158 void QScatterSeries::setPen(QPen pen)
162 159 {
163 160 d->m_markerPen = pen;
164 161 }
165 162
166 163 /*!
167 164 Returns the pen used for drawing markers.
168 165 */
169 166 QPen QScatterSeries::pen()
170 167 {
171 168 return d->m_markerPen;
172 169 }
173 170
174 171 /*!
175 172 Overrides the default brush of the marker items with a user defined \a brush. The default brush
176 173 is defined by chart theme setting.
177 174
178 175 For example:
179 176 \snippet ../example/scatter/main.cpp 4
180 177
181 178 Would fill your scatter markers with an opaque red color:
182 179 \image scatter_example_brush.jpg
183 180
184 181 \sa setPen()
185 182 \sa QChart::setChartTheme()
186 183 */
187 184 void QScatterSeries::setBrush(QBrush brush)
188 185 {
189 186 d->m_markerBrush = brush;
190 187 }
191 188
192 189 /*!
193 190 Returns the brush used for drawing markers.
194 191 */
195 192 QBrush QScatterSeries::brush()
196 193 {
197 194 return d->m_markerBrush;
198 195 }
199 196
200 197 /*!
201 198 Overrides the default shape of the marker items with a user defined \a shape. The default shape
202 199 is defined by chart theme setting.
203 200
204 201 For example:
205 202 \snippet ../example/scatter/main.cpp 6
206 203
207 204 Would make your scatter marker items rectangle:
208 205 \image scatter_example_shape.jpg
209 206 */
210 207 void QScatterSeries::setShape(MarkerShape shape)
211 208 {
212 209 d->m_markerShape = shape;
213 210 }
214 211
215 212 /*!
216 213 Returns the shape used for drawing markers.
217 214 */
218 215 QScatterSeries::MarkerShape QScatterSeries::shape()
219 216 {
220 217 return (QScatterSeries::MarkerShape) d->m_markerShape;
221 218 }
222 219
223 220 #include "moc_qscatterseries.cpp"
224 221
225 222 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,124 +1,146
1 1 #include "scatterpresenter_p.h"
2 2 #include "qscatterseries.h"
3 #include "chartpresenter_p.h"
3 4 #include <QPen>
4 5 #include <QPainter>
5 6 #include <QGraphicsScene>
6 7 #include <QGraphicsSceneMouseEvent>
7 8 #include <QGraphicsDropShadowEffect>
8 9 #include <QDebug>
9 10 #include <QTime>
10 11
11 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 13
13 14 ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent) :
14 15 ChartItem(parent),
15 16 m_series(series),
16 17 m_boundingRect(),
17 18 m_visibleChartArea()
18 19 {
19 20 if (parent)
20 21 m_boundingRect = parent->boundingRect();
21 22
22 23 if (series) {
23 24 connect(series, SIGNAL(changed()), this, SLOT(handleModelChanged()));
24 25 }
25 26
26 QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect();
27 dropShadow->setOffset(2.0);
28 dropShadow->setBlurRadius(2.0);
29 setGraphicsEffect(dropShadow);
27 setZValue(ChartPresenter::ScatterSeriesZValue);
28
29 // TODO: how to draw a drop shadow?
30 // QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect();
31 // dropShadow->setOffset(2.0);
32 // dropShadow->setBlurRadius(2.0);
33 // setGraphicsEffect(dropShadow);
30 34 }
31 35
32 36 void ScatterPresenter::handleDomainChanged(const Domain& domain)
33 37 {
34 38 m_visibleChartArea = domain;
35 39 changeGeometry();
36 40 }
37 41
38 42 void ScatterPresenter::handleGeometryChanged(const QRectF& rect)
39 43 {
40 44 m_boundingRect = rect;
41 45 changeGeometry();
42 46 }
43 47
44 48 void ScatterPresenter::handleModelChanged()
45 49 {
46 50 // TODO: more fine grained modelChanged signaling
47 51 changeGeometry();
48 52 }
49 53
50 54 void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
51 55 {
52 56 painter->save();
53 57 painter->setClipRect(m_boundingRect);
54 58
59 // TODO: how to draw a drop shadow?
60 // Now using a custom implementation for drop shadow instead of QGraphicsDropShadowEffect.
61 // It seems QGraphicsDropShadowEffect is quite heavy, at least on windows without open gl.
62 QPen dropShadowPen(QColor(0, 0, 0, 70));
63 dropShadowPen.setWidth(3);
64 painter->setPen(dropShadowPen);
65 painter->setBrush(dropShadowPen.color());
66 // painter->setRenderHint(QPainter::Antialiasing);
67 painter->drawPath(m_path.translated(2, 2));
68
55 69 // Paint the shape
56 70 // The custom settings in series override those defined by the theme
57 71 QPen pen = m_markerPen;
58 72 if (m_series->pen().color().isValid())
59 73 pen = m_series->pen();
74 painter->setPen(pen);
60 75 if (m_series->brush().color().isValid())
61 76 painter->setBrush(m_series->brush());
62 77 else
63 78 painter->setBrush(m_markerBrush);
64 painter->setPen(pen);
65 painter->drawPath(m_path);
79
80 // If either pen or brush is opaque, we need to draw the polygons one-by-one
81 if (painter->pen().color().alpha() < 255 || painter->brush().color().alpha() < 255) {
82 foreach (QPolygonF pol, m_path.toSubpathPolygons())
83 painter->drawPolygon(pol);
84 } else {
85 painter->drawPath(m_path);
86 }
66 87
67 88 painter->restore();
68 89 }
69 90
70 91 void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event)
71 92 {
72 93 qDebug() << "ScatterPresenter::mousePressEvent" << event << " cont: "
73 94 << m_path.contains(event->lastPos());
74 95
75 96 if (m_path.contains(event->lastPos()))
76 97 emit clicked();
77 98 }
78 99
79 100 void ScatterPresenter::changeGeometry()
80 101 {
81 102 if (m_boundingRect.isValid()) {
82 103 prepareGeometryChange();
83 104 qreal scalex = m_boundingRect.width() / m_visibleChartArea.spanX();
84 105 qreal scaley = m_boundingRect.height() / m_visibleChartArea.spanY();
85 106
86 107 int shape = m_series->shape();
87 108 m_path = QPainterPath();
109 m_path.setFillRule(Qt::WindingFill);
88 110
89 111 foreach (QPointF point, m_series->data()) {
90 112 // Convert relative coordinates to absolute pixel coordinates that can be used for drawing
91 113 qreal x = m_boundingRect.left() + point.x() * scalex - m_visibleChartArea.m_minX * scalex;
92 114 qreal y = m_boundingRect.bottom() - point.y() * scaley + m_visibleChartArea.m_minY * scaley;
93 115
94 116 if (scene()->width() > x && scene()->height() > y) {
95 117 switch (shape) {
96 118 case QScatterSeries::MarkerShapeDefault:
97 119 // Fallthrough, defaults to circle
98 120 case QScatterSeries::MarkerShapeCircle:
99 121 m_path.addEllipse(x, y, 9, 9);
100 122 break;
101 123 case QScatterSeries::MarkerShapePoint:
102 124 m_path.addEllipse(x, y, 2, 2);
103 125 break;
104 126 case QScatterSeries::MarkerShapeRectangle:
105 127 m_path.addRect(x, y, 9, 9);
106 128 break;
107 129 case QScatterSeries::MarkerShapeTiltedRectangle: {
108 130 // TODO: tilt the rectangle
109 131 m_path.addRect(x, y, 9, 9);
110 132 break;
111 133 }
112 134 default:
113 135 // TODO: implement the rest of the shapes
114 136 Q_ASSERT(false);
115 137 break;
116 138 }
117 139 }
118 140 }
119 141 }
120 142 }
121 143
122 144 #include "moc_scatterpresenter_p.cpp"
123 145
124 146 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now