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

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