1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
5
6#include <QtCharts/QAbstractBarSeries>
7#include <private/qabstractbarseries_p.h>
8#include <QtCharts/QBarSet>
9#include <private/qbarset_p.h>
10#include <private/abstractdomain_p.h>
11#include <private/chartdataset_p.h>
12#include <private/charttheme_p.h>
13#include <QtCharts/QValueAxis>
14#include <QtCharts/QBarCategoryAxis>
15#include <QtCharts/QBarLegendMarker>
16#include <private/baranimation_p.h>
17#include <private/abstractbarchartitem_p.h>
18#include <private/qchart_p.h>
19
20QT_BEGIN_NAMESPACE
21
22/*!
23 \class QAbstractBarSeries
24 \inmodule QtCharts
25 \brief The QAbstractBarSeries class is an abstract parent class for all bar series classes.
26
27 In bar charts, bars are defined as bar sets that contain one data value for each category.
28 The position of a bar is specified by the category and its height by the data value. Bar
29 series that contain multiple bar sets group together bars that belong to the same category.
30 The way the bars are displayed is determined by the subclass of this class chosen to create
31 the bar chart.
32
33 If a QValueAxis is used instead of QBarCategoryAxis for the main bar axis, the bars are
34 grouped around the index value of the category.
35
36 See the \l {Charts with Widgets Gallery} to learn how to use the QBarSeries class to create a simple bar chart.
37 \image examples_barchart.png
38
39 \sa QBarSet, QBarSeries, QStackedBarSeries, QPercentBarSeries
40 \sa QHorizontalBarSeries, QHorizontalStackedBarSeries, QHorizontalPercentBarSeries
41*/
42/*!
43 \qmltype AbstractBarSeries
44 \nativetype QAbstractBarSeries
45 \inqmlmodule QtCharts
46
47 \inherits AbstractSeries
48
49 \brief An abstract parent type for all bar series types.
50
51 In bar charts, bars are defined as bar sets that contain one data value for each category.
52 The position of a bar is specified by the category and its height by the data value. Bar
53 series that contain multiple bar sets group together bars that belong to the same category.
54 The way the bars are displayed is determined by the type chosen to create the bar chart:
55 BarSeries, StackedBarSeries, PercentBarSeries, HorizontalBarSeries, HorizontalStackedBarSeries,
56 or HorizontalPercentBarSeries.
57
58 If a ValueAxis type is used instead of a BarCategoryAxis type for the main bar axis, the
59 bars are grouped around the index value of the category.
60
61 The following QML code snippet shows how to use the BarSeries and BarCategoryAxis type
62 to create a simple bar chart:
63 \snippet qmlchartsgallery/qml/BarSeries.qml 1
64
65 \beginfloatleft
66 \image examples_qmlchart6.png
67 \endfloat
68 \clearfloat
69*/
70
71/*!
72 \qmlproperty AbstractAxis AbstractBarSeries::axisX
73 The x-axis used for the series. If you leave both axisX and axisXTop undefined, a
74 BarCategoryAxis is created for the series.
75 \sa axisXTop
76*/
77
78/*!
79 \qmlproperty AbstractAxis AbstractBarSeries::axisY
80 The y-axis used for the series. If you leave both axisY and axisYRight undefined, a
81 ValueAxis is created for the series.
82 \sa axisYRight
83*/
84
85/*!
86 \qmlproperty AbstractAxis AbstractBarSeries::axisXTop
87 The x-axis used for the series, drawn on top of the chart view.
88
89 \note You can only provide either axisX or axisXTop, but not both.
90 \sa axisX
91*/
92
93/*!
94 \qmlproperty AbstractAxis AbstractBarSeries::axisYRight
95 The y-axis used for the series, drawn to the right of the chart view.
96
97 \note You can only provide either axisY or axisYRight, but not both.
98 \sa axisY
99*/
100
101/*!
102 \property QAbstractBarSeries::barWidth
103 \brief The width of the bars of the series.
104
105 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
106 values are treated as zero. Setting the width to zero means that the width of the bar on the
107 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
108 using the x-axis scale.
109
110 \note When used with QBarSeries, this value specifies the width of a group of bars instead of
111 that of a single bar.
112 \sa QBarSeries
113*/
114/*!
115 \qmlproperty real AbstractBarSeries::barWidth
116 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
117 values are treated as zero. Setting the width to zero means that the width of the bar on the
118 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
119 using the x-axis scale.
120
121 \note When used with the BarSeries type, this value specifies the width of a group of bars
122 instead of that of a single bar.
123*/
124
125/*!
126 \property QAbstractBarSeries::count
127 \brief The number of bar sets in a bar series.
128*/
129/*!
130 \qmlproperty int AbstractBarSeries::count
131 The number of bar sets in a bar series.
132*/
133
134/*!
135 \property QAbstractBarSeries::labelsVisible
136 \brief The visibility of the labels in a bar series.
137*/
138/*!
139 \qmlproperty bool AbstractBarSeries::labelsVisible
140 The visibility of the labels in a bar series.
141*/
142
143/*!
144 \property QAbstractBarSeries::labelsFormat
145 \brief The format used for showing labels in a bar series.
146
147 QAbstractBarSeries supports the following format tag:
148 \table
149 \row
150 \li @value \li The value of the bar
151 \endtable
152
153 For example, the following usage of the format tags would produce labels that show the value
154 followed by the unit (u):
155 \code
156 series->setLabelsFormat("@value u");
157 \endcode
158
159 By default, the labels show the value of the bar. For the percent bar series, \e % is added
160 after the value. The labels are shown on the plot area, if the bars are close to each other,
161 the labels may overlap.
162
163 \sa labelsVisible, labelsPosition, labelsPrecision
164*/
165/*!
166 \qmlproperty string AbstractBarSeries::labelsFormat
167 The format used for showing labels in a bar series.
168
169 \sa QAbstractBarSeries::labelsFormat, labelsVisible, labelsPosition
170*/
171/*!
172 \fn void QAbstractBarSeries::labelsFormatChanged(const QString &format)
173 This signal is emitted when the \a format of data value labels changes.
174*/
175
176/*!
177 \enum QAbstractBarSeries::LabelsPosition
178
179 This enum value describes the position of the data value labels:
180
181 \value LabelsCenter Label is located in the center of the bar.
182 \value LabelsInsideEnd Label is located inside the bar at the top.
183 \value LabelsInsideBase Label is located inside the bar at the bottom.
184 \value LabelsOutsideEnd Label is located outside the bar at the top.
185 */
186
187/*!
188 \property QAbstractBarSeries::labelsPosition
189 \brief The position of value labels.
190
191 \sa labelsVisible, labelsFormat
192*/
193/*!
194 \qmlproperty enumeration AbstractBarSeries::labelsPosition
195
196 The position of the data value labels:
197
198 \value AbstractBarSeries.LabelsCenter
199 Label is located in the center of the bar.
200 \value AbstractBarSeries.LabelsInsideEnd
201 Label is located inside the bar at the top.
202 \value AbstractBarSeries.LabelsInsideBase
203 Label is located inside the bar at the bottom.
204 \value AbstractBarSeries.LabelsOutsideEnd
205 Label is located outside the bar at the top.
206
207 \sa labelsVisible, labelsFormat
208*/
209/*!
210 \fn void QAbstractBarSeries::labelsPositionChanged(QAbstractBarSeries::LabelsPosition position)
211 This signal is emitted when the \a position of value labels changes.
212*/
213
214/*!
215 \property QAbstractBarSeries::labelsAngle
216 \brief The angle of the value labels in degrees.
217*/
218/*!
219 \qmlproperty real AbstractBarSeries::labelsAngle
220 The angle of the value labels in degrees.
221*/
222/*!
223 \fn void QAbstractBarSeries::labelsAngleChanged(qreal angle)
224 This signal is emitted when the \a angle of the value labels changes.
225*/
226
227/*!
228 \property QAbstractBarSeries::labelsPrecision
229 \brief The maximum amount of significant digits shown in value labels.
230
231 Default value is 6.
232*/
233/*!
234 \qmlproperty real AbstractBarSeries::labelsPrecision
235 The maximum amount of significant digits shown in value labels.
236
237 Default value is 6.
238*/
239/*!
240 \fn void QAbstractBarSeries::labelsPrecisionChanged(int precision)
241 This signal is emitted when the \a precision of the value labels changes.
242*/
243
244/*!
245 \fn void QAbstractBarSeries::clicked(int index, QBarSet *barset)
246 This signal is emitted when the user clicks the bar specified by \a index
247 in the bar set specified by \a barset.
248*/
249/*!
250 \qmlsignal AbstractBarSeries::clicked(int index, BarSet barset)
251 This signal is emitted when the user clicks the bar specified by \a index
252 in the bar set specified by \a barset.
253
254 The corresponding signal handler is \c onClicked.
255*/
256
257/*!
258 \fn void QAbstractBarSeries::pressed(int index, QBarSet *barset)
259 This signal is emitted when the user clicks the bar specified by \a index
260 in the bar set specified by \a barset and holds down the mouse button.
261*/
262/*!
263 \qmlsignal AbstractBarSeries::pressed(int index, BarSet barset)
264 This signal is emitted when the user clicks the bar specified by \a index
265 in the bar set specified by \a barset and holds down the mouse button.
266
267 The corresponding signal handler is \c onPressed.
268*/
269
270/*!
271 \fn void QAbstractBarSeries::released(int index, QBarSet *barset)
272 This signal is emitted when the user releases the mouse press on the bar
273 specified by \a index in the bar set specified by \a barset.
274*/
275/*!
276 \qmlsignal AbstractBarSeries::released(int index, BarSet barset)
277 This signal is emitted when the user releases the mouse press on the bar
278 specified by \a index in the bar set specified by \a barset.
279
280 The corresponding signal handler is \c onReleased.
281*/
282
283/*!
284 \fn void QAbstractBarSeries::doubleClicked(int index, QBarSet *barset)
285 This signal is emitted when the user double-clicks the bar specified by \a index
286 in the bar set specified by \a barset.
287*/
288/*!
289 \qmlsignal AbstractBarSeries::doubleClicked(int index, BarSet barset)
290 This signal is emitted when the user double-clicks the bar specified by \a index
291 in the bar set specified by \a barset.
292
293 The corresponding signal handler is \c onDoubleClicked.
294*/
295
296/*!
297 \fn void QAbstractBarSeries::hovered(bool status, int index, QBarSet* barset)
298
299 This signal is emitted when a mouse is hovered over the bar specified by \a index in the
300 bar set specified by \a barset. When the mouse moves over the bar, \a status turns \c true,
301 and when the mouse moves away again, it turns \c false.
302*/
303/*!
304 \qmlsignal AbstractBarSeries::hovered(bool status, int index, BarSet barset)
305
306 This signal is emitted when a mouse is hovered over the bar specified by \a index in the
307 bar set specified by \a barset. When the mouse moves over the bar, \a status turns \c true,
308 and when the mouse moves away again, it turns \c false.
309
310 The corresponding signal handler is \c onHovered.
311*/
312
313/*!
314 \fn void QAbstractBarSeries::countChanged()
315 This signal is emitted when the number of bar sets is changed, for example by append() or
316 remove().
317*/
318
319/*!
320 \fn void QAbstractBarSeries::labelsVisibleChanged()
321 This signal is emitted when the labels' visibility changes.
322 \sa isLabelsVisible(), setLabelsVisible()
323*/
324
325/*!
326 \fn void QAbstractBarSeries::barsetsAdded(const QList<QBarSet *> &sets)
327 This signal is emitted when the bar sets specified by \a sets are added to the series.
328 \sa append(), insert()
329*/
330/*!
331 \qmlsignal AbstractBarSeries::barsetsAdded()
332 This signal is emitted when bar sets are added to the series.
333
334 The corresponding signal handler is \c onBarsetsAdded.
335*/
336
337/*!
338 \fn void QAbstractBarSeries::barsetsRemoved(const QList<QBarSet *> &sets)
339 This signal is emitted when the bar sets specified by \a sets are removed from the series.
340 \sa remove()
341*/
342/*!
343 \qmlsignal AbstractBarSeries::barsetsRemoved()
344 This signal is emitted when bar sets are removed from the series.
345
346 The corresponding signal handler is \c onBarsetsRemoved.
347*/
348
349/*!
350 \qmlmethod BarSet AbstractBarSeries::at(int index)
351 Returns the bar set at \a index. Returns null if the index is not valid.
352*/
353
354/*!
355 \qmlmethod BarSet AbstractBarSeries::append(string label, VariantList values)
356 Adds a new bar set with \a label and \a values to the index. \a values is
357 a list of real values.
358
359 For example:
360 \code
361 myBarSeries.append("set 1", [0, 0.2, 0.2, 0.5, 0.4, 1.5, 0.9]);
362 \endcode
363*/
364
365/*!
366 \qmlmethod BarSet AbstractBarSeries::insert(int index, string label, VariantList values)
367 Adds a new bar set with \a label and \a values to \a index. \a values can be a list
368 of real values or a list of XYPoint types.
369
370 If the index value is equal to or less than zero, the new bar set is prepended to the bar
371 series. If the index value is equal to or greater than the number of bar sets in the bar
372 series, the new bar set is appended to the bar series.
373
374 \sa append()
375*/
376
377/*!
378 \qmlmethod bool AbstractBarSeries::remove(BarSet barset)
379 Removes the bar set specified by \a barset from the series. Returns \c true if successful,
380 \c false otherwise.
381*/
382
383/*!
384 \qmlmethod AbstractBarSeries::clear()
385 Removes all bar sets from the series.
386*/
387
388/*!
389 Removes the abstract bar series and the bar sets owned by it.
390*/
391QAbstractBarSeries::~QAbstractBarSeries()
392{
393
394}
395
396/*!
397 \internal
398*/
399QAbstractBarSeries::QAbstractBarSeries(QAbstractBarSeriesPrivate &o, QObject *parent)
400 : QAbstractSeries(o, parent)
401{
402 Q_D(QAbstractSeries);
403 QObject::connect(sender: this, SIGNAL(countChanged()), receiver: d, SIGNAL(countChanged()));
404}
405
406/*!
407 Sets the width of the bars of the series to \a width.
408*/
409void QAbstractBarSeries::setBarWidth(qreal width)
410{
411 Q_D(QAbstractBarSeries);
412 d->setBarWidth(width);
413}
414
415/*!
416 Returns the width of the bars of the series.
417 \sa setBarWidth()
418*/
419qreal QAbstractBarSeries::barWidth() const
420{
421 Q_D(const QAbstractBarSeries);
422 return d->barWidth();
423}
424
425/*!
426 Adds a set of bars specified by \a set to the bar series and takes ownership of it. If the set
427 is null or it already belongs to the series, it will not be appended.
428 Returns \c true if appending succeeded.
429*/
430bool QAbstractBarSeries::append(QBarSet *set)
431{
432 Q_D(QAbstractBarSeries);
433 bool success = d->append(set);
434 if (success) {
435 QList<QBarSet *> sets;
436 sets.append(t: set);
437 set->setParent(this);
438 emit barsetsAdded(sets);
439 emit countChanged();
440 }
441 return success;
442}
443
444/*!
445 Removes the bar set specified by \a set from the series and permanently deletes it if
446 the removal succeeds. Returns \c true if the set was removed.
447*/
448bool QAbstractBarSeries::remove(QBarSet *set)
449{
450 Q_D(QAbstractBarSeries);
451 bool success = d->remove(set);
452 if (success) {
453 QList<QBarSet *> sets;
454 sets.append(t: set);
455 set->setParent(0);
456 emit barsetsRemoved(sets);
457 emit countChanged();
458 delete set;
459 set = 0;
460 }
461 return success;
462}
463
464/*!
465 Takes a single \a set from the series. Does not delete the bar set object.
466 \note The series remains the barset's parent object. You must set the
467 parent object to take full ownership.
468
469 Returns \c true if the take operation succeeds.
470*/
471bool QAbstractBarSeries::take(QBarSet *set)
472{
473 Q_D(QAbstractBarSeries);
474 bool success = d->remove(set);
475 if (success) {
476 QList<QBarSet *> sets;
477 sets.append(t: set);
478 emit barsetsRemoved(sets);
479 emit countChanged();
480 }
481 return success;
482}
483
484/*!
485 Adds a list of bar sets specified by \a sets to a bar series and takes ownership of the sets.
486 Returns \c true if all sets were appended successfully. If any of the sets is null or was
487 previously appended to the series, nothing is appended and this function returns \c false.
488 If any of the sets appears in the list more than once, nothing is appended and this function
489 returns \c false.
490*/
491bool QAbstractBarSeries::append(const QList<QBarSet *> &sets)
492{
493 Q_D(QAbstractBarSeries);
494 if (!d->append(sets))
495 return false;
496
497 for (auto *set : sets)
498 set->setParent(this);
499
500 emit barsetsAdded(sets);
501 emit countChanged();
502
503 return true;
504}
505
506/*!
507 Inserts a bar set specified by \a set to a series at the position specified by \a index
508 and takes ownership of the set. If the set is null or already belongs to the series, it will
509 not be appended. Returns \c true if inserting succeeds.
510*/
511bool QAbstractBarSeries::insert(int index, QBarSet *set)
512{
513 Q_D(QAbstractBarSeries);
514 bool success = d->insert(index, set);
515 if (success) {
516 QList<QBarSet *> sets;
517 sets.append(t: set);
518 emit barsetsAdded(sets);
519 emit countChanged();
520 }
521 return success;
522}
523
524/*!
525 Removes all bar sets from the series and permanently deletes them.
526*/
527void QAbstractBarSeries::clear()
528{
529 Q_D(QAbstractBarSeries);
530 QList<QBarSet *> sets = barSets();
531 bool success = d->remove(sets);
532 if (success) {
533 emit barsetsRemoved(sets);
534 emit countChanged();
535 foreach (QBarSet *set, sets)
536 delete set;
537 }
538}
539
540/*!
541 Returns the number of bar sets in a bar series.
542*/
543int QAbstractBarSeries::count() const
544{
545 Q_D(const QAbstractBarSeries);
546 return d->m_barSets.size();
547}
548
549/*!
550 Returns a list of bar sets in a bar series. Keeps the ownership of the bar sets.
551 */
552QList<QBarSet *> QAbstractBarSeries::barSets() const
553{
554 Q_D(const QAbstractBarSeries);
555 return d->m_barSets;
556}
557
558/*!
559 Sets the visibility of labels in a bar series to \a visible.
560*/
561void QAbstractBarSeries::setLabelsVisible(bool visible)
562{
563 Q_D(QAbstractBarSeries);
564 if (d->m_labelsVisible != visible) {
565 d->setLabelsVisible(visible);
566 emit labelsVisibleChanged();
567 }
568}
569
570/*!
571 Returns the visibility of labels.
572*/
573bool QAbstractBarSeries::isLabelsVisible() const
574{
575 Q_D(const QAbstractBarSeries);
576 return d->m_labelsVisible;
577}
578
579void QAbstractBarSeries::setLabelsFormat(const QString &format)
580{
581 Q_D(QAbstractBarSeries);
582 if (d->m_labelsFormat != format) {
583 d->m_labelsFormat = format;
584 d->setLabelsDirty(true);
585 emit labelsFormatChanged(format);
586 }
587}
588
589QString QAbstractBarSeries::labelsFormat() const
590{
591 Q_D(const QAbstractBarSeries);
592 return d->m_labelsFormat;
593}
594
595void QAbstractBarSeries::setLabelsAngle(qreal angle)
596{
597 Q_D(QAbstractBarSeries);
598 if (d->m_labelsAngle != angle) {
599 d->m_labelsAngle = angle;
600 d->setLabelsDirty(true);
601 emit labelsAngleChanged(angle);
602 }
603}
604
605qreal QAbstractBarSeries::labelsAngle() const
606{
607 Q_D(const QAbstractBarSeries);
608 return d->m_labelsAngle;
609}
610
611void QAbstractBarSeries::setLabelsPosition(QAbstractBarSeries::LabelsPosition position)
612{
613 Q_D(QAbstractBarSeries);
614 if (d->m_labelsPosition != position) {
615 d->m_labelsPosition = position;
616 emit labelsPositionChanged(position);
617 }
618}
619
620QAbstractBarSeries::LabelsPosition QAbstractBarSeries::labelsPosition() const
621{
622 Q_D(const QAbstractBarSeries);
623 return d->m_labelsPosition;
624}
625
626void QAbstractBarSeries::setLabelsPrecision(int precision)
627{
628 Q_D(QAbstractBarSeries);
629 if (d->m_labelsPrecision != precision) {
630 d->m_labelsPrecision = precision;
631 d->setLabelsDirty(true);
632 emit labelsPrecisionChanged(precision);
633 }
634}
635
636int QAbstractBarSeries::labelsPrecision() const
637{
638 Q_D(const QAbstractBarSeries);
639 return d->m_labelsPrecision;
640}
641
642///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
643
644QAbstractBarSeriesPrivate::QAbstractBarSeriesPrivate(QAbstractBarSeries *q) :
645 QAbstractSeriesPrivate(q),
646 m_barWidth(0.5), // Default value is 50% of category width
647 m_labelsVisible(false),
648 m_visible(true),
649 m_blockBarUpdate(false),
650 m_labelsFormat(),
651 m_labelsPosition(QAbstractBarSeries::LabelsCenter),
652 m_labelsAngle(0),
653 m_labelsPrecision(6),
654 m_visualsDirty(true),
655 m_labelsDirty(true)
656{
657}
658
659int QAbstractBarSeriesPrivate::categoryCount() const
660{
661 // No categories defined. return count of longest set.
662 int count = 0;
663 for (int i = 0; i < m_barSets.size(); i++) {
664 if (m_barSets.at(i)->count() > count)
665 count = m_barSets.at(i)->count();
666 }
667
668 return count;
669}
670
671void QAbstractBarSeriesPrivate::setBarWidth(qreal width)
672{
673 if (width < 0.0)
674 width = 0.0;
675 m_barWidth = width;
676 emit updatedLayout();
677}
678
679qreal QAbstractBarSeriesPrivate::barWidth() const
680{
681 return m_barWidth;
682}
683
684QBarSet *QAbstractBarSeriesPrivate::barsetAt(int index)
685{
686 return m_barSets.at(i: index);
687}
688
689void QAbstractBarSeriesPrivate::setVisible(bool visible)
690{
691 m_visible = visible;
692 emit visibleChanged();
693}
694
695void QAbstractBarSeriesPrivate::setLabelsVisible(bool visible)
696{
697 m_labelsVisible = visible;
698 emit labelsVisibleChanged(visible);
699}
700
701qreal QAbstractBarSeriesPrivate::min()
702{
703 if (m_barSets.size() <= 0)
704 return 0;
705
706 qreal min = INT_MAX;
707
708 for (int i = 0; i < m_barSets.size(); i++) {
709 int categoryCount = m_barSets.at(i)->count();
710 for (int j = 0; j < categoryCount; j++) {
711 qreal temp = m_barSets.at(i)->at(index: j);
712 if (temp < min)
713 min = temp;
714 }
715 }
716 return min;
717}
718
719qreal QAbstractBarSeriesPrivate::max()
720{
721 if (m_barSets.size() <= 0)
722 return 0;
723
724 qreal max = INT_MIN;
725
726 for (int i = 0; i < m_barSets.size(); i++) {
727 int categoryCount = m_barSets.at(i)->count();
728 for (int j = 0; j < categoryCount; j++) {
729 qreal temp = m_barSets.at(i)->at(index: j);
730 if (temp > max)
731 max = temp;
732 }
733 }
734
735 return max;
736}
737
738qreal QAbstractBarSeriesPrivate::valueAt(int set, int category)
739{
740 if ((set < 0) || (set >= m_barSets.size()))
741 return 0; // No set, no value.
742 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
743 return 0; // No category, no value.
744
745 return m_barSets.at(i: set)->at(index: category);
746}
747
748qreal QAbstractBarSeriesPrivate::percentageAt(int set, int category)
749{
750 if ((set < 0) || (set >= m_barSets.size()))
751 return 0; // No set, no value.
752 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
753 return 0; // No category, no value.
754
755 qreal value = m_barSets.at(i: set)->at(index: category);
756 qreal sum = categorySum(category);
757 if (qFuzzyCompare(p1: sum, p2: 0))
758 return 0;
759
760 return value / sum;
761}
762
763qreal QAbstractBarSeriesPrivate::categorySum(int category)
764{
765 qreal sum(0);
766 int count = m_barSets.size(); // Count sets
767 for (int set = 0; set < count; set++) {
768 if (category < m_barSets.at(i: set)->count())
769 sum += m_barSets.at(i: set)->at(index: category);
770 }
771 return sum;
772}
773
774qreal QAbstractBarSeriesPrivate::absoluteCategorySum(int category)
775{
776 qreal sum(0);
777 int count = m_barSets.size(); // Count sets
778 for (int set = 0; set < count; set++) {
779 if (category < m_barSets.at(i: set)->count())
780 sum += qAbs(t: m_barSets.at(i: set)->at(index: category));
781 }
782 return sum;
783}
784
785qreal QAbstractBarSeriesPrivate::maxCategorySum()
786{
787 qreal max = INT_MIN;
788 int count = categoryCount();
789 for (int i = 0; i < count; i++) {
790 qreal sum = categorySum(category: i);
791 if (sum > max)
792 max = sum;
793 }
794 return max;
795}
796
797qreal QAbstractBarSeriesPrivate::minX()
798{
799 if (m_barSets.size() <= 0)
800 return 0;
801
802 qreal min = INT_MAX;
803
804 for (int i = 0; i < m_barSets.size(); i++) {
805 int categoryCount = m_barSets.at(i)->count();
806 for (int j = 0; j < categoryCount; j++) {
807 qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(i: j).x();
808 if (temp < min)
809 min = temp;
810 }
811 }
812 return min;
813}
814
815qreal QAbstractBarSeriesPrivate::maxX()
816{
817 if (m_barSets.size() <= 0)
818 return 0;
819
820 qreal max = INT_MIN;
821
822 for (int i = 0; i < m_barSets.size(); i++) {
823 int categoryCount = m_barSets.at(i)->count();
824 for (int j = 0; j < categoryCount; j++) {
825 qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(i: j).x();
826 if (temp > max)
827 max = temp;
828 }
829 }
830
831 return max;
832}
833
834qreal QAbstractBarSeriesPrivate::categoryTop(int category)
835{
836 // Returns top (sum of all positive values) of category.
837 // Returns 0, if all values are negative
838 qreal top(0);
839 int count = m_barSets.size();
840 for (int set = 0; set < count; set++) {
841 if (category < m_barSets.at(i: set)->count()) {
842 qreal temp = m_barSets.at(i: set)->at(index: category);
843 if (temp > 0) {
844 top += temp;
845 }
846 }
847 }
848 return top;
849}
850
851qreal QAbstractBarSeriesPrivate::categoryBottom(int category)
852{
853 // Returns bottom (sum of all negative values) of category
854 // Returns 0, if all values are positive
855 qreal bottom(0);
856 int count = m_barSets.size();
857 for (int set = 0; set < count; set++) {
858 if (category < m_barSets.at(i: set)->count()) {
859 qreal temp = m_barSets.at(i: set)->at(index: category);
860 if (temp < 0) {
861 bottom += temp;
862 }
863 }
864 }
865 return bottom;
866}
867
868qreal QAbstractBarSeriesPrivate::top()
869{
870 // Returns top of all categories
871 qreal top(0);
872 int count = categoryCount();
873 for (int i = 0; i < count; i++) {
874 qreal temp = categoryTop(category: i);
875 if (temp > top)
876 top = temp;
877 }
878 return top;
879}
880
881qreal QAbstractBarSeriesPrivate::bottom()
882{
883 // Returns bottom of all categories
884 qreal bottom(0);
885 int count = categoryCount();
886 for (int i = 0; i < count; i++) {
887 qreal temp = categoryBottom(category: i);
888 if (temp < bottom)
889 bottom = temp;
890 }
891 return bottom;
892}
893
894bool QAbstractBarSeriesPrivate::blockBarUpdate()
895{
896 return m_blockBarUpdate;
897}
898
899qreal QAbstractBarSeriesPrivate::labelsAngle() const
900{
901 return m_labelsAngle;
902}
903
904void QAbstractBarSeriesPrivate::initializeDomain()
905{
906 qreal minX(domain()->minX());
907 qreal minY(domain()->minY());
908 qreal maxX(domain()->maxX());
909 qreal maxY(domain()->maxY());
910
911 qreal seriesMinX = this->minX();
912 qreal seriesMaxX = this->maxX();
913 qreal y = max();
914 minX = qMin(a: minX, b: seriesMinX - (qreal)0.5);
915 minY = qMin(a: minY, b: y);
916 maxX = qMax(a: maxX, b: seriesMaxX + (qreal)0.5);
917 maxY = qMax(a: maxY, b: y);
918
919 domain()->setRange(minX, maxX, minY, maxY);
920}
921
922QList<QLegendMarker*> QAbstractBarSeriesPrivate::createLegendMarkers(QLegend* legend)
923{
924 Q_Q(QAbstractBarSeries);
925 QList<QLegendMarker*> markers;
926
927 const auto barSets = q->barSets();
928 for (QBarSet *set : barSets) {
929 QBarLegendMarker* marker = new QBarLegendMarker(q,set,legend);
930 markers << marker;
931 }
932 return markers;
933}
934
935
936bool QAbstractBarSeriesPrivate::append(QBarSet *set)
937{
938 if ((m_barSets.contains(t: set)) || (set == 0))
939 return false; // Fail if set is already in list or set is null.
940
941 m_barSets.append(t: set);
942 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
943 context: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
944 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
945 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
946 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
947 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
948 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
949 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
950 connect(sender: set, signal: &QBarSet::selectedBarsChanged,
951 context: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
952
953 emit restructuredBars(); // this notifies barchartitem
954 return true;
955}
956
957bool QAbstractBarSeriesPrivate::remove(QBarSet *set)
958{
959 if (!m_barSets.contains(t: set))
960 return false; // Fail if set is not in list
961
962 m_barSets.removeOne(t: set);
963 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
964 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
965 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
966 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
967 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
968 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
969 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
970 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
971 disconnect(sender: set, signal: &QBarSet::selectedBarsChanged,
972 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
973
974 emit restructuredBars(); // this notifies barchartitem
975 return true;
976}
977
978bool QAbstractBarSeriesPrivate::append(const QList<QBarSet *> &sets)
979{
980 for (auto *set : sets) {
981 if ((set == 0) || (m_barSets.contains(t: set)))
982 return false; // Fail if any of the sets is null or is already appended.
983 if (sets.count(t: set) != 1)
984 return false; // Also fail if same set is more than once in given list.
985 }
986
987 for (auto *set : sets) {
988 m_barSets.append(t: set);
989 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
990 context: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
991 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
992 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
993 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
994 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
995 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
996 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
997 connect(sender: set, signal: &QBarSet::selectedBarsChanged,
998 context: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
999 }
1000
1001 emit restructuredBars(); // this notifies barchartitem
1002 return true;
1003}
1004
1005bool QAbstractBarSeriesPrivate::remove(const QList<QBarSet *> &sets)
1006{
1007 if (sets.size() == 0)
1008 return false;
1009
1010 foreach (QBarSet *set, sets) {
1011 if ((set == 0) || (!m_barSets.contains(t: set)))
1012 return false; // Fail if any of the sets is null or is not in series
1013 if (sets.count(t: set) != 1)
1014 return false; // Also fail if same set is more than once in given list.
1015 }
1016
1017 foreach (QBarSet *set, sets) {
1018 m_barSets.removeOne(t: set);
1019 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
1020 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1021 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
1022 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
1023 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
1024 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
1025 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
1026 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
1027 disconnect(sender: set, signal: &QBarSet::selectedBarsChanged,
1028 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1029 }
1030
1031 emit restructuredBars(); // this notifies barchartitem
1032
1033 return true;
1034}
1035
1036bool QAbstractBarSeriesPrivate::insert(int index, QBarSet *set)
1037{
1038 if ((m_barSets.contains(t: set)) || (set == 0))
1039 return false; // Fail if set is already in list or set is null.
1040
1041 m_barSets.insert(i: index, t: set);
1042 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
1043 context: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1044 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
1045 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
1046 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
1047 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
1048 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
1049 context: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
1050 disconnect(sender: set, signal: &QBarSet::selectedBarsChanged,
1051 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1052
1053 emit restructuredBars(); // this notifies barchartitem
1054 return true;
1055}
1056
1057void QAbstractBarSeriesPrivate::initializeAxes()
1058{
1059 Q_Q(QAbstractBarSeries);
1060
1061 foreach(QAbstractAxis* axis, m_axes) {
1062 if (axis->type() == QAbstractAxis::AxisTypeBarCategory) {
1063 switch (q->type()) {
1064 case QAbstractSeries::SeriesTypeHorizontalBar:
1065 case QAbstractSeries::SeriesTypeHorizontalPercentBar:
1066 case QAbstractSeries::SeriesTypeHorizontalStackedBar:
1067 if (axis->orientation() == Qt::Vertical)
1068 populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis));
1069 break;
1070 case QAbstractSeries::SeriesTypeBar:
1071 case QAbstractSeries::SeriesTypePercentBar:
1072 case QAbstractSeries::SeriesTypeStackedBar:
1073 case QAbstractSeries::SeriesTypeBoxPlot:
1074 case QAbstractSeries::SeriesTypeCandlestick:
1075 if (axis->orientation() == Qt::Horizontal)
1076 populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis));
1077 break;
1078 default:
1079 qWarning() << "Unexpected series type";
1080 break;
1081 }
1082 }
1083 }
1084
1085 // Make sure series animations are reset when axes change
1086 AbstractBarChartItem *item = qobject_cast<AbstractBarChartItem *>(object: m_item.get());
1087 if (item)
1088 item->resetAnimation();
1089}
1090
1091QAbstractAxis::AxisType QAbstractBarSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
1092{
1093 Q_Q(const QAbstractBarSeries);
1094
1095 switch (q->type()) {
1096 case QAbstractSeries::SeriesTypeHorizontalBar:
1097 case QAbstractSeries::SeriesTypeHorizontalPercentBar:
1098 case QAbstractSeries::SeriesTypeHorizontalStackedBar:
1099 if (orientation == Qt::Vertical)
1100 return QAbstractAxis::AxisTypeBarCategory;
1101 break;
1102 case QAbstractSeries::SeriesTypeBar:
1103 case QAbstractSeries::SeriesTypePercentBar:
1104 case QAbstractSeries::SeriesTypeStackedBar:
1105 case QAbstractSeries::SeriesTypeBoxPlot:
1106 case QAbstractSeries::SeriesTypeCandlestick:
1107 if (orientation == Qt::Horizontal)
1108 return QAbstractAxis::AxisTypeBarCategory;
1109 break;
1110 default:
1111 qWarning() << "Unexpected series type";
1112 break;
1113 }
1114 return QAbstractAxis::AxisTypeValue;
1115
1116}
1117
1118void QAbstractBarSeriesPrivate::handleSetValueChange(int index)
1119{
1120 QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender());
1121 if (priv)
1122 emit setValueChanged(index, barset: priv->q_ptr);
1123}
1124
1125void QAbstractBarSeriesPrivate::handleSetValueAdd(int index, int count)
1126{
1127 QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender());
1128 if (priv)
1129 emit setValueAdded(index, count, barset: priv->q_ptr);
1130}
1131
1132void QAbstractBarSeriesPrivate::handleSetValueRemove(int index, int count)
1133{
1134 QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender());
1135 if (priv)
1136 emit setValueRemoved(index, count, barset: priv->q_ptr);
1137}
1138
1139void QAbstractBarSeriesPrivate::populateCategories(QBarCategoryAxis *axis)
1140{
1141 QStringList categories;
1142 if (axis->categories().isEmpty()) {
1143 for (int i(1); i < categoryCount() + 1; i++)
1144 categories << presenter()->numberToString(value: i);
1145 axis->append(categories);
1146 }
1147}
1148
1149QAbstractAxis* QAbstractBarSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
1150{
1151 if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory)
1152 return new QBarCategoryAxis;
1153 else
1154 return new QValueAxis;
1155}
1156
1157void QAbstractBarSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
1158{
1159 m_blockBarUpdate = true; // Ensures that the bars are not updated before the theme is ready
1160
1161 const QList<QGradient> gradients = theme->seriesGradients();
1162
1163 // Since each bar series uses different number of colors, we need to account for other
1164 // bar series in the chart that are also themed when choosing colors.
1165 // First series count is used to determine the color stepping to keep old applications
1166 // with single bar series with a lot of sets colored as they always have been.
1167 int actualIndex = 0;
1168 int firstSeriesSetCount = m_barSets.size();
1169 if (m_item) {
1170 auto seriesMap = m_item->themeManager()->seriesMap();
1171 int lowestSeries = index;
1172 for (auto it = seriesMap.cbegin(), end = seriesMap.cend(); it != end; ++it) {
1173 if (it.value() != index) {
1174 auto barSeries = qobject_cast<QAbstractBarSeries *>(object: it.key());
1175 if (barSeries) {
1176 actualIndex += barSeries->count();
1177 if (it.value() < lowestSeries) {
1178 firstSeriesSetCount = qMax(a: barSeries->count(), b: gradients.size());
1179 lowestSeries = it.value();
1180 }
1181 }
1182 }
1183 }
1184 }
1185
1186 qreal takeAtPos = 0.5;
1187 qreal step = 0.2;
1188 if (firstSeriesSetCount > 1) {
1189 step = 1.0 / qreal(firstSeriesSetCount);
1190 if (firstSeriesSetCount % gradients.size())
1191 step *= gradients.size();
1192 else
1193 step *= (gradients.size() - 1);
1194 if (index > 0) {
1195 // Take necessary amount of initial steps
1196 int initialStepper = actualIndex;
1197 while (initialStepper > gradients.size()) {
1198 initialStepper -= gradients.size();
1199 takeAtPos += step;
1200 if (takeAtPos == 1.0)
1201 takeAtPos += step;
1202 takeAtPos -= int(takeAtPos);
1203 }
1204 }
1205 }
1206
1207 for (int i(0); i < m_barSets.size(); i++) {
1208 int colorIndex = (actualIndex + i) % gradients.size();
1209 if ((actualIndex + i) > 0 && (actualIndex + i) % gradients.size() == 0) {
1210 // There is no dedicated base color for each sets, generate more colors
1211 takeAtPos += step;
1212 if (takeAtPos == 1.0)
1213 takeAtPos += step;
1214 takeAtPos -= (int) takeAtPos;
1215 }
1216 if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_brush)
1217 m_barSets.at(i)->setBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: colorIndex), pos: takeAtPos));
1218
1219 // Pick label color from the opposite end of the gradient.
1220 // 0.3 as a boundary seems to work well.
1221 if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_labelBrush) {
1222 if (takeAtPos < 0.3)
1223 m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 1));
1224 else
1225 m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 0));
1226 }
1227 if (forced || QChartPrivate::defaultPen() == m_barSets.at(i)->d_ptr->m_pen) {
1228 QColor c = ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 0.0);
1229 m_barSets.at(i)->setPen(c);
1230 }
1231 }
1232 m_blockBarUpdate = false;
1233 emit updatedBars();
1234}
1235
1236void QAbstractBarSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration,
1237 QEasingCurve &curve)
1238{
1239 AbstractBarChartItem *bar = static_cast<AbstractBarChartItem *>(m_item.get());
1240 Q_ASSERT(bar);
1241 if (bar->animation())
1242 bar->animation()->stopAndDestroyLater();
1243
1244 if (options.testFlag(flag: QChart::SeriesAnimations))
1245 bar->setAnimation(new BarAnimation(bar, duration, curve));
1246 else
1247 bar->setAnimation(0);
1248 QAbstractSeriesPrivate::initializeAnimations(options, duration, curve);
1249}
1250
1251QT_END_NAMESPACE
1252
1253#include "moc_qabstractbarseries.cpp"
1254#include "moc_qabstractbarseries_p.cpp"
1255

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtcharts/src/charts/barchart/qabstractbarseries.cpp