summaryrefslogtreecommitdiffstats
path: root/chart2/source/view/inc/VSeriesPlotter.hxx
blob: ac911be461206642b01893f77e5f02f8b9a7fa2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
#pragma once

#include <memory>
#include "PlotterBase.hxx"
#include "VDataSeries.hxx"
#include "LabelAlignment.hxx"
#include "MinimumAndMaximumSupplier.hxx"
#include "LegendEntryProvider.hxx"
#include <basegfx/range/b2irectangle.hxx>
#include <com/sun/star/drawing/Direction3D.hpp>
#include <rtl/ref.hxx>
#include <svx/unoshape.hxx>

namespace com::sun::star::awt { struct Point; }
namespace com::sun::star::chart2 { class XChartType; }


namespace chart { class ExplicitCategoriesProvider; }
namespace chart { struct ExplicitScaleData; }
namespace chart { class ChartModel; }

namespace com::sun::star {
    namespace util {
        class XNumberFormatsSupplier;
    }
    namespace chart2 {
        class XColorScheme;
        class XRegressionCurveCalculator;
    }
}

namespace chart {

class ChartType;
class NumberFormatterWrapper;

class AxesNumberFormats
{
public:
    AxesNumberFormats() {};

    void setFormat( sal_Int32 nFormatKey, sal_Int32 nDimIndex, sal_Int32 nAxisIndex )
    {
        m_aNumberFormatMap[tFullAxisIndex(nDimIndex,nAxisIndex)] = nFormatKey;
    }

private:
    typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex;
    std::map< tFullAxisIndex, sal_Int32 > m_aNumberFormatMap;
};

/**
 * A list of series that have the same CoordinateSystem. They are used to be
 * plotted maybe in a stacked manner by a plotter.
 */
class VDataSeriesGroup final
{
public:
    VDataSeriesGroup() = delete;
    VDataSeriesGroup( std::unique_ptr<VDataSeries> pSeries );
    VDataSeriesGroup(VDataSeriesGroup&&) noexcept;
    ~VDataSeriesGroup();

    void addSeries( std::unique_ptr<VDataSeries> pSeries );//takes ownership of pSeries
    sal_Int32 getSeriesCount() const;
    void deleteSeries();

    sal_Int32    getPointCount() const;
    sal_Int32    getAttachedAxisIndexForFirstSeries() const;

    void getMinimumAndMaximumX( double& rfMinimum, double& rfMaximum ) const;
    void getMinimumAndMaximumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const;

    void calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
                                            , bool bSeparateStackingForDifferentSigns
                                            , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ) const;
    void calculateYMinAndMaxForCategoryRange( sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
                                                , bool bSeparateStackingForDifferentSigns
                                                , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex );

    std::vector< std::unique_ptr<VDataSeries> >   m_aSeriesVector;

private:
    //cached values
    struct CachedYValues
    {
        CachedYValues();

        bool    m_bValuesDirty;
        double  m_fMinimumY;
        double  m_fMaximumY;
    };

    mutable bool        m_bMaxPointCountDirty;
    mutable sal_Int32   m_nMaxPointCount;
    typedef std::map< sal_Int32, CachedYValues > tCachedYValuesPerAxisIndexMap;
    mutable std::vector< tCachedYValuesPerAxisIndexMap >   m_aListOfCachedYValues;
};

class VSeriesPlotter : public PlotterBase, public MinimumAndMaximumSupplier, public LegendEntryProvider
{
public:
    VSeriesPlotter() = delete;

    virtual ~VSeriesPlotter() override;

    /**
    * A new series can be positioned relative to other series in a chart.
    * This positioning has two dimensions. First a series can be placed
    * next to each other on the category axis. This position is indicated by xSlot.
    * Second a series can be stacked on top of another. This position is indicated by ySlot.
    * The positions are counted from 0 on.
    * xSlot < 0                     : append the series to already existing x series
    * xSlot > occupied              : append the series to already existing x series
    *
    * If the xSlot is already occupied the given ySlot decides what should happen:
    * ySlot < -1                    : move all existing series in the xSlot to next slot
    * ySlot == -1                   : stack on top at given x position
    * ySlot == already occupied     : insert at given y and x position
    * ySlot > occupied              : stack on top at given x position
    */
    virtual void addSeries( std::unique_ptr<VDataSeries> pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot );

