File indexing completed on 2024-12-15 04:02:26
0001 /* 0002 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "KChartPercentBarDiagram_p.h" 0010 0011 #include <QModelIndex> 0012 0013 #include "KChartBarDiagram.h" 0014 #include "KChartTextAttributes.h" 0015 #include "KChartAttributesModel.h" 0016 #include "KChartAbstractCartesianDiagram.h" 0017 0018 using namespace KChart; 0019 0020 PercentBarDiagram::PercentBarDiagram( BarDiagram* d ) 0021 : BarDiagramType( d ) 0022 { 0023 } 0024 0025 BarDiagram::BarType PercentBarDiagram::type() const 0026 { 0027 return BarDiagram::Percent; 0028 } 0029 0030 const QPair<QPointF, QPointF> PercentBarDiagram::calculateDataBoundaries() const 0031 { 0032 const int rowCount = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 0033 const int colCount = diagram()->model() ? diagram()->model()->columnCount( diagram()->rootIndex() ) : 0; 0034 0035 const qreal xMin = 0.0; 0036 const qreal xMax = rowCount; 0037 const qreal yMin = 0.0; 0038 const qreal yMax = 100.0; 0039 0040 qreal usedDepth = 0; 0041 0042 for ( int row = 0; row < rowCount ; ++row ) { 0043 for ( int col = 0; col < colCount; ++col ) { 0044 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 0045 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 0046 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 0047 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 0048 0049 if ( threeDAttrs.isEnabled() && threeDAttrs.depth() > usedDepth ) { 0050 usedDepth = threeDAttrs.depth(); 0051 } 0052 } 0053 } 0054 0055 return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax + usedDepth * 0.3 ) ); 0056 } 0057 0058 void PercentBarDiagram::paint( PaintContext* ctx ) 0059 { 0060 reverseMapper().clear(); 0061 0062 const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached 0063 0064 const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; 0065 const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); 0066 0067 const int rowCount = compressor().modelDataRows(); 0068 const int colCount = compressor().modelDataColumns(); 0069 0070 BarAttributes ba = diagram()->barAttributes(); 0071 qreal barWidth = 0; 0072 qreal maxDepth = 0; 0073 qreal width = boundRight.x() - boundLeft.x(); 0074 qreal groupWidth = width / rowCount; 0075 qreal spaceBetweenBars = 0; 0076 qreal spaceBetweenGroups = 0; 0077 0078 if ( ba.useFixedBarWidth() ) { 0079 barWidth = ba.fixedBarWidth(); 0080 groupWidth += barWidth; 0081 0082 // Pending Michel set a min and max value for the groupWidth 0083 // related to the area.width 0084 if ( groupWidth < 0 ) 0085 groupWidth = 0; 0086 0087 if ( groupWidth * rowCount > width ) 0088 groupWidth = width / rowCount; 0089 } 0090 0091 // maxLimit: allow the space between bars to be larger until area.width() 0092 // is covered by the groups. 0093 qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); 0094 0095 0096 //Pending Michel: FixMe 0097 if ( ba.useFixedDataValueGap() ) { 0098 if ( width > maxLimit ) 0099 spaceBetweenBars += ba.fixedDataValueGap(); 0100 else 0101 spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); 0102 } 0103 0104 if ( ba.useFixedValueBlockGap() ) 0105 spaceBetweenGroups += ba.fixedValueBlockGap(); 0106 0107 calculateValueAndGapWidths( rowCount, colCount,groupWidth, 0108 barWidth, spaceBetweenBars, spaceBetweenGroups ); 0109 0110 LabelPaintCache lpc; 0111 const qreal maxValue = 100; // always 100 % 0112 qreal sumValues = 0; 0113 QVector <qreal > sumValuesVector; 0114 0115 //calculate sum of values for each column and store 0116 for ( int row = 0; row < rowCount; ++row ) 0117 { 0118 for ( int col = 0; col < colCount; ++col ) 0119 { 0120 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 0121 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 0122 //if ( point.value > 0 ) 0123 sumValues += qMax( point.value, -point.value ); 0124 if ( col == colCount - 1 ) { 0125 sumValuesVector << sumValues ; 0126 sumValues = 0; 0127 } 0128 } 0129 } 0130 0131 // calculate stacked percent value 0132 for ( int col = 0; col < colCount; ++col ) 0133 { 0134 qreal offset = spaceBetweenGroups; 0135 if ( ba.useFixedBarWidth() ) 0136 offset -= ba.fixedBarWidth(); 0137 0138 CartesianCoordinatePlane *plane = static_cast<CartesianCoordinatePlane*>(ctx->coordinatePlane()); 0139 if (plane->isHorizontalRangeReversed()) { 0140 if (offset > 0) { 0141 offset = 0; 0142 } 0143 } else if ( offset < 0 ) { 0144 offset = 0; 0145 } 0146 for ( int row = 0; row < rowCount ; ++row ) 0147 { 0148 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 0149 const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); 0150 QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); 0151 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); 0152 0153 if ( threeDAttrs.isEnabled() ) { 0154 if ( barWidth > 0 ) 0155 barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; 0156 if ( barWidth <= 0 ) { 0157 barWidth = 0; 0158 maxDepth = offset - ( width/rowCount); 0159 } 0160 } else { 0161 barWidth = (width - (offset*rowCount))/ rowCount; 0162 } 0163 0164 const qreal value = qMax( p.value, -p.value ); 0165 qreal stackedValues = 0.0; 0166 qreal key = 0.0; 0167 0168 // calculate stacked percent value 0169 // we only take in account positives values for now. 0170 for ( int k = col; k >= 0 ; --k ) 0171 { 0172 const CartesianDiagramDataCompressor::CachePosition position( row, k ); 0173 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 0174 stackedValues += qMax( point.value, -point.value ); 0175 key = point.key; 0176 } 0177 0178 QPointF point, previousPoint; 0179 if ( sumValuesVector.at( row ) != 0 && value > 0 ) { 0180 point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues / sumValuesVector.at( row ) * maxValue ) ); 0181 point.rx() += offset / 2; 0182 0183 previousPoint = ctx->coordinatePlane()->translate( QPointF( key, ( stackedValues - value)/sumValuesVector.at(row)* maxValue ) ); 0184 } 0185 const qreal barHeight = previousPoint.y() - point.y(); 0186 0187 const QRectF rect( point, QSizeF( barWidth, barHeight ) ); 0188 m_private->addLabel( &lpc, sourceIndex, nullptr, PositionPoints( rect ), Position::North, 0189 Position::South, value ); 0190 paintBars( ctx, sourceIndex, rect, maxDepth ); 0191 } 0192 } 0193 m_private->paintDataValueTextsAndMarkers( ctx, lpc, false ); 0194 }