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 "KDChartPercentLyingBarDiagram_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 PercentLyingBarDiagram::PercentLyingBarDiagram( BarDiagram* d ) 00035 : BarDiagramType( d ) 00036 { 00037 } 00038 00039 BarDiagram::BarType PercentLyingBarDiagram::type() const 00040 { 00041 return BarDiagram::Percent; 00042 } 00043 00044 const QPair<QPointF, QPointF> PercentLyingBarDiagram::calculateDataBoundaries() const 00045 { 00046 //const int rowCount = compressor().modelDataRows(); 00047 //const int colCount = compressor().modelDataColumns(); 00048 00049 const double xMin = 0; 00050 const double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00051 double yMin = 0.0, yMax = 100.0; 00052 /*for( int col = 0; col < colCount; ++col ) 00053 { 00054 for( int row = 0; row < rowCount; ++row ) 00055 { 00056 // Ordinate should begin at 0 the max value being the 100% pos 00057 const QModelIndex idx = diagram()->model()->index( row, col, diagram()->rootIndex() ); 00058 // only positive values are handled 00059 double value = diagram()->model()->data( idx ).toDouble(); 00060 if ( value > 0 ) 00061 yMax = qMax( yMax, value ); 00062 } 00063 }*/ 00064 // special cases 00065 if ( yMax == yMin ) { 00066 if ( yMin == 0.0 ) 00067 yMax = 0.1; //we need at least a range 00068 else 00069 yMax = 0.0; // they are the same but negative 00070 } 00071 const QPointF bottomLeft( QPointF( yMin, xMin ) ); 00072 const QPointF topRight( QPointF( yMax, xMax ) ); 00073 00074 //qDebug() << "BarDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")"; 00075 return QPair< QPointF, QPointF >( bottomLeft, topRight ); 00076 } 00077 00078 void PercentLyingBarDiagram::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 = boundLeft.y() - boundRight.y(); 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 = ((ctx->rectangle().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.0; // 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 curRow = rowCount - 1; curRow >= 0; --curRow ) 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 col = 0; col < colCount ; ++col ) 00162 { 00163 double threeDOffset = 0.0; 00164 const CartesianDiagramDataCompressor::CachePosition position( curRow, col ); 00165 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 00166 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 00167 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 00168 00169 if ( threeDAttrs.isEnabled() ){ 00170 if ( barWidth > 0 ) { 00171 barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; 00172 threeDOffset = threeDAttrs.depth(); 00173 } 00174 if ( barWidth <= 0 ) { 00175 barWidth = 0.1; 00176 threeDOffset = (width - (offset*rowCount))/ rowCount; 00177 } 00178 }else{ 00179 barWidth = (width - (offset*rowCount))/ rowCount; 00180 } 00181 00182 const double value = qMax( p.value, -p.value ); 00183 double stackedValues = 0.0; 00184 double key = 0.0; 00185 00186 // calculate stacked percent value 00187 // we only take in account positives values for now. 00188 for( int k = col; k >= 0 ; --k ) 00189 { 00190 const CartesianDiagramDataCompressor::CachePosition position( curRow, k ); 00191 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00192 stackedValues += qMax( point.value, -point.value ); 00193 key = point.key; 00194 } 00195 00196 QPointF point, previousPoint; 00197 if( sumValuesVector.at( curRow ) != 0 && value > 0 ) { 00198 QPointF dataPoint( ( stackedValues / sumValuesVector.at( curRow ) * maxValue ), rowCount - key ); 00199 point = ctx->coordinatePlane()->translate( dataPoint ); 00200 point.ry() += offset / 2 + threeDOffset; 00201 00202 previousPoint = ctx->coordinatePlane()->translate( QPointF( ( ( stackedValues - value) / sumValuesVector.at( curRow ) * maxValue ), rowCount - key ) ); 00203 } 00204 00205 const double barHeight = point.x() - previousPoint.x(); 00206 00207 point.setX ( point.x() - barHeight ); 00208 00209 const QRectF rect( point, QSizeF( barHeight, barWidth ) ); 00210 appendDataValueTextInfoToList( diagram(), list, sourceIndex, PositionPoints( rect ), 00211 Position::NorthEast, Position::SouthWest, 00212 value ); 00213 paintBars( ctx, sourceIndex, rect, maxDepth ); 00214 } 00215 } 00216 paintDataValueTextsAndMarkers( diagram(), ctx, list, false ); 00217 }