    /** a value <= 0 for a directions means that this direction can be stretched arbitrary
    */
    virtual css::drawing::Direction3D  getPreferredDiagramAspectRatio() const;

    /** this enables you to handle series on the same x axis with different y axis
    the property AttachedAxisIndex at a dataseries indicates which value scale is to use
    (0==AttachedAxisIndex or a not set AttachedAxisIndex property indicates that this series should be scaled at the main y-axis;
    1==AttachedAxisIndex indicates that the series should be scaled at the first secondary axis if there is any otherwise at the main y axis
    and so on.
    The parameter nAxisIndex matches this DataSeries property 'AttachedAxisIndex'.
    nAxisIndex must be greater than 0. nAxisIndex==1 refers to the first secondary axis.
    )

    @throws css::uno::RuntimeException
    */

    void addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex );

    // MinimumAndMaximumSupplier

    virtual double getMinimumX() override;
    virtual double getMaximumX() override;

    virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override;
    virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override;

    virtual double getMinimumZ() override;
    virtual double getMaximumZ() override;

    virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) override;
    virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) override;
    virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) override;
    virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) override;
    virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override;

    virtual tools::Long calculateTimeResolutionOnXAxis() override;
    virtual void setTimeResolutionOnXAxis( tools::Long nTimeResolution, const Date& rNullDate ) override;

    void getMinimumAndMaximumX( double& rfMinimum, double& rfMaximum ) const;
    void getMinimumAndMaximumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const;


    // Methods for handling legends and legend entries.

    virtual std::vector< ViewLegendEntry > createLegendEntries(
            const css::awt::Size& rEntryKeyAspectRatio,
            css::chart2::LegendPosition eLegendPosition,
            const css::uno::Reference< css::beans::XPropertySet >& xTextProperties,
            const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
            const css::uno::Reference< css::uno::XComponentContext >& xContext,
            ChartModel& rModel
                ) override;

    virtual LegendSymbolStyle getLegendSymbolStyle();
    virtual css::awt::Size getPreferredLegendKeyAspectRatio() override;

    virtual css::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex/*-1 for series symbol*/ );

    rtl::Reference<SvxShapeGroup> createLegendSymbolForSeries(
                  const css::awt::Size& rEntryKeyAspectRatio
                , const VDataSeries& rSeries
                , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );

    rtl::Reference< SvxShapeGroup > createLegendSymbolForPoint(
                  const css::awt::Size& rEntryKeyAspectRatio
                , const VDataSeries& rSeries
                , sal_Int32 nPointIndex
                , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );

    std::vector< ViewLegendEntry > createLegendEntriesForSeries(
            const css::awt::Size& rEntryKeyAspectRatio,
            const VDataSeries& rSeries,
            const css::uno::Reference< css::beans::XPropertySet >& xTextProperties,
            const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
            const css::uno::Reference< css::uno::XComponentContext >& xContext
                );

    std::vector<VDataSeries*> getAllSeries();
    std::vector<VDataSeries const*> getAllSeries() const;

    // This method creates a series plotter of the requested type; e.g. : return new PieChart...
    static VSeriesPlotter* createSeriesPlotter( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
                                , sal_Int32 nDimensionCount
                                , bool bExcludingPositioning /*for pie and donut charts labels and exploded segments are excluded from the given size*/);

    sal_Int32 getPointCount() const;

    // Methods for number formats and color schemes

    void setNumberFormatsSupplier( const css::uno::Reference< css::util::XNumberFormatsSupplier > & xNumFmtSupplier );

    void setColorScheme( const css::uno::Reference< css::chart2::XColorScheme >& xColorScheme );

    void setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider );

    ExplicitCategoriesProvider* getExplicitCategoriesProvider() { return m_pExplicitCategoriesProvider; }

    //get series names for the z axis labels
    css::uno::Sequence<OUString> getSeriesNames() const;

    void setPageReferenceSize( const css::awt::Size & rPageRefSize );
    //better performance for big data
    void setCoordinateSystemResolution( const css::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution );
    bool PointsWereSkipped() const { return m_bPointsWereSkipped;}
    void setPieLabelsAllowToMove( bool bIsPieOrDonut ) { m_bPieLabelsAllowToMove = bIsPieOrDonut; };
    void setAvailableOuterRect( const basegfx::B2IRectangle& aAvailableOuterRect ) { m_aAvailableOuterRect = aAvailableOuterRect; };

    //return the depth for a logic 1
    double  getTransformedDepth() const;

    void    releaseShapes();

    virtual void rearrangeLabelToAvoidOverlapIfRequested( const css::awt::Size& rPageSize );

    bool WantToPlotInFrontOfAxisLine();
    virtual bool shouldSnapRectToUsedArea();

