summaryrefslogtreecommitdiff
path: root/chart2/source/view
diff options
context:
space:
mode:
authorKurt Nordback <kurt.nordback@protonmail.com>2023-09-01 16:13:15 -0600
committerNoel Grandin <noel.grandin@collabora.co.uk>2024-02-14 07:58:41 +0100
commitd81c98623b2abb991ca696b3b09011f6bb3de673 (patch)
tree8fcbacecee5d42d7397fffe61791bdce9ef1dcb0 /chart2/source/view
parent0f4002378d7cbf20ed5f33cbdc4e3c8e01e0338d (diff)
tdf#50934: Restructuring for of-pie charts
Change-Id: I9682c314efb888d57e94f82f084cc6d0825a4408 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160723 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'chart2/source/view')
-rw-r--r--chart2/source/view/charttypes/PieChart.cxx286
-rw-r--r--chart2/source/view/charttypes/PieChart.hxx14
2 files changed, 173 insertions, 127 deletions
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index 0f924de7c5ab..49cf48de3f05 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -790,13 +790,6 @@ void PieChart::createShapes()
///the angle axis scale range is [0, 1]. The max_offset parameter is used
///for exploded pie chart and its value is 0.5.
- ///the `explodeable` ring is the first one except when the radius axis
- ///orientation is reversed (always!?) and we are dealing with a donut: in
- ///such a case the `explodeable` ring is the last one.
- std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
- if( m_aPosHelper.isMathematicalOrientationRadius() && m_bUseRings )
- nExplodeableSlot = m_aZSlots.front().size()-1;
-
m_aLabelInfoList.clear();
m_fMaxOffset = std::numeric_limits<double>::quiet_NaN();
sal_Int32 n3DRelativeHeight = 100;
@@ -815,8 +808,6 @@ void PieChart::createShapes()
///(m_bUseRings||fSlotX<0.5)
for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); ++aXSlotIter, fSlotX+=1.0 )
{
- ShapeParam aParam;
-
std::vector< std::unique_ptr<VDataSeries> >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
if(pSeriesList->empty())//there should be only one series in each x slot
continue;
@@ -824,8 +815,6 @@ void PieChart::createShapes()
if(!pSeries)
continue;
- bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
-
/// The angle degree offset is set by the same property of the
/// data series.
/// Counter-clockwise offset from the 3 o'clock position.
@@ -835,6 +824,8 @@ void PieChart::createShapes()
///the current data series
sal_Int32 nPointIndex=0;
sal_Int32 nPointCount=pSeries->getTotalPointCount();
+ ShapeParam aParam;
+
for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
{
double fY = pSeries->getYValue( nPointIndex );
@@ -851,134 +842,175 @@ void PieChart::createShapes()
// Total sum of all Y values in this series is zero. Skip the whole series.
continue;
- double fLogicYForNextPoint = 0.0;
- ///iterate through all points to create shapes
- for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
- {
- double fLogicInnerRadius, fLogicOuterRadius;
-
- ///compute the maximum relative distance offset of the current slice
- ///from the pie center
- ///it is worth noting that after the first invocation the maximum
- ///offset value is cached, so it is evaluated only once per each
- ///call to `createShapes`
- double fOffset = getMaxOffset();
-
- ///compute the outer and the inner radius for the current ring slice
- bool bIsVisible = m_aPosHelper.getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
- if( !bIsVisible )
- continue;
+ switch (m_eSubType) {
+ case PieChartSubType_NONE:
+ createOneRing(SubPieType::NONE, fSlotX, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
+ break;
+ case PieChartSubType_BAR:
+ createOneRing(SubPieType::LEFT, fSlotX, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
+ break;
+ case PieChartSubType_PIE:
+ createOneRing(SubPieType::LEFT, fSlotX, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
+ break;
+ default:
+ assert(false); // this shouldn't happen
+ }
+ }//next x slot
+}
- aParam.mfDepth = getTransformedDepth() * (n3DRelativeHeight / 100.0);
+void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
+ double fSlotX,
+ ShapeParam& aParam,
+ const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ const rtl::Reference<SvxShapeGroup>& xTextTarget,
+ VDataSeries* pSeries,
+ sal_Int32 n3DRelativeHeight)
+{
+ bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
- rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
- ///collect data point information (logic coordinates, style ):
- double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
- if( std::isnan(fLogicYValue) )
- continue;
- if(fLogicYValue==0.0)//@todo: continue also if the resolution is too small
- continue;
- double fLogicYPos = fLogicYForNextPoint;
- fLogicYForNextPoint += fLogicYValue;
+ /// The angle degree offset is set by the same property of the
+ /// data series.
+ /// Counter-clockwise offset from the 3 o'clock position.
+ m_aPosHelper.m_fAngleDegreeOffset = pSeries->getStartingAngle();
+
+ ///iterate through all points to get the sum of all entries of
+ ///the current data series
+ sal_Int32 nPointCount=pSeries->getTotalPointCount();
+
+ ///the `explodeable` ring is the first one except when the radius axis
+ ///orientation is reversed (always!?) and we are dealing with a donut: in
+ ///such a case the `explodeable` ring is the last one.
+ std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
+ if( m_aPosHelper.isMathematicalOrientationRadius() && m_bUseRings )
+ nExplodeableSlot = m_aZSlots.front().size()-1;
+
+ double fLogicYForNextPoint = 0.0;
+ ///iterate through all points to create shapes
+ for(sal_Int32 nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
+ {
+ double fLogicInnerRadius, fLogicOuterRadius;
+
+ ///compute the maximum relative distance offset of the current slice
+ ///from the pie center
+ ///it is worth noting that after the first invocation the maximum
+ ///offset value is cached, so it is evaluated only once per each
+ ///call to `createShapes`
+ double fOffset = getMaxOffset();
+
+ ///compute the outer and the inner radius for the current ring slice
+ bool bIsVisible = m_aPosHelper.getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
+ if( !bIsVisible )
+ continue;
+
+ aParam.mfDepth = getTransformedDepth() * (n3DRelativeHeight / 100.0);
+
+ rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
+ ///collect data point information (logic coordinates, style ):
+ double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
+ if( std::isnan(fLogicYValue) )
+ continue;
+ if(fLogicYValue==0.0)//@todo: continue also if the resolution is too small
+ continue;
+ double fLogicYPos = fLogicYForNextPoint;
+ fLogicYForNextPoint += fLogicYValue;
- uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
+ uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
- //iterate through all subsystems to create partial points
+ //iterate through all subsystems to create partial points
+ {
+ //logic values on angle axis:
+ double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum;
+ double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / aParam.mfLogicYSum;
+
+ ///note that the explode percentage is set to the `Offset`
+ ///property of the current data series entry only for slices
+ ///belonging to the outer ring
+ aParam.mfExplodePercentage = 0.0;
+ bool bDoExplode = ( nExplodeableSlot == static_cast< std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
+ if(bDoExplode) try
{
- //logic values on angle axis:
- double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum;
- double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / aParam.mfLogicYSum;
-
- ///note that the explode percentage is set to the `Offset`
- ///property of the current data series entry only for slices
- ///belonging to the outer ring
- aParam.mfExplodePercentage = 0.0;
- bool bDoExplode = ( nExplodeableSlot == static_cast< std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
- if(bDoExplode) try
- {
- xPointProperties->getPropertyValue( "Offset") >>= aParam.mfExplodePercentage;
- }
- catch( const uno::Exception& )
- {
- TOOLS_WARN_EXCEPTION("chart2", "" );
- }
+ xPointProperties->getPropertyValue( "Offset") >>= aParam.mfExplodePercentage;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
- ///see notes for `PolarPlottingPositionHelper` methods
- ///transform to unit circle:
- aParam.mfUnitCircleWidthAngleDegree = m_aPosHelper.getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
- aParam.mfUnitCircleStartAngleDegree = m_aPosHelper.transformToAngleDegree( fLogicStartAngleValue );
- aParam.mfUnitCircleInnerRadius = m_aPosHelper.transformToRadius( fLogicInnerRadius );
- aParam.mfUnitCircleOuterRadius = m_aPosHelper.transformToRadius( fLogicOuterRadius );
-
- ///create data point
- aParam.mfLogicZ = -1.0; // For 3D pie chart label position
-
- // Do concentric explosion if it's a donut chart with more than one series
- const bool bConcentricExplosion = m_bUseRings && (m_aZSlots.front().size() > 1);
- rtl::Reference<SvxShape> xPointShape =
- createDataPoint(
- xSeriesGroupShape_Shapes, xPointProperties, aParam, nPointCount,
- bConcentricExplosion);
-
- ///point color:
- if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
- {
- xPointShape->setPropertyValue("FillColor",
- uno::Any(m_xColorScheme->getColorByIndex( nPointIndex )));
- }
+ ///see notes for `PolarPlottingPositionHelper` methods
+ ///transform to unit circle:
+ aParam.mfUnitCircleWidthAngleDegree = m_aPosHelper.getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
+ aParam.mfUnitCircleStartAngleDegree = m_aPosHelper.transformToAngleDegree( fLogicStartAngleValue );
+ aParam.mfUnitCircleInnerRadius = m_aPosHelper.transformToRadius( fLogicInnerRadius );
+ aParam.mfUnitCircleOuterRadius = m_aPosHelper.transformToRadius( fLogicOuterRadius );
+
+ ///create data point
+ aParam.mfLogicZ = -1.0; // For 3D pie chart label position
+
+ // Do concentric explosion if it's a donut chart with more than one series
+ const bool bConcentricExplosion = m_bUseRings && (m_aZSlots.front().size() > 1);
+ rtl::Reference<SvxShape> xPointShape =
+ createDataPoint(
+ xSeriesGroupShape_Shapes, xPointProperties, aParam, nPointCount,
+ bConcentricExplosion);
+
+ ///point color:
+ if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
+ {
+ xPointShape->setPropertyValue("FillColor",
+ uno::Any(m_xColorScheme->getColorByIndex( nPointIndex )));
+ }
- if(bHasFillColorMapping)
+ if(bHasFillColorMapping)
+ {
+ double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
+ if(!std::isnan(nPropVal))
{
- double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
- if(!std::isnan(nPropVal))
- {
- xPointShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>( nPropVal)));
- }
+ xPointShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>( nPropVal)));
}
+ }
- ///create label
- createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam);
+ ///create label
+ createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam);
- if(!bDoExplode)
- {
- ShapeFactory::setShapeName( xPointShape
- , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) );
- }
- else try
- {
- ///enable dragging of outer segments
-
- double fAngle = aParam.mfUnitCircleStartAngleDegree + aParam.mfUnitCircleWidthAngleDegree/2.0;
- double fMaxDeltaRadius = aParam.mfUnitCircleOuterRadius-aParam.mfUnitCircleInnerRadius;
- drawing::Position3D aOrigin = m_aPosHelper.transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ );
- drawing::Position3D aNewOrigin = m_aPosHelper.transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius + fMaxDeltaRadius, aParam.mfLogicZ );
-
- sal_Int32 nOffsetPercent( static_cast<sal_Int32>(aParam.mfExplodePercentage * 100.0) );
-
- awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
- aOrigin, m_xLogicTarget, m_nDimension ) );
- awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
- aNewOrigin, m_xLogicTarget, m_nDimension ) );
-
- //enable dragging of piesegments
- OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
- , pSeries->getSeriesParticle()
- , ObjectIdentifier::getPieSegmentDragMethodServiceName()
- , ObjectIdentifier::createPieSegmentDragParameterString(
- nOffsetPercent, aMinimumPosition, aMaximumPosition )
- ) );
-
- ShapeFactory::setShapeName( xPointShape
- , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) );
- }
- catch( const uno::Exception& )
- {
- TOOLS_WARN_EXCEPTION("chart2", "" );
- }
- }//next series in x slot (next y slot)
- }//next category
- }//next x slot
+ if(!bDoExplode)
+ {
+ ShapeFactory::setShapeName( xPointShape
+ , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) );
+ }
+ else try
+ {
+ ///enable dragging of outer segments
+
+ double fAngle = aParam.mfUnitCircleStartAngleDegree + aParam.mfUnitCircleWidthAngleDegree/2.0;
+ double fMaxDeltaRadius = aParam.mfUnitCircleOuterRadius-aParam.mfUnitCircleInnerRadius;
+ drawing::Position3D aOrigin = m_aPosHelper.transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ );
+ drawing::Position3D aNewOrigin = m_aPosHelper.transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius + fMaxDeltaRadius, aParam.mfLogicZ );
+
+ sal_Int32 nOffsetPercent( static_cast<sal_Int32>(aParam.mfExplodePercentage * 100.0) );
+
+ awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
+ aOrigin, m_xLogicTarget, m_nDimension ) );
+ awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
+ aNewOrigin, m_xLogicTarget, m_nDimension ) );
+
+ //enable dragging of piesegments
+ OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
+ , pSeries->getSeriesParticle()
+ , ObjectIdentifier::getPieSegmentDragMethodServiceName()
+ , ObjectIdentifier::createPieSegmentDragParameterString(
+ nOffsetPercent, aMinimumPosition, aMaximumPosition )
+ ) );
+
+ ShapeFactory::setShapeName( xPointShape
+ , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ }//next series in x slot (next y slot)
+ }//next category
}
PieChart::PieLabelInfo::PieLabelInfo()
diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx
index d6792f0b8479..5c04ee05cf86 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -75,6 +75,12 @@ public:
virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) override;
virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override;
+ enum class SubPieType {
+ NONE,
+ LEFT,
+ RIGHT
+ };
+
private: //methods
rtl::Reference<SvxShape>
createDataPoint(
@@ -122,6 +128,14 @@ struct PieLabelInfo;
bool performLabelBestFitInnerPlacement( ShapeParam& rShapeParam
, PieLabelInfo const & rPieLabelInfo );
+ void createOneRing([[maybe_unused]]enum SubPieType eType
+ , double fSlotX
+ , ShapeParam& aParam
+ , const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget
+ , const rtl::Reference<SvxShapeGroup>& xTextTarget
+ , VDataSeries* pSeries
+ , sal_Int32 n3DRelativeHeight);
+
private: //member
PiePositionHelper m_aPosHelper;
bool m_bUseRings;