KD Chart 2 [rev.2.4]
|
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 double xMin = 0.0; 00047 const double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00048 const double yMin = 0.0; 00049 const double yMax = 100.0; 00050 00051 const int rowCount = xMax; 00052 const int colCount = diagram()->model() ? diagram()->model()->columnCount( diagram()->rootIndex() ) : 0; 00053 00054 double usedDepth = 0; 00055 00056 for( int row = 0; row < rowCount ; ++row ) 00057 { 00058 for( int col = 0; col < colCount; ++col ) { 00059 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00060 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 00061 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 00062 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 00063 00064 if( threeDAttrs.isEnabled() ) 00065 if( threeDAttrs.depth() > usedDepth ) 00066 usedDepth = threeDAttrs.depth(); 00067 } 00068 00069 } 00070 00071 const QPointF bottomLeft( QPointF( xMin, yMin ) ); 00072 const QPointF topRight( QPointF( xMax, yMax + usedDepth * 0.3 ) ); 00073 00074 //qDebug() << "BarDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")"; 00075 return QPair< QPointF, QPointF >( bottomLeft, topRight ); 00076 } 00077 00078 void PercentBarDiagram::paint( PaintContext* ctx ) 00079 { 00080 reverseMapper().clear(); 00081 00082 const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached 00083 00084 const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; 00085 const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); 00086 00087 const int rowCount = compressor().modelDataRows(); 00088 const int colCount = compressor().modelDataColumns(); 00089 00090 BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) ); 00091 double barWidth = 0; 00092 double maxDepth = 0; 00093 double width = boundRight.x() - boundLeft.x(); 00094 double groupWidth = width/ (rowCount + 2); 00095 double spaceBetweenBars = 0; 00096 double spaceBetweenGroups = 0; 00097 00098 if ( ba.useFixedBarWidth() ) { 00099 barWidth = ba.fixedBarWidth(); 00100 groupWidth += barWidth; 00101 00102 // Pending Michel set a min and max value for the groupWidth 00103 // related to the area.width 00104 if ( groupWidth < 0 ) 00105 groupWidth = 0; 00106 00107 if ( groupWidth * rowCount > width ) 00108 groupWidth = width / rowCount; 00109 } 00110 00111 // maxLimit: allow the space between bars to be larger until area.width() 00112 // is covered by the groups. 00113 double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); 00114 00115 00116 //Pending Michel: FixMe 00117 if ( ba.useFixedDataValueGap() ) { 00118 if ( width > maxLimit ) 00119 spaceBetweenBars += ba.fixedDataValueGap(); 00120 else 00121 spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); 00122 } 00123 00124 if ( ba.useFixedValueBlockGap() ) 00125 spaceBetweenGroups += ba.fixedValueBlockGap(); 00126 00127 calculateValueAndGapWidths( rowCount, colCount,groupWidth, 00128 barWidth, spaceBetweenBars, spaceBetweenGroups ); 00129 00130 DataValueTextInfoList list; 00131 const double maxValue = 100; // always 100 % 00132 double sumValues = 0; 00133 QVector <double > sumValuesVector; 00134 00135 //calculate sum of values for each column and store 00136 for( int row = 0; row < rowCount; ++row ) 00137 { 00138 for( int col = 0; col < colCount; ++col ) 00139 { 00140 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00141 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00142 //if ( point.value > 0 ) 00143 sumValues += qMax( point.value, -point.value ); 00144 if ( col == colCount - 1 ) { 00145 sumValuesVector << sumValues ; 00146 sumValues = 0; 00147 } 00148 } 00149 } 00150 00151 // calculate stacked percent value 00152 for( int col = 0; col < colCount; ++col ) 00153 { 00154 double offset = spaceBetweenGroups; 00155 if( ba.useFixedBarWidth() ) 00156 offset -= ba.fixedBarWidth(); 00157 00158 if( offset < 0 ) 00159 offset = 0; 00160 00161 for( int row = 0; row < rowCount ; ++row ) 00162 { 00163 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00164 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 00165 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 00166 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 00167 00168 if ( threeDAttrs.isEnabled() ){ 00169 if ( barWidth > 0 ) 00170 barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; 00171 if ( barWidth <= 0 ) { 00172 barWidth = 0; 00173 maxDepth = offset - ( width/rowCount); 00174 } 00175 }else{ 00176 barWidth = (width - (offset*rowCount))/ rowCount; 00177 } 00178 00179 const double value = qMax( p.value, -p.value ); 00180 double stackedValues = 0.0; 00181 double key = 0.0; 00182 00183 // calculate stacked percent value 00184 // we only take in account positives values for now. 00185 for( int k = col; k >= 0 ; --k ) 00186 { 00187 const CartesianDiagramDataCompressor::CachePosition position( row, k ); 00188 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00189 stackedValues += qMax( point.value, -point.value ); 00190 key = point.key; 00191 } 00192 00193 QPointF point, previousPoint; 00194 if( sumValuesVector.at( row ) != 0 && value > 0 ) { 00195 point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues / sumValuesVector.at( row ) * maxValue ) ); 00196 point.rx() += offset / 2; 00197 00198 previousPoint = ctx->coordinatePlane()->translate( QPointF( key, ( stackedValues - value)/sumValuesVector.at(row)* maxValue ) ); 00199 } 00200 const double barHeight = previousPoint.y() - point.y(); 00201 00202 const QRectF rect( point, QSizeF( barWidth, barHeight ) ); 00203 appendDataValueTextInfoToList( diagram(), list, sourceIndex, PositionPoints( rect ), 00204 Position::NorthWest, Position::SouthEast, 00205 value ); 00206 paintBars( ctx, sourceIndex, rect, maxDepth ); 00207 } 00208 } 00209 paintDataValueTextsAndMarkers( diagram(), ctx, list, false ); 00210 }