##// END OF EJS Templates
Fix area series point labels...
Titta Heikkala -
r2778:6eb2f806ec7f
parent child
Show More
@@ -1,283 +1,284
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2015 The Qt Company Ltd
4 4 ** All rights reserved.
5 5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 6 **
7 7 ** This file is part of the Qt Charts module.
8 8 **
9 9 ** Licensees holding valid commercial license for Qt may use this file in
10 10 ** accordance with the Qt License Agreement provided with the Software
11 11 ** or, alternatively, in accordance with the terms contained in a written
12 12 ** agreement between you and The Qt Company.
13 13 **
14 14 ** If you have questions regarding the use of this file, please use
15 15 ** contact form at http://qt.io
16 16 **
17 17 ****************************************************************************/
18 18
19 19 #include <private/areachartitem_p.h>
20 20 #include <QtCharts/QAreaSeries>
21 21 #include <private/qareaseries_p.h>
22 22 #include <QtCharts/QLineSeries>
23 23 #include <private/chartpresenter_p.h>
24 24 #include <private/abstractdomain_p.h>
25 25 #include <QtGui/QPainter>
26 26 #include <QtWidgets/QGraphicsSceneMouseEvent>
27 27 #include <QtCore/QDebug>
28 28
29 29
30 30 QT_CHARTS_BEGIN_NAMESPACE
31 31
32 32 AreaChartItem::AreaChartItem(QAreaSeries *areaSeries, QGraphicsItem* item)
33 33 : ChartItem(areaSeries->d_func(),item),
34 34 m_series(areaSeries),
35 35 m_upper(0),
36 36 m_lower(0),
37 37 m_pointsVisible(false),
38 38 m_pointLabelsVisible(false),
39 39 m_pointLabelsFormat(areaSeries->pointLabelsFormat()),
40 40 m_pointLabelsFont(areaSeries->pointLabelsFont()),
41 41 m_pointLabelsColor(areaSeries->pointLabelsColor()),
42 42 m_mousePressed(false)
43 43 {
44 44 setAcceptHoverEvents(true);
45 45 setFlag(QGraphicsItem::ItemIsSelectable, true);
46 46 setZValue(ChartPresenter::LineChartZValue);
47 47 if (m_series->upperSeries())
48 48 m_upper = new AreaBoundItem(this, m_series->upperSeries());
49 49 if (m_series->lowerSeries())
50 50 m_lower = new AreaBoundItem(this, m_series->lowerSeries());
51 51
52 52 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
53 53 QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
54 54 QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
55 55 QObject::connect(this, SIGNAL(clicked(QPointF)), areaSeries, SIGNAL(clicked(QPointF)));
56 56 QObject::connect(this, SIGNAL(hovered(QPointF,bool)), areaSeries, SIGNAL(hovered(QPointF,bool)));
57 57 QObject::connect(this, SIGNAL(pressed(QPointF)), areaSeries, SIGNAL(pressed(QPointF)));
58 58 QObject::connect(this, SIGNAL(released(QPointF)), areaSeries, SIGNAL(released(QPointF)));
59 59 QObject::connect(this, SIGNAL(doubleClicked(QPointF)),
60 60 areaSeries, SIGNAL(doubleClicked(QPointF)));
61 61 QObject::connect(areaSeries, SIGNAL(pointLabelsFormatChanged(QString)),
62 62 this, SLOT(handleUpdated()));
63 63 QObject::connect(areaSeries, SIGNAL(pointLabelsVisibilityChanged(bool)),
64 64 this, SLOT(handleUpdated()));
65 65 QObject::connect(areaSeries, SIGNAL(pointLabelsFontChanged(QFont)),
66 66 this, SLOT(handleUpdated()));
67 67 QObject::connect(areaSeries, SIGNAL(pointLabelsColorChanged(QColor)),
68 68 this, SLOT(handleUpdated()));
69 69
70 70 handleUpdated();
71 71 }
72 72
73 73 AreaChartItem::~AreaChartItem()
74 74 {
75 75 delete m_upper;
76 76 delete m_lower;
77 77 }
78 78
79 79 void AreaChartItem::setPresenter(ChartPresenter *presenter)
80 80 {
81 81 if (m_upper)
82 82 m_upper->setPresenter(presenter);
83 83 if (m_lower) {
84 84 m_lower->setPresenter(presenter);
85 85 }
86 86 ChartItem::setPresenter(presenter);
87 87 }
88 88
89 89 QRectF AreaChartItem::boundingRect() const
90 90 {
91 91 return m_rect;
92 92 }
93 93
94 94 QPainterPath AreaChartItem::shape() const
95 95 {
96 96 return m_path;
97 97 }
98 98
99 99 void AreaChartItem::updatePath()
100 100 {
101 101 QPainterPath path;
102 102 QRectF rect(QPointF(0,0),domain()->size());
103 103
104 104 path = m_upper->path();
105 105
106 106 if (m_lower) {
107 107 // Note: Polarcharts always draw area correctly only when both series have equal width or are
108 108 // fully displayed. If one series is partally off-chart, the connecting line between
109 109 // the series does not attach to the end of the partially hidden series but to the point
110 110 // where it intersects the axis line. The problem is especially noticeable when one of the series
111 111 // is entirely off-chart, in which case the connecting line connects two ends of the
112 112 // visible series.
113 113 // This happens because we get the paths from linechart, which omits off-chart segments.
114 114 // To properly fix, linechart would need to provide true full path, in right, left, and the rest
115 115 // portions to enable proper clipping. However, combining those to single visually unified area
116 116 // would be a nightmare, since they would have to be painted separately.
117 117 path.connectPath(m_lower->path().toReversed());
118 118 } else {
119 119 QPointF first = path.pointAtPercent(0);
120 120 QPointF last = path.pointAtPercent(1);
121 121 if (presenter()->chartType() == QChart::ChartTypeCartesian) {
122 122 path.lineTo(last.x(), rect.bottom());
123 123 path.lineTo(first.x(), rect.bottom());
124 124 } else { // polar
125 125 path.lineTo(rect.center());
126 126 }
127 127 }
128 128 path.closeSubpath();
129 129
130 130 // Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses
131 131 // a region that has to be compatible with QRect.
132 132 if (path.boundingRect().height() <= INT_MAX
133 133 && path.boundingRect().width() <= INT_MAX) {
134 134 prepareGeometryChange();
135 135 m_path = path;
136 136 m_rect = path.boundingRect();
137 137 update();
138 138 }
139 139 }
140 140
141 141 void AreaChartItem::handleUpdated()
142 142 {
143 143 setVisible(m_series->isVisible());
144 144 m_pointsVisible = m_series->pointsVisible();
145 145 m_linePen = m_series->pen();
146 146 m_brush = m_series->brush();
147 147 m_pointPen = m_series->pen();
148 148 m_pointPen.setWidthF(2 * m_pointPen.width());
149 149 setOpacity(m_series->opacity());
150 150 m_pointLabelsFormat = m_series->pointLabelsFormat();
151 151 m_pointLabelsVisible = m_series->pointLabelsVisible();
152 152 m_pointLabelsFont = m_series->pointLabelsFont();
153 153 m_pointLabelsColor = m_series->pointLabelsColor();
154 154 update();
155 155 }
156 156
157 157 void AreaChartItem::handleDomainUpdated()
158 158 {
159 159 if (m_upper) {
160 160 AbstractDomain* d = m_upper->domain();
161 161 d->setSize(domain()->size());
162 162 d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
163 163 m_upper->handleDomainUpdated();
164 164 }
165 165
166 166 if (m_lower) {
167 167 AbstractDomain* d = m_lower->domain();
168 168 d->setSize(domain()->size());
169 169 d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
170 170 m_lower->handleDomainUpdated();
171 171 }
172 172 }
173 173
174 174 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
175 175 {
176 176 Q_UNUSED(widget)
177 177 Q_UNUSED(option)
178 178 painter->save();
179 179 painter->setPen(m_linePen);
180 180 painter->setBrush(m_brush);
181 181 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
182 182 if (presenter()->chartType() == QChart::ChartTypePolar)
183 183 painter->setClipRegion(QRegion(clipRect.toRect(), QRegion::Ellipse));
184 184 else
185 185 painter->setClipRect(clipRect);
186 186 painter->drawPath(m_path);
187 187 if (m_pointsVisible) {
188 188 painter->setPen(m_pointPen);
189 189 painter->drawPoints(m_upper->geometryPoints());
190 190 if (m_lower)
191 191 painter->drawPoints(m_lower->geometryPoints());
192 192 }
193 193
194 194 // Draw series point label
195 195 if (m_pointLabelsVisible) {
196 196 static const QString xPointTag(QLatin1String("@xPoint"));
197 197 static const QString yPointTag(QLatin1String("@yPoint"));
198 198 const int labelOffset = 2;
199 199
200 200 painter->setFont(m_pointLabelsFont);
201 201 painter->setPen(QPen(m_pointLabelsColor));
202 202 QFontMetrics fm(painter->font());
203 203
204 QString pointLabel = m_pointLabelsFormat;
204 QString pointLabel;
205 205
206 206 if (m_series->upperSeries()) {
207 207 for (int i(0); i < m_series->upperSeries()->count(); i++) {
208 pointLabel = m_pointLabelsFormat;
208 209 pointLabel.replace(xPointTag,
209 210 presenter()->numberToString(m_series->upperSeries()->at(i).x()));
210 211 pointLabel.replace(yPointTag,
211 212 presenter()->numberToString(m_series->upperSeries()->at(i).y()));
212 213
213 214 // Position text in relation to the point
214 215 int pointLabelWidth = fm.width(pointLabel);
215 216 QPointF position(m_upper->geometryPoints().at(i));
216 217 position.setX(position.x() - pointLabelWidth / 2);
217 218 position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 - labelOffset);
218 219
219 220 painter->drawText(position, pointLabel);
220 221 }
221 222 }
222 223
223 224 if (m_series->lowerSeries()) {
224 225 for (int i(0); i < m_series->lowerSeries()->count(); i++) {
226 pointLabel = m_pointLabelsFormat;
225 227 pointLabel.replace(xPointTag,
226 228 presenter()->numberToString(m_series->lowerSeries()->at(i).x()));
227 229 pointLabel.replace(yPointTag,
228 230 presenter()->numberToString(m_series->lowerSeries()->at(i).y()));
229 231
230 232 // Position text in relation to the point
231 233 int pointLabelWidth = fm.width(pointLabel);
232 234 QPointF position(m_lower->geometryPoints().at(i));
233 235 position.setX(position.x() - pointLabelWidth / 2);
234 236 position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 - labelOffset);
235
236 237 painter->drawText(position, pointLabel);
237 238 }
238 239 }
239 240 }
240 241
241 242 painter->restore();
242 243 }
243 244
244 245 void AreaChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
245 246 {
246 247 emit pressed(m_upper->domain()->calculateDomainPoint(event->pos()));
247 248 m_lastMousePos = event->pos();
248 249 m_mousePressed = true;
249 250 ChartItem::mousePressEvent(event);
250 251 }
251 252
252 253 void AreaChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
253 254 {
254 255 emit hovered(domain()->calculateDomainPoint(event->pos()), true);
255 256 event->accept();
256 257 // QGraphicsItem::hoverEnterEvent(event);
257 258 }
258 259
259 260 void AreaChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
260 261 {
261 262 emit hovered(domain()->calculateDomainPoint(event->pos()), false);
262 263 event->accept();
263 264 // QGraphicsItem::hoverEnterEvent(event);
264 265 }
265 266
266 267 void AreaChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
267 268 {
268 269 emit released(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
269 270 if (m_mousePressed)
270 271 emit clicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
271 272 m_mousePressed = false;
272 273 ChartItem::mouseReleaseEvent(event);
273 274 }
274 275
275 276 void AreaChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
276 277 {
277 278 emit doubleClicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos));
278 279 ChartItem::mouseDoubleClickEvent(event);
279 280 }
280 281
281 282 #include "moc_areachartitem_p.cpp"
282 283
283 284 QT_CHARTS_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now