1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtCharts/QCategoryAxis>
31#include <private/qcategoryaxis_p.h>
32#include <private/chartcategoryaxisx_p.h>
33#include <private/chartcategoryaxisy_p.h>
34#include <private/polarchartcategoryaxisangular_p.h>
35#include <private/polarchartcategoryaxisradial_p.h>
36#include <QtCharts/QChart>
37#include <QtCore/QtMath>
38#include <QtCore/QDebug>
39
40QT_CHARTS_BEGIN_NAMESPACE
41/*!
42 \class QCategoryAxis
43 \inmodule QtCharts
44 \brief The QCategoryAxis class places named ranges on the axis.
45
46 This class can be used to explain the underlying data by adding labeled categories.
47 Unlike QBarCategoryAxis, QCategoryAxis allows the widths of the category ranges to
48 be specified freely.
49
50 Example code on how to use QCategoryAxis:
51 \image api_category_axis.png
52 \code
53 QChartView *chartView = new QChartView;
54 QLineSeries *series = new QLineSeries;
55 // ...
56 chartView->chart()->addSeries(series);
57
58 QCategoryAxis *axisY = new QCategoryAxis;
59 axisY->setMin(0);
60 axisY->setMax(52);
61 axisY->setStartValue(15);
62 axisY->append("First", 20);
63 axisY->append("Second", 37);
64 axisY->append("Third", 52);
65 chartView->chart()->setAxisY(axisY, series);
66 \endcode
67*/
68/*!
69 \qmltype CategoryAxis
70 \instantiates QCategoryAxis
71 \inqmlmodule QtCharts
72
73 \inherits AbstractAxis
74 \brief CategoryAxis places named ranges on the axis.
75
76 This type can be used to explain the underlying data by adding labeled categories.
77 The widths of the category ranges can be specified freely.
78
79 For example:
80 \image examples_qmlaxes3.png
81 \snippet qmlaxes/qml/qmlaxes/View3.qml 1
82*/
83
84/*!
85 \property QCategoryAxis::startValue
86 \brief The low end of the first category on the axis.
87*/
88/*!
89 \qmlproperty int CategoryAxis::startValue
90 The low end of the first category on the axis.
91*/
92
93/*!
94 \property QCategoryAxis::count
95 \brief The number of categories.
96*/
97/*!
98 \qmlproperty int CategoryAxis::count
99 The number of categories.
100*/
101
102/*!
103 \property QCategoryAxis::categoriesLabels
104 \brief The category labels as a string list.
105*/
106/*!
107 \qmlproperty StringList CategoryAxis::categoriesLabels
108 The category labels as a list of strings.
109*/
110
111/*!
112 \fn void QCategoryAxis::categoriesChanged()
113 This signal is emitted when the categories of the axis change.
114*/
115
116/*!
117 \enum QCategoryAxis::AxisLabelsPosition
118
119 This enum describes the position of the category labels.
120
121 \value AxisLabelsPositionCenter Labels are centered to category.
122 \value AxisLabelsPositionOnValue Labels are positioned to the high end limit of the category.
123 */
124/*!
125 \property QCategoryAxis::labelsPosition
126 \brief The position of the category labels. The labels in the beginning and in the end of the
127 axes may overlap other axes' labels when positioned on value.
128*/
129/*!
130 \qmlproperty enumeration CategoryAxis::labelsPosition
131
132 The position of the category labels. The labels in the beginning and in the end of the
133 axes may overlap other axes' labels when positioned on value.
134
135 \value CategoryAxis.AxisLabelsPositionCenter
136 Labels are centered to category.
137 \value CategoryAxis.AxisLabelsPositionOnValue
138 Labels are positioned to the high end limit of the category.
139*/
140
141
142/*!
143 Constructs an axis object that is a child of \a parent.
144*/
145QCategoryAxis::QCategoryAxis(QObject *parent):
146 QValueAxis(*new QCategoryAxisPrivate(this), parent)
147{
148}
149
150/*!
151 Destroys the object.
152*/
153QCategoryAxis::~QCategoryAxis()
154{
155 Q_D(QCategoryAxis);
156 if (d->m_chart)
157 d->m_chart->removeAxis(axis: this);
158}
159
160/*!
161 \internal
162*/
163QCategoryAxis::QCategoryAxis(QCategoryAxisPrivate &d, QObject *parent): QValueAxis(d, parent)
164{
165
166}
167
168/*!
169 \qmlmethod CategoryAxis::append(string label, real endValue)
170 Appends a new category to the axis with the label \a label. A category label has to be unique.
171 \a endValue specifies the high end limit of the category.
172 It has to be greater than the high end limit of the previous category.
173 Otherwise the method returns without adding a new category.
174*/
175/*!
176 Appends a new category to the axis with the label \a categoryLabel.
177 A category label has to be unique.
178 \a categoryEndValue specifies the high end limit of the category.
179 It has to be greater than the high end limit of the previous category.
180 Otherwise the method returns without adding a new category.
181*/
182void QCategoryAxis::append(const QString &categoryLabel, qreal categoryEndValue)
183{
184 Q_D(QCategoryAxis);
185
186 if (!d->m_categories.contains(str: categoryLabel)) {
187 if (d->m_categories.isEmpty()) {
188 Range range(d->m_categoryMinimum, categoryEndValue);
189 d->m_categoriesMap.insert(akey: categoryLabel, avalue: range);
190 d->m_categories.append(t: categoryLabel);
191 emit categoriesChanged();
192 } else if (categoryEndValue > endValue(categoryLabel: d->m_categories.last())) {
193 Range previousRange = d->m_categoriesMap.value(akey: d->m_categories.last());
194 d->m_categoriesMap.insert(akey: categoryLabel, avalue: Range(previousRange.second, categoryEndValue));
195 d->m_categories.append(t: categoryLabel);
196 emit categoriesChanged();
197 }
198 }
199}
200
201/*!
202 Sets \a min to be the low end limit of the first category on the axis.
203 If categories have already been added to the axis, the passed value must be less
204 than the high end value of the already defined first category range.
205 Otherwise nothing is done.
206*/
207void QCategoryAxis::setStartValue(qreal min)
208{
209 Q_D(QCategoryAxis);
210 if (d->m_categories.isEmpty()) {
211 d->m_categoryMinimum = min;
212 emit categoriesChanged();
213 } else {
214 Range range = d->m_categoriesMap.value(akey: d->m_categories.first());
215 if (min < range.second) {
216 d->m_categoriesMap.insert(akey: d->m_categories.first(), avalue: Range(min, range.second));
217 emit categoriesChanged();
218 }
219 }
220}
221
222/*!
223 Returns the low end limit of the category specified by \a categoryLabel.
224*/
225qreal QCategoryAxis::startValue(const QString &categoryLabel) const
226{
227 Q_D(const QCategoryAxis);
228 if (categoryLabel.isEmpty())
229 return d->m_categoryMinimum;
230 return d->m_categoriesMap.value(akey: categoryLabel).first;
231}
232
233/*!
234 Returns the high end limit of the category specified by \a categoryLabel.
235*/
236qreal QCategoryAxis::endValue(const QString &categoryLabel) const
237{
238 Q_D(const QCategoryAxis);
239 return d->m_categoriesMap.value(akey: categoryLabel).second;
240}
241
242/*!
243 \qmlmethod CategoryAxis::remove(string label)
244 Removes a category specified by the label \a label from the axis.
245*/
246/*!
247 Removes a category specified by the label \a categoryLabel from the axis.
248*/
249void QCategoryAxis::remove(const QString &categoryLabel)
250{
251 Q_D(QCategoryAxis);
252 int labelIndex = d->m_categories.indexOf(t: categoryLabel);
253
254 // check if such label exists
255 if (labelIndex != -1) {
256 d->m_categories.removeAt(i: labelIndex);
257 d->m_categoriesMap.remove(akey: categoryLabel);
258
259 // the range of the interval that follows (if exists) needs to be updated
260 if (labelIndex < d->m_categories.count()) {
261 QString label = d->m_categories.at(i: labelIndex);
262 Range range = d->m_categoriesMap.value(akey: label);
263
264 // set the range
265 if (labelIndex == 0) {
266 range.first = d->m_categoryMinimum;
267 d->m_categoriesMap.insert(akey: label, avalue: range);
268 } else {
269 range.first = d->m_categoriesMap.value(akey: d->m_categories.at(i: labelIndex - 1)).second;
270 d->m_categoriesMap.insert(akey: label, avalue: range);
271 }
272 }
273 emit categoriesChanged();
274 }
275}
276
277/*!
278 \qmlmethod CategoryAxis::replace(string oldLabel, string newLabel)
279 Replaces an existing category label specified by \a oldLabel with \a newLabel.
280 If the old label does not exist, the method returns without making any changes.
281*/
282/*!
283 Replaces an existing category label specified by \a oldLabel with \a newLabel.
284 If the old label does not exist, the method returns without making any changes.
285 */
286void QCategoryAxis::replaceLabel(const QString &oldLabel, const QString &newLabel)
287{
288 Q_D(QCategoryAxis);
289 int labelIndex = d->m_categories.indexOf(t: oldLabel);
290
291 // check if such label exists
292 if (labelIndex != -1) {
293 d->m_categories.replace(i: labelIndex, t: newLabel);
294 Range range = d->m_categoriesMap.value(akey: oldLabel);
295 d->m_categoriesMap.remove(akey: oldLabel);
296 d->m_categoriesMap.insert(akey: newLabel, avalue: range);
297 emit categoriesChanged();
298 }
299}
300
301/*!
302 Returns the list of the categories' labels.
303 */
304QStringList QCategoryAxis::categoriesLabels()
305{
306 Q_D(QCategoryAxis);
307 return d->m_categories;
308}
309
310/*!
311 Returns the number of categories.
312 */
313int QCategoryAxis::count() const
314{
315 Q_D(const QCategoryAxis);
316 return d->m_categories.count();
317}
318
319/*!
320 Returns the type of the axis.
321*/
322QAbstractAxis::AxisType QCategoryAxis::type() const
323{
324 return QAbstractAxis::AxisTypeCategory;
325}
326
327void QCategoryAxis::setLabelsPosition(QCategoryAxis::AxisLabelsPosition position)
328{
329 Q_D(QCategoryAxis);
330 if (d->m_labelsPosition != position) {
331 d->m_labelsPosition = position;
332 emit labelsPositionChanged(position);
333 }
334}
335
336QCategoryAxis::AxisLabelsPosition QCategoryAxis::labelsPosition() const
337{
338 Q_D(const QCategoryAxis);
339 return d->m_labelsPosition;
340}
341
342//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
343
344QCategoryAxisPrivate::QCategoryAxisPrivate(QCategoryAxis *q)
345 : QValueAxisPrivate(q),
346 m_categoryMinimum(0),
347 m_labelsPosition(QCategoryAxis::AxisLabelsPositionCenter)
348{
349
350}
351
352QCategoryAxisPrivate::~QCategoryAxisPrivate()
353{
354
355}
356
357int QCategoryAxisPrivate::ticksCount() const
358{
359 return m_categories.count() + 1;
360}
361
362void QCategoryAxisPrivate::initializeGraphics(QGraphicsItem *parent)
363{
364 Q_Q(QCategoryAxis);
365 ChartAxisElement *axis(0);
366 if (m_chart->chartType() == QChart::ChartTypeCartesian) {
367 if (orientation() == Qt::Vertical)
368 axis = new ChartCategoryAxisY(q,parent);
369 else if (orientation() == Qt::Horizontal)
370 axis = new ChartCategoryAxisX(q,parent);
371 }
372
373 if (m_chart->chartType() == QChart::ChartTypePolar) {
374 if (orientation() == Qt::Vertical)
375 axis = new PolarChartCategoryAxisRadial(q, parent);
376 if (orientation() == Qt::Horizontal)
377 axis = new PolarChartCategoryAxisAngular(q, parent);
378 }
379
380 m_item.reset(other: axis);
381 QAbstractAxisPrivate::initializeGraphics(parent);
382}
383
384QT_CHARTS_END_NAMESPACE
385
386#include "moc_qcategoryaxis.cpp"
387#include "moc_qcategoryaxis_p.cpp"
388

source code of qtcharts/src/charts/axis/categoryaxis/qcategoryaxis.cpp