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 | |
20 | QT_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 | */ |
391 | QAbstractBarSeries::~QAbstractBarSeries() |
392 | { |
393 | |
394 | } |
395 | |
396 | /*! |
397 | \internal |
398 | */ |
399 | QAbstractBarSeries::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 | */ |
409 | void 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 | */ |
419 | qreal 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 | */ |
430 | bool 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 | */ |
448 | bool 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 | */ |
471 | bool 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 | */ |
491 | bool 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 | */ |
511 | bool 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 | */ |
527 | void 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 | */ |
543 | int 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 | */ |
552 | QList<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 | */ |
561 | void 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 | */ |
573 | bool QAbstractBarSeries::isLabelsVisible() const |
574 | { |
575 | Q_D(const QAbstractBarSeries); |
576 | return d->m_labelsVisible; |
577 | } |
578 | |
579 | void 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 | |
589 | QString QAbstractBarSeries::labelsFormat() const |
590 | { |
591 | Q_D(const QAbstractBarSeries); |
592 | return d->m_labelsFormat; |
593 | } |
594 | |
595 | void 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 | |
605 | qreal QAbstractBarSeries::labelsAngle() const |
606 | { |
607 | Q_D(const QAbstractBarSeries); |
608 | return d->m_labelsAngle; |
609 | } |
610 | |
611 | void 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 | |
620 | QAbstractBarSeries::LabelsPosition QAbstractBarSeries::labelsPosition() const |
621 | { |
622 | Q_D(const QAbstractBarSeries); |
623 | return d->m_labelsPosition; |
624 | } |
625 | |
626 | void 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 | |
636 | int QAbstractBarSeries::labelsPrecision() const |
637 | { |
638 | Q_D(const QAbstractBarSeries); |
639 | return d->m_labelsPrecision; |
640 | } |
641 | |
642 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
643 | |
644 | QAbstractBarSeriesPrivate::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 | |
659 | int 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 | |
671 | void QAbstractBarSeriesPrivate::setBarWidth(qreal width) |
672 | { |
673 | if (width < 0.0) |
674 | width = 0.0; |
675 | m_barWidth = width; |
676 | emit updatedLayout(); |
677 | } |
678 | |
679 | qreal QAbstractBarSeriesPrivate::barWidth() const |
680 | { |
681 | return m_barWidth; |
682 | } |
683 | |
684 | QBarSet *QAbstractBarSeriesPrivate::barsetAt(int index) |
685 | { |
686 | return m_barSets.at(i: index); |
687 | } |
688 | |
689 | void QAbstractBarSeriesPrivate::setVisible(bool visible) |
690 | { |
691 | m_visible = visible; |
692 | emit visibleChanged(); |
693 | } |
694 | |
695 | void QAbstractBarSeriesPrivate::setLabelsVisible(bool visible) |
696 | { |
697 | m_labelsVisible = visible; |
698 | emit labelsVisibleChanged(visible); |
699 | } |
700 | |
701 | qreal 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 | |
719 | qreal 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 | |
738 | qreal 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 | |
748 | qreal 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 | |
763 | qreal 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 | |
774 | qreal 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 | |
785 | qreal 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 | |
797 | qreal 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 | |
815 | qreal 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 | |
834 | qreal 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 | |
851 | qreal 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 | |
868 | qreal 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 | |
881 | qreal 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 | |
894 | bool QAbstractBarSeriesPrivate::blockBarUpdate() |
895 | { |
896 | return m_blockBarUpdate; |
897 | } |
898 | |
899 | qreal QAbstractBarSeriesPrivate::labelsAngle() const |
900 | { |
901 | return m_labelsAngle; |
902 | } |
903 | |
904 | void 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 | |
922 | QList<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 | |
936 | bool 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 | |
957 | bool 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 | |
978 | bool 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 | |
1005 | bool 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 | |
1036 | bool 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 | |
1057 | void 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 | |
1091 | QAbstractAxis::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 | |
1118 | void 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 | |
1125 | void 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 | |
1132 | void 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 | |
1139 | void 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 | |
1149 | QAbstractAxis* 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 | |
1157 | void 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 | |
1236 | void 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 | |
1251 | QT_END_NAMESPACE |
1252 | |
1253 | #include "moc_qabstractbarseries.cpp" |
1254 | #include "moc_qabstractbarseries_p.cpp" |
1255 |
Definitions
- ~QAbstractBarSeries
- QAbstractBarSeries
- setBarWidth
- barWidth
- append
- remove
- take
- append
- insert
- clear
- count
- barSets
- setLabelsVisible
- isLabelsVisible
- setLabelsFormat
- labelsFormat
- setLabelsAngle
- labelsAngle
- setLabelsPosition
- labelsPosition
- setLabelsPrecision
- labelsPrecision
- QAbstractBarSeriesPrivate
- categoryCount
- setBarWidth
- barWidth
- barsetAt
- setVisible
- setLabelsVisible
- min
- max
- valueAt
- percentageAt
- categorySum
- absoluteCategorySum
- maxCategorySum
- minX
- maxX
- categoryTop
- categoryBottom
- top
- bottom
- blockBarUpdate
- labelsAngle
- initializeDomain
- createLegendMarkers
- append
- remove
- append
- remove
- insert
- initializeAxes
- defaultAxisType
- handleSetValueChange
- handleSetValueAdd
- handleSetValueRemove
- populateCategories
- createDefaultAxis
- initializeTheme
Learn Advanced QML with KDAB
Find out more