tdf#50934: Implementation of bar-of-pie, plus minor of-pie fixes
Change-Id: Ib343953ee30124524884859c8fe9e88d2dc7d822
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160726
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index 0424130..aee48da 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -227,6 +227,7 @@ PieChart::~PieChart()
void PieChart::setScales( std::vector< ExplicitScaleData >&& rScales, bool /* bSwapXAndYAxis */ )
{
OSL_ENSURE(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence");
m_aCartesianScales = m_pPosHelper->getScales();
m_aPosHelper.setScales( std::move(rScales), true );
}
@@ -333,6 +334,50 @@ rtl::Reference<SvxShape> PieChart::createDataPoint(
return xShape;
}
rtl::Reference<SvxShape> PieChart::createBarDataPoint(
const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
const uno::Reference<beans::XPropertySet>& xObjectProperties,
const ShapeParam& rParam,
double fBarSegBottom, double fBarSegTop)
{
drawing::Position3D aP0, aP1;
// Draw the bar for bar-of-pie small and to the right. Width and
// position are hard-coded for now.
#if 0
aP0 = cartesianPosHelper.transformLogicToScene(0.75, fBarSegBottom,
rParam.mfLogicZ, false);
aP1 = cartesianPosHelper.transformLogicToScene(1.25, fBarSegTop,
rParam.mfLogicZ, false);
#else
double x0 = m_aPosHelper.transformUnitCircleToScene(0, 0.75, 0).PositionX;
double x1 = m_aPosHelper.transformUnitCircleToScene(0, 1.25, 0).PositionX;
double y0 = m_aPosHelper.transformUnitCircleToScene(
90, fBarSegBottom, 0).PositionY;
double y1 = m_aPosHelper.transformUnitCircleToScene(
90, fBarSegTop, 0).PositionY;
aP0 = drawing::Position3D(x0, y0, rParam.mfLogicZ);
aP1 = drawing::Position3D(x1, y1, rParam.mfLogicZ);
#endif
const css::awt::Point aPos(aP0.PositionX, aP1.PositionY);
const css::awt::Size aSz(fabs(aP0.PositionX - aP1.PositionX),
fabs(aP0.PositionY - aP1.PositionY));
const tNameSequence emptyNameSeq;
const tAnySequence emptyValSeq;
//create point
rtl::Reference<SvxShape> xShape = ShapeFactory::createRectangle(
xTarget,
aSz, aPos,
emptyNameSeq, emptyValSeq);
PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
return xShape;
}
void PieChart::createTextLabelShape(
const rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
VDataSeries& rSeries, sal_Int32 nPointIndex, ShapeParam& rParam )
@@ -880,6 +925,8 @@ void PieChart::createShapes()
pDataSrc = &ofPieSrc;
createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
createOneBar(SubPieType::RIGHT, aParam, xSeriesTarget,
xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
break;
case PieChartSubType_PIE:
pDataSrc = &ofPieSrc;
@@ -926,6 +973,25 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
if (!std::isnan(fY) ) ringSum += fY;
}
// determine the starting angle around the ring
auto sAngle = [&]()
{
if (eType == SubPieType::LEFT) {
// Left of-pie has the "composite" wedge (the one expanded in the right
// subgraph) facing to the right in the chart, to allow the expansion
// lines to meet it
double compositeVal = pDataSrc->getData(pSeries, nRingPtCnt - 1, eType);
return compositeVal * 360 / (ringSum * 2);
} else {
/// The angle degree offset is set by the same property of the
/// data series.
/// Counter-clockwise offset from the 3 o'clock position.
return static_cast<double>(pSeries->getStartingAngle());
}
};
m_aPosHelper.m_fAngleDegreeOffset = sAngle();
double fLogicYForNextPoint = 0.0;
///iterate through all points to create shapes
for(sal_Int32 nPointIndex = 0; nPointIndex < nRingPtCnt; nPointIndex++ )
@@ -1057,6 +1123,81 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
}//next category
}
void PieChart::createOneBar(
enum SubPieType eType,
ShapeParam& aParam,
const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
const rtl::Reference<SvxShapeGroup>& xTextTarget,
VDataSeries* pSeries,
const PieDataSrcBase *pDataSrc,
sal_Int32 n3DRelativeHeight)
{
bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
sal_Int32 nBarPtCnt = pDataSrc->getNPoints(pSeries, eType);
// Find sum of entries for this bar chart
double barSum = 0;
for (sal_Int32 nPointIndex = 0; nPointIndex < nBarPtCnt; nPointIndex++ ) {
double fY = pDataSrc->getData(pSeries, nPointIndex, eType);
if (!std::isnan(fY) ) barSum += fY;
}
double fBarBottom = 0.0;
double fBarTop = -0.5; // make the bar go from -0.5 to 0.5
///iterate through all points to create shapes
for(sal_Int32 nPointIndex = 0; nPointIndex < nBarPtCnt; nPointIndex++ )
{
aParam.mfDepth = getTransformedDepth() * (n3DRelativeHeight / 100.0);
rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
///collect data point information (logic coordinates, style ):
double fY = pDataSrc->getData(pSeries, nPointIndex, eType) / barSum;
if( std::isnan(fY) )
continue;
if(fY==0.0)//@todo: continue also if the resolution is too small
continue;
fBarBottom = fBarTop;
fBarTop += fY;
uno::Reference< beans::XPropertySet > xPointProperties =
pDataSrc->getProps(pSeries, nPointIndex, eType);
///create data point
aParam.mfLogicZ = -1.0; // For 3D pie chart label position
rtl::Reference<SvxShape> xPointShape =
createBarDataPoint(xSeriesGroupShape_Shapes,
xPointProperties, aParam,
fBarBottom, fBarTop);
///point color:
if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
{
xPointShape->setPropertyValue("FillColor",
uno::Any(m_xColorScheme->getColorByIndex( nPointIndex )));
}
if(bHasFillColorMapping)
{
double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
if(!std::isnan(nPropVal))
{
xPointShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>( nPropVal)));
}
}
///create label
createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam);
ShapeFactory::setShapeName( xPointShape,
ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(),
nPointIndex ) );
}//next category
}
PieChart::PieLabelInfo::PieLabelInfo()
: fValue(0.0)
, bMovementAllowed(false), bMoved(false)
@@ -1859,7 +2000,7 @@ bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLab
// class PieDataSrc
//=======================
double PieDataSrc::getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
enum SubPieType /*eType*/) const
[[maybe_unused]] enum SubPieType eType) const
{
return fabs(pSeries->getYValue( nPtIdx ));
}
@@ -1941,7 +2082,6 @@ uno::Reference< beans::XPropertySet > OfPieDataSrc::getProps(
}
}
} //namespace chart
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx
index 8abd997..731c4e6 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -45,9 +45,9 @@ public:
};
enum class SubPieType {
NONE,
LEFT,
RIGHT
NONE, // solo pie or donut
LEFT, // left pie in pie-of-pie
RIGHT // right pie in pie-of-pie
};
@@ -79,11 +79,12 @@ public:
//=======================
class PieDataSrc : public PieDataSrcBase
{
public:
sal_Int32 getNPoints(const VDataSeries* pSeries,
enum SubPieType eType) const;
double getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
enum SubPieType eType) const;
[[maybe_unused]]enum SubPieType eType) const;
virtual uno::Reference< beans::XPropertySet > getProps(
const VDataSeries* pSeries, sal_Int32 nPtIdx,
@@ -157,6 +158,11 @@ private: //methods
const sal_Int32 nPointCount,
const bool bConcentricExplosion);
rtl::Reference<SvxShape> createBarDataPoint(
const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
const uno::Reference<beans::XPropertySet>& xObjectProperties,
const ShapeParam& rParam,
double fBarSegBottom, double fBarSegTop);
/** This method creates a text shape for a label of a data point.
*
* @param xTextTarget
@@ -195,6 +201,7 @@ struct PieLabelInfo;
bool performLabelBestFitInnerPlacement( ShapeParam& rShapeParam
, PieLabelInfo const & rPieLabelInfo );
// A standalone pie, one pie in a pie-of-pie, or one ring of a donut
void createOneRing([[maybe_unused]]enum SubPieType eType
, double fSlotX
, ShapeParam& aParam
@@ -204,10 +211,21 @@ struct PieLabelInfo;
, const PieDataSrcBase *pDataSrc
, sal_Int32 n3DRelativeHeight);
// A bar chart in a bar-of-pie
void createOneBar(
enum SubPieType eType,
ShapeParam& aParam,
const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
const rtl::Reference<SvxShapeGroup>& xTextTarget,
VDataSeries* pSeries,
const PieDataSrcBase *pDataSrc,
sal_Int32 n3DRelativeHeight);
private: //member
PiePositionHelper m_aPosHelper;
bool m_bUseRings;
bool m_bSizeExcludesLabelsAndExplodedSegments;
std::vector< ExplicitScaleData > m_aCartesianScales; // for bar-of-pie
::css::chart2::PieChartSubType m_eSubType;
struct PieLabelInfo