protected:

    VSeriesPlotter( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
                , sal_Int32 nDimensionCount
                , bool bCategoryXAxis=true );

    // Methods for group shapes.

    rtl::Reference<SvxShapeGroupAnyD>
        getSeriesGroupShape( VDataSeries* pDataSeries
            , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );

    //the following group shapes will be created as children of SeriesGroupShape on demand
    //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)
    //parameter xTarget will be used as parent for the series group shape
    rtl::Reference<SvxShapeGroupAnyD>
        getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
            , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );
    rtl::Reference<SvxShapeGroupAnyD>
        getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
            , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );

    /// This method creates a 2D group shape for containing all text shapes
    /// needed for this series; the group is added to the text target;
    static rtl::Reference<SvxShapeGroup>
        getLabelsGroupShape( VDataSeries& rDataSeries
            , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );

    rtl::Reference<SvxShapeGroupAnyD>
        getErrorBarsGroupShape( VDataSeries& rDataSeries
            , const rtl::Reference<SvxShapeGroupAnyD>& xTarget, bool bYError );

    /** This method creates a text shape for a label related to a data point
     *  and append it to the root text shape group (xTarget).
     *
     *  @param xTarget
     *      the main root text shape group.
     *  @param rDataSeries
     *      the data series, the data point belongs to.
     *  @param nPointIndex
     *      the index of the data point the label is related to.
     *  @param fValue
     *      the value of the data point.
     *  @param fSumValue
     *      the sum of all data point values in the data series.
     *  @param rScreenPosition2D
     *      the anchor point position for the label.
     *  @param eAlignment
     *      the required alignment of the label.
     *  @param offset
     *      an optional offset depending on the label alignment.
     *  @param nTextWidth
     *      the maximum width of a text label (used for text wrapping).
     *
     *  @return
     *      a reference to the created text shape.
     */
    rtl::Reference<SvxShapeText>
        createDataLabel( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                , VDataSeries& rDataSeries
                , sal_Int32 nPointIndex
                , double fValue
                , double fSumValue
                , const css::awt::Point& rScreenPosition2D
                , LabelAlignment eAlignment
                , sal_Int32 nOffset=0
                , sal_Int32 nTextWidth = 0 );

    /// This method returns a text string representation of the passed numeric
    /// value by exploiting a NumberFormatterWrapper object.
    OUString getLabelTextForValue( VDataSeries const & rDataSeries
                , sal_Int32 nPointIndex
                , double fValue
                , bool bAsPercentage );

    /** creates two T-shaped error bars in both directions (up/down or
        left/right depending on the bVertical parameter)

        @param rPos
            logic coordinates

        @param xErrorBarProperties
            the XPropertySet returned by the DataPoint-property "ErrorBarX" or
            "ErrorBarY".

        @param nIndex
            the index of the data point in rData for which the calculation is
            done.

        @param bVertical
            for y-error bars this is true, for x-error-bars it is false.
     */
    void createErrorBar(
          const rtl::Reference<SvxShapeGroupAnyD>& xTarget
        , const css::drawing::Position3D & rPos
        , const css::uno::Reference< css::beans::XPropertySet > & xErrorBarProperties
        , const VDataSeries& rVDataSeries
        , sal_Int32 nIndex
        , bool bVertical
        , const double* pfScaledLogicX
        );

    void createErrorRectangle(
          const css::drawing::Position3D& rUnscaledLogicPosition
        , VDataSeries& rVDataSeries
        , sal_Int32 nIndex
        , const rtl::Reference<SvxShapeGroupAnyD>& rTarget
        , bool bUseXErrorData
        , bool bUseYErrorData
    );

    static void addErrorBorder(
          const css::drawing::Position3D& rPos0
        , const css::drawing::Position3D& rPos1
        , const rtl::Reference<SvxShapeGroupAnyD>& rTarget
        , const css::uno::Reference< css::beans::XPropertySet >& rErrorBorderProp );

    void createErrorBar_X( const css::drawing::Position3D& rUnscaledLogicPosition
        , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
        , const rtl::Reference<SvxShapeGroupAnyD>& xTarget );

    void createErrorBar_Y( const css::drawing::Position3D& rUnscaledLogicPosition
        , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
        , const rtl::Reference<SvxShapeGroupAnyD>& xTarget
        , double const * pfScaledLogicX );

    void createRegressionCurvesShapes( VDataSeries const & rVDataSeries
        , const rtl::Reference<SvxShapeGroupAnyD>& xTarget
        , const rtl::Reference<SvxShapeGroupAnyD>& xEquationTarget
        , bool bMaySkipPointsInRegressionCalculation );

    void createRegressionCurveEquationShapes( const OUString & rEquationCID
        , const css::uno::Reference< css::beans::XPropertySet > & xEquationProperties
        , const rtl::Reference<SvxShapeGroupAnyD>& xEquationTarget
        , const css::uno::Reference< css::chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator
        , css::awt::Point aDefaultPos );

    virtual PlottingPositionHelper& getPlottingPositionHelper( sal_Int32 nAxisIndex ) const;//nAxisIndex indicates whether the position belongs to the main axis ( nAxisIndex==0 ) or secondary axis ( nAxisIndex==1 )

    VDataSeries* getFirstSeries() const;

    OUString getCategoryName( sal_Int32 nPointIndex ) const;

