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