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/horizontalstackedbarchartitem_p.h>
31#include <private/qabstractbarseries_p.h>
32#include <private/qbarset_p.h>
33#include <private/bar_p.h>
34
35QT_CHARTS_BEGIN_NAMESPACE
36
37HorizontalStackedBarChartItem::HorizontalStackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item)
38 : AbstractBarChartItem(series, item)
39{
40}
41
42void HorizontalStackedBarChartItem::initializeLayout(int set, int category,
43 int layoutIndex, bool resetAnimation)
44{
45 Q_UNUSED(set)
46 Q_UNUSED(resetAnimation)
47
48 QRectF rect;
49 if (set > 0) {
50 const QBarSet *barSet = m_series->barSets().at(i: set);
51 const qreal value = barSet->at(index: category);
52 int checkIndex = set;
53 bool found = false;
54 // Negative values stack to negative side and positive values to positive side, so we need
55 // to find the previous set that stacks to the same side
56 while (checkIndex > 0 && !found) {
57 checkIndex--;
58 QBarSet *checkSet = m_series->barSets().at(i: checkIndex);
59 const qreal checkValue = checkSet->at(index: category);
60 if ((value < 0.0) == (checkValue < 0.0)) {
61 Bar *checkBar = m_indexForBarMap.value(akey: checkSet).value(akey: category);
62 rect = m_layout.at(i: checkBar->layoutIndex());
63 found = true;
64 break;
65 }
66 }
67 // If we didn't find a previous set to the same direction, just stack next to the first set
68 if (!found) {
69 QBarSet *firsSet = m_series->barSets().at(i: 0);
70 Bar *firstBar = m_indexForBarMap.value(akey: firsSet).value(akey: category);
71 rect = m_layout.at(i: firstBar->layoutIndex());
72 }
73 if (value < 0)
74 rect.setRight(rect.left());
75 else
76 rect.setLeft(rect.right());
77 } else {
78 QPointF topLeft;
79 QPointF bottomRight;
80 const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth;
81
82 if (domain()->type() == AbstractDomain::LogXYDomain
83 || domain()->type() == AbstractDomain::LogXLogYDomain) {
84 topLeft = topLeftPoint(category, barWidth, value: domain()->minX());
85 bottomRight = bottomRightPoint(category, barWidth, value: domain()->minX());
86 } else {
87 topLeft = topLeftPoint(category, barWidth, value: 0.0);
88 bottomRight = bottomRightPoint(category, barWidth, value: 0.0);
89 }
90
91 if (m_validData) {
92 rect.setTopLeft(topLeft);
93 rect.setBottomRight(bottomRight);
94 }
95 }
96 m_layout[layoutIndex] = rect.normalized();
97}
98
99QPointF HorizontalStackedBarChartItem::topLeftPoint(int category, qreal barWidth, qreal value)
100{
101 return domain()->calculateGeometryPoint(
102 point: QPointF(value, m_seriesPosAdjustment + category - (barWidth / 2)), ok&: m_validData);
103}
104
105QPointF HorizontalStackedBarChartItem::bottomRightPoint(int category, qreal barWidth, qreal value)
106{
107 return domain()->calculateGeometryPoint(
108 point: QPointF(value, m_seriesPosAdjustment + category + (barWidth / 2)), ok&: m_validData);
109}
110
111QVector<QRectF> HorizontalStackedBarChartItem::calculateLayout()
112{
113 QVector<QRectF> layout;
114 layout.resize(asize: m_layout.size());
115
116 const int setCount = m_series->count();
117 const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth;
118
119 QVector<qreal> positiveSums(m_categoryCount, 0.0);
120 QVector<qreal> negativeSums(m_categoryCount, 0.0);
121
122 for (int set = 0; set < setCount; set++) {
123 QBarSet *barSet = m_series->barSets().at(i: set);
124 const QList<Bar *> bars = m_barMap.value(akey: barSet);
125 for (int i = 0; i < m_categoryCount; i++) {
126 Bar *bar = bars.at(i);
127 const int category = bar->index();
128 qreal &positiveSum = positiveSums[category - m_firstCategory];
129 qreal &negativeSum = negativeSums[category - m_firstCategory];
130 qreal value = barSet->at(index: category);
131 QRectF rect;
132 QPointF topLeft;
133 QPointF bottomRight;
134 if (value < 0) {
135 bottomRight = bottomRightPoint(category, barWidth, value: value + negativeSum);
136 if (domain()->type() == AbstractDomain::XLogYDomain
137 || domain()->type() == AbstractDomain::LogXLogYDomain) {
138 topLeft = topLeftPoint(category, barWidth,
139 value: set ? negativeSum : domain()->minX());
140 } else {
141 topLeft = topLeftPoint(category, barWidth, value: set ? negativeSum : 0.0);
142 }
143 negativeSum += value;
144 } else {
145 bottomRight = bottomRightPoint(category, barWidth, value: value + positiveSum);
146 if (domain()->type() == AbstractDomain::XLogYDomain
147 || domain()->type() == AbstractDomain::LogXLogYDomain) {
148 topLeft = topLeftPoint(category, barWidth,
149 value: set ? positiveSum : domain()->minX());
150 } else {
151 topLeft = topLeftPoint(category, barWidth,
152 value: set ? positiveSum : 0.0);
153 }
154 positiveSum += value;
155 }
156
157 rect.setTopLeft(topLeft);
158 rect.setBottomRight(bottomRight);
159 rect = rect.normalized();
160 layout[bar->layoutIndex()] = rect;
161
162 // If animating, we need to reinitialize ~zero size bars with non-zero values
163 // so the bar growth animation starts at correct spot. We shouldn't reset if rect
164 // is already at correct position horizontally, so we check for that.
165 if (m_animation && value != 0.0) {
166 const QRectF &checkRect = m_layout.at(i: bar->layoutIndex());
167 if (checkRect.isEmpty() &&
168 ((value < 0.0 && !qFuzzyCompare(p1: checkRect.right(), p2: rect.right()))
169 || (value > 0.0 && !qFuzzyCompare(p1: checkRect.left(), p2: rect.left())))) {
170 initializeLayout(set, category, layoutIndex: bar->layoutIndex(), resetAnimation: true);
171 }
172 }
173 }
174 }
175 return layout;
176}
177
178QT_CHARTS_END_NAMESPACE
179
180#include "moc_horizontalstackedbarchartitem_p.cpp"
181

source code of qtcharts/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp