KD Chart 2  [rev.2.5]
KDChartStackedBarDiagram_p.cpp
Go to the documentation of this file.
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 <QModelIndex>
00024 
00025 #include "KDChartBarDiagram.h"
00026 #include "KDChartTextAttributes.h"
00027 #include "KDChartAttributesModel.h"
00028 #include "KDChartAbstractCartesianDiagram.h"
00029 #include "KDChartStackedBarDiagram_p.h"
00030 
00031 using namespace KDChart;
00032 
00033 StackedBarDiagram::StackedBarDiagram( BarDiagram* d )
00034     : BarDiagramType( d )
00035 {
00036 }
00037 
00038 BarDiagram::BarType StackedBarDiagram::type() const
00039 {
00040     return BarDiagram::Stacked;
00041 }
00042 
00043 const QPair<QPointF, QPointF> StackedBarDiagram::calculateDataBoundaries() const
00044 {
00045     const int rowCount = compressor().modelDataRows();
00046     const int colCount = compressor().modelDataColumns();
00047 
00048     const qreal xMin = 0.0;
00049     const qreal xMax = rowCount;
00050     qreal yMin = 0.0;
00051     qreal yMax = 0.0;
00052 
00053     bool isFirst = true;
00054     for( int row = 0; row < rowCount; ++row ) {
00055         // calculate sum of values per column - Find out stacked Min/Max
00056         qreal stackedValues = 0.0;
00057         qreal negativeStackedValues = 0.0;
00058         for ( int col = 0; col < colCount; ++col ) {
00059             const CartesianDiagramDataCompressor::CachePosition position( row, col );
00060             const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00061             const double value = ISNAN( point.value ) ? 0.0 : point.value;
00062 
00063             if ( value > 0.0 ) {
00064                 stackedValues += value;
00065             } else {
00066                 negativeStackedValues += value;
00067             }
00068 
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 ( isFirst ) {
00073                 yMin = negativeStackedValues < 0.0 ? negativeStackedValues : stackedValues;
00074                 yMax = stackedValues > 0.0 ? stackedValues : negativeStackedValues;
00075                 isFirst = false;
00076             } else {
00077                 yMin = qMin( qMin( yMin, stackedValues ), negativeStackedValues );
00078                 yMax = qMax( qMax( yMax, stackedValues ), negativeStackedValues );
00079             }
00080         }
00081     }
00082 
00083     // special cases
00084     if ( yMax == yMin ) {
00085         if ( yMin == 0.0 ) {
00086             yMax = 0.1; // we need at least a range
00087         } else if ( yMax < 0.0 ) {
00088             yMax = 0.0; // extend the range to zero
00089         } else if ( yMin > 0.0 ) {
00090             yMin = 0.0; // dito
00091         }
00092     }
00093 
00094     return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax ) );
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();
00110     qreal barWidth = 0;
00111     qreal maxDepth = 0;
00112     qreal width = boundRight.x() - boundLeft.x();
00113     qreal groupWidth = width/ (rowCount + 2);
00114     qreal spaceBetweenBars = 0;
00115     qreal 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 > width )
00127             groupWidth = width / rowCount;
00128     }
00129 
00130     // maxLimit: allow the space between bars to be larger until area.width()
00131     // is covered by the groups.
00132     qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
00133 
00134 
00135     //Pending Michel: FixMe
00136     if ( ba.useFixedDataValueGap() ) {
00137         if ( width > maxLimit )
00138             spaceBetweenBars += ba.fixedDataValueGap();
00139         else
00140             spaceBetweenBars = ((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     LabelPaintCache lpc;
00150     for( int col = 0; col < colCount; ++col )
00151     {
00152         qreal 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 qreal value = p.value;
00167             qreal stackedValues = 0.0;
00168             qreal 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 =  (width - (offset*rowCount))/ rowCount ;
00179             }
00180 
00181             for ( int k = col; k >= 0; --k )
00182             {
00183                 const CartesianDiagramDataCompressor::CachePosition position( row, k );
00184                 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00185                 if( !ISNAN( point.value ) && (( p.value >= 0.0 && point.value >= 0.0 ) || ( p.value < 0.0 && point.value < 0.0 )) )
00186                     stackedValues += point.value;
00187                 key = point.key;
00188             }
00189 
00190             if (!ISNAN( value ))
00191             {
00192                 const qreal usedDepth = threeDAttrs.depth();
00193 
00194                 QPointF point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues ) );
00195 
00196                 const qreal dy = point.y() - usedDepth;
00197                 if ( dy < 0 ) {
00198                     threeDAttrs.setDepth( point.y() - 1 );
00199                     diagram()->setThreeDBarAttributes( threeDAttrs );
00200                 }
00201 
00202                 point.rx() += offset / 2;
00203                 const QPointF previousPoint = ctx->coordinatePlane()->translate( QPointF( key, stackedValues - value ) );
00204                 const qreal barHeight = previousPoint.y() - point.y();
00205 
00206                 const QRectF rect( point, QSizeF( barWidth , barHeight ) );
00207                 addLabel( &lpc, index, PositionPoints( rect ), Position::North,
00208                           Position::South, value );
00209                 paintBars( ctx, index, rect, maxDepth );
00210             }
00211         }
00212     }
00213     paintDataValueTextsAndMarkers( ctx, lpc, false );
00214 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/