1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <private/percentbarchartitem_p.h> |
5 | #include <private/bar_p.h> |
6 | #include <private/qabstractbarseries_p.h> |
7 | #include <QtCharts/QBarSet> |
8 | #include <private/qbarset_p.h> |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | PercentBarChartItem::PercentBarChartItem(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 | |
21 | QString PercentBarChartItem::generateLabelText(int set, int category, qreal value) |
22 | { |
23 | Q_UNUSED(value); |
24 | |
25 | static const QString valueTag(QLatin1String("@value" )); |
26 | qreal p = m_series->d_func()->percentageAt(set, category) * 100.0; |
27 | QString vString(presenter()->numberToString(value: p, f: 'f', prec: 0)); |
28 | QString valueLabel; |
29 | if (m_series->labelsFormat().isEmpty()) { |
30 | vString.append(QStringLiteral("%" )); |
31 | valueLabel = vString; |
32 | } else { |
33 | valueLabel = m_series->labelsFormat(); |
34 | valueLabel.replace(before: valueTag, after: vString); |
35 | } |
36 | |
37 | return valueLabel; |
38 | } |
39 | |
40 | void PercentBarChartItem::initializeLayout(int set, int category, |
41 | int layoutIndex, bool resetAnimation) |
42 | { |
43 | Q_UNUSED(set); |
44 | Q_UNUSED(resetAnimation); |
45 | |
46 | QRectF rect; |
47 | |
48 | if (set > 0) { |
49 | QBarSet *barSet = m_series->barSets().at(i: set - 1); |
50 | Bar *bar = m_indexForBarMap.value(key: barSet).value(key: category); |
51 | rect = m_layout.at(i: bar->layoutIndex()); |
52 | rect.setBottom(rect.top()); |
53 | } else { |
54 | QPointF topLeft; |
55 | QPointF bottomRight; |
56 | const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth; |
57 | if (domain()->type() == AbstractDomain::XLogYDomain |
58 | || domain()->type() == AbstractDomain::LogXLogYDomain) { |
59 | topLeft = topLeftPoint(category, barWidth, value: domain()->minY()); |
60 | bottomRight = bottomRightPoint(category, barWidth, value: domain()->minY()); |
61 | } else { |
62 | topLeft = topLeftPoint(category, barWidth, value: 0.0); |
63 | bottomRight = bottomRightPoint(category, barWidth, value: 0.0); |
64 | } |
65 | if (m_validData) { |
66 | rect.setTopLeft(topLeft); |
67 | rect.setBottomRight(bottomRight); |
68 | } |
69 | } |
70 | |
71 | m_layout[layoutIndex] = rect.normalized(); |
72 | } |
73 | |
74 | void PercentBarChartItem::markLabelsDirty(QBarSet *barset, int index, int count) |
75 | { |
76 | Q_UNUSED(barset); |
77 | // Percent series need to dirty all labels of the stack |
78 | QList<QBarSet *> sets = m_barMap.keys(); |
79 | for (int set = 0; set < sets.size(); set++) |
80 | AbstractBarChartItem::markLabelsDirty(barset: sets.at(i: set), index, count); |
81 | } |
82 | |
83 | QPointF PercentBarChartItem::topLeftPoint(int category, qreal barWidth, qreal value) |
84 | { |
85 | return domain()->calculateGeometryPoint( |
86 | point: QPointF(m_seriesPosAdjustment + category - (barWidth / 2.0), value), ok&: m_validData); |
87 | } |
88 | |
89 | QPointF PercentBarChartItem::bottomRightPoint(int category, qreal barWidth, qreal value) |
90 | { |
91 | return domain()->calculateGeometryPoint( |
92 | point: QPointF(m_seriesPosAdjustment + category + (barWidth / 2.0), value), ok&: m_validData); |
93 | } |
94 | |
95 | QList<QRectF> PercentBarChartItem::calculateLayout() |
96 | { |
97 | QList<QRectF> layout; |
98 | layout.resize(size: m_layout.size()); |
99 | |
100 | const int setCount = m_series->count(); |
101 | const qreal barWidth = m_series->d_func()->barWidth() * m_seriesWidth; |
102 | |
103 | QList<qreal> categorySums(m_categoryCount); |
104 | QList<qreal> tempSums(m_categoryCount, 0.0); |
105 | |
106 | for (int category = 0; category < m_categoryCount; category++) |
107 | categorySums[category] = m_series->d_func()->categorySum(category: category + m_firstCategory); |
108 | |
109 | for (int set = 0; set < setCount; set++) { |
110 | QBarSet *barSet = m_series->barSets().at(i: set); |
111 | const QList<Bar *> bars = m_barMap.value(key: barSet); |
112 | for (int i = 0; i < m_categoryCount; i++) { |
113 | Bar *bar = bars.at(i); |
114 | const int category = bar->index(); |
115 | qreal &sum = tempSums[category - m_firstCategory]; |
116 | const qreal &categorySum = categorySums.at(i: category - m_firstCategory); |
117 | qreal value = barSet->at(index: category); |
118 | QRectF rect; |
119 | qreal topY = 0.0; |
120 | qreal newSum = value + sum; |
121 | qreal bottomY = 0.0; |
122 | if (categorySum != 0.0) { |
123 | if (newSum > 0.0) |
124 | topY = 100.0 * newSum / categorySum; |
125 | if (sum > 0.0) |
126 | bottomY = 100.0 * sum / categorySum; |
127 | } |
128 | QPointF topLeft = topLeftPoint(category, barWidth, value: topY); |
129 | QPointF bottomRight; |
130 | if (domain()->type() == AbstractDomain::XLogYDomain |
131 | || domain()->type() == AbstractDomain::LogXLogYDomain) { |
132 | bottomRight = bottomRightPoint(category, barWidth, |
133 | value: set ? bottomY : domain()->minY()); |
134 | } else { |
135 | bottomRight = bottomRightPoint(category, barWidth, value: bottomY); |
136 | } |
137 | |
138 | rect.setTopLeft(topLeft); |
139 | rect.setBottomRight(bottomRight); |
140 | layout[bar->layoutIndex()] = rect.normalized(); |
141 | sum = newSum; |
142 | } |
143 | } |
144 | return layout; |
145 | } |
146 | |
147 | void PercentBarChartItem::handleLabelsPositionChanged() |
148 | { |
149 | positionLabels(); |
150 | } |
151 | |
152 | void PercentBarChartItem::positionLabels() |
153 | { |
154 | positionLabelsVertical(); |
155 | } |
156 | |
157 | QT_END_NAMESPACE |
158 | |
159 | #include "moc_percentbarchartitem_p.cpp" |
160 | |