# KDChartStackedBarDiagram_p.cpp

Go to the documentation of this file.

    00001 /* -*- Mode: C++ -*-
    00002    KDChart - a multi-platform charting engine
    00003    */
    00004
    00005 /****************************************************************************
    00006  ** Copyright (C) 2005-2007 Klarälvdalens Datakonsult AB.  All rights reserved.
    00007  **
    00008  ** This file is part of the KD Chart library.
    00009  **
    00010  ** This file may be distributed and/or modified under the terms of the
    00011  ** GNU General Public License version 2 as published by the Free Software
    00012  ** Foundation and appearing in the file LICENSE.GPL included in the
    00013  ** packaging of this file.
    00014  **
    00015  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00016  ** accordance with the KD Chart Commercial License Agreement provided with
    00017  ** the Software.
    00018  **
    00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00021  **
    00022  ** See http://www.kdab.net/kdchart for
    00023  **   information about KD Chart Commercial License Agreements.
    00024  **
    00025  ** Contact info@kdab.net if any conditions of this
    00026  ** licensing are not clear to you.
    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         // calculate sum of values per column - Find out stacked Min/Max
    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             // this is always true yMin can be 0 in case all values
    00070             // are the same
    00071             // same for yMax it can be zero if all values are negative
    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     // special cases
    00083     if (  yMax == yMin ) {
    00084         if ( yMin == 0.0 )
    00085             yMax = 0.1; //we need at least a range
    00086         else if( yMax < 0.0 )
    00087             yMax = 0.0; // they are the same and negative
    00088         else if( yMin > 0.0 )
    00089             yMin = 0.0; // they are the same but positive
    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(); // cached
    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         // Pending Michel set a min and max value for the groupWidth
    00122         // related to the area.width
    00123         if ( groupWidth < 0 )
    00124             groupWidth = 0;
    00125
    00126         if ( groupWidth  * rowCount > ctx->rectangle().width() )
    00127             groupWidth = ctx->rectangle().width() / rowCount;
    00128     }
    00129
    00130     // maxLimit: allow the space between bars to be larger until area.width()
    00131     // is covered by the groups.
    00132     double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
    00133
    00134
    00135     //Pending Michel: FixMe
    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 }