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 "KDChartNormalBarDiagram_p.h"
00037
00038 using namespace KDChart;
00039
00040 NormalBarDiagram::NormalBarDiagram( BarDiagram* d )
00041 : BarDiagramType( d )
00042 {
00043 }
00044
00045 BarDiagram::BarType NormalBarDiagram::type() const
00046 {
00047 return BarDiagram::Normal;
00048 }
00049
00050 const QPair<QPointF, QPointF> NormalBarDiagram::calculateDataBoundaries() const
00051 {
00052 const int rowCount = compressor().modelDataRows();
00053 const int colCount = compressor().modelDataColumns();
00054
00055 double xMin = 0.0;
00056 double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
00057 double yMin = 0.0, yMax = 0.0;
00058
00059 bool bStarting = true;
00060 for ( int column = 0; column < colCount; ++column )
00061 {
00062 for ( int row = 0; row < rowCount; ++row )
00063 {
00064 const CartesianDiagramDataCompressor::CachePosition position( row, column );
00065 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00066 const double value = point.value;
00067
00068
00069
00070 if( bStarting ){
00071 yMin = value;
00072 yMax = value;
00073 bStarting = false;
00074 }else{
00075 yMin = qMin( yMin, value );
00076 yMax = qMax( yMax, value );
00077 }
00078 }
00079 }
00080
00081
00082 if ( yMax == yMin ) {
00083 if ( yMin == 0.0 )
00084 yMax = 0.1;
00085 else if( yMax < 0.0 )
00086 yMax = 0.0;
00087 else if( yMin > 0.0 )
00088 yMin = 0.0;
00089 }
00090 const QPointF bottomLeft ( QPointF( xMin, yMin ) );
00091 const QPointF topRight ( QPointF( xMax, yMax ) );
00092
00093 return QPair< QPointF, QPointF >( bottomLeft, topRight );
00094 }
00095
00096 void NormalBarDiagram::paint( PaintContext* ctx )
00097 {
00098 reverseMapper().clear();
00099
00100 const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries();
00101
00102 const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
00103 const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
00104
00105 const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00106 const int colCount = attributesModel()->columnCount(attributesModelRootIndex());
00107
00108 BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) );
00109 double barWidth = 0;
00110 double maxDepth = 0;
00111 double width = boundRight.x() - boundLeft.x();
00112 double groupWidth = width / (rowCount + 2);
00113 double spaceBetweenBars = 0;
00114 double spaceBetweenGroups = 0;
00115
00116 if ( ba.useFixedBarWidth() ) {
00117
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 if ( ba.useFixedDataValueGap() ) {
00136 if ( ctx->rectangle().width() > maxLimit )
00137 spaceBetweenBars += ba.fixedDataValueGap();
00138 else
00139 spaceBetweenBars = ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1);
00140 }
00141
00142 if ( ba.useFixedValueBlockGap() ) {
00143 spaceBetweenGroups += ba.fixedValueBlockGap();
00144 }
00145
00146 calculateValueAndGapWidths( rowCount, colCount,groupWidth,
00147 barWidth, spaceBetweenBars, spaceBetweenGroups );
00148
00149 DataValueTextInfoList list;
00150
00151 for( int row = 0; row < rowCount; ++row )
00152 {
00153 double offset = -groupWidth/2 + spaceBetweenGroups/2;
00154
00155 if ( ba.useFixedDataValueGap() )
00156 {
00157 if ( spaceBetweenBars > 0 )
00158 {
00159 if ( ctx->rectangle().width() > maxLimit )
00160 offset -= ba.fixedDataValueGap();
00161 else
00162 offset -= ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1);
00163
00164 }
00165 else
00166 {
00167 offset += barWidth/2;
00168 }
00169 }
00170
00171 for( int column=0; column< colCount; ++column )
00172 {
00173
00174 const CartesianDiagramDataCompressor::CachePosition position( row, column );
00175 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00176 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
00177 const qreal value = point.value;
00178 QPointF topPoint = ctx->coordinatePlane()->translate( QPointF( point.key + 0.5, value ) );
00179 QPointF bottomPoint = ctx->coordinatePlane()->translate( QPointF( point.key, 0 ) );
00180 const double barHeight = bottomPoint.y() - topPoint.y();
00181 topPoint.setX( topPoint.x() + offset );
00182 const QRectF rect( topPoint, QSizeF( barWidth, barHeight ) );
00183 appendDataValueTextInfoToList( diagram(), list, sourceIndex, PositionPoints( rect ),
00184 Position::NorthWest, Position::SouthEast,
00185 point.value );
00186 paintBars( ctx, sourceIndex, rect, maxDepth );
00187
00188 offset += barWidth + spaceBetweenBars;
00189 }
00190 }
00191 paintDataValueTextsAndMarkers( diagram(), ctx, list, false );
00192 }