protected:
    PlottingPositionHelper*    m_pMainPosHelper;

    rtl::Reference< ::chart::ChartType > m_xChartTypeModel;

    std::vector< std::vector< VDataSeriesGroup > >  m_aZSlots;

    bool                                m_bCategoryXAxis;//true->xvalues are indices (this would not be necessary if series for category chart wouldn't have x-values)
    tools::Long m_nTimeResolution;
    Date m_aNullDate;

    std::unique_ptr< NumberFormatterWrapper > m_apNumberFormatterWrapper;

    css::uno::Reference< css::chart2::XColorScheme >    m_xColorScheme;

    ExplicitCategoriesProvider*    m_pExplicitCategoriesProvider;

    //better performance for big data
    css::uno::Sequence< sal_Int32 >    m_aCoordinateSystemResolution;
    bool m_bPointsWereSkipped;
    bool m_bPieLabelsAllowToMove;
    basegfx::B2IRectangle m_aAvailableOuterRect;
    css::awt::Size m_aPageReferenceSize;

private:
    typedef std::map< sal_Int32 , ExplicitScaleData > tSecondaryValueScales;
    tSecondaryValueScales   m_aSecondaryValueScales;

    typedef std::map< sal_Int32 , std::unique_ptr<PlottingPositionHelper> > tSecondaryPosHelperMap;
    mutable tSecondaryPosHelperMap   m_aSecondaryPosHelperMap;
};

} //namespace chart

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */