diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /chart2/source/view/inc/VSeriesPlotter.hxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | chart2/source/view/inc/VSeriesPlotter.hxx | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/chart2/source/view/inc/VSeriesPlotter.hxx b/chart2/source/view/inc/VSeriesPlotter.hxx new file mode 100644 index 000000000..ac911be46 --- /dev/null +++ b/chart2/source/view/inc/VSeriesPlotter.hxx @@ -0,0 +1,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: */ |