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 "ShapeFactory.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 instanciated via servicefactory
48 #include "BarChart.hxx"
49 #include "PieChart.hxx"
50 #include "AreaChart.hxx"
51 #include "CandleStickChart.hxx"
52 #include "BubbleChart.hxx"
55 #include <com/sun/star/chart/ErrorBarStyle.hpp>
56 #include <com/sun/star/chart/TimeUnit.hpp>
57 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
58 #include <com/sun/star/container/XChild.hpp>
59 #include <com/sun/star/chart2/RelativePosition.hpp>
60 #include <editeng/unoprnms.hxx>
61 #include <tools/color.hxx>
62 // header for class OUStringBuffer
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>
74 #include <boost/ptr_container/ptr_map.hpp>
78 using namespace ::com::sun::star
;
79 using namespace ::com::sun::star::chart2
;
80 using ::com::sun::star::uno::Reference
;
81 using ::com::sun::star::uno::Sequence
;
84 //-----------------------------------------------------------------------------
86 VDataSeriesGroup::CachedYValues::CachedYValues()
87 : m_bValuesDirty(true)
93 VDataSeriesGroup::VDataSeriesGroup()
95 , m_bMaxPointCountDirty(true)
97 , m_aListOfCachedYValues()
101 VDataSeriesGroup::VDataSeriesGroup( VDataSeries
* pSeries
)
102 : m_aSeriesVector(1,pSeries
)
103 , m_bMaxPointCountDirty(true)
104 , m_nMaxPointCount(0)
105 , m_aListOfCachedYValues()
109 VDataSeriesGroup::~VDataSeriesGroup()
113 void VDataSeriesGroup::deleteSeries()
115 //delete all data series help objects:
116 ::std::vector
< VDataSeries
* >::const_iterator aIter
= m_aSeriesVector
.begin();
117 const ::std::vector
< VDataSeries
* >::const_iterator aEnd
= m_aSeriesVector
.end();
118 for( ; aIter
!= aEnd
; ++aIter
)
122 m_aSeriesVector
.clear();
125 void VDataSeriesGroup::addSeries( VDataSeries
* pSeries
)
127 m_aSeriesVector
.push_back(pSeries
);
128 m_bMaxPointCountDirty
=true;
131 sal_Int32
VDataSeriesGroup::getSeriesCount() const
133 return m_aSeriesVector
.size();
136 //-----------------------------------------------------------------------------
138 VSeriesPlotter::VSeriesPlotter( const uno::Reference
<XChartType
>& xChartTypeModel
139 , sal_Int32 nDimensionCount
, bool bCategoryXAxis
)
140 : PlotterBase( nDimensionCount
)
141 , m_pMainPosHelper( 0 )
142 , m_xChartTypeModel(xChartTypeModel
)
143 , m_xChartTypeModelProps( uno::Reference
< beans::XPropertySet
>::query( xChartTypeModel
))
145 , m_bCategoryXAxis(bCategoryXAxis
)
146 , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY
)
147 , m_aNullDate(30,12,1899)
149 , m_pExplicitCategoriesProvider(0)
150 , m_bPointsWereSkipped(false)
152 OSL_POSTCOND(m_xChartTypeModel
.is(),"no XChartType available in view, fallback to default values may be wrong");
155 VSeriesPlotter::~VSeriesPlotter()
157 //delete all data series help objects:
158 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
159 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
160 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
162 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
163 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
164 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
166 aXSlotIter
->deleteSeries();
172 tSecondaryPosHelperMap::iterator aPosIt
= m_aSecondaryPosHelperMap
.begin();
173 while( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
175 PlottingPositionHelper
* pPosHelper
= aPosIt
->second
;
180 m_aSecondaryPosHelperMap
.clear();
182 m_aSecondaryValueScales
.clear();
185 void VSeriesPlotter::addSeries( VDataSeries
* pSeries
, sal_Int32 zSlot
, sal_Int32 xSlot
, sal_Int32 ySlot
)
187 //take ownership of pSeries
189 OSL_PRECOND( pSeries
, "series to add is NULL" );
195 if( m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->isDateAxis() )
196 pSeries
->setXValues( m_pExplicitCategoriesProvider
->getOriginalCategories() );
198 pSeries
->setCategoryXAxis();
202 if( m_pExplicitCategoriesProvider
)
203 pSeries
->setXValuesIfNone( m_pExplicitCategoriesProvider
->getOriginalCategories() );
206 if(zSlot
<0 || zSlot
>=static_cast<sal_Int32
>(m_aZSlots
.size()))
209 ::std::vector
< VDataSeriesGroup
> aZSlot
;
210 aZSlot
.push_back( VDataSeriesGroup(pSeries
) );
211 m_aZSlots
.push_back( aZSlot
);
216 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[zSlot
];
218 if(xSlot
<0 || xSlot
>=static_cast<sal_Int32
>(rXSlots
.size()))
220 //append the series to already existing x series
221 rXSlots
.push_back( VDataSeriesGroup(pSeries
) );
225 //x slot is already occupied
226 //y slot decides what to do:
228 VDataSeriesGroup
& rYSlots
= rXSlots
[xSlot
];
229 sal_Int32 nYSlotCount
= rYSlots
.getSeriesCount();
233 //move all existing series in the xSlot to next slot
235 OSL_FAIL( "Not implemented yet");
237 else if( ySlot
== -1 || ySlot
>= nYSlotCount
)
239 //append the series to already existing y series
240 rYSlots
.addSeries(pSeries
);
244 //y slot is already occupied
245 //insert at given y and x position
248 OSL_FAIL( "Not implemented yet");
254 drawing::Direction3D
VSeriesPlotter::getPreferredDiagramAspectRatio() const
256 drawing::Direction3D
aRet(1.0,1.0,1.0);
257 drawing::Direction3D
aScale( m_pPosHelper
->getScaledLogicWidth() );
258 aRet
.DirectionZ
= aScale
.DirectionZ
*0.2;
259 if(aRet
.DirectionZ
>1.0)
261 if(aRet
.DirectionZ
>10)
266 bool VSeriesPlotter::keepAspectRatio() const
271 void VSeriesPlotter::releaseShapes()
273 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
274 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
275 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
277 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
278 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
279 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
281 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
283 ::std::vector
< VDataSeries
* >::iterator aSeriesIter
= pSeriesList
->begin();
284 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
286 //iterate through all series in this x slot
287 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
289 VDataSeries
* pSeries( *aSeriesIter
);
290 pSeries
->releaseShapes();
296 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShape( VDataSeries
* pDataSeries
297 , const uno::Reference
< drawing::XShapes
>& xTarget
)
299 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xGroupShape
);
302 //create a group shape for this series and add to logic target:
303 xShapes
= createGroupShape( xTarget
,pDataSeries
->getCID() );
304 pDataSeries
->m_xGroupShape
= xShapes
;
309 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries
* pDataSeries
310 , const uno::Reference
< drawing::XShapes
>& xTarget
)
312 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xFrontSubGroupShape
);
315 //ensure that the series group shape is already created
316 uno::Reference
< drawing::XShapes
> xSeriesShapes( this->getSeriesGroupShape( pDataSeries
, xTarget
) );
317 //ensure that the back child is created first
318 this->getSeriesGroupShapeBackChild( pDataSeries
, xTarget
);
319 //use series group shape as parent for the new created front group shape
320 xShapes
= createGroupShape( xSeriesShapes
);
321 pDataSeries
->m_xFrontSubGroupShape
= xShapes
;
326 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries
* pDataSeries
327 , const uno::Reference
< drawing::XShapes
>& xTarget
)
329 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xBackSubGroupShape
);
332 //ensure that the series group shape is already created
333 uno::Reference
< drawing::XShapes
> xSeriesShapes( this->getSeriesGroupShape( pDataSeries
, xTarget
) );
334 //use series group shape as parent for the new created back group shape
335 xShapes
= createGroupShape( xSeriesShapes
);
336 pDataSeries
->m_xBackSubGroupShape
= xShapes
;
341 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getLabelsGroupShape( VDataSeries
& rDataSeries
342 , const uno::Reference
< drawing::XShapes
>& xTextTarget
)
344 //xTextTarget needs to be a 2D shape container always!
346 uno::Reference
< drawing::XShapes
> xShapes( rDataSeries
.m_xLabelsGroupShape
);
349 //create a 2D group shape for texts of this series and add to text target:
350 xShapes
= m_pShapeFactory
->createGroup2D( xTextTarget
, rDataSeries
.getLabelsCID() );
351 rDataSeries
.m_xLabelsGroupShape
= xShapes
;
356 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getErrorBarsGroupShape( VDataSeries
& rDataSeries
357 , const uno::Reference
< drawing::XShapes
>& xTarget
360 uno::Reference
< ::com::sun::star::drawing::XShapes
> &rShapeGroup
=
361 bYError
? rDataSeries
.m_xErrorYBarsGroupShape
: rDataSeries
.m_xErrorXBarsGroupShape
;
363 uno::Reference
< drawing::XShapes
> xShapes( rShapeGroup
);
366 //create a group shape for this series and add to logic target:
367 xShapes
= this->createGroupShape( xTarget
,rDataSeries
.getErrorBarsCID(bYError
) );
368 rShapeGroup
= xShapes
;
374 OUString
VSeriesPlotter::getLabelTextForValue( VDataSeries
& rDataSeries
375 , sal_Int32 nPointIndex
377 , bool bAsPercentage
)
381 if( m_apNumberFormatterWrapper
.get())
383 sal_Int32 nNumberFormatKey
= 0;
384 if( rDataSeries
.hasExplicitNumberFormat(nPointIndex
,bAsPercentage
) )
385 nNumberFormatKey
= rDataSeries
.getExplicitNumberFormat(nPointIndex
,bAsPercentage
);
386 else if( bAsPercentage
)
388 sal_Int32 nPercentFormat
= DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper
->getNumberFormatsSupplier() );
389 if( nPercentFormat
!= -1 )
390 nNumberFormatKey
= nPercentFormat
;
394 if( rDataSeries
.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats
.hasFormat(1,rDataSeries
.getAttachedAxisIndex()) ) //y-axis
395 nNumberFormatKey
= m_aAxesNumberFormats
.getFormat(1,rDataSeries
.getAttachedAxisIndex());
397 nNumberFormatKey
= rDataSeries
.detectNumberFormatKey( nPointIndex
);
399 if(nNumberFormatKey
<0)
402 sal_Int32 nLabelCol
= 0;
404 aNumber
= m_apNumberFormatterWrapper
->getFormattedString(
405 nNumberFormatKey
, fValue
, nLabelCol
, bColChanged
);
406 //@todo: change color of label if bColChanged is true
410 sal_Unicode cDecSeparator
= '.';//@todo get this locale dependent
411 aNumber
= ::rtl::math::doubleToUString( fValue
, rtl_math_StringFormat_G
/*rtl_math_StringFormat*/
412 , 3/*DecPlaces*/ , cDecSeparator
, false /*bEraseTrailingDecZeros*/ );
417 uno::Reference
< drawing::XShape
> VSeriesPlotter::createDataLabel( const uno::Reference
< drawing::XShapes
>& xTarget
418 , VDataSeries
& rDataSeries
419 , sal_Int32 nPointIndex
422 , const awt::Point
& rScreenPosition2D
423 , LabelAlignment eAlignment
424 , sal_Int32 nOffset
)
426 uno::Reference
< drawing::XShape
> xTextShape
;
430 awt::Point
aScreenPosition2D(rScreenPosition2D
);
431 if(LABEL_ALIGN_LEFT
==eAlignment
)
432 aScreenPosition2D
.X
-= nOffset
;
433 else if(LABEL_ALIGN_RIGHT
==eAlignment
)
434 aScreenPosition2D
.X
+= nOffset
;
435 else if(LABEL_ALIGN_TOP
==eAlignment
)
436 aScreenPosition2D
.Y
-= nOffset
;
437 else if(LABEL_ALIGN_BOTTOM
==eAlignment
)
438 aScreenPosition2D
.Y
+= nOffset
;
440 uno::Reference
< drawing::XShapes
> xTarget_(
441 m_pShapeFactory
->createGroup2D( this->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 //------------------------------------------------
451 //prepare legend symbol
453 float fViewFontSize( 10.0 );
455 uno::Reference
< beans::XPropertySet
> xProps( rDataSeries
.getPropertiesOfPoint( nPointIndex
) );
457 xProps
->getPropertyValue( C2U( "CharHeight" )) >>= fViewFontSize
;
459 fViewFontSize
*= (2540.0f
/ 72.0f
);
461 Reference
< drawing::XShape
> xSymbol
;
462 if(pLabel
->ShowLegendSymbol
)
464 sal_Int32 nSymbolHeigth
= static_cast< sal_Int32
>( fViewFontSize
* 0.6 );
465 awt::Size aCurrentRatio
= this->getPreferredLegendKeyAspectRatio();
466 sal_Int32 nSymbolWidth
= aCurrentRatio
.Width
;
467 if( aCurrentRatio
.Height
> 0 )
469 nSymbolWidth
= nSymbolHeigth
* aCurrentRatio
.Width
/aCurrentRatio
.Height
;
471 awt::Size
aMaxSymbolExtent( nSymbolWidth
, nSymbolHeigth
);
473 if( rDataSeries
.isVaryColorsByPoint() )
474 xSymbol
.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent
, rDataSeries
, nPointIndex
, xTarget_
, m_xShapeFactory
) );
476 xSymbol
.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent
, rDataSeries
, xTarget_
, m_xShapeFactory
) );
480 ::rtl::OUStringBuffer aText
;
481 ::rtl::OUString
aSeparator(sal_Unicode(' '));
482 double fRotationDegrees
= 0.0;
485 uno::Reference
< beans::XPropertySet
> xPointProps( rDataSeries
.getPropertiesOfPoint( nPointIndex
) );
488 xPointProps
->getPropertyValue( C2U( "LabelSeparator" ) ) >>= aSeparator
;
489 xPointProps
->getPropertyValue( C2U( "TextRotation" ) ) >>= fRotationDegrees
;
492 catch( const uno::Exception
& e
)
494 ASSERT_EXCEPTION( e
);
496 bool bMultiLineLabel
= aSeparator
.equals(C2U("\n"));;
497 sal_Int32 nLineCountForSymbolsize
= 0;
499 if(pLabel
->ShowCategoryName
)
501 if( m_pExplicitCategoriesProvider
)
503 Sequence
< OUString
> aCategories( m_pExplicitCategoriesProvider
->getSimpleCategories() );
504 if( nPointIndex
>= 0 && nPointIndex
< aCategories
.getLength() )
506 aText
.append( aCategories
[nPointIndex
] );
507 ++nLineCountForSymbolsize
;
512 if(pLabel
->ShowNumber
)
514 OUString
aNumber( this->getLabelTextForValue( rDataSeries
515 , nPointIndex
, fValue
, false /*bAsPercentage*/ ) );
516 if( !aNumber
.isEmpty() )
518 if(aText
.getLength())
519 aText
.append(aSeparator
);
520 aText
.append(aNumber
);
521 ++nLineCountForSymbolsize
;
525 if(pLabel
->ShowNumberInPercent
)
533 OUString
aPercentage( this->getLabelTextForValue( rDataSeries
534 , nPointIndex
, fValue
, true /*bAsPercentage*/ ) );
535 if( !aPercentage
.isEmpty() )
537 if(aText
.getLength())
538 aText
.append(aSeparator
);
539 aText
.append(aPercentage
);
540 ++nLineCountForSymbolsize
;
544 //------------------------------------------------
545 //prepare properties for multipropertyset-interface of shape
546 tNameSequence
* pPropNames
;
547 tAnySequence
* pPropValues
;
548 if( !rDataSeries
.getTextLabelMultiPropertyLists( nPointIndex
, pPropNames
, pPropValues
) )
550 LabelPositionHelper::changeTextAdjustment( *pPropValues
, *pPropNames
, eAlignment
);
552 //------------------------------------------------
554 xTextShape
= ShapeFactory(m_xShapeFactory
).
555 createText( xTarget_
, aText
.makeStringAndClear()
556 , *pPropNames
, *pPropValues
, ShapeFactory::makeTransformation( aScreenPosition2D
) );
558 if( !xTextShape
.is() )
561 const awt::Point
aUnrotatedTextPos( xTextShape
->getPosition() );
562 if( fRotationDegrees
!= 0.0 )
564 const double fDegreesPi( fRotationDegrees
* ( F_PI
/ -180.0 ) );
565 uno::Reference
< beans::XPropertySet
> xProp( xTextShape
, uno::UNO_QUERY
);
567 xProp
->setPropertyValue( C2U( "Transformation" ), ShapeFactory::makeTransformation( aScreenPosition2D
, fDegreesPi
) );
568 LabelPositionHelper::correctPositionForRotation( xTextShape
, eAlignment
, fRotationDegrees
, true /*bRotateAroundCenter*/ );
573 const awt::Point
aOldTextPos( xTextShape
->getPosition() );
574 awt::Point
aNewTextPos( aOldTextPos
);
576 awt::Point
aSymbolPosition( aUnrotatedTextPos
);
577 awt::Size
aSymbolSize( xSymbol
->getSize() );
578 awt::Size
aTextSize( xTextShape
->getSize() );
580 sal_Int32 nXDiff
= aSymbolSize
.Width
+ static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize
* 0.22 ) );//minimum 1mm
581 if( !bMultiLineLabel
|| nLineCountForSymbolsize
<= 0 )
582 nLineCountForSymbolsize
= 1;
583 aSymbolPosition
.Y
+= ((aTextSize
.Height
/nLineCountForSymbolsize
)/4);
585 if(LABEL_ALIGN_LEFT
==eAlignment
586 || LABEL_ALIGN_LEFT_TOP
==eAlignment
587 || LABEL_ALIGN_LEFT_BOTTOM
==eAlignment
)
589 aSymbolPosition
.X
-= nXDiff
;
591 else if(LABEL_ALIGN_RIGHT
==eAlignment
592 || LABEL_ALIGN_RIGHT_TOP
==eAlignment
593 || LABEL_ALIGN_RIGHT_BOTTOM
==eAlignment
)
595 aNewTextPos
.X
+= nXDiff
;
597 else if(LABEL_ALIGN_TOP
==eAlignment
598 || LABEL_ALIGN_BOTTOM
==eAlignment
599 || LABEL_ALIGN_CENTER
==eAlignment
)
601 aSymbolPosition
.X
-= nXDiff
/2;
602 aNewTextPos
.X
+= nXDiff
/2;
605 xSymbol
->setPosition( aSymbolPosition
);
606 xTextShape
->setPosition( aNewTextPos
);
609 catch( const uno::Exception
& e
)
611 ASSERT_EXCEPTION( e
);
619 double lcl_getErrorBarLogicLength(
620 const uno::Sequence
< double > & rData
,
621 uno::Reference
< beans::XPropertySet
> xProp
,
622 sal_Int32 nErrorBarStyle
,
628 ::rtl::math::setNan( & fResult
);
631 switch( nErrorBarStyle
)
633 case ::com::sun::star::chart::ErrorBarStyle::NONE
:
635 case ::com::sun::star::chart::ErrorBarStyle::VARIANCE
:
636 fResult
= StatisticsHelper::getVariance( rData
);
638 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION
:
639 fResult
= StatisticsHelper::getStandardDeviation( rData
);
641 case ::com::sun::star::chart::ErrorBarStyle::RELATIVE
:
644 if( xProp
->getPropertyValue( bPositive
645 ? C2U("PositiveError")
646 : C2U("NegativeError")) >>= fPercent
)
648 if( nIndex
>=0 && nIndex
< rData
.getLength() &&
649 ! ::rtl::math::isNan( rData
[nIndex
] ) &&
650 ! ::rtl::math::isNan( fPercent
))
652 fResult
= rData
[nIndex
] * fPercent
/ 100.0;
657 case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE
:
658 xProp
->getPropertyValue( bPositive
659 ? C2U("PositiveError")
660 : C2U("NegativeError")) >>= fResult
;
662 case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN
:
664 // todo: check if this is really what's called error-margin
666 if( xProp
->getPropertyValue( bPositive
667 ? C2U("PositiveError")
668 : C2U("NegativeError")) >>= fPercent
)
671 ::rtl::math::setInf(&fMaxValue
, true);
672 const double* pValues
= rData
.getConstArray();
673 for(sal_Int32 i
=0; i
<rData
.getLength(); ++i
, ++pValues
)
675 if(fMaxValue
<*pValues
)
678 if( ::rtl::math::isFinite( fMaxValue
) &&
679 ::rtl::math::isFinite( fPercent
))
681 fResult
= fMaxValue
* fPercent
/ 100.0;
686 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR
:
687 fResult
= StatisticsHelper::getStandardError( rData
);
689 case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA
:
691 uno::Reference
< chart2::data::XDataSource
> xErrorBarData( xProp
, uno::UNO_QUERY
);
692 if( xErrorBarData
.is())
693 fResult
= StatisticsHelper::getErrorFromDataSource(
694 xErrorBarData
, nIndex
, bPositive
, bYError
);
699 catch( const uno::Exception
& e
)
701 ASSERT_EXCEPTION( e
);
707 void lcl_AddErrorBottomLine( const drawing::Position3D
& rPosition
, ::basegfx::B2DVector aMainDirection
708 , drawing::PolyPolygonShape3D
& rPoly
, sal_Int32 nSequenceIndex
)
710 double fFixedWidth
= 200.0;
712 aMainDirection
.normalize();
713 ::basegfx::B2DVector
aOrthoDirection(-aMainDirection
.getY(),aMainDirection
.getX());
714 aOrthoDirection
.normalize();
716 ::basegfx::B2DVector
aAnchor( rPosition
.PositionX
, rPosition
.PositionY
);
717 ::basegfx::B2DVector aStart
= aAnchor
+ aOrthoDirection
*fFixedWidth
/2.0;
718 ::basegfx::B2DVector aEnd
= aAnchor
- aOrthoDirection
*fFixedWidth
/2.0;
720 AddPointToPoly( rPoly
, drawing::Position3D( aStart
.getX(), aStart
.getY(), rPosition
.PositionZ
), nSequenceIndex
);
721 AddPointToPoly( rPoly
, drawing::Position3D( aEnd
.getX(), aEnd
.getY(), rPosition
.PositionZ
), nSequenceIndex
);
724 ::basegfx::B2DVector
lcl_getErrorBarMainDirection(
725 const drawing::Position3D
& rStart
726 , const drawing::Position3D
& rBottomEnd
727 , PlottingPositionHelper
* pPosHelper
728 , const drawing::Position3D
& rUnscaledLogicPosition
731 ::basegfx::B2DVector aMainDirection
= ::basegfx::B2DVector( rStart
.PositionX
- rBottomEnd
.PositionX
732 , rStart
.PositionY
- rBottomEnd
.PositionY
);
733 if( !aMainDirection
.getLength() )
735 //get logic clip values:
736 double MinX
= pPosHelper
->getLogicMinX();
737 double MinY
= pPosHelper
->getLogicMinY();
738 double MaxX
= pPosHelper
->getLogicMaxX();
739 double MaxY
= pPosHelper
->getLogicMaxY();
740 double fZ
= pPosHelper
->getLogicMinZ();
745 //main direction has constant x value
746 MinX
= rUnscaledLogicPosition
.PositionX
;
747 MaxX
= rUnscaledLogicPosition
.PositionX
;
751 //main direction has constant y value
752 MinY
= rUnscaledLogicPosition
.PositionY
;
753 MaxY
= rUnscaledLogicPosition
.PositionY
;
756 drawing::Position3D aStart
= pPosHelper
->transformLogicToScene( MinX
, MinY
, fZ
, false );
757 drawing::Position3D aEnd
= pPosHelper
->transformLogicToScene( MaxX
, MaxY
, fZ
, false );
759 aMainDirection
= ::basegfx::B2DVector( aStart
.PositionX
- aEnd
.PositionX
760 , aStart
.PositionY
- aEnd
.PositionY
);
762 if( !aMainDirection
.getLength() )
766 return aMainDirection
;
769 drawing::Position3D
lcl_transformMixedToScene( PlottingPositionHelper
* pPosHelper
770 , double fX
/*scaled*/, double fY
/*unscaled*/, double fZ
/*unscaled*/, bool bClip
)
773 return drawing::Position3D(0,0,0);
774 pPosHelper
->doLogicScaling( 0,&fY
,&fZ
);
776 pPosHelper
->clipScaledLogicValues( &fX
,&fY
,&fZ
);
777 return pPosHelper
->transformScaledLogicToScene( fX
, fY
, fZ
, false );
780 } // anonymous namespace
782 void VSeriesPlotter::createErrorBar(
783 const uno::Reference
< drawing::XShapes
>& xTarget
784 , const drawing::Position3D
& rUnscaledLogicPosition
785 , const uno::Reference
< beans::XPropertySet
> & xErrorBarProperties
786 , const VDataSeries
& rVDataSeries
788 , bool bYError
/* = true */
789 , double* pfScaledLogicX
792 if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel
, m_nDimension
) )
795 if( ! xErrorBarProperties
.is())
800 sal_Bool bShowPositive
= sal_False
;
801 sal_Bool bShowNegative
= sal_False
;
802 sal_Int32 nErrorBarStyle
= ::com::sun::star::chart::ErrorBarStyle::VARIANCE
;
804 xErrorBarProperties
->getPropertyValue( C2U( "ShowPositiveError" )) >>= bShowPositive
;
805 xErrorBarProperties
->getPropertyValue( C2U( "ShowNegativeError" )) >>= bShowNegative
;
806 xErrorBarProperties
->getPropertyValue( C2U( "ErrorBarStyle" )) >>= nErrorBarStyle
;
808 if(!bShowPositive
&& !bShowNegative
)
811 if(nErrorBarStyle
==::com::sun::star::chart::ErrorBarStyle::NONE
)
814 drawing::Position3D
aUnscaledLogicPosition(rUnscaledLogicPosition
);
815 if(nErrorBarStyle
==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION
)
818 aUnscaledLogicPosition
.PositionY
= rVDataSeries
.getYMeanValue();
820 aUnscaledLogicPosition
.PositionX
= rVDataSeries
.getXMeanValue();
823 bool bCreateNegativeBorder
= false;//make a vertical line at the negative end of the error bar
824 bool bCreatePositiveBorder
= false;//make a vertical line at the positive end of the error bar
825 drawing::Position3D
aMiddle(aUnscaledLogicPosition
);
826 const double fX
= aUnscaledLogicPosition
.PositionX
;
827 const double fY
= aUnscaledLogicPosition
.PositionY
;
828 const double fZ
= aUnscaledLogicPosition
.PositionZ
;
829 double fScaledX
= fX
;
831 fScaledX
= *pfScaledLogicX
;
833 m_pPosHelper
->doLogicScaling( &fScaledX
, 0, 0 );
835 aMiddle
= lcl_transformMixedToScene( m_pPosHelper
, fScaledX
, fY
, fZ
, true );
837 drawing::Position3D
aNegative(aMiddle
);
838 drawing::Position3D
aPositive(aMiddle
);
840 uno::Sequence
< double > aData( bYError
? rVDataSeries
.getAllY() : rVDataSeries
.getAllX() );
844 double fLength
= lcl_getErrorBarLogicLength( aData
, xErrorBarProperties
, nErrorBarStyle
, nIndex
, true, bYError
);
845 if( ::rtl::math::isFinite( fLength
) )
852 aPositive
= lcl_transformMixedToScene( m_pPosHelper
, fScaledX
, fLocalY
, fZ
, true );
857 aPositive
= m_pPosHelper
->transformLogicToScene( fLocalX
, fLocalY
, fZ
, true );
859 bCreatePositiveBorder
= m_pPosHelper
->isLogicVisible(fLocalX
, fLocalY
, fZ
);
862 bShowPositive
= false;
867 double fLength
= lcl_getErrorBarLogicLength( aData
, xErrorBarProperties
, nErrorBarStyle
, nIndex
, false, bYError
);
868 if( ::rtl::math::isFinite( fLength
) )
875 aNegative
= lcl_transformMixedToScene( m_pPosHelper
, fScaledX
, fLocalY
, fZ
, true );
880 aNegative
= m_pPosHelper
->transformLogicToScene( fLocalX
, fLocalY
, fZ
, true );
882 bCreateNegativeBorder
= m_pPosHelper
->isLogicVisible( fLocalX
, fLocalY
, fZ
);
885 bShowNegative
= false;
888 if(!bShowPositive
&& !bShowNegative
)
891 drawing::PolyPolygonShape3D aPoly
;
893 sal_Int32 nSequenceIndex
=0;
895 AddPointToPoly( aPoly
, aNegative
, nSequenceIndex
);
896 AddPointToPoly( aPoly
, aMiddle
, nSequenceIndex
);
898 AddPointToPoly( aPoly
, aPositive
, nSequenceIndex
);
900 if( bShowNegative
&& bCreateNegativeBorder
)
902 ::basegfx::B2DVector aMainDirection
= lcl_getErrorBarMainDirection( aMiddle
, aNegative
, m_pPosHelper
, aUnscaledLogicPosition
, bYError
);
904 lcl_AddErrorBottomLine( aNegative
, aMainDirection
, aPoly
, nSequenceIndex
);
906 if( bShowPositive
&& bCreatePositiveBorder
)
908 ::basegfx::B2DVector aMainDirection
= lcl_getErrorBarMainDirection( aMiddle
, aPositive
, m_pPosHelper
, aUnscaledLogicPosition
, bYError
);
910 lcl_AddErrorBottomLine( aPositive
, aMainDirection
, aPoly
, nSequenceIndex
);
913 uno::Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D( xTarget
, PolyToPointSequence( aPoly
) );
914 this->setMappedProperties( xShape
, xErrorBarProperties
, PropertyMapper::getPropertyNameMapForLineProperties() );
916 catch( const uno::Exception
& e
)
918 ASSERT_EXCEPTION( e
);
923 void VSeriesPlotter::createErrorBar_X( const drawing::Position3D
& rUnscaledLogicPosition
924 , VDataSeries
& rVDataSeries
, sal_Int32 nPointIndex
925 , const uno::Reference
< drawing::XShapes
>& xTarget
926 , double* pfScaledLogicX
)
931 uno::Reference
< beans::XPropertySet
> xErrorBarProp(rVDataSeries
.getXErrorBarProperties(nPointIndex
));
932 if( xErrorBarProp
.is())
934 uno::Reference
< drawing::XShapes
> xErrorBarsGroup_Shapes(
935 this->getErrorBarsGroupShape(rVDataSeries
, xTarget
, false) );
937 createErrorBar( xErrorBarsGroup_Shapes
938 , rUnscaledLogicPosition
, xErrorBarProp
939 , rVDataSeries
, nPointIndex
940 , false /* bYError */
945 void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D
& rUnscaledLogicPosition
946 , VDataSeries
& rVDataSeries
, sal_Int32 nPointIndex
947 , const uno::Reference
< drawing::XShapes
>& xTarget
948 , double* pfScaledLogicX
)
953 uno::Reference
< beans::XPropertySet
> xErrorBarProp(rVDataSeries
.getYErrorBarProperties(nPointIndex
));
954 if( xErrorBarProp
.is())
956 uno::Reference
< drawing::XShapes
> xErrorBarsGroup_Shapes(
957 this->getErrorBarsGroupShape(rVDataSeries
, xTarget
, true) );
959 createErrorBar( xErrorBarsGroup_Shapes
960 , rUnscaledLogicPosition
, xErrorBarProp
961 , rVDataSeries
, nPointIndex
967 void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries
& rVDataSeries
968 , const uno::Reference
< drawing::XShapes
>& xTarget
969 , const uno::Reference
< drawing::XShapes
>& xEquationTarget
970 , bool bMaySkipPointsInRegressionCalculation
)
974 uno::Reference
< XRegressionCurveContainer
> xRegressionContainer(
975 rVDataSeries
.getModel(), uno::UNO_QUERY
);
976 if(!xRegressionContainer
.is())
978 double fMinX
= m_pPosHelper
->getLogicMinX();
979 double fMaxX
= m_pPosHelper
->getLogicMaxX();
981 uno::Sequence
< uno::Reference
< XRegressionCurve
> > aCurveList
=
982 xRegressionContainer
->getRegressionCurves();
983 for(sal_Int32 nN
=0; nN
<aCurveList
.getLength(); nN
++)
985 uno::Reference
< XRegressionCurveCalculator
> xRegressionCurveCalculator(
986 aCurveList
[nN
]->getCalculator() );
987 if( ! xRegressionCurveCalculator
.is())
989 xRegressionCurveCalculator
->recalculateRegression( rVDataSeries
.getAllX(), rVDataSeries
.getAllY() );
991 sal_Int32 nRegressionPointCount
= 50;//@todo find a more optimal solution if more complicated curve types are introduced
992 drawing::PolyPolygonShape3D aRegressionPoly
;
993 aRegressionPoly
.SequenceX
.realloc(1);
994 aRegressionPoly
.SequenceY
.realloc(1);
995 aRegressionPoly
.SequenceZ
.realloc(1);
996 aRegressionPoly
.SequenceX
[0].realloc(nRegressionPointCount
);
997 aRegressionPoly
.SequenceY
[0].realloc(nRegressionPointCount
);
998 aRegressionPoly
.SequenceZ
[0].realloc(nRegressionPointCount
);
999 sal_Int32 nRealPointCount
=0;
1001 std::vector
< ExplicitScaleData
> aScales( m_pPosHelper
->getScales());
1002 uno::Reference
< chart2::XScaling
> xScalingX
;
1003 uno::Reference
< chart2::XScaling
> xScalingY
;
1004 if( aScales
.size() >= 2 )
1006 xScalingX
.set( aScales
[0].Scaling
);
1007 xScalingY
.set( aScales
[1].Scaling
);
1010 uno::Sequence
< geometry::RealPoint2D
> aCalculatedPoints(
1011 xRegressionCurveCalculator
->getCurveValues(
1012 fMinX
, fMaxX
, nRegressionPointCount
, xScalingX
, xScalingY
, bMaySkipPointsInRegressionCalculation
));
1013 nRegressionPointCount
= aCalculatedPoints
.getLength();
1014 for(sal_Int32 nP
=0; nP
<nRegressionPointCount
; nP
++)
1016 double fLogicX
= aCalculatedPoints
[nP
].X
;
1017 double fLogicY
= aCalculatedPoints
[nP
].Y
;
1018 double fLogicZ
= 0.0;//dummy
1020 m_pPosHelper
->doLogicScaling( &fLogicX
, &fLogicY
, &fLogicZ
);
1022 if( !::rtl::math::isNan(fLogicX
) && !::rtl::math::isInf(fLogicX
)
1023 && !::rtl::math::isNan(fLogicY
) && !::rtl::math::isInf(fLogicY
)
1024 && !::rtl::math::isNan(fLogicZ
) && !::rtl::math::isInf(fLogicZ
) )
1026 aRegressionPoly
.SequenceX
[0][nRealPointCount
] = fLogicX
;
1027 aRegressionPoly
.SequenceY
[0][nRealPointCount
] = fLogicY
;
1031 aRegressionPoly
.SequenceX
[0].realloc(nRealPointCount
);
1032 aRegressionPoly
.SequenceY
[0].realloc(nRealPointCount
);
1033 aRegressionPoly
.SequenceZ
[0].realloc(nRealPointCount
);
1035 drawing::PolyPolygonShape3D aClippedPoly
;
1036 Clipping::clipPolygonAtRectangle( aRegressionPoly
, m_pPosHelper
->getScaledLogicClipDoubleRect(), aClippedPoly
);
1037 aRegressionPoly
= aClippedPoly
;
1038 m_pPosHelper
->transformScaledLogicToScene( aRegressionPoly
);
1040 awt::Point aDefaultPos
;
1041 if( aRegressionPoly
.SequenceX
.getLength() && aRegressionPoly
.SequenceX
[0].getLength() )
1043 uno::Reference
< beans::XPropertySet
> xCurveModelProp( aCurveList
[nN
], uno::UNO_QUERY
);
1044 VLineProperties aVLineProperties
;
1045 aVLineProperties
.initFromPropertySet( xCurveModelProp
);
1047 //create an extra group shape for each curve for selection handling
1048 bool bAverageLine
= RegressionCurveHelper::isMeanValueLine( aCurveList
[nN
] );
1049 uno::Reference
< drawing::XShapes
> xRegressionGroupShapes
=
1050 createGroupShape( xTarget
, rVDataSeries
.getDataCurveCID( nN
, bAverageLine
) );
1051 uno::Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D(
1052 xRegressionGroupShapes
, PolyToPointSequence( aRegressionPoly
), &aVLineProperties
);
1053 m_pShapeFactory
->setShapeName( xShape
, C2U("MarkHandles") );
1054 aDefaultPos
= xShape
->getPosition();
1057 // curve equation and correlation coefficient
1058 uno::Reference
< beans::XPropertySet
> xEqProp( aCurveList
[nN
]->getEquationProperties());
1061 createRegressionCurveEquationShapes(
1062 rVDataSeries
.getDataCurveEquationCID( nN
),
1063 xEqProp
, xEquationTarget
, xRegressionCurveCalculator
,
1069 void VSeriesPlotter::createRegressionCurveEquationShapes(
1070 const OUString
& rEquationCID
,
1071 const uno::Reference
< beans::XPropertySet
> & xEquationProperties
,
1072 const uno::Reference
< drawing::XShapes
>& xEquationTarget
,
1073 const uno::Reference
< chart2::XRegressionCurveCalculator
> & xRegressionCurveCalculator
,
1074 awt::Point aDefaultPos
)
1076 OSL_ASSERT( xEquationProperties
.is());
1077 if( !xEquationProperties
.is())
1080 bool bShowEquation
= false;
1081 bool bShowCorrCoeff
= false;
1082 OUString
aSep( sal_Unicode('\n'));
1083 if(( xEquationProperties
->getPropertyValue( C2U("ShowEquation")) >>= bShowEquation
) &&
1084 ( xEquationProperties
->getPropertyValue( C2U("ShowCorrelationCoefficient")) >>= bShowCorrCoeff
))
1086 if( ! (bShowEquation
|| bShowCorrCoeff
))
1089 ::rtl::OUStringBuffer aFormula
;
1090 sal_Int32 nNumberFormatKey
= 0;
1091 xEquationProperties
->getPropertyValue( C2U("NumberFormat")) >>= nNumberFormatKey
;
1095 if( m_apNumberFormatterWrapper
.get())
1097 aFormula
= xRegressionCurveCalculator
->getFormattedRepresentation(
1098 m_apNumberFormatterWrapper
->getNumberFormatsSupplier(),
1103 aFormula
= xRegressionCurveCalculator
->getRepresentation();
1106 if( bShowCorrCoeff
)
1108 aFormula
.append( aSep
);
1111 if( bShowCorrCoeff
)
1113 aFormula
.append( sal_Unicode( 'R' ));
1114 aFormula
.append( sal_Unicode( 0x00b2 ));
1115 aFormula
.append( C2U( " = " ));
1116 double fR( xRegressionCurveCalculator
->getCorrelationCoefficient());
1117 if( m_apNumberFormatterWrapper
.get())
1119 sal_Int32 nLabelCol
= 0;
1122 m_apNumberFormatterWrapper
->getFormattedString(
1123 nNumberFormatKey
, fR
*fR
, nLabelCol
, bColChanged
));
1124 //@todo: change color of label if bColChanged is true
1128 sal_Unicode
aDecimalSep( '.' );//@todo get this locale dependent
1129 aFormula
.append( ::rtl::math::doubleToUString(
1130 fR
*fR
, rtl_math_StringFormat_G
, 4, aDecimalSep
, true ));
1134 awt::Point aScreenPosition2D
;
1135 chart2::RelativePosition aRelativePosition
;
1136 if( xEquationProperties
->getPropertyValue( C2U("RelativePosition")) >>= aRelativePosition
)
1138 //@todo decide whether x is primary or secondary
1139 double fX
= aRelativePosition
.Primary
*m_aPageReferenceSize
.Width
;
1140 double fY
= aRelativePosition
.Secondary
*m_aPageReferenceSize
.Height
;
1141 aScreenPosition2D
.X
= static_cast< sal_Int32
>( ::rtl::math::round( fX
));
1142 aScreenPosition2D
.Y
= static_cast< sal_Int32
>( ::rtl::math::round( fY
));
1145 aScreenPosition2D
= aDefaultPos
;
1147 if( aFormula
.getLength())
1149 // set fill and line properties on creation
1150 tNameSequence aNames
;
1151 tAnySequence aValues
;
1152 PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties
, aNames
, aValues
);
1154 uno::Reference
< drawing::XShape
> xTextShape
= m_pShapeFactory
->createText(
1155 xEquationTarget
, aFormula
.makeStringAndClear(),
1156 aNames
, aValues
, ShapeFactory::makeTransformation( aScreenPosition2D
));
1158 OSL_ASSERT( xTextShape
.is());
1159 if( xTextShape
.is())
1161 ShapeFactory::setShapeName( xTextShape
, rEquationCID
);
1162 awt::Size
aSize( xTextShape
->getSize() );
1163 awt::Point
aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
1164 aScreenPosition2D
, aSize
, aRelativePosition
.Anchor
) );
1165 //ensure that the equation is fully placed within the page (if possible)
1166 if( (aPos
.X
+ aSize
.Width
) > m_aPageReferenceSize
.Width
)
1167 aPos
.X
= m_aPageReferenceSize
.Width
- aSize
.Width
;
1170 if( (aPos
.Y
+ aSize
.Height
) > m_aPageReferenceSize
.Height
)
1171 aPos
.Y
= m_aPageReferenceSize
.Height
- aSize
.Height
;
1174 xTextShape
->setPosition(aPos
);
1181 void VSeriesPlotter::setMappedProperties(
1182 const uno::Reference
< drawing::XShape
>& xTargetShape
1183 , const uno::Reference
< beans::XPropertySet
>& xSource
1184 , const tPropertyNameMap
& rMap
1185 , tPropertyNameValueMap
* pOverwriteMap
)
1187 uno::Reference
< beans::XPropertySet
> xTargetProp( xTargetShape
, uno::UNO_QUERY
);
1188 PropertyMapper::setMappedProperties(xTargetProp
,xSource
,rMap
,pOverwriteMap
);
1191 void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution
, const Date
& rNullDate
)
1193 m_nTimeResolution
= TimeResolution
;
1194 m_aNullDate
= rNullDate
;
1197 //-------------------------------------------------------------------------
1198 // MinimumAndMaximumSupplier
1199 //-------------------------------------------------------------------------
1200 long VSeriesPlotter::calculateTimeResolutionOnXAxis()
1202 long nRet
= ::com::sun::star::chart::TimeUnit::YEAR
;
1203 if( m_pExplicitCategoriesProvider
)
1205 const std::vector
< DatePlusIndex
>& rDateCategories
= m_pExplicitCategoriesProvider
->getDateCategories();
1206 std::vector
< DatePlusIndex
>::const_iterator aIt
= rDateCategories
.begin(), aEnd
= rDateCategories
.end();
1207 Date
aNullDate(30,12,1899);
1208 if( m_apNumberFormatterWrapper
.get() )
1209 aNullDate
= m_apNumberFormatterWrapper
->getNullDate();
1212 Date
aPrevious(aNullDate
); aPrevious
+=static_cast<long>(rtl::math::approxFloor(aIt
->fValue
));
1214 for(;aIt
!=aEnd
;++aIt
)
1216 Date
aCurrent(aNullDate
); aCurrent
+=static_cast<long>(rtl::math::approxFloor(aIt
->fValue
));
1217 if( ::com::sun::star::chart::TimeUnit::YEAR
== nRet
)
1219 if( DateHelper::IsInSameYear( aPrevious
, aCurrent
) )
1220 nRet
= ::com::sun::star::chart::TimeUnit::MONTH
;
1222 if( ::com::sun::star::chart::TimeUnit::MONTH
== nRet
)
1224 if( DateHelper::IsInSameMonth( aPrevious
, aCurrent
) )
1225 nRet
= ::com::sun::star::chart::TimeUnit::DAY
;
1227 if( ::com::sun::star::chart::TimeUnit::DAY
== nRet
)
1235 double VSeriesPlotter::getMinimumX()
1237 double fMinimum
, fMaximum
;
1238 this->getMinimumAndMaximiumX( fMinimum
, fMaximum
);
1241 double VSeriesPlotter::getMaximumX()
1243 double fMinimum
, fMaximum
;
1244 this->getMinimumAndMaximiumX( fMinimum
, fMaximum
);
1248 double VSeriesPlotter::getMinimumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1250 if( !m_bCategoryXAxis
|| ( m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->isDateAxis() ) )
1252 double fMinY
, fMaxY
;
1253 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1257 double fMinimum
, fMaximum
;
1258 ::rtl::math::setInf(&fMinimum
, false);
1259 ::rtl::math::setInf(&fMaximum
, true);
1260 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1262 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1263 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1265 double fLocalMinimum
, fLocalMaximum
;
1266 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1267 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1268 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1269 , isSeperateStackingForDifferentSigns( 1 )
1270 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1271 if(fMaximum
<fLocalMaximum
)
1272 fMaximum
=fLocalMaximum
;
1273 if(fMinimum
>fLocalMinimum
)
1274 fMinimum
=fLocalMinimum
;
1277 if(::rtl::math::isInf(fMinimum
))
1278 ::rtl::math::setNan(&fMinimum
);
1282 double VSeriesPlotter::getMaximumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1284 if( !m_bCategoryXAxis
|| ( m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->isDateAxis() ) )
1286 double fMinY
, fMaxY
;
1287 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1291 double fMinimum
, fMaximum
;
1292 ::rtl::math::setInf(&fMinimum
, false);
1293 ::rtl::math::setInf(&fMaximum
, true);
1294 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1296 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1297 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1299 double fLocalMinimum
, fLocalMaximum
;
1300 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1301 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1302 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1303 , isSeperateStackingForDifferentSigns( 1 )
1304 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1305 if(fMaximum
<fLocalMaximum
)
1306 fMaximum
=fLocalMaximum
;
1307 if(fMinimum
>fLocalMinimum
)
1308 fMinimum
=fLocalMinimum
;
1311 if(::rtl::math::isInf(fMaximum
))
1312 ::rtl::math::setNan(&fMaximum
);
1316 double VSeriesPlotter::getMinimumZ()
1318 //this is the default for all charts without a meaningfull z axis
1321 double VSeriesPlotter::getMaximumZ()
1323 if( 3!=m_nDimension
|| !m_aZSlots
.size() )
1324 return getMinimumZ()+1;
1325 return m_aZSlots
.size();
1330 bool lcl_isValueAxis( sal_Int32 nDimensionIndex
, bool bCategoryXAxis
)
1332 // default implementation: true for Y axes, and for value X axis
1333 if( nDimensionIndex
== 0 )
1334 return !bCategoryXAxis
;
1335 if( nDimensionIndex
== 1 )
1341 bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex
)
1343 return lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1346 bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex
)
1348 // do not expand axes in 3D charts
1349 return (m_nDimension
< 3) && lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1352 bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex
)
1354 // default implementation: only for Y axis
1355 return nDimensionIndex
== 1;
1358 bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex
)
1360 // default implementation: only for Y axis
1361 return nDimensionIndex
== 1;
1364 bool VSeriesPlotter::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex
)
1366 // default implementation: only for Y axis
1367 return nDimensionIndex
== 1;
1370 void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1372 ::rtl::math::setInf(&rfMinimum
, false);
1373 ::rtl::math::setInf(&rfMaximum
, true);
1375 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1376 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1377 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1379 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1380 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1381 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
1383 double fLocalMinimum
, fLocalMaximum
;
1384 aXSlotIter
->getMinimumAndMaximiumX( fLocalMinimum
, fLocalMaximum
);
1385 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinimum
)
1386 rfMinimum
= fLocalMinimum
;
1387 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaximum
)
1388 rfMaximum
= fLocalMaximum
;
1391 if(::rtl::math::isInf(rfMinimum
))
1392 ::rtl::math::setNan(&rfMinimum
);
1393 if(::rtl::math::isInf(rfMaximum
))
1394 ::rtl::math::setNan(&rfMaximum
);
1397 void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1399 ::rtl::math::setInf(&rfMinY
, false);
1400 ::rtl::math::setInf(&rfMaxY
, true);
1402 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1403 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1404 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1406 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1407 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1408 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
1410 double fLocalMinimum
, fLocalMaximum
;
1411 aXSlotIter
->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum
, fLocalMaximum
, fMinX
, fMaxX
, nAxisIndex
);
1412 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinY
)
1413 rfMinY
= fLocalMinimum
;
1414 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaxY
)
1415 rfMaxY
= fLocalMaximum
;
1418 if(::rtl::math::isInf(rfMinY
))
1419 ::rtl::math::setNan(&rfMinY
);
1420 if(::rtl::math::isInf(rfMaxY
))
1421 ::rtl::math::setNan(&rfMaxY
);
1424 sal_Int32
VSeriesPlotter::getPointCount() const
1428 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1429 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1431 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1433 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1434 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1436 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
1438 sal_Int32 nPointCount
= aXSlotIter
->getPointCount();
1439 if( nPointCount
>nRet
)
1446 void VSeriesPlotter::setNumberFormatsSupplier(
1447 const uno::Reference
< util::XNumberFormatsSupplier
> & xNumFmtSupplier
)
1449 m_apNumberFormatterWrapper
.reset( new NumberFormatterWrapper( xNumFmtSupplier
));
1452 void VSeriesPlotter::setColorScheme( const uno::Reference
< XColorScheme
>& xColorScheme
)
1454 m_xColorScheme
= xColorScheme
;
1457 void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider
* pExplicitCategoriesProvider
)
1459 m_pExplicitCategoriesProvider
= pExplicitCategoriesProvider
;
1462 sal_Int32
VDataSeriesGroup::getPointCount() const
1464 if(!m_bMaxPointCountDirty
)
1465 return m_nMaxPointCount
;
1468 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1469 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1471 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1473 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1474 if( nPointCount
>nRet
)
1477 m_nMaxPointCount
=nRet
;
1478 m_aListOfCachedYValues
.clear();
1479 m_aListOfCachedYValues
.resize(m_nMaxPointCount
);
1480 m_bMaxPointCountDirty
=false;
1484 sal_Int32
VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1487 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1488 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1490 if( aSeriesIter
!= aSeriesEnd
)
1491 nRet
= (*aSeriesIter
)->getAttachedAxisIndex();
1496 void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1498 const ::std::vector
< VDataSeries
* >* pSeriesList
= &this->m_aSeriesVector
;
1500 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1501 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1503 ::rtl::math::setInf(&rfMinimum
, false);
1504 ::rtl::math::setInf(&rfMaximum
, true);
1506 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1508 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1509 for(sal_Int32 nN
=0;nN
<nPointCount
;nN
++)
1511 double fX
= (*aSeriesIter
)->getXValue( nN
);
1512 if( ::rtl::math::isNan(fX
) )
1520 if(::rtl::math::isInf(rfMinimum
))
1521 ::rtl::math::setNan(&rfMinimum
);
1522 if(::rtl::math::isInf(rfMaximum
))
1523 ::rtl::math::setNan(&rfMaximum
);
1529 * Keep track of minimum and maximum Y values for one or more data series.
1530 * When multiple data series exist, that indicates that the data series are
1533 * <p>For each X value, we calculate separate Y value ranges for each data
1534 * series in the first pass. In the second pass, we calculate the minimum Y
1535 * value by taking the absolute minimum value of all data series, whereas
1536 * the maxium Y value is the sum of all the series maximum Y values.</p>
1538 * <p>Once that's done for all X values, the final min / max Y values get
1539 * calculated by taking the absolute min / max Y values across all the X
1542 class PerXMinMaxCalculator
1544 typedef std::pair
<double, double> MinMaxType
;
1545 typedef std::map
<size_t, MinMaxType
> SeriesMinMaxType
;
1546 typedef boost::ptr_map
<double, SeriesMinMaxType
> GroupMinMaxType
;
1547 typedef boost::unordered_map
<double, MinMaxType
> TotalStoreType
;
1548 GroupMinMaxType maSeriesGroup
;
1552 PerXMinMaxCalculator() : mnCurSeries(0) {}
1554 void nextSeries() { ++mnCurSeries
; }
1556 void setValue(double fX
, double fY
)
1558 SeriesMinMaxType
* pStore
= getByXValue(fX
); // get storage for given X value.
1560 // This shouldn't happen!
1563 SeriesMinMaxType::iterator it
= pStore
->lower_bound(mnCurSeries
);
1564 if (it
!= pStore
->end() && !pStore
->key_comp()(mnCurSeries
, it
->first
))
1566 MinMaxType
& r
= it
->second
;
1567 // A min-max pair already exists for this series. Update it.
1575 // No existing pair. Insert a new one.
1577 it
, SeriesMinMaxType::value_type(
1578 mnCurSeries
, MinMaxType(fY
,fY
)));
1582 void getTotalRange(double& rfMin
, double& rfMax
) const
1584 rtl::math::setNan(&rfMin
);
1585 rtl::math::setNan(&rfMax
);
1587 TotalStoreType aStore
;
1588 getTotalStore(aStore
);
1593 TotalStoreType::const_iterator it
= aStore
.begin(), itEnd
= aStore
.end();
1594 rfMin
= it
->second
.first
;
1595 rfMax
= it
->second
.second
;
1596 for (++it
; it
!= itEnd
; ++it
)
1598 if (rfMin
> it
->second
.first
)
1599 rfMin
= it
->second
.first
;
1600 if (rfMax
< it
->second
.second
)
1601 rfMax
= it
->second
.second
;
1607 * Parse all data and reduce them into a set of global Y value ranges per
1610 void getTotalStore(TotalStoreType
& rStore
) const
1612 TotalStoreType aStore
;
1613 GroupMinMaxType::const_iterator it
= maSeriesGroup
.begin(), itEnd
= maSeriesGroup
.end();
1614 for (; it
!= itEnd
; ++it
)
1616 double fX
= it
->first
;
1618 const SeriesMinMaxType
& rSeries
= *it
->second
;
1619 SeriesMinMaxType::const_iterator itSeries
= rSeries
.begin(), itSeriesEnd
= rSeries
.end();
1620 for (; itSeries
!= itSeriesEnd
; ++itSeries
)
1622 double fYMin
= itSeries
->second
.first
, fYMax
= itSeries
->second
.second
;
1623 TotalStoreType::iterator itr
= aStore
.find(fX
);
1624 if (itr
== aStore
.end())
1625 // New min-max pair for give X value.
1627 TotalStoreType::value_type(fX
, std::pair
<double,double>(fYMin
,fYMax
)));
1630 MinMaxType
& r
= itr
->second
;
1631 if (fYMin
< r
.first
)
1632 r
.first
= fYMin
; // min y-value
1634 r
.second
+= fYMax
; // accumulative max y-value.
1638 rStore
.swap(aStore
);
1641 SeriesMinMaxType
* getByXValue(double fX
)
1643 GroupMinMaxType::iterator it
= maSeriesGroup
.find(fX
);
1644 if (it
== maSeriesGroup
.end())
1646 std::pair
<GroupMinMaxType::iterator
,bool> r
=
1647 maSeriesGroup
.insert(fX
, new SeriesMinMaxType
);
1650 // insertion failed.
1662 void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
1663 double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1665 ::rtl::math::setNan(&rfMinY
);
1666 ::rtl::math::setNan(&rfMaxY
);
1668 if (m_aSeriesVector
.empty())
1669 // No data series. Bail out.
1672 PerXMinMaxCalculator aRangeCalc
;
1673 std::vector
<VDataSeries
*>::const_iterator it
= m_aSeriesVector
.begin(), itEnd
= m_aSeriesVector
.end();
1674 for (; it
!= itEnd
; ++it
)
1676 const VDataSeries
* pSeries
= *it
;
1680 for (sal_Int32 i
= 0, n
= pSeries
->getTotalPointCount(); i
< n
; ++i
)
1682 if (nAxisIndex
!= pSeries
->getAttachedAxisIndex())
1685 double fX
= pSeries
->getXValue(i
);
1686 if (rtl::math::isNan(fX
))
1689 if (fX
< fMinX
|| fX
> fMaxX
)
1690 // Outside specified X range. Skip it.
1693 double fY
= pSeries
->getYValue(i
);
1694 if (::rtl::math::isNan(fY
))
1697 aRangeCalc
.setValue(fX
, fY
);
1699 aRangeCalc
.nextSeries();
1702 aRangeCalc
.getTotalRange(rfMinY
, rfMaxY
);
1705 void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
1706 , bool bSeperateStackingForDifferentSigns
1707 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1709 ::rtl::math::setInf(&rfMinimumY
, false);
1710 ::rtl::math::setInf(&rfMaximumY
, true);
1712 sal_Int32 nPointCount
= getPointCount();//necessary to create m_aListOfCachedYValues
1713 if(nCategoryIndex
<0 || nCategoryIndex
>=nPointCount
|| m_aSeriesVector
.empty())
1716 CachedYValues aCachedYValues
= m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
];
1717 if( !aCachedYValues
.m_bValuesDirty
)
1719 //return cached values
1720 rfMinimumY
= aCachedYValues
.m_fMinimumY
;
1721 rfMaximumY
= aCachedYValues
.m_fMaximumY
;
1725 double fTotalSum
, fPositiveSum
, fNegativeSum
, fFirstPositiveY
, fFirstNegativeY
;
1726 ::rtl::math::setNan( &fTotalSum
);
1727 ::rtl::math::setNan( &fPositiveSum
);
1728 ::rtl::math::setNan( &fNegativeSum
);
1729 ::rtl::math::setNan( &fFirstPositiveY
);
1730 ::rtl::math::setNan( &fFirstNegativeY
);
1732 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1733 ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1735 if( bSeperateStackingForDifferentSigns
)
1737 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1739 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1742 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1743 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1745 if( fValueMaxY
>= 0 )
1747 if( ::rtl::math::isNan( fPositiveSum
) )
1748 fPositiveSum
= fFirstPositiveY
= fValueMaxY
;
1750 fPositiveSum
+= fValueMaxY
;
1752 if( fValueMinY
< 0 )
1754 if(::rtl::math::isNan( fNegativeSum
))
1755 fNegativeSum
= fFirstNegativeY
= fValueMinY
;
1757 fNegativeSum
+= fValueMinY
;
1760 rfMinimumY
= ::rtl::math::isNan( fNegativeSum
) ? fFirstPositiveY
: fNegativeSum
;
1761 rfMaximumY
= ::rtl::math::isNan( fPositiveSum
) ? fFirstNegativeY
: fPositiveSum
;
1765 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1767 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1770 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1771 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1773 if( ::rtl::math::isNan( fTotalSum
) )
1775 rfMinimumY
= fValueMinY
;
1776 rfMaximumY
= fTotalSum
= fValueMaxY
;
1780 fTotalSum
+= fValueMaxY
;
1781 if( rfMinimumY
> fTotalSum
)
1782 rfMinimumY
= fTotalSum
;
1783 if( rfMaximumY
< fTotalSum
)
1784 rfMaximumY
= fTotalSum
;
1789 aCachedYValues
.m_fMinimumY
= rfMinimumY
;
1790 aCachedYValues
.m_fMaximumY
= rfMaximumY
;
1791 aCachedYValues
.m_bValuesDirty
= false;
1792 m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
]=aCachedYValues
;
1795 void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
1796 sal_Int32 nStartCategoryIndex
, sal_Int32 nEndCategoryIndex
1797 , bool bSeperateStackingForDifferentSigns
1798 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1800 //@todo maybe cache these values
1801 ::rtl::math::setInf(&rfMinimumY
, false);
1802 ::rtl::math::setInf(&rfMaximumY
, true);
1804 //iterate through the given categories
1805 if(nStartCategoryIndex
<0)
1806 nStartCategoryIndex
=0;
1807 if(nEndCategoryIndex
<0)
1808 nEndCategoryIndex
=0;
1809 for( sal_Int32 nCatIndex
= nStartCategoryIndex
; nCatIndex
<= nEndCategoryIndex
; nCatIndex
++ )
1811 double fMinimumY
; ::rtl::math::setNan(&fMinimumY
);
1812 double fMaximumY
; ::rtl::math::setNan(&fMaximumY
);
1814 this->calculateYMinAndMaxForCategory( nCatIndex
1815 , bSeperateStackingForDifferentSigns
, fMinimumY
, fMaximumY
, nAxisIndex
);
1817 if(rfMinimumY
> fMinimumY
)
1818 rfMinimumY
= fMinimumY
;
1819 if(rfMaximumY
< fMaximumY
)
1820 rfMaximumY
= fMaximumY
;
1824 double VSeriesPlotter::getTransformedDepth() const
1826 double MinZ
= m_pMainPosHelper
->getLogicMinZ();
1827 double MaxZ
= m_pMainPosHelper
->getLogicMaxZ();
1828 m_pMainPosHelper
->doLogicScaling( 0, 0, &MinZ
);
1829 m_pMainPosHelper
->doLogicScaling( 0, 0, &MaxZ
);
1830 return FIXED_SIZE_FOR_3D_CHART_VOLUME
/(MaxZ
-MinZ
);
1833 void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData
& rScale
, sal_Int32 nAxisIndex
)
1834 throw (uno::RuntimeException
)
1839 m_aSecondaryValueScales
[nAxisIndex
]=rScale
;
1842 PlottingPositionHelper
& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex
) const
1844 PlottingPositionHelper
* pRet
= 0;
1847 tSecondaryPosHelperMap::const_iterator aPosIt
= m_aSecondaryPosHelperMap
.find( nAxisIndex
);
1848 if( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
1850 pRet
= aPosIt
->second
;
1854 tSecondaryValueScales::const_iterator aScaleIt
= m_aSecondaryValueScales
.find( nAxisIndex
);
1855 if( aScaleIt
!= m_aSecondaryValueScales
.end() )
1857 pRet
= m_pPosHelper
->createSecondaryPosHelper( aScaleIt
->second
);
1858 m_aSecondaryPosHelperMap
[nAxisIndex
] = pRet
;
1863 pRet
= m_pMainPosHelper
;
1865 pRet
->setTimeResolution( m_nTimeResolution
, m_aNullDate
);
1869 void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size
& /*rPageSize*/ )
1873 VDataSeries
* VSeriesPlotter::getFirstSeries() const
1875 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1876 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1877 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1879 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1880 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1882 if( aXSlotIter
!= aXSlotEnd
)
1884 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1885 if( aSeriesGroup
.m_aSeriesVector
.size() )
1887 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1896 uno::Sequence
< rtl::OUString
> VSeriesPlotter::getSeriesNames() const
1898 ::std::vector
< rtl::OUString
> aRetVector
;
1900 rtl::OUString aRole
;
1901 if( m_xChartTypeModel
.is() )
1902 aRole
= m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel();
1904 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1905 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1906 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1908 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1909 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1911 if( aXSlotIter
!= aXSlotEnd
)
1913 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1914 if( aSeriesGroup
.m_aSeriesVector
.size() )
1916 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1917 uno::Reference
< XDataSeries
> xSeries( pSeries
? pSeries
->getModel() : 0 );
1920 rtl::OUString
aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries
, aRole
) );
1921 aRetVector
.push_back( aSeriesName
);
1926 return ContainerHelper::ContainerToSequence( aRetVector
);
1931 struct lcl_setRefSizeAtSeriesGroup
: public ::std::unary_function
< VDataSeriesGroup
, void >
1933 lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize
) : m_aRefSize( aRefSize
) {}
1934 void operator()( VDataSeriesGroup
& rGroup
)
1936 ::std::vector
< VDataSeries
* >::iterator
aIt( rGroup
.m_aSeriesVector
.begin());
1937 const ::std::vector
< VDataSeries
* >::iterator
aEndIt( rGroup
.m_aSeriesVector
.end());
1938 for( ; aIt
!= aEndIt
; ++aIt
)
1939 (*aIt
)->setPageReferenceSize( m_aRefSize
);
1943 awt::Size m_aRefSize
;
1945 } // anonymous namespace
1947 void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size
& rPageRefSize
)
1949 m_aPageReferenceSize
= rPageRefSize
;
1951 // set reference size also at all data series
1953 ::std::vector
< VDataSeriesGroup
> aSeriesGroups( FlattenVector( m_aZSlots
));
1954 ::std::for_each( aSeriesGroups
.begin(), aSeriesGroups
.end(),
1955 lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize
));
1958 //better performance for big data
1959 void VSeriesPlotter::setCoordinateSystemResolution( const Sequence
< sal_Int32
>& rCoordinateSystemResolution
)
1961 m_aCoordinateSystemResolution
= rCoordinateSystemResolution
;
1964 bool VSeriesPlotter::PointsWereSkipped() const
1966 return m_bPointsWereSkipped
;
1969 bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
1971 return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel
);
1974 bool VSeriesPlotter::shouldSnapRectToUsedArea()
1976 if( m_nDimension
== 3 )
1981 std::vector
< ViewLegendEntry
> VSeriesPlotter::createLegendEntries(
1982 const awt::Size
& rEntryKeyAspectRatio
1983 , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion
1984 , const Reference
< beans::XPropertySet
>& xTextProperties
1985 , const Reference
< drawing::XShapes
>& xTarget
1986 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
1987 , const Reference
< uno::XComponentContext
>& xContext
1990 std::vector
< ViewLegendEntry
> aResult
;
1994 //iterate through all series
1995 bool bBreak
= false;
1996 bool bFirstSeries
= true;
1997 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
1998 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1999 for( ; aZSlotIter
!=aZSlotEnd
&& !bBreak
; ++aZSlotIter
)
2001 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
2002 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
2003 for( ; aXSlotIter
!=aXSlotEnd
&& !bBreak
; ++aXSlotIter
)
2005 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
2006 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
2007 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
2008 //iterate through all series in this x slot
2009 for( ; aSeriesIter
!=aSeriesEnd
&& !bBreak
; ++aSeriesIter
)
2011 VDataSeries
* pSeries( *aSeriesIter
);
2015 std::vector
< ViewLegendEntry
> aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio
,
2016 *pSeries
, xTextProperties
, xTarget
, xShapeFactory
, xContext
) );
2018 //add series entries to the result now
2020 // use only the first series if VaryColorsByPoint is set for the first series
2021 if( bFirstSeries
&& pSeries
->isVaryColorsByPoint() )
2023 bFirstSeries
= false;
2025 // add entries reverse if chart is stacked in y-direction and the legend is not wide.
2026 // If the legend is wide and we have a stacked bar-chart the normal order
2027 // is the correct one
2028 bool bReverse
= false;
2029 if( eLegendExpansion
!= ::com::sun::star::chart::ChartLegendExpansion_WIDE
)
2031 StackingDirection
eStackingDirection( pSeries
->getStackingDirection() );
2032 bReverse
= ( eStackingDirection
== StackingDirection_Y_STACKING
);
2034 //todo: respect direction of axis in future
2038 aResult
.insert( aResult
.begin(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
2040 aResult
.insert( aResult
.end(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
2049 ::std::vector
< VDataSeries
* > VSeriesPlotter::getAllSeries()
2051 ::std::vector
< VDataSeries
* > aAllSeries
;
2052 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
2053 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
2054 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
2056 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
2057 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
2058 for( ; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
2060 ::std::vector
< VDataSeries
* > aSeriesList
= aXSlotIter
->m_aSeriesVector
;
2061 aAllSeries
.insert( aAllSeries
.end(), aSeriesList
.begin(), aSeriesList
.end() );
2069 bool lcl_HasVisibleLine( const uno::Reference
< beans::XPropertySet
>& xProps
, bool& rbHasDashedLine
)
2071 bool bHasVisibleLine
= false;
2072 rbHasDashedLine
= false;
2073 drawing::LineStyle aLineStyle
= drawing::LineStyle_NONE
;
2074 if( xProps
.is() && ( xProps
->getPropertyValue( C2U("LineStyle")) >>= aLineStyle
) )
2076 if( aLineStyle
!= drawing::LineStyle_NONE
)
2077 bHasVisibleLine
= true;
2078 if( aLineStyle
== drawing::LineStyle_DASH
)
2079 rbHasDashedLine
= true;
2081 return bHasVisibleLine
;
2084 bool lcl_HasRegressionCurves( const VDataSeries
& rSeries
, bool& rbHasDashedLine
)
2086 bool bHasRegressionCurves
= false;
2087 Reference
< XRegressionCurveContainer
> xRegrCont( rSeries
.getModel(), uno::UNO_QUERY
);
2090 Sequence
< Reference
< XRegressionCurve
> > aCurves( xRegrCont
->getRegressionCurves() );
2091 sal_Int32 i
= 0, nCount
= aCurves
.getLength();
2092 for( i
=0; i
<nCount
; ++i
)
2094 if( aCurves
[i
].is() )
2096 bHasRegressionCurves
= true;
2097 lcl_HasVisibleLine( uno::Reference
< beans::XPropertySet
>( aCurves
[i
], uno::UNO_QUERY
), rbHasDashedLine
);
2101 return bHasRegressionCurves
;
2104 LegendSymbolStyle
VSeriesPlotter::getLegendSymbolStyle()
2106 return LegendSymbolStyle_BOX
;
2109 awt::Size
VSeriesPlotter::getPreferredLegendKeyAspectRatio()
2111 awt::Size
aRet(1000,1000);
2112 if( m_nDimension
==3 )
2115 bool bSeriesAllowsLines
= (getLegendSymbolStyle() == LegendSymbolStyle_LINE
);
2116 bool bHasLines
= false;
2117 bool bHasDashedLines
= false;
2118 ::std::vector
< VDataSeries
* > aAllSeries( getAllSeries() );
2119 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= aAllSeries
.begin();
2120 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= aAllSeries
.end();
2121 //iterate through all series
2122 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
2124 if( bSeriesAllowsLines
)
2126 bool bCurrentDashed
= false;
2127 if( lcl_HasVisibleLine( (*aSeriesIter
)->getPropertiesOfSeries(), bCurrentDashed
) )
2130 if( bCurrentDashed
)
2132 bHasDashedLines
= true;
2137 bool bRegressionHasDashedLines
=false;
2138 if( lcl_HasRegressionCurves( **aSeriesIter
, bRegressionHasDashedLines
) )
2141 if( bRegressionHasDashedLines
)
2143 bHasDashedLines
= true;
2150 if( bHasDashedLines
)
2151 aRet
= awt::Size(1600,-1);
2153 aRet
= awt::Size(800,-1);
2158 uno::Any
VSeriesPlotter::getExplicitSymbol( const VDataSeries
& /*rSeries*/, sal_Int32
/*nPointIndex*/ )
2163 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForSeries(
2164 const awt::Size
& rEntryKeyAspectRatio
2165 , const VDataSeries
& rSeries
2166 , const Reference
< drawing::XShapes
>& xTarget
2167 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
2170 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
2171 uno::Any
aExplicitSymbol( this->getExplicitSymbol( rSeries
) );
2173 VLegendSymbolFactory::tPropertyType ePropType
=
2174 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
2176 // todo: maybe the property-style does not solely depend on the
2177 // legend-symbol type
2178 switch( eLegendSymbolStyle
)
2180 case LegendSymbolStyle_LINE
:
2181 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
2186 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio
,
2187 xTarget
, eLegendSymbolStyle
, xShapeFactory
2188 , rSeries
.getPropertiesOfSeries(), ePropType
, aExplicitSymbol
));
2193 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForPoint(
2194 const awt::Size
& rEntryKeyAspectRatio
2195 , const VDataSeries
& rSeries
2196 , sal_Int32 nPointIndex
2197 , const Reference
< drawing::XShapes
>& xTarget
2198 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
2201 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
2202 uno::Any
aExplicitSymbol( this->getExplicitSymbol(rSeries
,nPointIndex
) );
2204 VLegendSymbolFactory::tPropertyType ePropType
=
2205 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
2207 // todo: maybe the property-style does not solely depend on the
2208 // legend-symbol type
2209 switch( eLegendSymbolStyle
)
2211 case LegendSymbolStyle_LINE
:
2212 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
2218 // the default properties for the data point are the data series properties.
2219 // If a data point has own attributes overwrite them
2220 Reference
< beans::XPropertySet
> xSeriesProps( rSeries
.getPropertiesOfSeries() );
2221 Reference
< beans::XPropertySet
> xPointSet( xSeriesProps
);
2222 if( rSeries
.isAttributedDataPoint( nPointIndex
) )
2223 xPointSet
.set( rSeries
.getPropertiesOfPoint( nPointIndex
));
2225 // if a data point has no own color use a color fom the diagram's color scheme
2226 if( ! rSeries
.hasPointOwnColor( nPointIndex
))
2228 Reference
< util::XCloneable
> xCloneable( xPointSet
,uno::UNO_QUERY
);
2229 if( xCloneable
.is() && m_xColorScheme
.is() )
2231 xPointSet
.set( xCloneable
->createClone(), uno::UNO_QUERY
);
2232 Reference
< container::XChild
> xChild( xPointSet
, uno::UNO_QUERY
);
2234 xChild
->setParent( xSeriesProps
);
2236 OSL_ASSERT( xPointSet
.is());
2237 xPointSet
->setPropertyValue(
2238 C2U("Color"), uno::makeAny( m_xColorScheme
->getColorByIndex( nPointIndex
)));
2242 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio
,
2243 xTarget
, eLegendSymbolStyle
, xShapeFactory
, xPointSet
, ePropType
, aExplicitSymbol
));
2248 std::vector
< ViewLegendEntry
> VSeriesPlotter::createLegendEntriesForSeries(
2249 const awt::Size
& rEntryKeyAspectRatio
2250 , const VDataSeries
& rSeries
2251 , const Reference
< beans::XPropertySet
>& xTextProperties
2252 , const Reference
< drawing::XShapes
>& xTarget
2253 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
2254 , const Reference
< uno::XComponentContext
>& xContext
2257 std::vector
< ViewLegendEntry
> aResult
;
2259 if( ! ( xShapeFactory
.is() && xTarget
.is() && xContext
.is() ) )
2264 ViewLegendEntry aEntry
;
2265 OUString aLabelText
;
2266 bool bVaryColorsByPoint
= rSeries
.isVaryColorsByPoint();
2267 if( bVaryColorsByPoint
)
2269 Sequence
< OUString
> aCategoryNames
;
2270 if( m_pExplicitCategoriesProvider
)
2271 aCategoryNames
= m_pExplicitCategoriesProvider
->getSimpleCategories();
2273 for( sal_Int32 nIdx
=0; nIdx
<aCategoryNames
.getLength(); ++nIdx
)
2276 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
2278 // create the symbol
2279 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio
,
2280 rSeries
, nIdx
, xSymbolGroup
, xShapeFactory
) );
2282 // set CID to symbol for selection
2285 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2287 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT
, nIdx
) );
2288 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2289 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2290 ShapeFactory::setShapeName( xShape
, aCID
);
2294 aLabelText
= aCategoryNames
[nIdx
];
2295 if( xShape
.is() || !aLabelText
.isEmpty() )
2297 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
2298 aResult
.push_back(aEntry
);
2305 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
2307 // create the symbol
2308 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForSeries(
2309 rEntryKeyAspectRatio
, rSeries
, xSymbolGroup
, xShapeFactory
) );
2311 // set CID to symbol for selection
2314 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2316 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2317 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2318 ShapeFactory::setShapeName( xShape
, aCID
);
2322 aLabelText
= ( DataSeriesHelper::getDataSeriesLabel( rSeries
.getModel(), m_xChartTypeModel
.is() ? m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel() : C2U("values-y")) );
2323 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
2325 aResult
.push_back(aEntry
);
2328 // don't show legend entry of regression curve & friends if this type of chart
2329 // doesn't support statistics #i63016#, fdo#37197
2330 if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel
, m_nDimension
))
2333 Reference
< XRegressionCurveContainer
> xRegrCont( rSeries
.getModel(), uno::UNO_QUERY
);
2336 Sequence
< Reference
< XRegressionCurve
> > aCurves( xRegrCont
->getRegressionCurves());
2337 sal_Int32 i
= 0, nCount
= aCurves
.getLength();
2338 for( i
=0; i
<nCount
; ++i
)
2340 if( aCurves
[i
].is() )
2343 OUString
aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves
[i
] ) );
2344 replaceParamterInString( aResStr
, C2U("%SERIESNAME"), aLabelText
);
2345 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aResStr
, xTextProperties
);
2348 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
2350 // create the symbol
2351 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio
,
2352 xSymbolGroup
, LegendSymbolStyle_LINE
, xShapeFactory
,
2353 Reference
< beans::XPropertySet
>( aCurves
[i
], uno::UNO_QUERY
),
2354 VLegendSymbolFactory::PROP_TYPE_LINE
, uno::Any() ));
2356 // set CID to symbol for selection
2359 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2361 bool bAverageLine
= RegressionCurveHelper::isMeanValueLine( aCurves
[i
] );
2362 ObjectType eObjectType
= bAverageLine
? OBJECTTYPE_DATA_AVERAGE_LINE
: OBJECTTYPE_DATA_CURVE
;
2363 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType
, i
) );
2364 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2365 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2366 ShapeFactory::setShapeName( xShape
, aCID
);
2369 aResult
.push_back(aEntry
);
2374 catch( const uno::Exception
& ex
)
2376 ASSERT_EXCEPTION( ex
);
2381 VSeriesPlotter
* VSeriesPlotter::createSeriesPlotter(
2382 const uno::Reference
<XChartType
>& xChartTypeModel
2383 , sal_Int32 nDimensionCount
2384 , bool bExcludingPositioning
)
2386 rtl::OUString aChartType
= xChartTypeModel
->getChartType();
2388 //@todo: in future the plotter should be instanciated via service factory
2389 VSeriesPlotter
* pRet
=NULL
;
2390 if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN
) )
2391 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2392 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR
) )
2393 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2394 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA
) )
2395 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true);
2396 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE
) )
2397 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true);
2398 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER
) )
2399 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2400 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE
) )
2401 pRet
= new BubbleChart(xChartTypeModel
,nDimensionCount
);
2402 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE
) )
2403 pRet
= new PieChart(xChartTypeModel
,nDimensionCount
, bExcludingPositioning
);
2404 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET
) )
2405 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
2406 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET
) )
2407 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,false,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
2408 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK
) )
2409 pRet
= new CandleStickChart(xChartTypeModel
,nDimensionCount
);
2411 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2415 //.............................................................................
2417 //.............................................................................
2419 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */