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