diff --git a/src/KChart/Cartesian/DiagramFlavors/KChartPercentBarDiagram_p.cpp b/src/KChart/Cartesian/DiagramFlavors/KChartPercentBarDiagram_p.cpp index c1c6dff..d59da2f 100644 --- a/src/KChart/Cartesian/DiagramFlavors/KChartPercentBarDiagram_p.cpp +++ b/src/KChart/Cartesian/DiagramFlavors/KChartPercentBarDiagram_p.cpp @@ -1,200 +1,205 @@ /* * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. * * This file is part of the KD Chart library. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KChartPercentBarDiagram_p.h" #include #include "KChartBarDiagram.h" #include "KChartTextAttributes.h" #include "KChartAttributesModel.h" #include "KChartAbstractCartesianDiagram.h" using namespace KChart; PercentBarDiagram::PercentBarDiagram( BarDiagram* d ) : BarDiagramType( d ) { } BarDiagram::BarType PercentBarDiagram::type() const { return BarDiagram::Percent; } const QPair PercentBarDiagram::calculateDataBoundaries() const { const int rowCount = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; const int colCount = diagram()->model() ? diagram()->model()->columnCount( diagram()->rootIndex() ) : 0; const qreal xMin = 0.0; const qreal xMax = rowCount; const qreal yMin = 0.0; const qreal yMax = 100.0; qreal usedDepth = 0; for ( int row = 0; row < rowCount ; ++row ) { for ( int col = 0; col < colCount; ++col ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); if ( threeDAttrs.isEnabled() && threeDAttrs.depth() > usedDepth ) { usedDepth = threeDAttrs.depth(); } } } return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax + usedDepth * 0.3 ) ); } void PercentBarDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); const QPair boundaries = diagram()->dataBoundaries(); // cached const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); const int rowCount = compressor().modelDataRows(); const int colCount = compressor().modelDataColumns(); BarAttributes ba = diagram()->barAttributes(); qreal barWidth = 0; qreal maxDepth = 0; qreal width = boundRight.x() - boundLeft.x(); qreal groupWidth = width / rowCount; qreal spaceBetweenBars = 0; qreal spaceBetweenGroups = 0; if ( ba.useFixedBarWidth() ) { barWidth = ba.fixedBarWidth(); groupWidth += barWidth; // Pending Michel set a min and max value for the groupWidth // related to the area.width if ( groupWidth < 0 ) groupWidth = 0; if ( groupWidth * rowCount > width ) groupWidth = width / rowCount; } // maxLimit: allow the space between bars to be larger until area.width() // is covered by the groups. qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); //Pending Michel: FixMe if ( ba.useFixedDataValueGap() ) { if ( width > maxLimit ) spaceBetweenBars += ba.fixedDataValueGap(); else spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); } if ( ba.useFixedValueBlockGap() ) spaceBetweenGroups += ba.fixedValueBlockGap(); calculateValueAndGapWidths( rowCount, colCount,groupWidth, barWidth, spaceBetweenBars, spaceBetweenGroups ); LabelPaintCache lpc; const qreal maxValue = 100; // always 100 % qreal sumValues = 0; QVector sumValuesVector; //calculate sum of values for each column and store for ( int row = 0; row < rowCount; ++row ) { for ( int col = 0; col < colCount; ++col ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); //if ( point.value > 0 ) sumValues += qMax( point.value, -point.value ); if ( col == colCount - 1 ) { sumValuesVector << sumValues ; sumValues = 0; } } } // calculate stacked percent value for ( int col = 0; col < colCount; ++col ) { qreal offset = spaceBetweenGroups; if ( ba.useFixedBarWidth() ) offset -= ba.fixedBarWidth(); - - if ( offset < 0 ) - offset = 0; + CartesianCoordinatePlane *plane = static_cast(ctx->coordinatePlane()); + if (plane->isHorizontalRangeReversed()) { + if (offset > 0) { + offset = 0; + } + } else if ( offset < 0 ) { + offset = 0; + } for ( int row = 0; row < rowCount ; ++row ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); if ( threeDAttrs.isEnabled() ) { if ( barWidth > 0 ) barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; if ( barWidth <= 0 ) { barWidth = 0; maxDepth = offset - ( width/rowCount); } } else { barWidth = (width - (offset*rowCount))/ rowCount; } const qreal value = qMax( p.value, -p.value ); qreal stackedValues = 0.0; qreal key = 0.0; // calculate stacked percent value // we only take in account positives values for now. for ( int k = col; k >= 0 ; --k ) { const CartesianDiagramDataCompressor::CachePosition position( row, k ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); stackedValues += qMax( point.value, -point.value ); key = point.key; } QPointF point, previousPoint; if ( sumValuesVector.at( row ) != 0 && value > 0 ) { point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues / sumValuesVector.at( row ) * maxValue ) ); point.rx() += offset / 2; previousPoint = ctx->coordinatePlane()->translate( QPointF( key, ( stackedValues - value)/sumValuesVector.at(row)* maxValue ) ); } const qreal barHeight = previousPoint.y() - point.y(); const QRectF rect( point, QSizeF( barWidth, barHeight ) ); m_private->addLabel( &lpc, sourceIndex, nullptr, PositionPoints( rect ), Position::North, Position::South, value ); paintBars( ctx, sourceIndex, rect, maxDepth ); } } m_private->paintDataValueTextsAndMarkers( ctx, lpc, false ); } diff --git a/src/KChart/Cartesian/DiagramFlavors/KChartPercentLyingBarDiagram_p.cpp b/src/KChart/Cartesian/DiagramFlavors/KChartPercentLyingBarDiagram_p.cpp index f18eaec..59bb5ca 100644 --- a/src/KChart/Cartesian/DiagramFlavors/KChartPercentLyingBarDiagram_p.cpp +++ b/src/KChart/Cartesian/DiagramFlavors/KChartPercentLyingBarDiagram_p.cpp @@ -1,213 +1,218 @@ /* * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. * * This file is part of the KD Chart library. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KChartPercentLyingBarDiagram_p.h" #include #include "KChartBarDiagram.h" #include "KChartTextAttributes.h" #include "KChartAttributesModel.h" #include "KChartAbstractCartesianDiagram.h" using namespace KChart; PercentLyingBarDiagram::PercentLyingBarDiagram( BarDiagram* d ) : BarDiagramType( d ) { } BarDiagram::BarType PercentLyingBarDiagram::type() const { return BarDiagram::Percent; } const QPair PercentLyingBarDiagram::calculateDataBoundaries() const { //const int rowCount = compressor().modelDataRows(); //const int colCount = compressor().modelDataColumns(); const qreal xMin = 0; const qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; qreal yMin = 0.0, yMax = 100.0; /*for ( int col = 0; col < colCount; ++col ) { for ( int row = 0; row < rowCount; ++row ) { // Ordinate should begin at 0 the max value being the 100% pos const QModelIndex idx = diagram()->model()->index( row, col, diagram()->rootIndex() ); // only positive values are handled qreal value = diagram()->model()->data( idx ).toReal(); if ( value > 0 ) yMax = qMax( yMax, value ); } }*/ // special cases if ( yMax == yMin ) { if ( yMin == 0.0 ) yMax = 0.1; //we need at least a range else yMax = 0.0; // they are the same but negative } const QPointF bottomLeft( QPointF( yMin, xMin ) ); const QPointF topRight( QPointF( yMax, xMax ) ); //qDebug() << "BarDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")"; return QPair< QPointF, QPointF >( bottomLeft, topRight ); } void PercentLyingBarDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); const QPair boundaries = diagram()->dataBoundaries(); // cached const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); const int rowCount = compressor().modelDataRows(); const int colCount = compressor().modelDataColumns(); BarAttributes ba = diagram()->barAttributes(); qreal barWidth = 0; qreal maxDepth = 0; qreal width = boundLeft.y() - boundRight.y(); qreal groupWidth = width / rowCount; qreal spaceBetweenBars = 0; qreal spaceBetweenGroups = 0; if ( ba.useFixedBarWidth() ) { barWidth = ba.fixedBarWidth(); groupWidth += barWidth; // Pending Michel set a min and max value for the groupWidth // related to the area.width if ( groupWidth < 0 ) groupWidth = 0; if ( groupWidth * rowCount > width ) groupWidth = width / rowCount; } // maxLimit: allow the space between bars to be larger until area.width() // is covered by the groups. qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); //Pending Michel: FixMe if ( ba.useFixedDataValueGap() ) { if ( width > maxLimit ) spaceBetweenBars += ba.fixedDataValueGap(); else spaceBetweenBars = ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1); } if ( ba.useFixedValueBlockGap() ) spaceBetweenGroups += ba.fixedValueBlockGap(); calculateValueAndGapWidths( rowCount, colCount,groupWidth, barWidth, spaceBetweenBars, spaceBetweenGroups ); LabelPaintCache lpc; const qreal maxValue = 100.0; // always 100 % qreal sumValues = 0; QVector sumValuesVector; //calculate sum of values for each column and store for ( int row = 0; row < rowCount; ++row ) { for ( int col = 0; col < colCount; ++col ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); //if ( point.value > 0 ) sumValues += qMax( point.value, -point.value ); if ( col == colCount - 1 ) { sumValuesVector << sumValues ; sumValues = 0; } } } // calculate stacked percent value for ( int curRow = rowCount - 1; curRow >= 0; --curRow ) { qreal offset = spaceBetweenGroups; if ( ba.useFixedBarWidth() ) offset -= ba.fixedBarWidth(); - if ( offset < 0 ) + CartesianCoordinatePlane *plane = static_cast(ctx->coordinatePlane()); + if (plane->isVerticalRangeReversed()) { + if (offset > 0) { + offset = 0; + } + } else if ( offset < 0 ) { offset = 0; - + } for ( int col = 0; col < colCount ; ++col ) { qreal threeDOffset = 0.0; const CartesianDiagramDataCompressor::CachePosition position( curRow, col ); const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); QModelIndex sourceIndex = attributesModel()->mapToSource( p.index ); ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex ); if ( threeDAttrs.isEnabled() ) { if ( barWidth > 0 ) { barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; threeDOffset = threeDAttrs.depth(); } if ( barWidth <= 0 ) { barWidth = 0.1; threeDOffset = (width - (offset*rowCount))/ rowCount; } } else { barWidth = (width - (offset*rowCount))/ rowCount; } const qreal value = qMax( p.value, -p.value ); qreal stackedValues = 0.0; qreal key = 0.0; // calculate stacked percent value // we only take in account positives values for now. for ( int k = col; k >= 0 ; --k ) { const CartesianDiagramDataCompressor::CachePosition position( curRow, k ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); stackedValues += qMax( point.value, -point.value ); key = point.key; } QPointF point, previousPoint; if ( sumValuesVector.at( curRow ) != 0 && value > 0 ) { QPointF dataPoint( ( stackedValues / sumValuesVector.at( curRow ) * maxValue ), key + 1 ); point = ctx->coordinatePlane()->translate( dataPoint ); point.ry() += offset / 2 + threeDOffset; previousPoint = ctx->coordinatePlane()->translate( QPointF( ( ( stackedValues - value) / sumValuesVector.at( curRow ) * maxValue ), key + 1 ) ); } const qreal barHeight = point.x() - previousPoint.x(); point.setX( point.x() - barHeight ); const QRectF rect = QRectF( point, QSizeF( barHeight, barWidth ) ).translated( 1, 0 ); m_private->addLabel( &lpc, sourceIndex, nullptr, PositionPoints( rect ), Position::North, Position::South, value ); paintBars( ctx, sourceIndex, rect, maxDepth ); } } m_private->paintDataValueTextsAndMarkers( ctx, lpc, false ); } diff --git a/src/KChart/Cartesian/DiagramFlavors/KChartStackedBarDiagram_p.cpp b/src/KChart/Cartesian/DiagramFlavors/KChartStackedBarDiagram_p.cpp index 292e0cd..6fb1933 100644 --- a/src/KChart/Cartesian/DiagramFlavors/KChartStackedBarDiagram_p.cpp +++ b/src/KChart/Cartesian/DiagramFlavors/KChartStackedBarDiagram_p.cpp @@ -1,211 +1,216 @@ /* * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. * * This file is part of the KD Chart library. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KChartStackedBarDiagram_p.h" #include #include "KChartBarDiagram.h" #include "KChartTextAttributes.h" #include "KChartAttributesModel.h" #include "KChartAbstractCartesianDiagram.h" using namespace KChart; StackedBarDiagram::StackedBarDiagram( BarDiagram* d ) : BarDiagramType( d ) { } BarDiagram::BarType StackedBarDiagram::type() const { return BarDiagram::Stacked; } const QPair StackedBarDiagram::calculateDataBoundaries() const { const int rowCount = compressor().modelDataRows(); const int colCount = compressor().modelDataColumns(); const qreal xMin = 0.0; const qreal xMax = rowCount; qreal yMin = 0.0; qreal yMax = 0.0; bool isFirst = true; for ( int row = 0; row < rowCount; ++row ) { // calculate sum of values per column - Find out stacked Min/Max qreal stackedValues = 0.0; qreal negativeStackedValues = 0.0; for ( int col = 0; col < colCount; ++col ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); const double value = ISNAN( point.value ) ? 0.0 : point.value; if ( value > 0.0 ) { stackedValues += value; } else { negativeStackedValues += value; } // this is always true yMin can be 0 in case all values // are the same // same for yMax it can be zero if all values are negative if ( isFirst ) { yMin = negativeStackedValues < 0.0 ? negativeStackedValues : stackedValues; yMax = stackedValues > 0.0 ? stackedValues : negativeStackedValues; isFirst = false; } else { yMin = qMin( qMin( yMin, stackedValues ), negativeStackedValues ); yMax = qMax( qMax( yMax, stackedValues ), negativeStackedValues ); } } } // special cases if ( yMax == yMin ) { if ( yMin == 0.0 ) { yMax = 0.1; // we need at least a range } else if ( yMax < 0.0 ) { yMax = 0.0; // extend the range to zero } else if ( yMin > 0.0 ) { yMin = 0.0; // dito } } return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax ) ); } void StackedBarDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); const QPair boundaries = diagram()->dataBoundaries(); // cached const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); const int rowCount = compressor().modelDataRows(); const int colCount = compressor().modelDataColumns(); BarAttributes ba = diagram()->barAttributes(); qreal barWidth = 0; qreal maxDepth = 0; qreal width = boundRight.x() - boundLeft.x(); qreal groupWidth = width / rowCount; qreal spaceBetweenBars = 0; qreal spaceBetweenGroups = 0; if ( ba.useFixedBarWidth() ) { barWidth = ba.fixedBarWidth(); groupWidth += barWidth; // Pending Michel set a min and max value for the groupWidth // related to the area.width if ( groupWidth < 0 ) groupWidth = 0; if ( groupWidth * rowCount > width ) groupWidth = width / rowCount; } // maxLimit: allow the space between bars to be larger until area.width() // is covered by the groups. qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); //Pending Michel: FixMe if ( ba.useFixedDataValueGap() ) { if ( width > maxLimit ) spaceBetweenBars += ba.fixedDataValueGap(); else spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); } if ( ba.useFixedValueBlockGap() ) spaceBetweenGroups += ba.fixedValueBlockGap(); calculateValueAndGapWidths( rowCount, colCount,groupWidth, barWidth, spaceBetweenBars, spaceBetweenGroups ); LabelPaintCache lpc; for ( int col = 0; col < colCount; ++col ) { qreal offset = spaceBetweenGroups; if ( ba.useFixedBarWidth() ) offset -= ba.fixedBarWidth(); - - if ( offset < 0 ) - offset = 0; + CartesianCoordinatePlane *plane = static_cast(ctx->coordinatePlane()); + if (plane->isHorizontalRangeReversed()) { + if (offset > 0) { + offset = 0; + } + } else if ( offset < 0 ) { + offset = 0; + } for ( int row = 0; row < rowCount; ++row ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); const QModelIndex index = attributesModel()->mapToSource( p.index ); ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index ); const qreal value = p.value; qreal stackedValues = 0.0; qreal key = 0.0; if ( threeDAttrs.isEnabled() ) { if ( barWidth > 0 ) barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; if ( barWidth <= 0 ) { barWidth = 0; maxDepth = offset - (width/rowCount); } } else { barWidth = (width - (offset*rowCount))/ rowCount ; } for ( int k = col; k >= 0; --k ) { const CartesianDiagramDataCompressor::CachePosition position( row, k ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); if ( !ISNAN( point.value ) && (( p.value >= 0.0 && point.value >= 0.0 ) || ( p.value < 0.0 && point.value < 0.0 )) ) stackedValues += point.value; key = point.key; } if (!ISNAN( value )) { const qreal usedDepth = threeDAttrs.depth(); QPointF point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues ) ); const qreal dy = point.y() - usedDepth; if ( dy < 0 ) { threeDAttrs.setDepth( point.y() - 1 ); diagram()->setThreeDBarAttributes( threeDAttrs ); } point.rx() += offset / 2; const QPointF previousPoint = ctx->coordinatePlane()->translate( QPointF( key, stackedValues - value ) ); const qreal barHeight = previousPoint.y() - point.y(); const QRectF rect( point, QSizeF( barWidth , barHeight ) ); m_private->addLabel( &lpc, index, nullptr, PositionPoints( rect ), Position::North, Position::South, value ); paintBars( ctx, index, rect, maxDepth ); } } } m_private->paintDataValueTextsAndMarkers( ctx, lpc, false ); } diff --git a/src/KChart/Cartesian/DiagramFlavors/KChartStackedLyingBarDiagram_p.cpp b/src/KChart/Cartesian/DiagramFlavors/KChartStackedLyingBarDiagram_p.cpp index 5612d48..6b95030 100644 --- a/src/KChart/Cartesian/DiagramFlavors/KChartStackedLyingBarDiagram_p.cpp +++ b/src/KChart/Cartesian/DiagramFlavors/KChartStackedLyingBarDiagram_p.cpp @@ -1,200 +1,205 @@ /* * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. * * This file is part of the KD Chart library. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KChartStackedLyingBarDiagram_p.h" #include #include "KChartBarDiagram.h" #include "KChartTextAttributes.h" #include "KChartAttributesModel.h" #include "KChartAbstractCartesianDiagram.h" using namespace KChart; StackedLyingBarDiagram::StackedLyingBarDiagram( BarDiagram* d ) : BarDiagramType( d ) { } BarDiagram::BarType StackedLyingBarDiagram::type() const { return BarDiagram::Stacked; } const QPair StackedLyingBarDiagram::calculateDataBoundaries() const { const int rowCount = compressor().modelDataRows(); const int colCount = compressor().modelDataColumns(); const qreal xMin = 0; const qreal xMax = rowCount; qreal yMin = 0; qreal yMax = 0; bool isFirst = true; for ( int row = 0; row < rowCount; ++row ) { // calculate sum of values per column - Find out stacked Min/Max qreal stackedValues = 0.0; qreal negativeStackedValues = 0.0; for ( int col = 0; col < colCount; ++col ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); if ( point.value > 0.0 ) stackedValues += point.value; else negativeStackedValues += point.value; // this is always true yMin can be 0 in case all values // are the same // same for yMax it can be zero if all values are negative if ( isFirst ) { yMin = negativeStackedValues < 0.0 ? negativeStackedValues : stackedValues; yMax = stackedValues > 0.0 ? stackedValues : negativeStackedValues; isFirst = false; } else { yMin = qMin( qMin( yMin, stackedValues ), negativeStackedValues ); yMax = qMax( qMax( yMax, stackedValues ), negativeStackedValues ); } } } // special cases if ( yMax == yMin ) { if ( yMin == 0.0 ) { yMax = 0.1; // we need at least a range } else if ( yMax < 0.0 ) { yMax = 0.0; // extend the range to zero } else if ( yMin > 0.0 ) { yMin = 0.0; // dito } } return QPair< QPointF, QPointF >( QPointF( yMin, xMin ), QPointF( yMax, xMax ) ); } void StackedLyingBarDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); const QPair boundaries = diagram()->dataBoundaries(); // cached const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ; const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second ); const int rowCount = compressor().modelDataRows(); const int colCount = compressor().modelDataColumns(); BarAttributes ba = diagram()->barAttributes(); qreal barWidth = 0; qreal maxDepth = 0; qreal width = boundLeft.y() - boundRight.y(); qreal groupWidth = width / rowCount; qreal spaceBetweenBars = 0; qreal spaceBetweenGroups = 0; if ( ba.useFixedBarWidth() ) { barWidth = ba.fixedBarWidth(); groupWidth += barWidth; // Pending Michel set a min and max value for the groupWidth // related to the area.width if ( groupWidth < 0 ) groupWidth = 0; if ( groupWidth * rowCount > width ) groupWidth = width / rowCount; } // maxLimit: allow the space between bars to be larger until area.width() // is covered by the groups. qreal maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) ); //Pending Michel: FixMe if ( ba.useFixedDataValueGap() ) { if ( ctx->rectangle().width() > maxLimit ) spaceBetweenBars += ba.fixedDataValueGap(); else spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1); } if ( ba.useFixedValueBlockGap() ) spaceBetweenGroups += ba.fixedValueBlockGap(); calculateValueAndGapWidths( rowCount, colCount,groupWidth, barWidth, spaceBetweenBars, spaceBetweenGroups ); LabelPaintCache lpc; for ( int row = rowCount - 1; row >= 0; --row ) { qreal offset = spaceBetweenGroups; if ( ba.useFixedBarWidth() ) offset -= ba.fixedBarWidth(); - - if ( offset < 0 ) - offset = 0; + CartesianCoordinatePlane *plane = static_cast(ctx->coordinatePlane()); + if (plane->isVerticalRangeReversed()) { + if (offset > 0) { + offset = 0; + } + } else if ( offset < 0 ) { + offset = 0; + } for ( int col = 0; col < colCount; ++col ) { qreal threeDOffset = 0.0; const CartesianDiagramDataCompressor::CachePosition position( row, col ); const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position ); const QModelIndex index = attributesModel()->mapToSource( p.index ); ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index ); const qreal value = p.value; qreal stackedValues = 0.0; qreal key = 0.0; if ( threeDAttrs.isEnabled() ) { if ( barWidth > 0 ) { barWidth = (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount; threeDOffset = threeDAttrs.depth(); } if ( barWidth <= 0 ) { barWidth = 0.1; threeDOffset = (width - (offset*rowCount))/ rowCount; } } else { barWidth = (width - (offset*rowCount))/ rowCount; } for ( int k = col; k >= 0; --k ) { const CartesianDiagramDataCompressor::CachePosition position( row, k ); const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); if ( ( p.value >= 0.0 && point.value >= 0.0 ) || ( p.value < 0.0 && point.value < 0.0 ) ) stackedValues += point.value; key = point.key; } QPointF point = ctx->coordinatePlane()->translate( QPointF( stackedValues, key + 1 ) ); point.ry() += offset / 2 + threeDOffset; const QPointF previousPoint = ctx->coordinatePlane()->translate( QPointF( stackedValues - value, key + 1 ) ); const qreal barHeight = point.x() - previousPoint.x(); point.rx() -= barHeight; const QRectF rect = QRectF( point, QSizeF( barHeight , barWidth ) ).translated( 1, 0 ); m_private->addLabel( &lpc, index, nullptr, PositionPoints( rect ), Position::North, Position::South, value ); paintBars( ctx, index, rect, maxDepth ); } } m_private->paintDataValueTextsAndMarkers( ctx, lpc, false ); }