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
35 QT_CHARTS_BEGIN_NAMESPACE
36
HorizontalStackedBarChartItem(QAbstractBarSeries * series,QGraphicsItem * item)37 HorizontalStackedBarChartItem::HorizontalStackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item)
38 : AbstractBarChartItem(series, item)
39 {
40 }
41
initializeLayout(int set,int category,int layoutIndex,bool resetAnimation)42 void 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(set);
51 const qreal value = barSet->at(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(checkIndex);
59 const qreal checkValue = checkSet->at(category);
60 if ((value < 0.0) == (checkValue < 0.0)) {
61 Bar *checkBar = m_indexForBarMap.value(checkSet).value(category);
62 rect = m_layout.at(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(0);
70 Bar *firstBar = m_indexForBarMap.value(firsSet).value(category);
71 rect = m_layout.at(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, domain()->minX());
85 bottomRight = bottomRightPoint(category, barWidth, domain()->minX());
86 } else {
87 topLeft = topLeftPoint(category, barWidth, 0.0);
88 bottomRight = bottomRightPoint(category, barWidth, 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
topLeftPoint(int category,qreal barWidth,qreal value)99 QPointF HorizontalStackedBarChartItem::topLeftPoint(int category, qreal barWidth, qreal value)
100 {
101 return domain()->calculateGeometryPoint(
102 QPointF(value, m_seriesPosAdjustment + category - (barWidth / 2)), m_validData);
103 }
104
bottomRightPoint(int category,qreal barWidth,qreal value)105 QPointF HorizontalStackedBarChartItem::bottomRightPoint(int category, qreal barWidth, qreal value)
106 {
107 return domain()->calculateGeometryPoint(
108 QPointF(value, m_seriesPosAdjustment + category + (barWidth / 2)), m_validData);
109 }
110
calculateLayout()111 QVector<QRectF> HorizontalStackedBarChartItem::calculateLayout()
112 {
113 QVector<QRectF> layout;
114 layout.resize(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(set);
124 const QList<Bar *> bars = m_barMap.value(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(category);
131 QRectF rect;
132 QPointF topLeft;
133 QPointF bottomRight;
134 if (value < 0) {
135 bottomRight = bottomRightPoint(category, barWidth, value + negativeSum);
136 if (domain()->type() == AbstractDomain::XLogYDomain
137 || domain()->type() == AbstractDomain::LogXLogYDomain) {
138 topLeft = topLeftPoint(category, barWidth,
139 set ? negativeSum : domain()->minX());
140 } else {
141 topLeft = topLeftPoint(category, barWidth, set ? negativeSum : 0.0);
142 }
143 negativeSum += value;
144 } else {
145 bottomRight = bottomRightPoint(category, barWidth, value + positiveSum);
146 if (domain()->type() == AbstractDomain::XLogYDomain
147 || domain()->type() == AbstractDomain::LogXLogYDomain) {
148 topLeft = topLeftPoint(category, barWidth,
149 set ? positiveSum : domain()->minX());
150 } else {
151 topLeft = topLeftPoint(category, barWidth,
152 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(bar->layoutIndex());
167 if (checkRect.isEmpty() &&
168 ((value < 0.0 && !qFuzzyCompare(checkRect.right(), rect.right()))
169 || (value > 0.0 && !qFuzzyCompare(checkRect.left(), rect.left())))) {
170 initializeLayout(set, category, bar->layoutIndex(), true);
171 }
172 }
173 }
174 }
175 return layout;
176 }
177
178 QT_CHARTS_END_NAMESPACE
179
180 #include "moc_horizontalstackedbarchartitem_p.cpp"
181