##// END OF EJS Templates
Add possibility to set reverse values to axes...
Titta Heikkala -
r2781:7c9f8e5a27d8
parent child
Show More
@@ -183,6 +183,9 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
183 183 painter->setClipRegion(QRegion(clipRect.toRect(), QRegion::Ellipse));
184 184 else
185 185 painter->setClipRect(clipRect);
186
187 reversePainter(painter, clipRect);
188
186 189 painter->drawPath(m_path);
187 190 if (m_pointsVisible) {
188 191 painter->setPen(m_pointPen);
@@ -191,6 +194,8 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
191 194 painter->drawPoints(m_lower->geometryPoints());
192 195 }
193 196
197 reversePainter(painter, clipRect);
198
194 199 // Draw series point label
195 200 if (m_pointLabelsVisible) {
196 201 static const QString xPointTag(QLatin1String("@xPoint"));
@@ -214,9 +219,17 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
214 219 // Position text in relation to the point
215 220 int pointLabelWidth = fm.width(pointLabel);
216 221 QPointF position(m_upper->geometryPoints().at(i));
217 position.setX(position.x() - pointLabelWidth / 2);
218 position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 - labelOffset);
219
222 if (!seriesPrivate()->reverseXAxis())
223 position.setX(position.x() - pointLabelWidth / 2);
224 else
225 position.setX(domain()->size().width() - position.x() - pointLabelWidth / 2);
226 if (!seriesPrivate()->reverseYAxis()) {
227 position.setY(position.y() - m_series->upperSeries()->pen().width() / 2
228 - labelOffset);
229 } else {
230 position.setY(domain()->size().height() - position.y()
231 - m_series->upperSeries()->pen().width() / 2 - labelOffset);
232 }
220 233 painter->drawText(position, pointLabel);
221 234 }
222 235 }
@@ -232,8 +245,17 void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
232 245 // Position text in relation to the point
233 246 int pointLabelWidth = fm.width(pointLabel);
234 247 QPointF position(m_lower->geometryPoints().at(i));
235 position.setX(position.x() - pointLabelWidth / 2);
236 position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 - labelOffset);
248 if (!seriesPrivate()->reverseXAxis())
249 position.setX(position.x() - pointLabelWidth / 2);
250 else
251 position.setX(domain()->size().width() - position.x() - pointLabelWidth / 2);
252 if (!seriesPrivate()->reverseYAxis()) {
253 position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2
254 - labelOffset);
255 } else {
256 position.setY(domain()->size().height() - position.y()
257 - m_series->lowerSeries()->pen().width() / 2 - labelOffset);
258 }
237 259 painter->drawText(position, pointLabel);
238 260 }
239 261 }
@@ -91,6 +91,7 void ChartAxisElement::connectSlots()
91 91 QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&)));
92 92 QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool)));
93 93 QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal)));
94 QObject::connect(axis(), SIGNAL(reverseChanged(bool)), this, SLOT(handleReverseChanged(bool)));
94 95 }
95 96
96 97 void ChartAxisElement::handleArrowVisibleChanged(bool visible)
@@ -208,6 +209,14 void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
208 209 }
209 210 }
210 211
212 void ChartAxisElement::handleReverseChanged(bool reverse)
213 {
214 Q_UNUSED(reverse);
215
216 QGraphicsLayoutItem::updateGeometry();
217 presenter()->layout()->invalidate();
218 }
219
211 220 bool ChartAxisElement::isEmpty()
212 221 {
213 222 return axisGeometry().isEmpty()
@@ -123,6 +123,7 public Q_SLOTS:
123 123 void handleTitleTextChanged(const QString &title);
124 124 void handleTitleVisibleChanged(bool visible);
125 125 void handleRangeChanged(qreal min, qreal max);
126 void handleReverseChanged(bool reverse);
126 127
127 128 Q_SIGNALS:
128 129 void clicked();
@@ -102,10 +102,20 void HorizontalAxis::updateGeometry()
102 102 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
103 103
104 104 //grid line
105 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
105 if (axis()->isReverse()) {
106 gridItem->setLine(gridRect.right() - layout[i] + gridRect.left(), gridRect.top(),
107 gridRect.right() - layout[i] + gridRect.left(), gridRect.bottom());
108 } else {
109 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
110 }
106 111
107 112 //label text wrapping
108 QString text = labelList.at(i);
113 QString text;
114 if (axis()->isReverse() && axis()->type() != QAbstractAxis::AxisTypeCategory)
115 text = labelList.at(labelList.count() - i - 1);
116 else
117 text = labelList.at(i);
118
109 119 QRectF boundingRect;
110 120 // don't truncate empty labels
111 121 if (text.isEmpty()) {
@@ -130,18 +140,50 void HorizontalAxis::updateGeometry()
130 140
131 141 //ticks and label position
132 142 if (axis()->alignment() == Qt::AlignTop) {
133 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding());
134 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
143 if (axis()->isReverse()) {
144 labelItem->setPos(gridRect.right() - layout[layout.size() - i - 1]
145 + gridRect.left() - center.x(),
146 axisRect.bottom() - rect.height()
147 + (heightDiff / 2.0) - labelPadding());
148 tickItem->setLine(gridRect.right() + gridRect.left() - layout[i],
149 axisRect.bottom(),
150 gridRect.right() + gridRect.left() - layout[i],
151 axisRect.bottom() - labelPadding());
152 } else {
153 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height()
154 + (heightDiff / 2.0) - labelPadding());
155 tickItem->setLine(layout[i], axisRect.bottom(),
156 layout[i], axisRect.bottom() - labelPadding());
157 }
135 158 } else if (axis()->alignment() == Qt::AlignBottom) {
136 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding());
137 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
159 if (axis()->isReverse()) {
160 labelItem->setPos(gridRect.right() - layout[layout.size() - i - 1]
161 + gridRect.left() - center.x(),
162 axisRect.top() - (heightDiff / 2.0) + labelPadding());
163 tickItem->setLine(gridRect.right() + gridRect.left() - layout[i], axisRect.top(),
164 gridRect.right() + gridRect.left() - layout[i],
165 axisRect.top() + labelPadding());
166 } else {
167 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0)
168 + labelPadding());
169 tickItem->setLine(layout[i], axisRect.top(),
170 layout[i], axisRect.top() + labelPadding());
171 }
138 172 }
139 173
140 174 //label in between
141 175 bool forceHide = false;
142 176 if (intervalAxis() && (i + 1) != layout.size()) {
143 qreal leftBound = qMax(layout[i], gridRect.left());
144 qreal rightBound = qMin(layout[i + 1], gridRect.right());
177 qreal leftBound;
178 qreal rightBound;
179 if (axis()->isReverse()) {
180 leftBound = qMax(gridRect.right() + gridRect.left() - layout[i + 1],
181 gridRect.left());
182 rightBound = qMin(gridRect.right() + gridRect.left() - layout[i], gridRect.right());
183 } else {
184 leftBound = qMax(layout[i], gridRect.left());
185 rightBound = qMin(layout[i + 1], gridRect.right());
186 }
145 187 const qreal delta = rightBound - leftBound;
146 188 if (axis()->type() != QAbstractAxis::AxisTypeCategory) {
147 189 // Hide label in case visible part of the category at the grid edge is too narrow
@@ -163,7 +205,10 void HorizontalAxis::updateGeometry()
163 205 }
164 206 } else if (categoryAxis->labelsPosition()
165 207 == QCategoryAxis::AxisLabelsPositionOnValue) {
166 labelItem->setPos(rightBound - center.x(), labelItem->pos().y());
208 if (axis()->isReverse())
209 labelItem->setPos(leftBound - center.x(), labelItem->pos().y());
210 else
211 labelItem->setPos(rightBound - center.x(), labelItem->pos().y());
167 212 }
168 213 }
169 214 }
@@ -188,14 +233,29 void HorizontalAxis::updateGeometry()
188 233 qreal leftBound;
189 234 qreal rightBound;
190 235 if (i == 0) {
191 leftBound = gridRect.left();
192 rightBound = layout[0];
193 } else {
194 leftBound = layout[i];
195 if (i == layout.size() - 1)
236 if (axis()->isReverse()) {
237 leftBound = gridRect.right() + gridRect.left() - layout[i];
196 238 rightBound = gridRect.right();
197 else
198 rightBound = qMin(layout[i + 1], gridRect.right());
239 } else {
240 leftBound = gridRect.left();
241 rightBound = layout[0];
242 }
243 } else {
244 if (axis()->isReverse()) {
245 rightBound = gridRect.right() + gridRect.left() - layout[i];
246 if (i == layout.size() - 1) {
247 leftBound = gridRect.left();
248 } else {
249 leftBound = qMax(gridRect.right() + gridRect.left() - layout[i + 1],
250 gridRect.left());
251 }
252 } else {
253 leftBound = layout[i];
254 if (i == layout.size() - 1)
255 rightBound = gridRect.right();
256 else
257 rightBound = qMin(layout[i + 1], gridRect.right());
258 }
199 259 }
200 260 if (leftBound < gridRect.left())
201 261 leftBound = gridRect.left();
@@ -246,6 +246,23 QT_CHARTS_BEGIN_NAMESPACE
246 246 */
247 247
248 248 /*!
249 \property QAbstractAxis::reverse
250 The reverse property defines if reverse axis is used. By default the value is false.
251
252 Reverse axis is supported with line, spline, scatter and area series with cartesian chart.
253 All axes of the same orientation attached to same series must be reversed if one is reversed or
254 the behavior is undefined.
255 */
256 /*!
257 \qmlproperty alignment AbstractAxis::reverse
258 The reverse property defines if reverse axis is used. By default the value is false.
259
260 Reverse axis is supported with line, spline, scatter and area series with cartesian chart.
261 All axes of the same orientation attached to same series must be reversed if one is reversed or
262 the behavior is undefined.
263 */
264
265 /*!
249 266 \fn void QAbstractAxis::visibleChanged(bool visible)
250 267 Visibility of the axis has changed to \a visible.
251 268 */
@@ -831,6 +848,19 Qt::Alignment QAbstractAxis::alignment() const
831 848 return d_ptr->alignment();
832 849 }
833 850
851 bool QAbstractAxis::isReverse() const
852 {
853 return d_ptr->m_reverse;
854 }
855
856 void QAbstractAxis::setReverse(bool reverse)
857 {
858 if (d_ptr->m_reverse != reverse && type() != QAbstractAxis::AxisTypeBarCategory) {
859 d_ptr->m_reverse = reverse;
860 emit reverseChanged(reverse);
861 }
862 }
863
834 864 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
835 865
836 866 QAbstractAxisPrivate::QAbstractAxisPrivate(QAbstractAxis *q)
@@ -855,7 +885,8 QAbstractAxisPrivate::QAbstractAxisPrivate(QAbstractAxis *q)
855 885 m_shadesPen(QChartPrivate::defaultPen()),
856 886 m_shadesBrush(QChartPrivate::defaultBrush()),
857 887 m_shadesOpacity(1.0),
858 m_dirty(false)
888 m_dirty(false),
889 m_reverse(false)
859 890 {
860 891 }
861 892
@@ -61,6 +61,7 class QT_CHARTS_EXPORT QAbstractAxis : public QObject
61 61 Q_PROPERTY(Qt::Orientation orientation READ orientation)
62 62 //aligment
63 63 Q_PROPERTY(Qt::Alignment alignment READ alignment)
64 Q_PROPERTY(bool reverse READ isReverse WRITE setReverse NOTIFY reverseChanged)
64 65
65 66 public:
66 67
@@ -145,6 +146,10 public:
145 146 void setMax(const QVariant &max);
146 147 void setRange(const QVariant &min, const QVariant &max);
147 148
149 //reverse handling
150 void setReverse(bool reverse = true);
151 bool isReverse() const;
152
148 153 Q_SIGNALS:
149 154 void visibleChanged(bool visible);
150 155 void linePenChanged(const QPen &pen);
@@ -166,6 +171,7 Q_SIGNALS:
166 171 void shadesBorderColorChanged(QColor color);
167 172 void shadesPenChanged(const QPen &pen);
168 173 void shadesBrushChanged(const QBrush &brush);
174 void reverseChanged(bool reverse);
169 175
170 176 protected:
171 177 QScopedPointer<QAbstractAxisPrivate> d_ptr;
@@ -118,6 +118,8 private:
118 118
119 119 bool m_dirty;
120 120
121 bool m_reverse;
122
121 123 friend class QAbstractAxis;
122 124 friend class ChartDataSet;
123 125 friend class ChartPresenter;
@@ -104,10 +104,20 void VerticalAxis::updateGeometry()
104 104 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
105 105
106 106 //grid line
107 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
107 if (axis()->isReverse()) {
108 gridItem->setLine(gridRect.left(), gridRect.top() + gridRect.bottom() - layout[i],
109 gridRect.right(), gridRect.top() + gridRect.bottom() - layout[i]);
110 } else {
111 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
112 }
108 113
109 114 //label text wrapping
110 QString text = labelList.at(i);
115 QString text;
116 if (axis()->isReverse() && axis()->type() != QAbstractAxis::AxisTypeCategory)
117 text = labelList.at(labelList.count() - i - 1);
118 else
119 text = labelList.at(i);
120
111 121 QRectF boundingRect;
112 122 // don't truncate empty labels
113 123 if (text.isEmpty()) {
@@ -132,19 +142,54 void VerticalAxis::updateGeometry()
132 142
133 143 //ticks and label position
134 144 if (axis()->alignment() == Qt::AlignLeft) {
135 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
136 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
145 if (axis()->isReverse()) {
146 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0)
147 - labelPadding(),
148 gridRect.top() + gridRect.bottom()
149 - layout[layout.size() - i - 1] - center.y());
150 tickItem->setLine(axisRect.right() - labelPadding(),
151 gridRect.top() + gridRect.bottom() - layout[i],
152 axisRect.right(),
153 gridRect.top() + gridRect.bottom() - layout[i]);
154 } else {
155 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0)
156 - labelPadding(),
157 layout[i] - center.y());
158 tickItem->setLine(axisRect.right() - labelPadding(), layout[i],
159 axisRect.right(), layout[i]);
160 }
137 161 } else if (axis()->alignment() == Qt::AlignRight) {
138 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
139 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
162 if (axis()->isReverse()) {
163 tickItem->setLine(axisRect.left(),
164 gridRect.top() + gridRect.bottom() - layout[i],
165 axisRect.left() + labelPadding(),
166 gridRect.top() + gridRect.bottom() - layout[i]);
167 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0),
168 gridRect.top() + gridRect.bottom()
169 - layout[layout.size() - i - 1] - center.y());
170 } else {
171 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0),
172 layout[i] - center.y());
173 tickItem->setLine(axisRect.left(), layout[i],
174 axisRect.left() + labelPadding(), layout[i]);
175 }
140 176 }
141 177
142 178 //label in between
143 179 bool forceHide = false;
144 180 bool labelOnValue = false;
145 181 if (intervalAxis() && (i + 1) != layout.size()) {
146 qreal lowerBound = qMin(layout[i], gridRect.bottom());
147 qreal upperBound = qMax(layout[i + 1], gridRect.top());
182 qreal lowerBound;
183 qreal upperBound;
184 if (axis()->isReverse()) {
185 lowerBound = qMax(gridRect.top() + gridRect.bottom() - layout[i + 1],
186 gridRect.top());
187 upperBound = qMin(gridRect.top() + gridRect.bottom() - layout[i],
188 gridRect.bottom());
189 } else {
190 lowerBound = qMin(layout[i], gridRect.bottom());
191 upperBound = qMax(layout[i + 1], gridRect.top());
192 }
148 193 const qreal delta = lowerBound - upperBound;
149 194 if (axis()->type() != QAbstractAxis::AxisTypeCategory) {
150 195 // Hide label in case visible part of the category at the grid edge is too narrow
@@ -168,13 +213,21 void VerticalAxis::updateGeometry()
168 213 } else if (categoryAxis->labelsPosition()
169 214 == QCategoryAxis::AxisLabelsPositionOnValue) {
170 215 labelOnValue = true;
171 labelItem->setPos(labelItem->pos().x(), upperBound - center.y());
216 if (axis()->isReverse()) {
217 labelItem->setPos(labelItem->pos().x(), gridRect.top() + gridRect.bottom()
218 - layout[i + 1] - center.y());
219 } else {
220 labelItem->setPos(labelItem->pos().x(), upperBound - center.y());
221 }
172 222 }
173 223 }
174 224 }
175 225
176 226 //label overlap detection - compensate one pixel for rounding errors
177 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
227 if (axis()->isReverse()) {
228 if (forceHide)
229 labelItem->setVisible(false);
230 } else if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
178 231 ((labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom()
179 232 && !labelOnValue) ||
180 233 (labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0) && !labelOnValue)) {
@@ -195,14 +248,29 void VerticalAxis::updateGeometry()
195 248 qreal lowerBound;
196 249 qreal upperBound;
197 250 if (i == 0) {
198 lowerBound = gridRect.bottom();
199 upperBound = layout[0];
200 } else {
201 lowerBound = layout[i];
202 if (i == layout.size() - 1)
251 if (axis()->isReverse()) {
203 252 upperBound = gridRect.top();
204 else
205 upperBound = qMax(layout[i + 1], gridRect.top());
253 lowerBound = gridRect.top() + gridRect.bottom() - layout[i];
254 } else {
255 lowerBound = gridRect.bottom();
256 upperBound = layout[0];
257 }
258 } else {
259 if (axis()->isReverse()) {
260 upperBound = gridRect.top() + gridRect.bottom() - layout[i];
261 if (i == layout.size() - 1) {
262 lowerBound = gridRect.bottom();
263 } else {
264 lowerBound = qMax(gridRect.top() + gridRect.bottom() - layout[i + 1],
265 gridRect.top());
266 }
267 } else {
268 lowerBound = layout[i];
269 if (i == layout.size() - 1)
270 upperBound = gridRect.top();
271 else
272 upperBound = qMax(layout[i + 1], gridRect.top());
273 }
206 274
207 275 }
208 276 if (lowerBound > gridRect.bottom())
@@ -40,6 +40,19 void ChartItem::handleDomainUpdated()
40 40 qWarning() << __FUNCTION__<< "Slot not implemented";
41 41 }
42 42
43 void ChartItem::reversePainter(QPainter *painter, const QRectF &clipRect)
44 {
45 if (m_series->reverseXAxis()) {
46 painter->translate(clipRect.width(), 0);
47 painter->scale(-1, 1);
48 }
49
50 if (m_series->reverseYAxis()) {
51 painter->translate(0, clipRect.height());
52 painter->scale(1, -1);
53 }
54 }
55
43 56 #include "moc_chartitem_p.cpp"
44 57
45 58 QT_CHARTS_END_NAMESPACE
@@ -44,6 +44,9 public:
44 44 public Q_SLOTS:
45 45 virtual void handleDomainUpdated();
46 46
47 void reversePainter(QPainter *painter, const QRectF &clipRect);
48 QAbstractSeriesPrivate* seriesPrivate() const {return m_series;}
49
47 50 protected:
48 51 bool m_validData;
49 52 private:
@@ -363,6 +363,8 void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
363 363 painter->setClipRect(clipRect);
364 364 }
365 365
366 reversePainter(painter, clipRect);
367
366 368 if (m_pointsVisible) {
367 369 painter->setBrush(m_linePen.color());
368 370 painter->drawPath(m_linePath);
@@ -378,6 +380,8 void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
378 380 }
379 381 }
380 382
383 reversePainter(painter, clipRect);
384
381 385 if (m_pointLabelsVisible)
382 386 m_series->d_func()->drawSeriesPointLabels(painter, m_points, m_linePen.width() / 2);
383 387
@@ -318,6 +318,40 void QAbstractSeriesPrivate::initializeAnimations(QChart::AnimationOptions optio
318 318 Q_UNUSED(options);
319 319 }
320 320
321 bool QAbstractSeriesPrivate::reverseXAxis()
322 {
323 bool reverseXAxis = false;
324 if (m_axes.size() != 0 && !(m_chart->chartType() == QChart::ChartTypePolar)) {
325 int i = 0;
326 while (i < m_axes.size()) {
327 if (m_axes.at(i)->orientation() == Qt::Horizontal && m_axes.at(i)->isReverse()) {
328 reverseXAxis = true;
329 break;
330 }
331 i++;
332 }
333 }
334
335 return reverseXAxis;
336 }
337
338 bool QAbstractSeriesPrivate::reverseYAxis()
339 {
340 bool reverseYAxis = false;
341 if (m_axes.size() != 0 && !(m_chart->chartType() == QChart::ChartTypePolar)) {
342 int i = 0;
343 while (i < m_axes.size()) {
344 if (m_axes.at(i)->orientation() == Qt::Vertical && m_axes.at(i)->isReverse()) {
345 reverseYAxis = true;
346 break;
347 }
348 i++;
349 }
350 }
351
352 return reverseYAxis;
353 }
354
321 355 #include "moc_qabstractseries.cpp"
322 356 #include "moc_qabstractseries_p.cpp"
323 357
@@ -77,6 +77,8 public:
77 77 ChartPresenter *presenter() const;
78 78
79 79 QChart* chart() { return m_chart; }
80 bool reverseXAxis();
81 bool reverseYAxis();
80 82
81 83 Q_SIGNALS:
82 84 void countChanged();
@@ -86,6 +88,7 protected:
86 88 QChart *m_chart;
87 89 QScopedPointer<ChartItem> m_item;
88 90 QList<QAbstractAxis*> m_axes;
91
89 92 private:
90 93 QScopedPointer<AbstractDomain> m_domain;
91 94 QString m_name;
@@ -169,7 +169,17 void ScatterChartItem::updateGeometry()
169 169 // if it was caused by an insert, but this shouldn't be a problem as the points are
170 170 // fake anyway. After remove animation stops, geometry is updated to correct one.
171 171 m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i));
172 item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2);
172 QPointF position;
173 if (seriesPrivate()->reverseXAxis())
174 position.setX(domain()->size().width() - point.x() - rect.width() / 2);
175 else
176 position.setX(point.x() - rect.width() / 2);
177 if (seriesPrivate()->reverseYAxis())
178 position.setY(domain()->size().height() - point.y() - rect.height() / 2);
179 else
180 position.setY(point.y() - rect.height() / 2);
181 item->setPos(position);
182
173 183
174 184 if (!m_visible || offGridStatus.at(i))
175 185 item->setVisible(false);
@@ -446,6 +446,8 void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
446 446 painter->setClipRect(clipRect);
447 447 }
448 448
449 reversePainter(painter, clipRect);
450
449 451 painter->drawPath(m_path);
450 452
451 453 if (m_pointsVisible) {
@@ -456,6 +458,8 void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
456 458 painter->drawPoints(geometryPoints());
457 459 }
458 460
461 reversePainter(painter, clipRect);
462
459 463 if (m_pointLabelsVisible)
460 464 m_series->d_func()->drawSeriesPointLabels(painter, m_points, m_linePen.width() / 2);
461 465
@@ -851,8 +851,14 void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QP
851 851 // Position text in relation to the point
852 852 int pointLabelWidth = fm.width(pointLabel);
853 853 QPointF position(points.at(i));
854 position.setX(position.x() - pointLabelWidth / 2);
855 position.setY(position.y() - labelOffset);
854 if (!reverseXAxis())
855 position.setX(position.x() - pointLabelWidth / 2);
856 else
857 position.setX(domain()->size().width() - position.x() - pointLabelWidth / 2);
858 if (!reverseYAxis())
859 position.setY(position.y() - labelOffset);
860 else
861 position.setY(domain()->size().height() - position.y() - labelOffset);
856 862
857 863 painter->drawText(position, pointLabel);
858 864 }
@@ -303,6 +303,8 public:
303 303
304 304 // QtCharts 2.1
305 305 qmlRegisterType<DeclarativeCategoryAxis, 1>(uri, 2, 1, "CategoryAxis");
306 qmlRegisterUncreatableType<QAbstractAxis>(uri, 2, 1, "AbstractAxis",
307 QLatin1String("Trying to create uncreatable: AbstractAxis. Use specific types of axis instead."));
306 308 }
307 309
308 310 };
@@ -1497,9 +1497,13 Module {
1497 1497 Component {
1498 1498 name: "QtCharts::QAbstractAxis"
1499 1499 prototype: "QObject"
1500 exports: ["QtCharts/AbstractAxis 1.0", "QtCharts/AbstractAxis 2.0"]
1500 exports: [
1501 "QtCharts/AbstractAxis 1.0",
1502 "QtCharts/AbstractAxis 2.0",
1503 "QtCharts/AbstractAxis 2.1"
1504 ]
1501 1505 isCreatable: false
1502 exportMetaObjectRevisions: [0, 0]
1506 exportMetaObjectRevisions: [0, 0, 0]
1503 1507 Property { name: "visible"; type: "bool" }
1504 1508 Property { name: "lineVisible"; type: "bool" }
1505 1509 Property { name: "linePen"; type: "QPen" }
@@ -1522,6 +1526,7 Module {
1522 1526 Property { name: "titleFont"; type: "QFont" }
1523 1527 Property { name: "orientation"; type: "Qt::Orientation"; isReadonly: true }
1524 1528 Property { name: "alignment"; type: "Qt::Alignment"; isReadonly: true }
1529 Property { name: "reverse"; type: "bool" }
1525 1530 Signal {
1526 1531 name: "visibleChanged"
1527 1532 Parameter { name: "visible"; type: "bool" }
@@ -1602,6 +1607,10 Module {
1602 1607 name: "shadesBrushChanged"
1603 1608 Parameter { name: "brush"; type: "QBrush" }
1604 1609 }
1610 Signal {
1611 name: "reverseChanged"
1612 Parameter { name: "reverse"; type: "bool" }
1613 }
1605 1614 }
1606 1615 Component {
1607 1616 name: "QtCharts::QAbstractBarSeries"
@@ -56,6 +56,7 private slots:
56 56
57 57 void interval_data();
58 58 void interval();
59 void reverse();
59 60
60 61 private:
61 62 QCategoryAxis* m_categoryaxis;
@@ -110,6 +111,8 void tst_QCategoryAxis::qcategoryaxis()
110 111
111 112 QVERIFY(!qFuzzyCompare(m_categoryaxis->max(), 0));
112 113 QVERIFY(!qFuzzyCompare(m_categoryaxis->min(), 0));
114
115 QCOMPARE(m_categoryaxis->isReverse(), false);
113 116 }
114 117
115 118 void tst_QCategoryAxis::max_raw_data()
@@ -313,6 +316,22 void tst_QCategoryAxis::labels_position()
313 316 QCOMPARE(spy.count(), 1);
314 317 }
315 318
319 void tst_QCategoryAxis::reverse()
320 {
321 QSignalSpy spy(m_categoryaxis, SIGNAL(reverseChanged(bool)));
322 QCOMPARE(m_categoryaxis->isReverse(), false);
323
324 m_categoryaxis->setReverse();
325 QCOMPARE(m_categoryaxis->isReverse(), true);
326
327 m_chart->setAxisX(m_categoryaxis, m_series);
328 QCOMPARE(spy.count(), 1);
329
330 m_view->show();
331 QTest::qWaitForWindowShown(m_view);
332 QCOMPARE(m_categoryaxis->isReverse(), true);
333 }
334
316 335 QTEST_MAIN(tst_QCategoryAxis)
317 336 #include "tst_qcategoryaxis.moc"
318 337
@@ -52,6 +52,7 private slots:
52 52 void range();
53 53 void range_animation_data();
54 54 void range_animation();
55 void reverse();
55 56
56 57 private:
57 58 QDateTimeAxis *m_dateTimeAxisX;
@@ -113,6 +114,9 void tst_QDateTimeAxis::qdatetimeaxis()
113 114
114 115 QVERIFY(m_dateTimeAxisX->max().toMSecsSinceEpoch() != 0);
115 116 QVERIFY(m_dateTimeAxisX->min().toMSecsSinceEpoch() != 0);
117
118 QCOMPARE(m_dateTimeAxisX->isReverse(), false);
119 QCOMPARE(m_dateTimeAxisY->isReverse(), false);
116 120 }
117 121
118 122 void tst_QDateTimeAxis::max_raw_data()
@@ -307,6 +311,20 void tst_QDateTimeAxis::range_animation()
307 311 range();
308 312 }
309 313
314 void tst_QDateTimeAxis::reverse()
315 {
316 QSignalSpy spy(m_dateTimeAxisX, SIGNAL(reverseChanged(bool)));
317 QCOMPARE(m_dateTimeAxisX->isReverse(), false);
318
319 m_dateTimeAxisX->setReverse();
320 QCOMPARE(m_dateTimeAxisX->isReverse(), true);
321 QCOMPARE(spy.count(), 1);
322
323 m_view->show();
324 QTest::qWaitForWindowShown(m_view);
325 QCOMPARE(m_dateTimeAxisX->isReverse(), true);
326 }
327
310 328 QTEST_MAIN(tst_QDateTimeAxis)
311 329 #include "tst_qdatetimeaxis.moc"
312 330
@@ -57,6 +57,7 private slots:
57 57 void autoscale_data();
58 58 void autoscale();
59 59 void zoom();
60 void reverse();
60 61
61 62 private:
62 63 QLogValueAxis* m_logvaluesaxis;
@@ -109,6 +110,8 void tst_QLogValueAxis::qlogvalueaxis()
109 110
110 111 QCOMPARE(m_logvaluesaxis->max(), (qreal)100);
111 112 QCOMPARE(m_logvaluesaxis->min(), (qreal)1);
113
114 QCOMPARE(m_logvaluesaxis->isReverse(), false);
112 115 }
113 116
114 117 void tst_QLogValueAxis::max_raw_data()
@@ -313,8 +316,6 void tst_QLogValueAxis::noautoscale()
313 316 QCOMPARE(spy0.count(), 1);
314 317 QCOMPARE(spy1.count(), 1);
315 318 QCOMPARE(spy2.count(), 1);
316
317 m_chart->setAxisX(m_logvaluesaxis, m_series);
318 319 m_view->show();
319 320 QTest::qWaitForWindowShown(m_view);
320 321 QCOMPARE(m_logvaluesaxis->min(), min);
@@ -381,6 +382,20 void tst_QLogValueAxis::zoom()
381 382
382 383 }
383 384
385 void tst_QLogValueAxis::reverse()
386 {
387 QSignalSpy spy(m_logvaluesaxis, SIGNAL(reverseChanged(bool)));
388 QCOMPARE(m_logvaluesaxis->isReverse(), false);
389
390 m_logvaluesaxis->setReverse();
391 QCOMPARE(m_logvaluesaxis->isReverse(), true);
392 QCOMPARE(spy.count(), 1);
393
394 m_view->show();
395 QTest::qWaitForWindowShown(m_view);
396 QCOMPARE(m_logvaluesaxis->isReverse(), true);
397 }
398
384 399 QTEST_MAIN(tst_QLogValueAxis)
385 400 #include "tst_qlogvalueaxis.moc"
386 401
@@ -46,12 +46,28 Rectangle {
46 46
47 47 function test_properties() {
48 48 compare(lineSeries1.axisY.labelsPosition, CategoryAxis.AxisLabelsPositionCenter);
49 verify(lineSeries1.axisX.reverse == false, "AxisX reverse");
50 verify(lineSeries1.axisY.reverse == false, "AxisY reverse");
51
52 // Modify properties
53 lineSeries1.axisX.reverse = true;
54 verify(lineSeries1.axisX.reverse == true, "AxisX reverse");
55 lineSeries1.axisX.reverse = false;
56 verify(lineSeries1.axisX.reverse == false, "AxisX reverse");
49 57 }
50 58
51 59 function test_signals() {
52 60 axisLabelsPositionSpy.clear();
61 reverseChangedSpy.clear();
53 62 lineSeries1.axisY.labelsPosition = CategoryAxis.AxisLabelsPositionOnValue;
54 compare(axisLabelsPositionSpy.count, 1, "onLabelsPositionChanged")
63 compare(axisLabelsPositionSpy.count, 1, "onLabelsPositionChanged");
64
65 lineSeries1.axisX.reverse = true;
66 compare(reverseChangedSpy.count, 1, "onReverseChanged");
67
68 // restore original values
69 lineSeries1.axisX.reverse = false;
70 compare(reverseChangedSpy.count, 2, "onReverseChanged");
55 71 }
56 72 }
57 73
@@ -93,5 +109,10 Rectangle {
93 109 XYPoint { x: 0; y: 0 }
94 110 XYPoint { x: 5; y: 5 }
95 111 }
112 SignalSpy {
113 id: reverseChangedSpy
114 target: axisX
115 signalName: "reverseChanged"
116 }
96 117 }
97 118 }
@@ -40,10 +40,16 Rectangle {
40 40 verify(axisX.tickCount == 5, "AxisX tick count");
41 41 verify(axisY.tickCount == 5, "AxisY tick count");
42 42 verify(axisX.labelFormat == "", "label format");
43 verify(axisX.reverse == false, "AxisX reverse");
44 verify(axisY.reverse == false, "AxisY reverse");
43 45
44 46 // Modify properties
45 47 axisX.tickCount = 3;
46 48 verify(axisX.tickCount == 3, "set tick count");
49 axisX.reverse = true;
50 verify(axisX.reverse == true, "AxisX reverse");
51 axisX.reverse = false;
52 verify(axisX.reverse == false, "AxisX reverse");
47 53 }
48 54
49 55 function test_functions() {
@@ -67,6 +73,8 Rectangle {
67 73 function test_signals() {
68 74 minChangedSpy.clear();
69 75 maxChangedSpy.clear();
76 reverseChangedSpy.clear();
77
70 78 axisX.min = 2;
71 79 compare(minChangedSpy.count, 1, "onMinChanged");
72 80 compare(maxChangedSpy.count, 0, "onMaxChanged");
@@ -75,11 +83,16 Rectangle {
75 83 compare(minChangedSpy.count, 1, "onMinChanged");
76 84 compare(maxChangedSpy.count, 1, "onMaxChanged");
77 85
86 axisX.reverse = true;
87 compare(reverseChangedSpy.count, 1, "onReverseChanged");
88
78 89 // restore original values
79 90 axisX.min = 0;
80 91 axisX.max = 10;
92 axisX.reverse = false;
81 93 compare(minChangedSpy.count, 2, "onMinChanged");
82 94 compare(maxChangedSpy.count, 2, "onMaxChanged");
95 compare(reverseChangedSpy.count, 2, "onReverseChanged");
83 96 }
84 97 }
85 98
@@ -110,5 +123,10 Rectangle {
110 123 target: axisX
111 124 signalName: "maxChanged"
112 125 }
126 SignalSpy {
127 id: reverseChangedSpy
128 target: axisX
129 signalName: "reverseChanged"
130 }
113 131 }
114 132 }
@@ -59,6 +59,7 private slots:
59 59 void noautoscale();
60 60 void autoscale_data();
61 61 void autoscale();
62 void reverse();
62 63
63 64 private:
64 65 QValueAxis* m_valuesaxis;
@@ -113,6 +114,8 void tst_QValueAxis::qvalueaxis()
113 114 QVERIFY(!qFuzzyCompare(m_valuesaxis->max(), 0));
114 115 QVERIFY(!qFuzzyCompare(m_valuesaxis->min(), 0));
115 116 QCOMPARE(m_valuesaxis->tickCount(), 5);
117
118 QCOMPARE(m_valuesaxis->isReverse(), false);
116 119 }
117 120
118 121 void tst_QValueAxis::max_raw_data()
@@ -406,6 +409,22 void tst_QValueAxis::autoscale()
406 409 QVERIFY2(qFuzzyCompare(m_valuesaxis->max(), 100), "Max not equal");
407 410 }
408 411
412 void tst_QValueAxis::reverse()
413 {
414 QSignalSpy spy(m_valuesaxis, SIGNAL(reverseChanged(bool)));
415 QCOMPARE(m_valuesaxis->isReverse(), false);
416
417 m_valuesaxis->setReverse();
418 QCOMPARE(m_valuesaxis->isReverse(), true);
419
420 m_chart->setAxisX(m_valuesaxis, m_series);
421 QCOMPARE(spy.count(), 1);
422
423 m_view->show();
424 QTest::qWaitForWindowShown(m_view);
425 QCOMPARE(m_valuesaxis->isReverse(), true);
426 }
427
409 428 QTEST_MAIN(tst_QValueAxis)
410 429 #include "tst_qvalueaxis.moc"
411 430
@@ -23,23 +23,13 ChartView {
23 23 id: chartView
24 24 title: "chart axes"
25 25
26 // TODO: Do we need a property for orientation or properties "axisX" and "axisY" on ChartView
27 // to make an axis the default axis for all series with no other axes defined...?
28 // ValueAxis {
29 // orientation: ValueAxis.AxisX
30 // min: 0
31 // max: 10
32 // }
33 // axisX: ValueAxis {
34 // min: 0
35 // max: 10
36 // }
37 // ...Now that we don't have this implementation, the following axes won't have any affect:
38 26 ValueAxis {
27 id: valueAxisX
39 28 min: 0
40 29 max: 10
41 30 }
42 31 ValueAxis {
32 id: valueAxisY
43 33 min: 0
44 34 max: 5
45 35 }
@@ -51,6 +41,8 ChartView {
51 41 XYPoint { x: 2; y: 2 }
52 42 XYPoint { x: 3; y: 3 }
53 43 XYPoint { x: 4; y: 4 }
44 axisX: valueAxisX
45 axisY: valueAxisY
54 46 }
55 47
56 48 ScatterSeries {
@@ -64,6 +56,8 ChartView {
64 56 XYPoint { x: 2; y: 2 }
65 57 XYPoint { x: 3; y: 3 }
66 58 XYPoint { x: 4; y: 4 }
59 axisX: valueAxisX
60 axisY: valueAxisY
67 61 }
68 62
69 63 // Component.onCompleted: {
@@ -24,10 +24,12 ChartView {
24 24 title: "chart axes reverted"
25 25
26 26 ValueAxis {
27 id: valueAxisX
27 28 min: 0
28 29 max: 10
29 30 }
30 31 ValueAxis {
32 id: valueAxisY
31 33 min: 0
32 34 max: 5
33 35 }
@@ -43,6 +45,8 ChartView {
43 45 XYPoint { x: 2; y: 2 }
44 46 XYPoint { x: 3; y: 3 }
45 47 XYPoint { x: 4; y: 4 }
48 axisX: valueAxisX
49 axisY: valueAxisY
46 50 }
47 51
48 52 LineSeries {
@@ -52,5 +56,7 ChartView {
52 56 XYPoint { x: 2; y: 2 }
53 57 XYPoint { x: 3; y: 3 }
54 58 XYPoint { x: 4; y: 4 }
59 axisX: valueAxisX
60 axisY: valueAxisY
55 61 }
56 62 }
@@ -34,6 +34,8 ChartView {
34 34 XYPoint { x: 2.9; y: 4.9 }
35 35 XYPoint { x: 3.4; y: 3.0 }
36 36 XYPoint { x: 4.1; y: 3.3 }
37 axisX: axisX
38 axisY: axisY
37 39 }
38 40
39 41 onVisibleChanged: console.log("chart.onVisibleChanged: " + visible);
@@ -65,6 +67,7 ChartView {
65 67 }
66 68
67 69 ValueAxis{
70 id: axisX
68 71 onColorChanged: console.log("axisX.onColorChanged: " + color);
69 72 onLabelsVisibleChanged: console.log("axisX.onLabelsVisibleChanged: " + visible);
70 73 onLabelsColorChanged: console.log("axisX.onLabelsColorChanged: " + color);
@@ -75,9 +78,11 ChartView {
75 78 onShadesBorderColorChanged: console.log("axisX.onShadesBorderColorChanged: " + color);
76 79 onMinChanged: console.log("axisX.onMinChanged: " + min);
77 80 onMaxChanged: console.log("axisX.onMaxChanged: " + max);
81 onReverseChanged: console.log("axisX.onReverseChanged: " + reverse);
78 82 }
79 83
80 84 ValueAxis{
85 id: axisY
81 86 onColorChanged: console.log("axisY.onColorChanged: " + color);
82 87 onLabelsVisibleChanged: console.log("axisY.onLabelsVisibleChanged: " + visible);
83 88 onLabelsColorChanged: console.log("axisY.onLabelsColorChanged: " + color);
@@ -88,6 +93,7 ChartView {
88 93 onShadesBorderColorChanged: console.log("axisY.onShadesBorderColorChanged: " + color);
89 94 onMinChanged: console.log("axisY.onMinChanged: " + min);
90 95 onMaxChanged: console.log("axisY.onMaxChanged: " + max);
96 onReverseChanged: console.log("axisY.onReverseChanged: " + reverse);
91 97 }
92 98
93 99 Rectangle {
@@ -105,6 +105,10 Row {
105 105
106 106 onClicked: axis.tickCount--;
107 107 }
108 Button {
109 text: "axis reverse"
110 onClicked: axis.reverse = !axis.reverse;
111 }
108 112
109 113 FontEditor {
110 114 id: fontEditor
General Comments 0
You need to be logged in to leave comments. Login now