##// END OF EJS Templates
Fix clicked, released and doubleClicked signal points...
Titta Heikkala -
r2746:4909289ecbd7
parent child
Show More
@@ -1,283 +1,283
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/areachartitem_p.h>
19 #include <private/areachartitem_p.h>
20 #include <QtCharts/QAreaSeries>
20 #include <QtCharts/QAreaSeries>
21 #include <private/qareaseries_p.h>
21 #include <private/qareaseries_p.h>
22 #include <QtCharts/QLineSeries>
22 #include <QtCharts/QLineSeries>
23 #include <private/chartpresenter_p.h>
23 #include <private/chartpresenter_p.h>
24 #include <private/abstractdomain_p.h>
24 #include <private/abstractdomain_p.h>
25 #include <QtGui/QPainter>
25 #include <QtGui/QPainter>
26 #include <QtWidgets/QGraphicsSceneMouseEvent>
26 #include <QtWidgets/QGraphicsSceneMouseEvent>
27 #include <QtCore/QDebug>
27 #include <QtCore/QDebug>
28
28
29
29
30 QT_CHARTS_BEGIN_NAMESPACE
30 QT_CHARTS_BEGIN_NAMESPACE
31
31
32 AreaChartItem::AreaChartItem(QAreaSeries *areaSeries, QGraphicsItem* item)
32 AreaChartItem::AreaChartItem(QAreaSeries *areaSeries, QGraphicsItem* item)
33 : ChartItem(areaSeries->d_func(),item),
33 : ChartItem(areaSeries->d_func(),item),
34 m_series(areaSeries),
34 m_series(areaSeries),
35 m_upper(0),
35 m_upper(0),
36 m_lower(0),
36 m_lower(0),
37 m_pointsVisible(false),
37 m_pointsVisible(false),
38 m_pointLabelsVisible(false),
38 m_pointLabelsVisible(false),
39 m_pointLabelsFormat(areaSeries->pointLabelsFormat()),
39 m_pointLabelsFormat(areaSeries->pointLabelsFormat()),
40 m_pointLabelsFont(areaSeries->pointLabelsFont()),
40 m_pointLabelsFont(areaSeries->pointLabelsFont()),
41 m_pointLabelsColor(areaSeries->pointLabelsColor()),
41 m_pointLabelsColor(areaSeries->pointLabelsColor()),
42 m_mousePressed(false)
42 m_mousePressed(false)
43 {
43 {
44 setAcceptHoverEvents(true);
44 setAcceptHoverEvents(true);
45 setFlag(QGraphicsItem::ItemIsSelectable, true);
45 setFlag(QGraphicsItem::ItemIsSelectable, true);
46 setZValue(ChartPresenter::LineChartZValue);
46 setZValue(ChartPresenter::LineChartZValue);
47 if (m_series->upperSeries())
47 if (m_series->upperSeries())
48 m_upper = new AreaBoundItem(this, m_series->upperSeries());
48 m_upper = new AreaBoundItem(this, m_series->upperSeries());
49 if (m_series->lowerSeries())
49 if (m_series->lowerSeries())
50 m_lower = new AreaBoundItem(this, m_series->lowerSeries());
50 m_lower = new AreaBoundItem(this, m_series->lowerSeries());
51
51
52 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
52 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
53 QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
53 QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
54 QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
54 QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
55 QObject::connect(this, SIGNAL(clicked(QPointF)), areaSeries, SIGNAL(clicked(QPointF)));
55 QObject::connect(this, SIGNAL(clicked(QPointF)), areaSeries, SIGNAL(clicked(QPointF)));
56 QObject::connect(this, SIGNAL(hovered(QPointF,bool)), areaSeries, SIGNAL(hovered(QPointF,bool)));
56 QObject::connect(this, SIGNAL(hovered(QPointF,bool)), areaSeries, SIGNAL(hovered(QPointF,bool)));
57 QObject::connect(this, SIGNAL(pressed(QPointF)), areaSeries, SIGNAL(pressed(QPointF)));
57 QObject::connect(this, SIGNAL(pressed(QPointF)), areaSeries, SIGNAL(pressed(QPointF)));
58 QObject::connect(this, SIGNAL(released(QPointF)), areaSeries, SIGNAL(released(QPointF)));
58 QObject::connect(this, SIGNAL(released(QPointF)), areaSeries, SIGNAL(released(QPointF)));
59 QObject::connect(this, SIGNAL(doubleClicked(QPointF)),
59 QObject::connect(this, SIGNAL(doubleClicked(QPointF)),
60 areaSeries, SIGNAL(doubleClicked(QPointF)));
60 areaSeries, SIGNAL(doubleClicked(QPointF)));
61 QObject::connect(areaSeries, SIGNAL(pointLabelsFormatChanged(QString)),
61 QObject::connect(areaSeries, SIGNAL(pointLabelsFormatChanged(QString)),
62 this, SLOT(handleUpdated()));
62 this, SLOT(handleUpdated()));
63 QObject::connect(areaSeries, SIGNAL(pointLabelsVisibilityChanged(bool)),
63 QObject::connect(areaSeries, SIGNAL(pointLabelsVisibilityChanged(bool)),
64 this, SLOT(handleUpdated()));
64 this, SLOT(handleUpdated()));
65 QObject::connect(areaSeries, SIGNAL(pointLabelsFontChanged(QFont)),
65 QObject::connect(areaSeries, SIGNAL(pointLabelsFontChanged(QFont)),
66 this, SLOT(handleUpdated()));
66 this, SLOT(handleUpdated()));
67 QObject::connect(areaSeries, SIGNAL(pointLabelsColorChanged(QColor)),
67 QObject::connect(areaSeries, SIGNAL(pointLabelsColorChanged(QColor)),
68 this, SLOT(handleUpdated()));
68 this, SLOT(handleUpdated()));
69
69
70 handleUpdated();
70 handleUpdated();
71 }
71 }
72
72
73 AreaChartItem::~AreaChartItem()
73 AreaChartItem::~AreaChartItem()
74 {
74 {
75 delete m_upper;
75 delete m_upper;
76 delete m_lower;
76 delete m_lower;
77 }
77 }
78
78
79 void AreaChartItem::setPresenter(ChartPresenter *presenter)
79 void AreaChartItem::setPresenter(ChartPresenter *presenter)
80 {
80 {
81 if (m_upper)
81 if (m_upper)
82 m_upper->setPresenter(presenter);
82 m_upper->setPresenter(presenter);
83 if (m_lower) {
83 if (m_lower) {
84 m_lower->setPresenter(presenter);
84 m_lower->setPresenter(presenter);
85 }
85 }
86 ChartItem::setPresenter(presenter);
86 ChartItem::setPresenter(presenter);
87 }
87 }
88
88
89 QRectF AreaChartItem::boundingRect() const
89 QRectF AreaChartItem::boundingRect() const
90 {
90 {
91 return m_rect;
91 return m_rect;
92 }
92 }
93
93
94 QPainterPath AreaChartItem::shape() const
94 QPainterPath AreaChartItem::shape() const
95 {
95 {
96 return m_path;
96 return m_path;
97 }
97 }
98
98
99 void AreaChartItem::updatePath()
99 void AreaChartItem::updatePath()
100 {
100 {
101 QPainterPath path;
101 QPainterPath path;
102 QRectF rect(QPointF(0,0),domain()->size());
102 QRectF rect(QPointF(0,0),domain()->size());
103
103
104 path = m_upper->path();
104 path = m_upper->path();
105
105
106 if (m_lower) {
106 if (m_lower) {
107 // Note: Polarcharts always draw area correctly only when both series have equal width or are
107 // Note: Polarcharts always draw area correctly only when both series have equal width or are
108 // fully displayed. If one series is partally off-chart, the connecting line between
108 // fully displayed. If one series is partally off-chart, the connecting line between
109 // the series does not attach to the end of the partially hidden series but to the point
109 // the series does not attach to the end of the partially hidden series but to the point
110 // where it intersects the axis line. The problem is especially noticeable when one of the series
110 // where it intersects the axis line. The problem is especially noticeable when one of the series
111 // is entirely off-chart, in which case the connecting line connects two ends of the
111 // is entirely off-chart, in which case the connecting line connects two ends of the
112 // visible series.
112 // visible series.
113 // This happens because we get the paths from linechart, which omits off-chart segments.
113 // This happens because we get the paths from linechart, which omits off-chart segments.
114 // To properly fix, linechart would need to provide true full path, in right, left, and the rest
114 // To properly fix, linechart would need to provide true full path, in right, left, and the rest
115 // portions to enable proper clipping. However, combining those to single visually unified area
115 // portions to enable proper clipping. However, combining those to single visually unified area
116 // would be a nightmare, since they would have to be painted separately.
116 // would be a nightmare, since they would have to be painted separately.
117 path.connectPath(m_lower->path().toReversed());
117 path.connectPath(m_lower->path().toReversed());
118 } else {
118 } else {
119 QPointF first = path.pointAtPercent(0);
119 QPointF first = path.pointAtPercent(0);
120 QPointF last = path.pointAtPercent(1);
120 QPointF last = path.pointAtPercent(1);
121 if (presenter()->chartType() == QChart::ChartTypeCartesian) {
121 if (presenter()->chartType() == QChart::ChartTypeCartesian) {
122 path.lineTo(last.x(), rect.bottom());
122 path.lineTo(last.x(), rect.bottom());
123 path.lineTo(first.x(), rect.bottom());
123 path.lineTo(first.x(), rect.bottom());
124 } else { // polar
124 } else { // polar
125 path.lineTo(rect.center());
125 path.lineTo(rect.center());
126 }
126 }
127 }
127 }
128 path.closeSubpath();
128 path.closeSubpath();
129
129
130 // Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses
130 // Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses
131 // a region that has to be compatible with QRect.
131 // a region that has to be compatible with QRect.
132 if (path.boundingRect().height() <= INT_MAX
132 if (path.boundingRect().height() <= INT_MAX
133 && path.boundingRect().width() <= INT_MAX) {
133 && path.boundingRect().width() <= INT_MAX) {
134 prepareGeometryChange();
134 prepareGeometryChange();
135 m_path = path;
135 m_path = path;
136 m_rect = path.boundingRect();
136 m_rect = path.boundingRect();
137 update();
137 update();
138 }
138 }
139 }
139 }
140
140
141 void AreaChartItem::handleUpdated()
141 void AreaChartItem::handleUpdated()
142 {
142 {
143 setVisible(m_series->isVisible());
143 setVisible(m_series->isVisible());
144 m_pointsVisible = m_series->pointsVisible();
144 m_pointsVisible = m_series->pointsVisible();
145 m_linePen = m_series->pen();
145 m_linePen = m_series->pen();
146 m_brush = m_series->brush();
146 m_brush = m_series->brush();
147 m_pointPen = m_series->pen();
147 m_pointPen = m_series->pen();
148 m_pointPen.setWidthF(2 * m_pointPen.width());
148 m_pointPen.setWidthF(2 * m_pointPen.width());
149 setOpacity(m_series->opacity());
149 setOpacity(m_series->opacity());
150 m_pointLabelsFormat = m_series->pointLabelsFormat();
150 m_pointLabelsFormat = m_series->pointLabelsFormat();
151 m_pointLabelsVisible = m_series->pointLabelsVisible();
151 m_pointLabelsVisible = m_series->pointLabelsVisible();
152 m_pointLabelsFont = m_series->pointLabelsFont();
152 m_pointLabelsFont = m_series->pointLabelsFont();
153 m_pointLabelsColor = m_series->pointLabelsColor();
153 m_pointLabelsColor = m_series->pointLabelsColor();
154 update();
154 update();
155 }
155 }
156
156
157 void AreaChartItem::handleDomainUpdated()
157 void AreaChartItem::handleDomainUpdated()
158 {
158 {
159 if (m_upper) {
159 if (m_upper) {
160 AbstractDomain* d = m_upper->domain();
160 AbstractDomain* d = m_upper->domain();
161 d->setSize(domain()->size());
161 d->setSize(domain()->size());
162 d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
162 d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
163 m_upper->handleDomainUpdated();
163 m_upper->handleDomainUpdated();
164 }
164 }
165
165
166 if (m_lower) {
166 if (m_lower) {
167 AbstractDomain* d = m_lower->domain();
167 AbstractDomain* d = m_lower->domain();
168 d->setSize(domain()->size());
168 d->setSize(domain()->size());
169 d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
169 d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
170 m_lower->handleDomainUpdated();
170 m_lower->handleDomainUpdated();
171 }
171 }
172 }
172 }
173
173
174 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
174 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
175 {
175 {
176 Q_UNUSED(widget)
176 Q_UNUSED(widget)
177 Q_UNUSED(option)
177 Q_UNUSED(option)
178 painter->save();
178 painter->save();
179 painter->setPen(m_linePen);
179 painter->setPen(m_linePen);
180 painter->setBrush(m_brush);
180 painter->setBrush(m_brush);
181 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
181 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
182 if (presenter()->chartType() == QChart::ChartTypePolar)
182 if (presenter()->chartType() == QChart::ChartTypePolar)
183 painter->setClipRegion(QRegion(clipRect.toRect(), QRegion::Ellipse));
183 painter->setClipRegion(QRegion(clipRect.toRect(), QRegion::Ellipse));
184 else
184 else
185 painter->setClipRect(clipRect);
185 painter->setClipRect(clipRect);
186 painter->drawPath(m_path);
186 painter->drawPath(m_path);
187 if (m_pointsVisible) {
187 if (m_pointsVisible) {
188 painter->setPen(m_pointPen);
188 painter->setPen(m_pointPen);
189 painter->drawPoints(m_upper->geometryPoints());
189 painter->drawPoints(m_upper->geometryPoints());
190 if (m_lower)
190 if (m_lower)
191 painter->drawPoints(m_lower->geometryPoints());
191 painter->drawPoints(m_lower->geometryPoints());
192 }
192 }
193
193
194 // Draw series point label
194 // Draw series point label
195 if (m_pointLabelsVisible) {
195 if (m_pointLabelsVisible) {
196 static const QString xPointTag(QLatin1String("@xPoint"));
196 static const QString xPointTag(QLatin1String("@xPoint"));
197 static const QString yPointTag(QLatin1String("@yPoint"));
197 static const QString yPointTag(QLatin1String("@yPoint"));
198 const int labelOffset = 2;
198 const int labelOffset = 2;
199
199
200 painter->setFont(m_pointLabelsFont);
200 painter->setFont(m_pointLabelsFont);
201 painter->setPen(QPen(m_pointLabelsColor));
201 painter->setPen(QPen(m_pointLabelsColor));
202 QFontMetrics fm(painter->font());
202 QFontMetrics fm(painter->font());
203
203
204 QString pointLabel = m_pointLabelsFormat;
204 QString pointLabel = m_pointLabelsFormat;
205
205
206 if (m_series->upperSeries()) {
206 if (m_series->upperSeries()) {
207 for (int i(0); i < m_series->upperSeries()->count(); i++) {
207 for (int i(0); i < m_series->upperSeries()->count(); i++) {
208 pointLabel.replace(xPointTag,
208 pointLabel.replace(xPointTag,
209 presenter()->numberToString(m_series->upperSeries()->at(i).x()));
209 presenter()->numberToString(m_series->upperSeries()->at(i).x()));
210 pointLabel.replace(yPointTag,
210 pointLabel.replace(yPointTag,
211 presenter()->numberToString(m_series->upperSeries()->at(i).y()));
211 presenter()->numberToString(m_series->upperSeries()->at(i).y()));
212
212
213 // Position text in relation to the point
213 // Position text in relation to the point
214 int pointLabelWidth = fm.width(pointLabel);
214 int pointLabelWidth = fm.width(pointLabel);
215 QPointF position(m_upper->geometryPoints().at(i));
215 QPointF position(m_upper->geometryPoints().at(i));
216 position.setX(position.x() - pointLabelWidth / 2);
216 position.setX(position.x() - pointLabelWidth / 2);
217 position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 - labelOffset);
217 position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 - labelOffset);
218
218
219 painter->drawText(position, pointLabel);
219 painter->drawText(position, pointLabel);
220 }
220 }
221 }
221 }
222
222
223 if (m_series->lowerSeries()) {
223 if (m_series->lowerSeries()) {
224 for (int i(0); i < m_series->lowerSeries()->count(); i++) {
224 for (int i(0); i < m_series->lowerSeries()->count(); i++) {
225 pointLabel.replace(xPointTag,
225 pointLabel.replace(xPointTag,
226 presenter()->numberToString(m_series->lowerSeries()->at(i).x()));
226 presenter()->numberToString(m_series->lowerSeries()->at(i).x()));
227 pointLabel.replace(yPointTag,
227 pointLabel.replace(yPointTag,
228 presenter()->numberToString(m_series->lowerSeries()->at(i).y()));
228 presenter()->numberToString(m_series->lowerSeries()->at(i).y()));
229
229
230 // Position text in relation to the point
230 // Position text in relation to the point
231 int pointLabelWidth = fm.width(pointLabel);
231 int pointLabelWidth = fm.width(pointLabel);
232 QPointF position(m_lower->geometryPoints().at(i));
232 QPointF position(m_lower->geometryPoints().at(i));
233 position.setX(position.x() - pointLabelWidth / 2);
233 position.setX(position.x() - pointLabelWidth / 2);
234 position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 - labelOffset);
234 position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 - labelOffset);
235
235
236 painter->drawText(position, pointLabel);
236 painter->drawText(position, pointLabel);
237 }
237 }
238 }
238 }
239 }
239 }
240
240
241 painter->restore();
241 painter->restore();
242 }
242 }
243
243
244 void AreaChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
244 void AreaChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
245 {
245 {
246 emit pressed(m_upper->domain()->calculateDomainPoint(event->pos()));
246 emit pressed(m_upper->domain()->calculateDomainPoint(event->pos()));
247 m_lastMousePos = event->pos();
247 m_lastMousePos = event->pos();
248 m_mousePressed = true;
248 m_mousePressed = true;
249 ChartItem::mousePressEvent(event);
249 ChartItem::mousePressEvent(event);
250 }
250 }
251
251
252 void AreaChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
252 void AreaChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
253 {
253 {
254 emit hovered(domain()->calculateDomainPoint(event->pos()), true);
254 emit hovered(domain()->calculateDomainPoint(event->pos()), true);
255 event->accept();
255 event->accept();
256 // QGraphicsItem::hoverEnterEvent(event);
256 // QGraphicsItem::hoverEnterEvent(event);
257 }
257 }
258
258
259 void AreaChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
259 void AreaChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
260 {
260 {
261 emit hovered(domain()->calculateDomainPoint(event->pos()), false);
261 emit hovered(domain()->calculateDomainPoint(event->pos()), false);
262 event->accept();
262 event->accept();
263 // QGraphicsItem::hoverEnterEvent(event);
263 // QGraphicsItem::hoverEnterEvent(event);
264 }
264 }
265
265
266 void AreaChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
266 void AreaChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
267 {
267 {
268 emit released(m_upper->domain()->calculateDomainPoint(event->pos()));
268 emit released(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
269 if (m_lastMousePos == event->pos() && m_mousePressed)
269 if (m_mousePressed)
270 emit clicked(m_upper->domain()->calculateDomainPoint(event->pos()));
270 emit clicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
271 m_mousePressed = false;
271 m_mousePressed = false;
272 ChartItem::mouseReleaseEvent(event);
272 ChartItem::mouseReleaseEvent(event);
273 }
273 }
274
274
275 void AreaChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
275 void AreaChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
276 {
276 {
277 emit doubleClicked(m_upper->domain()->calculateDomainPoint(event->pos()));
277 emit doubleClicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
278 ChartItem::mouseDoubleClickEvent(event);
278 ChartItem::mouseDoubleClickEvent(event);
279 }
279 }
280
280
281 #include "moc_areachartitem_p.cpp"
281 #include "moc_areachartitem_p.cpp"
282
282
283 QT_CHARTS_END_NAMESPACE
283 QT_CHARTS_END_NAMESPACE
@@ -1,682 +1,695
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <QtCharts/QAreaSeries>
19 #include <QtCharts/QAreaSeries>
20 #include <private/qareaseries_p.h>
20 #include <private/qareaseries_p.h>
21 #include <QtCharts/QLineSeries>
21 #include <QtCharts/QLineSeries>
22 #include <private/areachartitem_p.h>
22 #include <private/areachartitem_p.h>
23 #include <private/abstractdomain_p.h>
23 #include <private/abstractdomain_p.h>
24 #include <private/chartdataset_p.h>
24 #include <private/chartdataset_p.h>
25 #include <private/charttheme_p.h>
25 #include <private/charttheme_p.h>
26 #include <QtCharts/QValueAxis>
26 #include <QtCharts/QValueAxis>
27 #include <QtCharts/QAreaLegendMarker>
27 #include <QtCharts/QAreaLegendMarker>
28 #include <private/qchart_p.h>
28 #include <private/qchart_p.h>
29
29
30 QT_CHARTS_BEGIN_NAMESPACE
30 QT_CHARTS_BEGIN_NAMESPACE
31
31
32 /*!
32 /*!
33 \class QAreaSeries
33 \class QAreaSeries
34 \inmodule Qt Charts
34 \inmodule Qt Charts
35 \brief The QAreaSeries class is used for making area charts.
35 \brief The QAreaSeries class is used for making area charts.
36
36
37 \mainclass
37 \mainclass
38
38
39 An area chart is used to show quantitative data. It is based on line chart, in the way that area between axis and the line
39 An area chart is used to show quantitative data. It is based on line chart, in the way that area between axis and the line
40 is emphasized with color. Since the area chart is based on line chart, QAreaSeries constructor needs QLineSeries instance,
40 is emphasized with color. Since the area chart is based on line chart, QAreaSeries constructor needs QLineSeries instance,
41 which defines "upper" boundary of the area. "Lower" boundary is defined by default by axis X. Instead of axis X "lower" boundary can be specified by other line.
41 which defines "upper" boundary of the area. "Lower" boundary is defined by default by axis X. Instead of axis X "lower" boundary can be specified by other line.
42 In that case QAreaSeries should be initiated with two QLineSeries instances. Please note terms "upper" and "lower" boundary can be misleading in cases
42 In that case QAreaSeries should be initiated with two QLineSeries instances. Please note terms "upper" and "lower" boundary can be misleading in cases
43 where "lower" boundary had bigger values than the "upper" one, however the main point that area between these two boundary lines will be filled.
43 where "lower" boundary had bigger values than the "upper" one, however the main point that area between these two boundary lines will be filled.
44
44
45 See the \l {AreaChart Example} {area chart example} to learn how to create a simple area chart.
45 See the \l {AreaChart Example} {area chart example} to learn how to create a simple area chart.
46 \image examples_areachart.png
46 \image examples_areachart.png
47 */
47 */
48
48
49 /*!
49 /*!
50 \qmltype AreaSeries
50 \qmltype AreaSeries
51 \instantiates QAreaSeries
51 \instantiates QAreaSeries
52 \inqmlmodule QtCharts
52 \inqmlmodule QtCharts
53
53
54 \inherits AbstractSeries
54 \inherits AbstractSeries
55
55
56 \brief The AreaSeries type is used for making area charts.
56 \brief The AreaSeries type is used for making area charts.
57
57
58 The following QML shows how to create a simple area chart:
58 The following QML shows how to create a simple area chart:
59 \snippet qmlchart/qml/qmlchart/View4.qml 1
59 \snippet qmlchart/qml/qmlchart/View4.qml 1
60 \beginfloatleft
60 \beginfloatleft
61 \image examples_qmlchart4.png
61 \image examples_qmlchart4.png
62 \endfloat
62 \endfloat
63 \clearfloat
63 \clearfloat
64 */
64 */
65
65
66 /*!
66 /*!
67 \property QAreaSeries::upperSeries
67 \property QAreaSeries::upperSeries
68 \brief The upper one of the two line series used to define area series boundaries.
68 \brief The upper one of the two line series used to define area series boundaries.
69 */
69 */
70 /*!
70 /*!
71 \qmlproperty LineSeries AreaSeries::upperSeries
71 \qmlproperty LineSeries AreaSeries::upperSeries
72 The upper one of the two line series used to define area series boundaries.
72 The upper one of the two line series used to define area series boundaries.
73 */
73 */
74
74
75 /*!
75 /*!
76 \property QAreaSeries::lowerSeries
76 \property QAreaSeries::lowerSeries
77 The lower one of the two line series used to define are series boundaries. Note if
77 The lower one of the two line series used to define are series boundaries. Note if
78 QAreaSeries was constructed without a\ lowerSeries this is null.
78 QAreaSeries was constructed without a\ lowerSeries this is null.
79 */
79 */
80 /*!
80 /*!
81 \qmlproperty LineSeries AreaSeries::lowerSeries
81 \qmlproperty LineSeries AreaSeries::lowerSeries
82 The lower one of the two line series used to define are series boundaries. Note if
82 The lower one of the two line series used to define are series boundaries. Note if
83 AreaSeries was constructed without a\ lowerSeries this is null.
83 AreaSeries was constructed without a\ lowerSeries this is null.
84 */
84 */
85
85
86 /*!
86 /*!
87 \property QAreaSeries::color
87 \property QAreaSeries::color
88 Fill (brush) color of the series. This is a convenience property for modifying the color of brush.
88 Fill (brush) color of the series. This is a convenience property for modifying the color of brush.
89 \sa QAreaSeries::brush()
89 \sa QAreaSeries::brush()
90 */
90 */
91 /*!
91 /*!
92 \qmlproperty color AreaSeries::color
92 \qmlproperty color AreaSeries::color
93 Fill (brush) color of the series.
93 Fill (brush) color of the series.
94 */
94 */
95
95
96 /*!
96 /*!
97 \property QAreaSeries::borderColor
97 \property QAreaSeries::borderColor
98 Line (pen) color of the series. This is a convenience property for modifying the color of pen.
98 Line (pen) color of the series. This is a convenience property for modifying the color of pen.
99 \sa QAreaSeries::pen()
99 \sa QAreaSeries::pen()
100 */
100 */
101 /*!
101 /*!
102 \qmlproperty color AreaSeries::borderColor
102 \qmlproperty color AreaSeries::borderColor
103 Line (pen) color of the series.
103 Line (pen) color of the series.
104 */
104 */
105
105
106 /*!
106 /*!
107 \qmlproperty real AreaSeries::borderWidth
107 \qmlproperty real AreaSeries::borderWidth
108 The width of the border line. By default the width is 2.0.
108 The width of the border line. By default the width is 2.0.
109 */
109 */
110
110
111 /*!
111 /*!
112 \fn QPen QAreaSeries::pen() const
112 \fn QPen QAreaSeries::pen() const
113 \brief Returns the pen used to draw line for this series.
113 \brief Returns the pen used to draw line for this series.
114 \sa setPen()
114 \sa setPen()
115 */
115 */
116
116
117 /*!
117 /*!
118 \fn QPen QAreaSeries::brush() const
118 \fn QPen QAreaSeries::brush() const
119 \brief Returns the brush used to draw line for this series.
119 \brief Returns the brush used to draw line for this series.
120 \sa setBrush()
120 \sa setBrush()
121 */
121 */
122
122
123 /*!
123 /*!
124 \qmlproperty QString AreaSeries::brushFilename
124 \qmlproperty QString AreaSeries::brushFilename
125 The name of the file used as a brush image for the series.
125 The name of the file used as a brush image for the series.
126 */
126 */
127
127
128 /*!
128 /*!
129 \fn void QAreaSeries::colorChanged(QColor color)
129 \fn void QAreaSeries::colorChanged(QColor color)
130 \brief Signal is emitted when the fill (brush) color has changed to \a color.
130 \brief Signal is emitted when the fill (brush) color has changed to \a color.
131 */
131 */
132 /*!
132 /*!
133 \qmlsignal AreaSeries::onColorChanged(color color)
133 \qmlsignal AreaSeries::onColorChanged(color color)
134 Signal is emitted when the fill (brush) color has changed to \a color.
134 Signal is emitted when the fill (brush) color has changed to \a color.
135 */
135 */
136
136
137 /*!
137 /*!
138 \fn void QAreaSeries::borderColorChanged(QColor color)
138 \fn void QAreaSeries::borderColorChanged(QColor color)
139 \brief Signal is emitted when the line (pen) color has changed to \a color.
139 \brief Signal is emitted when the line (pen) color has changed to \a color.
140 */
140 */
141 /*!
141 /*!
142 \qmlsignal AreaSeries::onBorderColorChanged(color color)
142 \qmlsignal AreaSeries::onBorderColorChanged(color color)
143 Signal is emitted when the line (pen) color has changed to \a color.
143 Signal is emitted when the line (pen) color has changed to \a color.
144 */
144 */
145
145
146 /*!
146 /*!
147 \fn void QAreaSeries::clicked(const QPointF& point)
147 \fn void QAreaSeries::clicked(const QPointF& point)
148 \brief Signal is emitted when user clicks the \a point on area chart.
148 \brief Signal is emitted when user clicks the \a point on area chart. The \a point is the point
149 where the press was triggered.
150 \sa pressed, released, doubleClicked
149 */
151 */
150 /*!
152 /*!
151 \qmlsignal AreaSeries::onClicked(QPointF point)
153 \qmlsignal AreaSeries::onClicked(QPointF point)
152 Signal is emitted when user clicks the \a point on area chart.
154 Signal is emitted when user clicks the \a point on area chart. The \a point is the point where
155 the press was triggered.
156 \sa onPressed, onReleased, onDoubleClicked
153 */
157 */
154
158
155 /*!
159 /*!
156 \fn void QAreaSeries::hovered(const QPointF &point, bool state)
160 \fn void QAreaSeries::hovered(const QPointF &point, bool state)
157 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
161 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
158 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
162 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
159 the series.
163 the series.
160 */
164 */
161 /*!
165 /*!
162 \qmlsignal AreaSeries::onHovered(point point, bool state)
166 \qmlsignal AreaSeries::onHovered(point point, bool state)
163 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
167 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
164 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
168 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
165 the series.
169 the series.
166 */
170 */
167
171
168 /*!
172 /*!
169 \fn void QAreaSeries::pressed(const QPointF& point)
173 \fn void QAreaSeries::pressed(const QPointF& point)
170 \brief Signal is emitted when user presses the \a point on area chart.
174 \brief Signal is emitted when user presses the \a point on area chart.
175 \sa clicked, released, doubleClicked
171 */
176 */
172 /*!
177 /*!
173 \qmlsignal AreaSeries::onPressed(QPointF point)
178 \qmlsignal AreaSeries::onPressed(QPointF point)
174 Signal is emitted when user presses the \a point on area chart.
179 Signal is emitted when user presses the \a point on area chart.
180 \sa onClicked, onReleased, onDoubleClicked
175 */
181 */
176
182
177 /*!
183 /*!
178 \fn void QAreaSeries::released(const QPointF& point)
184 \fn void QAreaSeries::released(const QPointF& point)
179 \brief Signal is emitted when user releases the \a point on area chart.
185 \brief Signal is emitted when user releases a press that was triggered on a \a point on area
186 chart.
187 \sa pressed, clicked, doubleClicked
180 */
188 */
181 /*!
189 /*!
182 \qmlsignal AreaSeries::onReleased(QPointF point)
190 \qmlsignal AreaSeries::onReleased(QPointF point)
183 Signal is emitted when user releases the \a point on area chart.
191 Signal is emitted when user releases a press that was triggered on a \a point on area chart.
192 \sa onPressed, onClicked, onDoubleClicked
184 */
193 */
185
194
186 /*!
195 /*!
187 \fn void QAreaSeries::doubleClicked(const QPointF& point)
196 \fn void QAreaSeries::doubleClicked(const QPointF& point)
188 \brief Signal is emitted when user doubleclicks the \a point on area chart.
197 \brief Signal is emitted when user doubleclicks the \a point on area chart. The \a point is the
198 point where the first press was triggered.
199 \sa pressed, released, clicked
189 */
200 */
190 /*!
201 /*!
191 \qmlsignal AreaSeries::onDoubleClicked(QPointF point)
202 \qmlsignal AreaSeries::onDoubleClicked(QPointF point)
192 Signal is emitted when user doubleclicks the \a point on area chart.
203 Signal is emitted when user doubleclicks the \a point on area chart. The \a point is the point
204 where the first press was triggered.
205 \sa onPressed, onReleased, onClicked
193 */
206 */
194
207
195 /*!
208 /*!
196 \fn void QAreaSeries::selected()
209 \fn void QAreaSeries::selected()
197 The signal is emitted if the user selects/deselects the XY series. The logic for maintaining selections should be
210 The signal is emitted if the user selects/deselects the XY series. The logic for maintaining selections should be
198 implemented by the user of QAreaSeries API.
211 implemented by the user of QAreaSeries API.
199 */
212 */
200 /*!
213 /*!
201 \qmlsignal AreaSeries::onSelected()
214 \qmlsignal AreaSeries::onSelected()
202 The signal is emitted if the user selects/deselects the XY series. The logic for maintaining selections should be
215 The signal is emitted if the user selects/deselects the XY series. The logic for maintaining selections should be
203 implemented by the user of AreaSeries API.
216 implemented by the user of AreaSeries API.
204 */
217 */
205
218
206 /*!
219 /*!
207 \fn void QAreaSeriesPrivate::updated()
220 \fn void QAreaSeriesPrivate::updated()
208 \brief \internal
221 \brief \internal
209 */
222 */
210
223
211 /*!
224 /*!
212 \property QAreaSeries::pointLabelsFormat
225 \property QAreaSeries::pointLabelsFormat
213 The \a format used for showing labels with series points.
226 The \a format used for showing labels with series points.
214
227
215 QAreaSeries supports the following format tags:
228 QAreaSeries supports the following format tags:
216 \table
229 \table
217 \row
230 \row
218 \li @xPoint \li The x value of the data point
231 \li @xPoint \li The x value of the data point
219 \row
232 \row
220 \li @yPoint \li The y value of the data point
233 \li @yPoint \li The y value of the data point
221 \endtable
234 \endtable
222
235
223 For example, the following usage of the format tags would produce labels that have the data
236 For example, the following usage of the format tags would produce labels that have the data
224 point (x, y) shown inside brackets separated by a comma:
237 point (x, y) shown inside brackets separated by a comma:
225 \code
238 \code
226 series->setPointLabelsFormat("(@xPoint, @yPoint)");
239 series->setPointLabelsFormat("(@xPoint, @yPoint)");
227 \endcode
240 \endcode
228
241
229 By default, the labels format is set to '@xPoint, @yPoint'. The labels are shown on the plot
242 By default, the labels format is set to '@xPoint, @yPoint'. The labels are shown on the plot
230 area, labels on the edge of the plot area are cut. If the points are close to each other the
243 area, labels on the edge of the plot area are cut. If the points are close to each other the
231 labels may overlap.
244 labels may overlap.
232
245
233 \sa QAreaSeries::pointLabelsVisible, QAreaSeries::pointLabelsFont, QAreaSeries::pointLabelsColor
246 \sa QAreaSeries::pointLabelsVisible, QAreaSeries::pointLabelsFont, QAreaSeries::pointLabelsColor
234 */
247 */
235 /*!
248 /*!
236 \qmlproperty string AreaSeries::pointLabelsFormat
249 \qmlproperty string AreaSeries::pointLabelsFormat
237 The \a format used for showing labels with series points.
250 The \a format used for showing labels with series points.
238
251
239 \sa QAreaSeries::pointLabelsFormat, pointLabelsVisible, pointLabelsFont, pointLabelsColor
252 \sa QAreaSeries::pointLabelsFormat, pointLabelsVisible, pointLabelsFont, pointLabelsColor
240 */
253 */
241 /*!
254 /*!
242 \fn void QAreaSeries::pointLabelsFormatChanged(const QString &format)
255 \fn void QAreaSeries::pointLabelsFormatChanged(const QString &format)
243 Signal is emitted when the \a format of data point labels is changed.
256 Signal is emitted when the \a format of data point labels is changed.
244 */
257 */
245 /*!
258 /*!
246 \qmlsignal AreaSeries::onPointLabelsFormatChanged(string format)
259 \qmlsignal AreaSeries::onPointLabelsFormatChanged(string format)
247 Signal is emitted when the \a format of data point labels is changed.
260 Signal is emitted when the \a format of data point labels is changed.
248 */
261 */
249
262
250 /*!
263 /*!
251 \property QAreaSeries::pointLabelsVisible
264 \property QAreaSeries::pointLabelsVisible
252 Defines the visibility for data point labels. False by default.
265 Defines the visibility for data point labels. False by default.
253
266
254 \sa QAreaSeries::pointLabelsFormat
267 \sa QAreaSeries::pointLabelsFormat
255 */
268 */
256 /*!
269 /*!
257 \qmlproperty bool AreaSeries::pointLabelsVisible
270 \qmlproperty bool AreaSeries::pointLabelsVisible
258 Defines the visibility for data point labels.
271 Defines the visibility for data point labels.
259
272
260 \sa pointLabelsFormat
273 \sa pointLabelsFormat
261 */
274 */
262 /*!
275 /*!
263 \fn void QAreaSeries::pointLabelsVisibilityChanged(bool visible)
276 \fn void QAreaSeries::pointLabelsVisibilityChanged(bool visible)
264 The visibility of the data point labels is changed to \a visible.
277 The visibility of the data point labels is changed to \a visible.
265 */
278 */
266 /*!
279 /*!
267 \qmlsignal AreaSeries::onPointLabelsVisibilityChanged(bool visible)
280 \qmlsignal AreaSeries::onPointLabelsVisibilityChanged(bool visible)
268 The visibility of the data point labels is changed to \a visible.
281 The visibility of the data point labels is changed to \a visible.
269 */
282 */
270
283
271 /*!
284 /*!
272 \property QAreaSeries::pointLabelsFont
285 \property QAreaSeries::pointLabelsFont
273 Defines the font used for data point labels.
286 Defines the font used for data point labels.
274
287
275 \sa QAreaSeries::pointLabelsFormat
288 \sa QAreaSeries::pointLabelsFormat
276 */
289 */
277 /*!
290 /*!
278 \qmlproperty font AreaSeries::pointLabelsFont
291 \qmlproperty font AreaSeries::pointLabelsFont
279 Defines the font used for data point labels.
292 Defines the font used for data point labels.
280
293
281 \sa pointLabelsFormat
294 \sa pointLabelsFormat
282 */
295 */
283 /*!
296 /*!
284 \fn void QAreaSeries::pointLabelsFontChanged(const QFont &font);
297 \fn void QAreaSeries::pointLabelsFontChanged(const QFont &font);
285 The font used for data point labels is changed to \a font.
298 The font used for data point labels is changed to \a font.
286 */
299 */
287 /*!
300 /*!
288 \qmlsignal AreaSeries::onPointLabelsFontChanged(Font font)
301 \qmlsignal AreaSeries::onPointLabelsFontChanged(Font font)
289 The font used for data point labels is changed to \a font.
302 The font used for data point labels is changed to \a font.
290 */
303 */
291
304
292 /*!
305 /*!
293 \property QAreaSeries::pointLabelsColor
306 \property QAreaSeries::pointLabelsColor
294 Defines the color used for data point labels. By default, the color is the color of the brush
307 Defines the color used for data point labels. By default, the color is the color of the brush
295 defined in theme for labels.
308 defined in theme for labels.
296
309
297 \sa QAreaSeries::pointLabelsFormat
310 \sa QAreaSeries::pointLabelsFormat
298 */
311 */
299 /*!
312 /*!
300 \qmlproperty font AreaSeries::pointLabelsColor
313 \qmlproperty font AreaSeries::pointLabelsColor
301 Defines the color used for data point labels. By default, the color is the color of the brush
314 Defines the color used for data point labels. By default, the color is the color of the brush
302 defined in theme for labels.
315 defined in theme for labels.
303
316
304 \sa pointLabelsFormat
317 \sa pointLabelsFormat
305 */
318 */
306 /*!
319 /*!
307 \fn void QAreaSeries::pointLabelsColorChanged(const QColor &color);
320 \fn void QAreaSeries::pointLabelsColorChanged(const QColor &color);
308 The color used for data point labels is changed to \a color.
321 The color used for data point labels is changed to \a color.
309 */
322 */
310 /*!
323 /*!
311 \qmlsignal AreaSeries::onPointLabelsColorChanged(Color color)
324 \qmlsignal AreaSeries::onPointLabelsColorChanged(Color color)
312 The color used for data point labels is changed to \a color.
325 The color used for data point labels is changed to \a color.
313 */
326 */
314
327
315 /*!
328 /*!
316 Constructs area series object which is a child of \a upperSeries. Area will be spanned between \a
329 Constructs area series object which is a child of \a upperSeries. Area will be spanned between \a
317 upperSeries line and \a lowerSeries line. If no \a lowerSeries is passed to constructor, area is specified by axis x (y=0) instead.
330 upperSeries line and \a lowerSeries line. If no \a lowerSeries is passed to constructor, area is specified by axis x (y=0) instead.
318 When series object is added to QChartView or QChart instance ownerships is transferred.
331 When series object is added to QChartView or QChart instance ownerships is transferred.
319 */
332 */
320 QAreaSeries::QAreaSeries(QLineSeries *upperSeries, QLineSeries *lowerSeries)
333 QAreaSeries::QAreaSeries(QLineSeries *upperSeries, QLineSeries *lowerSeries)
321 : QAbstractSeries(*new QAreaSeriesPrivate(upperSeries, lowerSeries, this), upperSeries)
334 : QAbstractSeries(*new QAreaSeriesPrivate(upperSeries, lowerSeries, this), upperSeries)
322 {
335 {
323 }
336 }
324
337
325 /*!
338 /*!
326 Constructs area series object without upper or lower series with \a parent object.
339 Constructs area series object without upper or lower series with \a parent object.
327 */
340 */
328 QAreaSeries::QAreaSeries(QObject *parent)
341 QAreaSeries::QAreaSeries(QObject *parent)
329 : QAbstractSeries(*new QAreaSeriesPrivate(0, 0, this), parent)
342 : QAbstractSeries(*new QAreaSeriesPrivate(0, 0, this), parent)
330 {
343 {
331 }
344 }
332
345
333 /*!
346 /*!
334 Destroys the object.
347 Destroys the object.
335 */
348 */
336 QAreaSeries::~QAreaSeries()
349 QAreaSeries::~QAreaSeries()
337 {
350 {
338 Q_D(QAreaSeries);
351 Q_D(QAreaSeries);
339 if (d->m_chart)
352 if (d->m_chart)
340 d->m_chart->removeSeries(this);
353 d->m_chart->removeSeries(this);
341 }
354 }
342
355
343 /*!
356 /*!
344 Returns QAbstractSeries::SeriesTypeArea.
357 Returns QAbstractSeries::SeriesTypeArea.
345 */
358 */
346 QAbstractSeries::SeriesType QAreaSeries::type() const
359 QAbstractSeries::SeriesType QAreaSeries::type() const
347 {
360 {
348 return QAbstractSeries::SeriesTypeArea;
361 return QAbstractSeries::SeriesTypeArea;
349 }
362 }
350
363
351 /*!
364 /*!
352 Sets the \a series that is to be used as the area chart upper series.
365 Sets the \a series that is to be used as the area chart upper series.
353 */
366 */
354 void QAreaSeries::setUpperSeries(QLineSeries *series)
367 void QAreaSeries::setUpperSeries(QLineSeries *series)
355 {
368 {
356 Q_D(QAreaSeries);
369 Q_D(QAreaSeries);
357 if (d->m_upperSeries != series)
370 if (d->m_upperSeries != series)
358 d->m_upperSeries = series;
371 d->m_upperSeries = series;
359 }
372 }
360
373
361 QLineSeries *QAreaSeries::upperSeries() const
374 QLineSeries *QAreaSeries::upperSeries() const
362 {
375 {
363 Q_D(const QAreaSeries);
376 Q_D(const QAreaSeries);
364 return d->m_upperSeries;
377 return d->m_upperSeries;
365 }
378 }
366
379
367 /*!
380 /*!
368 Sets the \a series that is to be used as the area chart lower series.
381 Sets the \a series that is to be used as the area chart lower series.
369 */
382 */
370 void QAreaSeries::setLowerSeries(QLineSeries *series)
383 void QAreaSeries::setLowerSeries(QLineSeries *series)
371 {
384 {
372 Q_D(QAreaSeries);
385 Q_D(QAreaSeries);
373 d->m_lowerSeries = series;
386 d->m_lowerSeries = series;
374 }
387 }
375
388
376 QLineSeries *QAreaSeries::lowerSeries() const
389 QLineSeries *QAreaSeries::lowerSeries() const
377 {
390 {
378 Q_D(const QAreaSeries);
391 Q_D(const QAreaSeries);
379 return d->m_lowerSeries;
392 return d->m_lowerSeries;
380 }
393 }
381
394
382 /*!
395 /*!
383 Sets \a pen used for drawing area outline.
396 Sets \a pen used for drawing area outline.
384 */
397 */
385 void QAreaSeries::setPen(const QPen &pen)
398 void QAreaSeries::setPen(const QPen &pen)
386 {
399 {
387 Q_D(QAreaSeries);
400 Q_D(QAreaSeries);
388 if (d->m_pen != pen) {
401 if (d->m_pen != pen) {
389 d->m_pen = pen;
402 d->m_pen = pen;
390 emit d->updated();
403 emit d->updated();
391 }
404 }
392 }
405 }
393
406
394 QPen QAreaSeries::pen() const
407 QPen QAreaSeries::pen() const
395 {
408 {
396 Q_D(const QAreaSeries);
409 Q_D(const QAreaSeries);
397 if (d->m_pen == QChartPrivate::defaultPen())
410 if (d->m_pen == QChartPrivate::defaultPen())
398 return QPen();
411 return QPen();
399 else
412 else
400 return d->m_pen;
413 return d->m_pen;
401 }
414 }
402
415
403 /*!
416 /*!
404 Sets \a brush used for filling the area.
417 Sets \a brush used for filling the area.
405 */
418 */
406 void QAreaSeries::setBrush(const QBrush &brush)
419 void QAreaSeries::setBrush(const QBrush &brush)
407 {
420 {
408 Q_D(QAreaSeries);
421 Q_D(QAreaSeries);
409 if (d->m_brush != brush) {
422 if (d->m_brush != brush) {
410 bool emitColorChanged = brush.color() != d->m_brush.color();
423 bool emitColorChanged = brush.color() != d->m_brush.color();
411 d->m_brush = brush;
424 d->m_brush = brush;
412 emit d->updated();
425 emit d->updated();
413 if (emitColorChanged)
426 if (emitColorChanged)
414 emit colorChanged(brush.color());
427 emit colorChanged(brush.color());
415 }
428 }
416 }
429 }
417
430
418 QBrush QAreaSeries::brush() const
431 QBrush QAreaSeries::brush() const
419 {
432 {
420 Q_D(const QAreaSeries);
433 Q_D(const QAreaSeries);
421 if (d->m_brush == QChartPrivate::defaultBrush())
434 if (d->m_brush == QChartPrivate::defaultBrush())
422 return QBrush();
435 return QBrush();
423 else
436 else
424 return d->m_brush;
437 return d->m_brush;
425 }
438 }
426
439
427 void QAreaSeries::setColor(const QColor &color)
440 void QAreaSeries::setColor(const QColor &color)
428 {
441 {
429 QBrush b = brush();
442 QBrush b = brush();
430 if (b == QBrush())
443 if (b == QBrush())
431 b.setStyle(Qt::SolidPattern);
444 b.setStyle(Qt::SolidPattern);
432 b.setColor(color);
445 b.setColor(color);
433 setBrush(b);
446 setBrush(b);
434 }
447 }
435
448
436 QColor QAreaSeries::color() const
449 QColor QAreaSeries::color() const
437 {
450 {
438 return brush().color();
451 return brush().color();
439 }
452 }
440
453
441 void QAreaSeries::setBorderColor(const QColor &color)
454 void QAreaSeries::setBorderColor(const QColor &color)
442 {
455 {
443 QPen p = pen();
456 QPen p = pen();
444 if (p.color() != color) {
457 if (p.color() != color) {
445 p.setColor(color);
458 p.setColor(color);
446 setPen(p);
459 setPen(p);
447 emit borderColorChanged(color);
460 emit borderColorChanged(color);
448 }
461 }
449 }
462 }
450
463
451 QColor QAreaSeries::borderColor() const
464 QColor QAreaSeries::borderColor() const
452 {
465 {
453 return pen().color();
466 return pen().color();
454 }
467 }
455
468
456 /*!
469 /*!
457 Sets if data points are \a visible and should be drawn on line.
470 Sets if data points are \a visible and should be drawn on line.
458 */
471 */
459 void QAreaSeries::setPointsVisible(bool visible)
472 void QAreaSeries::setPointsVisible(bool visible)
460 {
473 {
461 Q_D(QAreaSeries);
474 Q_D(QAreaSeries);
462 if (d->m_pointsVisible != visible) {
475 if (d->m_pointsVisible != visible) {
463 d->m_pointsVisible = visible;
476 d->m_pointsVisible = visible;
464 emit d->updated();
477 emit d->updated();
465 }
478 }
466 }
479 }
467
480
468 /*!
481 /*!
469 Returns if the points are drawn for this series.
482 Returns if the points are drawn for this series.
470 \sa setPointsVisible()
483 \sa setPointsVisible()
471 */
484 */
472 bool QAreaSeries::pointsVisible() const
485 bool QAreaSeries::pointsVisible() const
473 {
486 {
474 Q_D(const QAreaSeries);
487 Q_D(const QAreaSeries);
475 return d->m_pointsVisible;
488 return d->m_pointsVisible;
476 }
489 }
477
490
478 void QAreaSeries::setPointLabelsFormat(const QString &format)
491 void QAreaSeries::setPointLabelsFormat(const QString &format)
479 {
492 {
480 Q_D(QAreaSeries);
493 Q_D(QAreaSeries);
481 if (d->m_pointLabelsFormat != format) {
494 if (d->m_pointLabelsFormat != format) {
482 d->m_pointLabelsFormat = format;
495 d->m_pointLabelsFormat = format;
483 emit pointLabelsFormatChanged(format);
496 emit pointLabelsFormatChanged(format);
484 }
497 }
485 }
498 }
486
499
487 QString QAreaSeries::pointLabelsFormat() const
500 QString QAreaSeries::pointLabelsFormat() const
488 {
501 {
489 Q_D(const QAreaSeries);
502 Q_D(const QAreaSeries);
490 return d->m_pointLabelsFormat;
503 return d->m_pointLabelsFormat;
491 }
504 }
492
505
493 void QAreaSeries::setPointLabelsVisible(bool visible)
506 void QAreaSeries::setPointLabelsVisible(bool visible)
494 {
507 {
495 Q_D(QAreaSeries);
508 Q_D(QAreaSeries);
496 if (d->m_pointLabelsVisible != visible) {
509 if (d->m_pointLabelsVisible != visible) {
497 d->m_pointLabelsVisible = visible;
510 d->m_pointLabelsVisible = visible;
498 emit pointLabelsVisibilityChanged(visible);
511 emit pointLabelsVisibilityChanged(visible);
499 }
512 }
500 }
513 }
501
514
502 bool QAreaSeries::pointLabelsVisible() const
515 bool QAreaSeries::pointLabelsVisible() const
503 {
516 {
504 Q_D(const QAreaSeries);
517 Q_D(const QAreaSeries);
505 return d->m_pointLabelsVisible;
518 return d->m_pointLabelsVisible;
506 }
519 }
507
520
508 void QAreaSeries::setPointLabelsFont(const QFont &font)
521 void QAreaSeries::setPointLabelsFont(const QFont &font)
509 {
522 {
510 Q_D(QAreaSeries);
523 Q_D(QAreaSeries);
511 if (d->m_pointLabelsFont != font) {
524 if (d->m_pointLabelsFont != font) {
512 d->m_pointLabelsFont = font;
525 d->m_pointLabelsFont = font;
513 emit pointLabelsFontChanged(font);
526 emit pointLabelsFontChanged(font);
514 }
527 }
515 }
528 }
516
529
517 QFont QAreaSeries::pointLabelsFont() const
530 QFont QAreaSeries::pointLabelsFont() const
518 {
531 {
519 Q_D(const QAreaSeries);
532 Q_D(const QAreaSeries);
520 return d->m_pointLabelsFont;
533 return d->m_pointLabelsFont;
521 }
534 }
522
535
523 void QAreaSeries::setPointLabelsColor(const QColor &color)
536 void QAreaSeries::setPointLabelsColor(const QColor &color)
524 {
537 {
525 Q_D(QAreaSeries);
538 Q_D(QAreaSeries);
526 if (d->m_pointLabelsColor != color) {
539 if (d->m_pointLabelsColor != color) {
527 d->m_pointLabelsColor = color;
540 d->m_pointLabelsColor = color;
528 emit pointLabelsColorChanged(color);
541 emit pointLabelsColorChanged(color);
529 }
542 }
530 }
543 }
531
544
532 QColor QAreaSeries::pointLabelsColor() const
545 QColor QAreaSeries::pointLabelsColor() const
533 {
546 {
534 Q_D(const QAreaSeries);
547 Q_D(const QAreaSeries);
535 if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color())
548 if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color())
536 return QPen().color();
549 return QPen().color();
537 else
550 else
538 return d->m_pointLabelsColor;
551 return d->m_pointLabelsColor;
539 }
552 }
540
553
541 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
554 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
542
555
543 QAreaSeriesPrivate::QAreaSeriesPrivate(QLineSeries *upperSeries, QLineSeries *lowerSeries, QAreaSeries *q)
556 QAreaSeriesPrivate::QAreaSeriesPrivate(QLineSeries *upperSeries, QLineSeries *lowerSeries, QAreaSeries *q)
544 : QAbstractSeriesPrivate(q),
557 : QAbstractSeriesPrivate(q),
545 m_brush(QChartPrivate::defaultBrush()),
558 m_brush(QChartPrivate::defaultBrush()),
546 m_pen(QChartPrivate::defaultPen()),
559 m_pen(QChartPrivate::defaultPen()),
547 m_upperSeries(upperSeries),
560 m_upperSeries(upperSeries),
548 m_lowerSeries(lowerSeries),
561 m_lowerSeries(lowerSeries),
549 m_pointsVisible(false),
562 m_pointsVisible(false),
550 m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint")),
563 m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint")),
551 m_pointLabelsVisible(false),
564 m_pointLabelsVisible(false),
552 m_pointLabelsFont(QChartPrivate::defaultFont()),
565 m_pointLabelsFont(QChartPrivate::defaultFont()),
553 m_pointLabelsColor(QChartPrivate::defaultPen().color())
566 m_pointLabelsColor(QChartPrivate::defaultPen().color())
554 {
567 {
555 }
568 }
556
569
557 void QAreaSeriesPrivate::initializeDomain()
570 void QAreaSeriesPrivate::initializeDomain()
558 {
571 {
559 Q_Q(QAreaSeries);
572 Q_Q(QAreaSeries);
560
573
561 qreal minX(domain()->minX());
574 qreal minX(domain()->minX());
562 qreal minY(domain()->minY());
575 qreal minY(domain()->minY());
563 qreal maxX(domain()->maxX());
576 qreal maxX(domain()->maxX());
564 qreal maxY(domain()->maxY());
577 qreal maxY(domain()->maxY());
565
578
566 QLineSeries *upperSeries = q->upperSeries();
579 QLineSeries *upperSeries = q->upperSeries();
567 QLineSeries *lowerSeries = q->lowerSeries();
580 QLineSeries *lowerSeries = q->lowerSeries();
568
581
569 if (upperSeries) {
582 if (upperSeries) {
570 const QList<QPointF>& points = upperSeries->points();
583 const QList<QPointF>& points = upperSeries->points();
571
584
572 for (int i = 0; i < points.count(); i++) {
585 for (int i = 0; i < points.count(); i++) {
573 qreal x = points[i].x();
586 qreal x = points[i].x();
574 qreal y = points[i].y();
587 qreal y = points[i].y();
575 minX = qMin(minX, x);
588 minX = qMin(minX, x);
576 minY = qMin(minY, y);
589 minY = qMin(minY, y);
577 maxX = qMax(maxX, x);
590 maxX = qMax(maxX, x);
578 maxY = qMax(maxY, y);
591 maxY = qMax(maxY, y);
579 }
592 }
580 }
593 }
581 if (lowerSeries) {
594 if (lowerSeries) {
582
595
583 const QList<QPointF>& points = lowerSeries->points();
596 const QList<QPointF>& points = lowerSeries->points();
584
597
585 for (int i = 0; i < points.count(); i++) {
598 for (int i = 0; i < points.count(); i++) {
586 qreal x = points[i].x();
599 qreal x = points[i].x();
587 qreal y = points[i].y();
600 qreal y = points[i].y();
588 minX = qMin(minX, x);
601 minX = qMin(minX, x);
589 minY = qMin(minY, y);
602 minY = qMin(minY, y);
590 maxX = qMax(maxX, x);
603 maxX = qMax(maxX, x);
591 maxY = qMax(maxY, y);
604 maxY = qMax(maxY, y);
592 }
605 }
593 }
606 }
594
607
595 domain()->setRange(minX, maxX, minY, maxY);
608 domain()->setRange(minX, maxX, minY, maxY);
596 }
609 }
597
610
598 void QAreaSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
611 void QAreaSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
599 {
612 {
600 Q_Q(QAreaSeries);
613 Q_Q(QAreaSeries);
601 AreaChartItem *area = new AreaChartItem(q,parent);
614 AreaChartItem *area = new AreaChartItem(q,parent);
602 m_item.reset(area);
615 m_item.reset(area);
603 QAbstractSeriesPrivate::initializeGraphics(parent);
616 QAbstractSeriesPrivate::initializeGraphics(parent);
604 }
617 }
605 void QAreaSeriesPrivate::initializeAnimations(QChart::AnimationOptions options)
618 void QAreaSeriesPrivate::initializeAnimations(QChart::AnimationOptions options)
606 {
619 {
607 Q_Q(QAreaSeries);
620 Q_Q(QAreaSeries);
608 AreaChartItem *area = static_cast<AreaChartItem *>(m_item.data());
621 AreaChartItem *area = static_cast<AreaChartItem *>(m_item.data());
609
622
610 if (q->upperSeries() && area->upperLineItem()->animation())
623 if (q->upperSeries() && area->upperLineItem()->animation())
611 area->upperLineItem()->animation()->stopAndDestroyLater();
624 area->upperLineItem()->animation()->stopAndDestroyLater();
612 if (q->lowerSeries() && area->lowerLineItem()->animation())
625 if (q->lowerSeries() && area->lowerLineItem()->animation())
613 area->lowerLineItem()->animation()->stopAndDestroyLater();
626 area->lowerLineItem()->animation()->stopAndDestroyLater();
614
627
615 if (options.testFlag(QChart::SeriesAnimations)) {
628 if (options.testFlag(QChart::SeriesAnimations)) {
616 area->upperLineItem()->setAnimation(new XYAnimation(area->upperLineItem()));
629 area->upperLineItem()->setAnimation(new XYAnimation(area->upperLineItem()));
617 if (q->lowerSeries())
630 if (q->lowerSeries())
618 area->lowerLineItem()->setAnimation(new XYAnimation(area->lowerLineItem()));
631 area->lowerLineItem()->setAnimation(new XYAnimation(area->lowerLineItem()));
619 } else {
632 } else {
620 if (q->upperSeries())
633 if (q->upperSeries())
621 area->upperLineItem()->setAnimation(0);
634 area->upperLineItem()->setAnimation(0);
622 if (q->lowerSeries())
635 if (q->lowerSeries())
623 area->lowerLineItem()->setAnimation(0);
636 area->lowerLineItem()->setAnimation(0);
624 }
637 }
625 QAbstractSeriesPrivate::initializeAnimations(options);
638 QAbstractSeriesPrivate::initializeAnimations(options);
626 }
639 }
627
640
628 QList<QLegendMarker*> QAreaSeriesPrivate::createLegendMarkers(QLegend* legend)
641 QList<QLegendMarker*> QAreaSeriesPrivate::createLegendMarkers(QLegend* legend)
629 {
642 {
630 Q_Q(QAreaSeries);
643 Q_Q(QAreaSeries);
631 QList<QLegendMarker*> list;
644 QList<QLegendMarker*> list;
632 return list << new QAreaLegendMarker(q,legend);
645 return list << new QAreaLegendMarker(q,legend);
633 }
646 }
634
647
635
648
636 void QAreaSeriesPrivate::initializeAxes()
649 void QAreaSeriesPrivate::initializeAxes()
637 {
650 {
638
651
639 }
652 }
640
653
641 QAbstractAxis::AxisType QAreaSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
654 QAbstractAxis::AxisType QAreaSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
642 {
655 {
643 Q_UNUSED(orientation);
656 Q_UNUSED(orientation);
644 return QAbstractAxis::AxisTypeValue;
657 return QAbstractAxis::AxisTypeValue;
645 }
658 }
646
659
647 QAbstractAxis* QAreaSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
660 QAbstractAxis* QAreaSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
648 {
661 {
649 Q_UNUSED(orientation);
662 Q_UNUSED(orientation);
650 return new QValueAxis;
663 return new QValueAxis;
651 }
664 }
652
665
653 void QAreaSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
666 void QAreaSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
654 {
667 {
655 Q_Q(QAreaSeries);
668 Q_Q(QAreaSeries);
656
669
657 const QList<QGradient> gradients = theme->seriesGradients();
670 const QList<QGradient> gradients = theme->seriesGradients();
658 const QList<QColor> colors = theme->seriesColors();
671 const QList<QColor> colors = theme->seriesColors();
659
672
660 if (forced || QChartPrivate::defaultPen() == m_pen) {
673 if (forced || QChartPrivate::defaultPen() == m_pen) {
661 QPen pen;
674 QPen pen;
662 pen.setColor(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0));
675 pen.setColor(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0));
663 pen.setWidthF(2);
676 pen.setWidthF(2);
664 q->setPen(pen);
677 q->setPen(pen);
665 }
678 }
666
679
667 if (forced || QChartPrivate::defaultBrush() == m_brush) {
680 if (forced || QChartPrivate::defaultBrush() == m_brush) {
668 QBrush brush(colors.at(index % colors.size()));
681 QBrush brush(colors.at(index % colors.size()));
669 q->setBrush(brush);
682 q->setBrush(brush);
670 }
683 }
671
684
672 if (forced || QChartPrivate::defaultPen().color() == m_pointLabelsColor) {
685 if (forced || QChartPrivate::defaultPen().color() == m_pointLabelsColor) {
673 QColor color = theme->labelBrush().color();
686 QColor color = theme->labelBrush().color();
674 q->setPointLabelsColor(color);
687 q->setPointLabelsColor(color);
675 }
688 }
676 }
689 }
677
690
678
691
679 #include "moc_qareaseries.cpp"
692 #include "moc_qareaseries.cpp"
680 #include "moc_qareaseries_p.cpp"
693 #include "moc_qareaseries_p.cpp"
681
694
682 QT_CHARTS_END_NAMESPACE
695 QT_CHARTS_END_NAMESPACE
@@ -1,93 +1,92
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/bar_p.h>
19 #include <private/bar_p.h>
20 #include <QtGui/QPainter>
20 #include <QtGui/QPainter>
21 #include <QtWidgets/QGraphicsSceneEvent>
21 #include <QtWidgets/QGraphicsSceneEvent>
22 #include <QtWidgets/QStyleOptionGraphicsItem>
22 #include <QtWidgets/QStyleOptionGraphicsItem>
23 #include <QtWidgets/QStyle>
23 #include <QtWidgets/QStyle>
24
24
25 QT_CHARTS_BEGIN_NAMESPACE
25 QT_CHARTS_BEGIN_NAMESPACE
26
26
27 Bar::Bar(QBarSet *barset, int index, QGraphicsItem *parent) : QGraphicsRectItem(parent),
27 Bar::Bar(QBarSet *barset, int index, QGraphicsItem *parent) : QGraphicsRectItem(parent),
28 m_index(index),
28 m_index(index),
29 m_barset(barset),
29 m_barset(barset),
30 m_hovering(false),
30 m_hovering(false),
31 m_mousePressed(false)
31 m_mousePressed(false)
32 {
32 {
33 setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
33 setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
34 setAcceptHoverEvents(true);
34 setAcceptHoverEvents(true);
35 setFlag(QGraphicsItem::ItemIsSelectable);
35 setFlag(QGraphicsItem::ItemIsSelectable);
36 }
36 }
37
37
38 Bar::~Bar()
38 Bar::~Bar()
39 {
39 {
40 // End hover event, if bar is deleted during it
40 // End hover event, if bar is deleted during it
41 if (m_hovering)
41 if (m_hovering)
42 emit hovered(false, m_index, m_barset);
42 emit hovered(false, m_index, m_barset);
43 }
43 }
44
44
45 void Bar::mousePressEvent(QGraphicsSceneMouseEvent *event)
45 void Bar::mousePressEvent(QGraphicsSceneMouseEvent *event)
46 {
46 {
47 emit pressed(m_index, m_barset);
47 emit pressed(m_index, m_barset);
48 m_lastMousePos = event->pos();
49 m_mousePressed = true;
48 m_mousePressed = true;
50 QGraphicsItem::mousePressEvent(event);
49 QGraphicsItem::mousePressEvent(event);
51 }
50 }
52
51
53 void Bar::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
52 void Bar::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
54 {
53 {
55 Q_UNUSED(event)
54 Q_UNUSED(event)
56 m_hovering = true;
55 m_hovering = true;
57 emit hovered(true, m_index, m_barset);
56 emit hovered(true, m_index, m_barset);
58
57
59 }
58 }
60
59
61 void Bar::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
60 void Bar::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
62 {
61 {
63 Q_UNUSED(event)
62 Q_UNUSED(event)
64 m_hovering = false;
63 m_hovering = false;
65 emit hovered(false, m_index, m_barset);
64 emit hovered(false, m_index, m_barset);
66 }
65 }
67
66
68 void Bar::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
67 void Bar::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
69 {
68 {
70 emit released(m_index, m_barset);
69 emit released(m_index, m_barset);
71 if (m_lastMousePos == event->pos() && m_mousePressed)
70 if (m_mousePressed)
72 emit clicked(m_index, m_barset);
71 emit clicked(m_index, m_barset);
73 m_mousePressed = false;
72 m_mousePressed = false;
74 QGraphicsItem::mouseReleaseEvent(event);
73 QGraphicsItem::mouseReleaseEvent(event);
75 }
74 }
76
75
77 void Bar::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
76 void Bar::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
78 {
77 {
79 emit doubleClicked(m_index, m_barset);
78 emit doubleClicked(m_index, m_barset);
80 QGraphicsItem::mouseDoubleClickEvent(event);
79 QGraphicsItem::mouseDoubleClickEvent(event);
81 }
80 }
82
81
83 void Bar::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
82 void Bar::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
84 {
83 {
85 // Remove selection border around bar
84 // Remove selection border around bar
86 QStyleOptionGraphicsItem barOption(*option);
85 QStyleOptionGraphicsItem barOption(*option);
87 barOption.state &= ~QStyle::State_Selected;
86 barOption.state &= ~QStyle::State_Selected;
88 QGraphicsRectItem::paint(painter, &barOption, widget);
87 QGraphicsRectItem::paint(painter, &barOption, widget);
89 }
88 }
90
89
91 #include "moc_bar_p.cpp"
90 #include "moc_bar_p.cpp"
92
91
93 QT_CHARTS_END_NAMESPACE
92 QT_CHARTS_END_NAMESPACE
@@ -1,73 +1,72
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 // W A R N I N G
19 // W A R N I N G
20 // -------------
20 // -------------
21 //
21 //
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
23 // implementation detail. This header file may change from version to
23 // implementation detail. This header file may change from version to
24 // version without notice, or even be removed.
24 // version without notice, or even be removed.
25 //
25 //
26 // We mean it.
26 // We mean it.
27
27
28 #ifndef BAR_H
28 #ifndef BAR_H
29 #define BAR_H
29 #define BAR_H
30
30
31 #include <QtCharts/QChartGlobal>
31 #include <QtCharts/QChartGlobal>
32 #include <QtWidgets/QGraphicsRectItem>
32 #include <QtWidgets/QGraphicsRectItem>
33
33
34 QT_CHARTS_BEGIN_NAMESPACE
34 QT_CHARTS_BEGIN_NAMESPACE
35
35
36 class QBarSet;
36 class QBarSet;
37
37
38 // Single visual bar item of chart
38 // Single visual bar item of chart
39 class Bar : public QObject, public QGraphicsRectItem
39 class Bar : public QObject, public QGraphicsRectItem
40 {
40 {
41 Q_OBJECT
41 Q_OBJECT
42 public:
42 public:
43 Bar(QBarSet *barset, int index, QGraphicsItem *parent = 0);
43 Bar(QBarSet *barset, int index, QGraphicsItem *parent = 0);
44 ~Bar();
44 ~Bar();
45
45
46 public:
46 public:
47 void mousePressEvent(QGraphicsSceneMouseEvent *event);
47 void mousePressEvent(QGraphicsSceneMouseEvent *event);
48 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
48 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
49 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
49 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
50 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
50 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
51 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
51 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
52
52
53 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
53 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
54
54
55 Q_SIGNALS:
55 Q_SIGNALS:
56 void clicked(int index, QBarSet *barset);
56 void clicked(int index, QBarSet *barset);
57 void hovered(bool status, int index, QBarSet *barset);
57 void hovered(bool status, int index, QBarSet *barset);
58 void pressed(int index, QBarSet *barset);
58 void pressed(int index, QBarSet *barset);
59 void released(int index, QBarSet *barset);
59 void released(int index, QBarSet *barset);
60 void doubleClicked(int index, QBarSet *barset);
60 void doubleClicked(int index, QBarSet *barset);
61
61
62 private:
62 private:
63 int m_index;
63 int m_index;
64 QBarSet *m_barset;
64 QBarSet *m_barset;
65 bool m_hovering;
65 bool m_hovering;
66
66
67 QPointF m_lastMousePos;
68 bool m_mousePressed;
67 bool m_mousePressed;
69 };
68 };
70
69
71 QT_CHARTS_END_NAMESPACE
70 QT_CHARTS_END_NAMESPACE
72
71
73 #endif // BAR_H
72 #endif // BAR_H
@@ -1,211 +1,212
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/boxwhiskers_p.h>
19 #include <private/boxwhiskers_p.h>
20 #include <QtGui/QPainter>
20 #include <QtGui/QPainter>
21 #include <QtWidgets/QWidget>
21 #include <QtWidgets/QWidget>
22 #include <QtWidgets/QGraphicsSceneMouseEvent>
22 #include <QtWidgets/QGraphicsSceneMouseEvent>
23
23
24 QT_CHARTS_BEGIN_NAMESPACE
24 QT_CHARTS_BEGIN_NAMESPACE
25
25
26 BoxWhiskers::BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent) :
26 BoxWhiskers::BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent) :
27 QGraphicsObject(parent),
27 QGraphicsObject(parent),
28 m_boxSet(set),
28 m_boxSet(set),
29 m_domain(domain),
29 m_domain(domain),
30 m_mousePressed(false)
30 m_mousePressed(false)
31 {
31 {
32 setAcceptHoverEvents(true);
32 setAcceptHoverEvents(true);
33 setAcceptedMouseButtons(Qt::MouseButtonMask);
33 setAcceptedMouseButtons(Qt::MouseButtonMask);
34 setFlag(QGraphicsObject::ItemIsSelectable);
34 setFlag(QGraphicsObject::ItemIsSelectable);
35 }
35 }
36
36
37 BoxWhiskers::~BoxWhiskers()
37 BoxWhiskers::~BoxWhiskers()
38 {
38 {
39 }
39 }
40
40
41 void BoxWhiskers::mousePressEvent(QGraphicsSceneMouseEvent *event)
41 void BoxWhiskers::mousePressEvent(QGraphicsSceneMouseEvent *event)
42 {
42 {
43 Q_UNUSED(event)
43 emit pressed(m_boxSet);
44 emit pressed(m_boxSet);
44 m_lastMousePos = event->pos();
45 m_mousePressed = true;
45 m_mousePressed = true;
46 }
46 }
47
47
48 void BoxWhiskers::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
48 void BoxWhiskers::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
49 {
49 {
50 Q_UNUSED(event)
50 Q_UNUSED(event)
51 emit hovered(true, m_boxSet);
51 emit hovered(true, m_boxSet);
52 }
52 }
53
53
54 void BoxWhiskers::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
54 void BoxWhiskers::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
55 {
55 {
56 Q_UNUSED(event)
56 Q_UNUSED(event)
57 emit hovered(false, m_boxSet);
57 emit hovered(false, m_boxSet);
58 }
58 }
59
59
60 void BoxWhiskers::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
60 void BoxWhiskers::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
61 {
61 {
62 Q_UNUSED(event)
62 emit released(m_boxSet);
63 emit released(m_boxSet);
63 if (m_lastMousePos == event->pos() && m_mousePressed)
64 if (m_mousePressed)
64 emit clicked(m_boxSet);
65 emit clicked(m_boxSet);
65 }
66 }
66
67
67 void BoxWhiskers::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
68 void BoxWhiskers::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
68 {
69 {
69 Q_UNUSED(event)
70 Q_UNUSED(event)
70 // For Box a press signal needs to be explicitly fired for mouseDoubleClickEvent
71 // For Box a press signal needs to be explicitly fired for mouseDoubleClickEvent
71 emit pressed(m_boxSet);
72 emit pressed(m_boxSet);
72 emit doubleClicked(m_boxSet);
73 emit doubleClicked(m_boxSet);
73 }
74 }
74
75
75 void BoxWhiskers::setBrush(const QBrush &brush)
76 void BoxWhiskers::setBrush(const QBrush &brush)
76 {
77 {
77 m_brush = brush;
78 m_brush = brush;
78 m_outlinePen.setColor(m_brush.color());
79 m_outlinePen.setColor(m_brush.color());
79 update();
80 update();
80 }
81 }
81
82
82 void BoxWhiskers::setPen(const QPen &pen)
83 void BoxWhiskers::setPen(const QPen &pen)
83 {
84 {
84 qreal widthDiff = pen.widthF() - m_pen.widthF();
85 qreal widthDiff = pen.widthF() - m_pen.widthF();
85 m_boundingRect.adjust(-widthDiff, -widthDiff, widthDiff, widthDiff);
86 m_boundingRect.adjust(-widthDiff, -widthDiff, widthDiff, widthDiff);
86
87
87 m_pen = pen;
88 m_pen = pen;
88 m_medianPen = pen;
89 m_medianPen = pen;
89 m_medianPen.setCapStyle(Qt::FlatCap);
90 m_medianPen.setCapStyle(Qt::FlatCap);
90 m_outlinePen = pen;
91 m_outlinePen = pen;
91 m_outlinePen.setStyle(Qt::SolidLine);
92 m_outlinePen.setStyle(Qt::SolidLine);
92 m_outlinePen.setColor(m_brush.color());
93 m_outlinePen.setColor(m_brush.color());
93
94
94 update();
95 update();
95 }
96 }
96
97
97 void BoxWhiskers::setBoxWidth(const qreal width)
98 void BoxWhiskers::setBoxWidth(const qreal width)
98 {
99 {
99 m_boxWidth = width;
100 m_boxWidth = width;
100 }
101 }
101
102
102 void BoxWhiskers::setLayout(const BoxWhiskersData &data)
103 void BoxWhiskers::setLayout(const BoxWhiskersData &data)
103 {
104 {
104 m_data = data;
105 m_data = data;
105
106
106 updateGeometry(m_domain);
107 updateGeometry(m_domain);
107 update();
108 update();
108 }
109 }
109
110
110 QSizeF BoxWhiskers::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
111 QSizeF BoxWhiskers::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
111 {
112 {
112 Q_UNUSED(which)
113 Q_UNUSED(which)
113 Q_UNUSED(constraint)
114 Q_UNUSED(constraint)
114
115
115 return QSizeF();
116 return QSizeF();
116 }
117 }
117
118
118 void BoxWhiskers::setGeometry(const QRectF &rect)
119 void BoxWhiskers::setGeometry(const QRectF &rect)
119 {
120 {
120 Q_UNUSED(rect)
121 Q_UNUSED(rect)
121 }
122 }
122
123
123 QRectF BoxWhiskers::boundingRect() const
124 QRectF BoxWhiskers::boundingRect() const
124 {
125 {
125 return m_boundingRect;
126 return m_boundingRect;
126 }
127 }
127
128
128 void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
129 void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
129 {
130 {
130 Q_UNUSED(option)
131 Q_UNUSED(option)
131 Q_UNUSED(widget)
132 Q_UNUSED(widget)
132
133
133 painter->save();
134 painter->save();
134 painter->setBrush(m_brush);
135 painter->setBrush(m_brush);
135 painter->setClipRect(parentItem()->boundingRect());
136 painter->setClipRect(parentItem()->boundingRect());
136 painter->setPen(m_pen);
137 painter->setPen(m_pen);
137 painter->drawPath(m_boxPath);
138 painter->drawPath(m_boxPath);
138 if (!m_boxOutlined)
139 if (!m_boxOutlined)
139 painter->setPen(m_outlinePen);
140 painter->setPen(m_outlinePen);
140 painter->drawRect(m_middleBox);
141 painter->drawRect(m_middleBox);
141 painter->setPen(m_medianPen);
142 painter->setPen(m_medianPen);
142 qreal halfLine = m_pen.widthF() / 2.0;
143 qreal halfLine = m_pen.widthF() / 2.0;
143 painter->drawLine(QLineF(m_geometryLeft - halfLine, m_geometryMedian,
144 painter->drawLine(QLineF(m_geometryLeft - halfLine, m_geometryMedian,
144 m_geometryRight + halfLine, m_geometryMedian));
145 m_geometryRight + halfLine, m_geometryMedian));
145 painter->restore();
146 painter->restore();
146 }
147 }
147
148
148 void BoxWhiskers::updateGeometry(AbstractDomain *domain)
149 void BoxWhiskers::updateGeometry(AbstractDomain *domain)
149 {
150 {
150 m_domain = domain;
151 m_domain = domain;
151
152
152 prepareGeometryChange();
153 prepareGeometryChange();
153
154
154 QPainterPath path;
155 QPainterPath path;
155 m_boxPath = path;
156 m_boxPath = path;
156 m_boundingRect = m_boxPath.boundingRect();
157 m_boundingRect = m_boxPath.boundingRect();
157
158
158 qreal columnWidth = 1.0 / m_data.m_seriesCount;
159 qreal columnWidth = 1.0 / m_data.m_seriesCount;
159 qreal left = ((1.0 - m_boxWidth) / 2.0) * columnWidth + columnWidth * m_data.m_seriesIndex + m_data.m_index - 0.5;
160 qreal left = ((1.0 - m_boxWidth) / 2.0) * columnWidth + columnWidth * m_data.m_seriesIndex + m_data.m_index - 0.5;
160 qreal barWidth = m_boxWidth * columnWidth;
161 qreal barWidth = m_boxWidth * columnWidth;
161
162
162 QPointF geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_upperExtreme), m_validData);
163 QPointF geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_upperExtreme), m_validData);
163 if (!m_validData)
164 if (!m_validData)
164 return;
165 return;
165 m_geometryLeft = geometryPoint.x();
166 m_geometryLeft = geometryPoint.x();
166 qreal geometryUpperExtreme = geometryPoint.y();
167 qreal geometryUpperExtreme = geometryPoint.y();
167 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left + barWidth, m_data.m_upperQuartile), m_validData);
168 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left + barWidth, m_data.m_upperQuartile), m_validData);
168 if (!m_validData)
169 if (!m_validData)
169 return;
170 return;
170 m_geometryRight = geometryPoint.x();
171 m_geometryRight = geometryPoint.x();
171 qreal geometryUpperQuartile = geometryPoint.y();
172 qreal geometryUpperQuartile = geometryPoint.y();
172 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerQuartile), m_validData);
173 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerQuartile), m_validData);
173 if (!m_validData)
174 if (!m_validData)
174 return;
175 return;
175 qreal geometryLowerQuartile = geometryPoint.y();
176 qreal geometryLowerQuartile = geometryPoint.y();
176 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerExtreme), m_validData);
177 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerExtreme), m_validData);
177 if (!m_validData)
178 if (!m_validData)
178 return;
179 return;
179 qreal geometryLowerExtreme = geometryPoint.y();
180 qreal geometryLowerExtreme = geometryPoint.y();
180 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_median), m_validData);
181 geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_median), m_validData);
181 if (!m_validData)
182 if (!m_validData)
182 return;
183 return;
183 m_geometryMedian = geometryPoint.y();
184 m_geometryMedian = geometryPoint.y();
184
185
185 // Upper whisker
186 // Upper whisker
186 path.moveTo(m_geometryLeft, geometryUpperExtreme);
187 path.moveTo(m_geometryLeft, geometryUpperExtreme);
187 path.lineTo(m_geometryRight, geometryUpperExtreme);
188 path.lineTo(m_geometryRight, geometryUpperExtreme);
188 path.moveTo((m_geometryLeft + m_geometryRight) / 2.0, geometryUpperExtreme);
189 path.moveTo((m_geometryLeft + m_geometryRight) / 2.0, geometryUpperExtreme);
189 path.lineTo((m_geometryLeft + m_geometryRight) / 2.0, geometryUpperQuartile);
190 path.lineTo((m_geometryLeft + m_geometryRight) / 2.0, geometryUpperQuartile);
190
191
191 // Middle Box
192 // Middle Box
192 m_middleBox.setCoords(m_geometryLeft, geometryUpperQuartile, m_geometryRight, geometryLowerQuartile);
193 m_middleBox.setCoords(m_geometryLeft, geometryUpperQuartile, m_geometryRight, geometryLowerQuartile);
193
194
194 // Lower whisker
195 // Lower whisker
195 path.moveTo(m_geometryLeft, geometryLowerExtreme);
196 path.moveTo(m_geometryLeft, geometryLowerExtreme);
196 path.lineTo(m_geometryRight, geometryLowerExtreme);
197 path.lineTo(m_geometryRight, geometryLowerExtreme);
197 path.moveTo((m_geometryLeft + m_geometryRight) / 2.0, geometryLowerQuartile);
198 path.moveTo((m_geometryLeft + m_geometryRight) / 2.0, geometryLowerQuartile);
198 path.lineTo((m_geometryLeft + m_geometryRight) / 2.0, geometryLowerExtreme);
199 path.lineTo((m_geometryLeft + m_geometryRight) / 2.0, geometryLowerExtreme);
199
200
200 path.closeSubpath();
201 path.closeSubpath();
201
202
202 m_boxPath = path;
203 m_boxPath = path;
203 m_boundingRect = m_boxPath.boundingRect();
204 m_boundingRect = m_boxPath.boundingRect();
204
205
205 qreal extra = m_pen.widthF();
206 qreal extra = m_pen.widthF();
206 m_boundingRect.adjust(-extra, -extra, extra, extra);
207 m_boundingRect.adjust(-extra, -extra, extra, extra);
207 }
208 }
208
209
209 #include "moc_boxwhiskers_p.cpp"
210 #include "moc_boxwhiskers_p.cpp"
210
211
211 QT_CHARTS_END_NAMESPACE
212 QT_CHARTS_END_NAMESPACE
@@ -1,108 +1,107
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 // W A R N I N G
19 // W A R N I N G
20 // -------------
20 // -------------
21 //
21 //
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
23 // implementation detail. This header file may change from version to
23 // implementation detail. This header file may change from version to
24 // version without notice, or even be removed.
24 // version without notice, or even be removed.
25 //
25 //
26 // We mean it.
26 // We mean it.
27
27
28 #ifndef BOXWHISKERS_H
28 #ifndef BOXWHISKERS_H
29 #define BOXWHISKERS_H
29 #define BOXWHISKERS_H
30
30
31 #include <private/boxwhiskersdata_p.h>
31 #include <private/boxwhiskersdata_p.h>
32 #include <QtCharts/QChartGlobal>
32 #include <QtCharts/QChartGlobal>
33 #include <private/abstractdomain_p.h>
33 #include <private/abstractdomain_p.h>
34 #include <QtCharts/QBoxSet>
34 #include <QtCharts/QBoxSet>
35 #include <QtWidgets/QGraphicsRectItem>
35 #include <QtWidgets/QGraphicsRectItem>
36 #include <QtWidgets/QGraphicsLineItem>
36 #include <QtWidgets/QGraphicsLineItem>
37 #include <QtWidgets/QGraphicsLayoutItem>
37 #include <QtWidgets/QGraphicsLayoutItem>
38 #include <QtGui/QPainterPath>
38 #include <QtGui/QPainterPath>
39
39
40 QT_CHARTS_BEGIN_NAMESPACE
40 QT_CHARTS_BEGIN_NAMESPACE
41
41
42 class QBarSet;
42 class QBarSet;
43
43
44 class BoxWhiskers : public QGraphicsObject
44 class BoxWhiskers : public QGraphicsObject
45 {
45 {
46 Q_OBJECT
46 Q_OBJECT
47
47
48 public:
48 public:
49 BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent);
49 BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent);
50 ~BoxWhiskers();
50 ~BoxWhiskers();
51
51
52 void setBrush(const QBrush &brush);
52 void setBrush(const QBrush &brush);
53 void setPen(const QPen &pen);
53 void setPen(const QPen &pen);
54 void setLayout(const BoxWhiskersData &data);
54 void setLayout(const BoxWhiskersData &data);
55 void setBoxOutlined(const bool outlined) { m_boxOutlined = outlined; }
55 void setBoxOutlined(const bool outlined) { m_boxOutlined = outlined; }
56 void setBoxWidth(const qreal width);
56 void setBoxWidth(const qreal width);
57
57
58 void mousePressEvent(QGraphicsSceneMouseEvent *event);
58 void mousePressEvent(QGraphicsSceneMouseEvent *event);
59 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
59 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
60 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
60 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
61 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
61 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
62 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
62 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
63
63
64 QRectF boundingRect() const;
64 QRectF boundingRect() const;
65 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
65 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
66
66
67 void updateGeometry(AbstractDomain *domain);
67 void updateGeometry(AbstractDomain *domain);
68 protected:
68 protected:
69 QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
69 QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
70 void setGeometry(const QRectF &rect);
70 void setGeometry(const QRectF &rect);
71
71
72 Q_SIGNALS:
72 Q_SIGNALS:
73 void clicked(QBoxSet *boxset);
73 void clicked(QBoxSet *boxset);
74 void hovered(bool status, QBoxSet *boxset);
74 void hovered(bool status, QBoxSet *boxset);
75 void pressed(QBoxSet *boxset);
75 void pressed(QBoxSet *boxset);
76 void released(QBoxSet *boxset);
76 void released(QBoxSet *boxset);
77 void doubleClicked(QBoxSet *boxset);
77 void doubleClicked(QBoxSet *boxset);
78
78
79 private:
79 private:
80 friend class BoxPlotChartItem;
80 friend class BoxPlotChartItem;
81 friend class BoxPlotAnimation;
81 friend class BoxPlotAnimation;
82
82
83 QBoxSet *m_boxSet;
83 QBoxSet *m_boxSet;
84 AbstractDomain *m_domain;
84 AbstractDomain *m_domain;
85 QPainterPath m_boxPath;
85 QPainterPath m_boxPath;
86 QRectF m_boundingRect;
86 QRectF m_boundingRect;
87 bool m_hovering;
87 bool m_hovering;
88 bool m_validData;
88 bool m_validData;
89 QBrush m_brush;
89 QBrush m_brush;
90 QPen m_pen;
90 QPen m_pen;
91 QPen m_medianPen;
91 QPen m_medianPen;
92 QPen m_outlinePen;
92 QPen m_outlinePen;
93 bool m_boxOutlined;
93 bool m_boxOutlined;
94 qreal m_boxWidth;
94 qreal m_boxWidth;
95 BoxWhiskersData m_data;
95 BoxWhiskersData m_data;
96 QSizeF m_domainSize;
96 QSizeF m_domainSize;
97 QRectF m_middleBox;
97 QRectF m_middleBox;
98 qreal m_geometryMedian;
98 qreal m_geometryMedian;
99 qreal m_geometryLeft;
99 qreal m_geometryLeft;
100 qreal m_geometryRight;
100 qreal m_geometryRight;
101
101
102 QPointF m_lastMousePos;
103 bool m_mousePressed;
102 bool m_mousePressed;
104 };
103 };
105
104
106 QT_CHARTS_END_NAMESPACE
105 QT_CHARTS_END_NAMESPACE
107
106
108 #endif // BOXWHISKERS_H
107 #endif // BOXWHISKERS_H
@@ -1,422 +1,422
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/linechartitem_p.h>
19 #include <private/linechartitem_p.h>
20 #include <QtCharts/QLineSeries>
20 #include <QtCharts/QLineSeries>
21 #include <private/qlineseries_p.h>
21 #include <private/qlineseries_p.h>
22 #include <private/chartpresenter_p.h>
22 #include <private/chartpresenter_p.h>
23 #include <private/polardomain_p.h>
23 #include <private/polardomain_p.h>
24 #include <private/chartthememanager_p.h>
24 #include <private/chartthememanager_p.h>
25 #include <private/charttheme_p.h>
25 #include <private/charttheme_p.h>
26 #include <QtGui/QPainter>
26 #include <QtGui/QPainter>
27 #include <QtWidgets/QGraphicsSceneMouseEvent>
27 #include <QtWidgets/QGraphicsSceneMouseEvent>
28
28
29 QT_CHARTS_BEGIN_NAMESPACE
29 QT_CHARTS_BEGIN_NAMESPACE
30
30
31 const qreal mouseEventMinWidth(12);
31 const qreal mouseEventMinWidth(12);
32
32
33 LineChartItem::LineChartItem(QLineSeries *series, QGraphicsItem *item)
33 LineChartItem::LineChartItem(QLineSeries *series, QGraphicsItem *item)
34 : XYChart(series,item),
34 : XYChart(series,item),
35 m_series(series),
35 m_series(series),
36 m_pointsVisible(false),
36 m_pointsVisible(false),
37 m_chartType(QChart::ChartTypeUndefined),
37 m_chartType(QChart::ChartTypeUndefined),
38 m_pointLabelsVisible(false),
38 m_pointLabelsVisible(false),
39 m_pointLabelsFormat(series->pointLabelsFormat()),
39 m_pointLabelsFormat(series->pointLabelsFormat()),
40 m_pointLabelsFont(series->pointLabelsFont()),
40 m_pointLabelsFont(series->pointLabelsFont()),
41 m_pointLabelsColor(series->pointLabelsColor()),
41 m_pointLabelsColor(series->pointLabelsColor()),
42 m_mousePressed(false)
42 m_mousePressed(false)
43 {
43 {
44 setAcceptHoverEvents(true);
44 setAcceptHoverEvents(true);
45 setFlag(QGraphicsItem::ItemIsSelectable);
45 setFlag(QGraphicsItem::ItemIsSelectable);
46 setZValue(ChartPresenter::LineChartZValue);
46 setZValue(ChartPresenter::LineChartZValue);
47 QObject::connect(series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
47 QObject::connect(series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
48 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
48 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
49 QObject::connect(series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
49 QObject::connect(series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
50 QObject::connect(series, SIGNAL(pointLabelsFormatChanged(QString)),
50 QObject::connect(series, SIGNAL(pointLabelsFormatChanged(QString)),
51 this, SLOT(handleUpdated()));
51 this, SLOT(handleUpdated()));
52 QObject::connect(series, SIGNAL(pointLabelsVisibilityChanged(bool)),
52 QObject::connect(series, SIGNAL(pointLabelsVisibilityChanged(bool)),
53 this, SLOT(handleUpdated()));
53 this, SLOT(handleUpdated()));
54 QObject::connect(series, SIGNAL(pointLabelsFontChanged(QFont)), this, SLOT(handleUpdated()));
54 QObject::connect(series, SIGNAL(pointLabelsFontChanged(QFont)), this, SLOT(handleUpdated()));
55 QObject::connect(series, SIGNAL(pointLabelsColorChanged(QColor)), this, SLOT(handleUpdated()));
55 QObject::connect(series, SIGNAL(pointLabelsColorChanged(QColor)), this, SLOT(handleUpdated()));
56 handleUpdated();
56 handleUpdated();
57 }
57 }
58
58
59 QRectF LineChartItem::boundingRect() const
59 QRectF LineChartItem::boundingRect() const
60 {
60 {
61 return m_rect;
61 return m_rect;
62 }
62 }
63
63
64 QPainterPath LineChartItem::shape() const
64 QPainterPath LineChartItem::shape() const
65 {
65 {
66 return m_shapePath;
66 return m_shapePath;
67 }
67 }
68
68
69 void LineChartItem::updateGeometry()
69 void LineChartItem::updateGeometry()
70 {
70 {
71 m_points = geometryPoints();
71 m_points = geometryPoints();
72 const QVector<QPointF> &points = m_points;
72 const QVector<QPointF> &points = m_points;
73
73
74 if (points.size() == 0) {
74 if (points.size() == 0) {
75 prepareGeometryChange();
75 prepareGeometryChange();
76 m_fullPath = QPainterPath();
76 m_fullPath = QPainterPath();
77 m_linePath = QPainterPath();
77 m_linePath = QPainterPath();
78 m_rect = QRect();
78 m_rect = QRect();
79 return;
79 return;
80 }
80 }
81
81
82 QPainterPath linePath;
82 QPainterPath linePath;
83 QPainterPath fullPath;
83 QPainterPath fullPath;
84 // Use worst case scenario to determine required margin.
84 // Use worst case scenario to determine required margin.
85 qreal margin = m_linePen.width() * 1.42;
85 qreal margin = m_linePen.width() * 1.42;
86
86
87 // Area series use component line series that aren't necessarily added to the chart themselves,
87 // Area series use component line series that aren't necessarily added to the chart themselves,
88 // so check if chart type is forced before trying to obtain it from the chart.
88 // so check if chart type is forced before trying to obtain it from the chart.
89 QChart::ChartType chartType = m_chartType;
89 QChart::ChartType chartType = m_chartType;
90 if (chartType == QChart::ChartTypeUndefined)
90 if (chartType == QChart::ChartTypeUndefined)
91 chartType = m_series->chart()->chartType();
91 chartType = m_series->chart()->chartType();
92
92
93 // For polar charts, we need special handling for angular (horizontal)
93 // For polar charts, we need special handling for angular (horizontal)
94 // points that are off-grid.
94 // points that are off-grid.
95 if (chartType == QChart::ChartTypePolar) {
95 if (chartType == QChart::ChartTypePolar) {
96 QPainterPath linePathLeft;
96 QPainterPath linePathLeft;
97 QPainterPath linePathRight;
97 QPainterPath linePathRight;
98 QPainterPath *currentSegmentPath = 0;
98 QPainterPath *currentSegmentPath = 0;
99 QPainterPath *previousSegmentPath = 0;
99 QPainterPath *previousSegmentPath = 0;
100 qreal minX = domain()->minX();
100 qreal minX = domain()->minX();
101 qreal maxX = domain()->maxX();
101 qreal maxX = domain()->maxX();
102 qreal minY = domain()->minY();
102 qreal minY = domain()->minY();
103 QPointF currentSeriesPoint = m_series->at(0);
103 QPointF currentSeriesPoint = m_series->at(0);
104 QPointF currentGeometryPoint = points.at(0);
104 QPointF currentGeometryPoint = points.at(0);
105 QPointF previousGeometryPoint = points.at(0);
105 QPointF previousGeometryPoint = points.at(0);
106 int size = m_linePen.width();
106 int size = m_linePen.width();
107 bool pointOffGrid = false;
107 bool pointOffGrid = false;
108 bool previousPointWasOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
108 bool previousPointWasOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
109
109
110 qreal domainRadius = domain()->size().height() / 2.0;
110 qreal domainRadius = domain()->size().height() / 2.0;
111 const QPointF centerPoint(domainRadius, domainRadius);
111 const QPointF centerPoint(domainRadius, domainRadius);
112
112
113 if (!previousPointWasOffGrid) {
113 if (!previousPointWasOffGrid) {
114 fullPath.moveTo(points.at(0));
114 fullPath.moveTo(points.at(0));
115 if (m_pointsVisible && currentSeriesPoint.y() >= minY) {
115 if (m_pointsVisible && currentSeriesPoint.y() >= minY) {
116 // Do not draw ellipses for points below minimum Y.
116 // Do not draw ellipses for points below minimum Y.
117 linePath.addEllipse(points.at(0), size, size);
117 linePath.addEllipse(points.at(0), size, size);
118 fullPath.addEllipse(points.at(0), size, size);
118 fullPath.addEllipse(points.at(0), size, size);
119 linePath.moveTo(points.at(0));
119 linePath.moveTo(points.at(0));
120 fullPath.moveTo(points.at(0));
120 fullPath.moveTo(points.at(0));
121 }
121 }
122 }
122 }
123
123
124 qreal leftMarginLine = centerPoint.x() - margin;
124 qreal leftMarginLine = centerPoint.x() - margin;
125 qreal rightMarginLine = centerPoint.x() + margin;
125 qreal rightMarginLine = centerPoint.x() + margin;
126 qreal horizontal = centerPoint.y();
126 qreal horizontal = centerPoint.y();
127
127
128 // See ScatterChartItem::updateGeometry() for explanation why seriesLastIndex is needed
128 // See ScatterChartItem::updateGeometry() for explanation why seriesLastIndex is needed
129 const int seriesLastIndex = m_series->count() - 1;
129 const int seriesLastIndex = m_series->count() - 1;
130
130
131 for (int i = 1; i < points.size(); i++) {
131 for (int i = 1; i < points.size(); i++) {
132 // Interpolating line fragments would be ugly when thick pen is used,
132 // Interpolating line fragments would be ugly when thick pen is used,
133 // so we work around it by utilizing three separate
133 // so we work around it by utilizing three separate
134 // paths for line segments and clip those with custom regions at paint time.
134 // paths for line segments and clip those with custom regions at paint time.
135 // "Right" path contains segments that cross the axis line with visible point on the
135 // "Right" path contains segments that cross the axis line with visible point on the
136 // right side of the axis line, as well as segments that have one point within the margin
136 // right side of the axis line, as well as segments that have one point within the margin
137 // on the right side of the axis line and another point on the right side of the chart.
137 // on the right side of the axis line and another point on the right side of the chart.
138 // "Left" path contains points with similarly on the left side.
138 // "Left" path contains points with similarly on the left side.
139 // "Full" path contains rest of the points.
139 // "Full" path contains rest of the points.
140 // This doesn't yield perfect results always. E.g. when segment covers more than 90
140 // This doesn't yield perfect results always. E.g. when segment covers more than 90
141 // degrees and both of the points are within the margin, one in the top half and one in the
141 // degrees and both of the points are within the margin, one in the top half and one in the
142 // bottom half of the chart, the bottom one gets clipped incorrectly.
142 // bottom half of the chart, the bottom one gets clipped incorrectly.
143 // However, this should be rare occurrence in any sensible chart.
143 // However, this should be rare occurrence in any sensible chart.
144 currentSeriesPoint = m_series->at(qMin(seriesLastIndex, i));
144 currentSeriesPoint = m_series->at(qMin(seriesLastIndex, i));
145 currentGeometryPoint = points.at(i);
145 currentGeometryPoint = points.at(i);
146 pointOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
146 pointOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
147
147
148 // Draw something unless both off-grid
148 // Draw something unless both off-grid
149 if (!pointOffGrid || !previousPointWasOffGrid) {
149 if (!pointOffGrid || !previousPointWasOffGrid) {
150 QPointF intersectionPoint;
150 QPointF intersectionPoint;
151 qreal y;
151 qreal y;
152 if (pointOffGrid != previousPointWasOffGrid) {
152 if (pointOffGrid != previousPointWasOffGrid) {
153 if (currentGeometryPoint.x() == previousGeometryPoint.x()) {
153 if (currentGeometryPoint.x() == previousGeometryPoint.x()) {
154 y = currentGeometryPoint.y() + (currentGeometryPoint.y() - previousGeometryPoint.y()) / 2.0;
154 y = currentGeometryPoint.y() + (currentGeometryPoint.y() - previousGeometryPoint.y()) / 2.0;
155 } else {
155 } else {
156 qreal ratio = (centerPoint.x() - currentGeometryPoint.x()) / (currentGeometryPoint.x() - previousGeometryPoint.x());
156 qreal ratio = (centerPoint.x() - currentGeometryPoint.x()) / (currentGeometryPoint.x() - previousGeometryPoint.x());
157 y = currentGeometryPoint.y() + (currentGeometryPoint.y() - previousGeometryPoint.y()) * ratio;
157 y = currentGeometryPoint.y() + (currentGeometryPoint.y() - previousGeometryPoint.y()) * ratio;
158 }
158 }
159 intersectionPoint = QPointF(centerPoint.x(), y);
159 intersectionPoint = QPointF(centerPoint.x(), y);
160 }
160 }
161
161
162 bool dummyOk; // We know points are ok, but this is needed
162 bool dummyOk; // We know points are ok, but this is needed
163 qreal currentAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(currentSeriesPoint.x(), dummyOk);
163 qreal currentAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(currentSeriesPoint.x(), dummyOk);
164 qreal previousAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(m_series->at(i - 1).x(), dummyOk);
164 qreal previousAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(m_series->at(i - 1).x(), dummyOk);
165
165
166 if ((qAbs(currentAngle - previousAngle) > 180.0)) {
166 if ((qAbs(currentAngle - previousAngle) > 180.0)) {
167 // If the angle between two points is over 180 degrees (half X range),
167 // If the angle between two points is over 180 degrees (half X range),
168 // any direct segment between them becomes meaningless.
168 // any direct segment between them becomes meaningless.
169 // In this case two line segments are drawn instead, from previous
169 // In this case two line segments are drawn instead, from previous
170 // point to the center and from center to current point.
170 // point to the center and from center to current point.
171 if ((previousAngle < 0.0 || (previousAngle <= 180.0 && previousGeometryPoint.x() < rightMarginLine))
171 if ((previousAngle < 0.0 || (previousAngle <= 180.0 && previousGeometryPoint.x() < rightMarginLine))
172 && previousGeometryPoint.y() < horizontal) {
172 && previousGeometryPoint.y() < horizontal) {
173 currentSegmentPath = &linePathRight;
173 currentSegmentPath = &linePathRight;
174 } else if ((previousAngle > 360.0 || (previousAngle > 180.0 && previousGeometryPoint.x() > leftMarginLine))
174 } else if ((previousAngle > 360.0 || (previousAngle > 180.0 && previousGeometryPoint.x() > leftMarginLine))
175 && previousGeometryPoint.y() < horizontal) {
175 && previousGeometryPoint.y() < horizontal) {
176 currentSegmentPath = &linePathLeft;
176 currentSegmentPath = &linePathLeft;
177 } else if (previousAngle > 0.0 && previousAngle < 360.0) {
177 } else if (previousAngle > 0.0 && previousAngle < 360.0) {
178 currentSegmentPath = &linePath;
178 currentSegmentPath = &linePath;
179 } else {
179 } else {
180 currentSegmentPath = 0;
180 currentSegmentPath = 0;
181 }
181 }
182
182
183 if (currentSegmentPath) {
183 if (currentSegmentPath) {
184 if (previousSegmentPath != currentSegmentPath)
184 if (previousSegmentPath != currentSegmentPath)
185 currentSegmentPath->moveTo(previousGeometryPoint);
185 currentSegmentPath->moveTo(previousGeometryPoint);
186 if (previousPointWasOffGrid)
186 if (previousPointWasOffGrid)
187 fullPath.moveTo(intersectionPoint);
187 fullPath.moveTo(intersectionPoint);
188
188
189 currentSegmentPath->lineTo(centerPoint);
189 currentSegmentPath->lineTo(centerPoint);
190 fullPath.lineTo(centerPoint);
190 fullPath.lineTo(centerPoint);
191 }
191 }
192
192
193 previousSegmentPath = currentSegmentPath;
193 previousSegmentPath = currentSegmentPath;
194
194
195 if ((currentAngle < 0.0 || (currentAngle <= 180.0 && currentGeometryPoint.x() < rightMarginLine))
195 if ((currentAngle < 0.0 || (currentAngle <= 180.0 && currentGeometryPoint.x() < rightMarginLine))
196 && currentGeometryPoint.y() < horizontal) {
196 && currentGeometryPoint.y() < horizontal) {
197 currentSegmentPath = &linePathRight;
197 currentSegmentPath = &linePathRight;
198 } else if ((currentAngle > 360.0 || (currentAngle > 180.0 &&currentGeometryPoint.x() > leftMarginLine))
198 } else if ((currentAngle > 360.0 || (currentAngle > 180.0 &&currentGeometryPoint.x() > leftMarginLine))
199 && currentGeometryPoint.y() < horizontal) {
199 && currentGeometryPoint.y() < horizontal) {
200 currentSegmentPath = &linePathLeft;
200 currentSegmentPath = &linePathLeft;
201 } else if (currentAngle > 0.0 && currentAngle < 360.0) {
201 } else if (currentAngle > 0.0 && currentAngle < 360.0) {
202 currentSegmentPath = &linePath;
202 currentSegmentPath = &linePath;
203 } else {
203 } else {
204 currentSegmentPath = 0;
204 currentSegmentPath = 0;
205 }
205 }
206
206
207 if (currentSegmentPath) {
207 if (currentSegmentPath) {
208 if (previousSegmentPath != currentSegmentPath)
208 if (previousSegmentPath != currentSegmentPath)
209 currentSegmentPath->moveTo(centerPoint);
209 currentSegmentPath->moveTo(centerPoint);
210 if (!previousSegmentPath)
210 if (!previousSegmentPath)
211 fullPath.moveTo(centerPoint);
211 fullPath.moveTo(centerPoint);
212
212
213 currentSegmentPath->lineTo(currentGeometryPoint);
213 currentSegmentPath->lineTo(currentGeometryPoint);
214 if (pointOffGrid)
214 if (pointOffGrid)
215 fullPath.lineTo(intersectionPoint);
215 fullPath.lineTo(intersectionPoint);
216 else
216 else
217 fullPath.lineTo(currentGeometryPoint);
217 fullPath.lineTo(currentGeometryPoint);
218 }
218 }
219 } else {
219 } else {
220 if (previousAngle < 0.0 || currentAngle < 0.0
220 if (previousAngle < 0.0 || currentAngle < 0.0
221 || ((previousAngle <= 180.0 && currentAngle <= 180.0)
221 || ((previousAngle <= 180.0 && currentAngle <= 180.0)
222 && ((previousGeometryPoint.x() < rightMarginLine && previousGeometryPoint.y() < horizontal)
222 && ((previousGeometryPoint.x() < rightMarginLine && previousGeometryPoint.y() < horizontal)
223 || (currentGeometryPoint.x() < rightMarginLine && currentGeometryPoint.y() < horizontal)))) {
223 || (currentGeometryPoint.x() < rightMarginLine && currentGeometryPoint.y() < horizontal)))) {
224 currentSegmentPath = &linePathRight;
224 currentSegmentPath = &linePathRight;
225 } else if (previousAngle > 360.0 || currentAngle > 360.0
225 } else if (previousAngle > 360.0 || currentAngle > 360.0
226 || ((previousAngle > 180.0 && currentAngle > 180.0)
226 || ((previousAngle > 180.0 && currentAngle > 180.0)
227 && ((previousGeometryPoint.x() > leftMarginLine && previousGeometryPoint.y() < horizontal)
227 && ((previousGeometryPoint.x() > leftMarginLine && previousGeometryPoint.y() < horizontal)
228 || (currentGeometryPoint.x() > leftMarginLine && currentGeometryPoint.y() < horizontal)))) {
228 || (currentGeometryPoint.x() > leftMarginLine && currentGeometryPoint.y() < horizontal)))) {
229 currentSegmentPath = &linePathLeft;
229 currentSegmentPath = &linePathLeft;
230 } else {
230 } else {
231 currentSegmentPath = &linePath;
231 currentSegmentPath = &linePath;
232 }
232 }
233
233
234 if (currentSegmentPath != previousSegmentPath)
234 if (currentSegmentPath != previousSegmentPath)
235 currentSegmentPath->moveTo(previousGeometryPoint);
235 currentSegmentPath->moveTo(previousGeometryPoint);
236 if (previousPointWasOffGrid)
236 if (previousPointWasOffGrid)
237 fullPath.moveTo(intersectionPoint);
237 fullPath.moveTo(intersectionPoint);
238
238
239 if (pointOffGrid)
239 if (pointOffGrid)
240 fullPath.lineTo(intersectionPoint);
240 fullPath.lineTo(intersectionPoint);
241 else
241 else
242 fullPath.lineTo(currentGeometryPoint);
242 fullPath.lineTo(currentGeometryPoint);
243 currentSegmentPath->lineTo(currentGeometryPoint);
243 currentSegmentPath->lineTo(currentGeometryPoint);
244 }
244 }
245 } else {
245 } else {
246 currentSegmentPath = 0;
246 currentSegmentPath = 0;
247 }
247 }
248
248
249 previousPointWasOffGrid = pointOffGrid;
249 previousPointWasOffGrid = pointOffGrid;
250 if (m_pointsVisible && !pointOffGrid && currentSeriesPoint.y() >= minY) {
250 if (m_pointsVisible && !pointOffGrid && currentSeriesPoint.y() >= minY) {
251 linePath.addEllipse(points.at(i), size, size);
251 linePath.addEllipse(points.at(i), size, size);
252 fullPath.addEllipse(points.at(i), size, size);
252 fullPath.addEllipse(points.at(i), size, size);
253 linePath.moveTo(points.at(i));
253 linePath.moveTo(points.at(i));
254 fullPath.moveTo(points.at(i));
254 fullPath.moveTo(points.at(i));
255 }
255 }
256 previousSegmentPath = currentSegmentPath;
256 previousSegmentPath = currentSegmentPath;
257 previousGeometryPoint = currentGeometryPoint;
257 previousGeometryPoint = currentGeometryPoint;
258 }
258 }
259 m_linePathPolarRight = linePathRight;
259 m_linePathPolarRight = linePathRight;
260 m_linePathPolarLeft = linePathLeft;
260 m_linePathPolarLeft = linePathLeft;
261 // Note: This construction of m_fullpath is not perfect. The partial segments that are
261 // Note: This construction of m_fullpath is not perfect. The partial segments that are
262 // outside left/right clip regions at axis boundary still generate hover/click events,
262 // outside left/right clip regions at axis boundary still generate hover/click events,
263 // because shape doesn't get clipped. It doesn't seem possible to do sensibly.
263 // because shape doesn't get clipped. It doesn't seem possible to do sensibly.
264 } else { // not polar
264 } else { // not polar
265 linePath.moveTo(points.at(0));
265 linePath.moveTo(points.at(0));
266 if (m_pointsVisible) {
266 if (m_pointsVisible) {
267 int size = m_linePen.width();
267 int size = m_linePen.width();
268 linePath.addEllipse(points.at(0), size, size);
268 linePath.addEllipse(points.at(0), size, size);
269 linePath.moveTo(points.at(0));
269 linePath.moveTo(points.at(0));
270 for (int i = 1; i < points.size(); i++) {
270 for (int i = 1; i < points.size(); i++) {
271 linePath.lineTo(points.at(i));
271 linePath.lineTo(points.at(i));
272 linePath.addEllipse(points.at(i), size, size);
272 linePath.addEllipse(points.at(i), size, size);
273 linePath.moveTo(points.at(i));
273 linePath.moveTo(points.at(i));
274 }
274 }
275 } else {
275 } else {
276 for (int i = 1; i < points.size(); i++)
276 for (int i = 1; i < points.size(); i++)
277 linePath.lineTo(points.at(i));
277 linePath.lineTo(points.at(i));
278 }
278 }
279 fullPath = linePath;
279 fullPath = linePath;
280 }
280 }
281
281
282 QPainterPathStroker stroker;
282 QPainterPathStroker stroker;
283 // QPainter::drawLine does not respect join styles, for example BevelJoin becomes MiterJoin.
283 // QPainter::drawLine does not respect join styles, for example BevelJoin becomes MiterJoin.
284 // This is why we are prepared for the "worst case" scenario, i.e. use always MiterJoin and
284 // This is why we are prepared for the "worst case" scenario, i.e. use always MiterJoin and
285 // multiply line width with square root of two when defining shape and bounding rectangle.
285 // multiply line width with square root of two when defining shape and bounding rectangle.
286 stroker.setWidth(margin);
286 stroker.setWidth(margin);
287 stroker.setJoinStyle(Qt::MiterJoin);
287 stroker.setJoinStyle(Qt::MiterJoin);
288 stroker.setCapStyle(Qt::SquareCap);
288 stroker.setCapStyle(Qt::SquareCap);
289 stroker.setMiterLimit(m_linePen.miterLimit());
289 stroker.setMiterLimit(m_linePen.miterLimit());
290
290
291 QPainterPath checkShapePath = stroker.createStroke(fullPath);
291 QPainterPath checkShapePath = stroker.createStroke(fullPath);
292
292
293 // Only zoom in if the bounding rects of the paths fit inside int limits. QWidget::update() uses
293 // Only zoom in if the bounding rects of the paths fit inside int limits. QWidget::update() uses
294 // a region that has to be compatible with QRect.
294 // a region that has to be compatible with QRect.
295 if (checkShapePath.boundingRect().height() <= INT_MAX
295 if (checkShapePath.boundingRect().height() <= INT_MAX
296 && checkShapePath.boundingRect().width() <= INT_MAX
296 && checkShapePath.boundingRect().width() <= INT_MAX
297 && linePath.boundingRect().height() <= INT_MAX
297 && linePath.boundingRect().height() <= INT_MAX
298 && linePath.boundingRect().width() <= INT_MAX
298 && linePath.boundingRect().width() <= INT_MAX
299 && fullPath.boundingRect().height() <= INT_MAX
299 && fullPath.boundingRect().height() <= INT_MAX
300 && fullPath.boundingRect().width() <= INT_MAX) {
300 && fullPath.boundingRect().width() <= INT_MAX) {
301 prepareGeometryChange();
301 prepareGeometryChange();
302
302
303 m_linePath = linePath;
303 m_linePath = linePath;
304 m_fullPath = fullPath;
304 m_fullPath = fullPath;
305 m_shapePath = checkShapePath;
305 m_shapePath = checkShapePath;
306
306
307 m_rect = m_shapePath.boundingRect();
307 m_rect = m_shapePath.boundingRect();
308 } else {
308 } else {
309 update();
309 update();
310 }
310 }
311 }
311 }
312
312
313 void LineChartItem::handleUpdated()
313 void LineChartItem::handleUpdated()
314 {
314 {
315 // If points visibility has changed, a geometry update is needed.
315 // If points visibility has changed, a geometry update is needed.
316 // Also, if pen changes when points are visible, geometry update is needed.
316 // Also, if pen changes when points are visible, geometry update is needed.
317 bool doGeometryUpdate =
317 bool doGeometryUpdate =
318 (m_pointsVisible != m_series->pointsVisible())
318 (m_pointsVisible != m_series->pointsVisible())
319 || (m_series->pointsVisible() && (m_linePen != m_series->pen()));
319 || (m_series->pointsVisible() && (m_linePen != m_series->pen()));
320 setVisible(m_series->isVisible());
320 setVisible(m_series->isVisible());
321 setOpacity(m_series->opacity());
321 setOpacity(m_series->opacity());
322 m_pointsVisible = m_series->pointsVisible();
322 m_pointsVisible = m_series->pointsVisible();
323 m_linePen = m_series->pen();
323 m_linePen = m_series->pen();
324 m_pointLabelsFormat = m_series->pointLabelsFormat();
324 m_pointLabelsFormat = m_series->pointLabelsFormat();
325 m_pointLabelsVisible = m_series->pointLabelsVisible();
325 m_pointLabelsVisible = m_series->pointLabelsVisible();
326 m_pointLabelsFont = m_series->pointLabelsFont();
326 m_pointLabelsFont = m_series->pointLabelsFont();
327 m_pointLabelsColor = m_series->pointLabelsColor();
327 m_pointLabelsColor = m_series->pointLabelsColor();
328 if (doGeometryUpdate)
328 if (doGeometryUpdate)
329 updateGeometry();
329 updateGeometry();
330 update();
330 update();
331 }
331 }
332
332
333 void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
333 void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
334 {
334 {
335 Q_UNUSED(widget)
335 Q_UNUSED(widget)
336 Q_UNUSED(option)
336 Q_UNUSED(option)
337
337
338 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
338 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
339
339
340 painter->save();
340 painter->save();
341 painter->setPen(m_linePen);
341 painter->setPen(m_linePen);
342 bool alwaysUsePath = false;
342 bool alwaysUsePath = false;
343
343
344 if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
344 if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
345 qreal halfWidth = domain()->size().width() / 2.0;
345 qreal halfWidth = domain()->size().width() / 2.0;
346 QRectF clipRectLeft = QRectF(0, 0, halfWidth, domain()->size().height());
346 QRectF clipRectLeft = QRectF(0, 0, halfWidth, domain()->size().height());
347 QRectF clipRectRight = QRectF(halfWidth, 0, halfWidth, domain()->size().height());
347 QRectF clipRectRight = QRectF(halfWidth, 0, halfWidth, domain()->size().height());
348 QRegion fullPolarClipRegion(clipRect.toRect(), QRegion::Ellipse);
348 QRegion fullPolarClipRegion(clipRect.toRect(), QRegion::Ellipse);
349 QRegion clipRegionLeft(fullPolarClipRegion.intersected(clipRectLeft.toRect()));
349 QRegion clipRegionLeft(fullPolarClipRegion.intersected(clipRectLeft.toRect()));
350 QRegion clipRegionRight(fullPolarClipRegion.intersected(clipRectRight.toRect()));
350 QRegion clipRegionRight(fullPolarClipRegion.intersected(clipRectRight.toRect()));
351 painter->setClipRegion(clipRegionLeft);
351 painter->setClipRegion(clipRegionLeft);
352 painter->drawPath(m_linePathPolarLeft);
352 painter->drawPath(m_linePathPolarLeft);
353 painter->setClipRegion(clipRegionRight);
353 painter->setClipRegion(clipRegionRight);
354 painter->drawPath(m_linePathPolarRight);
354 painter->drawPath(m_linePathPolarRight);
355 painter->setClipRegion(fullPolarClipRegion);
355 painter->setClipRegion(fullPolarClipRegion);
356 alwaysUsePath = true; // required for proper clipping
356 alwaysUsePath = true; // required for proper clipping
357 } else {
357 } else {
358 painter->setClipRect(clipRect);
358 painter->setClipRect(clipRect);
359 }
359 }
360
360
361 if (m_pointsVisible) {
361 if (m_pointsVisible) {
362 painter->setBrush(m_linePen.color());
362 painter->setBrush(m_linePen.color());
363 painter->drawPath(m_linePath);
363 painter->drawPath(m_linePath);
364 } else {
364 } else {
365 painter->setBrush(QBrush(Qt::NoBrush));
365 painter->setBrush(QBrush(Qt::NoBrush));
366 if (m_linePen.style() != Qt::SolidLine || alwaysUsePath) {
366 if (m_linePen.style() != Qt::SolidLine || alwaysUsePath) {
367 // If pen style is not solid line, always fall back to path painting
367 // If pen style is not solid line, always fall back to path painting
368 // to ensure proper continuity of the pattern
368 // to ensure proper continuity of the pattern
369 painter->drawPath(m_linePath);
369 painter->drawPath(m_linePath);
370 } else {
370 } else {
371 for (int i(1); i < m_points.size(); i++)
371 for (int i(1); i < m_points.size(); i++)
372 painter->drawLine(m_points.at(i - 1), m_points.at(i));
372 painter->drawLine(m_points.at(i - 1), m_points.at(i));
373 }
373 }
374 }
374 }
375
375
376 if (m_pointLabelsVisible)
376 if (m_pointLabelsVisible)
377 m_series->d_func()->drawSeriesPointLabels(painter, m_points, m_linePen.width() / 2);
377 m_series->d_func()->drawSeriesPointLabels(painter, m_points, m_linePen.width() / 2);
378
378
379 painter->restore();
379 painter->restore();
380
380
381 }
381 }
382
382
383 void LineChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
383 void LineChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
384 {
384 {
385 emit XYChart::pressed(domain()->calculateDomainPoint(event->pos()));
385 emit XYChart::pressed(domain()->calculateDomainPoint(event->pos()));
386 m_lastMousePos = event->pos();
386 m_lastMousePos = event->pos();
387 m_mousePressed = true;
387 m_mousePressed = true;
388 QGraphicsItem::mousePressEvent(event);
388 QGraphicsItem::mousePressEvent(event);
389 }
389 }
390
390
391 void LineChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
391 void LineChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
392 {
392 {
393 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), true);
393 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), true);
394 // event->accept();
394 // event->accept();
395 QGraphicsItem::hoverEnterEvent(event);
395 QGraphicsItem::hoverEnterEvent(event);
396 }
396 }
397
397
398 void LineChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
398 void LineChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
399 {
399 {
400 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), false);
400 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), false);
401 // event->accept();
401 // event->accept();
402 QGraphicsItem::hoverEnterEvent(event);
402 QGraphicsItem::hoverEnterEvent(event);
403 }
403 }
404
404
405 void LineChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
405 void LineChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
406 {
406 {
407 emit XYChart::released(domain()->calculateDomainPoint(event->pos()));
407 emit XYChart::released(domain()->calculateDomainPoint(m_lastMousePos));
408 if (m_lastMousePos == event->pos() && m_mousePressed)
408 if (m_mousePressed)
409 emit XYChart::clicked(domain()->calculateDomainPoint(event->pos()));
409 emit XYChart::clicked(domain()->calculateDomainPoint(m_lastMousePos));
410 m_mousePressed = false;
410 m_mousePressed = false;
411 QGraphicsItem::mouseReleaseEvent(event);
411 QGraphicsItem::mouseReleaseEvent(event);
412 }
412 }
413
413
414 void LineChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
414 void LineChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
415 {
415 {
416 emit XYChart::doubleClicked(domain()->calculateDomainPoint(event->pos()));
416 emit XYChart::doubleClicked(domain()->calculateDomainPoint(m_lastMousePos));
417 QGraphicsItem::mouseDoubleClickEvent(event);
417 QGraphicsItem::mouseDoubleClickEvent(event);
418 }
418 }
419
419
420 #include "moc_linechartitem_p.cpp"
420 #include "moc_linechartitem_p.cpp"
421
421
422 QT_CHARTS_END_NAMESPACE
422 QT_CHARTS_END_NAMESPACE
@@ -1,335 +1,334
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/piesliceitem_p.h>
19 #include <private/piesliceitem_p.h>
20 #include <private/piechartitem_p.h>
20 #include <private/piechartitem_p.h>
21 #include <QtCharts/QPieSeries>
21 #include <QtCharts/QPieSeries>
22 #include <QtCharts/QPieSlice>
22 #include <QtCharts/QPieSlice>
23 #include <private/chartpresenter_p.h>
23 #include <private/chartpresenter_p.h>
24 #include <QtGui/QPainter>
24 #include <QtGui/QPainter>
25 #include <QtCore/QtMath>
25 #include <QtCore/QtMath>
26 #include <QtWidgets/QGraphicsSceneEvent>
26 #include <QtWidgets/QGraphicsSceneEvent>
27 #include <QtCore/QTime>
27 #include <QtCore/QTime>
28 #include <QtGui/QTextDocument>
28 #include <QtGui/QTextDocument>
29 #include <QtCore/QDebug>
29 #include <QtCore/QDebug>
30
30
31 QT_CHARTS_BEGIN_NAMESPACE
31 QT_CHARTS_BEGIN_NAMESPACE
32
32
33 QPointF offset(qreal angle, qreal length)
33 QPointF offset(qreal angle, qreal length)
34 {
34 {
35 qreal dx = qSin(angle * (M_PI / 180)) * length;
35 qreal dx = qSin(angle * (M_PI / 180)) * length;
36 qreal dy = qCos(angle * (M_PI / 180)) * length;
36 qreal dy = qCos(angle * (M_PI / 180)) * length;
37 return QPointF(dx, -dy);
37 return QPointF(dx, -dy);
38 }
38 }
39
39
40 PieSliceItem::PieSliceItem(QGraphicsItem *parent)
40 PieSliceItem::PieSliceItem(QGraphicsItem *parent)
41 : QGraphicsObject(parent),
41 : QGraphicsObject(parent),
42 m_hovered(false),
42 m_hovered(false),
43 m_mousePressed(false)
43 m_mousePressed(false)
44 {
44 {
45 setAcceptHoverEvents(true);
45 setAcceptHoverEvents(true);
46 setAcceptedMouseButtons(Qt::MouseButtonMask);
46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 setZValue(ChartPresenter::PieSeriesZValue);
47 setZValue(ChartPresenter::PieSeriesZValue);
48 setFlag(QGraphicsItem::ItemIsSelectable);
48 setFlag(QGraphicsItem::ItemIsSelectable);
49 m_labelItem = new QGraphicsTextItem(this);
49 m_labelItem = new QGraphicsTextItem(this);
50 m_labelItem->document()->setDocumentMargin(1.0);
50 m_labelItem->document()->setDocumentMargin(1.0);
51 }
51 }
52
52
53 PieSliceItem::~PieSliceItem()
53 PieSliceItem::~PieSliceItem()
54 {
54 {
55 // If user is hovering over the slice and it gets destroyed we do
55 // If user is hovering over the slice and it gets destroyed we do
56 // not get a hover leave event. So we must emit the signal here.
56 // not get a hover leave event. So we must emit the signal here.
57 if (m_hovered)
57 if (m_hovered)
58 emit hovered(false);
58 emit hovered(false);
59 }
59 }
60
60
61 QRectF PieSliceItem::boundingRect() const
61 QRectF PieSliceItem::boundingRect() const
62 {
62 {
63 return m_boundingRect;
63 return m_boundingRect;
64 }
64 }
65
65
66 QPainterPath PieSliceItem::shape() const
66 QPainterPath PieSliceItem::shape() const
67 {
67 {
68 // Don't include the label and label arm.
68 // Don't include the label and label arm.
69 // This is used to detect a mouse clicks. We do not want clicks from label.
69 // This is used to detect a mouse clicks. We do not want clicks from label.
70 return m_slicePath;
70 return m_slicePath;
71 }
71 }
72
72
73 void PieSliceItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
73 void PieSliceItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
74 {
74 {
75 painter->save();
75 painter->save();
76 painter->setClipRect(parentItem()->boundingRect());
76 painter->setClipRect(parentItem()->boundingRect());
77 painter->setPen(m_data.m_slicePen);
77 painter->setPen(m_data.m_slicePen);
78 painter->setBrush(m_data.m_sliceBrush);
78 painter->setBrush(m_data.m_sliceBrush);
79 painter->drawPath(m_slicePath);
79 painter->drawPath(m_slicePath);
80 painter->restore();
80 painter->restore();
81
81
82 if (m_data.m_isLabelVisible) {
82 if (m_data.m_isLabelVisible) {
83 painter->save();
83 painter->save();
84
84
85 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
85 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
86 painter->setBrush(m_data.m_labelBrush);
86 painter->setBrush(m_data.m_labelBrush);
87
87
88 if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
88 if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
89 painter->setClipRect(parentItem()->boundingRect());
89 painter->setClipRect(parentItem()->boundingRect());
90 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
90 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
91 }
91 }
92
92
93 painter->restore();
93 painter->restore();
94 }
94 }
95 }
95 }
96
96
97 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
97 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
98 {
98 {
99 m_hovered = true;
99 m_hovered = true;
100 emit hovered(true);
100 emit hovered(true);
101 }
101 }
102
102
103 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
103 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
104 {
104 {
105 m_hovered = false;
105 m_hovered = false;
106 emit hovered(false);
106 emit hovered(false);
107 }
107 }
108
108
109 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
109 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
110 {
110 {
111 emit pressed(event->buttons());
111 emit pressed(event->buttons());
112 m_lastMousePos = event->pos();
113 m_mousePressed = true;
112 m_mousePressed = true;
114 }
113 }
115
114
116 void PieSliceItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
115 void PieSliceItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
117 {
116 {
118 emit released(event->buttons());
117 emit released(event->buttons());
119 if (m_lastMousePos == event->pos() && m_mousePressed)
118 if (m_mousePressed)
120 emit clicked(event->buttons());
119 emit clicked(event->buttons());
121 }
120 }
122
121
123 void PieSliceItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
122 void PieSliceItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
124 {
123 {
125 // For Pie slice a press signal needs to be explicitly fired for mouseDoubleClickEvent
124 // For Pie slice a press signal needs to be explicitly fired for mouseDoubleClickEvent
126 emit pressed(event->buttons());
125 emit pressed(event->buttons());
127 emit doubleClicked(event->buttons());
126 emit doubleClicked(event->buttons());
128 }
127 }
129
128
130 void PieSliceItem::setLayout(const PieSliceData &sliceData)
129 void PieSliceItem::setLayout(const PieSliceData &sliceData)
131 {
130 {
132 m_data = sliceData;
131 m_data = sliceData;
133 updateGeometry();
132 updateGeometry();
134 update();
133 update();
135 }
134 }
136
135
137 void PieSliceItem::updateGeometry()
136 void PieSliceItem::updateGeometry()
138 {
137 {
139 if (m_data.m_radius <= 0)
138 if (m_data.m_radius <= 0)
140 return;
139 return;
141
140
142 prepareGeometryChange();
141 prepareGeometryChange();
143
142
144 // slice path
143 // slice path
145 qreal centerAngle;
144 qreal centerAngle;
146 QPointF armStart;
145 QPointF armStart;
147 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
146 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
148
147
149 m_labelItem->setVisible(m_data.m_isLabelVisible);
148 m_labelItem->setVisible(m_data.m_isLabelVisible);
150
149
151 if (m_data.m_isLabelVisible) {
150 if (m_data.m_isLabelVisible) {
152 // text rect
151 // text rect
153 m_labelTextRect = ChartPresenter::textBoundingRect(m_data.m_labelFont,
152 m_labelTextRect = ChartPresenter::textBoundingRect(m_data.m_labelFont,
154 m_data.m_labelText,
153 m_data.m_labelText,
155 0);
154 0);
156
155
157 QString label(m_data.m_labelText);
156 QString label(m_data.m_labelText);
158 m_labelItem->setDefaultTextColor(m_data.m_labelBrush.color());
157 m_labelItem->setDefaultTextColor(m_data.m_labelBrush.color());
159 m_labelItem->setFont(m_data.m_labelFont);
158 m_labelItem->setFont(m_data.m_labelFont);
160
159
161 // text position
160 // text position
162 if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
161 if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
163 setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
162 setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
164
163
165 // label arm path
164 // label arm path
166 QPointF labelTextStart;
165 QPointF labelTextStart;
167 m_labelArmPath = labelArmPath(armStart, centerAngle,
166 m_labelArmPath = labelArmPath(armStart, centerAngle,
168 m_data.m_radius * m_data.m_labelArmLengthFactor,
167 m_data.m_radius * m_data.m_labelArmLengthFactor,
169 m_labelTextRect.width(), &labelTextStart);
168 m_labelTextRect.width(), &labelTextStart);
170
169
171 m_labelTextRect.moveBottomLeft(labelTextStart);
170 m_labelTextRect.moveBottomLeft(labelTextStart);
172 if (m_labelTextRect.left() < 0)
171 if (m_labelTextRect.left() < 0)
173 m_labelTextRect.setLeft(0);
172 m_labelTextRect.setLeft(0);
174 else if (m_labelTextRect.left() < parentItem()->boundingRect().left())
173 else if (m_labelTextRect.left() < parentItem()->boundingRect().left())
175 m_labelTextRect.setLeft(parentItem()->boundingRect().left());
174 m_labelTextRect.setLeft(parentItem()->boundingRect().left());
176 if (m_labelTextRect.right() > parentItem()->boundingRect().right())
175 if (m_labelTextRect.right() > parentItem()->boundingRect().right())
177 m_labelTextRect.setRight(parentItem()->boundingRect().right());
176 m_labelTextRect.setRight(parentItem()->boundingRect().right());
178
177
179 label = ChartPresenter::truncatedText(m_data.m_labelFont, m_data.m_labelText,
178 label = ChartPresenter::truncatedText(m_data.m_labelFont, m_data.m_labelText,
180 qreal(0.0), m_labelTextRect.width(),
179 qreal(0.0), m_labelTextRect.width(),
181 m_labelTextRect.height(), m_labelTextRect);
180 m_labelTextRect.height(), m_labelTextRect);
182 m_labelArmPath = labelArmPath(armStart, centerAngle,
181 m_labelArmPath = labelArmPath(armStart, centerAngle,
183 m_data.m_radius * m_data.m_labelArmLengthFactor,
182 m_data.m_radius * m_data.m_labelArmLengthFactor,
184 m_labelTextRect.width(), &labelTextStart);
183 m_labelTextRect.width(), &labelTextStart);
185 m_labelTextRect.moveBottomLeft(labelTextStart);
184 m_labelTextRect.moveBottomLeft(labelTextStart);
186
185
187 m_labelItem->setTextWidth(m_labelTextRect.width()
186 m_labelItem->setTextWidth(m_labelTextRect.width()
188 + m_labelItem->document()->documentMargin());
187 + m_labelItem->document()->documentMargin());
189 m_labelItem->setHtml(label);
188 m_labelItem->setHtml(label);
190 m_labelItem->setRotation(0);
189 m_labelItem->setRotation(0);
191 m_labelItem->setPos(m_labelTextRect.x(), m_labelTextRect.y() + 1.0);
190 m_labelItem->setPos(m_labelTextRect.x(), m_labelTextRect.y() + 1.0);
192 } else {
191 } else {
193 // label inside
192 // label inside
194 setFlag(QGraphicsItem::ItemClipsChildrenToShape);
193 setFlag(QGraphicsItem::ItemClipsChildrenToShape);
195 m_labelItem->setTextWidth(m_labelTextRect.width()
194 m_labelItem->setTextWidth(m_labelTextRect.width()
196 + m_labelItem->document()->documentMargin());
195 + m_labelItem->document()->documentMargin());
197 m_labelItem->setHtml(label);
196 m_labelItem->setHtml(label);
198
197
199 QPointF textCenter;
198 QPointF textCenter;
200 if (m_data.m_holeRadius > 0) {
199 if (m_data.m_holeRadius > 0) {
201 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius
200 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius
202 + (m_data.m_radius
201 + (m_data.m_radius
203 - m_data.m_holeRadius) / 2);
202 - m_data.m_holeRadius) / 2);
204 } else {
203 } else {
205 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
204 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
206 }
205 }
207 m_labelItem->setPos(textCenter.x() - m_labelItem->boundingRect().width() / 2,
206 m_labelItem->setPos(textCenter.x() - m_labelItem->boundingRect().width() / 2,
208 textCenter.y() - m_labelTextRect.height() / 2);
207 textCenter.y() - m_labelTextRect.height() / 2);
209
208
210 QPointF labelCenter = m_labelItem->boundingRect().center();
209 QPointF labelCenter = m_labelItem->boundingRect().center();
211 m_labelItem->setTransformOriginPoint(labelCenter);
210 m_labelItem->setTransformOriginPoint(labelCenter);
212
211
213 if (m_data.m_labelPosition == QPieSlice::LabelInsideTangential) {
212 if (m_data.m_labelPosition == QPieSlice::LabelInsideTangential) {
214 m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2);
213 m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2);
215 } else if (m_data.m_labelPosition == QPieSlice::LabelInsideNormal) {
214 } else if (m_data.m_labelPosition == QPieSlice::LabelInsideNormal) {
216 if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
215 if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
217 m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
216 m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
218 else
217 else
219 m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
218 m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
220 } else {
219 } else {
221 m_labelItem->setRotation(0);
220 m_labelItem->setRotation(0);
222 }
221 }
223 }
222 }
224 // Hide label if it's outside the bounding rect of parent item
223 // Hide label if it's outside the bounding rect of parent item
225 QRectF labelRect(m_labelItem->boundingRect());
224 QRectF labelRect(m_labelItem->boundingRect());
226 labelRect.moveTopLeft(m_labelItem->pos());
225 labelRect.moveTopLeft(m_labelItem->pos());
227 if ((parentItem()->boundingRect().left()
226 if ((parentItem()->boundingRect().left()
228 < (labelRect.left() + m_labelItem->document()->documentMargin() + 1.0))
227 < (labelRect.left() + m_labelItem->document()->documentMargin() + 1.0))
229 && (parentItem()->boundingRect().right()
228 && (parentItem()->boundingRect().right()
230 > (labelRect.right() - m_labelItem->document()->documentMargin() - 1.0))
229 > (labelRect.right() - m_labelItem->document()->documentMargin() - 1.0))
231 && (parentItem()->boundingRect().top()
230 && (parentItem()->boundingRect().top()
232 < (labelRect.top() + m_labelItem->document()->documentMargin() + 1.0))
231 < (labelRect.top() + m_labelItem->document()->documentMargin() + 1.0))
233 && (parentItem()->boundingRect().bottom()
232 && (parentItem()->boundingRect().bottom()
234 > (labelRect.bottom() - m_labelItem->document()->documentMargin() - 1.0)))
233 > (labelRect.bottom() - m_labelItem->document()->documentMargin() - 1.0)))
235 m_labelItem->show();
234 m_labelItem->show();
236 else
235 else
237 m_labelItem->hide();
236 m_labelItem->hide();
238 }
237 }
239
238
240 // bounding rect
239 // bounding rect
241 if (m_data.m_isLabelVisible)
240 if (m_data.m_isLabelVisible)
242 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
241 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
243 else
242 else
244 m_boundingRect = m_slicePath.boundingRect();
243 m_boundingRect = m_slicePath.boundingRect();
245
244
246 // Inflate bounding rect by 2/3 pen width to make sure it encompasses whole slice also for thick pens
245 // Inflate bounding rect by 2/3 pen width to make sure it encompasses whole slice also for thick pens
247 // and miter joins.
246 // and miter joins.
248 int penWidth = (m_data.m_slicePen.width() * 2) / 3;
247 int penWidth = (m_data.m_slicePen.width() * 2) / 3;
249 m_boundingRect = m_boundingRect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
248 m_boundingRect = m_boundingRect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
250 }
249 }
251
250
252 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
251 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
253 {
252 {
254 if (slice->isExploded()) {
253 if (slice->isExploded()) {
255 qreal centerAngle = slice->startAngle() + (slice->angleSpan() / 2);
254 qreal centerAngle = slice->startAngle() + (slice->angleSpan() / 2);
256 qreal len = radius * slice->explodeDistanceFactor();
255 qreal len = radius * slice->explodeDistanceFactor();
257 point += offset(centerAngle, len);
256 point += offset(centerAngle, len);
258 }
257 }
259 return point;
258 return point;
260 }
259 }
261
260
262 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart)
261 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart)
263 {
262 {
264 // calculate center angle
263 // calculate center angle
265 *centerAngle = startAngle + (angleSpan / 2);
264 *centerAngle = startAngle + (angleSpan / 2);
266
265
267 // calculate slice rectangle
266 // calculate slice rectangle
268 QRectF rect(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
267 QRectF rect(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
269
268
270 // slice path
269 // slice path
271 QPainterPath path;
270 QPainterPath path;
272 if (m_data.m_holeRadius > 0) {
271 if (m_data.m_holeRadius > 0) {
273 QRectF insideRect(center.x() - m_data.m_holeRadius, center.y() - m_data.m_holeRadius, m_data.m_holeRadius * 2, m_data.m_holeRadius * 2);
272 QRectF insideRect(center.x() - m_data.m_holeRadius, center.y() - m_data.m_holeRadius, m_data.m_holeRadius * 2, m_data.m_holeRadius * 2);
274 path.arcMoveTo(rect, -startAngle + 90);
273 path.arcMoveTo(rect, -startAngle + 90);
275 path.arcTo(rect, -startAngle + 90, -angleSpan);
274 path.arcTo(rect, -startAngle + 90, -angleSpan);
276 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
275 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
277 path.closeSubpath();
276 path.closeSubpath();
278 } else {
277 } else {
279 path.moveTo(rect.center());
278 path.moveTo(rect.center());
280 path.arcTo(rect, -startAngle + 90, -angleSpan);
279 path.arcTo(rect, -startAngle + 90, -angleSpan);
281 path.closeSubpath();
280 path.closeSubpath();
282 }
281 }
283
282
284 // calculate label arm start point
283 // calculate label arm start point
285 *armStart = center;
284 *armStart = center;
286 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
285 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
287
286
288 return path;
287 return path;
289 }
288 }
290
289
291 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
290 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
292 {
291 {
293 // Normalize the angle to 0-360 range
292 // Normalize the angle to 0-360 range
294 // NOTE: We are using int here on purpose. Depenging on platform and hardware
293 // NOTE: We are using int here on purpose. Depenging on platform and hardware
295 // qreal can be a double, float or something the user gives to the Qt configure
294 // qreal can be a double, float or something the user gives to the Qt configure
296 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
295 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
297 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
296 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
298 // that might break we just use int. Precision for this is just fine for our needs.
297 // that might break we just use int. Precision for this is just fine for our needs.
299 int normalized = angle * 10.0;
298 int normalized = angle * 10.0;
300 normalized = normalized % 3600;
299 normalized = normalized % 3600;
301 if (normalized < 0)
300 if (normalized < 0)
302 normalized += 3600;
301 normalized += 3600;
303 angle = (qreal) normalized / 10.0;
302 angle = (qreal) normalized / 10.0;
304
303
305 // prevent label arm pointing straight down because it will look bad
304 // prevent label arm pointing straight down because it will look bad
306 if (angle < 180 && angle > 170)
305 if (angle < 180 && angle > 170)
307 angle = 170;
306 angle = 170;
308 if (angle > 180 && angle < 190)
307 if (angle > 180 && angle < 190)
309 angle = 190;
308 angle = 190;
310
309
311 // line from slice to label
310 // line from slice to label
312 QPointF parm1 = start + offset(angle, length);
311 QPointF parm1 = start + offset(angle, length);
313
312
314 // line to underline the label
313 // line to underline the label
315 QPointF parm2 = parm1;
314 QPointF parm2 = parm1;
316 if (angle < 180) { // arm swings the other way on the left side
315 if (angle < 180) { // arm swings the other way on the left side
317 parm2 += QPointF(textWidth, 0);
316 parm2 += QPointF(textWidth, 0);
318 *textStart = parm1;
317 *textStart = parm1;
319 } else {
318 } else {
320 parm2 += QPointF(-textWidth, 0);
319 parm2 += QPointF(-textWidth, 0);
321 *textStart = parm2;
320 *textStart = parm2;
322 }
321 }
323
322
324 QPainterPath path;
323 QPainterPath path;
325 path.moveTo(start);
324 path.moveTo(start);
326 path.lineTo(parm1);
325 path.lineTo(parm1);
327 path.lineTo(parm2);
326 path.lineTo(parm2);
328
327
329 return path;
328 return path;
330 }
329 }
331
330
332 #include "moc_piesliceitem_p.cpp"
331 #include "moc_piesliceitem_p.cpp"
333
332
334 QT_CHARTS_END_NAMESPACE
333 QT_CHARTS_END_NAMESPACE
335
334
@@ -1,97 +1,96
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 // W A R N I N G
19 // W A R N I N G
20 // -------------
20 // -------------
21 //
21 //
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
23 // implementation detail. This header file may change from version to
23 // implementation detail. This header file may change from version to
24 // version without notice, or even be removed.
24 // version without notice, or even be removed.
25 //
25 //
26 // We mean it.
26 // We mean it.
27
27
28 #ifndef PIESLICEITEM_H
28 #ifndef PIESLICEITEM_H
29 #define PIESLICEITEM_H
29 #define PIESLICEITEM_H
30
30
31 #include <QtCharts/QChartGlobal>
31 #include <QtCharts/QChartGlobal>
32 #include <private/charttheme_p.h>
32 #include <private/charttheme_p.h>
33 #include <QtCharts/QPieSeries>
33 #include <QtCharts/QPieSeries>
34 #include <private/pieslicedata_p.h>
34 #include <private/pieslicedata_p.h>
35 #include <QtWidgets/QGraphicsItem>
35 #include <QtWidgets/QGraphicsItem>
36 #include <QtCore/QRectF>
36 #include <QtCore/QRectF>
37 #include <QtGui/QColor>
37 #include <QtGui/QColor>
38 #include <QtGui/QPen>
38 #include <QtGui/QPen>
39
39
40 #define PIESLICE_LABEL_GAP 5
40 #define PIESLICE_LABEL_GAP 5
41
41
42 QT_CHARTS_BEGIN_NAMESPACE
42 QT_CHARTS_BEGIN_NAMESPACE
43 class PieChartItem;
43 class PieChartItem;
44 class PieSliceLabel;
44 class PieSliceLabel;
45 class QPieSlice;
45 class QPieSlice;
46
46
47 class PieSliceItem : public QGraphicsObject
47 class PieSliceItem : public QGraphicsObject
48 {
48 {
49 Q_OBJECT
49 Q_OBJECT
50
50
51 public:
51 public:
52 PieSliceItem(QGraphicsItem *parent = 0);
52 PieSliceItem(QGraphicsItem *parent = 0);
53 ~PieSliceItem();
53 ~PieSliceItem();
54
54
55 // from QGraphicsItem
55 // from QGraphicsItem
56 QRectF boundingRect() const;
56 QRectF boundingRect() const;
57 QPainterPath shape() const;
57 QPainterPath shape() const;
58 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
58 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
59 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
59 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
60 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
60 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
61 void mousePressEvent(QGraphicsSceneMouseEvent *event);
61 void mousePressEvent(QGraphicsSceneMouseEvent *event);
62 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
62 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
63 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
63 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
64
64
65 void setLayout(const PieSliceData &sliceData);
65 void setLayout(const PieSliceData &sliceData);
66 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
66 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
67
67
68 Q_SIGNALS:
68 Q_SIGNALS:
69 void clicked(Qt::MouseButtons buttons);
69 void clicked(Qt::MouseButtons buttons);
70 void hovered(bool state);
70 void hovered(bool state);
71 void pressed(Qt::MouseButtons buttons);
71 void pressed(Qt::MouseButtons buttons);
72 void released(Qt::MouseButtons buttons);
72 void released(Qt::MouseButtons buttons);
73 void doubleClicked(Qt::MouseButtons buttons);
73 void doubleClicked(Qt::MouseButtons buttons);
74
74
75 private:
75 private:
76 void updateGeometry();
76 void updateGeometry();
77 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
77 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
78 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
78 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
79
79
80 private:
80 private:
81 PieSliceData m_data;
81 PieSliceData m_data;
82 QRectF m_boundingRect;
82 QRectF m_boundingRect;
83 QPainterPath m_slicePath;
83 QPainterPath m_slicePath;
84 QPainterPath m_labelArmPath;
84 QPainterPath m_labelArmPath;
85 QRectF m_labelTextRect;
85 QRectF m_labelTextRect;
86 bool m_hovered;
86 bool m_hovered;
87 QGraphicsTextItem *m_labelItem;
87 QGraphicsTextItem *m_labelItem;
88
88
89 QPointF m_lastMousePos;
90 bool m_mousePressed;
89 bool m_mousePressed;
91
90
92 friend class PieSliceAnimation;
91 friend class PieSliceAnimation;
93 };
92 };
94
93
95 QT_CHARTS_END_NAMESPACE
94 QT_CHARTS_END_NAMESPACE
96
95
97 #endif // PIESLICEITEM_H
96 #endif // PIESLICEITEM_H
@@ -1,1005 +1,1005
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <QtCharts/QPieSeries>
19 #include <QtCharts/QPieSeries>
20 #include <private/qpieseries_p.h>
20 #include <private/qpieseries_p.h>
21 #include <QtCharts/QPieSlice>
21 #include <QtCharts/QPieSlice>
22 #include <private/qpieslice_p.h>
22 #include <private/qpieslice_p.h>
23 #include <private/pieslicedata_p.h>
23 #include <private/pieslicedata_p.h>
24 #include <private/chartdataset_p.h>
24 #include <private/chartdataset_p.h>
25 #include <private/charttheme_p.h>
25 #include <private/charttheme_p.h>
26 #include <QtCharts/QAbstractAxis>
26 #include <QtCharts/QAbstractAxis>
27 #include <private/pieanimation_p.h>
27 #include <private/pieanimation_p.h>
28 #include <private/charthelpers_p.h>
28 #include <private/charthelpers_p.h>
29
29
30 #include <QtCharts/QPieLegendMarker>
30 #include <QtCharts/QPieLegendMarker>
31
31
32 QT_CHARTS_BEGIN_NAMESPACE
32 QT_CHARTS_BEGIN_NAMESPACE
33
33
34 /*!
34 /*!
35 \class QPieSeries
35 \class QPieSeries
36 \inmodule Qt Charts
36 \inmodule Qt Charts
37 \brief Pie series API for Qt Charts.
37 \brief Pie series API for Qt Charts.
38
38
39 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
39 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
40 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
40 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
41 The actual slice size is determined by that relative value.
41 The actual slice size is determined by that relative value.
42
42
43 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0.
43 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0.
44 These relate to the actual chart rectangle.
44 These relate to the actual chart rectangle.
45
45
46 By default the pie is defined as a full pie but it can also be a partial pie.
46 By default the pie is defined as a full pie but it can also be a partial pie.
47 This can be done by setting a starting angle and angle span to the series.
47 This can be done by setting a starting angle and angle span to the series.
48 Full pie is 360 degrees where 0 is at 12 a'clock.
48 Full pie is 360 degrees where 0 is at 12 a'clock.
49
49
50 See the \l {PieChart Example} {pie chart example} or \l {DonutChart Example} {donut chart example} to learn how to use QPieSeries.
50 See the \l {PieChart Example} {pie chart example} or \l {DonutChart Example} {donut chart example} to learn how to use QPieSeries.
51 \table 100%
51 \table 100%
52 \row
52 \row
53 \li \image examples_piechart.png
53 \li \image examples_piechart.png
54 \li \image examples_donutchart.png
54 \li \image examples_donutchart.png
55 \endtable
55 \endtable
56 */
56 */
57 /*!
57 /*!
58 \qmltype PieSeries
58 \qmltype PieSeries
59 \instantiates QPieSeries
59 \instantiates QPieSeries
60 \inqmlmodule QtCharts
60 \inqmlmodule QtCharts
61
61
62 \inherits AbstractSeries
62 \inherits AbstractSeries
63
63
64 \brief The PieSeries type is used for making pie charts.
64 \brief The PieSeries type is used for making pie charts.
65
65
66 The following QML shows how to create a simple pie chart.
66 The following QML shows how to create a simple pie chart.
67
67
68 \snippet qmlchart/qml/qmlchart/View1.qml 1
68 \snippet qmlchart/qml/qmlchart/View1.qml 1
69
69
70 \beginfloatleft
70 \beginfloatleft
71 \image examples_qmlchart1.png
71 \image examples_qmlchart1.png
72 \endfloat
72 \endfloat
73 \clearfloat
73 \clearfloat
74 */
74 */
75
75
76 /*!
76 /*!
77 \property QPieSeries::horizontalPosition
77 \property QPieSeries::horizontalPosition
78 \brief Defines the horizontal position of the pie.
78 \brief Defines the horizontal position of the pie.
79
79
80 The value is a relative value to the chart rectangle where:
80 The value is a relative value to the chart rectangle where:
81
81
82 \list
82 \list
83 \li 0.0 is the absolute left.
83 \li 0.0 is the absolute left.
84 \li 1.0 is the absolute right.
84 \li 1.0 is the absolute right.
85 \endlist
85 \endlist
86 Default value is 0.5 (center).
86 Default value is 0.5 (center).
87 \sa verticalPosition
87 \sa verticalPosition
88 */
88 */
89
89
90 /*!
90 /*!
91 \qmlproperty real PieSeries::horizontalPosition
91 \qmlproperty real PieSeries::horizontalPosition
92
92
93 Defines the horizontal position of the pie.
93 Defines the horizontal position of the pie.
94
94
95 The value is a relative value to the chart rectangle where:
95 The value is a relative value to the chart rectangle where:
96
96
97 \list
97 \list
98 \li 0.0 is the absolute left.
98 \li 0.0 is the absolute left.
99 \li 1.0 is the absolute right.
99 \li 1.0 is the absolute right.
100 \endlist
100 \endlist
101 Default value is 0.5 (center).
101 Default value is 0.5 (center).
102 \sa verticalPosition
102 \sa verticalPosition
103 */
103 */
104
104
105 /*!
105 /*!
106 \property QPieSeries::verticalPosition
106 \property QPieSeries::verticalPosition
107 \brief Defines the vertical position of the pie.
107 \brief Defines the vertical position of the pie.
108
108
109 The value is a relative value to the chart rectangle where:
109 The value is a relative value to the chart rectangle where:
110
110
111 \list
111 \list
112 \li 0.0 is the absolute top.
112 \li 0.0 is the absolute top.
113 \li 1.0 is the absolute bottom.
113 \li 1.0 is the absolute bottom.
114 \endlist
114 \endlist
115 Default value is 0.5 (center).
115 Default value is 0.5 (center).
116 \sa horizontalPosition
116 \sa horizontalPosition
117 */
117 */
118
118
119 /*!
119 /*!
120 \qmlproperty real PieSeries::verticalPosition
120 \qmlproperty real PieSeries::verticalPosition
121
121
122 Defines the vertical position of the pie.
122 Defines the vertical position of the pie.
123
123
124 The value is a relative value to the chart rectangle where:
124 The value is a relative value to the chart rectangle where:
125
125
126 \list
126 \list
127 \li 0.0 is the absolute top.
127 \li 0.0 is the absolute top.
128 \li 1.0 is the absolute bottom.
128 \li 1.0 is the absolute bottom.
129 \endlist
129 \endlist
130 Default value is 0.5 (center).
130 Default value is 0.5 (center).
131 \sa horizontalPosition
131 \sa horizontalPosition
132 */
132 */
133
133
134 /*!
134 /*!
135 \property QPieSeries::size
135 \property QPieSeries::size
136 \brief Defines the pie size.
136 \brief Defines the pie size.
137
137
138 The value is a relative value to the chart rectangle where:
138 The value is a relative value to the chart rectangle where:
139
139
140 \list
140 \list
141 \li 0.0 is the minimum size (pie not drawn).
141 \li 0.0 is the minimum size (pie not drawn).
142 \li 1.0 is the maximum size that can fit the chart.
142 \li 1.0 is the maximum size that can fit the chart.
143 \endlist
143 \endlist
144
144
145 When setting this property the holeSize property is adjusted if necessary, to ensure that the hole size is not greater than the outer size.
145 When setting this property the holeSize property is adjusted if necessary, to ensure that the hole size is not greater than the outer size.
146
146
147 Default value is 0.7.
147 Default value is 0.7.
148 */
148 */
149
149
150 /*!
150 /*!
151 \qmlproperty real PieSeries::size
151 \qmlproperty real PieSeries::size
152
152
153 Defines the pie size.
153 Defines the pie size.
154
154
155 The value is a relative value to the chart rectangle where:
155 The value is a relative value to the chart rectangle where:
156
156
157 \list
157 \list
158 \li 0.0 is the minimum size (pie not drawn).
158 \li 0.0 is the minimum size (pie not drawn).
159 \li 1.0 is the maximum size that can fit the chart.
159 \li 1.0 is the maximum size that can fit the chart.
160 \endlist
160 \endlist
161
161
162 Default value is 0.7.
162 Default value is 0.7.
163 */
163 */
164
164
165 /*!
165 /*!
166 \property QPieSeries::holeSize
166 \property QPieSeries::holeSize
167 \brief Defines the donut hole size.
167 \brief Defines the donut hole size.
168
168
169 The value is a relative value to the chart rectangle where:
169 The value is a relative value to the chart rectangle where:
170
170
171 \list
171 \list
172 \li 0.0 is the minimum size (full pie drawn, without any hole inside).
172 \li 0.0 is the minimum size (full pie drawn, without any hole inside).
173 \li 1.0 is the maximum size that can fit the chart. (donut has no width)
173 \li 1.0 is the maximum size that can fit the chart. (donut has no width)
174 \endlist
174 \endlist
175
175
176 The value is never greater then size property.
176 The value is never greater then size property.
177 Default value is 0.0.
177 Default value is 0.0.
178 */
178 */
179
179
180 /*!
180 /*!
181 \qmlproperty real PieSeries::holeSize
181 \qmlproperty real PieSeries::holeSize
182
182
183 Defines the donut hole size.
183 Defines the donut hole size.
184
184
185 The value is a relative value to the chart rectangle where:
185 The value is a relative value to the chart rectangle where:
186
186
187 \list
187 \list
188 \li 0.0 is the minimum size (full pie drawn, without any hole inside).
188 \li 0.0 is the minimum size (full pie drawn, without any hole inside).
189 \li 1.0 is the maximum size that can fit the chart. (donut has no width)
189 \li 1.0 is the maximum size that can fit the chart. (donut has no width)
190 \endlist
190 \endlist
191
191
192 When setting this property the size property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
192 When setting this property the size property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
193
193
194 Default value is 0.0.
194 Default value is 0.0.
195 */
195 */
196
196
197 /*!
197 /*!
198 \property QPieSeries::startAngle
198 \property QPieSeries::startAngle
199 \brief Defines the starting angle of the pie.
199 \brief Defines the starting angle of the pie.
200
200
201 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
201 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
202
202
203 Default is value is 0.
203 Default is value is 0.
204 */
204 */
205
205
206 /*!
206 /*!
207 \qmlproperty real PieSeries::startAngle
207 \qmlproperty real PieSeries::startAngle
208
208
209 Defines the starting angle of the pie.
209 Defines the starting angle of the pie.
210
210
211 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
211 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
212
212
213 Default is value is 0.
213 Default is value is 0.
214 */
214 */
215
215
216 /*!
216 /*!
217 \property QPieSeries::endAngle
217 \property QPieSeries::endAngle
218 \brief Defines the ending angle of the pie.
218 \brief Defines the ending angle of the pie.
219
219
220 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
220 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
221
221
222 Default is value is 360.
222 Default is value is 360.
223 */
223 */
224
224
225 /*!
225 /*!
226 \qmlproperty real PieSeries::endAngle
226 \qmlproperty real PieSeries::endAngle
227
227
228 Defines the ending angle of the pie.
228 Defines the ending angle of the pie.
229
229
230 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
230 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
231
231
232 Default is value is 360.
232 Default is value is 360.
233 */
233 */
234
234
235 /*!
235 /*!
236 \property QPieSeries::count
236 \property QPieSeries::count
237
237
238 Number of slices in the series.
238 Number of slices in the series.
239 */
239 */
240
240
241 /*!
241 /*!
242 \qmlproperty int PieSeries::count
242 \qmlproperty int PieSeries::count
243
243
244 Number of slices in the series.
244 Number of slices in the series.
245 */
245 */
246
246
247 /*!
247 /*!
248 \fn void QPieSeries::countChanged()
248 \fn void QPieSeries::countChanged()
249 Emitted when the slice count has changed.
249 Emitted when the slice count has changed.
250 \sa count
250 \sa count
251 */
251 */
252 /*!
252 /*!
253 \qmlsignal PieSeries::onCountChanged()
253 \qmlsignal PieSeries::onCountChanged()
254 Emitted when the slice count has changed.
254 Emitted when the slice count has changed.
255 */
255 */
256
256
257 /*!
257 /*!
258 \property QPieSeries::sum
258 \property QPieSeries::sum
259
259
260 Sum of all slices.
260 Sum of all slices.
261
261
262 The series keeps track of the sum of all slices it holds.
262 The series keeps track of the sum of all slices it holds.
263 */
263 */
264
264
265 /*!
265 /*!
266 \qmlproperty real PieSeries::sum
266 \qmlproperty real PieSeries::sum
267
267
268 Sum of all slices.
268 Sum of all slices.
269
269
270 The series keeps track of the sum of all slices it holds.
270 The series keeps track of the sum of all slices it holds.
271 */
271 */
272
272
273 /*!
273 /*!
274 \fn void QPieSeries::sumChanged()
274 \fn void QPieSeries::sumChanged()
275 Emitted when the sum of all slices has changed.
275 Emitted when the sum of all slices has changed.
276 \sa sum
276 \sa sum
277 */
277 */
278 /*!
278 /*!
279 \qmlsignal PieSeries::onSumChanged()
279 \qmlsignal PieSeries::onSumChanged()
280 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
280 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
281 change value of a slice.
281 change value of a slice.
282 */
282 */
283
283
284 /*!
284 /*!
285 \fn void QPieSeries::added(QList<QPieSlice*> slices)
285 \fn void QPieSeries::added(QList<QPieSlice*> slices)
286
286
287 This signal is emitted when \a slices have been added to the series.
287 This signal is emitted when \a slices have been added to the series.
288
288
289 \sa append(), insert()
289 \sa append(), insert()
290 */
290 */
291 /*!
291 /*!
292 \qmlsignal PieSeries::onAdded(PieSlice slice)
292 \qmlsignal PieSeries::onAdded(PieSlice slice)
293 Emitted when \a slice has been added to the series.
293 Emitted when \a slice has been added to the series.
294 */
294 */
295
295
296 /*!
296 /*!
297 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
297 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
298 This signal is emitted when \a slices have been removed from the series.
298 This signal is emitted when \a slices have been removed from the series.
299 \sa remove()
299 \sa remove()
300 */
300 */
301 /*!
301 /*!
302 \qmlsignal PieSeries::onRemoved(PieSlice slice)
302 \qmlsignal PieSeries::onRemoved(PieSlice slice)
303 Emitted when \a slice has been removed from the series.
303 Emitted when \a slice has been removed from the series.
304 */
304 */
305
305
306 /*!
306 /*!
307 \fn void QPieSeries::clicked(QPieSlice* slice)
307 \fn void QPieSeries::clicked(QPieSlice *slice)
308 This signal is emitted when a \a slice has been clicked.
308 This signal is emitted when a \a slice has been clicked.
309 \sa QPieSlice::clicked()
309 \sa QPieSlice::clicked()
310 */
310 */
311 /*!
311 /*!
312 \qmlsignal PieSeries::onClicked(PieSlice slice)
312 \qmlsignal PieSeries::onClicked(PieSlice slice)
313 This signal is emitted when a \a slice has been clicked.
313 This signal is emitted when a \a slice has been clicked.
314 */
314 */
315
315
316 /*!
316 /*!
317 \fn void QPieSeries::pressed(QPieSlice* slice)
317 \fn void QPieSeries::pressed(QPieSlice *slice)
318 This signal is emitted when a \a slice has been pressed.
318 This signal is emitted when a \a slice has been pressed.
319 \sa QPieSlice::pressed()
319 \sa QPieSlice::pressed()
320 */
320 */
321 /*!
321 /*!
322 \qmlsignal PieSeries::onPressed(PieSlice slice)
322 \qmlsignal PieSeries::onPressed(PieSlice slice)
323 This signal is emitted when a \a slice has been pressed.
323 This signal is emitted when a \a slice has been pressed.
324 */
324 */
325
325
326 /*!
326 /*!
327 \fn void QPieSeries::released(QPieSlice* slice)
327 \fn void QPieSeries::released(QPieSlice *slice)
328 This signal is emitted when a \a slice has been released.
328 This signal is emitted when a \a slice has been released.
329 \sa QPieSlice::released()
329 \sa QPieSlice::released()
330 */
330 */
331 /*!
331 /*!
332 \qmlsignal PieSeries::onReleased(PieSlice slice)
332 \qmlsignal PieSeries::onReleased(PieSlice slice)
333 This signal is emitted when a \a slice has been released.
333 This signal is emitted when a \a slice has been released.
334 */
334 */
335
335
336 /*!
336 /*!
337 \fn void QPieSeries::doubleClicked(QPieSlice* slice)
337 \fn void QPieSeries::doubleClicked(QPieSlice *slice)
338 This signal is emitted when a \a slice has been doubleClicked.
338 This signal is emitted when a \a slice has been doubleClicked.
339 \sa QPieSlice::doubleClicked()
339 \sa QPieSlice::doubleClicked()
340 */
340 */
341 /*!
341 /*!
342 \qmlsignal PieSeries::onDoubleClicked(PieSlice slice)
342 \qmlsignal PieSeries::onDoubleClicked(PieSlice slice)
343 This signal is emitted when a \a slice has been doubleClicked.
343 This signal is emitted when a \a slice has been doubleClicked.
344 */
344 */
345
345
346 /*!
346 /*!
347 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
347 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
348 This signal is emitted when user has hovered over or away from the \a slice.
348 This signal is emitted when user has hovered over or away from the \a slice.
349 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
349 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
350 \sa QPieSlice::hovered()
350 \sa QPieSlice::hovered()
351 */
351 */
352 /*!
352 /*!
353 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
353 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
354 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
354 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
355 over the slice and false when hover has moved away from the slice.
355 over the slice and false when hover has moved away from the slice.
356 */
356 */
357
357
358 /*!
358 /*!
359 \qmlmethod PieSlice PieSeries::at(int index)
359 \qmlmethod PieSlice PieSeries::at(int index)
360 Returns slice at \a index. Returns null if the index is not valid.
360 Returns slice at \a index. Returns null if the index is not valid.
361 */
361 */
362
362
363 /*!
363 /*!
364 \qmlmethod PieSlice PieSeries::find(string label)
364 \qmlmethod PieSlice PieSeries::find(string label)
365 Returns the first slice with \a label. Returns null if the index is not valid.
365 Returns the first slice with \a label. Returns null if the index is not valid.
366 */
366 */
367
367
368 /*!
368 /*!
369 \qmlmethod PieSlice PieSeries::append(string label, real value)
369 \qmlmethod PieSlice PieSeries::append(string label, real value)
370 Adds a new slice with \a label and \a value to the pie.
370 Adds a new slice with \a label and \a value to the pie.
371 */
371 */
372
372
373 /*!
373 /*!
374 \qmlmethod bool PieSeries::remove(PieSlice slice)
374 \qmlmethod bool PieSeries::remove(PieSlice slice)
375 Removes the \a slice from the pie. Returns true if the removal was successful, false otherwise.
375 Removes the \a slice from the pie. Returns true if the removal was successful, false otherwise.
376 */
376 */
377
377
378 /*!
378 /*!
379 \qmlmethod PieSeries::clear()
379 \qmlmethod PieSeries::clear()
380 Removes all slices from the pie.
380 Removes all slices from the pie.
381 */
381 */
382
382
383 /*!
383 /*!
384 Constructs a series object which is a child of \a parent.
384 Constructs a series object which is a child of \a parent.
385 */
385 */
386 QPieSeries::QPieSeries(QObject *parent)
386 QPieSeries::QPieSeries(QObject *parent)
387 : QAbstractSeries(*new QPieSeriesPrivate(this), parent)
387 : QAbstractSeries(*new QPieSeriesPrivate(this), parent)
388 {
388 {
389 Q_D(QPieSeries);
389 Q_D(QPieSeries);
390 QObject::connect(this, SIGNAL(countChanged()), d, SIGNAL(countChanged()));
390 QObject::connect(this, SIGNAL(countChanged()), d, SIGNAL(countChanged()));
391 }
391 }
392
392
393 /*!
393 /*!
394 Destroys the series and its slices.
394 Destroys the series and its slices.
395 */
395 */
396 QPieSeries::~QPieSeries()
396 QPieSeries::~QPieSeries()
397 {
397 {
398 // NOTE: d_prt destroyed by QObject
398 // NOTE: d_prt destroyed by QObject
399 clear();
399 clear();
400 }
400 }
401
401
402 /*!
402 /*!
403 Returns QAbstractSeries::SeriesTypePie.
403 Returns QAbstractSeries::SeriesTypePie.
404 */
404 */
405 QAbstractSeries::SeriesType QPieSeries::type() const
405 QAbstractSeries::SeriesType QPieSeries::type() const
406 {
406 {
407 return QAbstractSeries::SeriesTypePie;
407 return QAbstractSeries::SeriesTypePie;
408 }
408 }
409
409
410 /*!
410 /*!
411 Appends a single \a slice to the series.
411 Appends a single \a slice to the series.
412 Slice ownership is passed to the series.
412 Slice ownership is passed to the series.
413
413
414 Returns true if append was succesfull.
414 Returns true if append was succesfull.
415 */
415 */
416 bool QPieSeries::append(QPieSlice *slice)
416 bool QPieSeries::append(QPieSlice *slice)
417 {
417 {
418 return append(QList<QPieSlice *>() << slice);
418 return append(QList<QPieSlice *>() << slice);
419 }
419 }
420
420
421 /*!
421 /*!
422 Appends an array of \a slices to the series.
422 Appends an array of \a slices to the series.
423 Slice ownership is passed to the series.
423 Slice ownership is passed to the series.
424
424
425 Returns true if append was successful.
425 Returns true if append was successful.
426 */
426 */
427 bool QPieSeries::append(QList<QPieSlice *> slices)
427 bool QPieSeries::append(QList<QPieSlice *> slices)
428 {
428 {
429 Q_D(QPieSeries);
429 Q_D(QPieSeries);
430
430
431 if (slices.count() == 0)
431 if (slices.count() == 0)
432 return false;
432 return false;
433
433
434 foreach (QPieSlice *s, slices) {
434 foreach (QPieSlice *s, slices) {
435 if (!s || d->m_slices.contains(s))
435 if (!s || d->m_slices.contains(s))
436 return false;
436 return false;
437 if (s->series()) // already added to some series
437 if (s->series()) // already added to some series
438 return false;
438 return false;
439 if (!isValidValue(s->value()))
439 if (!isValidValue(s->value()))
440 return false;
440 return false;
441 }
441 }
442
442
443 foreach (QPieSlice *s, slices) {
443 foreach (QPieSlice *s, slices) {
444 s->setParent(this);
444 s->setParent(this);
445 QPieSlicePrivate::fromSlice(s)->m_series = this;
445 QPieSlicePrivate::fromSlice(s)->m_series = this;
446 d->m_slices << s;
446 d->m_slices << s;
447 }
447 }
448
448
449 d->updateDerivativeData();
449 d->updateDerivativeData();
450
450
451 foreach(QPieSlice * s, slices) {
451 foreach(QPieSlice * s, slices) {
452 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
452 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
453 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
453 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
454 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
454 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
455 connect(s, SIGNAL(pressed()), d, SLOT(slicePressed()));
455 connect(s, SIGNAL(pressed()), d, SLOT(slicePressed()));
456 connect(s, SIGNAL(released()), d, SLOT(sliceReleased()));
456 connect(s, SIGNAL(released()), d, SLOT(sliceReleased()));
457 connect(s, SIGNAL(doubleClicked()), d, SLOT(sliceDoubleClicked()));
457 connect(s, SIGNAL(doubleClicked()), d, SLOT(sliceDoubleClicked()));
458 }
458 }
459
459
460 emit added(slices);
460 emit added(slices);
461 emit countChanged();
461 emit countChanged();
462
462
463 return true;
463 return true;
464 }
464 }
465
465
466 /*!
466 /*!
467 Appends a single \a slice to the series and returns a reference to the series.
467 Appends a single \a slice to the series and returns a reference to the series.
468 Slice ownership is passed to the series.
468 Slice ownership is passed to the series.
469 */
469 */
470 QPieSeries &QPieSeries::operator << (QPieSlice *slice)
470 QPieSeries &QPieSeries::operator << (QPieSlice *slice)
471 {
471 {
472 append(slice);
472 append(slice);
473 return *this;
473 return *this;
474 }
474 }
475
475
476
476
477 /*!
477 /*!
478 Appends a single slice to the series with give \a value and \a label.
478 Appends a single slice to the series with give \a value and \a label.
479 Slice ownership is passed to the series.
479 Slice ownership is passed to the series.
480 Returns NULL if value is NaN, Inf or -Inf and no slice is added to the series.
480 Returns NULL if value is NaN, Inf or -Inf and no slice is added to the series.
481 */
481 */
482 QPieSlice *QPieSeries::append(QString label, qreal value)
482 QPieSlice *QPieSeries::append(QString label, qreal value)
483 {
483 {
484 if (isValidValue(value)) {
484 if (isValidValue(value)) {
485 QPieSlice *slice = new QPieSlice(label, value);
485 QPieSlice *slice = new QPieSlice(label, value);
486 append(slice);
486 append(slice);
487 return slice;
487 return slice;
488 } else {
488 } else {
489 return 0;
489 return 0;
490 }
490 }
491 }
491 }
492
492
493 /*!
493 /*!
494 Inserts a single \a slice to the series before the slice at \a index position.
494 Inserts a single \a slice to the series before the slice at \a index position.
495 Slice ownership is passed to the series.
495 Slice ownership is passed to the series.
496
496
497 Returns true if insert was successful.
497 Returns true if insert was successful.
498 */
498 */
499 bool QPieSeries::insert(int index, QPieSlice *slice)
499 bool QPieSeries::insert(int index, QPieSlice *slice)
500 {
500 {
501 Q_D(QPieSeries);
501 Q_D(QPieSeries);
502
502
503 if (index < 0 || index > d->m_slices.count())
503 if (index < 0 || index > d->m_slices.count())
504 return false;
504 return false;
505
505
506 if (!slice || d->m_slices.contains(slice))
506 if (!slice || d->m_slices.contains(slice))
507 return false;
507 return false;
508
508
509 if (slice->series()) // already added to some series
509 if (slice->series()) // already added to some series
510 return false;
510 return false;
511
511
512 if (!isValidValue(slice->value()))
512 if (!isValidValue(slice->value()))
513 return false;
513 return false;
514
514
515 slice->setParent(this);
515 slice->setParent(this);
516 QPieSlicePrivate::fromSlice(slice)->m_series = this;
516 QPieSlicePrivate::fromSlice(slice)->m_series = this;
517 d->m_slices.insert(index, slice);
517 d->m_slices.insert(index, slice);
518
518
519 d->updateDerivativeData();
519 d->updateDerivativeData();
520
520
521 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
521 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
522 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
522 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
523 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
523 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
524 connect(slice, SIGNAL(pressed()), d, SLOT(slicePressed()));
524 connect(slice, SIGNAL(pressed()), d, SLOT(slicePressed()));
525 connect(slice, SIGNAL(released()), d, SLOT(sliceReleased()));
525 connect(slice, SIGNAL(released()), d, SLOT(sliceReleased()));
526 connect(slice, SIGNAL(doubleClicked()), d, SLOT(sliceDoubleClicked()));
526 connect(slice, SIGNAL(doubleClicked()), d, SLOT(sliceDoubleClicked()));
527
527
528 emit added(QList<QPieSlice *>() << slice);
528 emit added(QList<QPieSlice *>() << slice);
529 emit countChanged();
529 emit countChanged();
530
530
531 return true;
531 return true;
532 }
532 }
533
533
534 /*!
534 /*!
535 Removes a single \a slice from the series and deletes the slice.
535 Removes a single \a slice from the series and deletes the slice.
536
536
537 Do not reference the pointer after this call.
537 Do not reference the pointer after this call.
538
538
539 Returns true if remove was successful.
539 Returns true if remove was successful.
540 */
540 */
541 bool QPieSeries::remove(QPieSlice *slice)
541 bool QPieSeries::remove(QPieSlice *slice)
542 {
542 {
543 Q_D(QPieSeries);
543 Q_D(QPieSeries);
544
544
545 if (!d->m_slices.removeOne(slice))
545 if (!d->m_slices.removeOne(slice))
546 return false;
546 return false;
547
547
548 d->updateDerivativeData();
548 d->updateDerivativeData();
549
549
550 emit removed(QList<QPieSlice *>() << slice);
550 emit removed(QList<QPieSlice *>() << slice);
551 emit countChanged();
551 emit countChanged();
552
552
553 delete slice;
553 delete slice;
554 slice = 0;
554 slice = 0;
555
555
556 return true;
556 return true;
557 }
557 }
558
558
559 /*!
559 /*!
560 Takes a single \a slice from the series. Does not destroy the slice object.
560 Takes a single \a slice from the series. Does not destroy the slice object.
561
561
562 \note The series remains as the slice's parent object. You must set the
562 \note The series remains as the slice's parent object. You must set the
563 parent object to take full ownership.
563 parent object to take full ownership.
564
564
565 Returns true if take was successful.
565 Returns true if take was successful.
566 */
566 */
567 bool QPieSeries::take(QPieSlice *slice)
567 bool QPieSeries::take(QPieSlice *slice)
568 {
568 {
569 Q_D(QPieSeries);
569 Q_D(QPieSeries);
570
570
571 if (!d->m_slices.removeOne(slice))
571 if (!d->m_slices.removeOne(slice))
572 return false;
572 return false;
573
573
574 QPieSlicePrivate::fromSlice(slice)->m_series = 0;
574 QPieSlicePrivate::fromSlice(slice)->m_series = 0;
575 slice->disconnect(d);
575 slice->disconnect(d);
576
576
577 d->updateDerivativeData();
577 d->updateDerivativeData();
578
578
579 emit removed(QList<QPieSlice *>() << slice);
579 emit removed(QList<QPieSlice *>() << slice);
580 emit countChanged();
580 emit countChanged();
581
581
582 return true;
582 return true;
583 }
583 }
584
584
585 /*!
585 /*!
586 Clears all slices from the series.
586 Clears all slices from the series.
587 */
587 */
588 void QPieSeries::clear()
588 void QPieSeries::clear()
589 {
589 {
590 Q_D(QPieSeries);
590 Q_D(QPieSeries);
591 if (d->m_slices.count() == 0)
591 if (d->m_slices.count() == 0)
592 return;
592 return;
593
593
594 QList<QPieSlice *> slices = d->m_slices;
594 QList<QPieSlice *> slices = d->m_slices;
595 foreach (QPieSlice *s, d->m_slices)
595 foreach (QPieSlice *s, d->m_slices)
596 d->m_slices.removeOne(s);
596 d->m_slices.removeOne(s);
597
597
598 d->updateDerivativeData();
598 d->updateDerivativeData();
599
599
600 emit removed(slices);
600 emit removed(slices);
601 emit countChanged();
601 emit countChanged();
602
602
603 foreach (QPieSlice *s, slices)
603 foreach (QPieSlice *s, slices)
604 delete s;
604 delete s;
605 }
605 }
606
606
607 /*!
607 /*!
608 Returns a list of slices that belong to this series.
608 Returns a list of slices that belong to this series.
609 */
609 */
610 QList<QPieSlice *> QPieSeries::slices() const
610 QList<QPieSlice *> QPieSeries::slices() const
611 {
611 {
612 Q_D(const QPieSeries);
612 Q_D(const QPieSeries);
613 return d->m_slices;
613 return d->m_slices;
614 }
614 }
615
615
616 /*!
616 /*!
617 returns the number of the slices in this series.
617 returns the number of the slices in this series.
618 */
618 */
619 int QPieSeries::count() const
619 int QPieSeries::count() const
620 {
620 {
621 Q_D(const QPieSeries);
621 Q_D(const QPieSeries);
622 return d->m_slices.count();
622 return d->m_slices.count();
623 }
623 }
624
624
625 /*!
625 /*!
626 Returns true is the series is empty.
626 Returns true is the series is empty.
627 */
627 */
628 bool QPieSeries::isEmpty() const
628 bool QPieSeries::isEmpty() const
629 {
629 {
630 Q_D(const QPieSeries);
630 Q_D(const QPieSeries);
631 return d->m_slices.isEmpty();
631 return d->m_slices.isEmpty();
632 }
632 }
633
633
634 /*!
634 /*!
635 Returns the sum of all slice values in this series.
635 Returns the sum of all slice values in this series.
636
636
637 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
637 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
638 */
638 */
639 qreal QPieSeries::sum() const
639 qreal QPieSeries::sum() const
640 {
640 {
641 Q_D(const QPieSeries);
641 Q_D(const QPieSeries);
642 return d->m_sum;
642 return d->m_sum;
643 }
643 }
644
644
645 void QPieSeries::setHoleSize(qreal holeSize)
645 void QPieSeries::setHoleSize(qreal holeSize)
646 {
646 {
647 Q_D(QPieSeries);
647 Q_D(QPieSeries);
648 holeSize = qBound((qreal)0.0, holeSize, (qreal)1.0);
648 holeSize = qBound((qreal)0.0, holeSize, (qreal)1.0);
649 d->setSizes(holeSize, qMax(d->m_pieRelativeSize, holeSize));
649 d->setSizes(holeSize, qMax(d->m_pieRelativeSize, holeSize));
650 }
650 }
651
651
652 qreal QPieSeries::holeSize() const
652 qreal QPieSeries::holeSize() const
653 {
653 {
654 Q_D(const QPieSeries);
654 Q_D(const QPieSeries);
655 return d->m_holeRelativeSize;
655 return d->m_holeRelativeSize;
656 }
656 }
657
657
658 void QPieSeries::setHorizontalPosition(qreal relativePosition)
658 void QPieSeries::setHorizontalPosition(qreal relativePosition)
659 {
659 {
660 Q_D(QPieSeries);
660 Q_D(QPieSeries);
661
661
662 if (relativePosition < 0.0)
662 if (relativePosition < 0.0)
663 relativePosition = 0.0;
663 relativePosition = 0.0;
664 if (relativePosition > 1.0)
664 if (relativePosition > 1.0)
665 relativePosition = 1.0;
665 relativePosition = 1.0;
666
666
667 if (!qFuzzyCompare(d->m_pieRelativeHorPos, relativePosition)) {
667 if (!qFuzzyCompare(d->m_pieRelativeHorPos, relativePosition)) {
668 d->m_pieRelativeHorPos = relativePosition;
668 d->m_pieRelativeHorPos = relativePosition;
669 emit d->horizontalPositionChanged();
669 emit d->horizontalPositionChanged();
670 }
670 }
671 }
671 }
672
672
673 qreal QPieSeries::horizontalPosition() const
673 qreal QPieSeries::horizontalPosition() const
674 {
674 {
675 Q_D(const QPieSeries);
675 Q_D(const QPieSeries);
676 return d->m_pieRelativeHorPos;
676 return d->m_pieRelativeHorPos;
677 }
677 }
678
678
679 void QPieSeries::setVerticalPosition(qreal relativePosition)
679 void QPieSeries::setVerticalPosition(qreal relativePosition)
680 {
680 {
681 Q_D(QPieSeries);
681 Q_D(QPieSeries);
682
682
683 if (relativePosition < 0.0)
683 if (relativePosition < 0.0)
684 relativePosition = 0.0;
684 relativePosition = 0.0;
685 if (relativePosition > 1.0)
685 if (relativePosition > 1.0)
686 relativePosition = 1.0;
686 relativePosition = 1.0;
687
687
688 if (!qFuzzyCompare(d->m_pieRelativeVerPos, relativePosition)) {
688 if (!qFuzzyCompare(d->m_pieRelativeVerPos, relativePosition)) {
689 d->m_pieRelativeVerPos = relativePosition;
689 d->m_pieRelativeVerPos = relativePosition;
690 emit d->verticalPositionChanged();
690 emit d->verticalPositionChanged();
691 }
691 }
692 }
692 }
693
693
694 qreal QPieSeries::verticalPosition() const
694 qreal QPieSeries::verticalPosition() const
695 {
695 {
696 Q_D(const QPieSeries);
696 Q_D(const QPieSeries);
697 return d->m_pieRelativeVerPos;
697 return d->m_pieRelativeVerPos;
698 }
698 }
699
699
700 void QPieSeries::setPieSize(qreal relativeSize)
700 void QPieSeries::setPieSize(qreal relativeSize)
701 {
701 {
702 Q_D(QPieSeries);
702 Q_D(QPieSeries);
703 relativeSize = qBound((qreal)0.0, relativeSize, (qreal)1.0);
703 relativeSize = qBound((qreal)0.0, relativeSize, (qreal)1.0);
704 d->setSizes(qMin(d->m_holeRelativeSize, relativeSize), relativeSize);
704 d->setSizes(qMin(d->m_holeRelativeSize, relativeSize), relativeSize);
705
705
706 }
706 }
707
707
708 qreal QPieSeries::pieSize() const
708 qreal QPieSeries::pieSize() const
709 {
709 {
710 Q_D(const QPieSeries);
710 Q_D(const QPieSeries);
711 return d->m_pieRelativeSize;
711 return d->m_pieRelativeSize;
712 }
712 }
713
713
714
714
715 void QPieSeries::setPieStartAngle(qreal angle)
715 void QPieSeries::setPieStartAngle(qreal angle)
716 {
716 {
717 Q_D(QPieSeries);
717 Q_D(QPieSeries);
718 if (qFuzzyCompare(d->m_pieStartAngle, angle))
718 if (qFuzzyCompare(d->m_pieStartAngle, angle))
719 return;
719 return;
720 d->m_pieStartAngle = angle;
720 d->m_pieStartAngle = angle;
721 d->updateDerivativeData();
721 d->updateDerivativeData();
722 emit d->pieStartAngleChanged();
722 emit d->pieStartAngleChanged();
723 }
723 }
724
724
725 qreal QPieSeries::pieStartAngle() const
725 qreal QPieSeries::pieStartAngle() const
726 {
726 {
727 Q_D(const QPieSeries);
727 Q_D(const QPieSeries);
728 return d->m_pieStartAngle;
728 return d->m_pieStartAngle;
729 }
729 }
730
730
731 /*!
731 /*!
732 Sets the end angle of the pie.
732 Sets the end angle of the pie.
733
733
734 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
734 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
735
735
736 \a angle must be greater than start angle.
736 \a angle must be greater than start angle.
737
737
738 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
738 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
739 */
739 */
740 void QPieSeries::setPieEndAngle(qreal angle)
740 void QPieSeries::setPieEndAngle(qreal angle)
741 {
741 {
742 Q_D(QPieSeries);
742 Q_D(QPieSeries);
743 if (qFuzzyCompare(d->m_pieEndAngle, angle))
743 if (qFuzzyCompare(d->m_pieEndAngle, angle))
744 return;
744 return;
745 d->m_pieEndAngle = angle;
745 d->m_pieEndAngle = angle;
746 d->updateDerivativeData();
746 d->updateDerivativeData();
747 emit d->pieEndAngleChanged();
747 emit d->pieEndAngleChanged();
748 }
748 }
749
749
750 /*!
750 /*!
751 Returns the end angle of the pie.
751 Returns the end angle of the pie.
752
752
753 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
753 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
754
754
755 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
755 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
756 */
756 */
757 qreal QPieSeries::pieEndAngle() const
757 qreal QPieSeries::pieEndAngle() const
758 {
758 {
759 Q_D(const QPieSeries);
759 Q_D(const QPieSeries);
760 return d->m_pieEndAngle;
760 return d->m_pieEndAngle;
761 }
761 }
762
762
763 /*!
763 /*!
764 Sets the all the slice labels \a visible or invisible.
764 Sets the all the slice labels \a visible or invisible.
765
765
766 Note that this affects only the current slices in the series.
766 Note that this affects only the current slices in the series.
767 If user adds a new slice the default label visibility is false.
767 If user adds a new slice the default label visibility is false.
768
768
769 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
769 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
770 */
770 */
771 void QPieSeries::setLabelsVisible(bool visible)
771 void QPieSeries::setLabelsVisible(bool visible)
772 {
772 {
773 Q_D(QPieSeries);
773 Q_D(QPieSeries);
774 foreach (QPieSlice *s, d->m_slices)
774 foreach (QPieSlice *s, d->m_slices)
775 s->setLabelVisible(visible);
775 s->setLabelVisible(visible);
776 }
776 }
777
777
778 /*!
778 /*!
779 Sets the all the slice labels \a position
779 Sets the all the slice labels \a position
780
780
781 Note that this affects only the current slices in the series.
781 Note that this affects only the current slices in the series.
782 If user adds a new slice the default label position is LabelOutside
782 If user adds a new slice the default label position is LabelOutside
783
783
784 \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
784 \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
785 */
785 */
786 void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
786 void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
787 {
787 {
788 Q_D(QPieSeries);
788 Q_D(QPieSeries);
789 foreach (QPieSlice *s, d->m_slices)
789 foreach (QPieSlice *s, d->m_slices)
790 s->setLabelPosition(position);
790 s->setLabelPosition(position);
791 }
791 }
792
792
793 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
793 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
794
794
795
795
796 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
796 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
797 QAbstractSeriesPrivate(parent),
797 QAbstractSeriesPrivate(parent),
798 m_pieRelativeHorPos(0.5),
798 m_pieRelativeHorPos(0.5),
799 m_pieRelativeVerPos(0.5),
799 m_pieRelativeVerPos(0.5),
800 m_pieRelativeSize(0.7),
800 m_pieRelativeSize(0.7),
801 m_pieStartAngle(0),
801 m_pieStartAngle(0),
802 m_pieEndAngle(360),
802 m_pieEndAngle(360),
803 m_sum(0),
803 m_sum(0),
804 m_holeRelativeSize(0.0)
804 m_holeRelativeSize(0.0)
805 {
805 {
806 }
806 }
807
807
808 QPieSeriesPrivate::~QPieSeriesPrivate()
808 QPieSeriesPrivate::~QPieSeriesPrivate()
809 {
809 {
810 }
810 }
811
811
812 void QPieSeriesPrivate::updateDerivativeData()
812 void QPieSeriesPrivate::updateDerivativeData()
813 {
813 {
814 // calculate sum of all slices
814 // calculate sum of all slices
815 qreal sum = 0;
815 qreal sum = 0;
816 foreach (QPieSlice *s, m_slices)
816 foreach (QPieSlice *s, m_slices)
817 sum += s->value();
817 sum += s->value();
818
818
819 if (!qFuzzyCompare(m_sum, sum)) {
819 if (!qFuzzyCompare(m_sum, sum)) {
820 m_sum = sum;
820 m_sum = sum;
821 emit q_func()->sumChanged();
821 emit q_func()->sumChanged();
822 }
822 }
823
823
824 // nothing to show..
824 // nothing to show..
825 if (qFuzzyCompare(m_sum, 0))
825 if (qFuzzyCompare(m_sum, 0))
826 return;
826 return;
827
827
828 // update slice attributes
828 // update slice attributes
829 qreal sliceAngle = m_pieStartAngle;
829 qreal sliceAngle = m_pieStartAngle;
830 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
830 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
831 QVector<QPieSlice *> changed;
831 QVector<QPieSlice *> changed;
832 foreach (QPieSlice *s, m_slices) {
832 foreach (QPieSlice *s, m_slices) {
833 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
833 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
834 d->setPercentage(s->value() / m_sum);
834 d->setPercentage(s->value() / m_sum);
835 d->setStartAngle(sliceAngle);
835 d->setStartAngle(sliceAngle);
836 d->setAngleSpan(pieSpan * s->percentage());
836 d->setAngleSpan(pieSpan * s->percentage());
837 sliceAngle += s->angleSpan();
837 sliceAngle += s->angleSpan();
838 }
838 }
839
839
840
840
841 emit calculatedDataChanged();
841 emit calculatedDataChanged();
842 }
842 }
843
843
844 void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
844 void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
845 {
845 {
846 bool changed = false;
846 bool changed = false;
847
847
848 if (!qFuzzyCompare(m_holeRelativeSize, innerSize)) {
848 if (!qFuzzyCompare(m_holeRelativeSize, innerSize)) {
849 m_holeRelativeSize = innerSize;
849 m_holeRelativeSize = innerSize;
850 changed = true;
850 changed = true;
851 }
851 }
852
852
853 if (!qFuzzyCompare(m_pieRelativeSize, outerSize)) {
853 if (!qFuzzyCompare(m_pieRelativeSize, outerSize)) {
854 m_pieRelativeSize = outerSize;
854 m_pieRelativeSize = outerSize;
855 changed = true;
855 changed = true;
856 }
856 }
857
857
858 if (changed)
858 if (changed)
859 emit pieSizeChanged();
859 emit pieSizeChanged();
860 }
860 }
861
861
862 QPieSeriesPrivate *QPieSeriesPrivate::fromSeries(QPieSeries *series)
862 QPieSeriesPrivate *QPieSeriesPrivate::fromSeries(QPieSeries *series)
863 {
863 {
864 return series->d_func();
864 return series->d_func();
865 }
865 }
866
866
867 void QPieSeriesPrivate::sliceValueChanged()
867 void QPieSeriesPrivate::sliceValueChanged()
868 {
868 {
869 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
869 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
870 updateDerivativeData();
870 updateDerivativeData();
871 }
871 }
872
872
873 void QPieSeriesPrivate::sliceClicked()
873 void QPieSeriesPrivate::sliceClicked()
874 {
874 {
875 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
875 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
876 Q_ASSERT(m_slices.contains(slice));
876 Q_ASSERT(m_slices.contains(slice));
877 Q_Q(QPieSeries);
877 Q_Q(QPieSeries);
878 emit q->clicked(slice);
878 emit q->clicked(slice);
879 }
879 }
880
880
881 void QPieSeriesPrivate::sliceHovered(bool state)
881 void QPieSeriesPrivate::sliceHovered(bool state)
882 {
882 {
883 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
883 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
884 if (!m_slices.isEmpty()) {
884 if (!m_slices.isEmpty()) {
885 Q_ASSERT(m_slices.contains(slice));
885 Q_ASSERT(m_slices.contains(slice));
886 Q_Q(QPieSeries);
886 Q_Q(QPieSeries);
887 emit q->hovered(slice, state);
887 emit q->hovered(slice, state);
888 }
888 }
889 }
889 }
890
890
891 void QPieSeriesPrivate::slicePressed()
891 void QPieSeriesPrivate::slicePressed()
892 {
892 {
893 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
893 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
894 Q_ASSERT(m_slices.contains(slice));
894 Q_ASSERT(m_slices.contains(slice));
895 Q_Q(QPieSeries);
895 Q_Q(QPieSeries);
896 emit q->pressed(slice);
896 emit q->pressed(slice);
897 }
897 }
898
898
899 void QPieSeriesPrivate::sliceReleased()
899 void QPieSeriesPrivate::sliceReleased()
900 {
900 {
901 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
901 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
902 Q_ASSERT(m_slices.contains(slice));
902 Q_ASSERT(m_slices.contains(slice));
903 Q_Q(QPieSeries);
903 Q_Q(QPieSeries);
904 emit q->released(slice);
904 emit q->released(slice);
905 }
905 }
906
906
907 void QPieSeriesPrivate::sliceDoubleClicked()
907 void QPieSeriesPrivate::sliceDoubleClicked()
908 {
908 {
909 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
909 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
910 Q_ASSERT(m_slices.contains(slice));
910 Q_ASSERT(m_slices.contains(slice));
911 Q_Q(QPieSeries);
911 Q_Q(QPieSeries);
912 emit q->doubleClicked(slice);
912 emit q->doubleClicked(slice);
913 }
913 }
914
914
915 void QPieSeriesPrivate::initializeDomain()
915 void QPieSeriesPrivate::initializeDomain()
916 {
916 {
917 // does not apply to pie
917 // does not apply to pie
918 }
918 }
919
919
920 void QPieSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
920 void QPieSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
921 {
921 {
922 Q_Q(QPieSeries);
922 Q_Q(QPieSeries);
923 PieChartItem *pie = new PieChartItem(q,parent);
923 PieChartItem *pie = new PieChartItem(q,parent);
924 m_item.reset(pie);
924 m_item.reset(pie);
925 QAbstractSeriesPrivate::initializeGraphics(parent);
925 QAbstractSeriesPrivate::initializeGraphics(parent);
926 }
926 }
927
927
928 void QPieSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options)
928 void QPieSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options)
929 {
929 {
930 PieChartItem *item = static_cast<PieChartItem *>(m_item.data());
930 PieChartItem *item = static_cast<PieChartItem *>(m_item.data());
931 Q_ASSERT(item);
931 Q_ASSERT(item);
932 if (item->animation())
932 if (item->animation())
933 item->animation()->stopAndDestroyLater();
933 item->animation()->stopAndDestroyLater();
934
934
935 if (options.testFlag(QChart::SeriesAnimations))
935 if (options.testFlag(QChart::SeriesAnimations))
936 item->setAnimation(new PieAnimation(item));
936 item->setAnimation(new PieAnimation(item));
937 else
937 else
938 item->setAnimation(0);
938 item->setAnimation(0);
939 QAbstractSeriesPrivate::initializeAnimations(options);
939 QAbstractSeriesPrivate::initializeAnimations(options);
940 }
940 }
941
941
942 QList<QLegendMarker*> QPieSeriesPrivate::createLegendMarkers(QLegend* legend)
942 QList<QLegendMarker*> QPieSeriesPrivate::createLegendMarkers(QLegend* legend)
943 {
943 {
944 Q_Q(QPieSeries);
944 Q_Q(QPieSeries);
945 QList<QLegendMarker*> markers;
945 QList<QLegendMarker*> markers;
946 foreach(QPieSlice* slice, q->slices()) {
946 foreach(QPieSlice* slice, q->slices()) {
947 QPieLegendMarker* marker = new QPieLegendMarker(q,slice,legend);
947 QPieLegendMarker* marker = new QPieLegendMarker(q,slice,legend);
948 markers << marker;
948 markers << marker;
949 }
949 }
950 return markers;
950 return markers;
951 }
951 }
952
952
953 void QPieSeriesPrivate::initializeAxes()
953 void QPieSeriesPrivate::initializeAxes()
954 {
954 {
955
955
956 }
956 }
957
957
958 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
958 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
959 {
959 {
960 Q_UNUSED(orientation);
960 Q_UNUSED(orientation);
961 return QAbstractAxis::AxisTypeNoAxis;
961 return QAbstractAxis::AxisTypeNoAxis;
962 }
962 }
963
963
964 QAbstractAxis* QPieSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
964 QAbstractAxis* QPieSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
965 {
965 {
966 Q_UNUSED(orientation);
966 Q_UNUSED(orientation);
967 return 0;
967 return 0;
968 }
968 }
969
969
970 void QPieSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
970 void QPieSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
971 {
971 {
972 //Q_Q(QPieSeries);
972 //Q_Q(QPieSeries);
973 //const QList<QColor>& colors = theme->seriesColors();
973 //const QList<QColor>& colors = theme->seriesColors();
974 const QList<QGradient>& gradients = theme->seriesGradients();
974 const QList<QGradient>& gradients = theme->seriesGradients();
975
975
976 for (int i(0); i < m_slices.count(); i++) {
976 for (int i(0); i < m_slices.count(); i++) {
977
977
978 QColor penColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0);
978 QColor penColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0);
979
979
980 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
980 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
981 qreal pos = (qreal)(i + 1) / (qreal) m_slices.count();
981 qreal pos = (qreal)(i + 1) / (qreal) m_slices.count();
982 QColor brushColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), pos);
982 QColor brushColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), pos);
983
983
984 QPieSlice *s = m_slices.at(i);
984 QPieSlice *s = m_slices.at(i);
985 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
985 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
986
986
987 if (forced || d->m_data.m_slicePen.isThemed())
987 if (forced || d->m_data.m_slicePen.isThemed())
988 d->setPen(penColor, true);
988 d->setPen(penColor, true);
989
989
990 if (forced || d->m_data.m_sliceBrush.isThemed())
990 if (forced || d->m_data.m_sliceBrush.isThemed())
991 d->setBrush(brushColor, true);
991 d->setBrush(brushColor, true);
992
992
993 if (forced || d->m_data.m_labelBrush.isThemed())
993 if (forced || d->m_data.m_labelBrush.isThemed())
994 d->setLabelBrush(theme->labelBrush().color(), true);
994 d->setLabelBrush(theme->labelBrush().color(), true);
995
995
996 if (forced || d->m_data.m_labelFont.isThemed())
996 if (forced || d->m_data.m_labelFont.isThemed())
997 d->setLabelFont(theme->labelFont(), true);
997 d->setLabelFont(theme->labelFont(), true);
998 }
998 }
999 }
999 }
1000
1000
1001
1001
1002 #include "moc_qpieseries.cpp"
1002 #include "moc_qpieseries.cpp"
1003 #include "moc_qpieseries_p.cpp"
1003 #include "moc_qpieseries_p.cpp"
1004
1004
1005 QT_CHARTS_END_NAMESPACE
1005 QT_CHARTS_END_NAMESPACE
@@ -1,194 +1,189
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 // W A R N I N G
19 // W A R N I N G
20 // -------------
20 // -------------
21 //
21 //
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
22 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
23 // implementation detail. This header file may change from version to
23 // implementation detail. This header file may change from version to
24 // version without notice, or even be removed.
24 // version without notice, or even be removed.
25 //
25 //
26 // We mean it.
26 // We mean it.
27
27
28 #ifndef SCATTERCHARTITEM_H
28 #ifndef SCATTERCHARTITEM_H
29 #define SCATTERCHARTITEM_H
29 #define SCATTERCHARTITEM_H
30
30
31 #include <QtCharts/QChartGlobal>
31 #include <QtCharts/QChartGlobal>
32 #include <private/xychart_p.h>
32 #include <private/xychart_p.h>
33 #include <QtWidgets/QGraphicsEllipseItem>
33 #include <QtWidgets/QGraphicsEllipseItem>
34 #include <QtGui/QPen>
34 #include <QtGui/QPen>
35 #include <QtWidgets/QGraphicsSceneMouseEvent>
35 #include <QtWidgets/QGraphicsSceneMouseEvent>
36
36
37 QT_CHARTS_BEGIN_NAMESPACE
37 QT_CHARTS_BEGIN_NAMESPACE
38
38
39 class QScatterSeries;
39 class QScatterSeries;
40
40
41 class ScatterChartItem : public XYChart
41 class ScatterChartItem : public XYChart
42 {
42 {
43 Q_OBJECT
43 Q_OBJECT
44 Q_INTERFACES(QGraphicsItem)
44 Q_INTERFACES(QGraphicsItem)
45 public:
45 public:
46 explicit ScatterChartItem(QScatterSeries *series, QGraphicsItem *item = 0);
46 explicit ScatterChartItem(QScatterSeries *series, QGraphicsItem *item = 0);
47
47
48 public:
48 public:
49 //from QGraphicsItem
49 //from QGraphicsItem
50 QRectF boundingRect() const;
50 QRectF boundingRect() const;
51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
52
52
53 void setPen(const QPen &pen);
53 void setPen(const QPen &pen);
54 void setBrush(const QBrush &brush);
54 void setBrush(const QBrush &brush);
55
55
56 void markerSelected(QGraphicsItem *item);
56 void markerSelected(QGraphicsItem *item);
57 void markerHovered(QGraphicsItem *item, bool state);
57 void markerHovered(QGraphicsItem *item, bool state);
58 void markerPressed(QGraphicsItem *item);
58 void markerPressed(QGraphicsItem *item);
59 void markerReleased(QGraphicsItem *item);
59 void markerReleased(QGraphicsItem *item);
60 void markerDoubleClicked(QGraphicsItem *item);
60 void markerDoubleClicked(QGraphicsItem *item);
61
61
62 void setLastMousePosition(const QPointF pos) {m_lastMousePos = pos;}
63 QPointF lastMousePosition() const {return m_lastMousePos;}
64 void setMousePressed(bool pressed = true) {m_mousePressed = pressed;}
62 void setMousePressed(bool pressed = true) {m_mousePressed = pressed;}
65 bool mousePressed() {return m_mousePressed;}
63 bool mousePressed() {return m_mousePressed;}
66
64
67
65
68 public Q_SLOTS:
66 public Q_SLOTS:
69 void handleUpdated();
67 void handleUpdated();
70
68
71 private:
69 private:
72 void createPoints(int count);
70 void createPoints(int count);
73 void deletePoints(int count);
71 void deletePoints(int count);
74
72
75 protected:
73 protected:
76 void updateGeometry();
74 void updateGeometry();
77
75
78 private:
76 private:
79 QScatterSeries *m_series;
77 QScatterSeries *m_series;
80 QGraphicsItemGroup m_items;
78 QGraphicsItemGroup m_items;
81 bool m_visible;
79 bool m_visible;
82 int m_shape;
80 int m_shape;
83 int m_size;
81 int m_size;
84 QRectF m_rect;
82 QRectF m_rect;
85 QMap<QGraphicsItem *, QPointF> m_markerMap;
83 QMap<QGraphicsItem *, QPointF> m_markerMap;
86
84
87 bool m_pointLabelsVisible;
85 bool m_pointLabelsVisible;
88 QString m_pointLabelsFormat;
86 QString m_pointLabelsFormat;
89 QFont m_pointLabelsFont;
87 QFont m_pointLabelsFont;
90 QColor m_pointLabelsColor;
88 QColor m_pointLabelsColor;
91
89
92 QPointF m_lastMousePos;
93 bool m_mousePressed;
90 bool m_mousePressed;
94 };
91 };
95
92
96 class CircleMarker: public QGraphicsEllipseItem
93 class CircleMarker: public QGraphicsEllipseItem
97 {
94 {
98
95
99 public:
96 public:
100 CircleMarker(qreal x, qreal y, qreal w, qreal h, ScatterChartItem *parent)
97 CircleMarker(qreal x, qreal y, qreal w, qreal h, ScatterChartItem *parent)
101 : QGraphicsEllipseItem(x, y, w, h, parent),
98 : QGraphicsEllipseItem(x, y, w, h, parent),
102 m_parent(parent)
99 m_parent(parent)
103 {
100 {
104 setAcceptHoverEvents(true);
101 setAcceptHoverEvents(true);
105 setFlag(QGraphicsItem::ItemIsSelectable);
102 setFlag(QGraphicsItem::ItemIsSelectable);
106 }
103 }
107
104
108 protected:
105 protected:
109 void mousePressEvent(QGraphicsSceneMouseEvent *event)
106 void mousePressEvent(QGraphicsSceneMouseEvent *event)
110 {
107 {
111 QGraphicsEllipseItem::mousePressEvent(event);
108 QGraphicsEllipseItem::mousePressEvent(event);
112 m_parent->markerPressed(this);
109 m_parent->markerPressed(this);
113 m_parent->setLastMousePosition(event->pos());
114 m_parent->setMousePressed();
110 m_parent->setMousePressed();
115 }
111 }
116 void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
112 void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
117 {
113 {
118 QGraphicsEllipseItem::hoverEnterEvent(event);
114 QGraphicsEllipseItem::hoverEnterEvent(event);
119 m_parent->markerHovered(this, true);
115 m_parent->markerHovered(this, true);
120 }
116 }
121 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
117 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
122 {
118 {
123 QGraphicsEllipseItem::hoverLeaveEvent(event);
119 QGraphicsEllipseItem::hoverLeaveEvent(event);
124 m_parent->markerHovered(this, false);
120 m_parent->markerHovered(this, false);
125 }
121 }
126 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
122 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
127 {
123 {
128 QGraphicsEllipseItem::mouseReleaseEvent(event);
124 QGraphicsEllipseItem::mouseReleaseEvent(event);
129 m_parent->markerReleased(this);
125 m_parent->markerReleased(this);
130 if (m_parent->lastMousePosition() == event->pos() && m_parent->mousePressed())
126 if (m_parent->mousePressed())
131 m_parent->markerSelected(this);
127 m_parent->markerSelected(this);
132 m_parent->setMousePressed(false);
128 m_parent->setMousePressed(false);
133 }
129 }
134 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
130 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
135 {
131 {
136 QGraphicsEllipseItem::mouseDoubleClickEvent(event);
132 QGraphicsEllipseItem::mouseDoubleClickEvent(event);
137 m_parent->markerDoubleClicked(this);
133 m_parent->markerDoubleClicked(this);
138 }
134 }
139
135
140 private:
136 private:
141 ScatterChartItem *m_parent;
137 ScatterChartItem *m_parent;
142 };
138 };
143
139
144 class RectangleMarker: public QGraphicsRectItem
140 class RectangleMarker: public QGraphicsRectItem
145 {
141 {
146
142
147 public:
143 public:
148 RectangleMarker(qreal x, qreal y, qreal w, qreal h, ScatterChartItem *parent)
144 RectangleMarker(qreal x, qreal y, qreal w, qreal h, ScatterChartItem *parent)
149 : QGraphicsRectItem(x, y, w, h, parent),
145 : QGraphicsRectItem(x, y, w, h, parent),
150 m_parent(parent)
146 m_parent(parent)
151 {
147 {
152 setAcceptHoverEvents(true);
148 setAcceptHoverEvents(true);
153 setFlag(QGraphicsItem::ItemIsSelectable);
149 setFlag(QGraphicsItem::ItemIsSelectable);
154 }
150 }
155
151
156 protected:
152 protected:
157 void mousePressEvent(QGraphicsSceneMouseEvent *event)
153 void mousePressEvent(QGraphicsSceneMouseEvent *event)
158 {
154 {
159 QGraphicsRectItem::mousePressEvent(event);
155 QGraphicsRectItem::mousePressEvent(event);
160 m_parent->markerPressed(this);
156 m_parent->markerPressed(this);
161 m_parent->setLastMousePosition(event->pos());
162 m_parent->setMousePressed();
157 m_parent->setMousePressed();
163 }
158 }
164 void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
159 void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
165 {
160 {
166 QGraphicsRectItem::hoverEnterEvent(event);
161 QGraphicsRectItem::hoverEnterEvent(event);
167 m_parent->markerHovered(this, true);
162 m_parent->markerHovered(this, true);
168 }
163 }
169 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
164 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
170 {
165 {
171 QGraphicsRectItem::hoverLeaveEvent(event);
166 QGraphicsRectItem::hoverLeaveEvent(event);
172 m_parent->markerHovered(this, false);
167 m_parent->markerHovered(this, false);
173 }
168 }
174 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
169 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
175 {
170 {
176 QGraphicsRectItem::mouseReleaseEvent(event);
171 QGraphicsRectItem::mouseReleaseEvent(event);
177 m_parent->markerReleased(this);
172 m_parent->markerReleased(this);
178 if (m_parent->lastMousePosition() == event->pos() && m_parent->mousePressed())
173 if (m_parent->mousePressed())
179 m_parent->markerSelected(this);
174 m_parent->markerSelected(this);
180 m_parent->setMousePressed(false);
175 m_parent->setMousePressed(false);
181 }
176 }
182 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
177 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
183 {
178 {
184 QGraphicsRectItem::mouseDoubleClickEvent(event);
179 QGraphicsRectItem::mouseDoubleClickEvent(event);
185 m_parent->markerDoubleClicked(this);
180 m_parent->markerDoubleClicked(this);
186 }
181 }
187
182
188 private:
183 private:
189 ScatterChartItem *m_parent;
184 ScatterChartItem *m_parent;
190 };
185 };
191
186
192 QT_CHARTS_END_NAMESPACE
187 QT_CHARTS_END_NAMESPACE
193
188
194 #endif // SCATTERPRESENTER_H
189 #endif // SCATTERPRESENTER_H
@@ -1,502 +1,502
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/splinechartitem_p.h>
19 #include <private/splinechartitem_p.h>
20 #include <private/qsplineseries_p.h>
20 #include <private/qsplineseries_p.h>
21 #include <private/chartpresenter_p.h>
21 #include <private/chartpresenter_p.h>
22 #include <private/splineanimation_p.h>
22 #include <private/splineanimation_p.h>
23 #include <private/polardomain_p.h>
23 #include <private/polardomain_p.h>
24 #include <QtGui/QPainter>
24 #include <QtGui/QPainter>
25 #include <QtWidgets/QGraphicsSceneMouseEvent>
25 #include <QtWidgets/QGraphicsSceneMouseEvent>
26
26
27 QT_CHARTS_BEGIN_NAMESPACE
27 QT_CHARTS_BEGIN_NAMESPACE
28
28
29 SplineChartItem::SplineChartItem(QSplineSeries *series, QGraphicsItem *item)
29 SplineChartItem::SplineChartItem(QSplineSeries *series, QGraphicsItem *item)
30 : XYChart(series,item),
30 : XYChart(series,item),
31 m_series(series),
31 m_series(series),
32 m_pointsVisible(false),
32 m_pointsVisible(false),
33 m_animation(0),
33 m_animation(0),
34 m_pointLabelsVisible(false),
34 m_pointLabelsVisible(false),
35 m_pointLabelsFormat(series->pointLabelsFormat()),
35 m_pointLabelsFormat(series->pointLabelsFormat()),
36 m_pointLabelsFont(series->pointLabelsFont()),
36 m_pointLabelsFont(series->pointLabelsFont()),
37 m_pointLabelsColor(series->pointLabelsColor()),
37 m_pointLabelsColor(series->pointLabelsColor()),
38 m_mousePressed(false)
38 m_mousePressed(false)
39 {
39 {
40 setAcceptHoverEvents(true);
40 setAcceptHoverEvents(true);
41 setFlag(QGraphicsItem::ItemIsSelectable);
41 setFlag(QGraphicsItem::ItemIsSelectable);
42 setZValue(ChartPresenter::SplineChartZValue);
42 setZValue(ChartPresenter::SplineChartZValue);
43 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
43 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
44 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
44 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
45 QObject::connect(series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
45 QObject::connect(series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
46 QObject::connect(series, SIGNAL(pointLabelsFormatChanged(QString)),
46 QObject::connect(series, SIGNAL(pointLabelsFormatChanged(QString)),
47 this, SLOT(handleUpdated()));
47 this, SLOT(handleUpdated()));
48 QObject::connect(series, SIGNAL(pointLabelsVisibilityChanged(bool)),
48 QObject::connect(series, SIGNAL(pointLabelsVisibilityChanged(bool)),
49 this, SLOT(handleUpdated()));
49 this, SLOT(handleUpdated()));
50 QObject::connect(series, SIGNAL(pointLabelsFontChanged(QFont)), this, SLOT(handleUpdated()));
50 QObject::connect(series, SIGNAL(pointLabelsFontChanged(QFont)), this, SLOT(handleUpdated()));
51 QObject::connect(series, SIGNAL(pointLabelsColorChanged(QColor)), this, SLOT(handleUpdated()));
51 QObject::connect(series, SIGNAL(pointLabelsColorChanged(QColor)), this, SLOT(handleUpdated()));
52 handleUpdated();
52 handleUpdated();
53 }
53 }
54
54
55 QRectF SplineChartItem::boundingRect() const
55 QRectF SplineChartItem::boundingRect() const
56 {
56 {
57 return m_rect;
57 return m_rect;
58 }
58 }
59
59
60 QPainterPath SplineChartItem::shape() const
60 QPainterPath SplineChartItem::shape() const
61 {
61 {
62 return m_fullPath;
62 return m_fullPath;
63 }
63 }
64
64
65 void SplineChartItem::setAnimation(SplineAnimation *animation)
65 void SplineChartItem::setAnimation(SplineAnimation *animation)
66 {
66 {
67 m_animation = animation;
67 m_animation = animation;
68 XYChart::setAnimation(animation);
68 XYChart::setAnimation(animation);
69 }
69 }
70
70
71 ChartAnimation *SplineChartItem::animation() const
71 ChartAnimation *SplineChartItem::animation() const
72 {
72 {
73 return m_animation;
73 return m_animation;
74 }
74 }
75
75
76 void SplineChartItem::setControlGeometryPoints(QVector<QPointF>& points)
76 void SplineChartItem::setControlGeometryPoints(QVector<QPointF>& points)
77 {
77 {
78 m_controlPoints = points;
78 m_controlPoints = points;
79 }
79 }
80
80
81 QVector<QPointF> SplineChartItem::controlGeometryPoints() const
81 QVector<QPointF> SplineChartItem::controlGeometryPoints() const
82 {
82 {
83 return m_controlPoints;
83 return m_controlPoints;
84 }
84 }
85
85
86 void SplineChartItem::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
86 void SplineChartItem::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
87 {
87 {
88 QVector<QPointF> controlPoints;
88 QVector<QPointF> controlPoints;
89 if (newPoints.count() >= 2)
89 if (newPoints.count() >= 2)
90 controlPoints = calculateControlPoints(newPoints);
90 controlPoints = calculateControlPoints(newPoints);
91
91
92 if (m_animation)
92 if (m_animation)
93 m_animation->setup(oldPoints, newPoints, m_controlPoints, controlPoints, index);
93 m_animation->setup(oldPoints, newPoints, m_controlPoints, controlPoints, index);
94
94
95 m_points = newPoints;
95 m_points = newPoints;
96 m_controlPoints = controlPoints;
96 m_controlPoints = controlPoints;
97 setDirty(false);
97 setDirty(false);
98
98
99 if (m_animation)
99 if (m_animation)
100 presenter()->startAnimation(m_animation);
100 presenter()->startAnimation(m_animation);
101 else
101 else
102 updateGeometry();
102 updateGeometry();
103 }
103 }
104
104
105 void SplineChartItem::updateGeometry()
105 void SplineChartItem::updateGeometry()
106 {
106 {
107 const QVector<QPointF> &points = m_points;
107 const QVector<QPointF> &points = m_points;
108 const QVector<QPointF> &controlPoints = m_controlPoints;
108 const QVector<QPointF> &controlPoints = m_controlPoints;
109
109
110 if ((points.size() < 2) || (controlPoints.size() < 2)) {
110 if ((points.size() < 2) || (controlPoints.size() < 2)) {
111 prepareGeometryChange();
111 prepareGeometryChange();
112 m_path = QPainterPath();
112 m_path = QPainterPath();
113 m_rect = QRect();
113 m_rect = QRect();
114 return;
114 return;
115 }
115 }
116
116
117 Q_ASSERT(points.count() * 2 - 2 == controlPoints.count());
117 Q_ASSERT(points.count() * 2 - 2 == controlPoints.count());
118
118
119 QPainterPath splinePath;
119 QPainterPath splinePath;
120 QPainterPath fullPath;
120 QPainterPath fullPath;
121 // Use worst case scenario to determine required margin.
121 // Use worst case scenario to determine required margin.
122 qreal margin = m_linePen.width() * 1.42;
122 qreal margin = m_linePen.width() * 1.42;
123
123
124 if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
124 if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
125 QPainterPath splinePathLeft;
125 QPainterPath splinePathLeft;
126 QPainterPath splinePathRight;
126 QPainterPath splinePathRight;
127 QPainterPath *currentSegmentPath = 0;
127 QPainterPath *currentSegmentPath = 0;
128 QPainterPath *previousSegmentPath = 0;
128 QPainterPath *previousSegmentPath = 0;
129 qreal minX = domain()->minX();
129 qreal minX = domain()->minX();
130 qreal maxX = domain()->maxX();
130 qreal maxX = domain()->maxX();
131 qreal minY = domain()->minY();
131 qreal minY = domain()->minY();
132 QPointF currentSeriesPoint = m_series->at(0);
132 QPointF currentSeriesPoint = m_series->at(0);
133 QPointF currentGeometryPoint = points.at(0);
133 QPointF currentGeometryPoint = points.at(0);
134 QPointF previousGeometryPoint = points.at(0);
134 QPointF previousGeometryPoint = points.at(0);
135 bool pointOffGrid = false;
135 bool pointOffGrid = false;
136 bool previousPointWasOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
136 bool previousPointWasOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
137 m_visiblePoints.clear();
137 m_visiblePoints.clear();
138 m_visiblePoints.reserve(points.size());
138 m_visiblePoints.reserve(points.size());
139
139
140 qreal domainRadius = domain()->size().height() / 2.0;
140 qreal domainRadius = domain()->size().height() / 2.0;
141 const QPointF centerPoint(domainRadius, domainRadius);
141 const QPointF centerPoint(domainRadius, domainRadius);
142
142
143 if (!previousPointWasOffGrid) {
143 if (!previousPointWasOffGrid) {
144 fullPath.moveTo(points.at(0));
144 fullPath.moveTo(points.at(0));
145 // Do not draw points for points below minimum Y.
145 // Do not draw points for points below minimum Y.
146 if (m_pointsVisible && currentSeriesPoint.y() >= minY)
146 if (m_pointsVisible && currentSeriesPoint.y() >= minY)
147 m_visiblePoints.append(currentGeometryPoint);
147 m_visiblePoints.append(currentGeometryPoint);
148 }
148 }
149
149
150 qreal leftMarginLine = centerPoint.x() - margin;
150 qreal leftMarginLine = centerPoint.x() - margin;
151 qreal rightMarginLine = centerPoint.x() + margin;
151 qreal rightMarginLine = centerPoint.x() + margin;
152 qreal horizontal = centerPoint.y();
152 qreal horizontal = centerPoint.y();
153
153
154 // See ScatterChartItem::updateGeometry() for explanation why seriesLastIndex is needed
154 // See ScatterChartItem::updateGeometry() for explanation why seriesLastIndex is needed
155 const int seriesLastIndex = m_series->count() - 1;
155 const int seriesLastIndex = m_series->count() - 1;
156
156
157 for (int i = 1; i < points.size(); i++) {
157 for (int i = 1; i < points.size(); i++) {
158 // Interpolating spline fragments accurately is not trivial, and would anyway be ugly
158 // Interpolating spline fragments accurately is not trivial, and would anyway be ugly
159 // when thick pen is used, so we work around it by utilizing three separate
159 // when thick pen is used, so we work around it by utilizing three separate
160 // paths for spline segments and clip those with custom regions at paint time.
160 // paths for spline segments and clip those with custom regions at paint time.
161 // "Right" path contains segments that cross the axis line with visible point on the
161 // "Right" path contains segments that cross the axis line with visible point on the
162 // right side of the axis line, as well as segments that have one point within the margin
162 // right side of the axis line, as well as segments that have one point within the margin
163 // on the right side of the axis line and another point on the right side of the chart.
163 // on the right side of the axis line and another point on the right side of the chart.
164 // "Left" path contains points with similarly on the left side.
164 // "Left" path contains points with similarly on the left side.
165 // "Full" path contains rest of the points.
165 // "Full" path contains rest of the points.
166 // This doesn't yield perfect results always. E.g. when segment covers more than 90
166 // This doesn't yield perfect results always. E.g. when segment covers more than 90
167 // degrees and both of the points are within the margin, one in the top half and one in the
167 // degrees and both of the points are within the margin, one in the top half and one in the
168 // bottom half of the chart, the bottom one gets clipped incorrectly.
168 // bottom half of the chart, the bottom one gets clipped incorrectly.
169 // However, this should be rare occurrence in any sensible chart.
169 // However, this should be rare occurrence in any sensible chart.
170 currentSeriesPoint = m_series->at(qMin(seriesLastIndex, i));
170 currentSeriesPoint = m_series->at(qMin(seriesLastIndex, i));
171 currentGeometryPoint = points.at(i);
171 currentGeometryPoint = points.at(i);
172 pointOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
172 pointOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
173
173
174 // Draw something unless both off-grid
174 // Draw something unless both off-grid
175 if (!pointOffGrid || !previousPointWasOffGrid) {
175 if (!pointOffGrid || !previousPointWasOffGrid) {
176 bool dummyOk; // We know points are ok, but this is needed
176 bool dummyOk; // We know points are ok, but this is needed
177 qreal currentAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(currentSeriesPoint.x(), dummyOk);
177 qreal currentAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(currentSeriesPoint.x(), dummyOk);
178 qreal previousAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(m_series->at(i - 1).x(), dummyOk);
178 qreal previousAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(m_series->at(i - 1).x(), dummyOk);
179
179
180 if ((qAbs(currentAngle - previousAngle) > 180.0)) {
180 if ((qAbs(currentAngle - previousAngle) > 180.0)) {
181 // If the angle between two points is over 180 degrees (half X range),
181 // If the angle between two points is over 180 degrees (half X range),
182 // any direct segment between them becomes meaningless.
182 // any direct segment between them becomes meaningless.
183 // In this case two line segments are drawn instead, from previous
183 // In this case two line segments are drawn instead, from previous
184 // point to the center and from center to current point.
184 // point to the center and from center to current point.
185 if ((previousAngle < 0.0 || (previousAngle <= 180.0 && previousGeometryPoint.x() < rightMarginLine))
185 if ((previousAngle < 0.0 || (previousAngle <= 180.0 && previousGeometryPoint.x() < rightMarginLine))
186 && previousGeometryPoint.y() < horizontal) {
186 && previousGeometryPoint.y() < horizontal) {
187 currentSegmentPath = &splinePathRight;
187 currentSegmentPath = &splinePathRight;
188 } else if ((previousAngle > 360.0 || (previousAngle > 180.0 && previousGeometryPoint.x() > leftMarginLine))
188 } else if ((previousAngle > 360.0 || (previousAngle > 180.0 && previousGeometryPoint.x() > leftMarginLine))
189 && previousGeometryPoint.y() < horizontal) {
189 && previousGeometryPoint.y() < horizontal) {
190 currentSegmentPath = &splinePathLeft;
190 currentSegmentPath = &splinePathLeft;
191 } else if (previousAngle > 0.0 && previousAngle < 360.0) {
191 } else if (previousAngle > 0.0 && previousAngle < 360.0) {
192 currentSegmentPath = &splinePath;
192 currentSegmentPath = &splinePath;
193 } else {
193 } else {
194 currentSegmentPath = 0;
194 currentSegmentPath = 0;
195 }
195 }
196
196
197 if (currentSegmentPath) {
197 if (currentSegmentPath) {
198 if (previousSegmentPath != currentSegmentPath)
198 if (previousSegmentPath != currentSegmentPath)
199 currentSegmentPath->moveTo(previousGeometryPoint);
199 currentSegmentPath->moveTo(previousGeometryPoint);
200 if (!previousSegmentPath)
200 if (!previousSegmentPath)
201 fullPath.moveTo(previousGeometryPoint);
201 fullPath.moveTo(previousGeometryPoint);
202
202
203 currentSegmentPath->lineTo(centerPoint);
203 currentSegmentPath->lineTo(centerPoint);
204 fullPath.lineTo(centerPoint);
204 fullPath.lineTo(centerPoint);
205 }
205 }
206
206
207 previousSegmentPath = currentSegmentPath;
207 previousSegmentPath = currentSegmentPath;
208
208
209 if ((currentAngle < 0.0 || (currentAngle <= 180.0 && currentGeometryPoint.x() < rightMarginLine))
209 if ((currentAngle < 0.0 || (currentAngle <= 180.0 && currentGeometryPoint.x() < rightMarginLine))
210 && currentGeometryPoint.y() < horizontal) {
210 && currentGeometryPoint.y() < horizontal) {
211 currentSegmentPath = &splinePathRight;
211 currentSegmentPath = &splinePathRight;
212 } else if ((currentAngle > 360.0 || (currentAngle > 180.0 &&currentGeometryPoint.x() > leftMarginLine))
212 } else if ((currentAngle > 360.0 || (currentAngle > 180.0 &&currentGeometryPoint.x() > leftMarginLine))
213 && currentGeometryPoint.y() < horizontal) {
213 && currentGeometryPoint.y() < horizontal) {
214 currentSegmentPath = &splinePathLeft;
214 currentSegmentPath = &splinePathLeft;
215 } else if (currentAngle > 0.0 && currentAngle < 360.0) {
215 } else if (currentAngle > 0.0 && currentAngle < 360.0) {
216 currentSegmentPath = &splinePath;
216 currentSegmentPath = &splinePath;
217 } else {
217 } else {
218 currentSegmentPath = 0;
218 currentSegmentPath = 0;
219 }
219 }
220
220
221 if (currentSegmentPath) {
221 if (currentSegmentPath) {
222 if (previousSegmentPath != currentSegmentPath)
222 if (previousSegmentPath != currentSegmentPath)
223 currentSegmentPath->moveTo(centerPoint);
223 currentSegmentPath->moveTo(centerPoint);
224 if (!previousSegmentPath)
224 if (!previousSegmentPath)
225 fullPath.moveTo(centerPoint);
225 fullPath.moveTo(centerPoint);
226
226
227 currentSegmentPath->lineTo(currentGeometryPoint);
227 currentSegmentPath->lineTo(currentGeometryPoint);
228 fullPath.lineTo(currentGeometryPoint);
228 fullPath.lineTo(currentGeometryPoint);
229 }
229 }
230 } else {
230 } else {
231 QPointF cp1 = controlPoints[2 * (i - 1)];
231 QPointF cp1 = controlPoints[2 * (i - 1)];
232 QPointF cp2 = controlPoints[(2 * i) - 1];
232 QPointF cp2 = controlPoints[(2 * i) - 1];
233
233
234 if (previousAngle < 0.0 || currentAngle < 0.0
234 if (previousAngle < 0.0 || currentAngle < 0.0
235 || ((previousAngle <= 180.0 && currentAngle <= 180.0)
235 || ((previousAngle <= 180.0 && currentAngle <= 180.0)
236 && ((previousGeometryPoint.x() < rightMarginLine && previousGeometryPoint.y() < horizontal)
236 && ((previousGeometryPoint.x() < rightMarginLine && previousGeometryPoint.y() < horizontal)
237 || (currentGeometryPoint.x() < rightMarginLine && currentGeometryPoint.y() < horizontal)))) {
237 || (currentGeometryPoint.x() < rightMarginLine && currentGeometryPoint.y() < horizontal)))) {
238 currentSegmentPath = &splinePathRight;
238 currentSegmentPath = &splinePathRight;
239 } else if (previousAngle > 360.0 || currentAngle > 360.0
239 } else if (previousAngle > 360.0 || currentAngle > 360.0
240 || ((previousAngle > 180.0 && currentAngle > 180.0)
240 || ((previousAngle > 180.0 && currentAngle > 180.0)
241 && ((previousGeometryPoint.x() > leftMarginLine && previousGeometryPoint.y() < horizontal)
241 && ((previousGeometryPoint.x() > leftMarginLine && previousGeometryPoint.y() < horizontal)
242 || (currentGeometryPoint.x() > leftMarginLine && currentGeometryPoint.y() < horizontal)))) {
242 || (currentGeometryPoint.x() > leftMarginLine && currentGeometryPoint.y() < horizontal)))) {
243 currentSegmentPath = &splinePathLeft;
243 currentSegmentPath = &splinePathLeft;
244 } else {
244 } else {
245 currentSegmentPath = &splinePath;
245 currentSegmentPath = &splinePath;
246 }
246 }
247
247
248 if (currentSegmentPath != previousSegmentPath)
248 if (currentSegmentPath != previousSegmentPath)
249 currentSegmentPath->moveTo(previousGeometryPoint);
249 currentSegmentPath->moveTo(previousGeometryPoint);
250 if (!previousSegmentPath)
250 if (!previousSegmentPath)
251 fullPath.moveTo(previousGeometryPoint);
251 fullPath.moveTo(previousGeometryPoint);
252
252
253 fullPath.cubicTo(cp1, cp2, currentGeometryPoint);
253 fullPath.cubicTo(cp1, cp2, currentGeometryPoint);
254 currentSegmentPath->cubicTo(cp1, cp2, currentGeometryPoint);
254 currentSegmentPath->cubicTo(cp1, cp2, currentGeometryPoint);
255 }
255 }
256 } else {
256 } else {
257 currentSegmentPath = 0;
257 currentSegmentPath = 0;
258 }
258 }
259
259
260 previousPointWasOffGrid = pointOffGrid;
260 previousPointWasOffGrid = pointOffGrid;
261 if (!pointOffGrid && m_pointsVisible && currentSeriesPoint.y() >= minY)
261 if (!pointOffGrid && m_pointsVisible && currentSeriesPoint.y() >= minY)
262 m_visiblePoints.append(currentGeometryPoint);
262 m_visiblePoints.append(currentGeometryPoint);
263 previousSegmentPath = currentSegmentPath;
263 previousSegmentPath = currentSegmentPath;
264 previousGeometryPoint = currentGeometryPoint;
264 previousGeometryPoint = currentGeometryPoint;
265 }
265 }
266
266
267 m_pathPolarRight = splinePathRight;
267 m_pathPolarRight = splinePathRight;
268 m_pathPolarLeft = splinePathLeft;
268 m_pathPolarLeft = splinePathLeft;
269 // Note: This construction of m_fullpath is not perfect. The partial segments that are
269 // Note: This construction of m_fullpath is not perfect. The partial segments that are
270 // outside left/right clip regions at axis boundary still generate hover/click events,
270 // outside left/right clip regions at axis boundary still generate hover/click events,
271 // because shape doesn't get clipped. It doesn't seem possible to do sensibly.
271 // because shape doesn't get clipped. It doesn't seem possible to do sensibly.
272 } else { // not polar
272 } else { // not polar
273 splinePath.moveTo(points.at(0));
273 splinePath.moveTo(points.at(0));
274 for (int i = 0; i < points.size() - 1; i++) {
274 for (int i = 0; i < points.size() - 1; i++) {
275 const QPointF &point = points.at(i + 1);
275 const QPointF &point = points.at(i + 1);
276 splinePath.cubicTo(controlPoints[2 * i], controlPoints[2 * i + 1], point);
276 splinePath.cubicTo(controlPoints[2 * i], controlPoints[2 * i + 1], point);
277 }
277 }
278 fullPath = splinePath;
278 fullPath = splinePath;
279 }
279 }
280
280
281 QPainterPathStroker stroker;
281 QPainterPathStroker stroker;
282 // The full path is comprised of three separate paths.
282 // The full path is comprised of three separate paths.
283 // This is why we are prepared for the "worst case" scenario, i.e. use always MiterJoin and
283 // This is why we are prepared for the "worst case" scenario, i.e. use always MiterJoin and
284 // multiply line width with square root of two when defining shape and bounding rectangle.
284 // multiply line width with square root of two when defining shape and bounding rectangle.
285 stroker.setWidth(margin);
285 stroker.setWidth(margin);
286 stroker.setJoinStyle(Qt::MiterJoin);
286 stroker.setJoinStyle(Qt::MiterJoin);
287 stroker.setCapStyle(Qt::SquareCap);
287 stroker.setCapStyle(Qt::SquareCap);
288 stroker.setMiterLimit(m_linePen.miterLimit());
288 stroker.setMiterLimit(m_linePen.miterLimit());
289
289
290 // Only zoom in if the bounding rects of the path fit inside int limits. QWidget::update() uses
290 // Only zoom in if the bounding rects of the path fit inside int limits. QWidget::update() uses
291 // a region that has to be compatible with QRect.
291 // a region that has to be compatible with QRect.
292 QPainterPath checkShapePath = stroker.createStroke(fullPath);
292 QPainterPath checkShapePath = stroker.createStroke(fullPath);
293 if (checkShapePath.boundingRect().height() <= INT_MAX
293 if (checkShapePath.boundingRect().height() <= INT_MAX
294 && checkShapePath.boundingRect().width() <= INT_MAX
294 && checkShapePath.boundingRect().width() <= INT_MAX
295 && splinePath.boundingRect().height() <= INT_MAX
295 && splinePath.boundingRect().height() <= INT_MAX
296 && splinePath.boundingRect().width() <= INT_MAX) {
296 && splinePath.boundingRect().width() <= INT_MAX) {
297 m_path = splinePath;
297 m_path = splinePath;
298
298
299 prepareGeometryChange();
299 prepareGeometryChange();
300
300
301 m_fullPath = checkShapePath;
301 m_fullPath = checkShapePath;
302 m_rect = m_fullPath.boundingRect();
302 m_rect = m_fullPath.boundingRect();
303 }
303 }
304 }
304 }
305
305
306 /*!
306 /*!
307 Calculates control points which are needed by QPainterPath.cubicTo function to draw the cubic Bezier cureve between two points.
307 Calculates control points which are needed by QPainterPath.cubicTo function to draw the cubic Bezier cureve between two points.
308 */
308 */
309 QVector<QPointF> SplineChartItem::calculateControlPoints(const QVector<QPointF> &points)
309 QVector<QPointF> SplineChartItem::calculateControlPoints(const QVector<QPointF> &points)
310 {
310 {
311 QVector<QPointF> controlPoints;
311 QVector<QPointF> controlPoints;
312 controlPoints.resize(points.count() * 2 - 2);
312 controlPoints.resize(points.count() * 2 - 2);
313
313
314 int n = points.count() - 1;
314 int n = points.count() - 1;
315
315
316 if (n == 1) {
316 if (n == 1) {
317 //for n==1
317 //for n==1
318 controlPoints[0].setX((2 * points[0].x() + points[1].x()) / 3);
318 controlPoints[0].setX((2 * points[0].x() + points[1].x()) / 3);
319 controlPoints[0].setY((2 * points[0].y() + points[1].y()) / 3);
319 controlPoints[0].setY((2 * points[0].y() + points[1].y()) / 3);
320 controlPoints[1].setX(2 * controlPoints[0].x() - points[0].x());
320 controlPoints[1].setX(2 * controlPoints[0].x() - points[0].x());
321 controlPoints[1].setY(2 * controlPoints[0].y() - points[0].y());
321 controlPoints[1].setY(2 * controlPoints[0].y() - points[0].y());
322 return controlPoints;
322 return controlPoints;
323 }
323 }
324
324
325 // Calculate first Bezier control points
325 // Calculate first Bezier control points
326 // Set of equations for P0 to Pn points.
326 // Set of equations for P0 to Pn points.
327 //
327 //
328 // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 |
328 // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 |
329 // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 |
329 // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 |
330 // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 |
330 // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 |
331 // | . . . . . . . . . . . . | | ... | | ... |
331 // | . . . . . . . . . . . . | | ... | | ... |
332 // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi |
332 // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi |
333 // | . . . . . . . . . . . . | | ... | | ... |
333 // | . . . . . . . . . . . . | | ... | | ... |
334 // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) |
334 // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) |
335 // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn |
335 // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn |
336 //
336 //
337 QVector<qreal> vector;
337 QVector<qreal> vector;
338 vector.resize(n);
338 vector.resize(n);
339
339
340 vector[0] = points[0].x() + 2 * points[1].x();
340 vector[0] = points[0].x() + 2 * points[1].x();
341
341
342
342
343 for (int i = 1; i < n - 1; ++i)
343 for (int i = 1; i < n - 1; ++i)
344 vector[i] = 4 * points[i].x() + 2 * points[i + 1].x();
344 vector[i] = 4 * points[i].x() + 2 * points[i + 1].x();
345
345
346 vector[n - 1] = (8 * points[n - 1].x() + points[n].x()) / 2.0;
346 vector[n - 1] = (8 * points[n - 1].x() + points[n].x()) / 2.0;
347
347
348 QVector<qreal> xControl = firstControlPoints(vector);
348 QVector<qreal> xControl = firstControlPoints(vector);
349
349
350 vector[0] = points[0].y() + 2 * points[1].y();
350 vector[0] = points[0].y() + 2 * points[1].y();
351
351
352 for (int i = 1; i < n - 1; ++i)
352 for (int i = 1; i < n - 1; ++i)
353 vector[i] = 4 * points[i].y() + 2 * points[i + 1].y();
353 vector[i] = 4 * points[i].y() + 2 * points[i + 1].y();
354
354
355 vector[n - 1] = (8 * points[n - 1].y() + points[n].y()) / 2.0;
355 vector[n - 1] = (8 * points[n - 1].y() + points[n].y()) / 2.0;
356
356
357 QVector<qreal> yControl = firstControlPoints(vector);
357 QVector<qreal> yControl = firstControlPoints(vector);
358
358
359 for (int i = 0, j = 0; i < n; ++i, ++j) {
359 for (int i = 0, j = 0; i < n; ++i, ++j) {
360
360
361 controlPoints[j].setX(xControl[i]);
361 controlPoints[j].setX(xControl[i]);
362 controlPoints[j].setY(yControl[i]);
362 controlPoints[j].setY(yControl[i]);
363
363
364 j++;
364 j++;
365
365
366 if (i < n - 1) {
366 if (i < n - 1) {
367 controlPoints[j].setX(2 * points[i + 1].x() - xControl[i + 1]);
367 controlPoints[j].setX(2 * points[i + 1].x() - xControl[i + 1]);
368 controlPoints[j].setY(2 * points[i + 1].y() - yControl[i + 1]);
368 controlPoints[j].setY(2 * points[i + 1].y() - yControl[i + 1]);
369 } else {
369 } else {
370 controlPoints[j].setX((points[n].x() + xControl[n - 1]) / 2);
370 controlPoints[j].setX((points[n].x() + xControl[n - 1]) / 2);
371 controlPoints[j].setY((points[n].y() + yControl[n - 1]) / 2);
371 controlPoints[j].setY((points[n].y() + yControl[n - 1]) / 2);
372 }
372 }
373 }
373 }
374 return controlPoints;
374 return controlPoints;
375 }
375 }
376
376
377 QVector<qreal> SplineChartItem::firstControlPoints(const QVector<qreal>& vector)
377 QVector<qreal> SplineChartItem::firstControlPoints(const QVector<qreal>& vector)
378 {
378 {
379 QVector<qreal> result;
379 QVector<qreal> result;
380
380
381 int count = vector.count();
381 int count = vector.count();
382 result.resize(count);
382 result.resize(count);
383 result[0] = vector[0] / 2.0;
383 result[0] = vector[0] / 2.0;
384
384
385 QVector<qreal> temp;
385 QVector<qreal> temp;
386 temp.resize(count);
386 temp.resize(count);
387 temp[0] = 0;
387 temp[0] = 0;
388
388
389 qreal b = 2.0;
389 qreal b = 2.0;
390
390
391 for (int i = 1; i < count; i++) {
391 for (int i = 1; i < count; i++) {
392 temp[i] = 1 / b;
392 temp[i] = 1 / b;
393 b = (i < count - 1 ? 4.0 : 3.5) - temp[i];
393 b = (i < count - 1 ? 4.0 : 3.5) - temp[i];
394 result[i] = (vector[i] - result[i - 1]) / b;
394 result[i] = (vector[i] - result[i - 1]) / b;
395 }
395 }
396
396
397 for (int i = 1; i < count; i++)
397 for (int i = 1; i < count; i++)
398 result[count - i - 1] -= temp[count - i] * result[count - i];
398 result[count - i - 1] -= temp[count - i] * result[count - i];
399
399
400 return result;
400 return result;
401 }
401 }
402
402
403 //handlers
403 //handlers
404
404
405 void SplineChartItem::handleUpdated()
405 void SplineChartItem::handleUpdated()
406 {
406 {
407 setVisible(m_series->isVisible());
407 setVisible(m_series->isVisible());
408 setOpacity(m_series->opacity());
408 setOpacity(m_series->opacity());
409 m_pointsVisible = m_series->pointsVisible();
409 m_pointsVisible = m_series->pointsVisible();
410 m_linePen = m_series->pen();
410 m_linePen = m_series->pen();
411 m_pointPen = m_series->pen();
411 m_pointPen = m_series->pen();
412 m_pointPen.setWidthF(2 * m_pointPen.width());
412 m_pointPen.setWidthF(2 * m_pointPen.width());
413 m_pointLabelsFormat = m_series->pointLabelsFormat();
413 m_pointLabelsFormat = m_series->pointLabelsFormat();
414 m_pointLabelsVisible = m_series->pointLabelsVisible();
414 m_pointLabelsVisible = m_series->pointLabelsVisible();
415 m_pointLabelsFont = m_series->pointLabelsFont();
415 m_pointLabelsFont = m_series->pointLabelsFont();
416 m_pointLabelsColor = m_series->pointLabelsColor();
416 m_pointLabelsColor = m_series->pointLabelsColor();
417 update();
417 update();
418 }
418 }
419
419
420 //painter
420 //painter
421
421
422 void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
422 void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
423 {
423 {
424 Q_UNUSED(widget)
424 Q_UNUSED(widget)
425 Q_UNUSED(option)
425 Q_UNUSED(option)
426
426
427 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
427 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
428
428
429 painter->save();
429 painter->save();
430 painter->setPen(m_linePen);
430 painter->setPen(m_linePen);
431 painter->setBrush(Qt::NoBrush);
431 painter->setBrush(Qt::NoBrush);
432
432
433 if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
433 if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
434 qreal halfWidth = domain()->size().width() / 2.0;
434 qreal halfWidth = domain()->size().width() / 2.0;
435 QRectF clipRectLeft = QRectF(0, 0, halfWidth, domain()->size().height());
435 QRectF clipRectLeft = QRectF(0, 0, halfWidth, domain()->size().height());
436 QRectF clipRectRight = QRectF(halfWidth, 0, halfWidth, domain()->size().height());
436 QRectF clipRectRight = QRectF(halfWidth, 0, halfWidth, domain()->size().height());
437 QRegion fullPolarClipRegion(clipRect.toRect(), QRegion::Ellipse);
437 QRegion fullPolarClipRegion(clipRect.toRect(), QRegion::Ellipse);
438 QRegion clipRegionLeft(fullPolarClipRegion.intersected(clipRectLeft.toRect()));
438 QRegion clipRegionLeft(fullPolarClipRegion.intersected(clipRectLeft.toRect()));
439 QRegion clipRegionRight(fullPolarClipRegion.intersected(clipRectRight.toRect()));
439 QRegion clipRegionRight(fullPolarClipRegion.intersected(clipRectRight.toRect()));
440 painter->setClipRegion(clipRegionLeft);
440 painter->setClipRegion(clipRegionLeft);
441 painter->drawPath(m_pathPolarLeft);
441 painter->drawPath(m_pathPolarLeft);
442 painter->setClipRegion(clipRegionRight);
442 painter->setClipRegion(clipRegionRight);
443 painter->drawPath(m_pathPolarRight);
443 painter->drawPath(m_pathPolarRight);
444 painter->setClipRegion(fullPolarClipRegion);
444 painter->setClipRegion(fullPolarClipRegion);
445 } else {
445 } else {
446 painter->setClipRect(clipRect);
446 painter->setClipRect(clipRect);
447 }
447 }
448
448
449 painter->drawPath(m_path);
449 painter->drawPath(m_path);
450
450
451 if (m_pointsVisible) {
451 if (m_pointsVisible) {
452 painter->setPen(m_pointPen);
452 painter->setPen(m_pointPen);
453 if (m_series->chart()->chartType() == QChart::ChartTypePolar)
453 if (m_series->chart()->chartType() == QChart::ChartTypePolar)
454 painter->drawPoints(m_visiblePoints);
454 painter->drawPoints(m_visiblePoints);
455 else
455 else
456 painter->drawPoints(geometryPoints());
456 painter->drawPoints(geometryPoints());
457 }
457 }
458
458
459 if (m_pointLabelsVisible)
459 if (m_pointLabelsVisible)
460 m_series->d_func()->drawSeriesPointLabels(painter, m_points, m_linePen.width() / 2);
460 m_series->d_func()->drawSeriesPointLabels(painter, m_points, m_linePen.width() / 2);
461
461
462 painter->restore();
462 painter->restore();
463 }
463 }
464
464
465 void SplineChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
465 void SplineChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
466 {
466 {
467 emit XYChart::pressed(domain()->calculateDomainPoint(event->pos()));
467 emit XYChart::pressed(domain()->calculateDomainPoint(event->pos()));
468 m_lastMousePos = event->pos();
468 m_lastMousePos = event->pos();
469 m_mousePressed = true;
469 m_mousePressed = true;
470 QGraphicsItem::mousePressEvent(event);
470 QGraphicsItem::mousePressEvent(event);
471 }
471 }
472
472
473 void SplineChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
473 void SplineChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
474 {
474 {
475 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), true);
475 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), true);
476 QGraphicsItem::hoverEnterEvent(event);
476 QGraphicsItem::hoverEnterEvent(event);
477 }
477 }
478
478
479 void SplineChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
479 void SplineChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
480 {
480 {
481 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), false);
481 emit XYChart::hovered(domain()->calculateDomainPoint(event->pos()), false);
482 QGraphicsItem::hoverLeaveEvent(event);
482 QGraphicsItem::hoverLeaveEvent(event);
483 }
483 }
484
484
485 void SplineChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
485 void SplineChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
486 {
486 {
487 emit XYChart::released(domain()->calculateDomainPoint(event->pos()));
487 emit XYChart::released(domain()->calculateDomainPoint(m_lastMousePos));
488 if (m_lastMousePos == event->pos() && m_mousePressed)
488 if (m_mousePressed)
489 emit XYChart::clicked(domain()->calculateDomainPoint(event->pos()));
489 emit XYChart::clicked(domain()->calculateDomainPoint(m_lastMousePos));
490 m_mousePressed = false;
490 m_mousePressed = false;
491 QGraphicsItem::mouseReleaseEvent(event);
491 QGraphicsItem::mouseReleaseEvent(event);
492 }
492 }
493
493
494 void SplineChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
494 void SplineChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
495 {
495 {
496 emit XYChart::doubleClicked(domain()->calculateDomainPoint(event->pos()));
496 emit XYChart::doubleClicked(domain()->calculateDomainPoint(m_lastMousePos));
497 QGraphicsItem::mouseDoubleClickEvent(event);
497 QGraphicsItem::mouseDoubleClickEvent(event);
498 }
498 }
499
499
500 #include "moc_splinechartitem_p.cpp"
500 #include "moc_splinechartitem_p.cpp"
501
501
502 QT_CHARTS_END_NAMESPACE
502 QT_CHARTS_END_NAMESPACE
@@ -1,848 +1,861
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <QtCharts/QXYSeries>
19 #include <QtCharts/QXYSeries>
20 #include <private/qxyseries_p.h>
20 #include <private/qxyseries_p.h>
21 #include <private/abstractdomain_p.h>
21 #include <private/abstractdomain_p.h>
22 #include <QtCharts/QValueAxis>
22 #include <QtCharts/QValueAxis>
23 #include <private/xychart_p.h>
23 #include <private/xychart_p.h>
24 #include <QtCharts/QXYLegendMarker>
24 #include <QtCharts/QXYLegendMarker>
25 #include <private/charthelpers_p.h>
25 #include <private/charthelpers_p.h>
26 #include <private/qchart_p.h>
26 #include <private/qchart_p.h>
27 #include <QtGui/QPainter>
27 #include <QtGui/QPainter>
28
28
29 QT_CHARTS_BEGIN_NAMESPACE
29 QT_CHARTS_BEGIN_NAMESPACE
30
30
31 /*!
31 /*!
32 \class QXYSeries
32 \class QXYSeries
33 \inmodule Qt Charts
33 \inmodule Qt Charts
34 \brief The QXYSeries class is a base class for line, spline and scatter series.
34 \brief The QXYSeries class is a base class for line, spline and scatter series.
35 */
35 */
36 /*!
36 /*!
37 \qmltype XYSeries
37 \qmltype XYSeries
38 \instantiates QXYSeries
38 \instantiates QXYSeries
39 \inqmlmodule QtCharts
39 \inqmlmodule QtCharts
40
40
41 \inherits AbstractSeries
41 \inherits AbstractSeries
42
42
43 \brief The XYSeries type is a base type for line, spline and scatter series.
43 \brief The XYSeries type is a base type for line, spline and scatter series.
44
44
45 The XYSeries class is a base class for line, spline and scatter series.
45 The XYSeries class is a base class for line, spline and scatter series.
46 The class cannot be instantiated directly.
46 The class cannot be instantiated directly.
47 */
47 */
48
48
49 /*!
49 /*!
50 \qmlproperty AbstractAxis XYSeries::axisX
50 \qmlproperty AbstractAxis XYSeries::axisX
51 The x axis used for the series. If you leave both axisX and axisXTop undefined, a ValueAxis is created for
51 The x axis used for the series. If you leave both axisX and axisXTop undefined, a ValueAxis is created for
52 the series.
52 the series.
53 \sa axisXTop
53 \sa axisXTop
54 */
54 */
55
55
56 /*!
56 /*!
57 \qmlproperty AbstractAxis XYSeries::axisY
57 \qmlproperty AbstractAxis XYSeries::axisY
58 The y axis used for the series. If you leave both axisY and axisYRight undefined, a ValueAxis is created for
58 The y axis used for the series. If you leave both axisY and axisYRight undefined, a ValueAxis is created for
59 the series.
59 the series.
60 \sa axisYRight
60 \sa axisYRight
61 */
61 */
62
62
63 /*!
63 /*!
64 \qmlproperty AbstractAxis XYSeries::axisXTop
64 \qmlproperty AbstractAxis XYSeries::axisXTop
65 The x axis used for the series, drawn on top of the chart view. Note that you can only provide either axisX or
65 The x axis used for the series, drawn on top of the chart view. Note that you can only provide either axisX or
66 axisXTop, but not both.
66 axisXTop, but not both.
67 \sa axisX
67 \sa axisX
68 */
68 */
69
69
70 /*!
70 /*!
71 \qmlproperty AbstractAxis XYSeries::axisYRight
71 \qmlproperty AbstractAxis XYSeries::axisYRight
72 The y axis used for the series, drawn to the right on the chart view. Note that you can only provide either axisY
72 The y axis used for the series, drawn to the right on the chart view. Note that you can only provide either axisY
73 or axisYRight, but not both.
73 or axisYRight, but not both.
74 \sa axisY
74 \sa axisY
75 */
75 */
76
76
77 /*!
77 /*!
78 \qmlproperty AbstractAxis XYSeries::axisAngular
78 \qmlproperty AbstractAxis XYSeries::axisAngular
79 The angular axis used for the series, drawn around the polar chart view.
79 The angular axis used for the series, drawn around the polar chart view.
80 \sa axisX
80 \sa axisX
81 */
81 */
82
82
83 /*!
83 /*!
84 \qmlproperty AbstractAxis XYSeries::axisRadial
84 \qmlproperty AbstractAxis XYSeries::axisRadial
85 The radial axis used for the series, drawn inside the polar chart view.
85 The radial axis used for the series, drawn inside the polar chart view.
86 \sa axisY
86 \sa axisY
87 */
87 */
88
88
89 /*!
89 /*!
90 \property QXYSeries::pointsVisible
90 \property QXYSeries::pointsVisible
91 Controls if the data points are visible and should be drawn.
91 Controls if the data points are visible and should be drawn.
92 */
92 */
93 /*!
93 /*!
94 \qmlproperty bool XYSeries::pointsVisible
94 \qmlproperty bool XYSeries::pointsVisible
95 Controls if the data points are visible and should be drawn.
95 Controls if the data points are visible and should be drawn.
96 */
96 */
97
97
98 /*!
98 /*!
99 \fn QPen QXYSeries::pen() const
99 \fn QPen QXYSeries::pen() const
100 \brief Returns pen used to draw points for series.
100 \brief Returns pen used to draw points for series.
101 \sa setPen()
101 \sa setPen()
102 */
102 */
103
103
104 /*!
104 /*!
105 \fn QBrush QXYSeries::brush() const
105 \fn QBrush QXYSeries::brush() const
106 \brief Returns brush used to draw points for series.
106 \brief Returns brush used to draw points for series.
107 \sa setBrush()
107 \sa setBrush()
108 */
108 */
109
109
110 /*!
110 /*!
111 \property QXYSeries::color
111 \property QXYSeries::color
112 The color of the series. This is line (pen) color in case of QLineSeries or QSplineSeries and
112 The color of the series. This is line (pen) color in case of QLineSeries or QSplineSeries and
113 fill (brush) color in case of QScatterSeries or QAreaSeries.
113 fill (brush) color in case of QScatterSeries or QAreaSeries.
114 \sa QXYSeries::pen(), QXYSeries::brush()
114 \sa QXYSeries::pen(), QXYSeries::brush()
115 */
115 */
116 /*!
116 /*!
117 \qmlproperty color XYSeries::color
117 \qmlproperty color XYSeries::color
118 The color of the series. This is line (pen) color in case of LineSeries or SplineSeries and
118 The color of the series. This is line (pen) color in case of LineSeries or SplineSeries and
119 fill (brush) color in case of ScatterSeries or AreaSeries.
119 fill (brush) color in case of ScatterSeries or AreaSeries.
120 */
120 */
121
121
122 /*!
122 /*!
123 \property QXYSeries::pointLabelsFormat
123 \property QXYSeries::pointLabelsFormat
124 The \a format used for showing labels with series points.
124 The \a format used for showing labels with series points.
125
125
126 QXYSeries supports the following format tags:
126 QXYSeries supports the following format tags:
127 \table
127 \table
128 \row
128 \row
129 \li @xPoint \li The x value of the data point
129 \li @xPoint \li The x value of the data point
130 \row
130 \row
131 \li @yPoint \li The y value of the data point
131 \li @yPoint \li The y value of the data point
132 \endtable
132 \endtable
133
133
134 For example, the following usage of the format tags would produce labels that have the data
134 For example, the following usage of the format tags would produce labels that have the data
135 point (x, y) shown inside brackets separated by a comma:
135 point (x, y) shown inside brackets separated by a comma:
136 \code
136 \code
137 series->setPointLabelsFormat("(@xPoint, @yPoint)");
137 series->setPointLabelsFormat("(@xPoint, @yPoint)");
138 \endcode
138 \endcode
139
139
140 By default, the labels format is set to '@xPoint, @yPoint'. The labels are shown on the plot
140 By default, the labels format is set to '@xPoint, @yPoint'. The labels are shown on the plot
141 area, labels on the edge of the plot area are cut. If the points are close to each other the
141 area, labels on the edge of the plot area are cut. If the points are close to each other the
142 labels may overlap.
142 labels may overlap.
143
143
144 \sa QXYSeries::pointLabelsVisible, QXYSeries::pointLabelsFont, QXYSeries::pointLabelsColor
144 \sa QXYSeries::pointLabelsVisible, QXYSeries::pointLabelsFont, QXYSeries::pointLabelsColor
145 */
145 */
146 /*!
146 /*!
147 \qmlproperty string XYSeries::pointLabelsFormat
147 \qmlproperty string XYSeries::pointLabelsFormat
148 The \a format used for showing labels with series points.
148 The \a format used for showing labels with series points.
149
149
150 \sa QXYSeries::pointLabelsFormat, pointLabelsVisible, pointLabelsFont, pointLabelsColor
150 \sa QXYSeries::pointLabelsFormat, pointLabelsVisible, pointLabelsFont, pointLabelsColor
151 */
151 */
152 /*!
152 /*!
153 \fn void QXYSeries::pointLabelsFormatChanged(const QString &format)
153 \fn void QXYSeries::pointLabelsFormatChanged(const QString &format)
154 Signal is emitted when the \a format of data point labels is changed.
154 Signal is emitted when the \a format of data point labels is changed.
155 */
155 */
156 /*!
156 /*!
157 \qmlsignal XYSeries::onPointLabelsFormatChanged(string format)
157 \qmlsignal XYSeries::onPointLabelsFormatChanged(string format)
158 Signal is emitted when the \a format of data point labels is changed.
158 Signal is emitted when the \a format of data point labels is changed.
159 */
159 */
160
160
161 /*!
161 /*!
162 \property QXYSeries::pointLabelsVisible
162 \property QXYSeries::pointLabelsVisible
163 Defines the visibility for data point labels. False by default.
163 Defines the visibility for data point labels. False by default.
164
164
165 \sa QXYSeries::pointLabelsFormat
165 \sa QXYSeries::pointLabelsFormat
166 */
166 */
167 /*!
167 /*!
168 \qmlproperty bool XYSeries::pointLabelsVisible
168 \qmlproperty bool XYSeries::pointLabelsVisible
169 Defines the visibility for data point labels.
169 Defines the visibility for data point labels.
170
170
171 \sa pointLabelsFormat
171 \sa pointLabelsFormat
172 */
172 */
173 /*!
173 /*!
174 \fn void QXYSeries::pointLabelsVisibilityChanged(bool visible)
174 \fn void QXYSeries::pointLabelsVisibilityChanged(bool visible)
175 The visibility of the data point labels is changed to \a visible.
175 The visibility of the data point labels is changed to \a visible.
176 */
176 */
177 /*!
177 /*!
178 \qmlsignal XYSeries::onPointLabelsVisibilityChanged(bool visible)
178 \qmlsignal XYSeries::onPointLabelsVisibilityChanged(bool visible)
179 The visibility of the data point labels is changed to \a visible.
179 The visibility of the data point labels is changed to \a visible.
180 */
180 */
181
181
182 /*!
182 /*!
183 \property QXYSeries::pointLabelsFont
183 \property QXYSeries::pointLabelsFont
184 Defines the font used for data point labels.
184 Defines the font used for data point labels.
185
185
186 \sa QXYSeries::pointLabelsFormat
186 \sa QXYSeries::pointLabelsFormat
187 */
187 */
188 /*!
188 /*!
189 \qmlproperty font XYSeries::pointLabelsFont
189 \qmlproperty font XYSeries::pointLabelsFont
190 Defines the font used for data point labels.
190 Defines the font used for data point labels.
191
191
192 \sa pointLabelsFormat
192 \sa pointLabelsFormat
193 */
193 */
194 /*!
194 /*!
195 \fn void QXYSeries::pointLabelsFontChanged(const QFont &font);
195 \fn void QXYSeries::pointLabelsFontChanged(const QFont &font);
196 The font used for data point labels is changed to \a font.
196 The font used for data point labels is changed to \a font.
197 */
197 */
198 /*!
198 /*!
199 \qmlsignal XYSeries::onPointLabelsFontChanged(Font font)
199 \qmlsignal XYSeries::onPointLabelsFontChanged(Font font)
200 The font used for data point labels is changed to \a font.
200 The font used for data point labels is changed to \a font.
201 */
201 */
202
202
203 /*!
203 /*!
204 \property QXYSeries::pointLabelsColor
204 \property QXYSeries::pointLabelsColor
205 Defines the color used for data point labels. By default, the color is the color of the brush
205 Defines the color used for data point labels. By default, the color is the color of the brush
206 defined in theme for labels.
206 defined in theme for labels.
207
207
208 \sa QXYSeries::pointLabelsFormat
208 \sa QXYSeries::pointLabelsFormat
209 */
209 */
210 /*!
210 /*!
211 \qmlproperty font XYSeries::pointLabelsColor
211 \qmlproperty font XYSeries::pointLabelsColor
212 Defines the color used for data point labels. By default, the color is the color of the brush
212 Defines the color used for data point labels. By default, the color is the color of the brush
213 defined in theme for labels.
213 defined in theme for labels.
214
214
215 \sa pointLabelsFormat
215 \sa pointLabelsFormat
216 */
216 */
217 /*!
217 /*!
218 \fn void QXYSeries::pointLabelsColorChanged(const QColor &color);
218 \fn void QXYSeries::pointLabelsColorChanged(const QColor &color);
219 The color used for data point labels is changed to \a color.
219 The color used for data point labels is changed to \a color.
220 */
220 */
221 /*!
221 /*!
222 \qmlsignal XYSeries::onPointLabelsColorChanged(Color color)
222 \qmlsignal XYSeries::onPointLabelsColorChanged(Color color)
223 The color used for data point labels is changed to \a color.
223 The color used for data point labels is changed to \a color.
224 */
224 */
225
225
226 /*!
226 /*!
227 \fn void QXYSeries::clicked(const QPointF& point)
227 \fn void QXYSeries::clicked(const QPointF& point)
228 \brief Signal is emitted when user clicks the \a point on chart.
228 \brief Signal is emitted when user clicks the \a point on chart. The \a point is the point
229 where the press was triggered.
230 \sa pressed, released, doubleClicked
229 */
231 */
230 /*!
232 /*!
231 \qmlsignal XYSeries::onClicked(QPointF point)
233 \qmlsignal XYSeries::onClicked(QPointF point)
232 Signal is emitted when user clicks the \a point on chart. For example:
234 Signal is emitted when user clicks the \a point on chart. The \a point is the point where the
235 press was triggered. For example:
233 \code
236 \code
234 LineSeries {
237 LineSeries {
235 XYPoint { x: 0; y: 0 }
238 XYPoint { x: 0; y: 0 }
236 XYPoint { x: 1.1; y: 2.1 }
239 XYPoint { x: 1.1; y: 2.1 }
237 onClicked: console.log("onClicked: " + point.x + ", " + point.y);
240 onClicked: console.log("onClicked: " + point.x + ", " + point.y);
238 }
241 }
239 \endcode
242 \endcode
243 \sa onPressed, onReleased, onDoubleClicked
240 */
244 */
241
245
242 /*!
246 /*!
243 \fn void QXYSeries::hovered(const QPointF &point, bool state)
247 \fn void QXYSeries::hovered(const QPointF &point, bool state)
244 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
248 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
245 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
249 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
246 the series.
250 the series.
247 */
251 */
248 /*!
252 /*!
249 \qmlsignal XYSeries::onHovered(point point, bool state)
253 \qmlsignal XYSeries::onHovered(point point, bool state)
250 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
254 This signal is emitted when user has hovered over or away from the series. \a point shows the origin (coordinate)
251 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
255 of the hover event. \a state is true when user has hovered over the series and false when hover has moved away from
252 the series.
256 the series.
253 */
257 */
254
258
255 /*!
259 /*!
256 \fn void QXYSeries::pressed(const QPointF& point)
260 \fn void QXYSeries::pressed(const QPointF& point)
257 \brief Signal is emitted when user presses the \a point on chart.
261 \brief Signal is emitted when user presses the \a point on chart.
262 \sa clicked, released, doubleClicked
258 */
263 */
259 /*!
264 /*!
260 \qmlsignal XYSeries::onPressed(QPointF point)
265 \qmlsignal XYSeries::onPressed(QPointF point)
261 Signal is emitted when user presses the \a point on chart. For example:
266 Signal is emitted when user presses the \a point on chart. For example:
262 \code
267 \code
263 LineSeries {
268 LineSeries {
264 XYPoint { x: 0; y: 0 }
269 XYPoint { x: 0; y: 0 }
265 XYPoint { x: 1.1; y: 2.1 }
270 XYPoint { x: 1.1; y: 2.1 }
266 onPressed: console.log("onPressed: " + point.x + ", " + point.y);
271 onPressed: console.log("onPressed: " + point.x + ", " + point.y);
267 }
272 }
268 \endcode
273 \endcode
274 \sa onClicked, onReleased, onDoubleClicked
269 */
275 */
270
276
271 /*!
277 /*!
272 \fn void QXYSeries::released(const QPointF& point)
278 \fn void QXYSeries::released(const QPointF& point)
273 \brief Signal is emitted when user releases the \a point on chart.
279 \brief Signal is emitted when user releases a press that was triggered on a \a point on chart.
280 \sa pressed, clicked, doubleClicked
274 */
281 */
275 /*!
282 /*!
276 \qmlsignal XYSeries::onReleased(QPointF point)
283 \qmlsignal XYSeries::onReleased(QPointF point)
277 Signal is emitted when user releases the \a point on chart. For example:
284 Signal is emitted when user releases a press that was triggered on a \a point on chart.
285 For example:
278 \code
286 \code
279 LineSeries {
287 LineSeries {
280 XYPoint { x: 0; y: 0 }
288 XYPoint { x: 0; y: 0 }
281 XYPoint { x: 1.1; y: 2.1 }
289 XYPoint { x: 1.1; y: 2.1 }
282 onReleased: console.log("onReleased: " + point.x + ", " + point.y);
290 onReleased: console.log("onReleased: " + point.x + ", " + point.y);
283 }
291 }
284 \endcode
292 \endcode
293 \sa onPressed, onClicked, onDoubleClicked
285 */
294 */
286
295
287 /*!
296 /*!
288 \fn void QXYSeries::doubleClicked(const QPointF& point)
297 \fn void QXYSeries::doubleClicked(const QPointF& point)
289 \brief Signal is emitted when user doubleclicks the \a point on chart.
298 \brief Signal is emitted when user doubleclicks the \a point on chart. The \a point is the
299 point where the first press was triggered.
300 \sa pressed, released, clicked
290 */
301 */
291 /*!
302 /*!
292 \qmlsignal XYSeries::onDoubleClicked(QPointF point)
303 \qmlsignal XYSeries::onDoubleClicked(QPointF point)
293 Signal is emitted when user doubleclicks the \a point on chart. For example:
304 Signal is emitted when user doubleclicks the \a point on chart. The \a point is the point where
305 the first press was triggered. For example:
294 \code
306 \code
295 LineSeries {
307 LineSeries {
296 XYPoint { x: 0; y: 0 }
308 XYPoint { x: 0; y: 0 }
297 XYPoint { x: 1.1; y: 2.1 }
309 XYPoint { x: 1.1; y: 2.1 }
298 onDoubleClicked: console.log("onDoubleClicked: " + point.x + ", " + point.y);
310 onDoubleClicked: console.log("onDoubleClicked: " + point.x + ", " + point.y);
299 }
311 }
300 \endcode
312 \endcode
313 \sa onPressed, onReleased, onClicked
301 */
314 */
302
315
303 /*!
316 /*!
304 \fn void QXYSeries::pointReplaced(int index)
317 \fn void QXYSeries::pointReplaced(int index)
305 Signal is emitted when a point has been replaced at \a index.
318 Signal is emitted when a point has been replaced at \a index.
306 \sa replace()
319 \sa replace()
307 */
320 */
308 /*!
321 /*!
309 \qmlsignal XYSeries::onPointReplaced(int index)
322 \qmlsignal XYSeries::onPointReplaced(int index)
310 Signal is emitted when a point has been replaced at \a index.
323 Signal is emitted when a point has been replaced at \a index.
311 */
324 */
312
325
313 /*!
326 /*!
314 \fn void QXYSeries::pointsReplaced()
327 \fn void QXYSeries::pointsReplaced()
315 Signal is emitted when all points have been replaced with other points.
328 Signal is emitted when all points have been replaced with other points.
316 \sa replace()
329 \sa replace()
317 */
330 */
318 /*!
331 /*!
319 \qmlsignal XYSeries::onPointsReplaced()
332 \qmlsignal XYSeries::onPointsReplaced()
320 */
333 */
321
334
322 /*!
335 /*!
323 \fn void QXYSeries::pointAdded(int index)
336 \fn void QXYSeries::pointAdded(int index)
324 Signal is emitted when a point has been added at \a index.
337 Signal is emitted when a point has been added at \a index.
325 \sa append(), insert()
338 \sa append(), insert()
326 */
339 */
327 /*!
340 /*!
328 \qmlsignal XYSeries::onPointAdded(int index)
341 \qmlsignal XYSeries::onPointAdded(int index)
329 Signal is emitted when a point has been added at \a index.
342 Signal is emitted when a point has been added at \a index.
330 */
343 */
331
344
332 /*!
345 /*!
333 \fn void QXYSeries::pointRemoved(int index)
346 \fn void QXYSeries::pointRemoved(int index)
334 Signal is emitted when a point has been removed from \a index.
347 Signal is emitted when a point has been removed from \a index.
335 \sa remove()
348 \sa remove()
336 */
349 */
337
350
338 /*!
351 /*!
339 \qmlsignal XYSeries::onPointRemoved(int index)
352 \qmlsignal XYSeries::onPointRemoved(int index)
340 Signal is emitted when a point has been removed from \a index.
353 Signal is emitted when a point has been removed from \a index.
341 */
354 */
342
355
343 /*!
356 /*!
344 \fn void QXYSeries::colorChanged(QColor color)
357 \fn void QXYSeries::colorChanged(QColor color)
345 \brief Signal is emitted when the line (pen) color has changed to \a color.
358 \brief Signal is emitted when the line (pen) color has changed to \a color.
346 */
359 */
347 /*!
360 /*!
348 \qmlsignal XYSeries::onColorChanged(color color)
361 \qmlsignal XYSeries::onColorChanged(color color)
349 Signal is emitted when the line (pen) color has changed to \a color.
362 Signal is emitted when the line (pen) color has changed to \a color.
350 */
363 */
351
364
352 /*!
365 /*!
353 \fn void QXYSeriesPrivate::updated()
366 \fn void QXYSeriesPrivate::updated()
354 \brief \internal
367 \brief \internal
355 */
368 */
356
369
357 /*!
370 /*!
358 \qmlmethod XYSeries::append(real x, real y)
371 \qmlmethod XYSeries::append(real x, real y)
359 Append point (\a x, \a y) to the series
372 Append point (\a x, \a y) to the series
360 */
373 */
361
374
362 /*!
375 /*!
363 \qmlmethod XYSeries::replace(real oldX, real oldY, real newX, real newY)
376 \qmlmethod XYSeries::replace(real oldX, real oldY, real newX, real newY)
364 Replaces point (\a oldX, \a oldY) with point (\a newX, \a newY). Does nothing, if point (oldX, oldY) does not
377 Replaces point (\a oldX, \a oldY) with point (\a newX, \a newY). Does nothing, if point (oldX, oldY) does not
365 exist.
378 exist.
366 */
379 */
367
380
368 /*!
381 /*!
369 \qmlmethod XYSeries::remove(real x, real y)
382 \qmlmethod XYSeries::remove(real x, real y)
370 Removes point (\a x, \a y) from the series. Does nothing, if point (x, y) does not exist.
383 Removes point (\a x, \a y) from the series. Does nothing, if point (x, y) does not exist.
371 */
384 */
372
385
373 /*!
386 /*!
374 \qmlmethod XYSeries::insert(int index, real x, real y)
387 \qmlmethod XYSeries::insert(int index, real x, real y)
375 Inserts point (\a x, \a y) to the \a index. If index is 0 or smaller than 0 the point is prepended to the list of
388 Inserts point (\a x, \a y) to the \a index. If index is 0 or smaller than 0 the point is prepended to the list of
376 points. If index is the same as or bigger than count, the point is appended to the list of points.
389 points. If index is the same as or bigger than count, the point is appended to the list of points.
377 */
390 */
378
391
379 /*!
392 /*!
380 \qmlmethod QPointF XYSeries::at(int index)
393 \qmlmethod QPointF XYSeries::at(int index)
381 Returns point at \a index. Returns (0, 0) if the index is not valid.
394 Returns point at \a index. Returns (0, 0) if the index is not valid.
382 */
395 */
383
396
384 /*!
397 /*!
385 \internal
398 \internal
386
399
387 Constructs empty series object which is a child of \a parent.
400 Constructs empty series object which is a child of \a parent.
388 When series object is added to QChart instance ownerships is transferred.
401 When series object is added to QChart instance ownerships is transferred.
389 */
402 */
390 QXYSeries::QXYSeries(QXYSeriesPrivate &d, QObject *parent)
403 QXYSeries::QXYSeries(QXYSeriesPrivate &d, QObject *parent)
391 : QAbstractSeries(d, parent)
404 : QAbstractSeries(d, parent)
392 {
405 {
393 }
406 }
394
407
395 /*!
408 /*!
396 Destroys the object. Series added to QChart instances are owned by those,
409 Destroys the object. Series added to QChart instances are owned by those,
397 and are destroyed when QChart instances are destroyed.
410 and are destroyed when QChart instances are destroyed.
398 */
411 */
399 QXYSeries::~QXYSeries()
412 QXYSeries::~QXYSeries()
400 {
413 {
401 }
414 }
402
415
403 /*!
416 /*!
404 Adds data point (\a x, \a y) to the series.
417 Adds data point (\a x, \a y) to the series.
405 */
418 */
406 void QXYSeries::append(qreal x, qreal y)
419 void QXYSeries::append(qreal x, qreal y)
407 {
420 {
408 append(QPointF(x, y));
421 append(QPointF(x, y));
409 }
422 }
410
423
411 /*!
424 /*!
412 This is an overloaded function.
425 This is an overloaded function.
413 Adds data \a point to the series.
426 Adds data \a point to the series.
414 */
427 */
415 void QXYSeries::append(const QPointF &point)
428 void QXYSeries::append(const QPointF &point)
416 {
429 {
417 Q_D(QXYSeries);
430 Q_D(QXYSeries);
418
431
419 if (isValidValue(point)) {
432 if (isValidValue(point)) {
420 d->m_points << point;
433 d->m_points << point;
421 emit pointAdded(d->m_points.count() - 1);
434 emit pointAdded(d->m_points.count() - 1);
422 }
435 }
423 }
436 }
424
437
425 /*!
438 /*!
426 This is an overloaded function.
439 This is an overloaded function.
427 Adds list of data \a points to the series.
440 Adds list of data \a points to the series.
428 */
441 */
429 void QXYSeries::append(const QList<QPointF> &points)
442 void QXYSeries::append(const QList<QPointF> &points)
430 {
443 {
431 foreach (const QPointF &point , points)
444 foreach (const QPointF &point , points)
432 append(point);
445 append(point);
433 }
446 }
434
447
435 /*!
448 /*!
436 Replaces data point (\a oldX, \a oldY) with data point (\a newX, \a newY).
449 Replaces data point (\a oldX, \a oldY) with data point (\a newX, \a newY).
437 \sa QXYSeries::pointReplaced()
450 \sa QXYSeries::pointReplaced()
438 */
451 */
439 void QXYSeries::replace(qreal oldX, qreal oldY, qreal newX, qreal newY)
452 void QXYSeries::replace(qreal oldX, qreal oldY, qreal newX, qreal newY)
440 {
453 {
441 replace(QPointF(oldX, oldY), QPointF(newX, newY));
454 replace(QPointF(oldX, oldY), QPointF(newX, newY));
442 }
455 }
443
456
444 /*!
457 /*!
445 Replaces \a oldPoint with \a newPoint.
458 Replaces \a oldPoint with \a newPoint.
446 \sa QXYSeries::pointReplaced()
459 \sa QXYSeries::pointReplaced()
447 */
460 */
448 void QXYSeries::replace(const QPointF &oldPoint, const QPointF &newPoint)
461 void QXYSeries::replace(const QPointF &oldPoint, const QPointF &newPoint)
449 {
462 {
450 Q_D(QXYSeries);
463 Q_D(QXYSeries);
451 int index = d->m_points.indexOf(oldPoint);
464 int index = d->m_points.indexOf(oldPoint);
452 if (index == -1)
465 if (index == -1)
453 return;
466 return;
454 replace(index, newPoint);
467 replace(index, newPoint);
455 }
468 }
456
469
457 /*!
470 /*!
458 Replaces the point at \a index with data point (\a newX, \a newY).
471 Replaces the point at \a index with data point (\a newX, \a newY).
459 \sa QXYSeries::pointReplaced()
472 \sa QXYSeries::pointReplaced()
460 */
473 */
461 void QXYSeries::replace(int index, qreal newX, qreal newY)
474 void QXYSeries::replace(int index, qreal newX, qreal newY)
462 {
475 {
463 replace(index, QPointF(newX, newY));
476 replace(index, QPointF(newX, newY));
464 }
477 }
465
478
466 /*!
479 /*!
467 Replaces the point at \a index with \a newPoint.
480 Replaces the point at \a index with \a newPoint.
468 \sa QXYSeries::pointReplaced()
481 \sa QXYSeries::pointReplaced()
469 */
482 */
470 void QXYSeries::replace(int index, const QPointF &newPoint)
483 void QXYSeries::replace(int index, const QPointF &newPoint)
471 {
484 {
472 Q_D(QXYSeries);
485 Q_D(QXYSeries);
473 if (isValidValue(newPoint)) {
486 if (isValidValue(newPoint)) {
474 d->m_points[index] = newPoint;
487 d->m_points[index] = newPoint;
475 emit pointReplaced(index);
488 emit pointReplaced(index);
476 }
489 }
477 }
490 }
478
491
479 /*!
492 /*!
480 Replaces the current points with \a points.
493 Replaces the current points with \a points.
481 \note This is much faster than replacing data points one by one,
494 \note This is much faster than replacing data points one by one,
482 or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced()
495 or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced()
483 when the points have been replaced.
496 when the points have been replaced.
484 \sa QXYSeries::pointsReplaced()
497 \sa QXYSeries::pointsReplaced()
485 */
498 */
486 void QXYSeries::replace(QList<QPointF> points)
499 void QXYSeries::replace(QList<QPointF> points)
487 {
500 {
488 Q_D(QXYSeries);
501 Q_D(QXYSeries);
489 d->m_points = points.toVector();
502 d->m_points = points.toVector();
490 emit pointsReplaced();
503 emit pointsReplaced();
491 }
504 }
492
505
493 /*!
506 /*!
494 Removes the point (\a x, \a y) from the series.
507 Removes the point (\a x, \a y) from the series.
495 */
508 */
496 void QXYSeries::remove(qreal x, qreal y)
509 void QXYSeries::remove(qreal x, qreal y)
497 {
510 {
498 remove(QPointF(x, y));
511 remove(QPointF(x, y));
499 }
512 }
500
513
501 /*!
514 /*!
502 Removes the \a point from the series.
515 Removes the \a point from the series.
503 */
516 */
504 void QXYSeries::remove(const QPointF &point)
517 void QXYSeries::remove(const QPointF &point)
505 {
518 {
506 Q_D(QXYSeries);
519 Q_D(QXYSeries);
507 int index = d->m_points.indexOf(point);
520 int index = d->m_points.indexOf(point);
508 if (index == -1)
521 if (index == -1)
509 return;
522 return;
510 remove(index);
523 remove(index);
511 }
524 }
512
525
513 /*!
526 /*!
514 Removes the point at \a index from the series.
527 Removes the point at \a index from the series.
515 */
528 */
516 void QXYSeries::remove(int index)
529 void QXYSeries::remove(int index)
517 {
530 {
518 Q_D(QXYSeries);
531 Q_D(QXYSeries);
519 d->m_points.remove(index);
532 d->m_points.remove(index);
520 emit pointRemoved(index);
533 emit pointRemoved(index);
521 }
534 }
522
535
523 /*!
536 /*!
524 Inserts a \a point in the series at \a index position.
537 Inserts a \a point in the series at \a index position.
525 */
538 */
526 void QXYSeries::insert(int index, const QPointF &point)
539 void QXYSeries::insert(int index, const QPointF &point)
527 {
540 {
528 Q_D(QXYSeries);
541 Q_D(QXYSeries);
529 if (isValidValue(point)) {
542 if (isValidValue(point)) {
530 d->m_points.insert(index, point);
543 d->m_points.insert(index, point);
531 emit pointAdded(index);
544 emit pointAdded(index);
532 }
545 }
533 }
546 }
534
547
535 /*!
548 /*!
536 Removes all points from the series.
549 Removes all points from the series.
537 */
550 */
538 void QXYSeries::clear()
551 void QXYSeries::clear()
539 {
552 {
540 Q_D(QXYSeries);
553 Q_D(QXYSeries);
541 for (int i = d->m_points.size() - 1; i >= 0; i--)
554 for (int i = d->m_points.size() - 1; i >= 0; i--)
542 remove(d->m_points.at(i));
555 remove(d->m_points.at(i));
543 }
556 }
544
557
545 /*!
558 /*!
546 Returns list of points in the series.
559 Returns list of points in the series.
547 */
560 */
548 QList<QPointF> QXYSeries::points() const
561 QList<QPointF> QXYSeries::points() const
549 {
562 {
550 Q_D(const QXYSeries);
563 Q_D(const QXYSeries);
551 return d->m_points.toList();
564 return d->m_points.toList();
552 }
565 }
553
566
554 /*!
567 /*!
555 Returns point at \a index in internal points vector.
568 Returns point at \a index in internal points vector.
556 */
569 */
557 const QPointF &QXYSeries::at(int index) const
570 const QPointF &QXYSeries::at(int index) const
558 {
571 {
559 Q_D(const QXYSeries);
572 Q_D(const QXYSeries);
560 return d->m_points.at(index);
573 return d->m_points.at(index);
561 }
574 }
562
575
563 /*!
576 /*!
564 Returns number of data points within series.
577 Returns number of data points within series.
565 */
578 */
566 int QXYSeries::count() const
579 int QXYSeries::count() const
567 {
580 {
568 Q_D(const QXYSeries);
581 Q_D(const QXYSeries);
569 return d->m_points.count();
582 return d->m_points.count();
570 }
583 }
571
584
572
585
573 /*!
586 /*!
574 Sets \a pen used for drawing points on the chart. If the pen is not defined, the
587 Sets \a pen used for drawing points on the chart. If the pen is not defined, the
575 pen from chart theme is used.
588 pen from chart theme is used.
576 \sa QChart::setTheme()
589 \sa QChart::setTheme()
577 */
590 */
578 void QXYSeries::setPen(const QPen &pen)
591 void QXYSeries::setPen(const QPen &pen)
579 {
592 {
580 Q_D(QXYSeries);
593 Q_D(QXYSeries);
581 if (d->m_pen != pen) {
594 if (d->m_pen != pen) {
582 bool emitColorChanged = d->m_pen.color() != pen.color();
595 bool emitColorChanged = d->m_pen.color() != pen.color();
583 d->m_pen = pen;
596 d->m_pen = pen;
584 emit d->updated();
597 emit d->updated();
585 if (emitColorChanged)
598 if (emitColorChanged)
586 emit colorChanged(pen.color());
599 emit colorChanged(pen.color());
587 }
600 }
588 }
601 }
589
602
590 QPen QXYSeries::pen() const
603 QPen QXYSeries::pen() const
591 {
604 {
592 Q_D(const QXYSeries);
605 Q_D(const QXYSeries);
593 if (d->m_pen == QChartPrivate::defaultPen())
606 if (d->m_pen == QChartPrivate::defaultPen())
594 return QPen();
607 return QPen();
595 else
608 else
596 return d->m_pen;
609 return d->m_pen;
597 }
610 }
598
611
599 /*!
612 /*!
600 Sets \a brush used for drawing points on the chart. If the brush is not defined, brush
613 Sets \a brush used for drawing points on the chart. If the brush is not defined, brush
601 from chart theme setting is used.
614 from chart theme setting is used.
602 \sa QChart::setTheme()
615 \sa QChart::setTheme()
603 */
616 */
604 void QXYSeries::setBrush(const QBrush &brush)
617 void QXYSeries::setBrush(const QBrush &brush)
605 {
618 {
606 Q_D(QXYSeries);
619 Q_D(QXYSeries);
607 if (d->m_brush != brush) {
620 if (d->m_brush != brush) {
608 d->m_brush = brush;
621 d->m_brush = brush;
609 emit d->updated();
622 emit d->updated();
610 }
623 }
611 }
624 }
612
625
613 QBrush QXYSeries::brush() const
626 QBrush QXYSeries::brush() const
614 {
627 {
615 Q_D(const QXYSeries);
628 Q_D(const QXYSeries);
616 if (d->m_brush == QChartPrivate::defaultBrush())
629 if (d->m_brush == QChartPrivate::defaultBrush())
617 return QBrush();
630 return QBrush();
618 else
631 else
619 return d->m_brush;
632 return d->m_brush;
620 }
633 }
621
634
622 void QXYSeries::setColor(const QColor &color)
635 void QXYSeries::setColor(const QColor &color)
623 {
636 {
624 QPen p = pen();
637 QPen p = pen();
625 if (p.color() != color) {
638 if (p.color() != color) {
626 p.setColor(color);
639 p.setColor(color);
627 setPen(p);
640 setPen(p);
628 }
641 }
629 }
642 }
630
643
631 QColor QXYSeries::color() const
644 QColor QXYSeries::color() const
632 {
645 {
633 return pen().color();
646 return pen().color();
634 }
647 }
635
648
636 void QXYSeries::setPointsVisible(bool visible)
649 void QXYSeries::setPointsVisible(bool visible)
637 {
650 {
638 Q_D(QXYSeries);
651 Q_D(QXYSeries);
639 if (d->m_pointsVisible != visible) {
652 if (d->m_pointsVisible != visible) {
640 d->m_pointsVisible = visible;
653 d->m_pointsVisible = visible;
641 emit d->updated();
654 emit d->updated();
642 }
655 }
643 }
656 }
644
657
645 bool QXYSeries::pointsVisible() const
658 bool QXYSeries::pointsVisible() const
646 {
659 {
647 Q_D(const QXYSeries);
660 Q_D(const QXYSeries);
648 return d->m_pointsVisible;
661 return d->m_pointsVisible;
649 }
662 }
650
663
651 void QXYSeries::setPointLabelsFormat(const QString &format)
664 void QXYSeries::setPointLabelsFormat(const QString &format)
652 {
665 {
653 Q_D(QXYSeries);
666 Q_D(QXYSeries);
654 if (d->m_pointLabelsFormat != format) {
667 if (d->m_pointLabelsFormat != format) {
655 d->m_pointLabelsFormat = format;
668 d->m_pointLabelsFormat = format;
656 emit pointLabelsFormatChanged(format);
669 emit pointLabelsFormatChanged(format);
657 }
670 }
658 }
671 }
659
672
660 QString QXYSeries::pointLabelsFormat() const
673 QString QXYSeries::pointLabelsFormat() const
661 {
674 {
662 Q_D(const QXYSeries);
675 Q_D(const QXYSeries);
663 return d->m_pointLabelsFormat;
676 return d->m_pointLabelsFormat;
664 }
677 }
665
678
666 void QXYSeries::setPointLabelsVisible(bool visible)
679 void QXYSeries::setPointLabelsVisible(bool visible)
667 {
680 {
668 Q_D(QXYSeries);
681 Q_D(QXYSeries);
669 if (d->m_pointLabelsVisible != visible) {
682 if (d->m_pointLabelsVisible != visible) {
670 d->m_pointLabelsVisible = visible;
683 d->m_pointLabelsVisible = visible;
671 emit pointLabelsVisibilityChanged(visible);
684 emit pointLabelsVisibilityChanged(visible);
672 }
685 }
673 }
686 }
674
687
675 bool QXYSeries::pointLabelsVisible() const
688 bool QXYSeries::pointLabelsVisible() const
676 {
689 {
677 Q_D(const QXYSeries);
690 Q_D(const QXYSeries);
678 return d->m_pointLabelsVisible;
691 return d->m_pointLabelsVisible;
679 }
692 }
680
693
681 void QXYSeries::setPointLabelsFont(const QFont &font)
694 void QXYSeries::setPointLabelsFont(const QFont &font)
682 {
695 {
683 Q_D(QXYSeries);
696 Q_D(QXYSeries);
684 if (d->m_pointLabelsFont != font) {
697 if (d->m_pointLabelsFont != font) {
685 d->m_pointLabelsFont = font;
698 d->m_pointLabelsFont = font;
686 emit pointLabelsFontChanged(font);
699 emit pointLabelsFontChanged(font);
687 }
700 }
688 }
701 }
689
702
690 QFont QXYSeries::pointLabelsFont() const
703 QFont QXYSeries::pointLabelsFont() const
691 {
704 {
692 Q_D(const QXYSeries);
705 Q_D(const QXYSeries);
693 return d->m_pointLabelsFont;
706 return d->m_pointLabelsFont;
694 }
707 }
695
708
696 void QXYSeries::setPointLabelsColor(const QColor &color)
709 void QXYSeries::setPointLabelsColor(const QColor &color)
697 {
710 {
698 Q_D(QXYSeries);
711 Q_D(QXYSeries);
699 if (d->m_pointLabelsColor != color) {
712 if (d->m_pointLabelsColor != color) {
700 d->m_pointLabelsColor = color;
713 d->m_pointLabelsColor = color;
701 emit pointLabelsColorChanged(color);
714 emit pointLabelsColorChanged(color);
702 }
715 }
703 }
716 }
704
717
705 QColor QXYSeries::pointLabelsColor() const
718 QColor QXYSeries::pointLabelsColor() const
706 {
719 {
707 Q_D(const QXYSeries);
720 Q_D(const QXYSeries);
708 if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color())
721 if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color())
709 return QPen().color();
722 return QPen().color();
710 else
723 else
711 return d->m_pointLabelsColor;
724 return d->m_pointLabelsColor;
712 }
725 }
713
726
714 /*!
727 /*!
715 Stream operator for adding a data \a point to the series.
728 Stream operator for adding a data \a point to the series.
716 \sa append()
729 \sa append()
717 */
730 */
718 QXYSeries &QXYSeries::operator<< (const QPointF &point)
731 QXYSeries &QXYSeries::operator<< (const QPointF &point)
719 {
732 {
720 append(point);
733 append(point);
721 return *this;
734 return *this;
722 }
735 }
723
736
724
737
725 /*!
738 /*!
726 Stream operator for adding a list of \a points to the series.
739 Stream operator for adding a list of \a points to the series.
727 \sa append()
740 \sa append()
728 */
741 */
729
742
730 QXYSeries &QXYSeries::operator<< (const QList<QPointF>& points)
743 QXYSeries &QXYSeries::operator<< (const QList<QPointF>& points)
731 {
744 {
732 append(points);
745 append(points);
733 return *this;
746 return *this;
734 }
747 }
735
748
736 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
749 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
737
750
738
751
739 QXYSeriesPrivate::QXYSeriesPrivate(QXYSeries *q)
752 QXYSeriesPrivate::QXYSeriesPrivate(QXYSeries *q)
740 : QAbstractSeriesPrivate(q),
753 : QAbstractSeriesPrivate(q),
741 m_pen(QChartPrivate::defaultPen()),
754 m_pen(QChartPrivate::defaultPen()),
742 m_brush(QChartPrivate::defaultBrush()),
755 m_brush(QChartPrivate::defaultBrush()),
743 m_pointsVisible(false),
756 m_pointsVisible(false),
744 m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint")),
757 m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint")),
745 m_pointLabelsVisible(false),
758 m_pointLabelsVisible(false),
746 m_pointLabelsFont(QChartPrivate::defaultFont()),
759 m_pointLabelsFont(QChartPrivate::defaultFont()),
747 m_pointLabelsColor(QChartPrivate::defaultPen().color())
760 m_pointLabelsColor(QChartPrivate::defaultPen().color())
748 {
761 {
749 }
762 }
750
763
751 void QXYSeriesPrivate::initializeDomain()
764 void QXYSeriesPrivate::initializeDomain()
752 {
765 {
753 qreal minX(0);
766 qreal minX(0);
754 qreal minY(0);
767 qreal minY(0);
755 qreal maxX(1);
768 qreal maxX(1);
756 qreal maxY(1);
769 qreal maxY(1);
757
770
758 Q_Q(QXYSeries);
771 Q_Q(QXYSeries);
759
772
760 const QList<QPointF>& points = q->points();
773 const QList<QPointF>& points = q->points();
761
774
762 if (!points.isEmpty()) {
775 if (!points.isEmpty()) {
763 minX = points[0].x();
776 minX = points[0].x();
764 minY = points[0].y();
777 minY = points[0].y();
765 maxX = minX;
778 maxX = minX;
766 maxY = minY;
779 maxY = minY;
767
780
768 for (int i = 0; i < points.count(); i++) {
781 for (int i = 0; i < points.count(); i++) {
769 qreal x = points[i].x();
782 qreal x = points[i].x();
770 qreal y = points[i].y();
783 qreal y = points[i].y();
771 minX = qMin(minX, x);
784 minX = qMin(minX, x);
772 minY = qMin(minY, y);
785 minY = qMin(minY, y);
773 maxX = qMax(maxX, x);
786 maxX = qMax(maxX, x);
774 maxY = qMax(maxY, y);
787 maxY = qMax(maxY, y);
775 }
788 }
776 }
789 }
777
790
778 domain()->setRange(minX, maxX, minY, maxY);
791 domain()->setRange(minX, maxX, minY, maxY);
779 }
792 }
780
793
781 QList<QLegendMarker*> QXYSeriesPrivate::createLegendMarkers(QLegend* legend)
794 QList<QLegendMarker*> QXYSeriesPrivate::createLegendMarkers(QLegend* legend)
782 {
795 {
783 Q_Q(QXYSeries);
796 Q_Q(QXYSeries);
784 QList<QLegendMarker*> list;
797 QList<QLegendMarker*> list;
785 return list << new QXYLegendMarker(q,legend);
798 return list << new QXYLegendMarker(q,legend);
786 }
799 }
787
800
788 void QXYSeriesPrivate::initializeAxes()
801 void QXYSeriesPrivate::initializeAxes()
789 {
802 {
790
803
791 }
804 }
792
805
793 QAbstractAxis::AxisType QXYSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
806 QAbstractAxis::AxisType QXYSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
794 {
807 {
795 Q_UNUSED(orientation);
808 Q_UNUSED(orientation);
796 return QAbstractAxis::AxisTypeValue;
809 return QAbstractAxis::AxisTypeValue;
797 }
810 }
798
811
799 QAbstractAxis* QXYSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
812 QAbstractAxis* QXYSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
800 {
813 {
801 Q_UNUSED(orientation);
814 Q_UNUSED(orientation);
802 return new QValueAxis;
815 return new QValueAxis;
803 }
816 }
804
817
805 void QXYSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options)
818 void QXYSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options)
806 {
819 {
807 XYChart *item = static_cast<XYChart *>(m_item.data());
820 XYChart *item = static_cast<XYChart *>(m_item.data());
808 Q_ASSERT(item);
821 Q_ASSERT(item);
809 if (item->animation())
822 if (item->animation())
810 item->animation()->stopAndDestroyLater();
823 item->animation()->stopAndDestroyLater();
811
824
812 if (options.testFlag(QChart::SeriesAnimations))
825 if (options.testFlag(QChart::SeriesAnimations))
813 item->setAnimation(new XYAnimation(item));
826 item->setAnimation(new XYAnimation(item));
814 else
827 else
815 item->setAnimation(0);
828 item->setAnimation(0);
816 QAbstractSeriesPrivate::initializeAnimations(options);
829 QAbstractSeriesPrivate::initializeAnimations(options);
817 }
830 }
818
831
819 void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QPointF> &points,
832 void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QPointF> &points,
820 const int offset)
833 const int offset)
821 {
834 {
822 static const QString xPointTag(QLatin1String("@xPoint"));
835 static const QString xPointTag(QLatin1String("@xPoint"));
823 static const QString yPointTag(QLatin1String("@yPoint"));
836 static const QString yPointTag(QLatin1String("@yPoint"));
824 const int labelOffset = offset + 2;
837 const int labelOffset = offset + 2;
825
838
826 painter->setFont(m_pointLabelsFont);
839 painter->setFont(m_pointLabelsFont);
827 painter->setPen(QPen(m_pointLabelsColor));
840 painter->setPen(QPen(m_pointLabelsColor));
828 QFontMetrics fm(painter->font());
841 QFontMetrics fm(painter->font());
829
842
830 for (int i(0); i < m_points.size(); i++) {
843 for (int i(0); i < m_points.size(); i++) {
831 QString pointLabel = m_pointLabelsFormat;
844 QString pointLabel = m_pointLabelsFormat;
832 pointLabel.replace(xPointTag, presenter()->numberToString(m_points.at(i).x()));
845 pointLabel.replace(xPointTag, presenter()->numberToString(m_points.at(i).x()));
833 pointLabel.replace(yPointTag, presenter()->numberToString(m_points.at(i).y()));
846 pointLabel.replace(yPointTag, presenter()->numberToString(m_points.at(i).y()));
834
847
835 // Position text in relation to the point
848 // Position text in relation to the point
836 int pointLabelWidth = fm.width(pointLabel);
849 int pointLabelWidth = fm.width(pointLabel);
837 QPointF position(points.at(i));
850 QPointF position(points.at(i));
838 position.setX(position.x() - pointLabelWidth / 2);
851 position.setX(position.x() - pointLabelWidth / 2);
839 position.setY(position.y() - labelOffset);
852 position.setY(position.y() - labelOffset);
840
853
841 painter->drawText(position, pointLabel);
854 painter->drawText(position, pointLabel);
842 }
855 }
843 }
856 }
844
857
845 #include "moc_qxyseries.cpp"
858 #include "moc_qxyseries.cpp"
846 #include "moc_qxyseries_p.cpp"
859 #include "moc_qxyseries_p.cpp"
847
860
848 QT_CHARTS_END_NAMESPACE
861 QT_CHARTS_END_NAMESPACE
@@ -1,202 +1,204
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include "../qxyseries/tst_qxyseries.h"
19 #include "../qxyseries/tst_qxyseries.h"
20 #include <QtCharts/QLineSeries>
20 #include <QtCharts/QLineSeries>
21
21
22
22
23 Q_DECLARE_METATYPE(QList<QPointF>)
23 Q_DECLARE_METATYPE(QList<QPointF>)
24
24
25 class tst_QLineSeries : public tst_QXYSeries
25 class tst_QLineSeries : public tst_QXYSeries
26 {
26 {
27 Q_OBJECT
27 Q_OBJECT
28
28
29 public slots:
29 public slots:
30 void initTestCase();
30 void initTestCase();
31 void cleanupTestCase();
31 void cleanupTestCase();
32 void init();
32 void init();
33 void cleanup();
33 void cleanup();
34 private slots:
34 private slots:
35 void qlineseries_data();
35 void qlineseries_data();
36 void qlineseries();
36 void qlineseries();
37 void pressedSignal();
37 void pressedSignal();
38 void releasedSignal();
38 void releasedSignal();
39 void doubleClickedSignal();
39 void doubleClickedSignal();
40 protected:
40 protected:
41 void pointsVisible_data();
41 void pointsVisible_data();
42 };
42 };
43
43
44 void tst_QLineSeries::initTestCase()
44 void tst_QLineSeries::initTestCase()
45 {
45 {
46 }
46 }
47
47
48 void tst_QLineSeries::cleanupTestCase()
48 void tst_QLineSeries::cleanupTestCase()
49 {
49 {
50 QTest::qWait(1); // Allow final deleteLaters to run
50 QTest::qWait(1); // Allow final deleteLaters to run
51 }
51 }
52
52
53 void tst_QLineSeries::init()
53 void tst_QLineSeries::init()
54 {
54 {
55 tst_QXYSeries::init();
55 tst_QXYSeries::init();
56 m_series = new QLineSeries();
56 m_series = new QLineSeries();
57 }
57 }
58
58
59 void tst_QLineSeries::cleanup()
59 void tst_QLineSeries::cleanup()
60 {
60 {
61 delete m_series;
61 delete m_series;
62 m_series=0;
62 m_series=0;
63 tst_QXYSeries::cleanup();
63 tst_QXYSeries::cleanup();
64 }
64 }
65
65
66 void tst_QLineSeries::qlineseries_data()
66 void tst_QLineSeries::qlineseries_data()
67 {
67 {
68
68
69 }
69 }
70
70
71 void tst_QLineSeries::qlineseries()
71 void tst_QLineSeries::qlineseries()
72 {
72 {
73 QLineSeries series;
73 QLineSeries series;
74
74
75 QCOMPARE(series.count(),0);
75 QCOMPARE(series.count(),0);
76 QCOMPARE(series.brush(), QBrush());
76 QCOMPARE(series.brush(), QBrush());
77 QCOMPARE(series.points(), QList<QPointF>());
77 QCOMPARE(series.points(), QList<QPointF>());
78 QCOMPARE(series.pen(), QPen());
78 QCOMPARE(series.pen(), QPen());
79 QCOMPARE(series.pointsVisible(), false);
79 QCOMPARE(series.pointsVisible(), false);
80 QCOMPARE(series.pointLabelsVisible(), false);
80 QCOMPARE(series.pointLabelsVisible(), false);
81 QCOMPARE(series.pointLabelsFormat(), QLatin1String("@xPoint, @yPoint"));
81 QCOMPARE(series.pointLabelsFormat(), QLatin1String("@xPoint, @yPoint"));
82
82
83 series.append(QList<QPointF>());
83 series.append(QList<QPointF>());
84 series.append(0.0,0.0);
84 series.append(0.0,0.0);
85 series.append(QPointF());
85 series.append(QPointF());
86
86
87 series.remove(0.0,0.0);
87 series.remove(0.0,0.0);
88 series.remove(QPointF());
88 series.remove(QPointF());
89 series.clear();
89 series.clear();
90
90
91 series.replace(QPointF(),QPointF());
91 series.replace(QPointF(),QPointF());
92 series.replace(0,0,0,0);
92 series.replace(0,0,0,0);
93 series.setBrush(QBrush());
93 series.setBrush(QBrush());
94
94
95 series.setPen(QPen());
95 series.setPen(QPen());
96 series.setPointsVisible(false);
96 series.setPointsVisible(false);
97
97
98 series.setPointLabelsVisible(false);
98 series.setPointLabelsVisible(false);
99 series.setPointLabelsFormat(QString());
99 series.setPointLabelsFormat(QString());
100
100
101 m_chart->addSeries(&series);
101 m_chart->addSeries(&series);
102 m_view->show();
102 m_view->show();
103 QTest::qWaitForWindowShown(m_view);
103 QTest::qWaitForWindowShown(m_view);
104 }
104 }
105
105
106 void tst_QLineSeries::pressedSignal()
106 void tst_QLineSeries::pressedSignal()
107 {
107 {
108 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
108 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
109
109
110 QPointF linePoint(4, 12);
110 QPointF linePoint(4, 12);
111 QLineSeries *lineSeries = new QLineSeries();
111 QLineSeries *lineSeries = new QLineSeries();
112 lineSeries->append(QPointF(2, 1));
112 lineSeries->append(QPointF(2, 1));
113 lineSeries->append(linePoint);
113 lineSeries->append(linePoint);
114 lineSeries->append(QPointF(6, 12));
114 lineSeries->append(QPointF(6, 12));
115
115
116 QChartView view;
116 QChartView view;
117 view.chart()->legend()->setVisible(false);
117 view.chart()->legend()->setVisible(false);
118 view.chart()->addSeries(lineSeries);
118 view.chart()->addSeries(lineSeries);
119 view.show();
119 view.show();
120 QTest::qWaitForWindowShown(&view);
120 QTest::qWaitForWindowShown(&view);
121
121
122 QSignalSpy seriesSpy(lineSeries, SIGNAL(pressed(QPointF)));
122 QSignalSpy seriesSpy(lineSeries, SIGNAL(pressed(QPointF)));
123
123
124 QPointF checkPoint = view.chart()->mapToPosition(linePoint);
124 QPointF checkPoint = view.chart()->mapToPosition(linePoint);
125 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
125 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
126 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
126 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
127
127
128 QCOMPARE(seriesSpy.count(), 1);
128 QCOMPARE(seriesSpy.count(), 1);
129 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
129 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
130 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
130 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
131 // this causes small distinction in decimals so we round it before comparing
131 // this causes small distinction in decimals so we round it before comparing
132 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
132 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
133 QCOMPARE(qRound(signalPoint.x()), qRound(linePoint.x()));
133 QCOMPARE(qRound(signalPoint.x()), qRound(linePoint.x()));
134 QCOMPARE(qRound(signalPoint.y()), qRound(linePoint.y()));
134 QCOMPARE(qRound(signalPoint.y()), qRound(linePoint.y()));
135 }
135 }
136
136
137 void tst_QLineSeries::releasedSignal()
137 void tst_QLineSeries::releasedSignal()
138 {
138 {
139 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
139 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
140
140
141 QPointF linePoint(4, 12);
141 QPointF linePoint(4, 12);
142 QLineSeries *lineSeries = new QLineSeries();
142 QLineSeries *lineSeries = new QLineSeries();
143 lineSeries->append(QPointF(2, 20));
143 lineSeries->append(QPointF(2, 20));
144 lineSeries->append(linePoint);
144 lineSeries->append(linePoint);
145 lineSeries->append(QPointF(6, 12));
145 lineSeries->append(QPointF(6, 12));
146
146
147 QChartView view;
147 QChartView view;
148 view.chart()->legend()->setVisible(false);
148 view.chart()->legend()->setVisible(false);
149 view.chart()->addSeries(lineSeries);
149 view.chart()->addSeries(lineSeries);
150 view.show();
150 view.show();
151 QTest::qWaitForWindowShown(&view);
151 QTest::qWaitForWindowShown(&view);
152
152
153 QSignalSpy seriesSpy(lineSeries, SIGNAL(released(QPointF)));
153 QSignalSpy seriesSpy(lineSeries, SIGNAL(released(QPointF)));
154
154
155 QPointF checkPoint = view.chart()->mapToPosition(linePoint);
155 QPointF checkPoint = view.chart()->mapToPosition(linePoint);
156 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
156 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
157 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
157 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
158
158
159 QCOMPARE(seriesSpy.count(), 1);
159 QCOMPARE(seriesSpy.count(), 1);
160 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
160 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
161 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
161 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
162 // this causes small distinction in decimals so we round it before comparing
162 // this causes small distinction in decimals so we round it before comparing
163 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
163 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
164 QCOMPARE(qRound(signalPoint.x()), qRound(linePoint.x()));
164 QCOMPARE(qRound(signalPoint.x()), qRound(linePoint.x()));
165 QCOMPARE(qRound(signalPoint.y()), qRound(linePoint.y()));
165 QCOMPARE(qRound(signalPoint.y()), qRound(linePoint.y()));
166 }
166 }
167
167
168 void tst_QLineSeries::doubleClickedSignal()
168 void tst_QLineSeries::doubleClickedSignal()
169 {
169 {
170 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
170 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
171
171
172 QPointF linePoint(4, 12);
172 QPointF linePoint(4, 12);
173 QLineSeries *lineSeries = new QLineSeries();
173 QLineSeries *lineSeries = new QLineSeries();
174 lineSeries->append(QPointF(2, 20));
174 lineSeries->append(QPointF(2, 20));
175 lineSeries->append(linePoint);
175 lineSeries->append(linePoint);
176 lineSeries->append(QPointF(6, 12));
176 lineSeries->append(QPointF(6, 12));
177
177
178 QChartView view;
178 QChartView view;
179 view.chart()->legend()->setVisible(false);
179 view.chart()->legend()->setVisible(false);
180 view.chart()->addSeries(lineSeries);
180 view.chart()->addSeries(lineSeries);
181 view.show();
181 view.show();
182 QTest::qWaitForWindowShown(&view);
182 QTest::qWaitForWindowShown(&view);
183
183
184 QSignalSpy seriesSpy(lineSeries, SIGNAL(doubleClicked(QPointF)));
184 QSignalSpy seriesSpy(lineSeries, SIGNAL(doubleClicked(QPointF)));
185
185
186 QPointF checkPoint = view.chart()->mapToPosition(linePoint);
186 QPointF checkPoint = view.chart()->mapToPosition(linePoint);
187 // mouseClick needed first to save the position
188 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
187 QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
189 QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
188 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
190 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
189
191
190 QCOMPARE(seriesSpy.count(), 1);
192 QCOMPARE(seriesSpy.count(), 1);
191 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
193 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
192 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
194 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
193 // this causes small distinction in decimals so we round it before comparing
195 // this causes small distinction in decimals so we round it before comparing
194 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
196 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
195 QCOMPARE(qRound(signalPoint.x()), qRound(linePoint.x()));
197 QCOMPARE(qRound(signalPoint.x()), qRound(linePoint.x()));
196 QCOMPARE(qRound(signalPoint.y()), qRound(linePoint.y()));
198 QCOMPARE(qRound(signalPoint.y()), qRound(linePoint.y()));
197 }
199 }
198
200
199 QTEST_MAIN(tst_QLineSeries)
201 QTEST_MAIN(tst_QLineSeries)
200
202
201 #include "tst_qlineseries.moc"
203 #include "tst_qlineseries.moc"
202
204
@@ -1,194 +1,196
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include "../qxyseries/tst_qxyseries.h"
19 #include "../qxyseries/tst_qxyseries.h"
20 #include <QtCharts/QSplineSeries>
20 #include <QtCharts/QSplineSeries>
21
21
22 Q_DECLARE_METATYPE(QList<QPointF>)
22 Q_DECLARE_METATYPE(QList<QPointF>)
23
23
24 class tst_QSplineSeries : public tst_QXYSeries
24 class tst_QSplineSeries : public tst_QXYSeries
25 {
25 {
26 Q_OBJECT
26 Q_OBJECT
27
27
28 public slots:
28 public slots:
29 void initTestCase();
29 void initTestCase();
30 void cleanupTestCase();
30 void cleanupTestCase();
31 void init();
31 void init();
32 void cleanup();
32 void cleanup();
33 private slots:
33 private slots:
34 void qsplineseries_data();
34 void qsplineseries_data();
35 void qsplineseries();
35 void qsplineseries();
36 void pressedSignal();
36 void pressedSignal();
37 void releasedSignal();
37 void releasedSignal();
38 void doubleClickedSignal();
38 void doubleClickedSignal();
39 protected:
39 protected:
40 void pointsVisible_data();
40 void pointsVisible_data();
41 };
41 };
42
42
43 void tst_QSplineSeries::initTestCase()
43 void tst_QSplineSeries::initTestCase()
44 {
44 {
45 }
45 }
46
46
47 void tst_QSplineSeries::cleanupTestCase()
47 void tst_QSplineSeries::cleanupTestCase()
48 {
48 {
49 QTest::qWait(1); // Allow final deleteLaters to run
49 QTest::qWait(1); // Allow final deleteLaters to run
50 }
50 }
51
51
52 void tst_QSplineSeries::init()
52 void tst_QSplineSeries::init()
53 {
53 {
54 tst_QXYSeries::init();
54 tst_QXYSeries::init();
55 m_series = new QSplineSeries();
55 m_series = new QSplineSeries();
56 }
56 }
57
57
58 void tst_QSplineSeries::cleanup()
58 void tst_QSplineSeries::cleanup()
59 {
59 {
60 delete m_series;
60 delete m_series;
61 tst_QXYSeries::cleanup();
61 tst_QXYSeries::cleanup();
62 }
62 }
63
63
64 void tst_QSplineSeries::qsplineseries_data()
64 void tst_QSplineSeries::qsplineseries_data()
65 {
65 {
66
66
67 }
67 }
68
68
69 void tst_QSplineSeries::qsplineseries()
69 void tst_QSplineSeries::qsplineseries()
70 {
70 {
71 QSplineSeries series;
71 QSplineSeries series;
72
72
73 QCOMPARE(series.count(),0);
73 QCOMPARE(series.count(),0);
74 QCOMPARE(series.brush(), QBrush());
74 QCOMPARE(series.brush(), QBrush());
75 QCOMPARE(series.points(), QList<QPointF>());
75 QCOMPARE(series.points(), QList<QPointF>());
76 QCOMPARE(series.pen(), QPen());
76 QCOMPARE(series.pen(), QPen());
77 QCOMPARE(series.pointsVisible(), false);
77 QCOMPARE(series.pointsVisible(), false);
78
78
79 series.append(QList<QPointF>());
79 series.append(QList<QPointF>());
80 series.append(0.0,0.0);
80 series.append(0.0,0.0);
81 series.append(QPointF());
81 series.append(QPointF());
82
82
83 series.remove(0.0,0.0);
83 series.remove(0.0,0.0);
84 series.remove(QPointF());
84 series.remove(QPointF());
85 series.clear();
85 series.clear();
86
86
87 series.replace(QPointF(),QPointF());
87 series.replace(QPointF(),QPointF());
88 series.replace(0,0,0,0);
88 series.replace(0,0,0,0);
89 series.setBrush(QBrush());
89 series.setBrush(QBrush());
90
90
91 series.setPen(QPen());
91 series.setPen(QPen());
92 series.setPointsVisible(false);
92 series.setPointsVisible(false);
93
93
94 m_chart->addSeries(&series);
94 m_chart->addSeries(&series);
95 m_view->show();
95 m_view->show();
96 QTest::qWaitForWindowShown(m_view);
96 QTest::qWaitForWindowShown(m_view);
97 }
97 }
98
98
99 void tst_QSplineSeries::pressedSignal()
99 void tst_QSplineSeries::pressedSignal()
100 {
100 {
101 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
101 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
102
102
103 QPointF splinePoint(4, 12);
103 QPointF splinePoint(4, 12);
104 QSplineSeries *splineSeries = new QSplineSeries();
104 QSplineSeries *splineSeries = new QSplineSeries();
105 splineSeries->append(QPointF(2, 1));
105 splineSeries->append(QPointF(2, 1));
106 splineSeries->append(splinePoint);
106 splineSeries->append(splinePoint);
107 splineSeries->append(QPointF(6, 12));
107 splineSeries->append(QPointF(6, 12));
108
108
109 QChartView view;
109 QChartView view;
110 view.chart()->legend()->setVisible(false);
110 view.chart()->legend()->setVisible(false);
111 view.chart()->addSeries(splineSeries);
111 view.chart()->addSeries(splineSeries);
112 view.show();
112 view.show();
113 QTest::qWaitForWindowShown(&view);
113 QTest::qWaitForWindowShown(&view);
114
114
115 QSignalSpy seriesSpy(splineSeries, SIGNAL(pressed(QPointF)));
115 QSignalSpy seriesSpy(splineSeries, SIGNAL(pressed(QPointF)));
116
116
117 QPointF checkPoint = view.chart()->mapToPosition(splinePoint);
117 QPointF checkPoint = view.chart()->mapToPosition(splinePoint);
118 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
118 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
119 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
119 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
120
120
121 QCOMPARE(seriesSpy.count(), 1);
121 QCOMPARE(seriesSpy.count(), 1);
122 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
122 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
123 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
123 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
124 // this causes small distinction in decimals so we round it before comparing
124 // this causes small distinction in decimals so we round it before comparing
125 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
125 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
126 QCOMPARE(qRound(signalPoint.x()), qRound(splinePoint.x()));
126 QCOMPARE(qRound(signalPoint.x()), qRound(splinePoint.x()));
127 QCOMPARE(qRound(signalPoint.y()), qRound(splinePoint.y()));
127 QCOMPARE(qRound(signalPoint.y()), qRound(splinePoint.y()));
128 }
128 }
129
129
130 void tst_QSplineSeries::releasedSignal()
130 void tst_QSplineSeries::releasedSignal()
131 {
131 {
132 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
132 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
133
133
134 QPointF splinePoint(4, 12);
134 QPointF splinePoint(4, 12);
135 QSplineSeries *splineSeries = new QSplineSeries();
135 QSplineSeries *splineSeries = new QSplineSeries();
136 splineSeries->append(QPointF(2, 20));
136 splineSeries->append(QPointF(2, 20));
137 splineSeries->append(splinePoint);
137 splineSeries->append(splinePoint);
138 splineSeries->append(QPointF(6, 12));
138 splineSeries->append(QPointF(6, 12));
139
139
140 QChartView view;
140 QChartView view;
141 view.chart()->legend()->setVisible(false);
141 view.chart()->legend()->setVisible(false);
142 view.chart()->addSeries(splineSeries);
142 view.chart()->addSeries(splineSeries);
143 view.show();
143 view.show();
144 QTest::qWaitForWindowShown(&view);
144 QTest::qWaitForWindowShown(&view);
145
145
146 QSignalSpy seriesSpy(splineSeries, SIGNAL(released(QPointF)));
146 QSignalSpy seriesSpy(splineSeries, SIGNAL(released(QPointF)));
147
147
148 QPointF checkPoint = view.chart()->mapToPosition(splinePoint);
148 QPointF checkPoint = view.chart()->mapToPosition(splinePoint);
149 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
149 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
150 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
150 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
151
151
152 QCOMPARE(seriesSpy.count(), 1);
152 QCOMPARE(seriesSpy.count(), 1);
153 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
153 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
154 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
154 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
155 // this causes small distinction in decimals so we round it before comparing
155 // this causes small distinction in decimals so we round it before comparing
156 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
156 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
157 QCOMPARE(qRound(signalPoint.x()), qRound(splinePoint.x()));
157 QCOMPARE(qRound(signalPoint.x()), qRound(splinePoint.x()));
158 QCOMPARE(qRound(signalPoint.y()), qRound(splinePoint.y()));
158 QCOMPARE(qRound(signalPoint.y()), qRound(splinePoint.y()));
159 }
159 }
160
160
161 void tst_QSplineSeries::doubleClickedSignal()
161 void tst_QSplineSeries::doubleClickedSignal()
162 {
162 {
163 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
163 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
164
164
165 QPointF splinePoint(4, 12);
165 QPointF splinePoint(4, 12);
166 QSplineSeries *splineSeries = new QSplineSeries();
166 QSplineSeries *splineSeries = new QSplineSeries();
167 splineSeries->append(QPointF(2, 20));
167 splineSeries->append(QPointF(2, 20));
168 splineSeries->append(splinePoint);
168 splineSeries->append(splinePoint);
169 splineSeries->append(QPointF(6, 12));
169 splineSeries->append(QPointF(6, 12));
170
170
171 QChartView view;
171 QChartView view;
172 view.chart()->legend()->setVisible(false);
172 view.chart()->legend()->setVisible(false);
173 view.chart()->addSeries(splineSeries);
173 view.chart()->addSeries(splineSeries);
174 view.show();
174 view.show();
175 QTest::qWaitForWindowShown(&view);
175 QTest::qWaitForWindowShown(&view);
176
176
177 QSignalSpy seriesSpy(splineSeries, SIGNAL(doubleClicked(QPointF)));
177 QSignalSpy seriesSpy(splineSeries, SIGNAL(doubleClicked(QPointF)));
178
178
179 QPointF checkPoint = view.chart()->mapToPosition(splinePoint);
179 QPointF checkPoint = view.chart()->mapToPosition(splinePoint);
180 // mouseClick needed first to save the position
181 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
180 QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
182 QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, checkPoint.toPoint());
181 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
183 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
182
184
183 QCOMPARE(seriesSpy.count(), 1);
185 QCOMPARE(seriesSpy.count(), 1);
184 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
186 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
185 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
187 // checkPoint is QPointF and for the mouseClick it it's changed to QPoint
186 // this causes small distinction in decimals so we round it before comparing
188 // this causes small distinction in decimals so we round it before comparing
187 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
189 QPointF signalPoint = qvariant_cast<QPointF>(seriesSpyArg.at(0));
188 QCOMPARE(qRound(signalPoint.x()), qRound(splinePoint.x()));
190 QCOMPARE(qRound(signalPoint.x()), qRound(splinePoint.x()));
189 QCOMPARE(qRound(signalPoint.y()), qRound(splinePoint.y()));
191 QCOMPARE(qRound(signalPoint.y()), qRound(splinePoint.y()));
190 }
192 }
191 QTEST_MAIN(tst_QSplineSeries)
193 QTEST_MAIN(tst_QSplineSeries)
192
194
193 #include "tst_qsplineseries.moc"
195 #include "tst_qsplineseries.moc"
194
196
@@ -1,79 +1,80
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 import QtQuick 2.0
19 import QtQuick 2.0
20 import QtCharts 2.0
20 import QtCharts 2.0
21
21
22 ChartView {
22 ChartView {
23 title: "scatter series"
23 title: "scatter series"
24 property variant series: scatterSeries
24 property variant series: scatterSeries
25 animationOptions: ChartView.SeriesAnimations
25 animationOptions: ChartView.SeriesAnimations
26
26
27 ScatterSeries {
27 ScatterSeries {
28 id: scatterSeries
28 id: scatterSeries
29 name: "scatter 1"
29 name: "scatter 1"
30 XYPoint { x: 1.5; y: 1.5 }
30 XYPoint { x: 1.5; y: 1.5 }
31 XYPoint { x: 1.5; y: 1.6 }
31 XYPoint { x: 1.5; y: 1.6 }
32 XYPoint { x: 1.57; y: 1.55 }
32 XYPoint { x: 1.57; y: 1.55 }
33 XYPoint { x: 1.8; y: 1.8 }
33 XYPoint { x: 1.8; y: 1.8 }
34 XYPoint { x: 1.9; y: 1.6 }
34 XYPoint { x: 1.9; y: 1.6 }
35 XYPoint { x: 2.1; y: 1.3 }
35 XYPoint { x: 2.1; y: 1.3 }
36 XYPoint { x: 2.5; y: 2.1 }
36 XYPoint { x: 2.5; y: 2.1 }
37
37
38 pointLabelsFormat: "@xPoint, @yPoint";
38 pointLabelsFormat: "@xPoint, @yPoint";
39
39
40 onNameChanged: console.log("scatterSeries.onNameChanged: " + name);
40 onNameChanged: console.log("scatterSeries.onNameChanged: " + name);
41 onVisibleChanged: console.log("scatterSeries.onVisibleChanged: " + visible);
41 onVisibleChanged: console.log("scatterSeries.onVisibleChanged: " + visible);
42 onOpacityChanged: console.log(name + ".onOpacityChanged: " + opacity);
42 onOpacityChanged: console.log(name + ".onOpacityChanged: " + opacity);
43 onClicked: console.log(name + ".onClicked: " + point.x + ", " + point.y);
43 onClicked: console.log(name + ".onClicked: " + point.x + ", " + point.y);
44 onHovered: console.log(name + ".onHovered: " + point.x + ", " + point.y);
44 onHovered: console.log(name + ".onHovered: " + point.x + ", " + point.y);
45 onPointReplaced: console.log("scatterSeries.onPointReplaced: " + index);
45 onPointReplaced: console.log("scatterSeries.onPointReplaced: " + index);
46 onPointRemoved: console.log("scatterSeries.onPointRemoved: " + index);
46 onPointRemoved: console.log("scatterSeries.onPointRemoved: " + index);
47 onPointAdded: console.log("scatterSeries.onPointAdded: " + series.at(index).x + ", " + series.at(index).y);
47 onPointAdded: console.log("scatterSeries.onPointAdded: " + series.at(index).x + ", " + series.at(index).y);
48 onColorChanged: console.log("scatterSeries.onColorChanged: " + color);
48 onColorChanged: console.log("scatterSeries.onColorChanged: " + color);
49 onBorderColorChanged: console.log("scatterSeries.onBorderColorChanged: " + borderColor);
49 onBorderColorChanged: console.log("scatterSeries.onBorderColorChanged: " + borderColor);
50 onBorderWidthChanged: console.log("scatterSeries.onBorderChanged: " + borderWidth);
50 onBorderWidthChanged: console.log("scatterSeries.onBorderChanged: " + borderWidth);
51 onCountChanged: console.log("scatterSeries.onCountChanged: " + count);
51 onCountChanged: console.log("scatterSeries.onCountChanged: " + count);
52 onPointLabelsVisibilityChanged: console.log("lineSeries.onPointLabelsVisibilityChanged: "
52 onPointLabelsVisibilityChanged: console.log("scatterSeries.onPointLabelsVisibilityChanged: "
53 + visible);
53 + visible);
54 onPointLabelsFormatChanged: console.log("lineSeries.onPointLabelsFormatChanged: "
54 onPointLabelsFormatChanged: console.log("scatterSeries.onPointLabelsFormatChanged: "
55 + format);
55 + format);
56 onPointLabelsFontChanged: console.log("lineSeries.onPointLabelsFontChanged: "
56 onPointLabelsFontChanged: console.log("scatterSeries.onPointLabelsFontChanged: "
57 + font.family);
57 + font.family);
58 onPointLabelsColorChanged: console.log("lineSeries.onPointLabelsColorChanged: "
58 onPointLabelsColorChanged: console.log("scatterSeries.onPointLabelsColorChanged: "
59 + color);
59 + color);
60 onPressed: console.log(name + ".onPressed: " + point.x + ", " + point.y);
60 onPressed: console.log(name + ".onPressed: " + point.x + ", " + point.y);
61 onReleased: console.log(name + ".onReleased: " + point.x + ", " + point.y);
61 onReleased: console.log(name + ".onReleased: " + point.x + ", " + point.y);
62 onDoubleClicked: console.log(name + ".onDoubleClicked: " + point.x + ", " + point.y);
62 onDoubleClicked: console.log(name + ".onDoubleClicked: " + point.x + ", " + point.y);
63 }
63 }
64
64
65 ScatterSeries {
65 ScatterSeries {
66 name: "scatter2"
66 name: "scatter2"
67 XYPoint { x: 2.0; y: 2.0 }
67 XYPoint { x: 2.0; y: 2.0 }
68 XYPoint { x: 2.0; y: 2.1 }
68 XYPoint { x: 2.0; y: 2.1 }
69 XYPoint { x: 2.07; y: 2.05 }
69 XYPoint { x: 2.07; y: 2.05 }
70 XYPoint { x: 2.2; y: 2.9 }
70 XYPoint { x: 2.2; y: 2.9 }
71 XYPoint { x: 2.4; y: 2.7 }
71 XYPoint { x: 2.4; y: 2.7 }
72 XYPoint { x: 2.67; y: 2.65 }
72 XYPoint { x: 2.67; y: 2.65 }
73 onClicked: console.log(name + ".onClicked: " + point.x + ", " + point.y);
73 onClicked: console.log(name + ".onClicked: " + point.x + ", " + point.y);
74 onHovered: console.log(name + ".onHovered: " + point.x + ", " + point.y);
74 onHovered: console.log(name + ".onHovered: " + point.x + ", " + point.y);
75 onPressed: console.log(name + ".onPressed: " + point.x + ", " + point.y);
75 onPressed: console.log(name + ".onPressed: " + point.x + ", " + point.y);
76 onReleased: console.log(name + ".onReleased: " + point.x + ", " + point.y);
76 onReleased: console.log(name + ".onReleased: " + point.x + ", " + point.y);
77 onDoubleClicked: console.log(name + ".onDoubleClicked: " + point.x + ", " + point.y);
77 onDoubleClicked: console.log(name + ".onDoubleClicked: " + point.x + ", " + point.y);
78 }
78 }
79
79 }
80 }
General Comments 0
You need to be logged in to leave comments. Login now