1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <private/stackedbarchartitem_p.h>
5#include <private/bar_p.h>
6#include <private/qbarset_p.h>
7#include <private/qabstractbarseries_p.h>
8#include <QtCharts/QBarSet>
9
10QT_BEGIN_NAMESPACE
11
12StackedBarChartItem::StackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) :
13 AbstractBarChartItem(series, item)
14{
15 m_orientation = Qt::Vertical;
16 connect(sender: series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)),
17 receiver: this, SLOT(handleLabelsPositionChanged()));
18 connect(sender: series, SIGNAL(labelsFormatChanged(QString)), receiver: this, SLOT(positionLabels()));
19}
20
21void StackedBarChartItem::initializeLayout(int set, int category,
22 int layoutIndex, bool resetAnimation)
23{
24 Q_UNUSED(set);
25 Q_UNUSED(resetAnimation);
26
27 QRectF rect;
28
29 if (set > 0) {
30 const QBarSet *barSet = m_series->barSets().at(i: set);
31 const qreal value = barSet->at(index: category);
32 int checkIndex = set;
33 bool found = false;
34 // Negative values stack to negative side and positive values to positive side, so we need
35 // to find the previous set that stacks to the same side
36 while (checkIndex > 0 && !found) {
37 checkIndex--;
38 QBarSet *checkSet = m_series->barSets().at(i: checkIndex);
39 const qreal checkValue = checkSet->at(index: category);
40 if ((value < 0.0) == (checkValue < 0.0)) {
41 Bar *checkBar = m_indexForBarMap.value(key: checkSet).value(key: category);
42 rect = m_layout.at(i: checkBar->layoutIndex());
43 found = true;
44 break;
45 }
46 }
47 // If we didn't find a previous set to the same direction, just stack next to the first set
48 if (!found) {
49 QBarSet *firsSet = m_series->barSets().at(i: 0);
50 Bar *firstBar = m_indexForBarMap.value(key: firsSet).value(key: category);
51 rect = m_layout.at(i: firstBar->layoutIndex());
52 }
53 if (value < 0)
54 rect.setTop(rect.bottom());
55 else
56 rect.setBottom(rect.top());
57 } else {
58 QPointF topLeft;
59 QPointF bottomRight;
60 const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth;
61 if (domain()->type() == AbstractDomain::XLogYDomain
62 || domain()->type() == AbstractDomain::LogXLogYDomain) {
63 topLeft = topLeftPoint(category, barWidth, value: domain()->minY());
64 bottomRight = bottomRightPoint(category, barWidth, value: domain()->minY());
65 } else {
66 topLeft = topLeftPoint(category, barWidth, value: 0.0);
67 bottomRight = bottomRightPoint(category, barWidth, value: 0.0);
68 }
69
70 if (m_validData) {
71 rect.setTopLeft(topLeft);
72 rect.setBottomRight(bottomRight);
73 }
74 }
75 m_layout[layoutIndex] = rect.normalized();
76}
77
78QPointF StackedBarChartItem::topLeftPoint(int category, qreal barWidth, qreal value)
79{
80 return domain()->calculateGeometryPoint(
81 point: QPointF(m_seriesPosAdjustment + category - (barWidth / 2), value), ok&: m_validData);
82}
83
84QPointF StackedBarChartItem::bottomRightPoint(int category, qreal barWidth, qreal value)
85{
86 return domain()->calculateGeometryPoint(
87 point: QPointF(m_seriesPosAdjustment + category + (barWidth / 2), value), ok&: m_validData);
88}
89
90QList<QRectF> StackedBarChartItem::calculateLayout()
91{
92 QList<QRectF> layout;
93 layout.resize(size: m_layout.size());
94
95 const int setCount = m_series->count();
96 const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth;
97
98 QList<qreal> positiveSums(m_categoryCount, 0.0);
99 QList<qreal> negativeSums(m_categoryCount, 0.0);
100
101 for (int set = 0; set < setCount; set++) {
102 QBarSet *barSet = m_series->barSets().at(i: set);
103 const QList<Bar *> bars = m_barMap.value(key: barSet);
104 for (int i = 0; i < m_categoryCount; i++) {
105 Bar *bar = bars.at(i);
106 const int category = bar->index();
107 qreal &positiveSum = positiveSums[category - m_firstCategory];
108 qreal &negativeSum = negativeSums[category - m_firstCategory];
109 qreal value = barSet->at(index: category);
110 QRectF rect;
111 QPointF topLeft;
112 QPointF bottomRight;
113 if (value < 0.0) {
114 topLeft = topLeftPoint(category, barWidth, value: value + negativeSum);
115 if (domain()->type() == AbstractDomain::XLogYDomain
116 || domain()->type() == AbstractDomain::LogXLogYDomain) {
117 bottomRight = bottomRightPoint(category, barWidth,
118 value: set ? negativeSum : domain()->minY());
119 } else {
120 bottomRight = bottomRightPoint(category, barWidth, value: set ? negativeSum : 0.0);
121 }
122 negativeSum += value;
123 } else {
124 topLeft = topLeftPoint(category, barWidth, value: value + positiveSum);
125 if (domain()->type() == AbstractDomain::XLogYDomain
126 || domain()->type() == AbstractDomain::LogXLogYDomain) {
127 bottomRight = bottomRightPoint(category, barWidth,
128 value: set ? positiveSum : domain()->minY());
129 } else {
130 bottomRight = bottomRightPoint(category, barWidth, value: set ? positiveSum : 0.0);
131 }
132 positiveSum += value;
133 }
134
135 rect.setTopLeft(topLeft);
136 rect.setBottomRight(bottomRight);
137 rect = rect.normalized();
138 layout[bar->layoutIndex()] = rect;
139
140 // If animating, we need to reinitialize ~zero size bars with non-zero values
141 // so the bar growth animation starts at correct spot. We shouldn't reset if rect
142 // is already at correct position vertically, so we check for that.
143 if (m_animation && value != 0.0) {
144 const QRectF &checkRect = m_layout.at(i: bar->layoutIndex());
145 if (checkRect.isEmpty() &&
146 ((value < 0.0 && !qFuzzyCompare(p1: checkRect.top(), p2: rect.top()))
147 || (value > 0.0 && !qFuzzyCompare(p1: checkRect.bottom(), p2: rect.bottom())))) {
148 initializeLayout(set, category, layoutIndex: bar->layoutIndex(), resetAnimation: true);
149 }
150 }
151 }
152 }
153 return layout;
154}
155
156void StackedBarChartItem::handleLabelsPositionChanged()
157{
158 positionLabels();
159}
160
161void StackedBarChartItem::positionLabels()
162{
163 positionLabelsVertical();
164}
165
166QT_END_NAMESPACE
167
168#include "moc_stackedbarchartitem_p.cpp"
169

source code of qtcharts/src/charts/barchart/vertical/stacked/stackedbarchartitem.cpp