KD Chart 2  [rev.2.6]
KDChartPercentLineDiagram_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2019 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 "KDChartPercentLineDiagram_p.h"
24 
25 #include <QModelIndex>
26 
27 #include "KDChartBarDiagram.h"
28 #include "KDChartLineDiagram.h"
29 #include "KDChartTextAttributes.h"
30 #include "KDChartAttributesModel.h"
32 #include "PaintingHelpers_p.h"
33 
34 using namespace KDChart;
35 using namespace std;
36 
37 PercentLineDiagram::PercentLineDiagram( LineDiagram* d )
38  : LineDiagramType( d )
39 {
40 }
41 
42 LineDiagram::LineType PercentLineDiagram::type() const
43 {
44  return LineDiagram::Percent;
45 }
46 
47 const QPair<QPointF, QPointF> PercentLineDiagram::calculateDataBoundaries() const
48 {
49  const qreal xMin = 0.0;
50  qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
51  if ( !diagram()->centerDataPoints() && diagram()->model() )
52  xMax -= 1;
53  const qreal yMin = 0.0;
54  const qreal yMax = 100.0;
55 
56  QPointF bottomLeft( QPointF( xMin, yMin ) );
57  QPointF topRight( QPointF( xMax, yMax ) );
58  return QPair<QPointF, QPointF> ( bottomLeft, topRight );
59 }
60 
61 void PercentLineDiagram::paint( PaintContext* ctx )
62 {
63  reverseMapper().clear();
64 
65  const int columnCount = compressor().modelDataColumns();
66  const int rowCount = compressor().modelDataRows();
67 
68 // FIXME integrade column index retrieval to compressor:
69  int maxFound = 0;
70 // { // find the last column number that is not hidden
71 // for ( int iColumn = datasetDimension() - 1;
72 // iColumn < columnCount;
73 // iColumn += datasetDimension() )
74 // if ( ! diagram()->isHidden( iColumn ) )
75 // maxFound = iColumn;
76 // }
77  maxFound = columnCount;
78  // ^^^ temp
79  const int lastVisibleColumn = maxFound - 1;
80 
81  LabelPaintCache lpc;
82  LineAttributesInfoList lineList;
83 
84  //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent
85 
86  qreal maxValue = 100; // always 100%
87  qreal sumValues = 0;
88  QVector <qreal > percentSumValues;
89 
90  //calculate sum of values for each column and store
91  for ( int row = 0; row < rowCount; ++row )
92  {
93  for ( int col = 0; col < columnCount; ++col )
94  {
95  const CartesianDiagramDataCompressor::CachePosition position( row, col );
96  CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
97  const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
98  const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
100  if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged )
101  point.value = interpolateMissingValue( position );
102  if ( point.value > 0 )
103  sumValues += point.value;
104  if ( col == lastVisibleColumn )
105  {
106  percentSumValues << sumValues ;
107  sumValues = 0;
108  }
109  }
110  }
111 
112  QList<QPointF> bottomPoints;
113  bool bFirstDataset = true;
114 
115  for ( int column = 0; column < columnCount; ++column )
116  {
117  //display area can be set by dataset ( == column) and/or by cell
118  LineAttributes laPreviousCell; // by default no area is drawn
119  QModelIndex indexPreviousCell;
120  QList<QPolygonF> areas;
121  QList<QPointF> points;
122 
123  for ( int row = 0; row < rowCount; ++row )
124  {
125  const CartesianDiagramDataCompressor::CachePosition position( row, column );
126  CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
127  const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
128  const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
129  const bool bDisplayCellArea = laCell.displayArea();
130 
131  qreal stackedValues = 0, nextValues = 0, nextKey = 0;
132  for ( int column2 = column;
133  column2 >= 0;//datasetDimension() - 1;
134  column2 -= 1 )//datasetDimension() )
135  {
136  const CartesianDiagramDataCompressor::CachePosition position( row, column2 );
137  CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
138 
140  if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged )
141  point.value = interpolateMissingValue( position );
142 
143  const qreal val = point.value;
144  if ( val > 0 )
145  stackedValues += val;
146  //qDebug() << valueForCell( iRow, iColumn2 );
147  if ( row + 1 < rowCount ) {
148  const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 );
149  CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
150 
152  if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged )
153  point.value = interpolateMissingValue( position );
154 
155  const qreal val = point.value;
156  if ( val > 0 )
157  nextValues += val;
158  nextKey = point.key;
159  }
160  }
161  if ( percentSumValues.at( row ) != 0 )
162  stackedValues = stackedValues / percentSumValues.at( row ) * maxValue;
163  else
164  stackedValues = 0.0;
165  //qDebug() << stackedValues << endl;
166  QPointF nextPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) );
167  points << nextPoint;
168 
169  const QPointF ptNorthWest( nextPoint );
170  const QPointF ptSouthWest(
171  bDisplayCellArea
172  ? ( bFirstDataset
173  ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, 0.0 ) )
174  : bottomPoints.at( row )
175  )
176  : nextPoint );
177  QPointF ptNorthEast;
178  QPointF ptSouthEast;
179 
180  if ( row + 1 < rowCount ) {
181  if ( percentSumValues.at( row + 1 ) != 0 )
182  nextValues = nextValues / percentSumValues.at( row + 1 ) * maxValue;
183  else
184  nextValues = 0.0;
185  QPointF toPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) );
186  lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) );
187  ptNorthEast = toPoint;
188  ptSouthEast =
189  bDisplayCellArea
190  ? ( bFirstDataset
191  ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, 0.0 ) )
192  : bottomPoints.at( row + 1 )
193  )
194  : toPoint;
195  if ( areas.count() && laCell != laPreviousCell ) {
196  PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
197  areas.clear();
198  }
199  if ( bDisplayCellArea ) {
200  QPolygonF poly;
201  poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
202  areas << poly;
203  laPreviousCell = laCell;
204  indexPreviousCell = sourceIndex;
205  } else {
206  //qDebug() << "no area shown for row"<<iRow<<" column"<<iColumn;
207  }
208  } else {
209  ptNorthEast = ptNorthWest;
210  ptSouthEast = ptSouthWest;
211  }
212 
213  if ( !ISNAN( point.value ) )
214  {
215  const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
216  m_private->addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest,
217  Position::NorthWest, point.value );
218  }
219  }
220  if ( areas.count() ) {
221  PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
222  areas.clear();
223  }
224  bottomPoints = points;
225  bFirstDataset = false;
226  }
227  PaintingHelpers::paintElements( m_private, ctx, lpc, lineList );
228 }
KDChartEnums::PositionValue value() const
Returns an integer value corresponding to this Position.
void paintElements(AbstractDiagram::Private *diagramPrivate, PaintContext *ctx, const LabelPaintCache &lpc, const LineAttributesInfoList &lineList)
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 line charts.
void paintAreas(AbstractDiagram::Private *diagramPrivate, PaintContext *ctx, const QModelIndex &index, const QList< QPolygonF > &areas, uint opacity)
static const Position & NorthWest
LineDiagram defines a common line diagram.
Stores information about painting diagrams.
Stores the absolute target points of a Position.
MissingValuesPolicy
MissingValuesPolicy specifies how a missing value will be shown in a line diagram.
MissingValuesPolicy missingValuesPolicy() const

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
https://www.kdab.com/
https://www.kdab.com/products/kd-chart/