00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <QModelIndex>
00031
00032 #include "KDChartBarDiagram.h"
00033 #include "KDChartTextAttributes.h"
00034 #include "KDChartAttributesModel.h"
00035 #include "KDChartAbstractCartesianDiagram.h"
00036 #include "KDChartStackedBarDiagram_p.h"
00037
00038 using namespace KDChart;
00039
00040 StackedBarDiagram::StackedBarDiagram( BarDiagram* d )
00041 : BarDiagramType( d )
00042 {
00043 }
00044
00045 BarDiagram::BarType StackedBarDiagram::type() const
00046 {
00047 return BarDiagram::Stacked;
00048 }
00049
00050 const QPair<QPointF, QPointF> StackedBarDiagram::calculateDataBoundaries() const
00051 {
00052 const int rowCount = compressor().modelDataRows();
00053 const int colCount = compressor().modelDataColumns();
00054
00055 double xMin = 0;
00056 double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
00057 double yMin = 0, yMax = 0;
00058
00059 bool bStarting = true;
00060 for( int row = 0; row < rowCount; ++row )
00061 {
00062
00063 double stackedValues = 0;
00064 for ( int col = 0; col < colCount ; ++col )
00065 {
00066 const CartesianDiagramDataCompressor::CachePosition position( row, col );
00067 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00068 stackedValues += point.value;
00069
00070
00071
00072 if( bStarting ){
00073 yMin = stackedValues;
00074 yMax = stackedValues;
00075 bStarting = false;
00076 }else{
00077 yMin = qMin( yMin, stackedValues );
00078 yMax = qMax( yMax, stackedValues );
00079 }
00080 }
00081 }
00082
00083 if ( yMax == yMin ) {
00084 if ( yMin == 0.0 )
00085 yMax = 0.1;
00086 else if( yMax < 0.0 )
00087 yMax = 0.0;
00088 else if( yMin > 0.0 )
00089 yMin = 0.0;
00090 }
00091 const QPointF bottomLeft ( QPointF( xMin, yMin ) );
00092 const QPointF topRight ( QPointF( xMax, yMax ) );
00093
00094 return QPair< QPointF, QPointF >( bottomLeft, topRight );
00095 }
00096
00097 void StackedBarDiagram::paint( PaintContext* ctx )
00098 {
00099 reverseMapper().clear();
00100
00101 const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries();
00102
00103 const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
00104 const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
00105
00106 const int rowCount = compressor().modelDataRows();
00107 const int colCount = compressor().modelDataColumns();
00108
00109 BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) );
00110 double barWidth = 0;
00111 double maxDepth = 0;
00112 double width = boundRight.x() - boundLeft.x();
00113 double groupWidth = width/ (rowCount + 2);
00114 double spaceBetweenBars = 0;
00115 double spaceBetweenGroups = 0;
00116
00117 if ( ba.useFixedBarWidth() ) {
00118 barWidth = ba.fixedBarWidth();
00119 groupWidth += barWidth;
00120
00121
00122
00123 if ( groupWidth < 0 )
00124 groupWidth = 0;
00125
00126 if ( groupWidth * rowCount > ctx->rectangle().width() )
00127 groupWidth = ctx->rectangle().width() / rowCount;
00128 }
00129
00130
00131
00132 double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
00133
00134
00135
00136 if ( ba.useFixedDataValueGap() ) {
00137 if ( ctx->rectangle().width() > maxLimit )
00138 spaceBetweenBars += ba.fixedDataValueGap();
00139 else
00140 spaceBetweenBars = ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1);
00141 }
00142
00143 if ( ba.useFixedValueBlockGap() )
00144 spaceBetweenGroups += ba.fixedValueBlockGap();
00145
00146 calculateValueAndGapWidths( rowCount, colCount,groupWidth,
00147 barWidth, spaceBetweenBars, spaceBetweenGroups );
00148
00149 DataValueTextInfoList list;
00150 for( int col = 0; col < colCount; ++col )
00151 {
00152 double offset = spaceBetweenGroups;
00153 if( ba.useFixedBarWidth() )
00154 offset -= ba.fixedBarWidth();
00155
00156 if( offset < 0 )
00157 offset = 0;
00158
00159 for( int row = 0; row < rowCount; ++row )
00160 {
00161 const CartesianDiagramDataCompressor::CachePosition position( row, col );
00162 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position );
00163
00164 const QModelIndex index = attributesModel()->mapToSource( p.index );
00165 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index );
00166 const double value = p.value;
00167 double stackedValues = 0.0;
00168 double key = 0.0;
00169
00170 if ( threeDAttrs.isEnabled() ) {
00171 if ( barWidth > 0 )
00172 barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
00173 if ( barWidth <= 0 ) {
00174 barWidth = 0;
00175 maxDepth = offset - (width/rowCount);
00176 }
00177 } else
00178 barWidth = (ctx->rectangle().width() - (offset*rowCount))/ rowCount ;
00179
00180 for ( int k = col; k >= 0; --k )
00181 {
00182 const CartesianDiagramDataCompressor::CachePosition position( row, k );
00183 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00184 stackedValues += point.value;
00185 key = point.key;
00186 }
00187 QPointF point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues ) );
00188 point.rx() += offset / 2;
00189 const QPointF previousPoint = ctx->coordinatePlane()->translate( QPointF( key, stackedValues - value ) );
00190 const double barHeight = previousPoint.y() - point.y();
00191
00192 const QRectF rect( point, QSizeF( barWidth , barHeight ) );
00193 appendDataValueTextInfoToList( diagram(), list, index, PositionPoints( rect ),
00194 Position::NorthWest, Position::SouthEast,
00195 value );
00196 paintBars( ctx, index, rect, maxDepth );
00197 }
00198 }
00199 paintDataValueTextsAndMarkers( diagram(), ctx, list, false );
00200 }