KQuickCharts

PieChart.cpp
1/*
2 * This file is part of KQuickCharts
3 * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7
8#include "PieChart.h"
9
10#include <QAbstractItemModel>
11#include <QDebug>
12
13#include "RangeGroup.h"
14#include "datasource/ChartDataSource.h"
15#include "scenegraph/PieChartNode.h"
16
17PieChart::PieChart(QQuickItem *parent)
18 : Chart(parent)
19{
20 setIndexingMode(Chart::IndexSourceValues);
21 m_range = std::make_unique<RangeGroup>();
22 connect(m_range.get(), &RangeGroup::rangeChanged, this, &PieChart::onDataChanged);
23}
24
26{
27 return m_range.get();
28}
29
30bool PieChart::filled() const
31{
32 return m_filled;
33}
34
35void PieChart::setFilled(bool newFilled)
36{
37 if (newFilled == m_filled) {
38 return;
39 }
40
41 m_filled = newFilled;
42 update();
43 Q_EMIT filledChanged();
44}
45
46qreal PieChart::thickness() const
47{
48 return m_thickness;
49}
50
51void PieChart::setThickness(qreal newThickness)
52{
53 if (newThickness == m_thickness) {
54 return;
55 }
56
57 m_thickness = newThickness;
58 update();
59 Q_EMIT thicknessChanged();
60}
61
62qreal PieChart::spacing() const
63{
64 return m_spacing;
65}
66
67void PieChart::setSpacing(qreal newSpacing)
68{
69 if (newSpacing == m_spacing) {
70 return;
71 }
72
73 m_spacing = newSpacing;
74 update();
75 Q_EMIT spacingChanged();
76}
77
79{
80 return m_backgroundColor;
81}
82
83void PieChart::setBackgroundColor(const QColor &color)
84{
85 if (color == m_backgroundColor) {
86 return;
87 }
88 m_backgroundColor = color;
89 update();
90 Q_EMIT backgroundColorChanged();
91}
92
93qreal PieChart::fromAngle() const
94{
95 return m_fromAngle;
96}
97
98void PieChart::setFromAngle(qreal newFromAngle)
99{
100 if (qFuzzyCompare(newFromAngle, m_fromAngle)) {
101 return;
102 }
103
104 m_fromAngle = newFromAngle;
105 update();
106 Q_EMIT fromAngleChanged();
107}
108
109qreal PieChart::toAngle() const
110{
111 return m_toAngle;
112}
113
114void PieChart::setToAngle(qreal newToAngle)
115{
116 if (qFuzzyCompare(newToAngle, m_toAngle)) {
117 return;
118 }
119
120 m_toAngle = newToAngle;
121 update();
122 Q_EMIT toAngleChanged();
123}
124
125bool PieChart::smoothEnds() const
126{
127 return m_smoothEnds;
128}
129
130void PieChart::setSmoothEnds(bool newSmoothEnds)
131{
132 if (newSmoothEnds == m_smoothEnds) {
133 return;
134 }
135
136 m_smoothEnds = newSmoothEnds;
137 update();
138 Q_EMIT smoothEndsChanged();
139}
140
141QSGNode *PieChart::updatePaintNode(QSGNode *node, UpdatePaintNodeData *data)
142{
143 Q_UNUSED(data);
144 if (!node) {
145 node = new QSGNode{};
146 }
147
148 auto sourceCount = valueSources().size();
149
150 if (m_sections.count() < sourceCount) {
151 return node;
152 }
153
154 auto minDimension = std::min(width(), height());
155
156 float outerRadius = minDimension;
157 for (int i = 0; i < sourceCount; ++i) {
158 float innerRadius = i == sourceCount - 1 && m_filled ? 0.0 : outerRadius - m_thickness * 2.0;
159
160 if (node->childCount() <= i) {
161 node->appendChildNode(new PieChartNode{});
162 }
163
164 auto pieNode = static_cast<PieChartNode *>(node->childAtIndex(i));
165 pieNode->setRect(boundingRect());
166 pieNode->setInnerRadius(innerRadius);
167 pieNode->setOuterRadius(outerRadius);
168 pieNode->setSections(m_sections.at(i));
169 pieNode->setBackgroundColor(m_backgroundColor);
170 pieNode->setColors(m_colors.at(i));
171 pieNode->setFromAngle(m_fromAngle);
172 pieNode->setToAngle(m_toAngle);
173 pieNode->setSmoothEnds(m_smoothEnds);
174
175 outerRadius = innerRadius - m_spacing * 2.0;
176 }
177
178 while (node->childCount() > sourceCount) {
179 auto lastNode = node->childAtIndex(node->childCount() - 1);
180 node->removeChildNode(lastNode);
181 delete lastNode;
182 }
183
184 return node;
185}
186
188{
189 m_sections.clear();
190 m_colors.clear();
191
192 const auto sources = valueSources();
193 const auto colors = colorSource();
194
195 if (!colors || sources.isEmpty() || !m_range->isValid()) {
196 return;
197 }
198
199 auto maximum = [](ChartDataSource *source) {
200 qreal result = 0.0;
201 for (int i = 0; i < source->itemCount(); ++i) {
202 result += source->item(i).toDouble();
203 }
204 return std::max(result, source->maximum().toDouble());
205 };
206
207 auto indexMode = indexingMode();
208 auto colorIndex = 0;
209 auto calculateZeroRange = [](ChartDataSource *) {
210 return 0.0;
211 };
212 auto range = m_range->calculateRange(valueSources(), calculateZeroRange, maximum);
213
214 for (auto source : sources) {
215 qreal threshold = range.start;
216 qreal total = 0.0;
217
218 QList<qreal> sections;
219 QList<QColor> sectionColors;
220
221 for (int i = 0; i < source->itemCount(); ++i) {
222 auto value = source->item(i).toReal();
223 auto limited = value - threshold;
224 if (limited > 0.0) {
225 if (total + limited >= range.end) {
226 limited = range.end - total;
227 }
228
229 sections << limited;
230 total += limited;
231
232 auto color = colors->item(colorIndex).value<QColor>();
233 sectionColors << color;
234 }
235 threshold = std::max(0.0, threshold - value);
236
237 if (indexMode != IndexEachSource) {
238 colorIndex++;
239 }
240 }
241
242 if (qFuzzyCompare(total, 0.0)) {
243 m_sections << QList<qreal>{0.0};
244 m_colors << QList<QColor>{colors->item(colorIndex).value<QColor>()};
245 }
246
247 for (auto &value : sections) {
248 value = value / range.distance;
249 }
250
251 m_sections << sections;
252 m_colors << sectionColors;
253
254 if (indexMode == IndexEachSource) {
255 colorIndex++;
256 } else if (indexMode == IndexSourceValues) {
257 colorIndex = 0;
258 }
259 }
260
261 update();
262}
263
264#include "moc_PieChart.cpp"
Abstract base class for data sources.
Abstract base class for all charts.
Definition Chart.h:22
QQmlListProperty< ChartDataSource > valueSources
The data sources providing the data this chart needs to render.
Definition Chart.h:70
ChartDataSource * colorSource
The data source to use for colors of chart items.
Definition Chart.h:62
@ IndexSourceValues
Index each value, restart indexing for each value source.
Definition Chart.h:34
@ IndexEachSource
Index each value source, never index individual values.
Definition Chart.h:35
IndexingMode indexingMode
The indexing mode used for indexing colors and names.
Definition Chart.h:81
bool smoothEnds
Smooth the ends of pie sections.
Definition PieChart.h:130
QSGNode * updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override
Reimplemented from QQuickItem.
Definition PieChart.cpp:141
qreal fromAngle
The starting angle of the arc used for the entire pie.
Definition PieChart.h:109
qreal spacing
The amount of spacing between pies when rendering multiple value sources.
Definition PieChart.h:90
void onDataChanged() override
Reimplemented from Chart.
Definition PieChart.cpp:187
qreal toAngle
The end angle of the arc used for the entire pie.
Definition PieChart.h:118
qreal thickness
The thickness of an individual pie, in pixels.
Definition PieChart.h:81
RangeGroup * range
The range of values to display in this PieChart.
Definition PieChart.h:64
bool filled
Whether to use a filled pie or not.
Definition PieChart.h:72
QColor backgroundColor
Sets a colour to use to fill remaining space on the pie.
Definition PieChart.h:99
An object that can be used as a grouped property to provide a value range for charts.
Definition RangeGroup.h:25
qreal distance
The distance between from and to.
Definition RangeGroup.h:70
int value() const const
const_reference at(qsizetype i) const const
void clear()
qsizetype count() const const
Q_EMITQ_EMIT
virtual QRectF boundingRect() const const
void update()
void appendChildNode(QSGNode *node)
QSGNode * childAtIndex(int i) const const
int childCount() const const
void removeChildNode(QSGNode *node)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:57 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.