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 .
20 #include "VSeriesPlotter.hxx"
21 #include "AbstractShapeFactory.hxx"
22 #include "chartview/ExplicitValueProvider.hxx"
24 #include "CommonConverters.hxx"
26 #include "ViewDefines.hxx"
27 #include "ObjectIdentifier.hxx"
28 #include "StatisticsHelper.hxx"
29 #include "PlottingPositionHelper.hxx"
30 #include "LabelPositionHelper.hxx"
31 #include "ChartTypeHelper.hxx"
32 #include "Clipping.hxx"
33 #include "servicenames_charttypes.hxx"
34 #include "NumberFormatterWrapper.hxx"
35 #include "ContainerHelper.hxx"
36 #include "DataSeriesHelper.hxx"
37 #include "RegressionCurveHelper.hxx"
38 #include "VLegendSymbolFactory.hxx"
39 #include "FormattedStringHelper.hxx"
41 #include "Strings.hrc"
42 #include "RelativePositionHelper.hxx"
43 #include "DateHelper.hxx"
44 #include "DiagramHelper.hxx"
45 #include "defines.hxx"
47 //only for creation: @todo remove if all plotter are uno components and instantiated via servicefactory
48 #include "BarChart.hxx"
49 #include "PieChart.hxx"
50 #include "AreaChart.hxx"
51 #include "CandleStickChart.hxx"
52 #include "BubbleChart.hxx"
53 #include "NetChart.hxx"
54 #include <unonames.hxx>
56 #include <com/sun/star/chart/ErrorBarStyle.hpp>
57 #include <com/sun/star/chart/TimeUnit.hpp>
58 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
59 #include <com/sun/star/container/XChild.hpp>
60 #include <com/sun/star/chart2/RelativePosition.hpp>
61 #include <editeng/unoprnms.hxx>
62 #include <tools/color.hxx>
63 #include <rtl/ustrbuf.hxx>
64 #include <rtl/math.hxx>
65 #include <basegfx/vector/b2dvector.hxx>
66 #include <com/sun/star/drawing/LineStyle.hpp>
67 #include <com/sun/star/util/XCloneable.hpp>
69 #include <svx/unoshape.hxx>
73 #include <unordered_map>
75 #include <boost/ptr_container/ptr_map.hpp>
79 using namespace ::com::sun::star
;
80 using namespace ::com::sun::star::chart2
;
81 using ::com::sun::star::uno::Reference
;
82 using ::com::sun::star::uno::Sequence
;
84 VDataSeriesGroup::CachedYValues::CachedYValues()
85 : m_bValuesDirty(true)
91 VDataSeriesGroup::VDataSeriesGroup()
93 , m_bMaxPointCountDirty(true)
95 , m_aListOfCachedYValues()
99 VDataSeriesGroup::VDataSeriesGroup( VDataSeries
* pSeries
)
100 : m_aSeriesVector(1,pSeries
)
101 , m_bMaxPointCountDirty(true)
102 , m_nMaxPointCount(0)
103 , m_aListOfCachedYValues()
107 VDataSeriesGroup::~VDataSeriesGroup()
111 void VDataSeriesGroup::deleteSeries()
113 //delete all data series help objects:
114 ::std::vector
< VDataSeries
* >::const_iterator aIter
= m_aSeriesVector
.begin();
115 const ::std::vector
< VDataSeries
* >::const_iterator aEnd
= m_aSeriesVector
.end();
116 for( ; aIter
!= aEnd
; ++aIter
)
120 m_aSeriesVector
.clear();
123 void VDataSeriesGroup::addSeries( VDataSeries
* pSeries
)
125 m_aSeriesVector
.push_back(pSeries
);
126 m_bMaxPointCountDirty
=true;
129 sal_Int32
VDataSeriesGroup::getSeriesCount() const
131 return m_aSeriesVector
.size();
134 VSeriesPlotter::VSeriesPlotter( const uno::Reference
<XChartType
>& xChartTypeModel
135 , sal_Int32 nDimensionCount
, bool bCategoryXAxis
)
136 : PlotterBase( nDimensionCount
)
137 , m_pMainPosHelper( 0 )
138 , m_xChartTypeModel(xChartTypeModel
)
139 , m_xChartTypeModelProps( uno::Reference
< beans::XPropertySet
>::query( xChartTypeModel
))
141 , m_bCategoryXAxis(bCategoryXAxis
)
142 , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY
)
143 , m_aNullDate(30,12,1899)
145 , m_pExplicitCategoriesProvider(0)
146 , m_bPointsWereSkipped(false)
148 SAL_WARN_IF(!m_xChartTypeModel
.is(),"chart2","no XChartType available in view, fallback to default values may be wrong");
151 VSeriesPlotter::~VSeriesPlotter()
153 //delete all data series help objects:
154 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
155 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
156 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
158 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
159 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
160 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
162 aXSlotIter
->deleteSeries();
168 tSecondaryPosHelperMap::iterator aPosIt
= m_aSecondaryPosHelperMap
.begin();
169 while( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
171 PlottingPositionHelper
* pPosHelper
= aPosIt
->second
;
176 m_aSecondaryPosHelperMap
.clear();
178 m_aSecondaryValueScales
.clear();
181 void VSeriesPlotter::addSeries( VDataSeries
* pSeries
, sal_Int32 zSlot
, sal_Int32 xSlot
, sal_Int32 ySlot
)
183 //take ownership of pSeries
185 OSL_PRECOND( pSeries
, "series to add is NULL" );
191 if( m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->isDateAxis() )
192 pSeries
->setXValues( m_pExplicitCategoriesProvider
->getOriginalCategories() );
194 pSeries
->setCategoryXAxis();
198 if( m_pExplicitCategoriesProvider
)
199 pSeries
->setXValuesIfNone( m_pExplicitCategoriesProvider
->getOriginalCategories() );
202 if(zSlot
<0 || zSlot
>=static_cast<sal_Int32
>(m_aZSlots
.size()))
205 ::std::vector
< VDataSeriesGroup
> aZSlot
;
206 aZSlot
.push_back( VDataSeriesGroup(pSeries
) );
207 m_aZSlots
.push_back( aZSlot
);
212 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[zSlot
];
214 if(xSlot
<0 || xSlot
>=static_cast<sal_Int32
>(rXSlots
.size()))
216 //append the series to already existing x series
217 rXSlots
.push_back( VDataSeriesGroup(pSeries
) );
221 //x slot is already occupied
222 //y slot decides what to do:
224 VDataSeriesGroup
& rYSlots
= rXSlots
[xSlot
];
225 sal_Int32 nYSlotCount
= rYSlots
.getSeriesCount();
229 //move all existing series in the xSlot to next slot
231 OSL_FAIL( "Not implemented yet");
233 else if( ySlot
== -1 || ySlot
>= nYSlotCount
)
235 //append the series to already existing y series
236 rYSlots
.addSeries(pSeries
);
240 //y slot is already occupied
241 //insert at given y and x position
244 OSL_FAIL( "Not implemented yet");
250 drawing::Direction3D
VSeriesPlotter::getPreferredDiagramAspectRatio() const
252 drawing::Direction3D
aRet(1.0,1.0,1.0);
256 drawing::Direction3D
aScale( m_pPosHelper
->getScaledLogicWidth() );
257 aRet
.DirectionZ
= aScale
.DirectionZ
*0.2;
258 if(aRet
.DirectionZ
>1.0)
260 if(aRet
.DirectionZ
>10)
265 bool VSeriesPlotter::keepAspectRatio() const
270 void VSeriesPlotter::releaseShapes()
272 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
273 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
274 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
276 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
277 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
278 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
280 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
282 ::std::vector
< VDataSeries
* >::iterator aSeriesIter
= pSeriesList
->begin();
283 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
285 //iterate through all series in this x slot
286 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
288 VDataSeries
* pSeries( *aSeriesIter
);
289 pSeries
->releaseShapes();
295 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShape( VDataSeries
* pDataSeries
296 , const uno::Reference
< drawing::XShapes
>& xTarget
)
298 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xGroupShape
);
301 //create a group shape for this series and add to logic target:
302 xShapes
= createGroupShape( xTarget
,pDataSeries
->getCID() );
303 pDataSeries
->m_xGroupShape
= xShapes
;
308 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries
* pDataSeries
309 , const uno::Reference
< drawing::XShapes
>& xTarget
)
311 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xFrontSubGroupShape
);
314 //ensure that the series group shape is already created
315 uno::Reference
< drawing::XShapes
> xSeriesShapes( this->getSeriesGroupShape( pDataSeries
, xTarget
) );
316 //ensure that the back child is created first
317 this->getSeriesGroupShapeBackChild( pDataSeries
, xTarget
);
318 //use series group shape as parent for the new created front group shape
319 xShapes
= createGroupShape( xSeriesShapes
);
320 pDataSeries
->m_xFrontSubGroupShape
= xShapes
;
325 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries
* pDataSeries
326 , const uno::Reference
< drawing::XShapes
>& xTarget
)
328 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xBackSubGroupShape
);
331 //ensure that the series group shape is already created
332 uno::Reference
< drawing::XShapes
> xSeriesShapes( this->getSeriesGroupShape( pDataSeries
, xTarget
) );
333 //use series group shape as parent for the new created back group shape
334 xShapes
= createGroupShape( xSeriesShapes
);
335 pDataSeries
->m_xBackSubGroupShape
= xShapes
;
340 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getLabelsGroupShape( VDataSeries
& rDataSeries
341 , const uno::Reference
< drawing::XShapes
>& xTextTarget
)
343 //xTextTarget needs to be a 2D shape container always!
345 uno::Reference
< drawing::XShapes
> xShapes( rDataSeries
.m_xLabelsGroupShape
);
348 //create a 2D group shape for texts of this series and add to text target:
349 xShapes
= m_pShapeFactory
->createGroup2D( xTextTarget
, rDataSeries
.getLabelsCID() );
350 rDataSeries
.m_xLabelsGroupShape
= xShapes
;
355 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getErrorBarsGroupShape( VDataSeries
& rDataSeries
356 , const uno::Reference
< drawing::XShapes
>& xTarget
359 uno::Reference
< ::com::sun::star::drawing::XShapes
> &rShapeGroup
=
360 bYError
? rDataSeries
.m_xErrorYBarsGroupShape
: rDataSeries
.m_xErrorXBarsGroupShape
;
362 uno::Reference
< drawing::XShapes
> xShapes( rShapeGroup
);
365 //create a group shape for this series and add to logic target:
366 xShapes
= this->createGroupShape( xTarget
,rDataSeries
.getErrorBarsCID(bYError
) );
367 rShapeGroup
= xShapes
;
373 OUString
VSeriesPlotter::getLabelTextForValue( VDataSeries
& rDataSeries
374 , sal_Int32 nPointIndex
376 , bool bAsPercentage
)
380 if( m_apNumberFormatterWrapper
.get())
382 sal_Int32 nNumberFormatKey
= 0;
383 if( rDataSeries
.hasExplicitNumberFormat(nPointIndex
,bAsPercentage
) )
384 nNumberFormatKey
= rDataSeries
.getExplicitNumberFormat(nPointIndex
,bAsPercentage
);
385 else if( bAsPercentage
)
387 sal_Int32 nPercentFormat
= DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper
->getNumberFormatsSupplier() );
388 if( nPercentFormat
!= -1 )
389 nNumberFormatKey
= nPercentFormat
;
393 if( rDataSeries
.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats
.hasFormat(1,rDataSeries
.getAttachedAxisIndex()) ) //y-axis
394 nNumberFormatKey
= m_aAxesNumberFormats
.getFormat(1,rDataSeries
.getAttachedAxisIndex());
396 nNumberFormatKey
= rDataSeries
.detectNumberFormatKey( nPointIndex
);
398 if(nNumberFormatKey
<0)
401 sal_Int32 nLabelCol
= 0;
403 aNumber
= m_apNumberFormatterWrapper
->getFormattedString(
404 nNumberFormatKey
, fValue
, nLabelCol
, bColChanged
);
405 //@todo: change color of label if bColChanged is true
409 sal_Unicode cDecSeparator
= '.';//@todo get this locale dependent
410 aNumber
= ::rtl::math::doubleToUString( fValue
, rtl_math_StringFormat_G
/*rtl_math_StringFormat*/
411 , 3/*DecPlaces*/ , cDecSeparator
, false /*bEraseTrailingDecZeros*/ );
416 uno::Reference
< drawing::XShape
> VSeriesPlotter::createDataLabel( const uno::Reference
< drawing::XShapes
>& xTarget
417 , VDataSeries
& rDataSeries
418 , sal_Int32 nPointIndex
421 , const awt::Point
& rScreenPosition2D
422 , LabelAlignment eAlignment
423 , sal_Int32 nOffset
)
425 uno::Reference
< drawing::XShape
> xTextShape
;
429 awt::Point
aScreenPosition2D(rScreenPosition2D
);
430 if(LABEL_ALIGN_LEFT
==eAlignment
)
431 aScreenPosition2D
.X
-= nOffset
;
432 else if(LABEL_ALIGN_RIGHT
==eAlignment
)
433 aScreenPosition2D
.X
+= nOffset
;
434 else if(LABEL_ALIGN_TOP
==eAlignment
)
435 aScreenPosition2D
.Y
-= nOffset
;
436 else if(LABEL_ALIGN_BOTTOM
==eAlignment
)
437 aScreenPosition2D
.Y
+= nOffset
;
439 uno::Reference
< drawing::XShapes
> xTarget_
=
440 m_pShapeFactory
->createGroup2D(
441 getLabelsGroupShape(rDataSeries
, xTarget
),
442 ObjectIdentifier::createPointCID( rDataSeries
.getLabelCID_Stub(), nPointIndex
));
444 //check whether the label needs to be created and how:
445 DataPointLabel
* pLabel
= rDataSeries
.getDataPointLabelIfLabel( nPointIndex
);
450 //prepare legend symbol
452 // get the font size for the label through the "CharHeight" property
453 // attached to the passed data series entry.
454 // (By tracing font height values it results that for pie chart the
455 // font size is not the same for all labels, but here no font size
456 // modification occurs).
457 float fViewFontSize( 10.0 );
459 uno::Reference
< beans::XPropertySet
> xProps( rDataSeries
.getPropertiesOfPoint( nPointIndex
) );
461 xProps
->getPropertyValue( "CharHeight") >>= fViewFontSize
;
463 fViewFontSize
*= (2540.0f
/ 72.0f
);
466 // the font height is used for computing the size of an optional legend
467 // symbol to be prepended to the text label.
468 Reference
< drawing::XShape
> xSymbol
;
469 if(pLabel
->ShowLegendSymbol
)
471 sal_Int32 nSymbolHeight
= static_cast< sal_Int32
>( fViewFontSize
* 0.6 );
472 awt::Size aCurrentRatio
= getPreferredLegendKeyAspectRatio();
473 sal_Int32 nSymbolWidth
= aCurrentRatio
.Width
;
474 if( aCurrentRatio
.Height
> 0 )
476 nSymbolWidth
= nSymbolHeight
* aCurrentRatio
.Width
/aCurrentRatio
.Height
;
478 awt::Size
aMaxSymbolExtent( nSymbolWidth
, nSymbolHeight
);
480 if( rDataSeries
.isVaryColorsByPoint() )
481 xSymbol
.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent
, rDataSeries
, nPointIndex
, xTarget_
, m_xShapeFactory
) );
483 xSymbol
.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent
, rDataSeries
, xTarget_
, m_xShapeFactory
) );
487 OUStringBuffer aText
;
488 OUString
aSeparator(" ");
489 double fRotationDegrees
= 0.0;
492 uno::Reference
< beans::XPropertySet
> xPointProps( rDataSeries
.getPropertiesOfPoint( nPointIndex
) );
495 xPointProps
->getPropertyValue( "LabelSeparator" ) >>= aSeparator
;
496 // Extract the optional text rotation through the
497 // "TextRotation" property attached to the passed data point.
498 xPointProps
->getPropertyValue( "TextRotation" ) >>= fRotationDegrees
;
501 catch( const uno::Exception
& e
)
503 ASSERT_EXCEPTION( e
);
506 // check if data series entry percent value and absolute value have to
507 // be appended to the text label, and what should be the separator
508 // character (comma, space, new line). In case it is a new line we get
509 // a multi-line label.
510 bool bMultiLineLabel
= aSeparator
== "\n";
511 sal_Int32 nLineCountForSymbolsize
= 0;
513 if(pLabel
->ShowCategoryName
)
515 if( m_pExplicitCategoriesProvider
)
517 Sequence
< OUString
> aCategories( m_pExplicitCategoriesProvider
->getSimpleCategories() );
518 if( nPointIndex
>= 0 && nPointIndex
< aCategories
.getLength() )
520 aText
.append( aCategories
[nPointIndex
] );
521 ++nLineCountForSymbolsize
;
526 if(pLabel
->ShowNumber
)
528 OUString aNumber
= getLabelTextForValue(rDataSeries
, nPointIndex
, fValue
, false);
529 if( !aNumber
.isEmpty() )
532 aText
.append(aSeparator
);
533 aText
.append(aNumber
);
534 ++nLineCountForSymbolsize
;
538 if(pLabel
->ShowNumberInPercent
)
546 OUString aPercentage
= getLabelTextForValue(rDataSeries
, nPointIndex
, fValue
, true);
547 if( !aPercentage
.isEmpty() )
550 aText
.append(aSeparator
);
551 aText
.append(aPercentage
);
552 ++nLineCountForSymbolsize
;
556 //prepare properties for multipropertyset-interface of shape
557 tNameSequence
* pPropNames
;
558 tAnySequence
* pPropValues
;
559 if( !rDataSeries
.getTextLabelMultiPropertyLists( nPointIndex
, pPropNames
, pPropValues
) )
562 // set text alignment for the text shape to be created.
563 LabelPositionHelper::changeTextAdjustment( *pPropValues
, *pPropNames
, eAlignment
);
566 xTextShape
= AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory
)->
567 createText( xTarget_
, aText
.makeStringAndClear()
568 , *pPropNames
, *pPropValues
, AbstractShapeFactory::makeTransformation( aScreenPosition2D
) );
570 if( !xTextShape
.is() )
573 // in case text is rotated, the transformation property of the text
574 // shape is modified.
575 const awt::Point
aUnrotatedTextPos( xTextShape
->getPosition() );
576 if( fRotationDegrees
!= 0.0 )
578 const double fDegreesPi( fRotationDegrees
* ( F_PI
/ -180.0 ) );
579 uno::Reference
< beans::XPropertySet
> xProp( xTextShape
, uno::UNO_QUERY
);
581 xProp
->setPropertyValue( "Transformation", AbstractShapeFactory::makeTransformation( aScreenPosition2D
, fDegreesPi
) );
582 LabelPositionHelper::correctPositionForRotation( xTextShape
, eAlignment
, fRotationDegrees
, true /*bRotateAroundCenter*/ );
585 // in case legend symbol has to be displayed, text shape position is
589 const awt::Point
aOldTextPos( xTextShape
->getPosition() );
590 awt::Point
aNewTextPos( aOldTextPos
);
592 awt::Point
aSymbolPosition( aUnrotatedTextPos
);
593 awt::Size
aSymbolSize( xSymbol
->getSize() );
594 awt::Size
aTextSize( xTextShape
->getSize() );
596 sal_Int32 nXDiff
= aSymbolSize
.Width
+ static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize
* 0.22 ) );//minimum 1mm
597 if( !bMultiLineLabel
|| nLineCountForSymbolsize
<= 0 )
598 nLineCountForSymbolsize
= 1;
599 aSymbolPosition
.Y
+= ((aTextSize
.Height
/nLineCountForSymbolsize
)/4);
601 if(LABEL_ALIGN_LEFT
==eAlignment
602 || LABEL_ALIGN_LEFT_TOP
==eAlignment
603 || LABEL_ALIGN_LEFT_BOTTOM
==eAlignment
)
605 aSymbolPosition
.X
-= nXDiff
;
607 else if(LABEL_ALIGN_RIGHT
==eAlignment
608 || LABEL_ALIGN_RIGHT_TOP
==eAlignment
609 || LABEL_ALIGN_RIGHT_BOTTOM
==eAlignment
)
611 aNewTextPos
.X
+= nXDiff
;
613 else if(LABEL_ALIGN_TOP
==eAlignment
614 || LABEL_ALIGN_BOTTOM
==eAlignment
615 || LABEL_ALIGN_CENTER
==eAlignment
)
617 aSymbolPosition
.X
-= nXDiff
/2;
618 aNewTextPos
.X
+= nXDiff
/2;
621 xSymbol
->setPosition( aSymbolPosition
);
622 xTextShape
->setPosition( aNewTextPos
);
625 catch( const uno::Exception
& e
)
627 ASSERT_EXCEPTION( e
);
635 double lcl_getErrorBarLogicLength(
636 const uno::Sequence
< double > & rData
,
637 uno::Reference
< beans::XPropertySet
> xProp
,
638 sal_Int32 nErrorBarStyle
,
644 ::rtl::math::setNan( & fResult
);
647 switch( nErrorBarStyle
)
649 case ::com::sun::star::chart::ErrorBarStyle::NONE
:
651 case ::com::sun::star::chart::ErrorBarStyle::VARIANCE
:
652 fResult
= StatisticsHelper::getVariance( rData
);
654 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION
:
655 fResult
= StatisticsHelper::getStandardDeviation( rData
);
657 case ::com::sun::star::chart::ErrorBarStyle::RELATIVE
:
660 if( xProp
->getPropertyValue( bPositive
661 ? OUString("PositiveError")
662 : OUString("NegativeError") ) >>= fPercent
)
664 if( nIndex
>=0 && nIndex
< rData
.getLength() &&
665 ! ::rtl::math::isNan( rData
[nIndex
] ) &&
666 ! ::rtl::math::isNan( fPercent
))
668 fResult
= rData
[nIndex
] * fPercent
/ 100.0;
673 case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE
:
674 xProp
->getPropertyValue( bPositive
675 ? OUString("PositiveError")
676 : OUString("NegativeError") ) >>= fResult
;
678 case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN
:
680 // todo: check if this is really what's called error-margin
682 if( xProp
->getPropertyValue( bPositive
683 ? OUString("PositiveError")
684 : OUString("NegativeError") ) >>= fPercent
)
687 ::rtl::math::setInf(&fMaxValue
, true);
688 const double* pValues
= rData
.getConstArray();
689 for(sal_Int32 i
=0; i
<rData
.getLength(); ++i
, ++pValues
)
691 if(fMaxValue
<*pValues
)
694 if( ::rtl::math::isFinite( fMaxValue
) &&
695 ::rtl::math::isFinite( fPercent
))
697 fResult
= fMaxValue
* fPercent
/ 100.0;
702 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR
:
703 fResult
= StatisticsHelper::getStandardError( rData
);
705 case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA
:
707 uno::Reference
< chart2::data::XDataSource
> xErrorBarData( xProp
, uno::UNO_QUERY
);
708 if( xErrorBarData
.is())
709 fResult
= StatisticsHelper::getErrorFromDataSource(
710 xErrorBarData
, nIndex
, bPositive
, bYError
);
715 catch( const uno::Exception
& e
)
717 ASSERT_EXCEPTION( e
);
723 void lcl_AddErrorBottomLine( const drawing::Position3D
& rPosition
, ::basegfx::B2DVector aMainDirection
724 , drawing::PolyPolygonShape3D
& rPoly
, sal_Int32 nSequenceIndex
)
726 double fFixedWidth
= 200.0;
728 aMainDirection
.normalize();
729 ::basegfx::B2DVector
aOrthoDirection(-aMainDirection
.getY(),aMainDirection
.getX());
730 aOrthoDirection
.normalize();
732 ::basegfx::B2DVector
aAnchor( rPosition
.PositionX
, rPosition
.PositionY
);
733 ::basegfx::B2DVector aStart
= aAnchor
+ aOrthoDirection
*fFixedWidth
/2.0;
734 ::basegfx::B2DVector aEnd
= aAnchor
- aOrthoDirection
*fFixedWidth
/2.0;
736 AddPointToPoly( rPoly
, drawing::Position3D( aStart
.getX(), aStart
.getY(), rPosition
.PositionZ
), nSequenceIndex
);
737 AddPointToPoly( rPoly
, drawing::Position3D( aEnd
.getX(), aEnd
.getY(), rPosition
.PositionZ
), nSequenceIndex
);
740 ::basegfx::B2DVector
lcl_getErrorBarMainDirection(
741 const drawing::Position3D
& rStart
742 , const drawing::Position3D
& rBottomEnd
743 , PlottingPositionHelper
* pPosHelper
744 , const drawing::Position3D
& rUnscaledLogicPosition
747 ::basegfx::B2DVector aMainDirection
= ::basegfx::B2DVector( rStart
.PositionX
- rBottomEnd
.PositionX
748 , rStart
.PositionY
- rBottomEnd
.PositionY
);
749 if( !aMainDirection
.getLength() )
751 //get logic clip values:
752 double MinX
= pPosHelper
->getLogicMinX();
753 double MinY
= pPosHelper
->getLogicMinY();
754 double MaxX
= pPosHelper
->getLogicMaxX();
755 double MaxY
= pPosHelper
->getLogicMaxY();
756 double fZ
= pPosHelper
->getLogicMinZ();
760 //main direction has constant x value
761 MinX
= rUnscaledLogicPosition
.PositionX
;
762 MaxX
= rUnscaledLogicPosition
.PositionX
;
766 //main direction has constant y value
767 MinY
= rUnscaledLogicPosition
.PositionY
;
768 MaxY
= rUnscaledLogicPosition
.PositionY
;
771 drawing::Position3D aStart
= pPosHelper
->transformLogicToScene( MinX
, MinY
, fZ
, false );
772 drawing::Position3D aEnd
= pPosHelper
->transformLogicToScene( MaxX
, MaxY
, fZ
, false );
774 aMainDirection
= ::basegfx::B2DVector( aStart
.PositionX
- aEnd
.PositionX
775 , aStart
.PositionY
- aEnd
.PositionY
);
777 if( !aMainDirection
.getLength() )
781 return aMainDirection
;
784 drawing::Position3D
lcl_transformMixedToScene( PlottingPositionHelper
* pPosHelper
785 , double fX
/*scaled*/, double fY
/*unscaled*/, double fZ
/*unscaled*/, bool bClip
)
788 return drawing::Position3D(0,0,0);
789 pPosHelper
->doLogicScaling( 0,&fY
,&fZ
);
791 pPosHelper
->clipScaledLogicValues( &fX
,&fY
,&fZ
);
792 return pPosHelper
->transformScaledLogicToScene( fX
, fY
, fZ
, false );
795 } // anonymous namespace
797 void VSeriesPlotter::createErrorBar(
798 const uno::Reference
< drawing::XShapes
>& xTarget
799 , const drawing::Position3D
& rUnscaledLogicPosition
800 , const uno::Reference
< beans::XPropertySet
> & xErrorBarProperties
801 , const VDataSeries
& rVDataSeries
803 , bool bYError
/* = true */
804 , double* pfScaledLogicX
807 if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel
, m_nDimension
) )
810 if( ! xErrorBarProperties
.is())
815 bool bShowPositive
= false;
816 bool bShowNegative
= false;
817 sal_Int32 nErrorBarStyle
= ::com::sun::star::chart::ErrorBarStyle::VARIANCE
;
819 xErrorBarProperties
->getPropertyValue( "ShowPositiveError") >>= bShowPositive
;
820 xErrorBarProperties
->getPropertyValue( "ShowNegativeError") >>= bShowNegative
;
821 xErrorBarProperties
->getPropertyValue( "ErrorBarStyle") >>= nErrorBarStyle
;
823 if(!bShowPositive
&& !bShowNegative
)
826 if(nErrorBarStyle
==::com::sun::star::chart::ErrorBarStyle::NONE
)
832 drawing::Position3D
aUnscaledLogicPosition(rUnscaledLogicPosition
);
833 if(nErrorBarStyle
==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION
)
836 aUnscaledLogicPosition
.PositionY
= rVDataSeries
.getYMeanValue();
838 aUnscaledLogicPosition
.PositionX
= rVDataSeries
.getXMeanValue();
841 bool bCreateNegativeBorder
= false;//make a vertical line at the negative end of the error bar
842 bool bCreatePositiveBorder
= false;//make a vertical line at the positive end of the error bar
843 drawing::Position3D
aMiddle(aUnscaledLogicPosition
);
844 const double fX
= aUnscaledLogicPosition
.PositionX
;
845 const double fY
= aUnscaledLogicPosition
.PositionY
;
846 const double fZ
= aUnscaledLogicPosition
.PositionZ
;
847 double fScaledX
= fX
;
849 fScaledX
= *pfScaledLogicX
;
851 m_pPosHelper
->doLogicScaling( &fScaledX
, 0, 0 );
853 aMiddle
= lcl_transformMixedToScene( m_pPosHelper
, fScaledX
, fY
, fZ
, true );
855 drawing::Position3D
aNegative(aMiddle
);
856 drawing::Position3D
aPositive(aMiddle
);
858 uno::Sequence
< double > aData( bYError
? rVDataSeries
.getAllY() : rVDataSeries
.getAllX() );
862 double fLength
= lcl_getErrorBarLogicLength( aData
, xErrorBarProperties
, nErrorBarStyle
, nIndex
, true, bYError
);
863 if( ::rtl::math::isFinite( fLength
) )
870 aPositive
= lcl_transformMixedToScene( m_pPosHelper
, fScaledX
, fLocalY
, fZ
, true );
875 aPositive
= m_pPosHelper
->transformLogicToScene( fLocalX
, fLocalY
, fZ
, true );
877 bCreatePositiveBorder
= m_pPosHelper
->isLogicVisible(fLocalX
, fLocalY
, fZ
);
880 bShowPositive
= false;
885 double fLength
= lcl_getErrorBarLogicLength( aData
, xErrorBarProperties
, nErrorBarStyle
, nIndex
, false, bYError
);
886 if( ::rtl::math::isFinite( fLength
) )
893 aNegative
= lcl_transformMixedToScene( m_pPosHelper
, fScaledX
, fLocalY
, fZ
, true );
898 aNegative
= m_pPosHelper
->transformLogicToScene( fLocalX
, fLocalY
, fZ
, true );
900 bCreateNegativeBorder
= m_pPosHelper
->isLogicVisible( fLocalX
, fLocalY
, fZ
);
903 bShowNegative
= false;
906 if(!bShowPositive
&& !bShowNegative
)
909 drawing::PolyPolygonShape3D aPoly
;
911 sal_Int32 nSequenceIndex
=0;
913 AddPointToPoly( aPoly
, aNegative
, nSequenceIndex
);
914 AddPointToPoly( aPoly
, aMiddle
, nSequenceIndex
);
916 AddPointToPoly( aPoly
, aPositive
, nSequenceIndex
);
918 if( bShowNegative
&& bCreateNegativeBorder
)
920 ::basegfx::B2DVector aMainDirection
= lcl_getErrorBarMainDirection( aMiddle
, aNegative
, m_pPosHelper
, aUnscaledLogicPosition
, bYError
);
922 lcl_AddErrorBottomLine( aNegative
, aMainDirection
, aPoly
, nSequenceIndex
);
924 if( bShowPositive
&& bCreatePositiveBorder
)
926 ::basegfx::B2DVector aMainDirection
= lcl_getErrorBarMainDirection( aMiddle
, aPositive
, m_pPosHelper
, aUnscaledLogicPosition
, bYError
);
928 lcl_AddErrorBottomLine( aPositive
, aMainDirection
, aPoly
, nSequenceIndex
);
931 uno::Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D( xTarget
, PolyToPointSequence( aPoly
) );
932 setMappedProperties( xShape
, xErrorBarProperties
, PropertyMapper::getPropertyNameMapForLineProperties() );
934 catch( const uno::Exception
& e
)
936 ASSERT_EXCEPTION( e
);
941 void VSeriesPlotter::createErrorBar_X( const drawing::Position3D
& rUnscaledLogicPosition
942 , VDataSeries
& rVDataSeries
, sal_Int32 nPointIndex
943 , const uno::Reference
< drawing::XShapes
>& xTarget
944 , double* pfScaledLogicX
)
949 uno::Reference
< beans::XPropertySet
> xErrorBarProp(rVDataSeries
.getXErrorBarProperties(nPointIndex
));
950 if( xErrorBarProp
.is())
952 uno::Reference
< drawing::XShapes
> xErrorBarsGroup_Shapes(
953 this->getErrorBarsGroupShape(rVDataSeries
, xTarget
, false) );
955 createErrorBar( xErrorBarsGroup_Shapes
956 , rUnscaledLogicPosition
, xErrorBarProp
957 , rVDataSeries
, nPointIndex
958 , false /* bYError */
963 void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D
& rUnscaledLogicPosition
964 , VDataSeries
& rVDataSeries
, sal_Int32 nPointIndex
965 , const uno::Reference
< drawing::XShapes
>& xTarget
966 , double* pfScaledLogicX
)
971 uno::Reference
< beans::XPropertySet
> xErrorBarProp(rVDataSeries
.getYErrorBarProperties(nPointIndex
));
972 if( xErrorBarProp
.is())
974 uno::Reference
< drawing::XShapes
> xErrorBarsGroup_Shapes(
975 this->getErrorBarsGroupShape(rVDataSeries
, xTarget
, true) );
977 createErrorBar( xErrorBarsGroup_Shapes
978 , rUnscaledLogicPosition
, xErrorBarProp
979 , rVDataSeries
, nPointIndex
985 void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries
& rVDataSeries
,
986 const uno::Reference
< drawing::XShapes
>& xTarget
,
987 const uno::Reference
< drawing::XShapes
>& xEquationTarget
,
988 bool bMaySkipPoints
)
992 uno::Reference
< XRegressionCurveContainer
> xContainer( rVDataSeries
.getModel(), uno::UNO_QUERY
);
999 uno::Sequence
< uno::Reference
< XRegressionCurve
> > aCurveList
= xContainer
->getRegressionCurves();
1001 for(sal_Int32 nN
=0; nN
<aCurveList
.getLength(); nN
++)
1003 uno::Reference
< XRegressionCurveCalculator
> xCalculator( aCurveList
[nN
]->getCalculator() );
1004 if( !xCalculator
.is())
1007 uno::Reference
< beans::XPropertySet
> xProperties( aCurveList
[nN
], uno::UNO_QUERY
);
1009 bool bAverageLine
= RegressionCurveHelper::isMeanValueLine( aCurveList
[nN
] );
1011 sal_Int32 aDegree
= 2;
1012 sal_Int32 aPeriod
= 2;
1013 double aExtrapolateForward
= 0.0;
1014 double aExtrapolateBackward
= 0.0;
1015 bool aForceIntercept
= false;
1016 double aInterceptValue
= 0.0;
1018 if ( xProperties
.is() && !bAverageLine
)
1020 xProperties
->getPropertyValue( "PolynomialDegree") >>= aDegree
;
1021 xProperties
->getPropertyValue( "MovingAveragePeriod") >>= aPeriod
;
1022 xProperties
->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward
;
1023 xProperties
->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward
;
1024 xProperties
->getPropertyValue( "ForceIntercept") >>= aForceIntercept
;
1025 if (aForceIntercept
)
1026 xProperties
->getPropertyValue( "InterceptValue") >>= aInterceptValue
;
1029 double fChartMinX
= m_pPosHelper
->getLogicMinX();
1030 double fChartMaxX
= m_pPosHelper
->getLogicMaxX();
1032 double fMinX
= fChartMinX
;
1033 double fMaxX
= fChartMaxX
;
1035 double fPointScale
= 1.0;
1039 rVDataSeries
.getMinMaxXValue(fMinX
, fMaxX
);
1040 fMaxX
+= aExtrapolateForward
;
1041 fMinX
-= aExtrapolateBackward
;
1043 fPointScale
= (fMaxX
- fMinX
) / (fChartMaxX
- fChartMinX
);
1046 xCalculator
->setRegressionProperties(aDegree
, aForceIntercept
, aInterceptValue
, aPeriod
);
1047 xCalculator
->recalculateRegression( rVDataSeries
.getAllX(), rVDataSeries
.getAllY() );
1048 sal_Int32 nPointCount
= 100 * fPointScale
;
1050 if ( nPointCount
< 2 )
1053 std::vector
< ExplicitScaleData
> aScales( m_pPosHelper
->getScales());
1054 uno::Reference
< chart2::XScaling
> xScalingX
;
1055 uno::Reference
< chart2::XScaling
> xScalingY
;
1056 if( aScales
.size() >= 2 )
1058 xScalingX
.set( aScales
[0].Scaling
);
1059 xScalingY
.set( aScales
[1].Scaling
);
1062 uno::Sequence
< geometry::RealPoint2D
> aCalculatedPoints(
1063 xCalculator
->getCurveValues(
1064 fMinX
, fMaxX
, nPointCount
,
1065 xScalingX
, xScalingY
, bMaySkipPoints
));
1067 nPointCount
= aCalculatedPoints
.getLength();
1069 drawing::PolyPolygonShape3D aRegressionPoly
;
1070 aRegressionPoly
.SequenceX
.realloc(1);
1071 aRegressionPoly
.SequenceY
.realloc(1);
1072 aRegressionPoly
.SequenceZ
.realloc(1);
1073 aRegressionPoly
.SequenceX
[0].realloc(nPointCount
);
1074 aRegressionPoly
.SequenceY
[0].realloc(nPointCount
);
1075 aRegressionPoly
.SequenceZ
[0].realloc(nPointCount
);
1077 sal_Int32 nRealPointCount
= 0;
1079 for(sal_Int32 nP
= 0; nP
< aCalculatedPoints
.getLength(); ++nP
)
1081 double fLogicX
= aCalculatedPoints
[nP
].X
;
1082 double fLogicY
= aCalculatedPoints
[nP
].Y
;
1083 double fLogicZ
= 0.0; //dummy
1085 // fdo#51656: don't scale mean value lines
1087 m_pPosHelper
->doLogicScaling( &fLogicX
, &fLogicY
, &fLogicZ
);
1089 if(!rtl::math::isNan(fLogicX
) && !rtl::math::isInf(fLogicX
) &&
1090 !rtl::math::isNan(fLogicY
) && !rtl::math::isInf(fLogicY
) &&
1091 !rtl::math::isNan(fLogicZ
) && !rtl::math::isInf(fLogicZ
) )
1093 aRegressionPoly
.SequenceX
[0][nRealPointCount
] = fLogicX
;
1094 aRegressionPoly
.SequenceY
[0][nRealPointCount
] = fLogicY
;
1098 aRegressionPoly
.SequenceX
[0].realloc(nRealPointCount
);
1099 aRegressionPoly
.SequenceY
[0].realloc(nRealPointCount
);
1100 aRegressionPoly
.SequenceZ
[0].realloc(nRealPointCount
);
1102 drawing::PolyPolygonShape3D aClippedPoly
;
1103 Clipping::clipPolygonAtRectangle( aRegressionPoly
, m_pPosHelper
->getScaledLogicClipDoubleRect(), aClippedPoly
);
1104 aRegressionPoly
= aClippedPoly
;
1105 m_pPosHelper
->transformScaledLogicToScene( aRegressionPoly
);
1107 awt::Point aDefaultPos
;
1108 if( aRegressionPoly
.SequenceX
.getLength() && aRegressionPoly
.SequenceX
[0].getLength() )
1110 VLineProperties aVLineProperties
;
1111 aVLineProperties
.initFromPropertySet( xProperties
);
1113 //create an extra group shape for each curve for selection handling
1114 uno::Reference
< drawing::XShapes
> xRegressionGroupShapes
=
1115 createGroupShape( xTarget
, rVDataSeries
.getDataCurveCID( nN
, bAverageLine
) );
1116 uno::Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D(
1117 xRegressionGroupShapes
, PolyToPointSequence( aRegressionPoly
), &aVLineProperties
);
1118 AbstractShapeFactory::setShapeName( xShape
, "MarkHandles" );
1119 aDefaultPos
= xShape
->getPosition();
1122 // curve equation and correlation coefficient
1123 uno::Reference
< beans::XPropertySet
> xEquationProperties( aCurveList
[nN
]->getEquationProperties());
1124 if( xEquationProperties
.is())
1126 createRegressionCurveEquationShapes(
1127 rVDataSeries
.getDataCurveEquationCID( nN
),
1128 xEquationProperties
, xEquationTarget
, xCalculator
,
1134 void VSeriesPlotter::createRegressionCurveEquationShapes(
1135 const OUString
& rEquationCID
,
1136 const uno::Reference
< beans::XPropertySet
> & xEquationProperties
,
1137 const uno::Reference
< drawing::XShapes
>& xEquationTarget
,
1138 const uno::Reference
< chart2::XRegressionCurveCalculator
> & xRegressionCurveCalculator
,
1139 awt::Point aDefaultPos
)
1141 OSL_ASSERT( xEquationProperties
.is());
1142 if( !xEquationProperties
.is())
1145 bool bShowEquation
= false;
1146 bool bShowCorrCoeff
= false;
1147 OUString
aSep( "\n" );
1148 if(( xEquationProperties
->getPropertyValue( "ShowEquation") >>= bShowEquation
) &&
1149 ( xEquationProperties
->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCorrCoeff
))
1151 if( ! (bShowEquation
|| bShowCorrCoeff
))
1154 OUStringBuffer aFormula
;
1155 sal_Int32 nNumberFormatKey
= 0;
1156 xEquationProperties
->getPropertyValue(CHART_UNONAME_NUMFMT
) >>= nNumberFormatKey
;
1160 if( m_apNumberFormatterWrapper
.get())
1162 aFormula
= xRegressionCurveCalculator
->getFormattedRepresentation(
1163 m_apNumberFormatterWrapper
->getNumberFormatsSupplier(),
1168 aFormula
= xRegressionCurveCalculator
->getRepresentation();
1171 if( bShowCorrCoeff
)
1173 aFormula
.append( aSep
);
1176 if( bShowCorrCoeff
)
1178 aFormula
.append( "R" );
1179 aFormula
.append( sal_Unicode( 0x00b2 ));
1180 aFormula
.append( " = ");
1181 double fR( xRegressionCurveCalculator
->getCorrelationCoefficient());
1182 if( m_apNumberFormatterWrapper
.get())
1184 sal_Int32 nLabelCol
= 0;
1187 m_apNumberFormatterWrapper
->getFormattedString(
1188 nNumberFormatKey
, fR
*fR
, nLabelCol
, bColChanged
));
1189 //@todo: change color of label if bColChanged is true
1193 sal_Unicode
aDecimalSep( '.' );//@todo get this locale dependent
1194 aFormula
.append( ::rtl::math::doubleToUString(
1195 fR
*fR
, rtl_math_StringFormat_G
, 4, aDecimalSep
, true ));
1199 awt::Point aScreenPosition2D
;
1200 chart2::RelativePosition aRelativePosition
;
1201 if( xEquationProperties
->getPropertyValue( "RelativePosition") >>= aRelativePosition
)
1203 //@todo decide whether x is primary or secondary
1204 double fX
= aRelativePosition
.Primary
*m_aPageReferenceSize
.Width
;
1205 double fY
= aRelativePosition
.Secondary
*m_aPageReferenceSize
.Height
;
1206 aScreenPosition2D
.X
= static_cast< sal_Int32
>( ::rtl::math::round( fX
));
1207 aScreenPosition2D
.Y
= static_cast< sal_Int32
>( ::rtl::math::round( fY
));
1210 aScreenPosition2D
= aDefaultPos
;
1212 if( !aFormula
.isEmpty())
1214 // set fill and line properties on creation
1215 tNameSequence aNames
;
1216 tAnySequence aValues
;
1217 PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties
, aNames
, aValues
);
1219 uno::Reference
< drawing::XShape
> xTextShape
= m_pShapeFactory
->createText(
1220 xEquationTarget
, aFormula
.makeStringAndClear(),
1221 aNames
, aValues
, AbstractShapeFactory::makeTransformation( aScreenPosition2D
));
1223 OSL_ASSERT( xTextShape
.is());
1224 if( xTextShape
.is())
1226 AbstractShapeFactory::setShapeName( xTextShape
, rEquationCID
);
1227 awt::Size
aSize( xTextShape
->getSize() );
1228 awt::Point
aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
1229 aScreenPosition2D
, aSize
, aRelativePosition
.Anchor
) );
1230 //ensure that the equation is fully placed within the page (if possible)
1231 if( (aPos
.X
+ aSize
.Width
) > m_aPageReferenceSize
.Width
)
1232 aPos
.X
= m_aPageReferenceSize
.Width
- aSize
.Width
;
1235 if( (aPos
.Y
+ aSize
.Height
) > m_aPageReferenceSize
.Height
)
1236 aPos
.Y
= m_aPageReferenceSize
.Height
- aSize
.Height
;
1239 xTextShape
->setPosition(aPos
);
1245 void VSeriesPlotter::setMappedProperties(
1246 const uno::Reference
< drawing::XShape
>& xTargetShape
1247 , const uno::Reference
< beans::XPropertySet
>& xSource
1248 , const tPropertyNameMap
& rMap
1249 , tPropertyNameValueMap
* pOverwriteMap
)
1251 uno::Reference
< beans::XPropertySet
> xTargetProp( xTargetShape
, uno::UNO_QUERY
);
1252 PropertyMapper::setMappedProperties(xTargetProp
,xSource
,rMap
,pOverwriteMap
);
1255 void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution
, const Date
& rNullDate
)
1257 m_nTimeResolution
= TimeResolution
;
1258 m_aNullDate
= rNullDate
;
1261 // MinimumAndMaximumSupplier
1262 long VSeriesPlotter::calculateTimeResolutionOnXAxis()
1264 long nRet
= ::com::sun::star::chart::TimeUnit::YEAR
;
1265 if( m_pExplicitCategoriesProvider
)
1267 const std::vector
< DatePlusIndex
>& rDateCategories
= m_pExplicitCategoriesProvider
->getDateCategories();
1268 std::vector
< DatePlusIndex
>::const_iterator aIt
= rDateCategories
.begin(), aEnd
= rDateCategories
.end();
1269 Date
aNullDate(30,12,1899);
1270 if( m_apNumberFormatterWrapper
.get() )
1271 aNullDate
= m_apNumberFormatterWrapper
->getNullDate();
1274 Date
aPrevious(aNullDate
); aPrevious
+=static_cast<long>(rtl::math::approxFloor(aIt
->fValue
));
1276 for(;aIt
!=aEnd
;++aIt
)
1278 Date
aCurrent(aNullDate
); aCurrent
+=static_cast<long>(rtl::math::approxFloor(aIt
->fValue
));
1279 if( ::com::sun::star::chart::TimeUnit::YEAR
== nRet
)
1281 if( DateHelper::IsInSameYear( aPrevious
, aCurrent
) )
1282 nRet
= ::com::sun::star::chart::TimeUnit::MONTH
;
1284 if( ::com::sun::star::chart::TimeUnit::MONTH
== nRet
)
1286 if( DateHelper::IsInSameMonth( aPrevious
, aCurrent
) )
1287 nRet
= ::com::sun::star::chart::TimeUnit::DAY
;
1289 if( ::com::sun::star::chart::TimeUnit::DAY
== nRet
)
1297 double VSeriesPlotter::getMinimumX()
1299 double fMinimum
, fMaximum
;
1300 getMinimumAndMaximiumX( fMinimum
, fMaximum
);
1303 double VSeriesPlotter::getMaximumX()
1305 double fMinimum
, fMaximum
;
1306 getMinimumAndMaximiumX( fMinimum
, fMaximum
);
1310 double VSeriesPlotter::getMinimumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1312 if( !m_bCategoryXAxis
|| ( m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->isDateAxis() ) )
1314 double fMinY
, fMaxY
;
1315 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1319 double fMinimum
, fMaximum
;
1320 ::rtl::math::setInf(&fMinimum
, false);
1321 ::rtl::math::setInf(&fMaximum
, true);
1322 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1324 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1325 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1327 double fLocalMinimum
, fLocalMaximum
;
1328 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1329 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1330 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1331 , isSeparateStackingForDifferentSigns( 1 )
1332 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1333 if(fMaximum
<fLocalMaximum
)
1334 fMaximum
=fLocalMaximum
;
1335 if(fMinimum
>fLocalMinimum
)
1336 fMinimum
=fLocalMinimum
;
1339 if(::rtl::math::isInf(fMinimum
))
1340 ::rtl::math::setNan(&fMinimum
);
1344 double VSeriesPlotter::getMaximumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1346 if( !m_bCategoryXAxis
|| ( m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->isDateAxis() ) )
1348 double fMinY
, fMaxY
;
1349 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1353 double fMinimum
, fMaximum
;
1354 ::rtl::math::setInf(&fMinimum
, false);
1355 ::rtl::math::setInf(&fMaximum
, true);
1356 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1358 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1359 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1361 double fLocalMinimum
, fLocalMaximum
;
1362 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1363 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1364 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1365 , isSeparateStackingForDifferentSigns( 1 )
1366 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1367 if(fMaximum
<fLocalMaximum
)
1368 fMaximum
=fLocalMaximum
;
1369 if(fMinimum
>fLocalMinimum
)
1370 fMinimum
=fLocalMinimum
;
1373 if(::rtl::math::isInf(fMaximum
))
1374 ::rtl::math::setNan(&fMaximum
);
1378 double VSeriesPlotter::getMinimumZ()
1380 //this is the default for all charts without a meaningfull z axis
1383 double VSeriesPlotter::getMaximumZ()
1385 if( 3!=m_nDimension
|| !m_aZSlots
.size() )
1386 return getMinimumZ()+1;
1387 return m_aZSlots
.size();
1392 bool lcl_isValueAxis( sal_Int32 nDimensionIndex
, bool bCategoryXAxis
)
1394 // default implementation: true for Y axes, and for value X axis
1395 if( nDimensionIndex
== 0 )
1396 return !bCategoryXAxis
;
1397 if( nDimensionIndex
== 1 )
1403 bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex
)
1405 return lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1408 bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex
)
1410 // do not expand axes in 3D charts
1411 return (m_nDimension
< 3) && lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1414 bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex
)
1416 // default implementation: only for Y axis
1417 return nDimensionIndex
== 1;
1420 bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex
)
1422 // default implementation: only for Y axis
1423 return nDimensionIndex
== 1;
1426 bool VSeriesPlotter::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex
)
1428 // default implementation: only for Y axis
1429 return nDimensionIndex
== 1;
1432 void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1434 ::rtl::math::setInf(&rfMinimum
, false);
1435 ::rtl::math::setInf(&rfMaximum
, true);
1437 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1438 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1439 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1441 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1442 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1443 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
1445 double fLocalMinimum
, fLocalMaximum
;
1446 aXSlotIter
->getMinimumAndMaximiumX( fLocalMinimum
, fLocalMaximum
);
1447 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinimum
)
1448 rfMinimum
= fLocalMinimum
;
1449 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaximum
)
1450 rfMaximum
= fLocalMaximum
;
1453 if(::rtl::math::isInf(rfMinimum
))
1454 ::rtl::math::setNan(&rfMinimum
);
1455 if(::rtl::math::isInf(rfMaximum
))
1456 ::rtl::math::setNan(&rfMaximum
);
1459 void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1461 ::rtl::math::setInf(&rfMinY
, false);
1462 ::rtl::math::setInf(&rfMaxY
, true);
1464 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1465 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1466 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1468 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1469 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1470 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
1472 double fLocalMinimum
, fLocalMaximum
;
1473 aXSlotIter
->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum
, fLocalMaximum
, fMinX
, fMaxX
, nAxisIndex
);
1474 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinY
)
1475 rfMinY
= fLocalMinimum
;
1476 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaxY
)
1477 rfMaxY
= fLocalMaximum
;
1480 if(::rtl::math::isInf(rfMinY
))
1481 ::rtl::math::setNan(&rfMinY
);
1482 if(::rtl::math::isInf(rfMaxY
))
1483 ::rtl::math::setNan(&rfMaxY
);
1486 sal_Int32
VSeriesPlotter::getPointCount() const
1490 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1491 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1493 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1495 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1496 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1498 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
1500 sal_Int32 nPointCount
= aXSlotIter
->getPointCount();
1501 if( nPointCount
>nRet
)
1508 void VSeriesPlotter::setNumberFormatsSupplier(
1509 const uno::Reference
< util::XNumberFormatsSupplier
> & xNumFmtSupplier
)
1511 m_apNumberFormatterWrapper
.reset( new NumberFormatterWrapper( xNumFmtSupplier
));
1514 void VSeriesPlotter::setColorScheme( const uno::Reference
< XColorScheme
>& xColorScheme
)
1516 m_xColorScheme
= xColorScheme
;
1519 void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider
* pExplicitCategoriesProvider
)
1521 m_pExplicitCategoriesProvider
= pExplicitCategoriesProvider
;
1524 sal_Int32
VDataSeriesGroup::getPointCount() const
1526 if(!m_bMaxPointCountDirty
)
1527 return m_nMaxPointCount
;
1530 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1531 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1533 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1535 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1536 if( nPointCount
>nRet
)
1539 m_nMaxPointCount
=nRet
;
1540 m_aListOfCachedYValues
.clear();
1541 m_aListOfCachedYValues
.resize(m_nMaxPointCount
);
1542 m_bMaxPointCountDirty
=false;
1546 sal_Int32
VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1549 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1550 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1552 if( aSeriesIter
!= aSeriesEnd
)
1553 nRet
= (*aSeriesIter
)->getAttachedAxisIndex();
1558 void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1560 const ::std::vector
< VDataSeries
* >* pSeriesList
= &this->m_aSeriesVector
;
1562 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1563 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1565 ::rtl::math::setInf(&rfMinimum
, false);
1566 ::rtl::math::setInf(&rfMaximum
, true);
1568 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1570 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1571 for(sal_Int32 nN
=0;nN
<nPointCount
;nN
++)
1573 double fX
= (*aSeriesIter
)->getXValue( nN
);
1574 if( ::rtl::math::isNan(fX
) )
1582 if(::rtl::math::isInf(rfMinimum
))
1583 ::rtl::math::setNan(&rfMinimum
);
1584 if(::rtl::math::isInf(rfMaximum
))
1585 ::rtl::math::setNan(&rfMaximum
);
1591 * Keep track of minimum and maximum Y values for one or more data series.
1592 * When multiple data series exist, that indicates that the data series are
1595 * <p>For each X value, we calculate separate Y value ranges for each data
1596 * series in the first pass. In the second pass, we calculate the minimum Y
1597 * value by taking the absolute minimum value of all data series, whereas
1598 * the maxium Y value is the sum of all the series maximum Y values.</p>
1600 * <p>Once that's done for all X values, the final min / max Y values get
1601 * calculated by taking the absolute min / max Y values across all the X
1604 class PerXMinMaxCalculator
1606 typedef std::pair
<double, double> MinMaxType
;
1607 typedef std::map
<size_t, MinMaxType
> SeriesMinMaxType
;
1608 typedef boost::ptr_map
<double, SeriesMinMaxType
> GroupMinMaxType
;
1609 typedef std::unordered_map
<double, MinMaxType
> TotalStoreType
;
1610 GroupMinMaxType maSeriesGroup
;
1614 PerXMinMaxCalculator() : mnCurSeries(0) {}
1616 void nextSeries() { ++mnCurSeries
; }
1618 void setValue(double fX
, double fY
)
1620 SeriesMinMaxType
* pStore
= getByXValue(fX
); // get storage for given X value.
1622 // This shouldn't happen!
1625 SeriesMinMaxType::iterator it
= pStore
->lower_bound(mnCurSeries
);
1626 if (it
!= pStore
->end() && !pStore
->key_comp()(mnCurSeries
, it
->first
))
1628 MinMaxType
& r
= it
->second
;
1629 // A min-max pair already exists for this series. Update it.
1637 // No existing pair. Insert a new one.
1639 it
, SeriesMinMaxType::value_type(
1640 mnCurSeries
, MinMaxType(fY
,fY
)));
1644 void getTotalRange(double& rfMin
, double& rfMax
) const
1646 rtl::math::setNan(&rfMin
);
1647 rtl::math::setNan(&rfMax
);
1649 TotalStoreType aStore
;
1650 getTotalStore(aStore
);
1655 TotalStoreType::const_iterator it
= aStore
.begin(), itEnd
= aStore
.end();
1656 rfMin
= it
->second
.first
;
1657 rfMax
= it
->second
.second
;
1658 for (++it
; it
!= itEnd
; ++it
)
1660 if (rfMin
> it
->second
.first
)
1661 rfMin
= it
->second
.first
;
1662 if (rfMax
< it
->second
.second
)
1663 rfMax
= it
->second
.second
;
1669 * Parse all data and reduce them into a set of global Y value ranges per
1672 void getTotalStore(TotalStoreType
& rStore
) const
1674 TotalStoreType aStore
;
1675 GroupMinMaxType::const_iterator it
= maSeriesGroup
.begin(), itEnd
= maSeriesGroup
.end();
1676 for (; it
!= itEnd
; ++it
)
1678 double fX
= it
->first
;
1680 const SeriesMinMaxType
& rSeries
= *it
->second
;
1681 SeriesMinMaxType::const_iterator itSeries
= rSeries
.begin(), itSeriesEnd
= rSeries
.end();
1682 for (; itSeries
!= itSeriesEnd
; ++itSeries
)
1684 double fYMin
= itSeries
->second
.first
, fYMax
= itSeries
->second
.second
;
1685 TotalStoreType::iterator itr
= aStore
.find(fX
);
1686 if (itr
== aStore
.end())
1687 // New min-max pair for give X value.
1689 TotalStoreType::value_type(fX
, std::pair
<double,double>(fYMin
,fYMax
)));
1692 MinMaxType
& r
= itr
->second
;
1693 if (fYMin
< r
.first
)
1694 r
.first
= fYMin
; // min y-value
1696 r
.second
+= fYMax
; // accumulative max y-value.
1700 rStore
.swap(aStore
);
1703 SeriesMinMaxType
* getByXValue(double fX
)
1705 GroupMinMaxType::iterator it
= maSeriesGroup
.find(fX
);
1706 if (it
== maSeriesGroup
.end())
1708 std::pair
<GroupMinMaxType::iterator
,bool> r
=
1709 maSeriesGroup
.insert(fX
, new SeriesMinMaxType
);
1712 // insertion failed.
1724 void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
1725 double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1727 ::rtl::math::setNan(&rfMinY
);
1728 ::rtl::math::setNan(&rfMaxY
);
1730 if (m_aSeriesVector
.empty())
1731 // No data series. Bail out.
1734 PerXMinMaxCalculator aRangeCalc
;
1735 std::vector
<VDataSeries
*>::const_iterator it
= m_aSeriesVector
.begin(), itEnd
= m_aSeriesVector
.end();
1736 for (; it
!= itEnd
; ++it
)
1738 const VDataSeries
* pSeries
= *it
;
1742 for (sal_Int32 i
= 0, n
= pSeries
->getTotalPointCount(); i
< n
; ++i
)
1744 if (nAxisIndex
!= pSeries
->getAttachedAxisIndex())
1747 double fX
= pSeries
->getXValue(i
);
1748 if (rtl::math::isNan(fX
))
1751 if (fX
< fMinX
|| fX
> fMaxX
)
1752 // Outside specified X range. Skip it.
1755 double fY
= pSeries
->getYValue(i
);
1756 if (::rtl::math::isNan(fY
))
1759 aRangeCalc
.setValue(fX
, fY
);
1761 aRangeCalc
.nextSeries();
1764 aRangeCalc
.getTotalRange(rfMinY
, rfMaxY
);
1767 void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
1768 , bool bSeparateStackingForDifferentSigns
1769 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1771 ::rtl::math::setInf(&rfMinimumY
, false);
1772 ::rtl::math::setInf(&rfMaximumY
, true);
1774 sal_Int32 nPointCount
= getPointCount();//necessary to create m_aListOfCachedYValues
1775 if(nCategoryIndex
<0 || nCategoryIndex
>=nPointCount
|| m_aSeriesVector
.empty())
1778 CachedYValues aCachedYValues
= m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
];
1779 if( !aCachedYValues
.m_bValuesDirty
)
1781 //return cached values
1782 rfMinimumY
= aCachedYValues
.m_fMinimumY
;
1783 rfMaximumY
= aCachedYValues
.m_fMaximumY
;
1787 double fTotalSum
, fPositiveSum
, fNegativeSum
, fFirstPositiveY
, fFirstNegativeY
;
1788 ::rtl::math::setNan( &fTotalSum
);
1789 ::rtl::math::setNan( &fPositiveSum
);
1790 ::rtl::math::setNan( &fNegativeSum
);
1791 ::rtl::math::setNan( &fFirstPositiveY
);
1792 ::rtl::math::setNan( &fFirstNegativeY
);
1794 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1795 ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1797 if( bSeparateStackingForDifferentSigns
)
1799 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1801 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1804 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1805 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1807 if( fValueMaxY
>= 0 )
1809 if( ::rtl::math::isNan( fPositiveSum
) )
1810 fPositiveSum
= fFirstPositiveY
= fValueMaxY
;
1812 fPositiveSum
+= fValueMaxY
;
1814 if( fValueMinY
< 0 )
1816 if(::rtl::math::isNan( fNegativeSum
))
1817 fNegativeSum
= fFirstNegativeY
= fValueMinY
;
1819 fNegativeSum
+= fValueMinY
;
1822 rfMinimumY
= ::rtl::math::isNan( fNegativeSum
) ? fFirstPositiveY
: fNegativeSum
;
1823 rfMaximumY
= ::rtl::math::isNan( fPositiveSum
) ? fFirstNegativeY
: fPositiveSum
;
1827 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1829 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1832 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1833 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1835 if( ::rtl::math::isNan( fTotalSum
) )
1837 rfMinimumY
= fValueMinY
;
1838 rfMaximumY
= fTotalSum
= fValueMaxY
;
1842 fTotalSum
+= fValueMaxY
;
1843 if( rfMinimumY
> fTotalSum
)
1844 rfMinimumY
= fTotalSum
;
1845 if( rfMaximumY
< fTotalSum
)
1846 rfMaximumY
= fTotalSum
;
1851 aCachedYValues
.m_fMinimumY
= rfMinimumY
;
1852 aCachedYValues
.m_fMaximumY
= rfMaximumY
;
1853 aCachedYValues
.m_bValuesDirty
= false;
1854 m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
]=aCachedYValues
;
1857 void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
1858 sal_Int32 nStartCategoryIndex
, sal_Int32 nEndCategoryIndex
1859 , bool bSeparateStackingForDifferentSigns
1860 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1862 //@todo maybe cache these values
1863 ::rtl::math::setInf(&rfMinimumY
, false);
1864 ::rtl::math::setInf(&rfMaximumY
, true);
1866 //iterate through the given categories
1867 if(nStartCategoryIndex
<0)
1868 nStartCategoryIndex
=0;
1869 if(nEndCategoryIndex
<0)
1870 nEndCategoryIndex
=0;
1871 for( sal_Int32 nCatIndex
= nStartCategoryIndex
; nCatIndex
<= nEndCategoryIndex
; nCatIndex
++ )
1873 double fMinimumY
; ::rtl::math::setNan(&fMinimumY
);
1874 double fMaximumY
; ::rtl::math::setNan(&fMaximumY
);
1876 this->calculateYMinAndMaxForCategory( nCatIndex
1877 , bSeparateStackingForDifferentSigns
, fMinimumY
, fMaximumY
, nAxisIndex
);
1879 if(rfMinimumY
> fMinimumY
)
1880 rfMinimumY
= fMinimumY
;
1881 if(rfMaximumY
< fMaximumY
)
1882 rfMaximumY
= fMaximumY
;
1886 double VSeriesPlotter::getTransformedDepth() const
1888 double MinZ
= m_pMainPosHelper
->getLogicMinZ();
1889 double MaxZ
= m_pMainPosHelper
->getLogicMaxZ();
1890 m_pMainPosHelper
->doLogicScaling( 0, 0, &MinZ
);
1891 m_pMainPosHelper
->doLogicScaling( 0, 0, &MaxZ
);
1892 return FIXED_SIZE_FOR_3D_CHART_VOLUME
/(MaxZ
-MinZ
);
1895 void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData
& rScale
, sal_Int32 nAxisIndex
)
1896 throw (uno::RuntimeException
)
1901 m_aSecondaryValueScales
[nAxisIndex
]=rScale
;
1904 PlottingPositionHelper
& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex
) const
1906 PlottingPositionHelper
* pRet
= 0;
1909 tSecondaryPosHelperMap::const_iterator aPosIt
= m_aSecondaryPosHelperMap
.find( nAxisIndex
);
1910 if( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
1912 pRet
= aPosIt
->second
;
1914 else if (m_pPosHelper
)
1916 tSecondaryValueScales::const_iterator aScaleIt
= m_aSecondaryValueScales
.find( nAxisIndex
);
1917 if( aScaleIt
!= m_aSecondaryValueScales
.end() )
1919 pRet
= m_pPosHelper
->createSecondaryPosHelper( aScaleIt
->second
);
1920 m_aSecondaryPosHelperMap
[nAxisIndex
] = pRet
;
1925 pRet
= m_pMainPosHelper
;
1927 pRet
->setTimeResolution( m_nTimeResolution
, m_aNullDate
);
1931 void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size
& /*rPageSize*/ )
1935 VDataSeries
* VSeriesPlotter::getFirstSeries() const
1937 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1938 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1939 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1941 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1942 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1944 if( aXSlotIter
!= aXSlotEnd
)
1946 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1947 if( aSeriesGroup
.m_aSeriesVector
.size() )
1949 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1958 uno::Sequence
< OUString
> VSeriesPlotter::getSeriesNames() const
1960 ::std::vector
< OUString
> aRetVector
;
1963 if( m_xChartTypeModel
.is() )
1964 aRole
= m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel();
1966 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1967 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1968 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1970 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1971 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1973 if( aXSlotIter
!= aXSlotEnd
)
1975 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1976 if( aSeriesGroup
.m_aSeriesVector
.size() )
1978 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1979 uno::Reference
< XDataSeries
> xSeries( pSeries
? pSeries
->getModel() : 0 );
1982 OUString
aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries
, aRole
) );
1983 aRetVector
.push_back( aSeriesName
);
1988 return ContainerHelper::ContainerToSequence( aRetVector
);
1993 struct lcl_setRefSizeAtSeriesGroup
: public ::std::unary_function
< VDataSeriesGroup
, void >
1995 lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize
) : m_aRefSize( aRefSize
) {}
1996 void operator()( VDataSeriesGroup
& rGroup
)
1998 ::std::vector
< VDataSeries
* >::iterator
aIt( rGroup
.m_aSeriesVector
.begin());
1999 const ::std::vector
< VDataSeries
* >::iterator
aEndIt( rGroup
.m_aSeriesVector
.end());
2000 for( ; aIt
!= aEndIt
; ++aIt
)
2001 (*aIt
)->setPageReferenceSize( m_aRefSize
);
2005 awt::Size m_aRefSize
;
2007 } // anonymous namespace
2009 void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size
& rPageRefSize
)
2011 m_aPageReferenceSize
= rPageRefSize
;
2013 // set reference size also at all data series
2015 ::std::vector
< VDataSeriesGroup
> aSeriesGroups( FlattenVector( m_aZSlots
));
2016 ::std::for_each( aSeriesGroups
.begin(), aSeriesGroups
.end(),
2017 lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize
));
2020 //better performance for big data
2021 void VSeriesPlotter::setCoordinateSystemResolution( const Sequence
< sal_Int32
>& rCoordinateSystemResolution
)
2023 m_aCoordinateSystemResolution
= rCoordinateSystemResolution
;
2026 bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
2028 return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel
);
2031 bool VSeriesPlotter::shouldSnapRectToUsedArea()
2033 if( m_nDimension
== 3 )
2038 std::vector
< ViewLegendEntry
> VSeriesPlotter::createLegendEntries(
2039 const awt::Size
& rEntryKeyAspectRatio
2040 , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion
2041 , const Reference
< beans::XPropertySet
>& xTextProperties
2042 , const Reference
< drawing::XShapes
>& xTarget
2043 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
2044 , const Reference
< uno::XComponentContext
>& xContext
2047 std::vector
< ViewLegendEntry
> aResult
;
2051 //iterate through all series
2052 bool bBreak
= false;
2053 bool bFirstSeries
= true;
2054 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
2055 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
2056 for( ; aZSlotIter
!=aZSlotEnd
&& !bBreak
; ++aZSlotIter
)
2058 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
2059 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
2060 for( ; aXSlotIter
!=aXSlotEnd
&& !bBreak
; ++aXSlotIter
)
2062 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
2063 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
2064 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
2065 //iterate through all series in this x slot
2066 for( ; aSeriesIter
!=aSeriesEnd
&& !bBreak
; ++aSeriesIter
)
2068 VDataSeries
* pSeries( *aSeriesIter
);
2072 std::vector
< ViewLegendEntry
> aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio
,
2073 *pSeries
, xTextProperties
, xTarget
, xShapeFactory
, xContext
) );
2075 //add series entries to the result now
2077 // use only the first series if VaryColorsByPoint is set for the first series
2078 if( bFirstSeries
&& pSeries
->isVaryColorsByPoint() )
2080 bFirstSeries
= false;
2082 // add entries reverse if chart is stacked in y-direction and the legend is not wide.
2083 // If the legend is wide and we have a stacked bar-chart the normal order
2084 // is the correct one
2085 bool bReverse
= false;
2086 if( eLegendExpansion
!= ::com::sun::star::chart::ChartLegendExpansion_WIDE
)
2088 StackingDirection
eStackingDirection( pSeries
->getStackingDirection() );
2089 bReverse
= ( eStackingDirection
== StackingDirection_Y_STACKING
);
2091 //todo: respect direction of axis in future
2095 aResult
.insert( aResult
.begin(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
2097 aResult
.insert( aResult
.end(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
2106 ::std::vector
< VDataSeries
* > VSeriesPlotter::getAllSeries()
2108 ::std::vector
< VDataSeries
* > aAllSeries
;
2109 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
2110 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
2111 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
2113 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
2114 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
2115 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
2117 ::std::vector
< VDataSeries
* > aSeriesList
= aXSlotIter
->m_aSeriesVector
;
2118 aAllSeries
.insert( aAllSeries
.end(), aSeriesList
.begin(), aSeriesList
.end() );
2126 bool lcl_HasVisibleLine( const uno::Reference
< beans::XPropertySet
>& xProps
, bool& rbHasDashedLine
)
2128 bool bHasVisibleLine
= false;
2129 rbHasDashedLine
= false;
2130 drawing::LineStyle aLineStyle
= drawing::LineStyle_NONE
;
2131 if( xProps
.is() && ( xProps
->getPropertyValue( "LineStyle") >>= aLineStyle
) )
2133 if( aLineStyle
!= drawing::LineStyle_NONE
)
2134 bHasVisibleLine
= true;
2135 if( aLineStyle
== drawing::LineStyle_DASH
)
2136 rbHasDashedLine
= true;
2138 return bHasVisibleLine
;
2141 bool lcl_HasRegressionCurves( const VDataSeries
& rSeries
, bool& rbHasDashedLine
)
2143 bool bHasRegressionCurves
= false;
2144 Reference
< XRegressionCurveContainer
> xRegrCont( rSeries
.getModel(), uno::UNO_QUERY
);
2147 Sequence
< Reference
< XRegressionCurve
> > aCurves( xRegrCont
->getRegressionCurves() );
2148 sal_Int32 i
= 0, nCount
= aCurves
.getLength();
2149 for( i
=0; i
<nCount
; ++i
)
2151 if( aCurves
[i
].is() )
2153 bHasRegressionCurves
= true;
2154 lcl_HasVisibleLine( uno::Reference
< beans::XPropertySet
>( aCurves
[i
], uno::UNO_QUERY
), rbHasDashedLine
);
2158 return bHasRegressionCurves
;
2161 LegendSymbolStyle
VSeriesPlotter::getLegendSymbolStyle()
2163 return LegendSymbolStyle_BOX
;
2166 awt::Size
VSeriesPlotter::getPreferredLegendKeyAspectRatio()
2168 awt::Size
aRet(1000,1000);
2169 if( m_nDimension
==3 )
2172 bool bSeriesAllowsLines
= (getLegendSymbolStyle() == LegendSymbolStyle_LINE
);
2173 bool bHasLines
= false;
2174 bool bHasDashedLines
= false;
2175 ::std::vector
< VDataSeries
* > aAllSeries( getAllSeries() );
2176 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= aAllSeries
.begin();
2177 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= aAllSeries
.end();
2178 //iterate through all series
2179 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
2181 if( bSeriesAllowsLines
)
2183 bool bCurrentDashed
= false;
2184 if( lcl_HasVisibleLine( (*aSeriesIter
)->getPropertiesOfSeries(), bCurrentDashed
) )
2187 if( bCurrentDashed
)
2189 bHasDashedLines
= true;
2194 bool bRegressionHasDashedLines
=false;
2195 if( lcl_HasRegressionCurves( **aSeriesIter
, bRegressionHasDashedLines
) )
2198 if( bRegressionHasDashedLines
)
2200 bHasDashedLines
= true;
2207 if( bHasDashedLines
)
2208 aRet
= awt::Size(1600,-1);
2210 aRet
= awt::Size(800,-1);
2215 uno::Any
VSeriesPlotter::getExplicitSymbol( const VDataSeries
& /*rSeries*/, sal_Int32
/*nPointIndex*/ )
2220 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForSeries(
2221 const awt::Size
& rEntryKeyAspectRatio
2222 , const VDataSeries
& rSeries
2223 , const Reference
< drawing::XShapes
>& xTarget
2224 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
2227 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
2228 uno::Any
aExplicitSymbol( this->getExplicitSymbol( rSeries
) );
2230 VLegendSymbolFactory::tPropertyType ePropType
=
2231 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
2233 // todo: maybe the property-style does not solely depend on the
2234 // legend-symbol type
2235 switch( eLegendSymbolStyle
)
2237 case LegendSymbolStyle_LINE
:
2238 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
2243 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio
,
2244 xTarget
, eLegendSymbolStyle
, xShapeFactory
2245 , rSeries
.getPropertiesOfSeries(), ePropType
, aExplicitSymbol
));
2250 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForPoint(
2251 const awt::Size
& rEntryKeyAspectRatio
2252 , const VDataSeries
& rSeries
2253 , sal_Int32 nPointIndex
2254 , const Reference
< drawing::XShapes
>& xTarget
2255 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
2258 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
2259 uno::Any
aExplicitSymbol( this->getExplicitSymbol(rSeries
,nPointIndex
) );
2261 VLegendSymbolFactory::tPropertyType ePropType
=
2262 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
2264 // todo: maybe the property-style does not solely depend on the
2265 // legend-symbol type
2266 switch( eLegendSymbolStyle
)
2268 case LegendSymbolStyle_LINE
:
2269 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
2275 // the default properties for the data point are the data series properties.
2276 // If a data point has own attributes overwrite them
2277 Reference
< beans::XPropertySet
> xSeriesProps( rSeries
.getPropertiesOfSeries() );
2278 Reference
< beans::XPropertySet
> xPointSet( xSeriesProps
);
2279 if( rSeries
.isAttributedDataPoint( nPointIndex
) )
2280 xPointSet
.set( rSeries
.getPropertiesOfPoint( nPointIndex
));
2282 // if a data point has no own color use a color fom the diagram's color scheme
2283 if( ! rSeries
.hasPointOwnColor( nPointIndex
))
2285 Reference
< util::XCloneable
> xCloneable( xPointSet
,uno::UNO_QUERY
);
2286 if( xCloneable
.is() && m_xColorScheme
.is() )
2288 xPointSet
.set( xCloneable
->createClone(), uno::UNO_QUERY
);
2289 Reference
< container::XChild
> xChild( xPointSet
, uno::UNO_QUERY
);
2291 xChild
->setParent( xSeriesProps
);
2293 OSL_ASSERT( xPointSet
.is());
2294 xPointSet
->setPropertyValue(
2295 "Color", uno::makeAny( m_xColorScheme
->getColorByIndex( nPointIndex
)));
2299 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio
,
2300 xTarget
, eLegendSymbolStyle
, xShapeFactory
, xPointSet
, ePropType
, aExplicitSymbol
));
2305 std::vector
< ViewLegendEntry
> VSeriesPlotter::createLegendEntriesForSeries(
2306 const awt::Size
& rEntryKeyAspectRatio
2307 , const VDataSeries
& rSeries
2308 , const Reference
< beans::XPropertySet
>& xTextProperties
2309 , const Reference
< drawing::XShapes
>& xTarget
2310 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
2311 , const Reference
< uno::XComponentContext
>& xContext
2314 std::vector
< ViewLegendEntry
> aResult
;
2316 if( ! ( xShapeFactory
.is() && xTarget
.is() && xContext
.is() ) )
2321 ViewLegendEntry aEntry
;
2322 OUString aLabelText
;
2323 bool bVaryColorsByPoint
= rSeries
.isVaryColorsByPoint();
2324 if( bVaryColorsByPoint
)
2326 Sequence
< OUString
> aCategoryNames
;
2327 if( m_pExplicitCategoriesProvider
)
2328 aCategoryNames
= m_pExplicitCategoriesProvider
->getSimpleCategories();
2330 for( sal_Int32 nIdx
=0; nIdx
<aCategoryNames
.getLength(); ++nIdx
)
2333 uno::Reference
< drawing::XShapes
> xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory
)->createGroup2D( xTarget
));
2335 // create the symbol
2336 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio
,
2337 rSeries
, nIdx
, xSymbolGroup
, xShapeFactory
) );
2339 // set CID to symbol for selection
2342 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2344 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT
, nIdx
) );
2345 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2346 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2347 AbstractShapeFactory::setShapeName( xShape
, aCID
);
2351 aLabelText
= aCategoryNames
[nIdx
];
2352 if( xShape
.is() || !aLabelText
.isEmpty() )
2354 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
2355 aResult
.push_back(aEntry
);
2362 uno::Reference
< drawing::XShapes
> xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory
)->createGroup2D( xTarget
));
2364 // create the symbol
2365 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForSeries(
2366 rEntryKeyAspectRatio
, rSeries
, xSymbolGroup
, xShapeFactory
) );
2368 // set CID to symbol for selection
2371 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2373 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2374 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2375 AbstractShapeFactory::setShapeName( xShape
, aCID
);
2379 aLabelText
= ( DataSeriesHelper::getDataSeriesLabel( rSeries
.getModel(), m_xChartTypeModel
.is() ? m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel() : "values-y") );
2380 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
2382 aResult
.push_back(aEntry
);
2385 // don't show legend entry of regression curve & friends if this type of chart
2386 // doesn't support statistics #i63016#, fdo#37197
2387 if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel
, m_nDimension
))
2390 Reference
< XRegressionCurveContainer
> xRegrCont( rSeries
.getModel(), uno::UNO_QUERY
);
2393 Sequence
< Reference
< XRegressionCurve
> > aCurves( xRegrCont
->getRegressionCurves());
2394 sal_Int32 i
= 0, nCount
= aCurves
.getLength();
2395 for( i
=0; i
<nCount
; ++i
)
2397 if( aCurves
[i
].is() )
2400 OUString
aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves
[i
] ) );
2401 replaceParamterInString( aResStr
, "%SERIESNAME", aLabelText
);
2402 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aResStr
, xTextProperties
);
2405 uno::Reference
< drawing::XShapes
> xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory
)->createGroup2D( xTarget
));
2407 // create the symbol
2408 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio
,
2409 xSymbolGroup
, LegendSymbolStyle_LINE
, xShapeFactory
,
2410 Reference
< beans::XPropertySet
>( aCurves
[i
], uno::UNO_QUERY
),
2411 VLegendSymbolFactory::PROP_TYPE_LINE
, uno::Any() ));
2413 // set CID to symbol for selection
2416 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2418 bool bAverageLine
= RegressionCurveHelper::isMeanValueLine( aCurves
[i
] );
2419 ObjectType eObjectType
= bAverageLine
? OBJECTTYPE_DATA_AVERAGE_LINE
: OBJECTTYPE_DATA_CURVE
;
2420 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType
, i
) );
2421 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2422 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2423 AbstractShapeFactory::setShapeName( xShape
, aCID
);
2426 aResult
.push_back(aEntry
);
2431 catch( const uno::Exception
& ex
)
2433 ASSERT_EXCEPTION( ex
);
2438 VSeriesPlotter
* VSeriesPlotter::createSeriesPlotter(
2439 const uno::Reference
<XChartType
>& xChartTypeModel
2440 , sal_Int32 nDimensionCount
2441 , bool bExcludingPositioning
)
2443 if (!xChartTypeModel
.is())
2446 OUString aChartType
= xChartTypeModel
->getChartType();
2448 VSeriesPlotter
* pRet
=NULL
;
2449 if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN
) )
2450 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2451 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR
) )
2452 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2453 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA
) )
2454 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true);
2455 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE
) )
2456 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true);
2457 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER
) )
2458 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2459 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE
) )
2460 pRet
= new BubbleChart(xChartTypeModel
,nDimensionCount
);
2461 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE
) )
2462 pRet
= new PieChart(xChartTypeModel
,nDimensionCount
, bExcludingPositioning
);
2463 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET
) )
2464 pRet
= new NetChart(xChartTypeModel
,nDimensionCount
,true,new PolarPlottingPositionHelper());
2465 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET
) )
2466 pRet
= new NetChart(xChartTypeModel
,nDimensionCount
,false,new PolarPlottingPositionHelper());
2467 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK
) )
2468 pRet
= new CandleStickChart(xChartTypeModel
,nDimensionCount
);
2470 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */