1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <private/stackedbarchartitem_p.h>
31#include <private/bar_p.h>
32#include <private/qbarset_p.h>
33#include <private/qabstractbarseries_p.h>
34#include <QtCharts/QBarSet>
35
36QT_CHARTS_BEGIN_NAMESPACE
37
38StackedBarChartItem::StackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) :
39 AbstractBarChartItem(series, item)
40{
41 m_orientation = Qt::Vertical;
42 connect(sender: series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)),
43 receiver: this, SLOT(handleLabelsPositionChanged()));
44 connect(sender: series, SIGNAL(labelsFormatChanged(QString)), receiver: this, SLOT(positionLabels()));
45}
46
47void StackedBarChartItem::initializeLayout(int set, int category,
48 int layoutIndex, bool resetAnimation)
49{
50 Q_UNUSED(set)
51 Q_UNUSED(resetAnimation)
52
53 QRectF rect;
54
55 if (set > 0) {
56 const QBarSet *barSet = m_series->barSets().at(i: set);
57 const qreal value = barSet->at(index: category);
58 int checkIndex = set;
59 bool found = false;
60 // Negative values stack to negative side and positive values to positive side, so we need
61 // to find the previous set that stacks to the same side
62 while (checkIndex > 0 && !found) {
63 checkIndex--;
64 QBarSet *checkSet = m_series->barSets().at(i: checkIndex);
65 const qreal checkValue = checkSet->at(index: category);
66 if ((value < 0.0) == (checkValue < 0.0)) {
67 Bar *checkBar = m_indexForBarMap.value(akey: checkSet).value(akey: category);
68 rect = m_layout.at(i: checkBar->layoutIndex());
69 found = true;
70 break;
71 }
72 }
73 // If we didn't find a previous set to the same direction, just stack next to the first set
74 if (!found) {
75 QBarSet *firsSet = m_series->barSets().at(i: 0);
76 Bar *firstBar = m_indexForBarMap.value(akey: firsSet).value(akey: category);
77 rect = m_layout.at(i: firstBar->layoutIndex());
78 }
79 if (value < 0)
80 rect.setTop(rect.bottom());
81 else
82 rect.setBottom(rect.top());
83 } else {
84 QPointF topLeft;
85 QPointF bottomRight;
86 const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth;
87 if (domain()->type() == AbstractDomain::XLogYDomain
88 || domain()->type() == AbstractDomain::LogXLogYDomain) {
89 topLeft = topLeftPoint(category, barWidth, value: domain()->minY());
90 bottomRight = bottomRightPoint(category, barWidth, value: domain()->minY());
91 } else {
92 topLeft = topLeftPoint(category, barWidth, value: 0.0);
93 bottomRight = bottomRightPoint(category, barWidth, value: 0.0);
94 }
95
96 if (m_validData) {
97 rect.setTopLeft(topLeft);
98 rect.setBottomRight(bottomRight);
99 }
100 }
101 m_layout[layoutIndex] = rect.normalized();
102}
103
104QPointF StackedBarChartItem::topLeftPoint(int category, qreal barWidth, qreal value)
105{
106 return domain()->calculateGeometryPoint(
107 point: QPointF(m_seriesPosAdjustment + category - (barWidth / 2), value), ok&: m_validData);
108}
109
110QPointF StackedBarChartItem::bottomRightPoint(int category, qreal barWidth, qreal value)
111{
112 return domain()->calculateGeometryPoint(
113 point: QPointF(m_seriesPosAdjustment + category + (barWidth / 2), value), ok&: m_validData);
114}
115
116QVector<QRectF> StackedBarChartItem::calculateLayout()
117{
118 QVector<QRectF> layout;
119 layout.resize(asize: m_layout.size());
120
121 const int setCount = m_series->count();
122 const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth;
123
124 QVector<qreal> positiveSums(m_categoryCount, 0.0);
125 QVector<qreal> negativeSums(m_categoryCount, 0.0);
126
127 for (int set = 0; set < setCount; set++) {
128 QBarSet *barSet = m_series->barSets().at(i: set);
129 const QList<Bar *> bars = m_barMap.value(akey: barSet);
130 for (int i = 0; i < m_categoryCount; i++) {
131 Bar *bar = bars.at(i);
132 const int category = bar->index();
133 qreal &positiveSum = positiveSums[category - m_firstCategory];
134 qreal &negativeSum = negativeSums[category - m_firstCategory];
135 qreal value = barSet->at(index: category);
136 QRectF rect;
137 QPointF topLeft;
138 QPointF bottomRight;
139 if (value < 0.0) {
140 topLeft = topLeftPoint(category, barWidth, value: value + negativeSum);
141 if (domain()->type() == AbstractDomain::XLogYDomain
142 || domain()->type() == AbstractDomain::LogXLogYDomain) {
143 bottomRight = bottomRightPoint(category, barWidth,
144 value: set ? negativeSum : domain()->minY());
145 } else {
146 bottomRight = bottomRightPoint(category, barWidth, value: set ? negativeSum : 0.0);
147 }
148 negativeSum += value;
149 } else {
150 topLeft = topLeftPoint(category, barWidth, value: value + positiveSum);
151 if (domain()->type() == AbstractDomain::XLogYDomain
152 || domain()->type() == AbstractDomain::LogXLogYDomain) {
153 bottomRight = bottomRightPoint(category, barWidth,
154 value: set ? positiveSum : domain()->minY());
155 } else {
156 bottomRight = bottomRightPoint(category, barWidth, value: set ? positiveSum : 0.0);
157 }
158 positiveSum += value;
159 }
160
161 rect.setTopLeft(topLeft);
162 rect.setBottomRight(bottomRight);
163 rect = rect.normalized();
164 layout[bar->layoutIndex()] = rect;
165
166 // If animating, we need to reinitialize ~zero size bars with non-zero values
167 // so the bar growth animation starts at correct spot. We shouldn't reset if rect
168 // is already at correct position vertically, so we check for that.
169 if (m_animation && value != 0.0) {
170 const QRectF &checkRect = m_layout.at(i: bar->layoutIndex());
171 if (checkRect.isEmpty() &&
172 ((value < 0.0 && !qFuzzyCompare(p1: checkRect.top(), p2: rect.top()))
173 || (value > 0.0 && !qFuzzyCompare(p1: checkRect.bottom(), p2: rect.bottom())))) {
174 initializeLayout(set, category, layoutIndex: bar->layoutIndex(), resetAnimation: true);
175 }
176 }
177 }
178 }
179 return layout;
180}
181
182void StackedBarChartItem::handleLabelsPositionChanged()
183{
184 positionLabels();
185}
186
187void StackedBarChartItem::positionLabels()
188{
189 positionLabelsVertical();
190}
191
192QT_CHARTS_END_NAMESPACE
193
194#include "moc_stackedbarchartitem_p.cpp"
195

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