merge the formfield patch from ooo-build
[ooovba.git] / chart2 / source / view / charttypes / VSeriesPlotter.cxx
blob8a246bac7a7f2de69fd513901a7281522ef4c406
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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"
40 #include "macros.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"
55 #include "ResId.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>
82 #include <functional>
84 //.............................................................................
85 namespace chart
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;
92 using rtl::OUString;
94 //-----------------------------------------------------------------------------
95 //-----------------------------------------------------------------------------
96 //-----------------------------------------------------------------------------
98 VDataSeriesGroup::CachedYValues::CachedYValues()
99 : m_bValuesDirty(true)
100 , m_fMinimumY(0.0)
101 , m_fMaximumY(0.0)
105 VDataSeriesGroup::VDataSeriesGroup()
106 : m_aSeriesVector()
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++ )
133 delete *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 ))
159 , m_aZSlots()
160 , m_bCategoryXAxis(bCategoryXAxis)
161 , m_xColorScheme()
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();
181 aZSlotIter->clear();
183 m_aZSlots.clear();
185 tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
186 while( aPosIt != m_aSecondaryPosHelperMap.end() )
188 PlottingPositionHelper* pPosHelper = aPosIt->second;
189 if( pPosHelper )
190 delete pPosHelper;
191 ++aPosIt;
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" );
203 if(!pSeries)
204 return;
206 if(m_bCategoryXAxis)
207 pSeries->setCategoryXAxis();
209 if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
211 //new z slot
212 ::std::vector< VDataSeriesGroup > aZSlot;
213 aZSlot.push_back( VDataSeriesGroup(pSeries) );
214 m_aZSlots.push_back( aZSlot );
216 else
218 //existing zslot
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) );
226 else
228 //x slot is already occupied
229 //y slot decides what to do:
231 VDataSeriesGroup& rYSlots = rXSlots[xSlot];
232 sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
234 if( ySlot < -1 )
236 //move all existing series in the xSlot to next slot
237 //@todo
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);
245 else
247 //y slot is already occupied
248 //insert at given y and x position
250 //@todo
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)
263 aRet.DirectionZ=1.0;
264 if(aRet.DirectionZ>10)
265 aRet.DirectionZ=10;
266 return aRet;
269 bool VSeriesPlotter::keepAspectRatio() const
271 return true;
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 );
303 if( !xShapes.is() )
305 //create a group shape for this series and add to logic target:
306 xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
307 pDataSeries->m_xGroupShape = xShapes;
309 return 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 );
316 if(!xShapes.is())
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;
326 return 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 );
333 if(!xShapes.is())
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;
341 return 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 );
350 if(!xShapes.is())
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;
356 return 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 );
363 if(!xShapes.is())
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;
369 return xShapes;
373 OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
374 , sal_Int32 nPointIndex
375 , double fValue
376 , bool bAsPercentage )
378 OUString aNumber;
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;
391 else
393 if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
394 nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
395 else
396 nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
398 if(nNumberFormatKey<0)
399 nNumberFormatKey=0;
401 sal_Int32 nLabelCol = 0;
402 bool bColChanged;
403 aNumber = m_apNumberFormatterWrapper->getFormattedString(
404 nNumberFormatKey, fValue, nLabelCol, bColChanged );
405 //@todo: change color of label if bColChanged is true
407 else
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*/ );
413 return aNumber;
416 uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Reference< drawing::XShapes >& xTarget
417 , VDataSeries& rDataSeries
418 , sal_Int32 nPointIndex
419 , double fValue
420 , double fSumValue
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 );
446 if( !pLabel )
447 return xTextShape;
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 ) );
457 else
458 xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( rDataSeries, xTarget_, m_xShapeFactory ) );
461 //prepare text
462 ::rtl::OUStringBuffer aText;
463 ::rtl::OUString aSeparator(sal_Unicode(' '));
464 double fRotationDegrees = 0.0;
467 uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
468 if(xPointProps.is())
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)
509 if(fSumValue==0.0)
510 fSumValue=1.0;
511 fValue /= fSumValue;
512 if( fValue < 0 )
513 fValue*=-1.0;
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 ) )
531 return xTextShape;
532 LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
534 //------------------------------------------------
535 //create text shape
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 );
545 if( xProp.is() )
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 );
592 //set position
593 xTextShape->setPosition( aNewTextPos );
596 catch( uno::Exception& e )
598 ASSERT_EXCEPTION( e );
601 return xTextShape;
604 namespace
606 double lcl_getErrorBarLogicLength(
607 const uno::Sequence< double > & rData,
608 uno::Reference< beans::XPropertySet > xProp,
609 sal_Int32 nErrorBarStyle,
610 sal_Int32 nIndex,
611 bool bPositive )
613 double fResult;
614 ::rtl::math::setNan( & fResult );
617 switch( nErrorBarStyle )
619 case ::com::sun::star::chart::ErrorBarStyle::NONE:
620 break;
621 case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
622 fResult = StatisticsHelper::getVariance( rData );
623 break;
624 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
625 fResult = StatisticsHelper::getStandardDeviation( rData );
626 break;
627 case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
629 double fPercent = 0;
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;
642 break;
643 case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
644 xProp->getPropertyValue( bPositive
645 ? C2U("PositiveError")
646 : C2U("NegativeError")) >>= fResult;
647 break;
648 case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
650 // todo: check if this is really what's called error-margin
651 double fPercent = 0;
652 if( xProp->getPropertyValue( bPositive
653 ? C2U("PositiveError")
654 : C2U("NegativeError")) >>= fPercent )
656 double fMaxValue;
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)
662 fMaxValue=*pValues;
664 if( ::rtl::math::isFinite( fMaxValue ) &&
665 ::rtl::math::isFinite( fPercent ))
667 fResult = fMaxValue * fPercent / 100.0;
671 break;
672 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
673 fResult = StatisticsHelper::getStandardError( rData );
674 break;
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 */ );
682 break;
685 catch( uno::Exception & e )
687 ASSERT_EXCEPTION( e );
690 return fResult;
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
715 , bool bYError )
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();
729 if( bYError )
731 //main direction has constant x value
732 MinX = rUnscaledLogicPosition.PositionX;
733 MaxX = rUnscaledLogicPosition.PositionX;
735 else
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() )
750 //@todo
752 return aMainDirection;
755 } // anonymous namespace
757 // virtual
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
763 , sal_Int32 nIndex
764 , bool bYError /* = true */
767 if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
768 return;
770 if( ! xErrorBarProperties.is())
771 return;
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)
784 return;
786 if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
787 return;
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() );
806 if( bShowPositive )
808 double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true );
809 if( ::rtl::math::isFinite( fLength ) )
811 double fLocalX = fX;
812 double fLocalY = fY;
813 if( bYError )
814 fLocalY+=fLength;
815 else
816 fLocalX+=fLength;
817 bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
818 aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
820 else
821 bShowPositive = false;
824 if( bShowNegative )
826 double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false );
827 if( ::rtl::math::isFinite( fLength ) )
829 double fLocalX = fX;
830 double fLocalY = fY;
831 if( bYError )
832 fLocalY-=fLength;
833 else
834 fLocalX-=fLength;
836 bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
837 aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
839 else
840 bShowNegative = false;
843 if(!bShowPositive && !bShowNegative)
844 return;
846 drawing::PolyPolygonShape3D aPoly;
848 sal_Int32 nSequenceIndex=0;
849 if( bShowNegative )
850 AddPointToPoly( aPoly, aNegative, nSequenceIndex );
851 AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
852 if( bShowPositive )
853 AddPointToPoly( aPoly, aPositive, nSequenceIndex );
855 if( bShowNegative && bCreateNegativeBorder )
857 ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
858 nSequenceIndex++;
859 lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
861 if( bShowPositive && bCreatePositiveBorder )
863 ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
864 nSequenceIndex++;
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 );
878 // virtual
879 void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition
880 , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
881 , const uno::Reference< drawing::XShapes >& xTarget )
883 if(m_nDimension!=2)
884 return;
885 // error bars
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 )
904 if(m_nDimension!=2)
905 return;
906 uno::Reference< XRegressionCurveContainer > xRegressionContainer(
907 rVDataSeries.getModel(), uno::UNO_QUERY );
908 if(!xRegressionContainer.is())
909 return;
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())
920 continue;
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;
960 nRealPointCount++;
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());
991 if( xEqProp.is())
993 createRegressionCurveEquationShapes(
994 rVDataSeries.getDataCurveEquationCID( nN ),
995 xEqProp, xEquationTarget, xRegressionCurveCalculator,
996 aDefaultPos );
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())
1010 return;
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))
1019 return;
1021 ::rtl::OUStringBuffer aFormula;
1022 sal_Int32 nNumberFormatKey = 0;
1023 xEquationProperties->getPropertyValue( C2U("NumberFormat")) >>= nNumberFormatKey;
1025 if( bShowEquation )
1027 if( m_apNumberFormatterWrapper.get())
1029 aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
1030 m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
1031 nNumberFormatKey );
1033 else
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;
1053 bool bColChanged;
1054 aFormula.append(
1055 m_apNumberFormatterWrapper->getFormattedString(
1056 nNumberFormatKey, fR*fR, nLabelCol, bColChanged ));
1057 //@todo: change color of label if bColChanged is true
1059 else
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 ));
1077 else
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 )
1094 // {
1095 // uno::Reference< beans::XPropertySet > xShapeProp( xTextShape, uno::UNO_QUERY );
1096 // if( xShapeProp.is())
1097 // RelativeSizeHelper::adaptFontSizes( xShapeProp, aOldRefSize, m_aPageReferenceSize );
1098 // }
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 );
1134 return fMinimum;
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 );
1147 return 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);
1154 if (xPropSet.is())
1158 xPropSet->getPropertyValue(C2U("Percent")) >>= bPercent;
1160 catch (const beans::UnknownPropertyException&)
1165 if (bPercent)
1166 // This plotter is percent-stacked.
1167 return 0.0;
1169 if( !m_bCategoryXAxis )
1171 double fMinY, fMaxY;
1172 this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
1173 return fMinY;
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);
1198 return 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);
1205 if (xPropSet.is())
1209 xPropSet->getPropertyValue(C2U("Percent")) >>= bPercent;
1211 catch (const beans::UnknownPropertyException&)
1216 if (bPercent)
1217 // This plotter is percent-stacked.
1218 return 100.0;
1220 if( !m_bCategoryXAxis )
1222 double fMinY, fMaxY;
1223 this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
1224 return fMaxY;
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);
1249 return fMaximum;
1252 double VSeriesPlotter::getMinimumZ()
1254 //this is the default for all charts without a meaningfull z axis
1255 return 0.5;
1257 double VSeriesPlotter::getMaximumZ()
1259 if( 3!=m_nDimension )
1260 return 0.5;
1261 return m_aZSlots.size()+0.5;
1264 namespace
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 )
1272 return true;
1273 return false;
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
1362 sal_Int32 nRet = 0;
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 )
1376 nRet = nPointCount;
1379 return 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;
1403 sal_Int32 nRet = 0;
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 )
1411 nRet = nPointCount;
1413 m_nMaxPointCount=nRet;
1414 m_aListOfCachedYValues.clear();
1415 m_aListOfCachedYValues.resize(m_nMaxPointCount);
1416 m_bMaxPointCountDirty=false;
1417 return nRet;
1420 sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1422 sal_Int32 nRet = 0;
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();
1429 return nRet;
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) )
1449 continue;
1450 if(rfMaximum<fX)
1451 rfMaximum=fX;
1452 if(rfMinimum>fX)
1453 rfMinimum=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() )
1477 continue;
1479 double fX = (*aSeriesIter)->getXValue( nN );
1480 if( ::rtl::math::isNan(fX) )
1481 continue;
1482 if( fX < fMinX || fX > fMaxX )
1483 continue;
1484 double fY = (*aSeriesIter)->getYValue( nN );
1485 if( ::rtl::math::isNan(fY) )
1486 continue;
1487 if(rfMaxY<fY)
1488 rfMaxY=fY;
1489 if(rfMinY>fY)
1490 rfMinY=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())
1508 return;
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;
1516 return;
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() )
1534 continue;
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;
1543 else
1544 fPositiveSum += fValueMaxY;
1546 if( fValueMinY < 0 )
1548 if(::rtl::math::isNan( fNegativeSum ))
1549 fNegativeSum = fFirstNegativeY = fValueMinY;
1550 else
1551 fNegativeSum += fValueMinY;
1554 rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
1555 rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
1557 else
1559 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1561 if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
1562 continue;
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;
1572 else
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)
1630 if( nAxisIndex<1 )
1631 return;
1633 m_aSecondaryValueScales[nAxisIndex]=rScale;
1636 PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
1638 PlottingPositionHelper* pRet = 0;
1639 if(nAxisIndex>0)
1641 tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
1642 if( aPosIt != m_aSecondaryPosHelperMap.end() )
1644 pRet = aPosIt->second;
1646 else
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;
1656 if( !pRet )
1658 pRet = m_pMainPosHelper;
1660 return *pRet;
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];
1682 if(pSeries)
1683 return pSeries;
1687 return 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 );
1712 if( xSeries.is() )
1714 rtl::OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
1715 aRetVector.push_back( aSeriesName );
1720 return ContainerHelper::ContainerToSequence( aRetVector );
1723 namespace
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 );
1736 private:
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;
1778 if( xTarget.is() )
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 );
1798 if(!pSeries)
1799 continue;
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() )
1808 bBreak = true;
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
1823 if(bReverse)
1824 aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
1825 else
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*/ )
1851 return uno::Any();
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;
1876 break;
1877 default:
1878 break;
1880 Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol(
1881 xTarget, eLegendSymbolStyle, xShapeFactory
1882 , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
1884 return xShape;
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;
1910 break;
1911 default:
1912 break;
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 );
1930 if( xChild.is())
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 ));
1942 return xShape;
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() ) )
1956 return aResult;
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 )
1971 // symbol
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
1979 if( xShape.is() )
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 );
1989 // label
1990 aLabelText = aCategoryNames[nIdx];
1991 if( xShape.is() || aLabelText.getLength() )
1993 aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
1994 aResult.push_back(aEntry);
1998 else
2000 // symbol
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
2008 if( xShape.is())
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 );
2017 // label
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#
2026 return aResult;
2028 Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
2029 if( xRegrCont.is())
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] ) )
2037 //label
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 );
2043 // symbol
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
2053 if( xShape.is())
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 );
2074 return aResult;
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 >();
2087 //static
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);
2116 else
2117 pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
2118 return pRet;
2121 //.............................................................................
2122 } //namespace chart
2123 //.............................................................................