KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 00014 ** 00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 ** 00018 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 00020 ** 00021 **********************************************************************/ 00022 00023 #include "KDChartPercentBarDiagram_p.h" 00024 00025 #include <QModelIndex> 00026 00027 #include "KDChartBarDiagram.h" 00028 #include "KDChartTextAttributes.h" 00029 #include "KDChartAttributesModel.h" 00030 #include "KDChartAbstractCartesianDiagram.h" 00031 00032 using namespace KDChart; 00033 00034 PercentBarDiagram::PercentBarDiagram( BarDiagram* d ) 00035 : BarDiagramType( d ) 00036 { 00037 } 00038 00039 BarDiagram::BarType PercentBarDiagram::type() const 00040 { 00041 return BarDiagram::Percent; 00042 } 00043 00044 const QPair<QPointF, QPointF> PercentBarDiagram::calculateDataBoundaries() const 00045 { 00046 const int rowCount = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00047 const int colCount = diagram()->model() ? diagram()->model()->columnCount( diagram()->rootIndex() ) : 0; 00048 00049 const qreal xMin = 0.0; 00050 const qreal xMax = rowCount; 00051 const qreal yMin = 0.0; 00052 const qreal yMax = 100.0; 00053 00054 qreal usedDepth = 0; 00055 00056 for( int row = 0; row < rowCount ; ++row ) { 00057 for( int col = 0; col < colCount; ++col ) { 00058 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00059 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 00060 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 00061 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 00062 00063 if ( threeDAttrs.isEnabled() && threeDAttrs.depth() > usedDepth ) { 00064 usedDepth = threeDAttrs.depth(); 00065 } 00066 } 00067 } 00068 00069 return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax + usedDepth * 0.3 ) ); 00070 } 00071 00072 void PercentBarDiagram::paint( PaintContext* ctx ) 00073 { 00074 reverseMapper().clear(); 00075 00076 const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached 00077 00078 const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; 00079 const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); 00080 00081 const int rowCount = compressor().modelDataRows(); 00082 const int colCount = compressor().modelDataColumns(); 00083 00084 BarAttributes ba = diagram()->barAttributes(); 00085 qreal barWidth = 0; 00086 qreal maxDepth = 0; 00087 qreal width = boundRight.x() - boundLeft.x(); 00088 qreal groupWidth = width/ (rowCount + 2); 00089 qreal spaceBetweenBars = 0; 00090 qreal spaceBetweenGroups = 0; 00091 00092 if ( ba.useFixedBarWidth() ) { 00093 barWidth = ba.fixedBarWidth(); 00094 groupWidth += barWidth; 00095 00096 // Pending Michel set a min and max value for the groupWidth 00097 // related to the area.width 00098 if ( groupWidth < 0 ) 00099 groupWidth = 0; 00100 00101 if ( groupWidth * rowCount > width ) 00102 groupWidth = width / rowCount; 00103 } 00104 00105 // maxLimit: allow the space between bars to be larger until area.width() 00106 // is covered by the groups. 00107 qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); 00108 00109 00110 //Pending Michel: FixMe 00111 if ( ba.useFixedDataValueGap() ) { 00112 if ( width > maxLimit ) 00113 spaceBetweenBars += ba.fixedDataValueGap(); 00114 else 00115 spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); 00116 } 00117 00118 if ( ba.useFixedValueBlockGap() ) 00119 spaceBetweenGroups += ba.fixedValueBlockGap(); 00120 00121 calculateValueAndGapWidths( rowCount, colCount,groupWidth, 00122 barWidth, spaceBetweenBars, spaceBetweenGroups ); 00123 00124 LabelPaintCache lpc; 00125 const qreal maxValue = 100; // always 100 % 00126 qreal sumValues = 0; 00127 QVector <qreal > sumValuesVector; 00128 00129 //calculate sum of values for each column and store 00130 for( int row = 0; row < rowCount; ++row ) 00131 { 00132 for( int col = 0; col < colCount; ++col ) 00133 { 00134 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00135 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00136 //if ( point.value > 0 ) 00137 sumValues += qMax( point.value, -point.value ); 00138 if ( col == colCount - 1 ) { 00139 sumValuesVector << sumValues ; 00140 sumValues = 0; 00141 } 00142 } 00143 } 00144 00145 // calculate stacked percent value 00146 for( int col = 0; col < colCount; ++col ) 00147 { 00148 qreal offset = spaceBetweenGroups; 00149 if( ba.useFixedBarWidth() ) 00150 offset -= ba.fixedBarWidth(); 00151 00152 if( offset < 0 ) 00153 offset = 0; 00154 00155 for( int row = 0; row < rowCount ; ++row ) 00156 { 00157 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00158 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 00159 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 00160 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 00161 00162 if ( threeDAttrs.isEnabled() ){ 00163 if ( barWidth > 0 ) 00164 barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; 00165 if ( barWidth <= 0 ) { 00166 barWidth = 0; 00167 maxDepth = offset - ( width/rowCount); 00168 } 00169 }else{ 00170 barWidth = (width - (offset*rowCount))/ rowCount; 00171 } 00172 00173 const qreal value = qMax( p.value, -p.value ); 00174 qreal stackedValues = 0.0; 00175 qreal key = 0.0; 00176 00177 // calculate stacked percent value 00178 // we only take in account positives values for now. 00179 for( int k = col; k >= 0 ; --k ) 00180 { 00181 const CartesianDiagramDataCompressor::CachePosition position( row, k ); 00182 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00183 stackedValues += qMax( point.value, -point.value ); 00184 key = point.key; 00185 } 00186 00187 QPointF point, previousPoint; 00188 if( sumValuesVector.at( row ) != 0 && value > 0 ) { 00189 point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues / sumValuesVector.at( row ) * maxValue ) ); 00190 point.rx() += offset / 2; 00191 00192 previousPoint = ctx->coordinatePlane()->translate( QPointF( key, ( stackedValues - value)/sumValuesVector.at(row)* maxValue ) ); 00193 } 00194 const qreal barHeight = previousPoint.y() - point.y(); 00195 00196 const QRectF rect( point, QSizeF( barWidth, barHeight ) ); 00197 addLabel( &lpc, sourceIndex, PositionPoints( rect ), Position::North, 00198 Position::South, value ); 00199 paintBars( ctx, sourceIndex, rect, maxDepth ); 00200 } 00201 } 00202 paintDataValueTextsAndMarkers( ctx, lpc, false ); 00203 }