1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #ifndef _CHART2_VSERIESPLOTTER_HXX
24 #define _CHART2_VSERIESPLOTTER_HXX
25 
26 #include "PlotterBase.hxx"
27 #include "VDataSeries.hxx"
28 #include "LabelAlignment.hxx"
29 #include "MinimumAndMaximumSupplier.hxx"
30 #include "LegendEntryProvider.hxx"
31 #include "ExplicitCategoriesProvider.hxx"
32 #include <com/sun/star/chart2/XChartType.hpp>
33 #include <com/sun/star/drawing/Direction3D.hpp>
34 
35 
36 namespace com { namespace sun { namespace star {
37     namespace util {
38         class XNumberFormatsSupplier;
39     }
40     namespace chart2 {
41         class XColorScheme;
42         class XRegressionCurveCalculator;
43     }
44 }}}
45 
46 //.............................................................................
47 namespace chart
48 {
49 //.............................................................................
50 
51 class NumberFormatterWrapper;
52 
53 class AxesNumberFormats
54 {
55 public:
AxesNumberFormats()56     AxesNumberFormats() {};
57 
setFormat(sal_Int32 nFormatKey,sal_Int32 nDimIndex,sal_Int32 nAxisIndex)58     void setFormat( sal_Int32 nFormatKey, sal_Int32 nDimIndex, sal_Int32 nAxisIndex )
59     {
60         m_aNumberFormatMap[tFullAxisIndex(nDimIndex,nAxisIndex)] = nFormatKey;
61     }
hasFormat(sal_Int32 nDimIndex,sal_Int32 nAxisIndex) const62     sal_Int32 hasFormat( sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) const
63     {
64         return (m_aNumberFormatMap.find(tFullAxisIndex(nDimIndex,nAxisIndex)) !=m_aNumberFormatMap.end());
65     }
getFormat(sal_Int32 nDimIndex,sal_Int32 nAxisIndex) const66     sal_Int32 getFormat( sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) const
67     {
68         tNumberFormatMap::const_iterator aIt = m_aNumberFormatMap.find(tFullAxisIndex(nDimIndex,nAxisIndex));
69         if( aIt !=m_aNumberFormatMap.end() )
70             return aIt->second;
71         return 0;
72     }
73 
74 private:
75     typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex;
76     typedef std::map< tFullAxisIndex, sal_Int32 > tNumberFormatMap;
77     tNumberFormatMap m_aNumberFormatMap;
78 };
79 
80 //-----------------------------------------------------------------------------
81 /**
82 */
83 
84 //enum StackType { STACK_NORMAL, STACK_NONE, STACK_BESIDES, STACK_ONTOP, STACK_BEHIND };
85 
86 class VDataSeriesGroup
87 {
88     //a list of series that have the same CoordinateSystem
89     //they are used to be plotted maybe in a stacked manner by a plotter
90 
91 public:
92     VDataSeriesGroup();
93     VDataSeriesGroup( VDataSeries* pSeries );
94     virtual ~VDataSeriesGroup();
95 
96     void addSeries( VDataSeries* pSeries );//takes ownership of pSeries
97     sal_Int32 getSeriesCount() const;
98     void deleteSeries();
99 
100     sal_Int32    getPointCount() const;
101     sal_Int32    getAttachedAxisIndexForFirstSeries() const;
102 
103     void getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const;
104     void getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const;
105 
106     void calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
107                                             , bool bSeperateStackingForDifferentSigns
108                                             , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex );
109     void calculateYMinAndMaxForCategoryRange( sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
110                                                 , bool bSeperateStackingForDifferentSigns
111                                                 , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex );
112 
113     ::std::vector< VDataSeries* >   m_aSeriesVector;
114 
115 private:
116     //cached values
117     struct CachedYValues
118     {
119         CachedYValues();
120 
121         bool    m_bValuesDirty;
122         double  m_fMinimumY;
123         double  m_fMaximumY;
124     };
125 
126     mutable bool        m_bMaxPointCountDirty;
127     mutable sal_Int32   m_nMaxPointCount;
128     typedef std::map< sal_Int32, CachedYValues > tCachedYValuesPerAxisIndexMap;
129     mutable ::std::vector< tCachedYValuesPerAxisIndexMap >   m_aListOfCachedYValues;
130 };
131 
132 class VSeriesPlotter : public PlotterBase, public MinimumAndMaximumSupplier, public LegendEntryProvider
133 {
134 	//-------------------------------------------------------------------------
135 	// public methods
136 	//-------------------------------------------------------------------------
137 public:
138 	virtual ~VSeriesPlotter();
139 
140     /*
141     * A new series can be positioned relative to other series in a chart.
142     * This positioning has two dimensions. First a series can be placed
143     * next to each other on the category axis. This position is indicated by xSlot.
144     * Second a series can be stacked on top of another. This position is indicated by ySlot.
145     * The positions are counted from 0 on.
146     * xSlot < 0                     : append the series to already existing x series
147     * xSlot > occupied              : append the series to already existing x series
148     *
149     * If the xSlot is already occupied the given ySlot decides what should happen:
150     * ySlot < -1                    : move all existing series in the xSlot to next slot
151     * ySlot == -1                   : stack on top at given x position
152     * ySlot == already occupied     : insert at given y and x position
153     * ySlot > occupied              : stack on top at given x position
154     */
155     virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 );
156 
157     /** a value <= 0 for a directions means that this direction can be stretched arbitrary
158     */
159     virtual ::com::sun::star::drawing::Direction3D  getPreferredDiagramAspectRatio() const;
160     virtual bool keepAspectRatio() const;
161 
162     /** this enables you to handle series on the same x axis with different y axis
163     the property AttachedAxisIndex at a dataseries indicates which value scale is to use
164     (0==AttachedAxisIndex or a not set AttachedAxisIndex property indicates that this series should be scaled at the main y-axis;
165     1==AttachedAxisIndex indicates that the series should be scaled at the first secondary axis if there is any otherwise at the main y axis
166     and so on.
167     The parameter nAxisIndex matches this DataSereis property 'AttachedAxisIndex'.
168     nAxisIndex must be greater than 0. nAxisIndex==1 referres to the first secondary axis.
169     )
170     */
171 
172     virtual void addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
173                 throw (::com::sun::star::uno::RuntimeException);
174 
175     //-------------------------------------------------------------------------
176 	// MinimumAndMaximumSupplier
177 	//-------------------------------------------------------------------------
178 
179     virtual double getMinimumX();
180     virtual double getMaximumX();
181 
182     virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex );
183     virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex );
184 
185     virtual double getMinimumZ();
186     virtual double getMaximumZ();
187 
188     virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex );
189     virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex );
190     virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex );
191     virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex );
192     virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex );
193 
194     virtual long calculateTimeResolutionOnXAxis();
195     virtual void setTimeResolutionOnXAxis( long nTimeResolution, const Date& rNullDate );
196 
197     //------
198 
199     void getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const;
200     void getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const;
201 
202     //-------------------------------------------------------------------------
203     //-------------------------------------------------------------------------
204 
205     virtual std::vector< ViewLegendEntry > createLegendEntries(
206             const ::com::sun::star::awt::Size& rEntryKeyAspectRatio,
207             ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion,
208             const ::com::sun::star::uno::Reference<
209                 ::com::sun::star::beans::XPropertySet >& xTextProperties,
210             const ::com::sun::star::uno::Reference<
211                 ::com::sun::star::drawing::XShapes >& xTarget,
212             const ::com::sun::star::uno::Reference<
213                 ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory,
214             const ::com::sun::star::uno::Reference<
215                 ::com::sun::star::uno::XComponentContext >& xContext
216                 );
217 
218 
219     virtual LegendSymbolStyle getLegendSymbolStyle();
220     virtual com::sun::star::awt::Size getPreferredLegendKeyAspectRatio();
221 
222     virtual ::com::sun::star::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex=-1/*-1 for series symbol*/ );
223 
224     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > createLegendSymbolForSeries(
225                   const ::com::sun::star::awt::Size& rEntryKeyAspectRatio
226                 , const VDataSeries& rSeries
227                 , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget
228                 , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory );
229 
230     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > createLegendSymbolForPoint(
231                   const ::com::sun::star::awt::Size& rEntryKeyAspectRatio
232                 , const VDataSeries& rSeries
233                 , sal_Int32 nPointIndex
234                 , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget
235                 , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory );
236 
237     virtual std::vector< ViewLegendEntry > createLegendEntriesForSeries(
238             const ::com::sun::star::awt::Size& rEntryKeyAspectRatio,
239             const VDataSeries& rSeries,
240             const ::com::sun::star::uno::Reference<
241                 ::com::sun::star::beans::XPropertySet >& xTextProperties,
242             const ::com::sun::star::uno::Reference<
243                 ::com::sun::star::drawing::XShapes >& xTarget,
244             const ::com::sun::star::uno::Reference<
245                 ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory,
246             const ::com::sun::star::uno::Reference<
247                 ::com::sun::star::uno::XComponentContext >& xContext
248                 );
249 
250     ::std::vector< VDataSeries* > getAllSeries();
251 
252     //-------------------------------------------------------------------------
253     //-------------------------------------------------------------------------
254 
255     static VSeriesPlotter* createSeriesPlotter( const ::com::sun::star::uno::Reference<
256                                 ::com::sun::star::chart2::XChartType >& xChartTypeModel
257                                 , sal_Int32 nDimensionCount
258                                 , bool bExcludingPositioning = false /*for pie and donut charts labels and exploded segments are excluded from the given size*/);
259 
260     sal_Int32 getPointCount() const;
261 
262     void setNumberFormatsSupplier( const ::com::sun::star::uno::Reference<
263                         ::com::sun::star::util::XNumberFormatsSupplier > & xNumFmtSupplier );
setAxesNumberFormats(const AxesNumberFormats & rAxesNumberFormats)264     void setAxesNumberFormats( const AxesNumberFormats& rAxesNumberFormats ) { m_aAxesNumberFormats = rAxesNumberFormats; };
265 
266     void setColorScheme( const ::com::sun::star::uno::Reference<
267                         ::com::sun::star::chart2::XColorScheme >& xColorScheme );
268 
269     void setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider );
270 
271     //get series names for the z axis labels
272     ::com::sun::star::uno::Sequence< rtl::OUString > getSeriesNames() const;
273 
274     void setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize );
275     //better performance for big data
276     void setCoordinateSystemResolution( const ::com::sun::star::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution );
277     bool PointsWereSkipped() const;
278 
279     //return the depth for a logic 1
280     double  getTransformedDepth() const;
281 
282     void    releaseShapes();
283 
284     virtual void rearrangeLabelToAvoidOverlapIfRequested( const ::com::sun::star::awt::Size& rPageSize );
285 
286     bool WantToPlotInFrontOfAxisLine();
287     virtual bool shouldSnapRectToUsedArea();
288 
289     //-------------------------------------------------------------------------
290     //-------------------------------------------------------------------------
291     //-------------------------------------------------------------------------
292 private: //methods
293 	//no default constructor
294 	VSeriesPlotter();
295 
296 protected: //methods
297 
298     VSeriesPlotter( const ::com::sun::star::uno::Reference<
299                 ::com::sun::star::chart2::XChartType >& xChartTypeModel
300                 , sal_Int32 nDimensionCount
301                 , bool bCategoryXAxis=true );
302 
303     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >
304         getSeriesGroupShape( VDataSeries* pDataSeries
305             , const::com::sun::star:: uno::Reference<
306                 ::com::sun::star::drawing::XShapes >& xTarget );
307 
308     //the following group shapes will be created as children of SeriesGroupShape on demand
309     //they can be used to assure that some parts of a series shape are always in front of others (e.g. symbols in front of lines)
310     //parameter xTarget will be used as parent for the series group shape
311     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >
312         getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
313             , const::com::sun::star:: uno::Reference<
314                 ::com::sun::star::drawing::XShapes >& xTarget );
315     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >
316         getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
317             , const::com::sun::star:: uno::Reference<
318                 ::com::sun::star::drawing::XShapes >& xTarget );
319 
320     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >
321         getLabelsGroupShape( VDataSeries& rDataSeries
322             , const::com::sun::star:: uno::Reference<
323                 ::com::sun::star::drawing::XShapes >& xTarget );
324 
325     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >
326         getErrorBarsGroupShape( VDataSeries& rDataSeries
327             , const::com::sun::star:: uno::Reference<
328                 ::com::sun::star::drawing::XShapes >& xTarget );
329 
330     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
331         createDataLabel( const ::com::sun::star::uno::Reference<
332                     ::com::sun::star::drawing::XShapes >& xTarget
333                 , VDataSeries& rDataSeries
334                 , sal_Int32 nPointIndex
335                 , double fValue
336                 , double fSumValue
337                 , const ::com::sun::star::awt::Point& rScreenPosition2D
338                 , LabelAlignment eAlignment=LABEL_ALIGN_CENTER
339                 , sal_Int32 nOffset=0 );
340 
341     ::rtl::OUString getLabelTextForValue( VDataSeries& rDataSeries
342                 , sal_Int32 nPointIndex
343                 , double fValue
344                 , bool bAsPercentage );
345 
346     /** creates two T-shaped error bars in both directions (up/down or
347         left/right depending on the bVertical parameter)
348 
349         @param rPos
350             logic coordinates
351 
352         @param xErrorBarProperties
353             the XPropertySet returned by the DataPoint-property "ErrorBarX" or
354             "ErrorBarY".
355 
356         @param nIndex
357             the index of the data point in rData for which the calculation is
358             done.
359 
360         @param bVertical
361             for y-error bars this is true, for x-error-bars it is false.
362      */
363     virtual void createErrorBar(
364           const ::com::sun::star::uno::Reference<
365                 ::com::sun::star::drawing::XShapes >& xTarget
366         , const ::com::sun::star::drawing::Position3D & rPos
367         , const ::com::sun::star::uno::Reference<
368                 ::com::sun::star::beans::XPropertySet > & xErrorBarProperties
369         , const VDataSeries& rVDataSeries
370         , sal_Int32 nIndex
371         , bool bVertical
372         , double* pfScaledLogicX
373         );
374 
375     virtual void createErrorBar_Y( const ::com::sun::star::drawing::Position3D& rUnscaledLogicPosition
376         , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
377         , const ::com::sun::star::uno::Reference<
378                 ::com::sun::star::drawing::XShapes >& xTarget
379         , double* pfScaledLogicX=0 );
380 
381     virtual void createRegressionCurvesShapes( VDataSeries& rVDataSeries
382         , const ::com::sun::star::uno::Reference<
383                 ::com::sun::star::drawing::XShapes >& xTarget
384         , const ::com::sun::star::uno::Reference<
385                 ::com::sun::star::drawing::XShapes >& xEquationTarget
386         , bool bMaySkipPointsInRegressionCalculation );
387 
388     virtual void createRegressionCurveEquationShapes( const ::rtl::OUString & rEquationCID
389         , const ::com::sun::star::uno::Reference<
390             ::com::sun::star::beans::XPropertySet > & xEquationProperties
391         , const ::com::sun::star::uno::Reference<
392             ::com::sun::star::drawing::XShapes >& xEquationTarget
393         , const ::com::sun::star::uno::Reference<
394             ::com::sun::star::chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator
395         , ::com::sun::star::awt::Point aDefaultPos );
396 
397     virtual void setMappedProperties(
398           const ::com::sun::star::uno::Reference<
399                 ::com::sun::star::drawing::XShape >& xTarget
400         , const ::com::sun::star::uno::Reference<
401                 ::com::sun::star::beans::XPropertySet >& xSource
402         , const tPropertyNameMap& rMap
403         , tPropertyNameValueMap* pOverwriteMap=0 );
404 
405     virtual PlottingPositionHelper& getPlottingPositionHelper( sal_Int32 nAxisIndex ) const;//nAxisIndex indicates wether the position belongs to the main axis ( nAxisIndex==0 ) or secondary axis ( nAxisIndex==1 )
406 
407     VDataSeries* getFirstSeries() const;
408 
409 protected: //member
410     PlottingPositionHelper*    m_pMainPosHelper;
411 
412     ::com::sun::star::uno::Reference<
413             ::com::sun::star::chart2::XChartType >    m_xChartTypeModel;
414     ::com::sun::star::uno::Reference<
415             ::com::sun::star::beans::XPropertySet >           m_xChartTypeModelProps;
416 
417     ::std::vector< ::std::vector< VDataSeriesGroup > >  m_aZSlots;
418 
419     bool								m_bCategoryXAxis;//true->xvalues are indices (this would not be necessary if series for category chart wouldn't have x-values)
420     long m_nTimeResolution;
421     Date m_aNullDate;
422 
423     ::std::auto_ptr< NumberFormatterWrapper > m_apNumberFormatterWrapper;
424     AxesNumberFormats                         m_aAxesNumberFormats;//direct numberformats on axes, if empty ask the data series instead
425 
426     ::com::sun::star::uno::Reference<
427             ::com::sun::star::chart2::XColorScheme >    m_xColorScheme;
428 
429     ExplicitCategoriesProvider*    m_pExplicitCategoriesProvider;
430 
431     //better performance for big data
432     ::com::sun::star::uno::Sequence< sal_Int32 >    m_aCoordinateSystemResolution;
433     bool m_bPointsWereSkipped;
434 
435 private: //member
436     typedef std::map< sal_Int32 , ExplicitScaleData > tSecondaryValueScales;
437     tSecondaryValueScales   m_aSecondaryValueScales;
438 
439     typedef std::map< sal_Int32 , PlottingPositionHelper* > tSecondaryPosHelperMap;
440     mutable tSecondaryPosHelperMap   m_aSecondaryPosHelperMap;
441     ::com::sun::star::awt::Size      m_aPageReferenceSize;
442 };
443 
444 //.............................................................................
445 } //namespace chart
446 //.............................................................................
447 #endif
448