KD Chart 2  [rev.2.7]
KDChartPercentBarDiagram_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "KDChartPercentBarDiagram_p.h"
24 
25 #include <QModelIndex>
26 
27 #include "KDChartBarDiagram.h"
28 #include "KDChartTextAttributes.h"
29 #include "KDChartAttributesModel.h"
31 
32 using namespace KDChart;
33 
34 PercentBarDiagram::PercentBarDiagram( BarDiagram* d )
35  : BarDiagramType( d )
36 {
37 }
38 
39 BarDiagram::BarType PercentBarDiagram::type() const
40 {
41  return BarDiagram::Percent;
42 }
43 
44 const QPair<QPointF, QPointF> PercentBarDiagram::calculateDataBoundaries() const
45 {
46  const int rowCount = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
47  const int colCount = diagram()->model() ? diagram()->model()->columnCount( diagram()->rootIndex() ) : 0;
48 
49  const qreal xMin = 0.0;
50  const qreal xMax = rowCount;
51  const qreal yMin = 0.0;
52  const qreal yMax = 100.0;
53 
54  qreal usedDepth = 0;
55 
56  for ( int row = 0; row < rowCount ; ++row ) {
57  for ( int col = 0; col < colCount; ++col ) {
58  const CartesianDiagramDataCompressor::CachePosition position( row, col );
59  const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position );
60  QModelIndex sourceIndex = attributesModel()->mapToSource( p.index );
61  ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex );
62 
63  if ( threeDAttrs.isEnabled() && threeDAttrs.depth() > usedDepth ) {
64  usedDepth = threeDAttrs.depth();
65  }
66  }
67  }
68 
69  return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax + usedDepth * 0.3 ) );
70 }
71 
72 void PercentBarDiagram::paint( PaintContext* ctx )
73 {
74  reverseMapper().clear();
75 
76  const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
77 
78  const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
79  const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
80 
81  const int rowCount = compressor().modelDataRows();
82  const int colCount = compressor().modelDataColumns();
83 
84  BarAttributes ba = diagram()->barAttributes();
85  qreal barWidth = 0;
86  qreal maxDepth = 0;
87  qreal width = boundRight.x() - boundLeft.x();
88  qreal groupWidth = width / rowCount;
89  qreal spaceBetweenBars = 0;
90  qreal spaceBetweenGroups = 0;
91 
92  if ( ba.useFixedBarWidth() ) {
93  barWidth = ba.fixedBarWidth();
94  groupWidth += barWidth;
95 
96  // Pending Michel set a min and max value for the groupWidth
97  // related to the area.width
98  if ( groupWidth < 0 )
99  groupWidth = 0;
100 
101  if ( groupWidth * rowCount > width )
102  groupWidth = width / rowCount;
103  }
104 
105  // maxLimit: allow the space between bars to be larger until area.width()
106  // is covered by the groups.
107  qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
108 
109 
110  //Pending Michel: FixMe
111  if ( ba.useFixedDataValueGap() ) {
112  if ( width > maxLimit )
113  spaceBetweenBars += ba.fixedDataValueGap();
114  else
115  spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1);
116  }
117 
118  if ( ba.useFixedValueBlockGap() )
119  spaceBetweenGroups += ba.fixedValueBlockGap();
120 
121  calculateValueAndGapWidths( rowCount, colCount,groupWidth,
122  barWidth, spaceBetweenBars, spaceBetweenGroups );
123 
124  LabelPaintCache lpc;
125  const qreal maxValue = 100; // always 100 %
126  qreal sumValues = 0;
127  QVector <qreal > sumValuesVector;
128 
129  //calculate sum of values for each column and store
130  for ( int row = 0; row < rowCount; ++row )
131  {
132  for ( int col = 0; col < colCount; ++col )
133  {
134  const CartesianDiagramDataCompressor::CachePosition position( row, col );
135  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
136  //if ( point.value > 0 )
137  sumValues += qMax( point.value, -point.value );
138  if ( col == colCount - 1 ) {
139  sumValuesVector << sumValues ;
140  sumValues = 0;
141  }
142  }
143  }
144 
145  // calculate stacked percent value
146  for ( int col = 0; col < colCount; ++col )
147  {
148  qreal offset = spaceBetweenGroups;
149  if ( ba.useFixedBarWidth() )
150  offset -= ba.fixedBarWidth();
151 
152  if ( offset < 0 )
153  offset = 0;
154 
155  for ( int row = 0; row < rowCount ; ++row )
156  {
157  const CartesianDiagramDataCompressor::CachePosition position( row, col );
158  const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position );
159  QModelIndex sourceIndex = attributesModel()->mapToSource( p.index );
160  ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex );
161 
162  if ( threeDAttrs.isEnabled() ) {
163  if ( barWidth > 0 )
164  barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
165  if ( barWidth <= 0 ) {
166  barWidth = 0;
167  maxDepth = offset - ( width/rowCount);
168  }
169  } else {
170  barWidth = (width - (offset*rowCount))/ rowCount;
171  }
172 
173  const qreal value = qMax( p.value, -p.value );
174  qreal stackedValues = 0.0;
175  qreal key = 0.0;
176 
177  // calculate stacked percent value
178  // we only take in account positives values for now.
179  for ( int k = col; k >= 0 ; --k )
180  {
181  const CartesianDiagramDataCompressor::CachePosition position( row, k );
182  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
183  stackedValues += qMax( point.value, -point.value );
184  key = point.key;
185  }
186 
187  QPointF point, previousPoint;
188  if ( sumValuesVector.at( row ) != 0 && value > 0 ) {
189  point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues / sumValuesVector.at( row ) * maxValue ) );
190  point.rx() += offset / 2;
191 
192  previousPoint = ctx->coordinatePlane()->translate( QPointF( key, ( stackedValues - value)/sumValuesVector.at(row)* maxValue ) );
193  }
194  const qreal barHeight = previousPoint.y() - point.y();
195 
196  const QRectF rect( point, QSizeF( barWidth, barHeight ) );
197  m_private->addLabel( &lpc, sourceIndex, 0, PositionPoints( rect ), Position::North,
198  Position::South, value );
199  paintBars( ctx, sourceIndex, rect, maxDepth );
200  }
201  }
202  m_private->paintDataValueTextsAndMarkers( ctx, lpc, false );
203 }
virtual const QPointF translate(const QPointF &diagramPoint) const =0
Translate the given point in value space coordinates to a position in pixel space.
AbstractCoordinatePlane * coordinatePlane() const
Set of attributes for changing the appearance of bar charts.
static const Position & South
BarDiagram defines a common bar diagram.
Stores information about painting diagrams.
A set of 3D bar attributes.
Stores the absolute target points of a Position.
static const Position & North

Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/

https://www.kdab.com/development-resources/qt-tools/kd-chart/