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 if( !m_bCategoryXAxis
)
1154 double fMinY
, fMaxY
;
1155 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1159 double fMinimum
, fMaximum
;
1160 ::rtl::math::setInf(&fMinimum
, false);
1161 ::rtl::math::setInf(&fMaximum
, true);
1162 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1164 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1165 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1167 double fLocalMinimum
, fLocalMaximum
;
1168 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1169 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1170 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1171 , isSeperateStackingForDifferentSigns( 1 )
1172 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1173 if(fMaximum
<fLocalMaximum
)
1174 fMaximum
=fLocalMaximum
;
1175 if(fMinimum
>fLocalMinimum
)
1176 fMinimum
=fLocalMinimum
;
1179 if(::rtl::math::isInf(fMinimum
))
1180 ::rtl::math::setNan(&fMinimum
);
1184 double VSeriesPlotter::getMaximumYInRange( double fMinimumX
, double fMaximumX
, sal_Int32 nAxisIndex
)
1186 if( !m_bCategoryXAxis
)
1188 double fMinY
, fMaxY
;
1189 this->getMinimumAndMaximiumYInContinuousXRange( fMinY
, fMaxY
, fMinimumX
, fMaximumX
, nAxisIndex
);
1193 double fMinimum
, fMaximum
;
1194 ::rtl::math::setInf(&fMinimum
, false);
1195 ::rtl::math::setInf(&fMaximum
, true);
1196 for(size_t nZ
=0; nZ
<m_aZSlots
.size();nZ
++ )
1198 ::std::vector
< VDataSeriesGroup
>& rXSlots
= m_aZSlots
[nZ
];
1199 for(size_t nN
=0; nN
<rXSlots
.size();nN
++ )
1201 double fLocalMinimum
, fLocalMaximum
;
1202 rXSlots
[nN
].calculateYMinAndMaxForCategoryRange(
1203 static_cast<sal_Int32
>(fMinimumX
-1.0) //first category (index 0) matches with real number 1.0
1204 , static_cast<sal_Int32
>(fMaximumX
-1.0) //first category (index 0) matches with real number 1.0
1205 , isSeperateStackingForDifferentSigns( 1 )
1206 , fLocalMinimum
, fLocalMaximum
, nAxisIndex
);
1207 if(fMaximum
<fLocalMaximum
)
1208 fMaximum
=fLocalMaximum
;
1209 if(fMinimum
>fLocalMinimum
)
1210 fMinimum
=fLocalMinimum
;
1213 if(::rtl::math::isInf(fMaximum
))
1214 ::rtl::math::setNan(&fMaximum
);
1218 double VSeriesPlotter::getMinimumZ()
1220 //this is the default for all charts without a meaningfull z axis
1223 double VSeriesPlotter::getMaximumZ()
1225 if( 3!=m_nDimension
)
1227 return m_aZSlots
.size()+0.5;
1232 bool lcl_isValueAxis( sal_Int32 nDimensionIndex
, bool bCategoryXAxis
)
1234 // default implementation: true for Y axes, and for value X axis
1235 if( nDimensionIndex
== 0 )
1236 return !bCategoryXAxis
;
1237 if( nDimensionIndex
== 1 )
1243 bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex
)
1245 return lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1248 bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex
)
1250 // do not expand axes in 3D charts
1251 return (m_nDimension
< 3) && lcl_isValueAxis( nDimensionIndex
, m_bCategoryXAxis
);
1254 bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex
)
1256 // default implementation: only for Y axis
1257 return nDimensionIndex
== 1;
1260 bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex
)
1262 // default implementation: only for Y axis
1263 return nDimensionIndex
== 1;
1266 bool VSeriesPlotter::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex
)
1268 // default implementation: only for Y axis
1269 return nDimensionIndex
== 1;
1272 void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1274 ::rtl::math::setInf(&rfMinimum
, false);
1275 ::rtl::math::setInf(&rfMaximum
, true);
1277 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1278 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1279 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
1281 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1282 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1283 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
1285 double fLocalMinimum
, fLocalMaximum
;
1286 aXSlotIter
->getMinimumAndMaximiumX( fLocalMinimum
, fLocalMaximum
);
1287 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinimum
)
1288 rfMinimum
= fLocalMinimum
;
1289 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaximum
)
1290 rfMaximum
= fLocalMaximum
;
1293 if(::rtl::math::isInf(rfMinimum
))
1294 ::rtl::math::setNan(&rfMinimum
);
1295 if(::rtl::math::isInf(rfMaximum
))
1296 ::rtl::math::setNan(&rfMaximum
);
1299 void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1301 ::rtl::math::setInf(&rfMinY
, false);
1302 ::rtl::math::setInf(&rfMaxY
, true);
1304 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1305 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1306 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
1308 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1309 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1310 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
1312 double fLocalMinimum
, fLocalMaximum
;
1313 aXSlotIter
->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum
, fLocalMaximum
, fMinX
, fMaxX
, nAxisIndex
);
1314 if( !::rtl::math::isNan(fLocalMinimum
) && fLocalMinimum
< rfMinY
)
1315 rfMinY
= fLocalMinimum
;
1316 if( !::rtl::math::isNan(fLocalMaximum
) && fLocalMaximum
> rfMaxY
)
1317 rfMaxY
= fLocalMaximum
;
1320 if(::rtl::math::isInf(rfMinY
))
1321 ::rtl::math::setNan(&rfMinY
);
1322 if(::rtl::math::isInf(rfMaxY
))
1323 ::rtl::math::setNan(&rfMaxY
);
1326 sal_Int32
VSeriesPlotter::getPointCount() const
1330 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotIter
= m_aZSlots
.begin();
1331 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1333 for( ; aZSlotIter
!= aZSlotEnd
; aZSlotIter
++ )
1335 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1336 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1338 for( ; aXSlotIter
!= aXSlotEnd
; aXSlotIter
++ )
1340 sal_Int32 nPointCount
= aXSlotIter
->getPointCount();
1341 if( nPointCount
>nRet
)
1348 void VSeriesPlotter::setNumberFormatsSupplier(
1349 const uno::Reference
< util::XNumberFormatsSupplier
> & xNumFmtSupplier
)
1351 m_apNumberFormatterWrapper
.reset( new NumberFormatterWrapper( xNumFmtSupplier
));
1354 void VSeriesPlotter::setColorScheme( const uno::Reference
< XColorScheme
>& xColorScheme
)
1356 m_xColorScheme
= xColorScheme
;
1359 void VSeriesPlotter::setExplicitCategoriesProvider( const uno::Reference
< data::XTextualDataSequence
>& xExplicitCategoriesProvider
)
1361 m_xExplicitCategoriesProvider
= xExplicitCategoriesProvider
;
1364 sal_Int32
VDataSeriesGroup::getPointCount() const
1366 if(!m_bMaxPointCountDirty
)
1367 return m_nMaxPointCount
;
1370 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1371 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1373 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
1375 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1376 if( nPointCount
>nRet
)
1379 m_nMaxPointCount
=nRet
;
1380 m_aListOfCachedYValues
.clear();
1381 m_aListOfCachedYValues
.resize(m_nMaxPointCount
);
1382 m_bMaxPointCountDirty
=false;
1386 sal_Int32
VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1389 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1390 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1392 if( aSeriesIter
!= aSeriesEnd
)
1393 nRet
= (*aSeriesIter
)->getAttachedAxisIndex();
1398 void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum
, double& rfMaximum
) const
1400 const ::std::vector
< VDataSeries
* >* pSeriesList
= &this->m_aSeriesVector
;
1402 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1403 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1405 ::rtl::math::setInf(&rfMinimum
, false);
1406 ::rtl::math::setInf(&rfMaximum
, true);
1408 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
1410 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1411 for(sal_Int32 nN
=0;nN
<nPointCount
;nN
++)
1413 double fX
= (*aSeriesIter
)->getXValue( nN
);
1414 if( ::rtl::math::isNan(fX
) )
1422 if(::rtl::math::isInf(rfMinimum
))
1423 ::rtl::math::setNan(&rfMinimum
);
1424 if(::rtl::math::isInf(rfMaximum
))
1425 ::rtl::math::setNan(&rfMaximum
);
1427 void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY
, double& rfMaxY
, double fMinX
, double fMaxX
, sal_Int32 nAxisIndex
) const
1429 const ::std::vector
< VDataSeries
* >* pSeriesList
= &this->m_aSeriesVector
;
1431 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1432 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1434 ::rtl::math::setInf(&rfMinY
, false);
1435 ::rtl::math::setInf(&rfMaxY
, true);
1437 for( ; aSeriesIter
!= aSeriesEnd
; aSeriesIter
++ )
1439 sal_Int32 nPointCount
= (*aSeriesIter
)->getTotalPointCount();
1440 for(sal_Int32 nN
=0;nN
<nPointCount
;nN
++)
1442 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1445 double fX
= (*aSeriesIter
)->getXValue( nN
);
1446 if( ::rtl::math::isNan(fX
) )
1448 if( fX
< fMinX
|| fX
> fMaxX
)
1450 double fY
= (*aSeriesIter
)->getYValue( nN
);
1451 if( ::rtl::math::isNan(fY
) )
1459 if(::rtl::math::isInf(rfMinY
))
1460 ::rtl::math::setNan(&rfMinY
);
1461 if(::rtl::math::isInf(rfMaxY
))
1462 ::rtl::math::setNan(&rfMaxY
);
1465 void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
1466 , bool bSeperateStackingForDifferentSigns
1467 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1469 ::rtl::math::setInf(&rfMinimumY
, false);
1470 ::rtl::math::setInf(&rfMaximumY
, true);
1472 sal_Int32 nPointCount
= getPointCount();//necessary to create m_aListOfCachedYValues
1473 if(nCategoryIndex
<0 || nCategoryIndex
>=nPointCount
|| m_aSeriesVector
.empty())
1476 CachedYValues aCachedYValues
= m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
];
1477 if( !aCachedYValues
.m_bValuesDirty
)
1479 //return cached values
1480 rfMinimumY
= aCachedYValues
.m_fMinimumY
;
1481 rfMaximumY
= aCachedYValues
.m_fMaximumY
;
1485 double fTotalSum
, fPositiveSum
, fNegativeSum
, fFirstPositiveY
, fFirstNegativeY
;
1486 ::rtl::math::setNan( &fTotalSum
);
1487 ::rtl::math::setNan( &fPositiveSum
);
1488 ::rtl::math::setNan( &fNegativeSum
);
1489 ::rtl::math::setNan( &fFirstPositiveY
);
1490 ::rtl::math::setNan( &fFirstNegativeY
);
1492 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= m_aSeriesVector
.begin();
1493 ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= m_aSeriesVector
.end();
1495 if( bSeperateStackingForDifferentSigns
)
1497 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1499 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1502 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1503 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1505 if( fValueMaxY
>= 0 )
1507 if( ::rtl::math::isNan( fPositiveSum
) )
1508 fPositiveSum
= fFirstPositiveY
= fValueMaxY
;
1510 fPositiveSum
+= fValueMaxY
;
1512 if( fValueMinY
< 0 )
1514 if(::rtl::math::isNan( fNegativeSum
))
1515 fNegativeSum
= fFirstNegativeY
= fValueMinY
;
1517 fNegativeSum
+= fValueMinY
;
1520 rfMinimumY
= ::rtl::math::isNan( fNegativeSum
) ? fFirstPositiveY
: fNegativeSum
;
1521 rfMaximumY
= ::rtl::math::isNan( fPositiveSum
) ? fFirstNegativeY
: fPositiveSum
;
1525 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
1527 if( nAxisIndex
!= (*aSeriesIter
)->getAttachedAxisIndex() )
1530 double fValueMinY
= (*aSeriesIter
)->getMinimumofAllDifferentYValues( nCategoryIndex
);
1531 double fValueMaxY
= (*aSeriesIter
)->getMaximumofAllDifferentYValues( nCategoryIndex
);
1533 if( ::rtl::math::isNan( fTotalSum
) )
1535 rfMinimumY
= fValueMinY
;
1536 rfMaximumY
= fTotalSum
= fValueMaxY
;
1540 fTotalSum
+= fValueMaxY
;
1541 if( rfMinimumY
> fTotalSum
)
1542 rfMinimumY
= fTotalSum
;
1543 if( rfMaximumY
< fTotalSum
)
1544 rfMaximumY
= fTotalSum
;
1549 aCachedYValues
.m_fMinimumY
= rfMinimumY
;
1550 aCachedYValues
.m_fMaximumY
= rfMaximumY
;
1551 aCachedYValues
.m_bValuesDirty
= false;
1552 m_aListOfCachedYValues
[nCategoryIndex
][nAxisIndex
]=aCachedYValues
;
1555 void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
1556 sal_Int32 nStartCategoryIndex
, sal_Int32 nEndCategoryIndex
1557 , bool bSeperateStackingForDifferentSigns
1558 , double& rfMinimumY
, double& rfMaximumY
, sal_Int32 nAxisIndex
)
1560 //@todo maybe cache these values
1561 ::rtl::math::setInf(&rfMinimumY
, false);
1562 ::rtl::math::setInf(&rfMaximumY
, true);
1564 //iterate through the given categories
1565 if(nStartCategoryIndex
<0)
1566 nStartCategoryIndex
=0;
1567 if(nEndCategoryIndex
<0)
1568 nEndCategoryIndex
=0;
1569 for( sal_Int32 nCatIndex
= nStartCategoryIndex
; nCatIndex
<= nEndCategoryIndex
; nCatIndex
++ )
1571 double fMinimumY
; ::rtl::math::setNan(&fMinimumY
);
1572 double fMaximumY
; ::rtl::math::setNan(&fMaximumY
);
1574 this->calculateYMinAndMaxForCategory( nCatIndex
1575 , bSeperateStackingForDifferentSigns
, fMinimumY
, fMaximumY
, nAxisIndex
);
1577 if(rfMinimumY
> fMinimumY
)
1578 rfMinimumY
= fMinimumY
;
1579 if(rfMaximumY
< fMaximumY
)
1580 rfMaximumY
= fMaximumY
;
1584 double VSeriesPlotter::getTransformedDepth() const
1586 double MinZ
= m_pMainPosHelper
->getLogicMinZ();
1587 double MaxZ
= m_pMainPosHelper
->getLogicMaxZ();
1588 m_pMainPosHelper
->doLogicScaling( 0, 0, &MinZ
);
1589 m_pMainPosHelper
->doLogicScaling( 0, 0, &MaxZ
);
1590 return FIXED_SIZE_FOR_3D_CHART_VOLUME
/(MaxZ
-MinZ
);
1593 void SAL_CALL
VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData
& rScale
, sal_Int32 nAxisIndex
)
1594 throw (uno::RuntimeException
)
1599 m_aSecondaryValueScales
[nAxisIndex
]=rScale
;
1602 PlottingPositionHelper
& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex
) const
1604 PlottingPositionHelper
* pRet
= 0;
1607 tSecondaryPosHelperMap::const_iterator aPosIt
= m_aSecondaryPosHelperMap
.find( nAxisIndex
);
1608 if( aPosIt
!= m_aSecondaryPosHelperMap
.end() )
1610 pRet
= aPosIt
->second
;
1614 tSecondaryValueScales::const_iterator aScaleIt
= m_aSecondaryValueScales
.find( nAxisIndex
);
1615 if( aScaleIt
!= m_aSecondaryValueScales
.end() )
1617 pRet
= m_pPosHelper
->createSecondaryPosHelper( aScaleIt
->second
);
1618 m_aSecondaryPosHelperMap
[nAxisIndex
] = pRet
;
1624 pRet
= m_pMainPosHelper
;
1629 void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size
& /*rPageSize*/ )
1633 VDataSeries
* VSeriesPlotter::getFirstSeries() const
1635 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1636 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1637 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1639 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1640 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1642 if( aXSlotIter
!= aXSlotEnd
)
1644 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1645 if( aSeriesGroup
.m_aSeriesVector
.size() )
1647 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1656 uno::Sequence
< rtl::OUString
> VSeriesPlotter::getSeriesNames() const
1658 ::std::vector
< rtl::OUString
> aRetVector
;
1660 rtl::OUString aRole
;
1661 if( m_xChartTypeModel
.is() )
1662 aRole
= m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel();
1664 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotIter( m_aZSlots
.begin() );
1665 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator
aZSlotEnd( m_aZSlots
.end() );
1666 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
1668 ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotIter
= aZSlotIter
->begin();
1669 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1671 if( aXSlotIter
!= aXSlotEnd
)
1673 VDataSeriesGroup
aSeriesGroup( *aXSlotIter
);
1674 if( aSeriesGroup
.m_aSeriesVector
.size() )
1676 VDataSeries
* pSeries
= aSeriesGroup
.m_aSeriesVector
[0];
1677 uno::Reference
< XDataSeries
> xSeries( pSeries
? pSeries
->getModel() : 0 );
1680 rtl::OUString
aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries
, aRole
) );
1681 aRetVector
.push_back( aSeriesName
);
1686 return ContainerHelper::ContainerToSequence( aRetVector
);
1691 struct lcl_setRefSizeAtSeriesGroup
: public ::std::unary_function
< VDataSeriesGroup
, void >
1693 lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize
) : m_aRefSize( aRefSize
) {}
1694 void operator()( VDataSeriesGroup
& rGroup
)
1696 ::std::vector
< VDataSeries
* >::iterator
aIt( rGroup
.m_aSeriesVector
.begin());
1697 const ::std::vector
< VDataSeries
* >::iterator
aEndIt( rGroup
.m_aSeriesVector
.end());
1698 for( ; aIt
!= aEndIt
; ++aIt
)
1699 (*aIt
)->setPageReferenceSize( m_aRefSize
);
1703 awt::Size m_aRefSize
;
1705 } // anonymous namespace
1707 void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size
& rPageRefSize
)
1709 m_aPageReferenceSize
= rPageRefSize
;
1711 // set reference size also at all data series
1713 ::std::vector
< VDataSeriesGroup
> aSeriesGroups( FlattenVector( m_aZSlots
));
1714 ::std::for_each( aSeriesGroups
.begin(), aSeriesGroups
.end(),
1715 lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize
));
1718 //better performance for big data
1719 void VSeriesPlotter::setCoordinateSystemResolution( const Sequence
< sal_Int32
>& rCoordinateSystemResolution
)
1721 m_aCoordinateSystemResolution
= rCoordinateSystemResolution
;
1724 bool VSeriesPlotter::PointsWereSkipped() const
1726 return m_bPointsWereSkipped
;
1729 bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
1731 return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel
);
1734 Sequence
< ViewLegendEntry
> SAL_CALL
VSeriesPlotter::createLegendEntries(
1735 LegendExpansion eLegendExpansion
1736 , const Reference
< beans::XPropertySet
>& xTextProperties
1737 , const Reference
< drawing::XShapes
>& xTarget
1738 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
1739 , const Reference
< uno::XComponentContext
>& xContext
1740 ) throw (uno::RuntimeException
)
1742 std::vector
< ViewLegendEntry
> aResult
;
1746 //iterate through all series
1747 bool bBreak
= false;
1748 bool bFirstSeries
= true;
1749 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
1750 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
1751 for( ; aZSlotIter
!=aZSlotEnd
&& !bBreak
; aZSlotIter
++ )
1753 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
1754 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
1755 for( ; aXSlotIter
!=aXSlotEnd
&& !bBreak
; aXSlotIter
++ )
1757 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
1758 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
1759 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
1760 //iterate through all series in this x slot
1761 for( ; aSeriesIter
!=aSeriesEnd
&& !bBreak
; ++aSeriesIter
)
1763 VDataSeries
* pSeries( *aSeriesIter
);
1767 std::vector
< ViewLegendEntry
> aSeriesEntries( this->createLegendEntriesForSeries(
1768 *pSeries
, xTextProperties
, xTarget
, xShapeFactory
, xContext
) );
1770 //add series entries to the result now
1772 // use only the first series if VaryColorsByPoint is set for the first series
1773 if( bFirstSeries
&& pSeries
->isVaryColorsByPoint() )
1775 bFirstSeries
= false;
1777 // add entries reverse if chart is stacked in y-direction and the legend is not wide.
1778 // If the legend is wide and we have a stacked bar-chart the normal order
1779 // is the correct one
1780 bool bReverse
= false;
1781 if( eLegendExpansion
!= LegendExpansion_WIDE
)
1783 StackingDirection
eStackingDirection( pSeries
->getStackingDirection() );
1784 bReverse
= ( eStackingDirection
== StackingDirection_Y_STACKING
);
1786 //todo: respect direction of axis in future
1790 aResult
.insert( aResult
.begin(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
1792 aResult
.insert( aResult
.end(), aSeriesEntries
.begin(), aSeriesEntries
.end() );
1797 //add charttype specific entries if any
1799 std::vector
< ViewLegendEntry
> aChartTypeEntries( this->createLegendEntriesForChartType(
1800 xTextProperties
, xTarget
, xShapeFactory
, xContext
) );
1801 aResult
.insert( aResult
.end(), aChartTypeEntries
.begin(), aChartTypeEntries
.end() );
1805 return ::chart::ContainerHelper::ContainerToSequence( aResult
);
1809 LegendSymbolStyle
VSeriesPlotter::getLegendSymbolStyle()
1811 return chart2::LegendSymbolStyle_BOX
;
1815 uno::Any
VSeriesPlotter::getExplicitSymbol( const VDataSeries
& /*rSeries*/, sal_Int32
/*nPointIndex*/ )
1820 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForSeries(
1821 const VDataSeries
& rSeries
1822 , const Reference
< drawing::XShapes
>& xTarget
1823 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
1826 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
1827 uno::Any
aExplicitSymbol( this->getExplicitSymbol( rSeries
) );
1829 VLegendSymbolFactory::tPropertyType ePropType
=
1830 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES
;
1832 // todo: maybe the property-style does not solely depend on the
1833 // legend-symbol type
1834 switch( eLegendSymbolStyle
)
1836 case LegendSymbolStyle_HORIZONTAL_LINE
:
1837 case LegendSymbolStyle_VERTICAL_LINE
:
1838 case LegendSymbolStyle_DIAGONAL_LINE
:
1839 case LegendSymbolStyle_LINE_WITH_BOX
:
1840 case LegendSymbolStyle_LINE_WITH_SYMBOL
:
1841 ePropType
= VLegendSymbolFactory::PROP_TYPE_LINE_SERIES
;
1846 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol(
1847 xTarget
, eLegendSymbolStyle
, xShapeFactory
1848 , rSeries
.getPropertiesOfSeries(), ePropType
, aExplicitSymbol
));
1853 Reference
< drawing::XShape
> VSeriesPlotter::createLegendSymbolForPoint(
1854 const VDataSeries
& rSeries
1855 , sal_Int32 nPointIndex
1856 , const Reference
< drawing::XShapes
>& xTarget
1857 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
)
1860 LegendSymbolStyle eLegendSymbolStyle
= this->getLegendSymbolStyle();
1861 uno::Any
aExplicitSymbol( this->getExplicitSymbol(rSeries
,nPointIndex
) );
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
;
1881 // the default properties for the data point are the data series properties.
1882 // If a data point has own attributes overwrite them
1883 Reference
< beans::XPropertySet
> xSeriesProps( rSeries
.getPropertiesOfSeries() );
1884 Reference
< beans::XPropertySet
> xPointSet( xSeriesProps
);
1885 if( rSeries
.isAttributedDataPoint( nPointIndex
) )
1886 xPointSet
.set( rSeries
.getPropertiesOfPoint( nPointIndex
));
1888 // if a data point has no own color use a color fom the diagram's color scheme
1889 if( ! rSeries
.hasPointOwnColor( nPointIndex
))
1891 Reference
< util::XCloneable
> xCloneable( xPointSet
,uno::UNO_QUERY
);
1892 if( xCloneable
.is() && m_xColorScheme
.is() )
1894 xPointSet
.set( xCloneable
->createClone(), uno::UNO_QUERY
);
1895 Reference
< container::XChild
> xChild( xPointSet
, uno::UNO_QUERY
);
1897 xChild
->setParent( xSeriesProps
);
1899 OSL_ASSERT( xPointSet
.is());
1900 xPointSet
->setPropertyValue(
1901 C2U("Color"), uno::makeAny( m_xColorScheme
->getColorByIndex( nPointIndex
)));
1905 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol(
1906 xTarget
, eLegendSymbolStyle
, xShapeFactory
, xPointSet
, ePropType
, aExplicitSymbol
));
1911 std::vector
< ViewLegendEntry
> SAL_CALL
VSeriesPlotter::createLegendEntriesForSeries(
1912 const VDataSeries
& rSeries
1913 , const Reference
< beans::XPropertySet
>& xTextProperties
1914 , const Reference
< drawing::XShapes
>& xTarget
1915 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
1916 , const Reference
< uno::XComponentContext
>& xContext
1919 std::vector
< ViewLegendEntry
> aResult
;
1921 if( ! ( xShapeFactory
.is() && xTarget
.is() && xContext
.is() ) )
1926 ViewLegendEntry aEntry
;
1927 OUString aLabelText
;
1928 bool bVaryColorsByPoint
= rSeries
.isVaryColorsByPoint();
1929 if( bVaryColorsByPoint
)
1931 Sequence
< OUString
> aCategoryNames
;
1932 if( m_xExplicitCategoriesProvider
.is() )
1933 aCategoryNames
= m_xExplicitCategoriesProvider
->getTextualData();
1935 for( sal_Int32 nIdx
=0; nIdx
<aCategoryNames
.getLength(); ++nIdx
)
1938 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
1940 // create the symbol
1941 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForPoint(
1942 rSeries
, nIdx
, xSymbolGroup
, xShapeFactory
) );
1944 // set CID to symbol for selection
1947 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
1949 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT
, nIdx
) );
1950 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
1951 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
1952 ShapeFactory::setShapeName( xShape
, aCID
);
1956 aLabelText
= aCategoryNames
[nIdx
];
1957 if( xShape
.is() || aLabelText
.getLength() )
1959 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
1960 aResult
.push_back(aEntry
);
1967 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
1969 // create the symbol
1970 Reference
< drawing::XShape
> xShape( this->createLegendSymbolForSeries(
1971 rSeries
, xSymbolGroup
, xShapeFactory
) );
1973 // set CID to symbol for selection
1976 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
1978 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
1979 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
1980 ShapeFactory::setShapeName( xShape
, aCID
);
1984 aLabelText
= ( DataSeriesHelper::getDataSeriesLabel( rSeries
.getModel(), m_xChartTypeModel
.is() ? m_xChartTypeModel
->getRoleOfSequenceForSeriesLabel() : C2U("values-y")) );
1985 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aLabelText
, xTextProperties
);
1987 aResult
.push_back(aEntry
);
1990 // regression curves
1991 if ( 3 == m_nDimension
) // #i63016#
1994 Reference
< XRegressionCurveContainer
> xRegrCont( rSeries
.getModel(), uno::UNO_QUERY
);
1997 Sequence
< Reference
< XRegressionCurve
> > aCurves( xRegrCont
->getRegressionCurves());
1998 sal_Int32 i
= 0, nCount
= aCurves
.getLength();
1999 for( i
=0; i
<nCount
; ++i
)
2001 if( aCurves
[i
].is() && !RegressionCurveHelper::isMeanValueLine( aCurves
[i
] ) )
2004 OUString
aResStr( SchResId::getResString( STR_STATISTICS_IN_LEGEND
));
2005 replaceParamterInString( aResStr
, C2U("%REGRESSIONCURVE"), RegressionCurveHelper::getUINameForRegressionCurve( aCurves
[i
] ));
2006 replaceParamterInString( aResStr
, C2U("%SERIESNAME"), aLabelText
);
2007 aEntry
.aLabel
= FormattedStringHelper::createFormattedStringSequence( xContext
, aResStr
, xTextProperties
);
2010 uno::Reference
< drawing::XShapes
> xSymbolGroup( ShapeFactory(xShapeFactory
).createGroup2D( xTarget
));
2012 // create the symbol
2013 Reference
< drawing::XShape
> xShape( VLegendSymbolFactory::createSymbol(
2014 xSymbolGroup
, chart2::LegendSymbolStyle_DIAGONAL_LINE
, xShapeFactory
,
2015 Reference
< beans::XPropertySet
>( aCurves
[i
], uno::UNO_QUERY
),
2016 VLegendSymbolFactory::PROP_TYPE_LINE
, uno::Any() ));
2018 // set CID to symbol for selection
2021 aEntry
.aSymbol
= uno::Reference
< drawing::XShape
>( xSymbolGroup
, uno::UNO_QUERY
);
2023 bool bAverageLine
= false;//@todo find out wether this is an average line or a regression curve
2024 ObjectType eObjectType
= bAverageLine
? OBJECTTYPE_DATA_AVERAGE_LINE
: OBJECTTYPE_DATA_CURVE
;
2025 OUString
aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType
, i
) );
2026 aChildParticle
= ObjectIdentifier::addChildParticle( aChildParticle
, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY
, 0 ) );
2027 OUString aCID
= ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries
.getSeriesParticle(), aChildParticle
);
2028 ShapeFactory::setShapeName( xShape
, aCID
);
2031 aResult
.push_back(aEntry
);
2036 catch( uno::Exception
& ex
)
2038 ASSERT_EXCEPTION( ex
);
2043 std::vector
< ViewLegendEntry
> SAL_CALL
VSeriesPlotter::createLegendEntriesForChartType(
2044 const Reference
< beans::XPropertySet
>& /* xTextProperties */,
2045 const Reference
< drawing::XShapes
>& /* xTarget */,
2046 const Reference
< lang::XMultiServiceFactory
>& /* xShapeFactory */,
2047 const Reference
< uno::XComponentContext
>& /* xContext */
2050 return std::vector
< ViewLegendEntry
>();
2054 VSeriesPlotter
* VSeriesPlotter::createSeriesPlotter(
2055 const uno::Reference
<XChartType
>& xChartTypeModel
2056 , sal_Int32 nDimensionCount
)
2058 rtl::OUString aChartType
= xChartTypeModel
->getChartType();
2060 //@todo: in future the plotter should be instanciated via service factory
2061 VSeriesPlotter
* pRet
=NULL
;
2062 if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN
) )
2063 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2064 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR
) )
2065 pRet
= new BarChart(xChartTypeModel
,nDimensionCount
);
2066 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA
) )
2067 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true);
2068 else if( aChartType
.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE
) )
2069 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true);
2070 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER
) )
2071 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2072 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE
) )
2073 pRet
= new BubbleChart(xChartTypeModel
,nDimensionCount
);
2074 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE
) )
2075 pRet
= new PieChart(xChartTypeModel
,nDimensionCount
);
2076 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET
) )
2077 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,true,new PolarPlottingPositionHelper(),true,true,false,1,drawing::Direction3D(1,1,1) );
2078 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET
) )
2079 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,true,false,new PolarPlottingPositionHelper(),true,true,false,1,drawing::Direction3D(1,1,1) );
2080 else if( aChartType
.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK
) )
2081 pRet
= new CandleStickChart(xChartTypeModel
,nDimensionCount
);
2083 pRet
= new AreaChart(xChartTypeModel
,nDimensionCount
,false,true);
2087 //.............................................................................
2089 //.............................................................................