summaryrefslogtreecommitdiffstats
path: root/src/charts/barchart/horizontal
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2016-08-26 15:53:02 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2016-09-19 10:51:01 +0000
commit105d75533d31ceee0c39ef9e084294ed49ecbd89 (patch)
tree4d2a73a1974d8ccd79d027ab19f8d4143909b458 /src/charts/barchart/horizontal
parentced3a47d266938fd73a4b45f56cca4847cbb6967 (diff)
Optimize barcharts painting
Previously, bar charts used to recreate the bar chart visuals from scratch whenever any change to the bar data occurred. The following changes were made: - Graphics items are generated only for visible bars and labels - Graphics items are reused if layout or data changes - Labels are not generated unless they are visible - Only newly added bars are animated from scratch; existing bars will retain their size, making things more visually pleasing. With these optimizations, the size of the bar series is irrelevant to the painting performance, only thing that matters is how many bars and labels are actually within visible range. Task-number: QTBUG-52442 Change-Id: If3199a86e6819ef6219d2eb5f06d729c0bdbd2ae Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Diffstat (limited to 'src/charts/barchart/horizontal')
-rw-r--r--src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp64
-rw-r--r--src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h2
-rw-r--r--src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp134
-rw-r--r--src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h5
-rw-r--r--src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp64
-rw-r--r--src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h2
6 files changed, 148 insertions, 123 deletions
diff --git a/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp b/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp
index d0fd83d4..6b9b7192 100644
--- a/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp
+++ b/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp
@@ -39,48 +39,62 @@ HorizontalBarChartItem::HorizontalBarChartItem(QAbstractBarSeries *series, QGrap
{
}
-void HorizontalBarChartItem::initializeLayout()
+void HorizontalBarChartItem::initializeLayout(int set, int category, int layoutIndex,
+ bool resetAnimation)
{
- qreal categoryCount = m_series->d_func()->categoryCount();
- qreal setCount = m_series->count();
- qreal barWidth = m_series->d_func()->barWidth();
-
- m_layout.clear();
- for(int category = 0; category < categoryCount; category++) {
- for (int set = 0; set < setCount; set++) {
- QRectF rect;
- QPointF topLeft;
- QPointF bottomRight;
- if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) {
- topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2 + set/setCount * barWidth), m_validData);
- bottomRight = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2 + (set + 1)/setCount * barWidth), m_validData);
- } else {
- topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2 + set/setCount * barWidth), m_validData);
- bottomRight = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2 + (set + 1)/setCount * barWidth), m_validData);
- }
+ QRectF rect;
- if (!m_validData)
- return;
+ int previousSetIndex = layoutIndex - m_categoryCount;
+ if (previousSetIndex >= 0) {
+ rect = m_layout.at(previousSetIndex);
+ qreal oldTop = rect.top();
+ if (resetAnimation)
+ rect.setTop(oldTop - rect.height());
+ rect.setBottom(oldTop);
+ rect.setRight(rect.left());
+ } else {
+ QPointF topLeft;
+ QPointF bottomRight;
+ qreal barWidth = m_series->d_func()->barWidth();
+ qreal setCount = m_series->count();
+ if (domain()->type() == AbstractDomain::LogXYDomain
+ || domain()->type() == AbstractDomain::LogXLogYDomain) {
+ topLeft = domain()->calculateGeometryPoint(
+ QPointF(domain()->minX(),
+ category - barWidth / 2 + set/setCount * barWidth), m_validData);
+ bottomRight = domain()->calculateGeometryPoint(
+ QPointF(domain()->minX(),
+ category - barWidth / 2 + (set + 1)/setCount * barWidth),
+ m_validData);
+ } else {
+ topLeft = domain()->calculateGeometryPoint(
+ QPointF(0, category - barWidth / 2 + set/setCount * barWidth), m_validData);
+ bottomRight = domain()->calculateGeometryPoint(
+ QPointF(0, category - barWidth / 2 + (set + 1)/setCount * barWidth),
+ m_validData);
+ }
+ if (m_validData) {
rect.setTopLeft(topLeft);
rect.setBottomRight(bottomRight);
- m_layout.append(rect.normalized());
}
}
+ m_layout[layoutIndex] = rect.normalized();
}
QVector<QRectF> HorizontalBarChartItem::calculateLayout()
{
QVector<QRectF> layout;
+ layout.reserve(m_layout.size());
// Use temporary qreals for accuracy
- qreal categoryCount = m_series->d_func()->categoryCount();
qreal setCount = m_series->count();
qreal barWidth = m_series->d_func()->barWidth();
- for(int category = 0; category < categoryCount; category++) {
- for (int set = 0; set < setCount; set++) {
- qreal value = m_series->barSets().at(set)->at(category);
+ for (int set = 0; set < setCount; set++) {
+ const QBarSet *barSet = m_series->barSets().at(set);
+ for (int category = m_firstCategory; category <= m_lastCategory; category++) {
+ qreal value = barSet->at(category);
QRectF rect;
QPointF topLeft;
if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain)
diff --git a/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h b/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h
index 720eadb7..6a80cf1a 100644
--- a/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h
+++ b/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h
@@ -52,7 +52,7 @@ public:
private:
virtual QVector<QRectF> calculateLayout();
- void initializeLayout();
+ void initializeLayout(int set, int category, int layoutIndex, bool resetAnimation);
};
QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp
index ffebbaae..326c5f45 100644
--- a/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp
+++ b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp
@@ -39,50 +39,89 @@ HorizontalPercentBarChartItem::HorizontalPercentBarChartItem(QAbstractBarSeries
{
}
-void HorizontalPercentBarChartItem::initializeLayout()
+QString HorizontalPercentBarChartItem::generateLabelText(int set, int category, qreal value)
{
- qreal categoryCount = m_series->d_func()->categoryCount();
- qreal setCount = m_series->count();
- qreal barWidth = m_series->d_func()->barWidth();
+ Q_UNUSED(value)
- m_layout.clear();
- for(int category = 0; category < categoryCount; category++) {
- for (int set = 0; set < setCount; set++) {
- QRectF rect;
- QPointF topLeft;
- QPointF bottomRight;
- if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) {
- topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2), m_validData);
- bottomRight = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category + barWidth / 2), m_validData);
- } else {
- topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2), m_validData);
- bottomRight = domain()->calculateGeometryPoint(QPointF(0, category + barWidth / 2), m_validData);
- }
-
- if (!m_validData)
- return;
+ static const QString valueTag(QLatin1String("@value"));
+ qreal p = m_series->d_func()->percentageAt(set, category) * 100.0;
+ QString vString(presenter()->numberToString(p, 'f', 0));
+ QString valueLabel;
+ if (m_series->labelsFormat().isEmpty()) {
+ vString.append(QStringLiteral("%"));
+ valueLabel = vString;
+ } else {
+ valueLabel = m_series->labelsFormat();
+ valueLabel.replace(valueTag, vString);
+ }
+
+ return valueLabel;
+}
+void HorizontalPercentBarChartItem::initializeLayout(int set, int category, int layoutIndex,
+ bool resetAnimation)
+{
+ Q_UNUSED(set)
+ Q_UNUSED(resetAnimation)
+
+ QRectF rect;
+
+ int previousSetIndex = layoutIndex - m_categoryCount;
+ if (previousSetIndex >= 0) {
+ rect = m_layout.at(previousSetIndex);
+ rect.setLeft(rect.right());
+ } else {
+ QPointF topLeft;
+ QPointF bottomRight;
+ qreal barWidth = m_series->d_func()->barWidth();
+ if (domain()->type() == AbstractDomain::LogXYDomain
+ || domain()->type() == AbstractDomain::LogXLogYDomain) {
+ topLeft = domain()->calculateGeometryPoint(
+ QPointF(domain()->minX(), category - barWidth / 2), m_validData);
+ bottomRight = domain()->calculateGeometryPoint(
+ QPointF(domain()->minX(), category + barWidth / 2), m_validData);
+ } else {
+ topLeft = domain()->calculateGeometryPoint(
+ QPointF(0, category - barWidth / 2), m_validData);
+ bottomRight = domain()->calculateGeometryPoint(
+ QPointF(0, category + barWidth / 2), m_validData);
+ }
+ if (m_validData) {
rect.setTopLeft(topLeft);
rect.setBottomRight(bottomRight);
- m_layout.append(rect.normalized());
}
}
+ m_layout[layoutIndex] = rect.normalized();
+}
+
+void HorizontalPercentBarChartItem::markLabelsDirty(QBarSet *barset, int visualIndex, int count)
+{
+ Q_UNUSED(barset)
+ // Percent series need to dirty all labels of the stack
+ QList<QBarSet *> sets = m_barMap.keys();
+ for (int set = 0; set < sets.size(); set++)
+ AbstractBarChartItem::markLabelsDirty(sets.at(set), visualIndex, count);
}
QVector<QRectF> HorizontalPercentBarChartItem::calculateLayout()
{
QVector<QRectF> layout;
+ layout.reserve(m_layout.size());
// Use temporary qreals for accuracy
- qreal categoryCount = m_series->d_func()->categoryCount();
qreal setCount = m_series->count();
qreal barWidth = m_series->d_func()->barWidth();
- for(int category = 0; category < categoryCount; category++) {
- qreal sum = 0;
- qreal categorySum = m_series->d_func()->categorySum(category);
- for (int set = 0; set < setCount; set++) {
- qreal value = m_series->barSets().at(set)->at(category);
+ QVector<qreal> categorySums(m_categoryCount);
+ QVector<qreal> tempSums(m_categoryCount, 0.0);
+ for (int category = 0; category < m_categoryCount; category++)
+ categorySums[category] = m_series->d_func()->categorySum(category + m_firstCategory);
+ for (int set = 0; set < setCount; set++) {
+ const QBarSet *barSet = m_series->barSets().at(set);
+ for (int category = m_firstCategory; category <= m_lastCategory; category++) {
+ qreal &sum = tempSums[category - m_firstCategory];
+ const qreal &categorySum = categorySums.at(category - m_firstCategory);
+ qreal value = barSet->at(category);
QRectF rect;
qreal topX = 0;
if (sum > 0)
@@ -107,47 +146,6 @@ QVector<QRectF> HorizontalPercentBarChartItem::calculateLayout()
return layout;
}
-void HorizontalPercentBarChartItem::handleUpdatedBars()
-{
- // Handle changes in pen, brush, labels etc.
- int categoryCount = m_series->d_func()->categoryCount();
- int setCount = m_series->count();
- int itemIndex(0);
- static const QString valueTag(QLatin1String("@value"));
-
- for (int category = 0; category < categoryCount; category++) {
- for (int set = 0; set < setCount; set++) {
- QBarSetPrivate *barSet = m_series->d_func()->barsetAt(set)->d_ptr.data();
- Bar *bar = m_bars.at(itemIndex);
- bar->setPen(barSet->m_pen);
- bar->setBrush(barSet->m_brush);
- bar->update();
-
- QGraphicsTextItem *label = m_labels.at(itemIndex);
- qreal p = m_series->d_func()->percentageAt(set, category) * 100.0;
- QString vString(presenter()->numberToString(p, 'f', 0));
- QString valueLabel;
- if (p == 0) {
- label->setVisible(false);
- } else {
- label->setVisible(m_series->isLabelsVisible());
- if (m_series->labelsFormat().isEmpty()) {
- vString.append(QStringLiteral("%"));
- valueLabel = vString;
- } else {
- valueLabel = m_series->labelsFormat();
- valueLabel.replace(valueTag, vString);
- }
- }
- label->setHtml(valueLabel);
- label->setFont(barSet->m_labelFont);
- label->setDefaultTextColor(barSet->m_labelBrush.color());
- label->update();
- itemIndex++;
- }
- }
-}
-
#include "moc_horizontalpercentbarchartitem_p.cpp"
QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h
index ed6f2c3a..afd8e40d 100644
--- a/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h
+++ b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h
@@ -49,11 +49,12 @@ class HorizontalPercentBarChartItem : public AbstractBarChartItem
Q_OBJECT
public:
HorizontalPercentBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0);
- void handleUpdatedBars();
+ virtual QString generateLabelText(int set, int category, qreal value);
private:
virtual QVector<QRectF> calculateLayout();
- void initializeLayout();
+ void initializeLayout(int set, int category, int layoutIndex, bool resetAnimation);
+ void markLabelsDirty(QBarSet *barset, int visualIndex, int count);
};
QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp
index 78ccd9f4..e38186e4 100644
--- a/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp
+++ b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp
@@ -39,50 +39,62 @@ HorizontalStackedBarChartItem::HorizontalStackedBarChartItem(QAbstractBarSeries
{
}
-void HorizontalStackedBarChartItem::initializeLayout()
+void HorizontalStackedBarChartItem::initializeLayout(int set, int category, int layoutIndex,
+ bool resetAnimation)
{
- qreal categoryCount = m_series->d_func()->categoryCount();
- qreal setCount = m_series->count();
- qreal barWidth = m_series->d_func()->barWidth();
+ Q_UNUSED(set)
+ Q_UNUSED(resetAnimation)
- m_layout.clear();
- for(int category = 0; category < categoryCount; category++) {
- for (int set = 0; set < setCount; set++) {
- QRectF rect;
- QPointF topLeft;
- QPointF bottomRight;
- if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) {
- topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2), m_validData);
- bottomRight = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category + barWidth / 2), m_validData);
- } else {
- topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2), m_validData);
- bottomRight = domain()->calculateGeometryPoint(QPointF(0, category + barWidth / 2), m_validData);
- }
+ QRectF rect;
- if (!m_validData)
- return;
+ int previousSetIndex = layoutIndex - m_categoryCount;
+ if (previousSetIndex >= 0) {
+ rect = m_layout.at(previousSetIndex);
+ rect.setLeft(rect.right());
+ } else {
+ QPointF topLeft;
+ QPointF bottomRight;
+ qreal barWidth = m_series->d_func()->barWidth();
+ if (domain()->type() == AbstractDomain::LogXYDomain
+ || domain()->type() == AbstractDomain::LogXLogYDomain) {
+ topLeft = domain()->calculateGeometryPoint(
+ QPointF(domain()->minX(), category - barWidth / 2), m_validData);
+ bottomRight = domain()->calculateGeometryPoint(
+ QPointF(domain()->minX(), category + barWidth / 2), m_validData);
+ } else {
+ topLeft = domain()->calculateGeometryPoint(
+ QPointF(0, category - barWidth / 2), m_validData);
+ bottomRight = domain()->calculateGeometryPoint(
+ QPointF(0, category + barWidth / 2), m_validData);
+ }
+
+ if (m_validData) {
rect.setTopLeft(topLeft);
rect.setBottomRight(bottomRight);
- m_layout.append(rect.normalized());
}
}
+ m_layout[layoutIndex] = rect.normalized();
}
QVector<QRectF> HorizontalStackedBarChartItem::calculateLayout()
{
QVector<QRectF> layout;
+ layout.reserve(m_layout.size());
// Use temporary qreals for accuracy
- qreal categoryCount = m_series->d_func()->categoryCount();
qreal setCount = m_series->count();
qreal barWidth = m_series->d_func()->barWidth();
- for(int category = 0; category < categoryCount; category++) {
- qreal positiveSum = 0;
- qreal negativeSum = 0;
- for (int set = 0; set < setCount; set++) {
- qreal value = m_series->barSets().at(set)->at(category);
+ QVector<qreal> positiveSums(m_categoryCount, 0.0);
+ QVector<qreal> negativeSums(m_categoryCount, 0.0);
+
+ for (int set = 0; set < setCount; set++) {
+ const QBarSet *barSet = m_series->barSets().at(set);
+ for (int category = m_firstCategory; category <= m_lastCategory; category++) {
+ qreal &positiveSum = positiveSums[category - m_firstCategory];
+ qreal &negativeSum = negativeSums[category - m_firstCategory];
+ qreal value = barSet->at(category);
QRectF rect;
QPointF topLeft;
QPointF bottomRight;
diff --git a/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h
index 6f1b6640..bbbc6bd8 100644
--- a/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h
+++ b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h
@@ -52,7 +52,7 @@ public:
private:
virtual QVector<QRectF> calculateLayout();
- void initializeLayout();
+ void initializeLayout(int set, int category, int layoutIndex, bool resetAnimation);
};
QT_CHARTS_END_NAMESPACE