Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / chart2 / source / view / charttypes / NetChart.cxx
blob823004d2091a0d966b5670989ecfbb925549ed6b
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 "NetChart.hxx"
21 #include <PlottingPositionHelper.hxx>
22 #include <ShapeFactory.hxx>
23 #include <ExplicitCategoriesProvider.hxx>
24 #include <CommonConverters.hxx>
25 #include <ObjectIdentifier.hxx>
26 #include <LabelPositionHelper.hxx>
27 #include <Clipping.hxx>
28 #include <PolarLabelPositionHelper.hxx>
29 #include <DateHelper.hxx>
31 #include <com/sun/star/chart2/Symbol.hpp>
32 #include <com/sun/star/chart/DataLabelPlacement.hpp>
33 #include <com/sun/star/chart/MissingValueTreatment.hpp>
35 #include <rtl/math.hxx>
36 #include <osl/diagnose.h>
38 #include <com/sun/star/drawing/XShapes.hpp>
40 namespace chart
42 using namespace ::com::sun::star;
43 using namespace ::rtl::math;
44 using namespace ::com::sun::star::chart2;
46 NetChart::NetChart( const uno::Reference<XChartType>& xChartTypeModel
47 , sal_Int32 nDimensionCount
48 , bool bNoArea
49 , std::unique_ptr<PlottingPositionHelper> pPlottingPositionHelper
51 : VSeriesPlotter( xChartTypeModel, nDimensionCount, true )
52 , m_pMainPosHelper(std::move(pPlottingPositionHelper))
53 , m_bArea(!bNoArea)
54 , m_bLine(bNoArea)
56 // we only support 2D Net charts
57 assert(nDimensionCount == 2);
59 m_pMainPosHelper->AllowShiftXAxisPos(true);
60 m_pMainPosHelper->AllowShiftZAxisPos(true);
62 PlotterBase::m_pPosHelper = m_pMainPosHelper.get();
63 VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get();
66 NetChart::~NetChart()
70 double NetChart::getMaximumX()
72 double fMax = VSeriesPlotter::getMaximumX() + 1.0;
73 return fMax;
76 bool NetChart::isExpandIfValuesCloseToBorder( sal_Int32 )
78 return false;
81 bool NetChart::isSeparateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ )
83 // no separate stacking in all types of line/area charts
84 return false;
87 LegendSymbolStyle NetChart::getLegendSymbolStyle()
89 if( m_bArea )
90 return LegendSymbolStyle::Box;
91 return LegendSymbolStyle::Line;
94 uno::Any NetChart::getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex )
96 uno::Any aRet;
98 Symbol* pSymbolProperties = rSeries.getSymbolProperties( nPointIndex );
99 if( pSymbolProperties )
101 aRet <<= *pSymbolProperties;
104 return aRet;
107 drawing::Direction3D NetChart::getPreferredDiagramAspectRatio() const
109 return drawing::Direction3D(1,1,1);
112 bool NetChart::impl_createLine( VDataSeries* pSeries
113 , drawing::PolyPolygonShape3D* pSeriesPoly
114 , PlottingPositionHelper const * pPosHelper )
116 //return true if a line was created successfully
117 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
119 drawing::PolyPolygonShape3D aPoly;
121 bool bIsClipped = false;
122 if( !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) )
124 // do NOT connect last and first point, if one is NAN, and NAN handling is NAN_AS_GAP
125 double fFirstY = pSeries->getYValue( 0 );
126 double fLastY = pSeries->getYValue( VSeriesPlotter::getPointCount() - 1 );
127 if( (pSeries->getMissingValueTreatment() != css::chart::MissingValueTreatment::LEAVE_GAP)
128 || (::rtl::math::isFinite( fFirstY ) && ::rtl::math::isFinite( fLastY )) )
130 // connect last point in last polygon with first point in first polygon
131 ::basegfx::B2DRectangle aScaledLogicClipDoubleRect( pPosHelper->getScaledLogicClipDoubleRect() );
132 drawing::PolyPolygonShape3D aTmpPoly(*pSeriesPoly);
133 drawing::Position3D aLast(aScaledLogicClipDoubleRect.getMaxX(),aTmpPoly.SequenceY[0][0],aTmpPoly.SequenceZ[0][0]);
134 // add connector line to last polygon
135 AddPointToPoly( aTmpPoly, aLast, pSeriesPoly->SequenceX.getLength() - 1 );
136 Clipping::clipPolygonAtRectangle( aTmpPoly, aScaledLogicClipDoubleRect, aPoly );
137 bIsClipped = true;
141 if( !bIsClipped )
142 Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
145 if(!ShapeFactory::hasPolygonAnyLines(aPoly))
146 return false;
148 //transformation 3) -> 4)
149 pPosHelper->transformScaledLogicToScene( aPoly );
151 //create line:
152 uno::Reference< drawing::XShape > xShape;
154 xShape = m_pShapeFactory->createLine2D( xSeriesGroupShape_Shapes
155 , PolyToPointSequence( aPoly ) );
156 setMappedProperties( xShape
157 , pSeries->getPropertiesOfSeries()
158 , PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
159 //because of this name this line will be used for marking
160 ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles");
162 return true;
165 bool NetChart::impl_createArea( VDataSeries* pSeries
166 , drawing::PolyPolygonShape3D* pSeriesPoly
167 , drawing::PolyPolygonShape3D const * pPreviousSeriesPoly
168 , PlottingPositionHelper const * pPosHelper )
170 //return true if an area was created successfully
172 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
173 double zValue = pSeries->m_fLogicZPos;
175 drawing::PolyPolygonShape3D aPoly( *pSeriesPoly );
176 //add second part to the polygon (grounding points or previous series points)
177 if( !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) )
179 if( pPreviousSeriesPoly )
180 addPolygon( aPoly, *pPreviousSeriesPoly );
182 else if(!pPreviousSeriesPoly)
184 double fMinX = pSeries->m_fLogicMinX;
185 double fMaxX = pSeries->m_fLogicMaxX;
186 double fY = pPosHelper->getBaseValueY();//logic grounding
188 //clip to scale
189 if(fMaxX<pPosHelper->getLogicMinX() || fMinX>pPosHelper->getLogicMaxX())
190 return false;//no visible shape needed
191 pPosHelper->clipLogicValues( &fMinX, &fY, nullptr );
192 pPosHelper->clipLogicValues( &fMaxX, nullptr, nullptr );
194 //apply scaling
196 pPosHelper->doLogicScaling( &fMinX, &fY, &zValue );
197 pPosHelper->doLogicScaling( &fMaxX, nullptr, nullptr );
200 AddPointToPoly( aPoly, drawing::Position3D( fMaxX,fY,zValue) );
201 AddPointToPoly( aPoly, drawing::Position3D( fMinX,fY,zValue) );
203 else
205 appendPoly( aPoly, *pPreviousSeriesPoly );
207 ShapeFactory::closePolygon(aPoly);
209 //apply clipping
211 drawing::PolyPolygonShape3D aClippedPoly;
212 Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false );
213 ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping
214 aPoly = aClippedPoly;
217 if(!ShapeFactory::hasPolygonAnyLines(aPoly))
218 return false;
220 //transformation 3) -> 4)
221 pPosHelper->transformScaledLogicToScene( aPoly );
223 //create area:
224 uno::Reference< drawing::XShape >
225 xShape = m_pShapeFactory->createArea2D( xSeriesGroupShape_Shapes
226 , aPoly );
227 setMappedProperties( xShape
228 , pSeries->getPropertiesOfSeries()
229 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
230 //because of this name this line will be used for marking
231 ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles");
232 return true;
235 void NetChart::impl_createSeriesShapes()
237 //the polygon shapes for each series need to be created before
239 //iterate through all series again to create the series shapes
240 for( auto const& rZSlot : m_aZSlots )
242 for( auto const& rXSlot : rZSlot )
244 std::map< sal_Int32, drawing::PolyPolygonShape3D* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex
245 drawing::PolyPolygonShape3D* pSeriesPoly = nullptr;
247 //iterate through all series
248 for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector )
250 sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
251 m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex);
253 pSeriesPoly = &pSeries->m_aPolyPolygonShape3D;
254 if( m_bArea )
256 if (!impl_createArea(pSeries.get(), pSeriesPoly,
257 aPreviousSeriesPolyMap[nAttachedAxisIndex], m_pPosHelper))
258 continue;
260 if( m_bLine )
262 if (!impl_createLine(pSeries.get(), pSeriesPoly, m_pPosHelper))
263 continue;
265 aPreviousSeriesPolyMap[nAttachedAxisIndex] = pSeriesPoly;
266 }//next series in x slot (next y slot)
267 }//next x slot
268 }//next z slot
271 namespace
274 void lcl_reorderSeries( std::vector< std::vector< VDataSeriesGroup > >& rZSlots )
276 std::vector< std::vector< VDataSeriesGroup > > aRet;
277 aRet.reserve( rZSlots.size() );
279 std::vector< std::vector< VDataSeriesGroup > >::reverse_iterator aZIt( rZSlots.rbegin() );
280 std::vector< std::vector< VDataSeriesGroup > >::reverse_iterator aZEnd( rZSlots.rend() );
281 for( ; aZIt != aZEnd; ++aZIt )
283 std::vector< VDataSeriesGroup > aXSlot;
285 std::vector< VDataSeriesGroup >::reverse_iterator aXIt( aZIt->rbegin() );
286 std::vector< VDataSeriesGroup >::reverse_iterator aXEnd( aZIt->rend() );
287 for( ; aXIt != aXEnd; ++aXIt )
288 aXSlot.push_back(std::move(*aXIt));
290 aRet.push_back(std::move(aXSlot));
293 rZSlots = std::move(aRet);
296 }//anonymous namespace
298 //better performance for big data
299 struct FormerPoint
301 FormerPoint( double fX, double fY, double fZ )
302 : m_fX(fX), m_fY(fY), m_fZ(fZ)
304 FormerPoint()
306 ::rtl::math::setNan( &m_fX );
307 ::rtl::math::setNan( &m_fY );
308 ::rtl::math::setNan( &m_fZ );
311 double m_fX;
312 double m_fY;
313 double m_fZ;
316 void NetChart::createShapes()
318 if( m_aZSlots.empty() ) //no series
319 return;
321 if( m_bArea )
322 lcl_reorderSeries( m_aZSlots );
324 OSL_ENSURE(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"NetChart is not proper initialized");
325 if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
326 return;
328 //the text labels should be always on top of the other series shapes
329 //for area chart the error bars should be always on top of the other series shapes
331 //therefore create an own group for the texts and the error bars to move them to front
332 //(because the text group is created after the series group the texts are displayed on top)
333 m_xSeriesTarget = createGroupShape( m_xLogicTarget );
334 m_xTextTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget );
336 //check necessary here that different Y axis can not be stacked in the same group? ... hm?
338 //update/create information for current group
339 double fLogicZ = 1.0;//as defined
341 sal_Int32 const nStartIndex = 0; // inclusive ;..todo get somehow from x scale
342 sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
343 if(nEndIndex<=0)
344 nEndIndex=1;
346 //better performance for big data
347 std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap;
348 m_bPointsWereSkipped = false;
350 bool bDateCategory = (m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis());
352 //iterate through all x values per indices
353 for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
355 std::map< sal_Int32, double > aLogicYSumMap;//one for each different nAttachedAxisIndex
356 for( auto const& rZSlot : m_aZSlots )
358 //iterate through all x slots in this category to get 100percent sum
359 for( auto const& rXSlot : rZSlot )
361 for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector )
363 if(!pSeries)
364 continue;
366 if (bDateCategory)
367 pSeries->doSortByXValues();
369 sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
370 if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
371 aLogicYSumMap[nAttachedAxisIndex]=0.0;
373 m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex);
375 double fAdd = pSeries->getYValue( nIndex );
376 if( !::rtl::math::isNan(fAdd) && !::rtl::math::isInf(fAdd) )
377 aLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd );
382 for( auto const& rZSlot : m_aZSlots )
384 //for the area chart there should be at most one x slot (no side by side stacking available)
385 //attention different: xSlots are always interpreted as independent areas one behind the other: @todo this doesn't work why not???
386 for( auto const& rXSlot : rZSlot )
388 std::map< sal_Int32, double > aLogicYForNextSeriesMap;//one for each different nAttachedAxisIndex
389 //iterate through all series
390 for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector )
392 if(!pSeries)
393 continue;
395 /* #i70133# ignore points outside of series length in standard area
396 charts. Stacked area charts will use missing points as zeros. In
397 standard charts, pSeriesList contains only one series. */
398 if( m_bArea && (rXSlot.m_aSeriesVector.size() == 1) && (nIndex >= pSeries->getTotalPointCount()) )
399 continue;
401 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeFrontChild(pSeries.get(), m_xSeriesTarget);
403 sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
404 m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex);
406 pSeries->m_fLogicZPos = fLogicZ;
408 //collect data point information (logic coordinates, style ):
409 double fLogicX = pSeries->getXValue(nIndex);
410 if (bDateCategory)
411 fLogicX = DateHelper::RasterizeDateValue( fLogicX, m_aNullDate, m_nTimeResolution );
412 double fLogicY = pSeries->getYValue(nIndex);
414 if( m_bArea && ( ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY) ) )
416 if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP )
418 if( rXSlot.m_aSeriesVector.size() == 1 || pSeries == rXSlot.m_aSeriesVector.front() )
420 fLogicY = m_pPosHelper->getLogicMinY();
421 if (!m_pPosHelper->isMathematicalOrientationY())
422 fLogicY = m_pPosHelper->getLogicMaxY();
424 else
425 fLogicY = 0.0;
429 if (m_pPosHelper->isPercentY() && aLogicYSumMap[nAttachedAxisIndex] != 0.0)
431 fLogicY = fabs( fLogicY )/aLogicYSumMap[nAttachedAxisIndex];
434 if( ::rtl::math::isNan(fLogicX) || ::rtl::math::isInf(fLogicX)
435 || ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY)
436 || ::rtl::math::isNan(fLogicZ) || ::rtl::math::isInf(fLogicZ) )
438 if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP )
440 drawing::PolyPolygonShape3D& rPolygon = pSeries->m_aPolyPolygonShape3D;
441 sal_Int32& rIndex = pSeries->m_nPolygonIndex;
442 if( 0<= rIndex && rIndex < rPolygon.SequenceX.getLength() )
444 if( rPolygon.SequenceX[ rIndex ].hasElements() )
445 rIndex++; //start a new polygon for the next point if the current poly is not empty
448 continue;
451 if( aLogicYForNextSeriesMap.find(nAttachedAxisIndex) == aLogicYForNextSeriesMap.end() )
452 aLogicYForNextSeriesMap[nAttachedAxisIndex] = 0.0;
454 double fLogicValueForLabeDisplay = fLogicY;
456 fLogicY += aLogicYForNextSeriesMap[nAttachedAxisIndex];
457 aLogicYForNextSeriesMap[nAttachedAxisIndex] = fLogicY;
459 bool bIsVisible = m_pPosHelper->isLogicVisible(fLogicX, fLogicY, fLogicZ);
461 //remind minimal and maximal x values for area 'grounding' points
462 //only for filled area
464 double& rfMinX = pSeries->m_fLogicMinX;
465 if(!nIndex||fLogicX<rfMinX)
466 rfMinX=fLogicX;
467 double& rfMaxX = pSeries->m_fLogicMaxX;
468 if(!nIndex||fLogicX>rfMaxX)
469 rfMaxX=fLogicX;
472 drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ );
473 drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition);
474 m_pPosHelper->doLogicScaling(aScaledLogicPosition);
476 //transformation 3) -> 4)
477 drawing::Position3D aScenePosition(
478 m_pPosHelper->transformLogicToScene(fLogicX, fLogicY, fLogicZ, false));
480 //better performance for big data
481 FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] );
482 m_pPosHelper->setCoordinateSystemResolution(m_aCoordinateSystemResolution);
483 if( !pSeries->isAttributedDataPoint(nIndex)
484 && m_pPosHelper->isSameForGivenResolution(
485 aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ
486 , aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ ) )
488 m_bPointsWereSkipped = true;
489 continue;
491 aSeriesFormerPointMap[pSeries.get()] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ);
493 //store point information for series polygon
494 //for area and/or line (symbols only do not need this)
495 if( isValidPosition(aScaledLogicPosition) )
497 AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aScaledLogicPosition, pSeries->m_nPolygonIndex );
499 //prepare clipping for filled net charts
500 if( !bIsVisible && m_bArea )
502 drawing::Position3D aClippedPos(aScaledLogicPosition);
503 m_pPosHelper->clipScaledLogicValues(nullptr, &aClippedPos.PositionY,
504 nullptr);
505 if (m_pPosHelper->isLogicVisible(aClippedPos.PositionX,
506 aClippedPos.PositionY,
507 aClippedPos.PositionZ))
509 AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aClippedPos, pSeries->m_nPolygonIndex );
510 AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aScaledLogicPosition, pSeries->m_nPolygonIndex );
515 //create a single datapoint if point is visible
516 //apply clipping:
517 if( !bIsVisible )
518 continue;
520 Symbol* pSymbolProperties = pSeries->getSymbolProperties( nIndex );
521 bool bCreateSymbol = pSymbolProperties && (pSymbolProperties->Style != SymbolStyle_NONE);
523 if( !bCreateSymbol && !pSeries->getDataPointLabelIfLabel(nIndex) )
524 continue;
526 //create a group shape for this point and add to the series shape:
527 OUString aPointCID = ObjectIdentifier::createPointCID(
528 pSeries->getPointCID_Stub(), nIndex );
529 uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(
530 createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
531 uno::Reference<drawing::XShape> xPointGroupShape_Shape( xPointGroupShape_Shapes, uno::UNO_QUERY );
534 //create data point
535 drawing::Direction3D aSymbolSize(0,0,0);
536 if (bCreateSymbol) // implies pSymbolProperties
538 if (pSymbolProperties->Style != SymbolStyle_NONE)
540 aSymbolSize.DirectionX = pSymbolProperties->Size.Width;
541 aSymbolSize.DirectionY = pSymbolProperties->Size.Height;
544 if (pSymbolProperties->Style == SymbolStyle_STANDARD)
546 sal_Int32 nSymbol = pSymbolProperties->StandardSymbol;
547 m_pShapeFactory->createSymbol2D(
548 xPointGroupShape_Shapes, aScenePosition, aSymbolSize, nSymbol,
549 pSymbolProperties->BorderColor, pSymbolProperties->FillColor);
551 else if (pSymbolProperties->Style == SymbolStyle_GRAPHIC)
553 m_pShapeFactory->createGraphic2D(xPointGroupShape_Shapes,
554 aScenePosition, aSymbolSize,
555 pSymbolProperties->Graphic);
557 //@todo other symbol styles
560 //create data point label
561 if( pSeries->getDataPointLabelIfLabel(nIndex) )
563 LabelAlignment eAlignment = LABEL_ALIGN_TOP;
564 drawing::Position3D aScenePosition3D( aScenePosition.PositionX
565 , aScenePosition.PositionY
566 , aScenePosition.PositionZ+getTransformedDepth() );
568 sal_Int32 nLabelPlacement = pSeries->getLabelPlacement(
569 nIndex, m_xChartTypeModel, m_pPosHelper->isSwapXAndY());
571 switch(nLabelPlacement)
573 case css::chart::DataLabelPlacement::TOP:
574 aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
575 eAlignment = LABEL_ALIGN_TOP;
576 break;
577 case css::chart::DataLabelPlacement::BOTTOM:
578 aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1);
579 eAlignment = LABEL_ALIGN_BOTTOM;
580 break;
581 case css::chart::DataLabelPlacement::LEFT:
582 aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1);
583 eAlignment = LABEL_ALIGN_LEFT;
584 break;
585 case css::chart::DataLabelPlacement::RIGHT:
586 aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1);
587 eAlignment = LABEL_ALIGN_RIGHT;
588 break;
589 case css::chart::DataLabelPlacement::CENTER:
590 eAlignment = LABEL_ALIGN_CENTER;
591 //todo implement this different for area charts
592 break;
593 default:
594 OSL_FAIL("this label alignment is not implemented yet");
595 aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
596 eAlignment = LABEL_ALIGN_TOP;
597 break;
600 awt::Point aScreenPosition2D;//get the screen position for the labels
601 sal_Int32 nOffset = 100; //todo maybe calculate this font height dependent
602 if( nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE )
604 PolarPlottingPositionHelper* pPolarPosHelper
605 = dynamic_cast<PolarPlottingPositionHelper*>(m_pPosHelper);
606 if( pPolarPosHelper )
608 PolarLabelPositionHelper aPolarLabelPositionHelper(pPolarPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
609 aScreenPosition2D = aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues(
610 eAlignment, fLogicX, fLogicY, fLogicZ, nOffset );
613 else
615 if(eAlignment==LABEL_ALIGN_CENTER )
616 nOffset = 0;
617 aScreenPosition2D = LabelPositionHelper(m_nDimension,m_xLogicTarget,m_pShapeFactory)
618 .transformSceneToScreenPosition( aScenePosition3D );
621 createDataLabel( m_xTextTarget, *pSeries, nIndex
622 , fLogicValueForLabeDisplay
623 , aLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset );
627 //remove PointGroupShape if empty
628 if(!xPointGroupShape_Shapes->getCount())
629 xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
631 }//next series in x slot (next y slot)
632 }//next x slot
633 }//next z slot
634 }//next category
636 impl_createSeriesShapes();
640 } //namespace chart
642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */