1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: VSeriesPlotter.cxx,v $
10 * $Revision: 1.44.8.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_chart2.hxx"
35 #include "VSeriesPlotter.hxx"
36 #include "ShapeFactory.hxx"
37 #include "chartview/ExplicitValueProvider.hxx"
39 #include "CommonConverters.hxx"
41 #include "ViewDefines.hxx"
42 #include "ObjectIdentifier.hxx"
43 #include "StatisticsHelper.hxx"
44 #include "PlottingPositionHelper.hxx"
45 #include "LabelPositionHelper.hxx"
46 #include "ChartTypeHelper.hxx"
47 #include "Clipping.hxx"
48 #include "servicenames_charttypes.hxx"
49 #include "chartview/NumberFormatterWrapper.hxx"
50 #include "ContainerHelper.hxx"
51 #include "DataSeriesHelper.hxx"
52 #include "RegressionCurveHelper.hxx"
53 #include "VLegendSymbolFactory.hxx"
54 #include "FormattedStringHelper.hxx"
56 #include "Strings.hrc"
57 #include "RelativePositionHelper.hxx"
59 //only for creation: @todo remove if all plotter are uno components and instanciated via servicefactory
60 #include "BarChart.hxx"
61 #include "PieChart.hxx"
62 #include "AreaChart.hxx"
63 #include "CandleStickChart.hxx"
64 #include "BubbleChart.hxx"
67 #include <com/sun/star/chart/ErrorBarStyle.hpp>
68 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
69 #include <com/sun/star/container/XChild.hpp>
70 #include <com/sun/star/chart2/RelativePosition.hpp>
71 #include <svx/unoprnms.hxx>
72 #include <tools/color.hxx>
73 // header for class OUStringBuffer
74 #include <rtl/ustrbuf.hxx>
75 #include <rtl/math.hxx>
76 #include <tools/debug.hxx>
77 #include <basegfx/vector/b2dvector.hxx>
78 #include <com/sun/star/util/XCloneable.hpp>
80 #include <svx/unoshape.hxx>
84 //.............................................................................
87 //.............................................................................
88 using namespace ::com::sun::star
;
89 using namespace ::com::sun::star::chart2
;
90 using ::com::sun::star::uno::Reference
;
91 using ::com::sun::star::uno::Sequence
;
94 //-----------------------------------------------------------------------------
95 //-----------------------------------------------------------------------------
96 //-----------------------------------------------------------------------------
98 VDataSeriesGroup::CachedYValues::CachedYValues()
99 : m_bValuesDirty(true)
105 VDataSeriesGroup::VDataSeriesGroup()
107 , m_bMaxPointCountDirty(true)
108 , m_nMaxPointCount(0)
109 , m_aListOfCachedYValues()
114 VDataSeriesGroup::VDataSeriesGroup( VDataSeries
* pSeries
)
115 : m_aSeriesVector(1,pSeries
)
116 , m_bMaxPointCountDirty(true)
117 , m_nMaxPointCount(0)
118 , m_aListOfCachedYValues()
122 VDataSeriesGroup::~VDataSeriesGroup()
126 void VDataSeriesGroup::deleteSeries()
128 //delete all data series help objects:
129 ::std::vector
< VDataSeries
* >::const_iterator aIter
= m_aSeriesVector
.begin();
130 const ::std::vector
< VDataSeries
* >::const_iterator aEnd
= m_aSeriesVector
.end();
131 for( ; aIter
!= aEnd
; aIter
++ )
135 m_aSeriesVector
.clear();
138 void VDataSeriesGroup::addSeries( VDataSeries
* pSeries
)
140 m_aSeriesVector
.push_back(pSeries
);
141 m_bMaxPointCountDirty
=true;
144 sal_Int32
VDataSeriesGroup::getSeriesCount() const
146 return m_aSeriesVector
.size();
149 //-----------------------------------------------------------------------------
150 //-----------------------------------------------------------------------------
151 //-----------------------------------------------------------------------------
153 VSeriesPlotter::VSeriesPlotter( const uno::Reference
<XChartType
>& xChartTypeModel
154 , sal_Int32 nDimensionCount
, bool bCategoryXAxis
)
155 : PlotterBase( nDimensionCount
)
156 , m_pMainPosHelper( 0 )
157 , m_xChartTypeModel(xChartTypeModel
)
158 , m_xChartTypeModelProps( uno::Reference
< beans::XPropertySet
>::query( xChartTypeModel
))
160 , m_bCategoryXAxis(bCategoryXAxis
)
162 , m_xExplicitCategoriesProvider()
163 , m_bPointsWereSkipped(false)
165 DBG_ASSERT(m_xChartTypeModel
.is(),"no XChartType available in view, fallback to default values may be wrong");
168 VSeriesPlotter::~VSeriesPlotter()
170 //delete all data series help objects:
171 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
172 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
173 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
175 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
176 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
177 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
179 aXSlotIter
->deleteSeries();
185 tSecondaryPosHelperMap::iterator aPosIt
= m_aSecondaryPosHelperMap
.begin();
186 while( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
188 PlottingPositionHelper
* pPosHelper
= aPosIt
->second
;
193 m_aSecondaryPosHelperMap
.clear();
195 m_aSecondaryValueScales
.clear();
198 void VSeriesPlotter::addSeries( VDataSeries
* pSeries
, sal_Int32 zSlot
, sal_Int32 xSlot
, sal_Int32 ySlot
)
200 //take ownership of pSeries
202 DBG_ASSERT( pSeries
, "series to add is NULL" );
207 pSeries
->setCategoryXAxis();
209 if(zSlot
<0 || zSlot
>=static_cast<sal_Int32
>(m_aZSlots
.size()))
212 ::std::vector
< VDataSeriesGroup
> aZSlot
;
213 aZSlot
.push_back( VDataSeriesGroup(pSeries
) );
214 m_aZSlots
.push_back( aZSlot
);
219 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[zSlot
];
221 if(xSlot
<0 || xSlot
>=static_cast<sal_Int32
>(rXSlots
.size()))
223 //append the series to already existing x series
224 rXSlots
.push_back( VDataSeriesGroup(pSeries
) );
228 //x slot is already occupied
229 //y slot decides what to do:
231 VDataSeriesGroup
& rYSlots
= rXSlots
[xSlot
];
232 sal_Int32 nYSlotCount
= rYSlots
.getSeriesCount();
236 //move all existing series in the xSlot to next slot
238 OSL_ENSURE( false, "Not implemented yet");
240 else if( ySlot
== -1 || ySlot
>= nYSlotCount
)
242 //append the series to already existing y series
243 rYSlots
.addSeries(pSeries
);
247 //y slot is already occupied
248 //insert at given y and x position
251 OSL_ENSURE( false, "Not implemented yet");
257 drawing::Direction3D
VSeriesPlotter::getPreferredDiagramAspectRatio() const
259 drawing::Direction3D
aRet(1.0,1.0,1.0);
260 drawing::Direction3D
aScale( m_pPosHelper
->getScaledLogicWidth() );
261 aRet
.DirectionZ
= aScale
.DirectionZ
*0.2;
262 if(aRet
.DirectionZ
>1.0)
264 if(aRet
.DirectionZ
>10)
269 bool VSeriesPlotter::keepAspectRatio() const
274 void VSeriesPlotter::releaseShapes()
276 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
277 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
278 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
280 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
281 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
282 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
284 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
286 ::std::vector
< VDataSeries
* >::iterator aSeriesIter
= pSeriesList
->begin();
287 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
289 //iterate through all series in this x slot
290 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
292 VDataSeries
* pSeries( *aSeriesIter
);
293 pSeries
->releaseShapes();
299 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShape( VDataSeries
* pDataSeries
300 , const uno::Reference
< drawing::XShapes
>& xTarget
)
302 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xGroupShape
);
305 //create a group shape for this series and add to logic target:
306 xShapes
= createGroupShape( xTarget
,pDataSeries
->getCID() );
307 pDataSeries
->m_xGroupShape
= xShapes
;
312 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries
* pDataSeries
313 , const uno::Reference
< drawing::XShapes
>& xTarget
)
315 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xFrontSubGroupShape
);
318 //ensure that the series group shape is already created
319 uno::Reference
< drawing::XShapes
> xSeriesShapes( this->getSeriesGroupShape( pDataSeries
, xTarget
) );
320 //ensure that the back child is created first
321 this->getSeriesGroupShapeBackChild( pDataSeries
, xTarget
);
322 //use series group shape as parent for the new created front group shape
323 xShapes
= createGroupShape( xSeriesShapes
);
324 pDataSeries
->m_xFrontSubGroupShape
= xShapes
;
329 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries
* pDataSeries
330 , const uno::Reference
< drawing::XShapes
>& xTarget
)
332 uno::Reference
< drawing::XShapes
> xShapes( pDataSeries
->m_xBackSubGroupShape
);
335 //ensure that the series group shape is already created
336 uno::Reference
< drawing::XShapes
> xSeriesShapes( this->getSeriesGroupShape( pDataSeries
, xTarget
) );
337 //use series group shape as parent for the new created back group shape
338 xShapes
= createGroupShape( xSeriesShapes
);
339 pDataSeries
->m_xBackSubGroupShape
= xShapes
;
344 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getLabelsGroupShape( VDataSeries
& rDataSeries
345 , const uno::Reference
< drawing::XShapes
>& xTextTarget
)
347 //xTextTarget needs to be a 2D shape container always!
349 uno::Reference
< drawing::XShapes
> xShapes( rDataSeries
.m_xLabelsGroupShape
);
352 //create a 2D group shape for texts of this series and add to text target:
353 xShapes
= m_pShapeFactory
->createGroup2D( xTextTarget
, rDataSeries
.getLabelsCID() );
354 rDataSeries
.m_xLabelsGroupShape
= xShapes
;
359 uno::Reference
< drawing::XShapes
> VSeriesPlotter::getErrorBarsGroupShape( VDataSeries
& rDataSeries
360 , const uno::Reference
< drawing::XShapes
>& xTarget
)
362 uno::Reference
< drawing::XShapes
> xShapes( rDataSeries
.m_xErrorBarsGroupShape
);
365 //create a group shape for this series and add to logic target:
366 xShapes
= this->createGroupShape( xTarget
,rDataSeries
.getErrorBarsCID() );
367 rDataSeries
.m_xErrorBarsGroupShape
= 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
= ExplicitValueProvider::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
/*,sal_Int32 const * pGroups*/ /*,sal_Unicode cGroupSeparator*/ ,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( this->getLabelsGroupShape(rDataSeries
, xTarget
)
441 , ObjectIdentifier::createPointCID( rDataSeries
.getLabelCID_Stub(),nPointIndex
) ) );
443 //check wether the label needs to be created and how:
444 DataPointLabel
* pLabel
= rDataSeries
.getDataPointLabelIfLabel( nPointIndex
);
449 //------------------------------------------------
450 //prepare legend symbol
452 Reference
< drawing::XShape
> xSymbol
;
453 if(pLabel
->ShowLegendSymbol
)
455 if( rDataSeries
.isVaryColorsByPoint() )
456 xSymbol
.set( VSeriesPlotter::createLegendSymbolForPoint( rDataSeries
, nPointIndex
, xTarget_
, m_xShapeFactory
) );
458 xSymbol
.set( VSeriesPlotter::createLegendSymbolForSeries( rDataSeries
, xTarget_
, m_xShapeFactory
) );
462 ::rtl::OUStringBuffer aText
;
463 ::rtl::OUString
aSeparator(sal_Unicode(' '));
464 double fRotationDegrees
= 0.0;
467 uno::Reference
< beans::XPropertySet
> xPointProps( rDataSeries
.getPropertiesOfPoint( nPointIndex
) );
470 xPointProps
->getPropertyValue( C2U( "LabelSeparator" ) ) >>= aSeparator
;
471 xPointProps
->getPropertyValue( C2U( "TextRotation" ) ) >>= fRotationDegrees
;
474 catch( uno::Exception
& e
)
476 ASSERT_EXCEPTION( e
);
478 bool bMultiLineLabel
= aSeparator
.equals(C2U("\n"));;
479 sal_Int32 nLineCountForSymbolsize
= 0;
481 if(pLabel
->ShowCategoryName
)
483 if( m_xExplicitCategoriesProvider
.is() )
485 Sequence
< OUString
> aCategories( m_xExplicitCategoriesProvider
->getTextualData() );
486 if( nPointIndex
>= 0 && nPointIndex
< aCategories
.getLength() )
488 aText
.append( aCategories
[nPointIndex
] );
489 ++nLineCountForSymbolsize
;
494 if(pLabel
->ShowNumber
)
496 OUString
aNumber( this->getLabelTextForValue( rDataSeries
497 , nPointIndex
, fValue
, false /*bAsPercentage*/ ) );
498 if( aNumber
.getLength() )
500 if(aText
.getLength())
501 aText
.append(aSeparator
);
502 aText
.append(aNumber
);
503 ++nLineCountForSymbolsize
;
507 if(pLabel
->ShowNumberInPercent
)
515 OUString
aPercentage( this->getLabelTextForValue( rDataSeries
516 , nPointIndex
, fValue
, true /*bAsPercentage*/ ) );
517 if( aPercentage
.getLength() )
519 if(aText
.getLength())
520 aText
.append(aSeparator
);
521 aText
.append(aPercentage
);
522 ++nLineCountForSymbolsize
;
526 //------------------------------------------------
527 //prepare properties for multipropertyset-interface of shape
528 tNameSequence
* pPropNames
;
529 tAnySequence
* pPropValues
;
530 if( !rDataSeries
.getTextLabelMultiPropertyLists( nPointIndex
, pPropNames
, pPropValues
) )
532 LabelPositionHelper::changeTextAdjustment( *pPropValues
, *pPropNames
, eAlignment
);
534 //------------------------------------------------
536 xTextShape
= ShapeFactory(m_xShapeFactory
).
537 createText( xTarget_
, aText
.makeStringAndClear()
538 , *pPropNames
, *pPropValues
, ShapeFactory::makeTransformation( aScreenPosition2D
) );
540 const awt::Point
aUnrotatedTextPos( xTextShape
->getPosition() );
541 if( fRotationDegrees
!= 0.0 )
543 const double fDegreesPi( fRotationDegrees
* ( F_PI
/ -180.0 ) );
544 uno::Reference
< beans::XPropertySet
> xProp( xTextShape
, uno::UNO_QUERY
);
546 xProp
->setPropertyValue( C2U( "Transformation" ), ShapeFactory::makeTransformation( aScreenPosition2D
, fDegreesPi
) );
547 LabelPositionHelper::correctPositionForRotation( xTextShape
, eAlignment
, fRotationDegrees
, true /*bRotateAroundCenter*/ );
550 if( xSymbol
.is() && xTextShape
.is() )
552 const awt::Point
aOldTextPos( xTextShape
->getPosition() );
553 awt::Point
aNewTextPos( aOldTextPos
);
555 awt::Size
aSymbolSize( xSymbol
->getSize() );
556 awt::Size
aTextSize( xTextShape
->getSize() );
558 if( !bMultiLineLabel
|| nLineCountForSymbolsize
<= 0 )
559 nLineCountForSymbolsize
= 1;
560 sal_Int32 nYDiff
= aTextSize
.Height
/nLineCountForSymbolsize
;
561 sal_Int32 nXDiff
= aSymbolSize
.Width
* nYDiff
/aSymbolSize
.Height
;
563 aSymbolSize
.Width
= nXDiff
* 75/100;
564 aSymbolSize
.Height
= nYDiff
* 75/100;
566 awt::Point
aSymbolPosition( aUnrotatedTextPos
);
567 aSymbolPosition
.Y
+= (nYDiff
* 25/200);
569 if(LABEL_ALIGN_LEFT
==eAlignment
570 || LABEL_ALIGN_LEFT_TOP
==eAlignment
571 || LABEL_ALIGN_LEFT_BOTTOM
==eAlignment
)
573 aSymbolPosition
.X
-= nXDiff
;
575 else if(LABEL_ALIGN_RIGHT
==eAlignment
576 || LABEL_ALIGN_RIGHT_TOP
==eAlignment
577 || LABEL_ALIGN_RIGHT_BOTTOM
==eAlignment
)
579 aNewTextPos
.X
+= nXDiff
;
581 else if(LABEL_ALIGN_TOP
==eAlignment
582 || LABEL_ALIGN_BOTTOM
==eAlignment
583 || LABEL_ALIGN_CENTER
==eAlignment
)
585 aSymbolPosition
.X
-= nXDiff
/2;
586 aNewTextPos
.X
+= nXDiff
/2;
589 xSymbol
->setSize( aSymbolSize
);
590 xSymbol
->setPosition( aSymbolPosition
);
593 xTextShape
->setPosition( aNewTextPos
);
596 catch( uno::Exception
& e
)
598 ASSERT_EXCEPTION( e
);
606 double lcl_getErrorBarLogicLength(
607 const uno::Sequence
< double > & rData
,
608 uno::Reference
< beans::XPropertySet
> xProp
,
609 sal_Int32 nErrorBarStyle
,
614 ::rtl::math::setNan( & fResult
);
617 switch( nErrorBarStyle
)
619 case ::com::sun::star::chart::ErrorBarStyle::NONE
:
621 case ::com::sun::star::chart::ErrorBarStyle::VARIANCE
:
622 fResult
= StatisticsHelper::getVariance( rData
);
624 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION
:
625 fResult
= StatisticsHelper::getStandardDeviation( rData
);
627 case ::com::sun::star::chart::ErrorBarStyle::RELATIVE
:
630 if( xProp
->getPropertyValue( bPositive
631 ? C2U("PositiveError")
632 : C2U("NegativeError")) >>= fPercent
)
634 if( nIndex
>=0 && nIndex
< rData
.getLength() &&
635 ! ::rtl::math::isNan( rData
[nIndex
] ) &&
636 ! ::rtl::math::isNan( fPercent
))
638 fResult
= rData
[nIndex
] * fPercent
/ 100.0;
643 case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE
:
644 xProp
->getPropertyValue( bPositive
645 ? C2U("PositiveError")
646 : C2U("NegativeError")) >>= fResult
;
648 case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN
:
650 // todo: check if this is really what's called error-margin
652 if( xProp
->getPropertyValue( bPositive
653 ? C2U("PositiveError")
654 : C2U("NegativeError")) >>= fPercent
)
657 ::rtl::math::setInf(&fMaxValue
, true);
658 const double* pValues
= rData
.getConstArray();
659 for(sal_Int32 i
=0; i
<rData
.getLength(); ++i
, ++pValues
)
661 if(fMaxValue
<*pValues
)
664 if( ::rtl::math::isFinite( fMaxValue
) &&
665 ::rtl::math::isFinite( fPercent
))
667 fResult
= fMaxValue
* fPercent
/ 100.0;
672 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR
:
673 fResult
= StatisticsHelper::getStandardError( rData
);
675 case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA
:
677 uno::Reference
< chart2::data::XDataSource
> xErrorBarData( xProp
, uno::UNO_QUERY
);
678 if( xErrorBarData
.is())
679 fResult
= StatisticsHelper::getErrorFromDataSource(
680 xErrorBarData
, nIndex
, bPositive
/*, true */ /* y-error */ );
685 catch( uno::Exception
& e
)
687 ASSERT_EXCEPTION( e
);
693 void lcl_AddErrorBottomLine( const drawing::Position3D
& rPosition
, ::basegfx::B2DVector aMainDirection
694 , drawing::PolyPolygonShape3D
& rPoly
, sal_Int32 nSequenceIndex
)
696 double fFixedWidth
= 200.0;
698 aMainDirection
.normalize();
699 ::basegfx::B2DVector
aOrthoDirection(-aMainDirection
.getY(),aMainDirection
.getX());
700 aOrthoDirection
.normalize();
702 ::basegfx::B2DVector
aAnchor( rPosition
.PositionX
, rPosition
.PositionY
);
703 ::basegfx::B2DVector aStart
= aAnchor
+ aOrthoDirection
*fFixedWidth
/2.0;
704 ::basegfx::B2DVector aEnd
= aAnchor
- aOrthoDirection
*fFixedWidth
/2.0;
706 AddPointToPoly( rPoly
, drawing::Position3D( aStart
.getX(), aStart
.getY(), rPosition
.PositionZ
), nSequenceIndex
);
707 AddPointToPoly( rPoly
, drawing::Position3D( aEnd
.getX(), aEnd
.getY(), rPosition
.PositionZ
), nSequenceIndex
);
710 ::basegfx::B2DVector
lcl_getErrorBarMainDirection(
711 const drawing::Position3D
& rStart
712 , const drawing::Position3D
& rBottomEnd
713 , PlottingPositionHelper
* pPosHelper
714 , const drawing::Position3D
& rUnscaledLogicPosition
717 ::basegfx::B2DVector aMainDirection
= ::basegfx::B2DVector( rStart
.PositionX
- rBottomEnd
.PositionX
718 , rStart
.PositionY
- rBottomEnd
.PositionY
);
719 if( !aMainDirection
.getLength() )
721 //get logic clip values:
722 double MinX
= pPosHelper
->getLogicMinX();
723 double MinY
= pPosHelper
->getLogicMinY();
724 double MaxX
= pPosHelper
->getLogicMaxX();
725 double MaxY
= pPosHelper
->getLogicMaxY();
726 double fZ
= pPosHelper
->getLogicMinZ();
731 //main direction has constant x value
732 MinX
= rUnscaledLogicPosition
.PositionX
;
733 MaxX
= rUnscaledLogicPosition
.PositionX
;
737 //main direction has constant y value
738 MinY
= rUnscaledLogicPosition
.PositionY
;
739 MaxY
= rUnscaledLogicPosition
.PositionY
;
742 drawing::Position3D aStart
= pPosHelper
->transformLogicToScene( MinX
, MinY
, fZ
, false );
743 drawing::Position3D aEnd
= pPosHelper
->transformLogicToScene( MaxX
, MaxY
, fZ
, false );
745 aMainDirection
= ::basegfx::B2DVector( aStart
.PositionX
- aEnd
.PositionX
746 , aStart
.PositionY
- aEnd
.PositionY
);
748 if( !aMainDirection
.getLength() )
752 return aMainDirection
;
755 } // anonymous namespace
758 void VSeriesPlotter::createErrorBar(
759 const uno::Reference
< drawing::XShapes
>& xTarget
760 , const drawing::Position3D
& rUnscaledLogicPosition
761 , const uno::Reference
< beans::XPropertySet
> & xErrorBarProperties
762 , const VDataSeries
& rVDataSeries
764 , bool bYError
/* = true */
767 if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel
, m_nDimension
) )
770 if( ! xErrorBarProperties
.is())
775 sal_Bool bShowPositive
= sal_False
;
776 sal_Bool bShowNegative
= sal_False
;
777 sal_Int32 nErrorBarStyle
= ::com::sun::star::chart::ErrorBarStyle::VARIANCE
;
779 xErrorBarProperties
->getPropertyValue( C2U( "ShowPositiveError" )) >>= bShowPositive
;
780 xErrorBarProperties
->getPropertyValue( C2U( "ShowNegativeError" )) >>= bShowNegative
;
781 xErrorBarProperties
->getPropertyValue( C2U( "ErrorBarStyle" )) >>= nErrorBarStyle
;
783 if(!bShowPositive
&& !bShowNegative
)
786 if(nErrorBarStyle
==::com::sun::star::chart::ErrorBarStyle::NONE
)
789 drawing::Position3D
aUnscaledLogicPosition(rUnscaledLogicPosition
);
790 if(nErrorBarStyle
==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION
)
791 aUnscaledLogicPosition
.PositionY
= rVDataSeries
.getYMeanValue();
793 bool bCreateNegativeBorder
= false;//make a vertical line at the negative end of the error bar
794 bool bCreatePositiveBorder
= false;//make a vertical line at the positive end of the error bar
795 drawing::Position3D
aMiddle(aUnscaledLogicPosition
);
796 const double fX
= aUnscaledLogicPosition
.PositionX
;
797 const double fY
= aUnscaledLogicPosition
.PositionY
;
798 const double fZ
= aUnscaledLogicPosition
.PositionZ
;
799 aMiddle
= m_pPosHelper
->transformLogicToScene( fX
, fY
, fZ
, true );
801 drawing::Position3D
aNegative(aMiddle
);
802 drawing::Position3D
aPositive(aMiddle
);
804 uno::Sequence
< double > aData( bYError
? rVDataSeries
.getAllY() : rVDataSeries
.getAllX() );
808 double fLength
= lcl_getErrorBarLogicLength( aData
, xErrorBarProperties
, nErrorBarStyle
, nIndex
, true );
809 if( ::rtl::math::isFinite( fLength
) )
817 bCreatePositiveBorder
= m_pPosHelper
->isLogicVisible(fLocalX
, fLocalY
, fZ
);
818 aPositive
= m_pPosHelper
->transformLogicToScene( fLocalX
, fLocalY
, fZ
, true );
821 bShowPositive
= false;
826 double fLength
= lcl_getErrorBarLogicLength( aData
, xErrorBarProperties
, nErrorBarStyle
, nIndex
, false );
827 if( ::rtl::math::isFinite( fLength
) )
836 bCreateNegativeBorder
= m_pPosHelper
->isLogicVisible( fLocalX
, fLocalY
, fZ
);
837 aNegative
= m_pPosHelper
->transformLogicToScene( fLocalX
, fLocalY
, fZ
, true );
840 bShowNegative
= false;
843 if(!bShowPositive
&& !bShowNegative
)
846 drawing::PolyPolygonShape3D aPoly
;
848 sal_Int32 nSequenceIndex
=0;
850 AddPointToPoly( aPoly
, aNegative
, nSequenceIndex
);
851 AddPointToPoly( aPoly
, aMiddle
, nSequenceIndex
);
853 AddPointToPoly( aPoly
, aPositive
, nSequenceIndex
);
855 if( bShowNegative
&& bCreateNegativeBorder
)
857 ::basegfx::B2DVector aMainDirection
= lcl_getErrorBarMainDirection( aMiddle
, aNegative
, m_pPosHelper
, aUnscaledLogicPosition
, bYError
);
859 lcl_AddErrorBottomLine( aNegative
, aMainDirection
, aPoly
, nSequenceIndex
);
861 if( bShowPositive
&& bCreatePositiveBorder
)
863 ::basegfx::B2DVector aMainDirection
= lcl_getErrorBarMainDirection( aMiddle
, aPositive
, m_pPosHelper
, aUnscaledLogicPosition
, bYError
);
865 lcl_AddErrorBottomLine( aPositive
, aMainDirection
, aPoly
, nSequenceIndex
);
868 uno::Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D( xTarget
, PolyToPointSequence( aPoly
) );
869 this->setMappedProperties( xShape
, xErrorBarProperties
, PropertyMapper::getPropertyNameMapForLineProperties() );
871 catch( uno::Exception
& e
)
873 ASSERT_EXCEPTION( e
);
879 void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D
& rUnscaledLogicPosition
880 , VDataSeries
& rVDataSeries
, sal_Int32 nPointIndex
881 , const uno::Reference
< drawing::XShapes
>& xTarget
)
886 uno::Reference
< beans::XPropertySet
> xErrorBarProp(rVDataSeries
.getYErrorBarProperties(nPointIndex
));
887 if( xErrorBarProp
.is())
889 uno::Reference
< drawing::XShapes
> xErrorBarsGroup_Shapes(
890 this->getErrorBarsGroupShape(rVDataSeries
, xTarget
) );
892 createErrorBar( xErrorBarsGroup_Shapes
893 , rUnscaledLogicPosition
, xErrorBarProp
894 , rVDataSeries
, nPointIndex
895 , true /* bYError */ );
899 void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries
& rVDataSeries
900 , const uno::Reference
< drawing::XShapes
>& xTarget
901 , const uno::Reference
< drawing::XShapes
>& xEquationTarget
902 , bool bMaySkipPointsInRegressionCalculation
)
906 uno::Reference
< XRegressionCurveContainer
> xRegressionContainer(
907 rVDataSeries
.getModel(), uno::UNO_QUERY
);
908 if(!xRegressionContainer
.is())
910 double fMinX
= m_pPosHelper
->getLogicMinX();
911 double fMaxX
= m_pPosHelper
->getLogicMaxX();
913 uno::Sequence
< uno::Reference
< XRegressionCurve
> > aCurveList
=
914 xRegressionContainer
->getRegressionCurves();
915 for(sal_Int32 nN
=0; nN
<aCurveList
.getLength(); nN
++)
917 uno::Reference
< XRegressionCurveCalculator
> xRegressionCurveCalculator(
918 aCurveList
[nN
]->getCalculator() );
919 if( ! xRegressionCurveCalculator
.is())
921 xRegressionCurveCalculator
->recalculateRegression( rVDataSeries
.getAllX(), rVDataSeries
.getAllY() );
923 sal_Int32 nRegressionPointCount
= 50;//@todo find a more optimal solution if more complicated curve types are introduced
924 drawing::PolyPolygonShape3D aRegressionPoly
;
925 aRegressionPoly
.SequenceX
.realloc(1);
926 aRegressionPoly
.SequenceY
.realloc(1);
927 aRegressionPoly
.SequenceZ
.realloc(1);
928 aRegressionPoly
.SequenceX
[0].realloc(nRegressionPointCount
);
929 aRegressionPoly
.SequenceY
[0].realloc(nRegressionPointCount
);
930 aRegressionPoly
.SequenceZ
[0].realloc(nRegressionPointCount
);
931 sal_Int32 nRealPointCount
=0;
933 uno::Sequence
< chart2::ExplicitScaleData
> aScaleDataSeq( m_pPosHelper
->getScales());
934 uno::Reference
< chart2::XScaling
> xScalingX
;
935 uno::Reference
< chart2::XScaling
> xScalingY
;
936 if( aScaleDataSeq
.getLength() >= 2 )
938 xScalingX
.set( aScaleDataSeq
[0].Scaling
);
939 xScalingY
.set( aScaleDataSeq
[1].Scaling
);
942 uno::Sequence
< geometry::RealPoint2D
> aCalculatedPoints(
943 xRegressionCurveCalculator
->getCurveValues(
944 fMinX
, fMaxX
, nRegressionPointCount
, xScalingX
, xScalingY
, bMaySkipPointsInRegressionCalculation
));
945 nRegressionPointCount
= aCalculatedPoints
.getLength();
946 for(sal_Int32 nP
=0; nP
<nRegressionPointCount
; nP
++)
948 double fLogicX
= aCalculatedPoints
[nP
].X
;
949 double fLogicY
= aCalculatedPoints
[nP
].Y
;
950 double fLogicZ
= 0.0;//dummy
952 m_pPosHelper
->doLogicScaling( &fLogicX
, &fLogicY
, &fLogicZ
);
954 if( !::rtl::math::isNan(fLogicX
) && !::rtl::math::isInf(fLogicX
)
955 && !::rtl::math::isNan(fLogicY
) && !::rtl::math::isInf(fLogicY
)
956 && !::rtl::math::isNan(fLogicZ
) && !::rtl::math::isInf(fLogicZ
) )
958 aRegressionPoly
.SequenceX
[0][nRealPointCount
] = fLogicX
;
959 aRegressionPoly
.SequenceY
[0][nRealPointCount
] = fLogicY
;
963 aRegressionPoly
.SequenceX
[0].realloc(nRealPointCount
);
964 aRegressionPoly
.SequenceY
[0].realloc(nRealPointCount
);
965 aRegressionPoly
.SequenceZ
[0].realloc(nRealPointCount
);
967 drawing::PolyPolygonShape3D aClippedPoly
;
968 Clipping::clipPolygonAtRectangle( aRegressionPoly
, m_pPosHelper
->getScaledLogicClipDoubleRect(), aClippedPoly
);
969 aRegressionPoly
= aClippedPoly
;
970 m_pPosHelper
->transformScaledLogicToScene( aRegressionPoly
);
972 awt::Point aDefaultPos
;
973 if( aRegressionPoly
.SequenceX
.getLength() && aRegressionPoly
.SequenceX
[0].getLength() )
975 uno::Reference
< beans::XPropertySet
> xCurveModelProp( aCurveList
[nN
], uno::UNO_QUERY
);
976 VLineProperties aVLineProperties
;
977 aVLineProperties
.initFromPropertySet( xCurveModelProp
);
979 //create an extra group shape for each curve for selection handling
980 bool bAverageLine
= RegressionCurveHelper::isMeanValueLine( aCurveList
[nN
] );
981 uno::Reference
< drawing::XShapes
> xRegressionGroupShapes
=
982 createGroupShape( xTarget
, rVDataSeries
.getDataCurveCID( nN
, bAverageLine
) );
983 uno::Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D(
984 xRegressionGroupShapes
, PolyToPointSequence( aRegressionPoly
), &aVLineProperties
);
985 m_pShapeFactory
->setShapeName( xShape
, C2U("MarkHandles") );
986 aDefaultPos
= xShape
->getPosition();
989 // curve equation and correlation coefficient
990 uno::Reference
< beans::XPropertySet
> xEqProp( aCurveList
[nN
]->getEquationProperties());
993 createRegressionCurveEquationShapes(
994 rVDataSeries
.getDataCurveEquationCID( nN
),
995 xEqProp
, xEquationTarget
, xRegressionCurveCalculator
,
1001 void VSeriesPlotter::createRegressionCurveEquationShapes(
1002 const OUString
& rEquationCID
,
1003 const uno::Reference
< beans::XPropertySet
> & xEquationProperties
,
1004 const uno::Reference
< drawing::XShapes
>& xEquationTarget
,
1005 const uno::Reference
< chart2::XRegressionCurveCalculator
> & xRegressionCurveCalculator
,
1006 awt::Point aDefaultPos
)
1008 OSL_ASSERT( xEquationProperties
.is());
1009 if( !xEquationProperties
.is())
1012 bool bShowEquation
= false;
1013 bool bShowCorrCoeff
= false;
1014 OUString
aSep( sal_Unicode('\n'));
1015 if(( xEquationProperties
->getPropertyValue( C2U("ShowEquation")) >>= bShowEquation
) &&
1016 ( xEquationProperties
->getPropertyValue( C2U("ShowCorrelationCoefficient")) >>= bShowCorrCoeff
))
1018 if( ! (bShowEquation
|| bShowCorrCoeff
))
1021 ::rtl::OUStringBuffer aFormula
;
1022 sal_Int32 nNumberFormatKey
= 0;
1023 xEquationProperties
->getPropertyValue( C2U("NumberFormat")) >>= nNumberFormatKey
;
1027 if( m_apNumberFormatterWrapper
.get())
1029 aFormula
= xRegressionCurveCalculator
->getFormattedRepresentation(
1030 m_apNumberFormatterWrapper
->getNumberFormatsSupplier(),
1035 aFormula
= xRegressionCurveCalculator
->getRepresentation();
1038 if( bShowCorrCoeff
)
1040 // xEquationProperties->getPropertyValue( C2U("Separator")) >>= aSep;
1041 aFormula
.append( aSep
);
1044 if( bShowCorrCoeff
)
1046 aFormula
.append( sal_Unicode( 'R' ));
1047 aFormula
.append( sal_Unicode( 0x00b2 ));
1048 aFormula
.append( C2U( " = " ));
1049 double fR( xRegressionCurveCalculator
->getCorrelationCoefficient());
1050 if( m_apNumberFormatterWrapper
.get())
1052 sal_Int32 nLabelCol
= 0;
1055 m_apNumberFormatterWrapper
->getFormattedString(
1056 nNumberFormatKey
, fR
*fR
, nLabelCol
, bColChanged
));
1057 //@todo: change color of label if bColChanged is true
1061 sal_Unicode
aDecimalSep( '.' );//@todo get this locale dependent
1062 aFormula
.append( ::rtl::math::doubleToUString(
1063 fR
*fR
, rtl_math_StringFormat_G
, 4, aDecimalSep
, true ));
1067 awt::Point aScreenPosition2D
;
1068 chart2::RelativePosition aRelativePosition
;
1069 if( xEquationProperties
->getPropertyValue( C2U("RelativePosition")) >>= aRelativePosition
)
1071 //@todo decide wether x is primary or secondary
1072 double fX
= aRelativePosition
.Primary
*m_aPageReferenceSize
.Width
;
1073 double fY
= aRelativePosition
.Secondary
*m_aPageReferenceSize
.Height
;
1074 aScreenPosition2D
.X
= static_cast< sal_Int32
>( ::rtl::math::round( fX
));
1075 aScreenPosition2D
.Y
= static_cast< sal_Int32
>( ::rtl::math::round( fY
));
1078 aScreenPosition2D
= aDefaultPos
;
1080 if( aFormula
.getLength())
1082 // set fill and line properties on creation
1083 tNameSequence aNames
;
1084 tAnySequence aValues
;
1085 PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties
, aNames
, aValues
);
1087 uno::Reference
< drawing::XShape
> xTextShape
= m_pShapeFactory
->createText(
1088 xEquationTarget
, aFormula
.makeStringAndClear(),
1089 aNames
, aValues
, ShapeFactory::makeTransformation( aScreenPosition2D
));
1091 // // adapt font sizes
1092 // awt::Size aOldRefSize;
1093 // if( xTitleProperties->getPropertyValue( C2U("ReferencePageSize")) >>= aOldRefSize )
1095 // uno::Reference< beans::XPropertySet > xShapeProp( xTextShape, uno::UNO_QUERY );
1096 // if( xShapeProp.is())
1097 // RelativeSizeHelper::adaptFontSizes( xShapeProp, aOldRefSize, m_aPageReferenceSize );
1100 OSL_ASSERT( xTextShape
.is());
1101 if( xTextShape
.is())
1103 ShapeFactory::setShapeName( xTextShape
, rEquationCID
);
1104 xTextShape
->setPosition(
1105 RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
1106 aScreenPosition2D
, xTextShape
->getSize(), aRelativePosition
.Anchor
));
1113 void VSeriesPlotter::setMappedProperties(
1114 const uno::Reference
< drawing::XShape
>& xTargetShape
1115 , const uno::Reference
< beans::XPropertySet
>& xSource
1116 , const tPropertyNameMap
& rMap
1117 , tPropertyNameValueMap
* pOverwriteMap
)
1119 uno::Reference
< beans::XPropertySet
> xTargetProp( xTargetShape
, uno::UNO_QUERY
);
1120 PropertyMapper::setMappedProperties(xTargetProp
,xSource
,rMap
,pOverwriteMap
);
1123 //-------------------------------------------------------------------------
1124 // MinimumAndMaximumSupplier
1125 //-------------------------------------------------------------------------
1127 double VSeriesPlotter::getMinimumX()
1129 if( m_bCategoryXAxis
)
1130 return 1.0;//first category (index 0) matches with real number 1.0
1132 double fMinimum
, fMaximum
;
1133 this->getMinimumAndMaximiumX( fMinimum
, fMaximum
);
1136 double VSeriesPlotter::getMaximumX()
1138 if( m_bCategoryXAxis
)
1140 //return category count
1141 sal_Int32 nPointCount
= getPointCount();
1142 return nPointCount
;//first category (index 0) matches with real number 1.0
1145 double fMinimum
, fMaximum
;
1146 this->getMinimumAndMaximiumX( fMinimum
, fMaximum
);
1150 double VSeriesPlotter::getMinimumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1152 sal_Bool bPercent
= sal_False
;
1153 uno::Reference
< beans::XPropertySet
> xPropSet(m_xChartTypeModel
, uno::UNO_QUERY
);
1158 xPropSet
->getPropertyValue(C2U("Percent")) >>= bPercent
;
1160 catch (const beans::UnknownPropertyException
&)
1166 // This plotter is percent-stacked.
1169 if( !m_bCategoryXAxis
)
1171 double fMinY
, fMaxY
;
1172 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1176 double fMinimum
, fMaximum
;
1177 ::rtl::math::setInf(&fMinimum
, false);
1178 ::rtl::math::setInf(&fMaximum
, true);
1179 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1181 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1182 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1184 double fLocalMinimum
, fLocalMaximum
;
1185 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1186 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1187 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1188 , isSeperateStackingForDifferentSigns( 1 )
1189 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1190 if(fMaximum
<fLocalMaximum
)
1191 fMaximum
=fLocalMaximum
;
1192 if(fMinimum
>fLocalMinimum
)
1193 fMinimum
=fLocalMinimum
;
1196 if(::rtl::math::isInf(fMinimum
))
1197 ::rtl::math::setNan(&fMinimum
);
1201 double VSeriesPlotter::getMaximumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1203 sal_Bool bPercent
= sal_False
;
1204 uno::Reference
< beans::XPropertySet
> xPropSet(m_xChartTypeModel
, uno::UNO_QUERY
);
1209 xPropSet
->getPropertyValue(C2U("Percent")) >>= bPercent
;
1211 catch (const beans::UnknownPropertyException
&)
1217 // This plotter is percent-stacked.
1220 if( !m_bCategoryXAxis
)
1222 double fMinY
, fMaxY
;
1223 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1227 double fMinimum
, fMaximum
;
1228 ::rtl::math::setInf(&fMinimum
, false);
1229 ::rtl::math::setInf(&fMaximum
, true);
1230 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1232 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1233 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1235 double fLocalMinimum
, fLocalMaximum
;
1236 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1237 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1238 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1239 , isSeperateStackingForDifferentSigns( 1 )
1240 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1241 if(fMaximum
<fLocalMaximum
)
1242 fMaximum
=fLocalMaximum
;
1243 if(fMinimum
>fLocalMinimum
)
1244 fMinimum
=fLocalMinimum
;
1247 if(::rtl::math::isInf(fMaximum
))
1248 ::rtl::math::setNan(&fMaximum
);
1252 double VSeriesPlotter::getMinimumZ()
1254 //this is the default for all charts without a meaningfull z axis
1257 double VSeriesPlotter::getMaximumZ()
1259 if( 3!=m_nDimension
)
1261 return m_aZSlots
.size()+0.5;
1266 bool lcl_isValueAxis( sal_Int32 nDimensionIndex
, bool bCategoryXAxis
)
1268 // default implementation: true for Y axes, and for value X axis
1269 if( nDimensionIndex
== 0 )
1270 return !bCategoryXAxis
;
1271 if( nDimensionIndex
== 1 )
1277 bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex
)
1279 return lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1282 bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex
)
1284 // do not expand axes in 3D charts
1285 return (m_nDimension
< 3) && lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1288 bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex
)
1290 // default implementation: only for Y axis
1291 return nDimensionIndex
== 1;
1294 bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex
)
1296 // default implementation: only for Y axis
1297 return nDimensionIndex
== 1;
1300 bool VSeriesPlotter::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex
)
1302 // default implementation: only for Y axis
1303 return nDimensionIndex
== 1;
1306 void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1308 ::rtl::math::setInf(&rfMinimum
, false);
1309 ::rtl::math::setInf(&rfMaximum
, true);
1311 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1312 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1313 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
1315 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1316 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1317 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
1319 double fLocalMinimum
, fLocalMaximum
;
1320 aXSlotIter
->getMinimumAndMaximiumX( fLocalMinimum
, fLocalMaximum
);
1321 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinimum
)
1322 rfMinimum
= fLocalMinimum
;
1323 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaximum
)
1324 rfMaximum
= fLocalMaximum
;
1327 if(::rtl::math::isInf(rfMinimum
))
1328 ::rtl::math::setNan(&rfMinimum
);
1329 if(::rtl::math::isInf(rfMaximum
))
1330 ::rtl::math::setNan(&rfMaximum
);
1333 void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1335 ::rtl::math::setInf(&rfMinY
, false);
1336 ::rtl::math::setInf(&rfMaxY
, true);
1338 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1339 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1340 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
1342 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1343 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1344 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
1346 double fLocalMinimum
, fLocalMaximum
;
1347 aXSlotIter
->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum
, fLocalMaximum
, fMinX
, fMaxX
, nAxisIndex
);
1348 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinY
)
1349 rfMinY
= fLocalMinimum
;
1350 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaxY
)
1351 rfMaxY
= fLocalMaximum
;
1354 if(::rtl::math::isInf(rfMinY
))
1355 ::rtl::math::setNan(&rfMinY
);
1356 if(::rtl::math::isInf(rfMaxY
))
1357 ::rtl::math::setNan(&rfMaxY
);
1360 sal_Int32
VSeriesPlotter::getPointCount() const
1364 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1365 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1367 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
1369 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1370 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1372 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
1374 sal_Int32 nPointCount
= aXSlotIter
->getPointCount();
1375 if( nPointCount
>nRet
)
1382 void VSeriesPlotter::setNumberFormatsSupplier(
1383 const uno::Reference
< util::XNumberFormatsSupplier
> & xNumFmtSupplier
)
1385 m_apNumberFormatterWrapper
.reset( new NumberFormatterWrapper( xNumFmtSupplier
));
1388 void VSeriesPlotter::setColorScheme( const uno::Reference
< XColorScheme
>& xColorScheme
)
1390 m_xColorScheme
= xColorScheme
;
1393 void VSeriesPlotter::setExplicitCategoriesProvider( const uno::Reference
< data::XTextualDataSequence
>& xExplicitCategoriesProvider
)
1395 m_xExplicitCategoriesProvider
= xExplicitCategoriesProvider
;
1398 sal_Int32
VDataSeriesGroup::getPointCount() const
1400 if(!m_bMaxPointCountDirty
)
1401 return m_nMaxPointCount
;
1404 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1405 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1407 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
1409 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1410 if( nPointCount
>nRet
)
1413 m_nMaxPointCount
=nRet
;
1414 m_aListOfCachedYValues
.clear();
1415 m_aListOfCachedYValues
.resize(m_nMaxPointCount
);
1416 m_bMaxPointCountDirty
=false;
1420 sal_Int32
VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1423 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1424 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1426 if( aSeriesIter
!= aSeriesEnd
)
1427 nRet
= (*aSeriesIter
)->getAttachedAxisIndex();
1432 void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1434 const ::std::vector
< VDataSeries
* >* pSeriesList
= &this->m_aSeriesVector
;
1436 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1437 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1439 ::rtl::math::setInf(&rfMinimum
, false);
1440 ::rtl::math::setInf(&rfMaximum
, true);
1442 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
1444 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1445 for(sal_Int32 nN
=0;nN
<nPointCount
;nN
++)
1447 double fX
= (*aSeriesIter
)->getXValue( nN
);
1448 if( ::rtl::math::isNan(fX
) )
1456 if(::rtl::math::isInf(rfMinimum
))
1457 ::rtl::math::setNan(&rfMinimum
);
1458 if(::rtl::math::isInf(rfMaximum
))
1459 ::rtl::math::setNan(&rfMaximum
);
1461 void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1463 const ::std::vector
< VDataSeries
* >* pSeriesList
= &this->m_aSeriesVector
;
1465 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1466 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1468 ::rtl::math::setInf(&rfMinY
, false);
1469 ::rtl::math::setInf(&rfMaxY
, true);
1471 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
1473 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1474 for(sal_Int32 nN
=0;nN
<nPointCount
;nN
++)
1476 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1479 double fX
= (*aSeriesIter
)->getXValue( nN
);
1480 if( ::rtl::math::isNan(fX
) )
1482 if( fX
< fMinX
|| fX
> fMaxX
)
1484 double fY
= (*aSeriesIter
)->getYValue( nN
);
1485 if( ::rtl::math::isNan(fY
) )
1493 if(::rtl::math::isInf(rfMinY
))
1494 ::rtl::math::setNan(&rfMinY
);
1495 if(::rtl::math::isInf(rfMaxY
))
1496 ::rtl::math::setNan(&rfMaxY
);
1499 void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
1500 , bool bSeperateStackingForDifferentSigns
1501 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1503 ::rtl::math::setInf(&rfMinimumY
, false);
1504 ::rtl::math::setInf(&rfMaximumY
, true);
1506 sal_Int32 nPointCount
= getPointCount();//necessary to create m_aListOfCachedYValues
1507 if(nCategoryIndex
<0 || nCategoryIndex
>=nPointCount
|| m_aSeriesVector
.empty())
1510 CachedYValues aCachedYValues
= m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
];
1511 if( !aCachedYValues
.m_bValuesDirty
)
1513 //return cached values
1514 rfMinimumY
= aCachedYValues
.m_fMinimumY
;
1515 rfMaximumY
= aCachedYValues
.m_fMaximumY
;
1519 double fTotalSum
, fPositiveSum
, fNegativeSum
, fFirstPositiveY
, fFirstNegativeY
;
1520 ::rtl::math::setNan( &fTotalSum
);
1521 ::rtl::math::setNan( &fPositiveSum
);
1522 ::rtl::math::setNan( &fNegativeSum
);
1523 ::rtl::math::setNan( &fFirstPositiveY
);
1524 ::rtl::math::setNan( &fFirstNegativeY
);
1526 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1527 ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1529 if( bSeperateStackingForDifferentSigns
)
1531 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1533 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1536 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1537 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1539 if( fValueMaxY
>= 0 )
1541 if( ::rtl::math::isNan( fPositiveSum
) )
1542 fPositiveSum
= fFirstPositiveY
= fValueMaxY
;
1544 fPositiveSum
+= fValueMaxY
;
1546 if( fValueMinY
< 0 )
1548 if(::rtl::math::isNan( fNegativeSum
))
1549 fNegativeSum
= fFirstNegativeY
= fValueMinY
;
1551 fNegativeSum
+= fValueMinY
;
1554 rfMinimumY
= ::rtl::math::isNan( fNegativeSum
) ? fFirstPositiveY
: fNegativeSum
;
1555 rfMaximumY
= ::rtl::math::isNan( fPositiveSum
) ? fFirstNegativeY
: fPositiveSum
;
1559 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1561 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1564 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1565 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1567 if( ::rtl::math::isNan( fTotalSum
) )
1569 rfMinimumY
= fValueMinY
;
1570 rfMaximumY
= fTotalSum
= fValueMaxY
;
1574 fTotalSum
+= fValueMaxY
;
1575 if( rfMinimumY
> fTotalSum
)
1576 rfMinimumY
= fTotalSum
;
1577 if( rfMaximumY
< fTotalSum
)
1578 rfMaximumY
= fTotalSum
;
1583 aCachedYValues
.m_fMinimumY
= rfMinimumY
;
1584 aCachedYValues
.m_fMaximumY
= rfMaximumY
;
1585 aCachedYValues
.m_bValuesDirty
= false;
1586 m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
]=aCachedYValues
;
1589 void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
1590 sal_Int32 nStartCategoryIndex
, sal_Int32 nEndCategoryIndex
1591 , bool bSeperateStackingForDifferentSigns
1592 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1594 //@todo maybe cache these values
1595 ::rtl::math::setInf(&rfMinimumY
, false);
1596 ::rtl::math::setInf(&rfMaximumY
, true);
1598 //iterate through the given categories
1599 if(nStartCategoryIndex
<0)
1600 nStartCategoryIndex
=0;
1601 if(nEndCategoryIndex
<0)
1602 nEndCategoryIndex
=0;
1603 for( sal_Int32 nCatIndex
= nStartCategoryIndex
; nCatIndex
<= nEndCategoryIndex
; nCatIndex
++ )
1605 double fMinimumY
; ::rtl::math::setNan(&fMinimumY
);
1606 double fMaximumY
; ::rtl::math::setNan(&fMaximumY
);
1608 this->calculateYMinAndMaxForCategory( nCatIndex
1609 , bSeperateStackingForDifferentSigns
, fMinimumY
, fMaximumY
, nAxisIndex
);
1611 if(rfMinimumY
> fMinimumY
)
1612 rfMinimumY
= fMinimumY
;
1613 if(rfMaximumY
< fMaximumY
)
1614 rfMaximumY
= fMaximumY
;
1618 double VSeriesPlotter::getTransformedDepth() const
1620 double MinZ
= m_pMainPosHelper
->getLogicMinZ();
1621 double MaxZ
= m_pMainPosHelper
->getLogicMaxZ();
1622 m_pMainPosHelper
->doLogicScaling( 0, 0, &MinZ
);
1623 m_pMainPosHelper
->doLogicScaling( 0, 0, &MaxZ
);
1624 return FIXED_SIZE_FOR_3D_CHART_VOLUME
/(MaxZ
-MinZ
);
1627 void SAL_CALL
VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData
& rScale
, sal_Int32 nAxisIndex
)
1628 throw (uno::RuntimeException
)
1633 m_aSecondaryValueScales
[nAxisIndex
]=rScale
;
1636 PlottingPositionHelper
& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex
) const
1638 PlottingPositionHelper
* pRet
= 0;
1641 tSecondaryPosHelperMap::const_iterator aPosIt
= m_aSecondaryPosHelperMap
.find( nAxisIndex
);
1642 if( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
1644 pRet
= aPosIt
->second
;
1648 tSecondaryValueScales::const_iterator aScaleIt
= m_aSecondaryValueScales
.find( nAxisIndex
);
1649 if( aScaleIt
!= m_aSecondaryValueScales
.end() )
1651 pRet
= m_pPosHelper
->createSecondaryPosHelper( aScaleIt
->second
);
1652 m_aSecondaryPosHelperMap
[nAxisIndex
] = pRet
;
1658 pRet
= m_pMainPosHelper
;
1663 void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size
& /*rPageSize*/ )
1667 VDataSeries
* VSeriesPlotter::getFirstSeries() const
1669 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1670 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1671 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1673 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1674 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1676 if( aXSlotIter
!= aXSlotEnd
)
1678 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1679 if( aSeriesGroup
.m_aSeriesVector
.size() )
1681 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1690 uno::Sequence
< rtl::OUString
> VSeriesPlotter::getSeriesNames() const
1692 ::std::vector
< rtl::OUString
> aRetVector
;
1694 rtl::OUString aRole
;
1695 if( m_xChartTypeModel
.is() )
1696 aRole
= m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel();
1698 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1699 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1700 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1702 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1703 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1705 if( aXSlotIter
!= aXSlotEnd
)
1707 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1708 if( aSeriesGroup
.m_aSeriesVector
.size() )
1710 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1711 uno::Reference
< XDataSeries
> xSeries( pSeries
? pSeries
->getModel() : 0 );
1714 rtl::OUString
aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries
, aRole
) );
1715 aRetVector
.push_back( aSeriesName
);
1720 return ContainerHelper::ContainerToSequence( aRetVector
);
1725 struct lcl_setRefSizeAtSeriesGroup
: public ::std::unary_function
< VDataSeriesGroup
, void >
1727 lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize
) : m_aRefSize( aRefSize
) {}
1728 void operator()( VDataSeriesGroup
& rGroup
)
1730 ::std::vector
< VDataSeries
* >::iterator
aIt( rGroup
.m_aSeriesVector
.begin());
1731 const ::std::vector
< VDataSeries
* >::iterator
aEndIt( rGroup
.m_aSeriesVector
.end());
1732 for( ; aIt
!= aEndIt
; ++aIt
)
1733 (*aIt
)->setPageReferenceSize( m_aRefSize
);
1737 awt::Size m_aRefSize
;
1739 } // anonymous namespace
1741 void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size
& rPageRefSize
)
1743 m_aPageReferenceSize
= rPageRefSize
;
1745 // set reference size also at all data series
1747 ::std::vector
< VDataSeriesGroup
> aSeriesGroups( FlattenVector( m_aZSlots
));
1748 ::std::for_each( aSeriesGroups
.begin(), aSeriesGroups
.end(),
1749 lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize
));
1752 //better performance for big data
1753 void VSeriesPlotter::setCoordinateSystemResolution( const Sequence
< sal_Int32
>& rCoordinateSystemResolution
)
1755 m_aCoordinateSystemResolution
= rCoordinateSystemResolution
;
1758 bool VSeriesPlotter::PointsWereSkipped() const
1760 return m_bPointsWereSkipped
;
1763 bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
1765 return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel
);
1768 Sequence
< ViewLegendEntry
> SAL_CALL
VSeriesPlotter::createLegendEntries(
1769 LegendExpansion eLegendExpansion
1770 , const Reference
< beans::XPropertySet
>& xTextProperties
1771 , const Reference
< drawing::XShapes
>& xTarget
1772 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
1773 , const Reference
< uno::XComponentContext
>& xContext
1774 ) throw (uno::RuntimeException
)
1776 std::vector
< ViewLegendEntry
> aResult
;
1780 //iterate through all series
1781 bool bBreak
= false;
1782 bool bFirstSeries
= true;
1783 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
1784 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1785 for( ; aZSlotIter
!=aZSlotEnd
&& !bBreak
; aZSlotIter
++ )
1787 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
1788 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1789 for( ; aXSlotIter
!=aXSlotEnd
&& !bBreak
; aXSlotIter
++ )
1791 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
1792 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1793 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1794 //iterate through all series in this x slot
1795 for( ; aSeriesIter
!=aSeriesEnd
&& !bBreak
; ++aSeriesIter
)
1797 VDataSeries
* pSeries( *aSeriesIter
);
1801 std::vector
< ViewLegendEntry
> aSeriesEntries( this->createLegendEntriesForSeries(
1802 *pSeries
, xTextProperties
, xTarget
, xShapeFactory
, xContext
) );
1804 //add series entries to the result now
1806 // use only the first series if VaryColorsByPoint is set for the first series
1807 if( bFirstSeries
&& pSeries
->isVaryColorsByPoint() )
1809 bFirstSeries
= false;
1811 // add entries reverse if chart is stacked in y-direction and the legend is not wide.
1812 // If the legend is wide and we have a stacked bar-chart the normal order
1813 // is the correct one
1814 bool bReverse
= false;
1815 if( eLegendExpansion
!= LegendExpansion_WIDE
)
1817 StackingDirection
eStackingDirection( pSeries
->getStackingDirection() );
1818 bReverse
= ( eStackingDirection
== StackingDirection_Y_STACKING
);
1820 //todo: respect direction of axis in future
1824 aResult
.insert( aResult
.begin(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
1826 aResult
.insert( aResult
.end(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
1831 //add charttype specific entries if any
1833 std::vector
< ViewLegendEntry
> aChartTypeEntries( this->createLegendEntriesForChartType(
1834 xTextProperties
, xTarget
, xShapeFactory
, xContext
) );
1835 aResult
.insert( aResult
.end(), aChartTypeEntries
.begin(), aChartTypeEntries
.end() );
1839 return ::chart::ContainerHelper::ContainerToSequence( aResult
);
1843 LegendSymbolStyle
VSeriesPlotter::getLegendSymbolStyle()
1845 return chart2::LegendSymbolStyle_BOX
;
1849 uno::Any
VSeriesPlotter::getExplicitSymbol( const VDataSeries
& /*rSeries*/, sal_Int32
/*nPointIndex*/ )
1854 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForSeries(
1855 const VDataSeries
& rSeries
1856 , const Reference
< drawing::XShapes
>& xTarget
1857 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
1860 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
1861 uno::Any
aExplicitSymbol( this->getExplicitSymbol( rSeries
) );
1863 VLegendSymbolFactory::tPropertyType ePropType
=
1864 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
1866 // todo: maybe the property-style does not solely depend on the
1867 // legend-symbol type
1868 switch( eLegendSymbolStyle
)
1870 case LegendSymbolStyle_HORIZONTAL_LINE
:
1871 case LegendSymbolStyle_VERTICAL_LINE
:
1872 case LegendSymbolStyle_DIAGONAL_LINE
:
1873 case LegendSymbolStyle_LINE_WITH_BOX
:
1874 case LegendSymbolStyle_LINE_WITH_SYMBOL
:
1875 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
1880 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol(
1881 xTarget
, eLegendSymbolStyle
, xShapeFactory
1882 , rSeries
.getPropertiesOfSeries(), ePropType
, aExplicitSymbol
));
1887 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForPoint(
1888 const VDataSeries
& rSeries
1889 , sal_Int32 nPointIndex
1890 , const Reference
< drawing::XShapes
>& xTarget
1891 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
1894 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
1895 uno::Any
aExplicitSymbol( this->getExplicitSymbol(rSeries
,nPointIndex
) );
1897 VLegendSymbolFactory::tPropertyType ePropType
=
1898 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
1900 // todo: maybe the property-style does not solely depend on the
1901 // legend-symbol type
1902 switch( eLegendSymbolStyle
)
1904 case LegendSymbolStyle_HORIZONTAL_LINE
:
1905 case LegendSymbolStyle_VERTICAL_LINE
:
1906 case LegendSymbolStyle_DIAGONAL_LINE
:
1907 case LegendSymbolStyle_LINE_WITH_BOX
:
1908 case LegendSymbolStyle_LINE_WITH_SYMBOL
:
1909 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
1915 // the default properties for the data point are the data series properties.
1916 // If a data point has own attributes overwrite them
1917 Reference
< beans::XPropertySet
> xSeriesProps( rSeries
.getPropertiesOfSeries() );
1918 Reference
< beans::XPropertySet
> xPointSet( xSeriesProps
);
1919 if( rSeries
.isAttributedDataPoint( nPointIndex
) )
1920 xPointSet
.set( rSeries
.getPropertiesOfPoint( nPointIndex
));
1922 // if a data point has no own color use a color fom the diagram's color scheme
1923 if( ! rSeries
.hasPointOwnColor( nPointIndex
))
1925 Reference
< util::XCloneable
> xCloneable( xPointSet
,uno::UNO_QUERY
);
1926 if( xCloneable
.is() && m_xColorScheme
.is() )
1928 xPointSet
.set( xCloneable
->createClone(), uno::UNO_QUERY
);
1929 Reference
< container::XChild
> xChild( xPointSet
, uno::UNO_QUERY
);
1931 xChild
->setParent( xSeriesProps
);
1933 OSL_ASSERT( xPointSet
.is());
1934 xPointSet
->setPropertyValue(
1935 C2U("Color"), uno::makeAny( m_xColorScheme
->getColorByIndex( nPointIndex
)));
1939 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol(
1940 xTarget
, eLegendSymbolStyle
, xShapeFactory
, xPointSet
, ePropType
, aExplicitSymbol
));
1945 std::vector
< ViewLegendEntry
> SAL_CALL
VSeriesPlotter::createLegendEntriesForSeries(
1946 const VDataSeries
& rSeries
1947 , const Reference
< beans::XPropertySet
>& xTextProperties
1948 , const Reference
< drawing::XShapes
>& xTarget
1949 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
1950 , const Reference
< uno::XComponentContext
>& xContext
1953 std::vector
< ViewLegendEntry
> aResult
;
1955 if( ! ( xShapeFactory
.is() && xTarget
.is() && xContext
.is() ) )
1960 ViewLegendEntry aEntry
;
1961 OUString aLabelText
;
1962 bool bVaryColorsByPoint
= rSeries
.isVaryColorsByPoint();
1963 if( bVaryColorsByPoint
)
1965 Sequence
< OUString
> aCategoryNames
;
1966 if( m_xExplicitCategoriesProvider
.is() )
1967 aCategoryNames
= m_xExplicitCategoriesProvider
->getTextualData();
1969 for( sal_Int32 nIdx
=0; nIdx
<aCategoryNames
.getLength(); ++nIdx
)
1972 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
1974 // create the symbol
1975 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForPoint(
1976 rSeries
, nIdx
, xSymbolGroup
, xShapeFactory
) );
1978 // set CID to symbol for selection
1981 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
1983 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT
, nIdx
) );
1984 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
1985 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
1986 ShapeFactory::setShapeName( xShape
, aCID
);
1990 aLabelText
= aCategoryNames
[nIdx
];
1991 if( xShape
.is() || aLabelText
.getLength() )
1993 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
1994 aResult
.push_back(aEntry
);
2001 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
2003 // create the symbol
2004 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForSeries(
2005 rSeries
, xSymbolGroup
, xShapeFactory
) );
2007 // set CID to symbol for selection
2010 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2012 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2013 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2014 ShapeFactory::setShapeName( xShape
, aCID
);
2018 aLabelText
= ( DataSeriesHelper::getDataSeriesLabel( rSeries
.getModel(), m_xChartTypeModel
.is() ? m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel() : C2U("values-y")) );
2019 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
2021 aResult
.push_back(aEntry
);
2024 // regression curves
2025 if ( 3 == m_nDimension
) // #i63016#
2028 Reference
< XRegressionCurveContainer
> xRegrCont( rSeries
.getModel(), uno::UNO_QUERY
);
2031 Sequence
< Reference
< XRegressionCurve
> > aCurves( xRegrCont
->getRegressionCurves());
2032 sal_Int32 i
= 0, nCount
= aCurves
.getLength();
2033 for( i
=0; i
<nCount
; ++i
)
2035 if( aCurves
[i
].is() && !RegressionCurveHelper::isMeanValueLine( aCurves
[i
] ) )
2038 OUString
aResStr( SchResId::getResString( STR_STATISTICS_IN_LEGEND
));
2039 replaceParamterInString( aResStr
, C2U("%REGRESSIONCURVE"), RegressionCurveHelper::getUINameForRegressionCurve( aCurves
[i
] ));
2040 replaceParamterInString( aResStr
, C2U("%SERIESNAME"), aLabelText
);
2041 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aResStr
, xTextProperties
);
2044 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
2046 // create the symbol
2047 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol(
2048 xSymbolGroup
, chart2::LegendSymbolStyle_DIAGONAL_LINE
, xShapeFactory
,
2049 Reference
< beans::XPropertySet
>( aCurves
[i
], uno::UNO_QUERY
),
2050 VLegendSymbolFactory::PROP_TYPE_LINE
, uno::Any() ));
2052 // set CID to symbol for selection
2055 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2057 bool bAverageLine
= false;//@todo find out wether this is an average line or a regression curve
2058 ObjectType eObjectType
= bAverageLine
? OBJECTTYPE_DATA_AVERAGE_LINE
: OBJECTTYPE_DATA_CURVE
;
2059 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType
, i
) );
2060 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2061 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2062 ShapeFactory::setShapeName( xShape
, aCID
);
2065 aResult
.push_back(aEntry
);
2070 catch( uno::Exception
& ex
)
2072 ASSERT_EXCEPTION( ex
);
2077 std::vector
< ViewLegendEntry
> SAL_CALL
VSeriesPlotter::createLegendEntriesForChartType(
2078 const Reference
< beans::XPropertySet
>& /* xTextProperties */,
2079 const Reference
< drawing::XShapes
>& /* xTarget */,
2080 const Reference
< lang::XMultiServiceFactory
>& /* xShapeFactory */,
2081 const Reference
< uno::XComponentContext
>& /* xContext */
2084 return std::vector
< ViewLegendEntry
>();
2088 VSeriesPlotter
* VSeriesPlotter::createSeriesPlotter(
2089 const uno::Reference
<XChartType
>& xChartTypeModel
2090 , sal_Int32 nDimensionCount
)
2092 rtl::OUString aChartType
= xChartTypeModel
->getChartType();
2094 //@todo: in future the plotter should be instanciated via service factory
2095 VSeriesPlotter
* pRet
=NULL
;
2096 if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN
) )
2097 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2098 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR
) )
2099 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2100 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA
) )
2101 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true);
2102 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE
) )
2103 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true);
2104 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER
) )
2105 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2106 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE
) )
2107 pRet
= new BubbleChart(xChartTypeModel
,nDimensionCount
);
2108 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE
) )
2109 pRet
= new PieChart(xChartTypeModel
,nDimensionCount
);
2110 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET
) )
2111 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true,new PolarPlottingPositionHelper(),true,true,false,1,drawing::Direction3D(1,1,1) );
2112 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET
) )
2113 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,false,new PolarPlottingPositionHelper(),true,true,false,1,drawing::Direction3D(1,1,1) );
2114 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK
) )
2115 pRet
= new CandleStickChart(xChartTypeModel
,nDimensionCount
);
2117 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2121 //.............................................................................
2123 //.............................................................................