KD Chart 2
[rev.2.5]
|
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 "KDChartNormalLyingBarDiagram_p.h" 00024 00025 #include <QModelIndex> 00026 00027 #include "KDChartBarDiagram.h" 00028 #include "KDChartTextAttributes.h" 00029 #include "KDChartAttributesModel.h" 00030 #include "KDChartAbstractCartesianDiagram.h" 00031 00032 using namespace KDChart; 00033 using namespace std; 00034 00035 NormalLyingBarDiagram::NormalLyingBarDiagram( BarDiagram* d ) 00036 : BarDiagramType( d ) 00037 { 00038 } 00039 00040 BarDiagram::BarType NormalLyingBarDiagram::type() const 00041 { 00042 return BarDiagram::Normal; 00043 } 00044 00045 const QPair<QPointF, QPointF> NormalLyingBarDiagram::calculateDataBoundaries() const 00046 { 00047 const int rowCount = compressor().modelDataRows(); 00048 const int colCount = compressor().modelDataColumns(); 00049 00050 qreal xMin = 0.0; 00051 qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00052 qreal yMin = 0.0, yMax = 0.0; 00053 00054 bool bStarting = true; 00055 for ( int column = 0; column < colCount; ++column ) 00056 { 00057 for ( int row = 0; row < rowCount; ++row ) 00058 { 00059 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 00060 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00061 const qreal value = ISNAN( point.value ) ? 0.0 : point.value; 00062 // this is always true yMin can be 0 in case all values 00063 // are the same 00064 // same for yMax it can be zero if all values are negative 00065 if( bStarting ){ 00066 yMin = value; 00067 yMax = value; 00068 bStarting = false; 00069 }else{ 00070 yMin = qMin( yMin, value ); 00071 yMax = qMax( yMax, value ); 00072 } 00073 } 00074 } 00075 00076 // special cases 00077 if ( yMax == yMin ) { 00078 if ( yMin == 0.0 ) 00079 yMax = 0.1; //we need at least a range 00080 else if( yMax < 0.0 ) 00081 yMax = 0.0; // they are the same and negative 00082 else if( yMin > 0.0 ) 00083 yMin = 0.0; // they are the same but positive 00084 } 00085 const QPointF bottomLeft ( QPointF( yMin, xMin ) ); 00086 const QPointF topRight ( QPointF( yMax, xMax ) ); 00087 00088 return QPair< QPointF, QPointF >( bottomLeft, topRight ); 00089 } 00090 00091 void NormalLyingBarDiagram::paint( PaintContext* ctx ) 00092 { 00093 reverseMapper().clear(); 00094 00095 const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached 00096 00097 const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; 00098 const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); 00099 00100 const int rowCount = attributesModel()->rowCount(attributesModelRootIndex()); 00101 const int colCount = attributesModel()->columnCount(attributesModelRootIndex()); 00102 00103 BarAttributes ba = diagram()->barAttributes(); 00104 qreal barWidth = 0; 00105 qreal maxDepth = 0; 00106 qreal width = boundLeft.y() - boundRight.y(); 00107 qreal groupWidth = width / (rowCount + 2); 00108 qreal spaceBetweenBars = 0; 00109 qreal spaceBetweenGroups = 0; 00110 00111 if ( ba.useFixedBarWidth() ) { 00112 00113 barWidth = ba.fixedBarWidth(); 00114 groupWidth += barWidth; 00115 00116 // Pending Michel set a min and max value for the groupWidth 00117 // related to the area.width 00118 if ( groupWidth < 0 ) 00119 groupWidth = 0; 00120 00121 if ( groupWidth * rowCount > width ) 00122 groupWidth = width / rowCount; 00123 } 00124 00125 // maxLimit: allow the space between bars to be larger until area.width() 00126 // is covered by the groups. 00127 qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); 00128 00129 //Pending Michel: FixMe 00130 if ( ba.useFixedDataValueGap() ) { 00131 if ( width > maxLimit ) 00132 spaceBetweenBars += ba.fixedDataValueGap(); 00133 else 00134 spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); 00135 } 00136 00137 if ( ba.useFixedValueBlockGap() ) { 00138 spaceBetweenGroups += ba.fixedValueBlockGap(); 00139 } 00140 00141 calculateValueAndGapWidths( rowCount, colCount,groupWidth, 00142 barWidth, spaceBetweenBars, spaceBetweenGroups ); 00143 00144 LabelPaintCache lpc; 00145 00146 for( int row = rowCount - 1; row >= 0; --row ) 00147 { 00148 qreal offset = (groupWidth + spaceBetweenGroups) / 2.0 - spaceBetweenBars; 00149 00150 if ( ba.useFixedDataValueGap() ) 00151 { 00152 if ( spaceBetweenBars > 0 ) 00153 { 00154 if ( width > maxLimit ) 00155 offset -= ba.fixedDataValueGap(); 00156 else 00157 offset -= ((width/rowCount) - groupWidth)/(colCount-1); 00158 00159 } 00160 else 00161 { 00162 offset += barWidth/2; 00163 } 00164 } 00165 00166 for( int column = colCount - 1; column >= 0; --column ) 00167 { 00168 offset -= barWidth + spaceBetweenBars; 00169 00170 // paint one group 00171 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 00172 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00173 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00174 const qreal value = point.value;//attributesModel()->data( sourceIndex ).toReal(); 00175 QPointF topPoint = ctx->coordinatePlane()->translate( QPointF( value, rowCount - (point.key + 0.5) ) ); 00176 QPointF bottomPoint = ctx->coordinatePlane()->translate( QPointF( 0, rowCount - point.key ) ); 00177 const qreal barHeight = topPoint.x() - bottomPoint.x(); 00178 topPoint.ry() += offset; 00179 topPoint.rx() -= barHeight; 00180 const QRectF rect( topPoint, QSizeF( barHeight, barWidth ) ); 00181 addLabel( &lpc, sourceIndex, PositionPoints( rect ), Position::North, 00182 Position::South, point.value ); 00183 paintBars( ctx, sourceIndex, rect, maxDepth ); 00184 } 00185 } 00186 paintDataValueTextsAndMarkers( ctx, lpc, false ); 00187 }