1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <VDataSeries.hxx>
23 #include <ObjectIdentifier.hxx>
24 #include <CommonConverters.hxx>
25 #include <LabelPositionHelper.hxx>
26 #include <ChartTypeHelper.hxx>
27 #include <RegressionCurveHelper.hxx>
28 #include <unonames.hxx>
30 #include <com/sun/star/chart/MissingValueTreatment.hpp>
31 #include <com/sun/star/chart2/DataPointLabel.hpp>
32 #include <com/sun/star/chart2/Symbol.hpp>
33 #include <com/sun/star/chart2/XDataSeries.hpp>
34 #include <com/sun/star/chart2/XRegressionCurveCalculator.hpp>
35 #include <com/sun/star/chart2/RelativePosition.hpp>
37 #include <osl/diagnose.h>
38 #include <tools/color.hxx>
39 #include <tools/diagnose_ex.h>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/beans/XPropertyState.hpp>
42 #include <com/sun/star/chart2/data/XDataSource.hpp>
46 using namespace ::com::sun::star
;
47 using namespace ::com::sun::star::chart2
;
48 using ::com::sun::star::uno::Reference
;
50 void VDataSequence::init( const uno::Reference
< data::XDataSequence
>& xModel
)
53 Doubles
= DataSequenceToDoubleSequence( xModel
);
56 bool VDataSequence::is() const
60 void VDataSequence::clear()
66 double VDataSequence::getValue( sal_Int32 index
) const
68 if( 0<=index
&& index
<Doubles
.getLength() )
69 return Doubles
[index
];
70 return std::numeric_limits
<double>::quiet_NaN();
73 sal_Int32
VDataSequence::detectNumberFormatKey( sal_Int32 index
) const
75 sal_Int32 nNumberFormatKey
= -1;
77 // -1 is allowed and means a key for the whole sequence
78 if( -1<=index
&& index
<Doubles
.getLength() &&
81 nNumberFormatKey
= Model
->getNumberFormatKeyByIndex( index
);
84 return nNumberFormatKey
;
87 sal_Int32
VDataSequence::getLength() const
89 return Doubles
.getLength();
94 struct lcl_LessXOfPoint
96 bool operator() ( const std::vector
< double >& first
,
97 const std::vector
< double >& second
)
99 if( !first
.empty() && !second
.empty() )
101 return first
[0]<second
[0];
107 void lcl_clearIfNoValuesButTextIsContained( VDataSequence
& rData
, const uno::Reference
<data::XDataSequence
>& xDataSequence
)
109 //#i71686#, #i101968#, #i102428#
110 sal_Int32 nCount
= rData
.Doubles
.getLength();
111 for( sal_Int32 i
= 0; i
< nCount
; ++i
)
113 if( !std::isnan( rData
.Doubles
[i
] ) )
116 //no double value is contained
118 uno::Sequence
< OUString
> aStrings( DataSequenceToStringSequence( xDataSequence
) );
119 sal_Int32 nTextCount
= aStrings
.getLength();
120 for( sal_Int32 j
= 0; j
< nTextCount
; ++j
)
122 if( !aStrings
[j
].isEmpty() )
131 void lcl_maybeReplaceNanWithZero( double& rfValue
, sal_Int32 nMissingValueTreatment
)
133 if( nMissingValueTreatment
== css::chart::MissingValueTreatment::USE_ZERO
134 && (std::isnan(rfValue
) || std::isinf(rfValue
)) )
140 VDataSeries::VDataSeries( const uno::Reference
< XDataSeries
>& xDataSeries
)
145 , m_xDataSeries(xDataSeries
)
147 , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y
)
148 , m_fXMeanValue(std::numeric_limits
<double>::quiet_NaN())
149 , m_fYMeanValue(std::numeric_limits
<double>::quiet_NaN())
150 , m_eStackingDirection(StackingDirection_NO_STACKING
)
152 , m_bConnectBars(false)
153 , m_bGroupBarsPerAxis(true)
154 , m_nStartingAngle(90)
155 , m_nGlobalSeriesIndex(0)
156 , m_nCurrentAttributedPoint(-1)
157 , m_nMissingValueTreatment(css::chart::MissingValueTreatment::LEAVE_GAP
)
158 , m_bAllowPercentValueInDataLabel(false)
159 , mpOldSeries(nullptr)
162 uno::Reference
<data::XDataSource
> xDataSource( xDataSeries
, uno::UNO_QUERY
);
164 uno::Sequence
< uno::Reference
<
165 chart2::data::XLabeledDataSequence
> > aDataSequences
=
166 xDataSource
->getDataSequences();
168 for(sal_Int32 nN
= aDataSequences
.getLength();nN
--;)
170 if(!aDataSequences
[nN
].is())
172 uno::Reference
<data::XDataSequence
> xDataSequence( aDataSequences
[nN
]->getValues());
173 uno::Reference
<beans::XPropertySet
> xProp(xDataSequence
, uno::UNO_QUERY
);
178 uno::Any aARole
= xProp
->getPropertyValue("Role");
182 if (aRole
== "values-x")
184 m_aValues_X
.init( xDataSequence
);
185 lcl_clearIfNoValuesButTextIsContained( m_aValues_X
, xDataSequence
);
187 else if (aRole
=="values-y")
188 m_aValues_Y
.init( xDataSequence
);
189 else if (aRole
== "values-min")
190 m_aValues_Y_Min
.init( xDataSequence
);
191 else if (aRole
== "values-max")
192 m_aValues_Y_Max
.init( xDataSequence
);
193 else if (aRole
== "values-first")
194 m_aValues_Y_First
.init( xDataSequence
);
195 else if (aRole
== "values-last")
196 m_aValues_Y_Last
.init( xDataSequence
);
197 else if (aRole
== "values-size")
198 m_aValues_Bubble_Size
.init( xDataSequence
);
201 VDataSequence aSequence
;
202 aSequence
.init(xDataSequence
);
203 m_PropertyMap
.insert(std::make_pair(aRole
, aSequence
));
206 catch( const uno::Exception
& )
208 TOOLS_WARN_EXCEPTION("chart2", "" );
213 //determine the point count
214 m_nPointCount
= m_aValues_Y
.getLength();
216 if( m_nPointCount
< m_aValues_Bubble_Size
.getLength() )
217 m_nPointCount
= m_aValues_Bubble_Size
.getLength();
218 if( m_nPointCount
< m_aValues_Y_Min
.getLength() )
219 m_nPointCount
= m_aValues_Y_Min
.getLength();
220 if( m_nPointCount
< m_aValues_Y_Max
.getLength() )
221 m_nPointCount
= m_aValues_Y_Max
.getLength();
222 if( m_nPointCount
< m_aValues_Y_First
.getLength() )
223 m_nPointCount
= m_aValues_Y_First
.getLength();
224 if( m_nPointCount
< m_aValues_Y_Last
.getLength() )
225 m_nPointCount
= m_aValues_Y_Last
.getLength();
228 uno::Reference
<beans::XPropertySet
> xProp(xDataSeries
, uno::UNO_QUERY
);
234 //get AttributedDataPoints
235 xProp
->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList
;
237 xProp
->getPropertyValue("StackingDirection") >>= m_eStackingDirection
;
239 xProp
->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex
;
243 catch( const uno::Exception
& )
245 TOOLS_WARN_EXCEPTION("chart2", "" );
249 VDataSeries::~VDataSeries()
253 void VDataSeries::doSortByXValues()
255 if( !(m_aValues_X
.is() && m_aValues_X
.Doubles
.hasElements()) )
258 //prepare a vector for sorting
259 std::vector
< std::vector
< double > > aTmp
;//outer vector are points, inner vector are the different values of the point
260 sal_Int32 nPointIndex
= 0;
261 for( nPointIndex
=0; nPointIndex
< m_nPointCount
; nPointIndex
++ )
264 { ((nPointIndex
< m_aValues_X
.Doubles
.getLength()) ? m_aValues_X
.Doubles
[nPointIndex
]
265 : std::numeric_limits
<double>::quiet_NaN()),
266 ((nPointIndex
< m_aValues_Y
.Doubles
.getLength()) ? m_aValues_Y
.Doubles
[nPointIndex
]
267 : std::numeric_limits
<double>::quiet_NaN())
273 std::stable_sort( aTmp
.begin(), aTmp
.end(), lcl_LessXOfPoint() );
275 //fill the sorted points back to the members
276 m_aValues_X
.Doubles
.realloc( m_nPointCount
);
277 m_aValues_Y
.Doubles
.realloc( m_nPointCount
);
279 for( nPointIndex
=0; nPointIndex
< m_nPointCount
; nPointIndex
++ )
281 m_aValues_X
.Doubles
[nPointIndex
]=aTmp
[nPointIndex
][0];
282 m_aValues_Y
.Doubles
[nPointIndex
]=aTmp
[nPointIndex
][1];
286 void VDataSeries::releaseShapes()
288 m_xGroupShape
.set(nullptr);
289 m_xLabelsGroupShape
.set(nullptr);
290 m_xErrorXBarsGroupShape
.set(nullptr);
291 m_xErrorYBarsGroupShape
.set(nullptr);
292 m_xFrontSubGroupShape
.set(nullptr);
293 m_xBackSubGroupShape
.set(nullptr);
295 m_aPolyPolygonShape3D
.SequenceX
.realloc(0);
296 m_aPolyPolygonShape3D
.SequenceY
.realloc(0);
297 m_aPolyPolygonShape3D
.SequenceZ
.realloc(0);
301 const uno::Reference
<css::chart2::XDataSeries
>& VDataSeries::getModel() const
303 return m_xDataSeries
;
306 void VDataSeries::setCategoryXAxis()
309 m_bAllowPercentValueInDataLabel
= true;
312 void VDataSeries::setXValues( const Reference
< chart2::data::XDataSequence
>& xValues
)
315 m_aValues_X
.init( xValues
);
316 m_bAllowPercentValueInDataLabel
= true;
319 void VDataSeries::setXValuesIfNone( const Reference
< chart2::data::XDataSequence
>& xValues
)
321 if( m_aValues_X
.is() )
324 m_aValues_X
.init( xValues
);
325 lcl_clearIfNoValuesButTextIsContained( m_aValues_X
, xValues
);
328 void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex
)
330 m_nGlobalSeriesIndex
= nGlobalSeriesIndex
;
333 void VDataSeries::setParticle( const OUString
& rSeriesParticle
)
335 m_aSeriesParticle
= rSeriesParticle
;
338 m_aCID
= ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle
);
339 m_aPointCID_Stub
= ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
, m_aSeriesParticle
);
341 m_aLabelCID_Stub
= ObjectIdentifier::createClassifiedIdentifierWithParent(
342 OBJECTTYPE_DATA_LABEL
, u
"", getLabelsCID() );
344 OUString
VDataSeries::getErrorBarsCID(bool bYError
) const
346 OUString
aChildParticle( ObjectIdentifier::getStringForType(
347 bYError
? OBJECTTYPE_DATA_ERRORS_Y
: OBJECTTYPE_DATA_ERRORS_X
)
350 return ObjectIdentifier::createClassifiedIdentifierForParticles(
351 m_aSeriesParticle
, aChildParticle
);
353 OUString
VDataSeries::getLabelsCID() const
355 OUString
aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS
) + "=" );
357 return ObjectIdentifier::createClassifiedIdentifierForParticles(
358 m_aSeriesParticle
, aChildParticle
);
360 OUString
VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex
, bool bAverageLine
) const
362 return ObjectIdentifier::createDataCurveCID( m_aSeriesParticle
, nCurveIndex
, bAverageLine
);
365 OUString
VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex
) const
367 return ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle
, nCurveIndex
);
369 void VDataSeries::setPageReferenceSize( const awt::Size
& rPageRefSize
)
371 m_aReferenceSize
= rPageRefSize
;
374 void VDataSeries::setConnectBars( bool bConnectBars
)
376 m_bConnectBars
= bConnectBars
;
379 bool VDataSeries::getConnectBars() const
381 return m_bConnectBars
;
384 void VDataSeries::setGroupBarsPerAxis( bool bGroupBarsPerAxis
)
386 m_bGroupBarsPerAxis
= bGroupBarsPerAxis
;
389 bool VDataSeries::getGroupBarsPerAxis() const
391 return m_bGroupBarsPerAxis
;
394 void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle
)
396 m_nStartingAngle
= nStartingAngle
;
399 sal_Int32
VDataSeries::getStartingAngle() const
401 return m_nStartingAngle
;
404 chart2::StackingDirection
VDataSeries::getStackingDirection() const
406 return m_eStackingDirection
;
409 sal_Int32
VDataSeries::getAttachedAxisIndex() const
414 void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex
)
416 if( nAttachedAxisIndex
< 0 )
417 nAttachedAxisIndex
= 0;
418 m_nAxisIndex
= nAttachedAxisIndex
;
421 double VDataSeries::getXValue( sal_Int32 index
) const
423 double fRet
= std::numeric_limits
<double>::quiet_NaN();
426 if( 0<=index
&& index
<m_aValues_X
.getLength() )
428 fRet
= m_aValues_X
.Doubles
[index
];
429 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_X
.getLength())
431 double nOldVal
= mpOldSeries
->m_aValues_X
.Doubles
[index
];
432 fRet
= nOldVal
+ (fRet
- nOldVal
) * mnPercent
;
438 // #i70133# always return correct X position - needed for short data series
439 if( 0<=index
/*&& index < m_nPointCount*/ )
440 fRet
= index
+1;//first category (index 0) matches with real number 1.0
442 lcl_maybeReplaceNanWithZero( fRet
, getMissingValueTreatment() );
446 double VDataSeries::getYValue( sal_Int32 index
) const
448 double fRet
= std::numeric_limits
<double>::quiet_NaN();
451 if( 0<=index
&& index
<m_aValues_Y
.getLength() )
453 fRet
= m_aValues_Y
.Doubles
[index
];
454 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_Y
.getLength())
456 double nOldVal
= mpOldSeries
->m_aValues_Y
.Doubles
[index
];
457 fRet
= nOldVal
+ (fRet
- nOldVal
) * mnPercent
;
463 // #i70133# always return correct X position - needed for short data series
464 if( 0<=index
/*&& index < m_nPointCount*/ )
465 fRet
= index
+1;//first category (index 0) matches with real number 1.0
467 lcl_maybeReplaceNanWithZero( fRet
, getMissingValueTreatment() );
471 void VDataSeries::getMinMaxXValue(double& fMin
, double& fMax
) const
473 fMax
= std::numeric_limits
<double>::quiet_NaN();
474 fMin
= std::numeric_limits
<double>::quiet_NaN();
476 uno::Sequence
< double > aValuesX
= getAllX();
478 if(!aValuesX
.hasElements())
482 while ( i
< aValuesX
.getLength() && std::isnan(aValuesX
[i
]) )
484 if ( i
< aValuesX
.getLength() )
485 fMax
= fMin
= aValuesX
[i
++];
487 for ( ; i
< aValuesX
.getLength(); i
++)
489 const double aValue
= aValuesX
[i
];
494 else if ( aValue
< fMin
)
500 double VDataSeries::getY_Min( sal_Int32 index
) const
502 return m_aValues_Y_Min
.getValue( index
);
504 double VDataSeries::getY_Max( sal_Int32 index
) const
506 return m_aValues_Y_Max
.getValue( index
);
508 double VDataSeries::getY_First( sal_Int32 index
) const
510 return m_aValues_Y_First
.getValue( index
);
512 double VDataSeries::getY_Last( sal_Int32 index
) const
514 return m_aValues_Y_Last
.getValue( index
);
516 double VDataSeries::getBubble_Size( sal_Int32 index
) const
518 double nNewVal
= m_aValues_Bubble_Size
.getValue( index
);
519 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_Bubble_Size
.getLength())
521 double nOldVal
= mpOldSeries
->m_aValues_Bubble_Size
.getValue( index
);
522 nNewVal
= nOldVal
+ (nNewVal
- nOldVal
) * mnPercent
;
528 bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex
, bool bForPercentage
) const
530 OUString aPropName
= bForPercentage
? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT
);
531 bool bHasNumberFormat
= false;
532 bool bLinkToSource
= true;
533 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( nPointIndex
));
534 if( xPointProp
.is() && (xPointProp
->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT
) >>= bLinkToSource
))
536 sal_Int32 nNumberFormat
= -1;
537 if( !bLinkToSource
&& (xPointProp
->getPropertyValue(aPropName
) >>= nNumberFormat
))
538 bHasNumberFormat
= true;
540 return bHasNumberFormat
;
542 sal_Int32
VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex
, bool bForPercentage
) const
544 OUString aPropName
= bForPercentage
? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT
);
545 sal_Int32 nNumberFormat
= -1;
546 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( nPointIndex
));
547 if( xPointProp
.is() )
548 xPointProp
->getPropertyValue(aPropName
) >>= nNumberFormat
;
549 return nNumberFormat
;
551 void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( std::u16string_view rRole
)
553 if (rRole
== u
"values-y")
554 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y
;
555 else if (rRole
== u
"values-size")
556 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Bubble_Size
;
557 else if (rRole
== u
"values-min")
558 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Min
;
559 else if (rRole
== u
"values-max")
560 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Max
;
561 else if (rRole
== u
"values-first")
562 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_First
;
563 else if (rRole
== u
"values-last")
564 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Last
;
565 else if (rRole
== u
"values-x")
566 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_X
;
568 sal_Int32
VDataSeries::detectNumberFormatKey( sal_Int32 index
) const
571 if( m_pValueSequenceForDataLabelNumberFormatDetection
)
572 nRet
= m_pValueSequenceForDataLabelNumberFormatDetection
->detectNumberFormatKey( index
);
576 sal_Int32
VDataSeries::getLabelPlacement( sal_Int32 nPointIndex
, const uno::Reference
< chart2::XChartType
>& xChartType
, bool bSwapXAndY
) const
578 sal_Int32 nLabelPlacement
=0;
581 uno::Reference
< beans::XPropertySet
> xPointProps( getPropertiesOfPoint( nPointIndex
) );
582 if( xPointProps
.is() )
583 xPointProps
->getPropertyValue("LabelPlacement") >>= nLabelPlacement
;
585 const uno::Sequence
< sal_Int32
> aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
586 xChartType
, bSwapXAndY
, m_xDataSeries
) );
588 for( sal_Int32 n
: aAvailablePlacements
)
589 if( n
== nLabelPlacement
)
590 return nLabelPlacement
; //ok
592 //otherwise use the first supported one
593 if( aAvailablePlacements
.hasElements() )
595 nLabelPlacement
= aAvailablePlacements
[0];
596 if( xPointProps
.is() )
597 xPointProps
->setPropertyValue("LabelPlacement", uno::Any(nLabelPlacement
));
598 return nLabelPlacement
;
601 OSL_FAIL("no label placement supported");
603 catch( const uno::Exception
& )
605 TOOLS_WARN_EXCEPTION("chart2", "" );
607 return nLabelPlacement
;
610 awt::Point
VDataSeries::getLabelPosition( awt::Point aTextShapePos
, sal_Int32 nPointIndex
) const
612 awt::Point
aPos(-1, -1);
615 RelativePosition aCustomLabelPosition
;
616 uno::Reference
< beans::XPropertySet
> xPointProps(getPropertiesOfPoint(nPointIndex
));
617 if( xPointProps
.is() && (xPointProps
->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition
))
619 aPos
.X
= static_cast<sal_Int32
>(aCustomLabelPosition
.Primary
* m_aReferenceSize
.Width
) + aTextShapePos
.X
;
620 aPos
.Y
= static_cast<sal_Int32
>(aCustomLabelPosition
.Secondary
* m_aReferenceSize
.Height
) + aTextShapePos
.Y
;
623 catch (const uno::Exception
&)
625 TOOLS_WARN_EXCEPTION("chart2", "");
630 bool VDataSeries::isLabelCustomPos(sal_Int32 nPointIndex
) const
632 bool bCustom
= false;
635 if( isAttributedDataPoint(nPointIndex
) )
637 uno::Reference
< beans::XPropertySet
> xPointProps(m_xDataSeries
->getDataPointByIndex(nPointIndex
));
638 RelativePosition aCustomLabelPosition
;
639 if( xPointProps
.is() && (xPointProps
->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition
) )
643 catch (const uno::Exception
&)
645 TOOLS_WARN_EXCEPTION("chart2", "");
650 double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index
) const
652 double fMin
= std::numeric_limits
<double>::infinity();
654 if( !m_aValues_Y
.is() &&
655 (m_aValues_Y_Min
.is() || m_aValues_Y_Max
.is()
656 || m_aValues_Y_First
.is() || m_aValues_Y_Last
.is() ) )
658 double fY_Min
= getY_Min( index
);
659 double fY_Max
= getY_Max( index
);
660 double fY_First
= getY_First( index
);
661 double fY_Last
= getY_Last( index
);
674 double fY
= getYValue( index
);
679 if( std::isinf(fMin
) )
680 return std::numeric_limits
<double>::quiet_NaN();
685 double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index
) const
687 double fMax
= -std::numeric_limits
<double>::infinity();
689 if( !m_aValues_Y
.is() &&
690 (m_aValues_Y_Min
.is() || m_aValues_Y_Max
.is()
691 || m_aValues_Y_First
.is() || m_aValues_Y_Last
.is() ) )
693 double fY_Min
= getY_Min( index
);
694 double fY_Max
= getY_Max( index
);
695 double fY_First
= getY_First( index
);
696 double fY_Last
= getY_Last( index
);
709 double fY
= getYValue( index
);
714 if( std::isinf(fMax
) )
715 return std::numeric_limits
<double>::quiet_NaN();
720 uno::Sequence
< double > const & VDataSeries::getAllX() const
722 if(!m_aValues_X
.is() && !m_aValues_X
.getLength() && m_nPointCount
)
724 //init x values from category indexes
725 //first category (index 0) matches with real number 1.0
726 m_aValues_X
.Doubles
.realloc( m_nPointCount
);
727 for(sal_Int32 nN
=m_aValues_X
.getLength();nN
--;)
728 m_aValues_X
.Doubles
[nN
] = nN
+1;
730 return m_aValues_X
.Doubles
;
733 uno::Sequence
< double > const & VDataSeries::getAllY() const
735 if(!m_aValues_Y
.is() && !m_aValues_Y
.getLength() && m_nPointCount
)
737 //init y values from indexes
738 //first y-value (index 0) matches with real number 1.0
739 m_aValues_Y
.Doubles
.realloc( m_nPointCount
);
740 for(sal_Int32 nN
=m_aValues_Y
.getLength();nN
--;)
741 m_aValues_Y
.Doubles
[nN
] = nN
+1;
743 return m_aValues_Y
.Doubles
;
746 double VDataSeries::getXMeanValue() const
748 if( std::isnan( m_fXMeanValue
) )
750 uno::Reference
< XRegressionCurveCalculator
> xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( u
"com.sun.star.chart2.MeanValueRegressionCurve" ) );
751 uno::Sequence
< double > aXValuesDummy
;
752 xCalculator
->recalculateRegression( aXValuesDummy
, getAllX() );
753 m_fXMeanValue
= xCalculator
->getCurveValue( 1.0 );
755 return m_fXMeanValue
;
758 double VDataSeries::getYMeanValue() const
760 if( std::isnan( m_fYMeanValue
) )
762 uno::Reference
< XRegressionCurveCalculator
> xCalculator(
763 RegressionCurveHelper::createRegressionCurveCalculatorByServiceName(u
"com.sun.star.chart2.MeanValueRegressionCurve"));
764 uno::Sequence
< double > aXValuesDummy
;
765 xCalculator
->recalculateRegression( aXValuesDummy
, getAllY() );
766 m_fYMeanValue
= xCalculator
->getCurveValue( 1.0 );
768 return m_fYMeanValue
;
771 static std::unique_ptr
<Symbol
> getSymbolPropertiesFromPropertySet( const uno::Reference
< beans::XPropertySet
>& xProp
)
773 std::unique_ptr
< Symbol
> apSymbolProps( new Symbol() );
776 if( xProp
->getPropertyValue("Symbol") >>= *apSymbolProps
)
778 //use main color to fill symbols
779 xProp
->getPropertyValue("Color") >>= apSymbolProps
->FillColor
;
780 // border of symbols always same as fill color
781 apSymbolProps
->BorderColor
= apSymbolProps
->FillColor
;
784 apSymbolProps
.reset();
786 catch(const uno::Exception
&)
788 TOOLS_WARN_EXCEPTION("chart2", "" );
790 return apSymbolProps
;
793 Symbol
* VDataSeries::getSymbolProperties( sal_Int32 index
) const
795 Symbol
* pRet
=nullptr;
796 if( isAttributedDataPoint( index
) )
798 adaptPointCache( index
);
799 if (!m_apSymbolProperties_AttributedPoint
)
800 m_apSymbolProperties_AttributedPoint
801 = getSymbolPropertiesFromPropertySet(getPropertiesOfPoint(index
));
802 pRet
= m_apSymbolProperties_AttributedPoint
.get();
803 //if a single data point does not have symbols but the dataseries itself has symbols
804 //we create an invisible symbol shape to enable selection of that point
805 if( !pRet
|| pRet
->Style
== SymbolStyle_NONE
)
807 if (!m_apSymbolProperties_Series
)
808 m_apSymbolProperties_Series
809 = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries());
810 if( m_apSymbolProperties_Series
&& m_apSymbolProperties_Series
->Style
!= SymbolStyle_NONE
)
812 if (!m_apSymbolProperties_InvisibleSymbolForSelection
)
814 m_apSymbolProperties_InvisibleSymbolForSelection
.reset(new Symbol
);
815 m_apSymbolProperties_InvisibleSymbolForSelection
->Style
= SymbolStyle_STANDARD
;
816 m_apSymbolProperties_InvisibleSymbolForSelection
->StandardSymbol
= 0;//square
817 m_apSymbolProperties_InvisibleSymbolForSelection
->Size
= com::sun::star::awt::Size(0, 0);//tdf#126033
818 m_apSymbolProperties_InvisibleSymbolForSelection
->BorderColor
= 0xff000000;//invisible
819 m_apSymbolProperties_InvisibleSymbolForSelection
->FillColor
= 0xff000000;//invisible
821 pRet
= m_apSymbolProperties_InvisibleSymbolForSelection
.get();
827 if (!m_apSymbolProperties_Series
)
828 m_apSymbolProperties_Series
829 = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries());
830 pRet
= m_apSymbolProperties_Series
.get();
833 if( pRet
&& pRet
->Style
== SymbolStyle_AUTO
)
835 pRet
->Style
= SymbolStyle_STANDARD
;
837 sal_Int32 nIndex
= m_nGlobalSeriesIndex
;
840 pRet
->StandardSymbol
= nIndex
;
846 uno::Reference
< beans::XPropertySet
> VDataSeries::getXErrorBarProperties( sal_Int32 index
) const
848 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
850 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( index
));
851 if( xPointProp
.is() )
852 xPointProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
;
853 return xErrorBarProp
;
856 uno::Reference
< beans::XPropertySet
> VDataSeries::getYErrorBarProperties( sal_Int32 index
) const
858 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
860 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( index
));
861 if( xPointProp
.is() )
862 xPointProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
;
863 return xErrorBarProp
;
866 bool VDataSeries::hasPointOwnColor( sal_Int32 index
) const
868 if( !isAttributedDataPoint(index
) )
873 uno::Reference
< beans::XPropertyState
> xPointState( getPropertiesOfPoint(index
), uno::UNO_QUERY_THROW
);
874 return (xPointState
->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE
);
876 catch(const uno::Exception
&)
878 TOOLS_WARN_EXCEPTION("chart2", "" );
883 bool VDataSeries::isAttributedDataPoint( sal_Int32 index
) const
885 //returns true if the data point assigned by the given index has set its own properties
886 if( index
>=m_nPointCount
|| m_nPointCount
==0)
888 for(sal_Int32 n
: m_aAttributedDataPointIndexList
)
896 bool VDataSeries::isVaryColorsByPoint() const
898 bool bVaryColorsByPoint
= false;
899 Reference
< beans::XPropertySet
> xSeriesProp( getPropertiesOfSeries() );
900 if( xSeriesProp
.is() )
901 xSeriesProp
->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint
;
902 return bVaryColorsByPoint
;
905 uno::Reference
< beans::XPropertySet
> VDataSeries::getPropertiesOfPoint( sal_Int32 index
) const
907 if( isAttributedDataPoint( index
) )
908 return m_xDataSeries
->getDataPointByIndex(index
);
909 return getPropertiesOfSeries();
912 uno::Reference
<beans::XPropertySet
> VDataSeries::getPropertiesOfSeries() const
914 return uno::Reference
<css::beans::XPropertySet
>(m_xDataSeries
, css::uno::UNO_QUERY
);
917 static std::unique_ptr
<DataPointLabel
> getDataPointLabelFromPropertySet( const uno::Reference
< beans::XPropertySet
>& xProp
)
919 std::unique_ptr
< DataPointLabel
> apLabel( new DataPointLabel() );
922 if( !(xProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= *apLabel
) )
925 catch(const uno::Exception
&)
927 TOOLS_WARN_EXCEPTION("chart2", "" );
932 void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex
) const
934 if( m_nCurrentAttributedPoint
!= nNewPointIndex
)
936 m_apLabel_AttributedPoint
.reset();
937 m_apLabelPropNames_AttributedPoint
.reset();
938 m_apLabelPropValues_AttributedPoint
.reset();
939 m_apSymbolProperties_AttributedPoint
.reset();
940 m_nCurrentAttributedPoint
= nNewPointIndex
;
944 DataPointLabel
* VDataSeries::getDataPointLabel( sal_Int32 index
) const
946 DataPointLabel
* pRet
= nullptr;
947 if( isAttributedDataPoint( index
) )
949 adaptPointCache( index
);
950 if (!m_apLabel_AttributedPoint
)
951 m_apLabel_AttributedPoint
952 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index
));
953 pRet
= m_apLabel_AttributedPoint
.get();
957 if (!m_apLabel_Series
)
959 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index
));
960 pRet
= m_apLabel_Series
.get();
962 if( !m_bAllowPercentValueInDataLabel
)
965 pRet
->ShowNumberInPercent
= false;
970 DataPointLabel
* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index
) const
972 DataPointLabel
* pLabel
= getDataPointLabel( index
);
973 if( !pLabel
|| (!pLabel
->ShowNumber
&& !pLabel
->ShowNumberInPercent
974 && !pLabel
->ShowCategoryName
&& !pLabel
->ShowCustomLabel
&& !pLabel
->ShowSeriesName
) )
979 bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index
980 , tNameSequence
*& pPropNames
981 , tAnySequence
*& pPropValues
) const
983 pPropNames
= nullptr; pPropValues
= nullptr;
984 uno::Reference
< beans::XPropertySet
> xTextProp
;
985 bool bDoDynamicFontResize
= false;
986 if( isAttributedDataPoint( index
) )
988 adaptPointCache( index
);
989 if (!m_apLabelPropValues_AttributedPoint
)
991 // Cache these properties for this point.
992 m_apLabelPropNames_AttributedPoint
.reset(new tNameSequence
);
993 m_apLabelPropValues_AttributedPoint
.reset(new tAnySequence
);
994 xTextProp
.set( getPropertiesOfPoint( index
));
995 PropertyMapper::getTextLabelMultiPropertyLists(
996 xTextProp
, *m_apLabelPropNames_AttributedPoint
, *m_apLabelPropValues_AttributedPoint
);
997 bDoDynamicFontResize
= true;
999 pPropNames
= m_apLabelPropNames_AttributedPoint
.get();
1000 pPropValues
= m_apLabelPropValues_AttributedPoint
.get();
1004 if (!m_apLabelPropValues_Series
)
1006 // Cache these properties for the whole series.
1007 m_apLabelPropNames_Series
.reset(new tNameSequence
);
1008 m_apLabelPropValues_Series
.reset(new tAnySequence
);
1009 xTextProp
.set( getPropertiesOfPoint( index
));
1010 PropertyMapper::getTextLabelMultiPropertyLists(
1011 xTextProp
, *m_apLabelPropNames_Series
, *m_apLabelPropValues_Series
);
1012 bDoDynamicFontResize
= true;
1014 pPropNames
= m_apLabelPropNames_Series
.get();
1015 pPropValues
= m_apLabelPropValues_Series
.get();
1018 if( bDoDynamicFontResize
&&
1019 pPropNames
&& pPropValues
&&
1022 LabelPositionHelper::doDynamicFontResize( *pPropValues
, *pPropNames
, xTextProp
, m_aReferenceSize
);
1025 return (pPropNames
&& pPropValues
);
1028 void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment
)
1030 m_nMissingValueTreatment
= nMissingValueTreatment
;
1033 sal_Int32
VDataSeries::getMissingValueTreatment() const
1035 return m_nMissingValueTreatment
;
1038 VDataSeries::VDataSeries()
1039 : m_nPolygonIndex(0)
1044 , m_pValueSequenceForDataLabelNumberFormatDetection(nullptr)
1047 , m_eStackingDirection(chart2::StackingDirection_NO_STACKING
)
1049 , m_bConnectBars(false)
1050 , m_bGroupBarsPerAxis(false)
1051 , m_nStartingAngle(0)
1052 , m_nGlobalSeriesIndex(0)
1053 , m_nCurrentAttributedPoint(0)
1054 , m_nMissingValueTreatment(0)
1055 , m_bAllowPercentValueInDataLabel(false)
1056 , mpOldSeries(nullptr)
1061 void VDataSeries::setOldTimeBased( VDataSeries
* pOldSeries
, double nPercent
)
1063 mnPercent
= nPercent
;
1064 mpOldSeries
= pOldSeries
;
1065 mpOldSeries
->mpOldSeries
= nullptr;
1068 VDataSeries
* VDataSeries::createCopyForTimeBased() const
1070 VDataSeries
* pNew
= new VDataSeries();
1071 pNew
->m_aValues_X
= m_aValues_X
;
1072 pNew
->m_aValues_Y
= m_aValues_Y
;
1073 pNew
->m_aValues_Z
= m_aValues_Z
;
1074 pNew
->m_aValues_Y_Min
= m_aValues_Y_Min
;
1075 pNew
->m_aValues_Y_Max
= m_aValues_Y_Max
;
1076 pNew
->m_aValues_Y_First
= m_aValues_Y_First
;
1077 pNew
->m_aValues_Y_Last
= m_aValues_Y_Last
;
1078 pNew
->m_aValues_Bubble_Size
= m_aValues_Bubble_Size
;
1079 pNew
->m_PropertyMap
= m_PropertyMap
;
1081 pNew
->m_nPointCount
= m_nPointCount
;
1086 double VDataSeries::getValueByProperty( sal_Int32 nIndex
, const OUString
& rPropName
) const
1088 auto const itr
= m_PropertyMap
.find(rPropName
);
1089 if (itr
== m_PropertyMap
.end())
1090 return std::numeric_limits
<double>::quiet_NaN();
1092 const VDataSequence
* pData
= &itr
->second
;
1093 double fValue
= pData
->getValue(nIndex
);
1094 if(mpOldSeries
&& mpOldSeries
->hasPropertyMapping(rPropName
))
1096 double fOldValue
= mpOldSeries
->getValueByProperty( nIndex
, rPropName
);
1097 if(rPropName
.endsWith("Color"))
1099 //optimized interpolation for color values
1100 Color
aColor(ColorTransparency
, static_cast<sal_uInt32
>(fValue
));
1101 Color
aOldColor(ColorTransparency
, static_cast<sal_uInt32
>(fOldValue
));
1102 sal_uInt8 r
= aOldColor
.GetRed() + (aColor
.GetRed() - aOldColor
.GetRed()) * mnPercent
;
1103 sal_uInt8 g
= aOldColor
.GetGreen() + (aColor
.GetGreen() - aOldColor
.GetGreen()) * mnPercent
;
1104 sal_uInt8 b
= aOldColor
.GetBlue() + (aColor
.GetBlue() - aOldColor
.GetBlue()) * mnPercent
;
1105 sal_uInt8 a
= aOldColor
.GetAlpha() + (aColor
.GetAlpha() - aOldColor
.GetAlpha()) * mnPercent
;
1106 Color
aRet(ColorAlpha
, a
, r
, g
, b
);
1107 return sal_uInt32(aRet
);
1109 return fOldValue
+ (fValue
- fOldValue
) * mnPercent
;
1114 bool VDataSeries::hasPropertyMapping(const OUString
& rPropName
) const
1116 return m_PropertyMap
.find(rPropName
) != m_PropertyMap
.end();
1121 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */