/*
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
* Licensed 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @addtogroup UI_Components
* @{
*
* @brief Defines UI components such as buttons, texts, images, lists, and progress bars.
*
* @since 1.0
* @version 1.0
*/
/**
* @file ui_chart.h
*
* @brief Defines the attributes of the chart component and provides functions for adding and deleting
* data sets to display a chart.
*
* @since 1.0
* @version 1.0
*/
#ifndef GRAPHIC_LITE_UI_CHART_H
#define GRAPHIC_LITE_UI_CHART_H
#include "components/ui_axis.h"
#include "components/ui_view_group.h"
#include "gfx_utils/list.h"
namespace OHOS {
class UIChart;
/**
* @brief Defines a data set and provides functions such as adding and deleting data points.
*
* @since 1.0
* @version 1.0
*/
class UIChartDataSerial : public HeapBase {
public:
/**
* @brief A constructor used to create a UIChartDataSerial instance.
*
* @since 1.0
* @version 1.0
*/
UIChartDataSerial();
/**
* @brief A destructor used to delete the UIChartDataSerial instance.
*
* @since 1.0
* @version 1.0
*/
virtual ~UIChartDataSerial()
{
if (pointArray_ != nullptr) {
UIFree(pointArray_);
pointArray_ = nullptr;
}
}
/**
* @brief Sets the maximum number of data points that can be stored in a data set.
*
* This function must be called before data is added, deleted, or modified. Otherwise, data operations will fail.
*
* @param maxCount Indicates the number of data points. The default value is 0.
*
* @return Returns true if the operation is successful; returns false otherwise.
* @since 1.0
* @version 1.0
*/
bool SetMaxDataCount(uint16_t maxCount);
/**
* @brief Modifies the value of a data point in the data set.
*
* @param index Indicates the index of the data point to modify.
* @param point Indicates the new value of the data point.
*
* @return Returns true if the operation is successful; returns false otherwise.
* @since 1.0
* @version 1.0
*/
bool ModifyPoint(uint16_t index, const Point& point);
/**
* @brief Obtains the coordinates in the chart for a data point in the data set.
*
* @param index Indicates the index of the data point to obtain.
* @param point Indicates the obtained coordinates. If the data set is not added to the chart,
* the original value of the data point is printed.
*
* @return Returns true if the operation is successful; returns false otherwise.
* @since 1.0
* @version 1.0
*/
bool GetPoint(uint16_t index, Point& point);
/**
* @brief Obtains the coordinates in the chart for a original data point in the data set.
*
* @param index Indicates the index of the data point to obtain.
* @param point Indicates the obtained coordinates. the original value of the data point is printed.
*
* @return Returns true if the operation is successful; returns false otherwise.
*/
bool GetOriginalPoint(uint16_t index, Point& point);
/**
* @brief Backup a variable
*
* @param pointArrayBack Indicates a copy of the variable
*
* @return Returns true if the operation is successful; returns false otherwise.
*/
bool PointArrayDup(Point** pointArrayBack);
/**
* @brief Adds data points.
*
* The new data points are appended to the last added data. \n
* No more data points can be added if the maximum number is reached \n
*
* @param data Indicates the pointer to the start address of the data point.
* @param count Indicates the number of data points to add.
* @return Returns true if the data points are added successfully; returns false otherwise.
* @since 1.0
* @version 1.0
*/
bool AddPoints(const Point* data, uint16_t count);
/**
* @brief Clears all data points.
*
* @since 1.0
* @version 1.0
*/
void ClearData();
/**
* @brief Obtains the number of data points available in the data set.
*
* @return Returns the number of data points.
* @since 1.0
* @version 1.0
*/
uint16_t GetDataCount() const
{
return dataCount_;
}
/**
* @brief Sets whether to smooth a polyline.
*
* This function applies only to line charts. After the smoothing, some data is discarded.
* Therefore, the polyline does not pass through all data points. \n
* If smooth is set to true, the filling color, top point, and bottom point of a line chart have
* deviations. Therefore, you are advised not to use these functions at the same time. \n
*
* @param smooth Specifies whether to smooth a polyline. Value true means to smooth a polyline, and value
* false means not to smooth a polyline. The default value is false.
* @since 1.0
* @version 1.0
*/
void EnableSmooth(bool smooth)
{
smooth_ = smooth;
}
/**
* @brief Checks whether smoothing is performed on a polyline.
*
* @return Returns true if smooth processing is performed on the polyline; returns false otherwise.
* @since 1.0
* @version 1.0
*/
bool IsSmooth() const
{
return smooth_;
}
/**
* @brief Enables the fill color of a line chart.
*
* This function applies only to line charts. By default, the area between the polyline and the x-axis is filled.
* You can use {@link SetGradientBottom} to modify the filled region. \n
*
* @param enable Specifies whether to enable the fill color. Value true means to enable the fill color,
* and value false means to disable the fill color. The default value is false.
* @since 1.0
* @version 1.0
*/
void EnableGradient(bool enable)
{
enableGradient_ = enable;
}
/**
* @brief Checks whether a polyline has a fill color.
*
* @return Returns true if there is a fill color; returns false otherwise.
* @since 1.0
* @version 1.0
*/
bool IsGradient() const
{
return enableGradient_;
}
/**
* @brief Obtains the index of the top point in the data set.
*
* @return Returns the index of the top point. If there are multiple top points, the first one is returned.
* @since 1.0
* @version 1.0
*/
uint16_t GetPeakIndex() const
{
return peakPointIndex_;
}
/**
* @brief Obtains the index of the frontmost point (the latest added or modified data point in a data set).
*
* @return Returns the index of the frontmost point.
* @since 1.0
* @version 1.0
*/
uint16_t GetLatestIndex() const
{
return latestIndex_;
}
/**
* @brief Obtains the index of the bottom point in a data set.
*
* @return Returns the index of the bottom point. If there are multiple bottom points, the first one is returned.
* @since 1.0
* @version 1.0
*/
uint16_t GetValleyIndex() const
{
return valleyPointIndex_;
}
/**
* @brief Obtains the Y value of the top point in a data set.
*
* The Y value is the data added by users, not the pixel coordinate.
*
* @return Returns the Y value.
* @since 1.0
* @version 1.0
*/
int16_t GetPeakData() const
{
return peakData_;
}
/**
* @brief Obtains the Y value of the bottom point in a data set.
*
* The Y value is the data added by users, not the pixel coordinate.
*
* @return Returns the Y value.
* @since 1.0
* @version 1.0
*/
int16_t GetValleyData() const
{
return valleyData_;
}
void SetLastPointIndex(uint16_t value)
{
lastPointIndex_ = value;
}
uint16_t GetLastPointIndex() const
{
return lastPointIndex_;
}
/**
* @brief Obtains the polyline color of the data set in a line chart.
*
* @return Returns the polyline color of the data set.
* @see SetLineColor
* @since 1.0
* @version 1.0
*/
ColorType GetLineColor() const
{
return serialColor_;
}
/**
* @brief Obtains the fill color of the data set.
*
* @return Returns the fill color.
* @see SetFillColor
* @since 1.0
* @version 1.0
*/
ColorType GetFillColor() const
{
return fillColor_;
}
/**
* @brief Sets the fill color of the data set.
*
* For a line chart, color refers to the fill color between the line and the x-axis.
* For a bar chart, color refers to the color of the bars.
*
* @param color Indicates the fill color to set.
* @see GetFillColor
* @since 1.0
* @version 1.0
*/
void SetFillColor(const ColorType& color)
{
fillColor_ = color;
}
/**
* @brief Sets the polyline color of the data set in the line chart.
*
* This function applies only to line charts.
*
* @param color Indicates the polyline color to set.
* @see GetLineColor
* @since 1.0
* @version 1.0
*/
void SetLineColor(const ColorType& color)
{
serialColor_ = color;
}
void BindToChart(UIChart* chart)
{
chart_ = chart;
}
/**
* @brief Hides some points in the data set.
*
* This function applies only to line charts. After the points are hidden, the line connected by the points
* is not displayed. \n
* The top and bottom points may appear in the hidden region. If this method is enabled,
* you are not advised to enable the display of the top and bottom points.
*
* @param index Indicates the point from which the hide starts.
* @param count Indicates the number of points to hide.
* @since 1.0
* @version 1.0
*/
void HidePoint(uint16_t index, uint16_t count);
/**
* @brief Obtains the index from which the data set starts to hide.
*
* @return Returns the index.
* @see HidePoint
* @since 1.0
* @version 1.0
*/
uint16_t GetHideIndex() const
{
return hideIndex_;
}
/**
* @brief Obtains the number of hidden points in the data set.
*
* @return Returns the number of hidden points.
* @see HidePoint
* @since 1.0
* @version 1.0
*/
uint16_t GetHideCount() const
{
return hideCount_;
}
/**
* @brief Defines the style for the top, bottom, and frontmost points in a line chart.
*/
struct PointStyle : public HeapBase {
/** Fill color */
ColorType fillColor;
/** Border color */
ColorType strokeColor;
/** Inner radius */
uint16_t radius;
/** Border width, which extends outwards from the inner radius */
uint16_t strokeWidth;
};
/**
* @brief Sets the style of the frontmost point on a polyline.
*
* @param style Indicates the style to set. For details, see {@link PointStyle}.
* @since 1.0
* @version 1.0
*/
void SetHeadPointStyle(const PointStyle& style)
{
headPointStyle_ = style;
}
/**
* @brief Sets the style of the top point of a polyline.
*
* @param style Indicates the style to set. For details, see {@link PointStyle}.
* @since 1.0
* @version 1.0
*/
void SetTopPointStyle(const PointStyle& style)
{
topPointStyle_ = style;
}
/**
* @brief Sets the style of the bottom point of a polyline.
*
* @param style Indicates the style to set. For details, see {@link PointStyle}.
* @since 1.0
* @version 1.0
*/
void SetBottomPointStyle(const PointStyle& style)
{
bottomPointStyle_ = style;
}
/**
* @brief Obtains the style of the frontmost point on a polyline.
*
* @return Returns the style of the point. For details, see {@link PointStyle}.
* @since 1.0
* @version 1.0
*/
const PointStyle& GetHeadPointStyle() const
{
return headPointStyle_;
}
/**
* @brief Obtains the style of the top point of a polyline.
*
* @return Returns the style of the point. For details, see {@link PointStyle}.
* @since 1.0
* @version 1.0
*/
const PointStyle& GetTopPointStyle() const
{
return topPointStyle_;
}
/**
* @brief Obtains the style of the bottom point of a polyline.
*
* @return Returns the style of the point. For details, see {@link PointStyle}.
* @since 1.0
* @version 1.0
*/
const PointStyle& GetBottomPointStyle() const
{
return bottomPointStyle_;
}
/**
* @brief Enables the feature of drawing the frontmost point on a polyline.
*
* @param enable Specifies whether to draw the frontmost point. Value true means to draw the frontmost
* point, and value false means not to draw the frontmost point.
* @since 1.0
* @version 1.0
*/
void EnableHeadPoint(bool enable)
{
enableHeadPoint_ = enable;
}
/**
* @brief enableHeadPoint_.
*
* @return Returns enableHeadPoint_.
*/
bool GetEnableHeadPoint() const
{
return enableHeadPoint_;
}
/**
* @brief Enables the feature of drawing the top point of a polyline. If there are multiple top points,
* only the first one is drawn.
*
* @param enable Specifies whether to draw the top point. Value true means to draw the top point,
* and value false means not to draw the top point.
* @since 1.0
* @version 1.0
*/
void EnableTopPoint(bool enable)
{
enableTopPoint_ = enable;
}
/**
* @brief enableTopPoint_.
*
* @return Returns enableTopPoint_.
*/
bool GetEnableTopPoint() const
{
return enableTopPoint_;
}
/**
* @brief Enables the feature of drawing the bottom point of a polyline. If there are multiple bottom points,
* only the first one is drawn.
*
* @param enable Specifies whether to draw the bottom point. Value true means to draw the bottom point,
* and value false means not to draw the bottom point.
* @since 1.0
* @version 1.0
*/
void EnableBottomPoint(bool enable)
{
enableBottomPoint_ = enable;
}
/**
* @brief enableBottomPoint_.
*
* @return Returns enableBottomPoint_.
*/
bool GetEnableBottomPoint() const
{
return enableBottomPoint_;
}
void DrawPoint(BufferInfo& gfxDstBuffer, const Rect& mask);
void Refresh();
protected:
uint16_t maxCount_;
Point* pointArray_;
private:
constexpr static uint16_t DEFAULT_POINT_RADIUS = 5;
constexpr static uint16_t MAX_POINTS_COUNT = 512;
ColorType serialColor_;
ColorType fillColor_;
uint16_t dataCount_;
uint16_t peakPointIndex_;
int16_t peakData_;
int16_t valleyData_;
uint16_t valleyPointIndex_;
uint16_t lastPointIndex_;
uint16_t latestIndex_;
uint16_t hideIndex_;
uint16_t hideCount_;
bool smooth_ : 1;
bool enableGradient_ : 1;
bool enableHeadPoint_ : 1;
bool enableTopPoint_ : 1;
bool enableBottomPoint_ : 1;
PointStyle headPointStyle_;
PointStyle topPointStyle_;
PointStyle bottomPointStyle_;
UIChart* chart_;
Rect invalidateRect_;
void RefreshInvalidateRect(uint16_t startIndex, uint16_t endIndex);
void RefreshInvalidateRect(uint16_t pointIndex, const PointStyle& style);
bool UpdatePeakAndValley(uint16_t startPos, uint16_t endPos);
void DoDrawPoint(BufferInfo& gfxDstBuffer, const Point& point, const PointStyle& style, const Rect& mask);
};
/**
* @brief Defines the chart class and provides functions such as adding and deleting data sets to display a chart.
*
* @since 1.0
* @version 1.0
*/
class UIChart : public UIViewGroup {
public:
/**
* @brief A constructor used to create a UIChart instance.
*
* @since 1.0
* @version 1.0
*/
UIChart() : enableReverse_(false), needRefresh_(false), mixData_(nullptr)
{
Add(&xAxis_);
Add(&yAxis_);
SetStyle(STYLE_LINE_WIDTH, 1);
SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
}
/**
* @brief A destructor used to delete the UIChart instance.
*
* @since 1.0
* @version 1.0
*/
virtual ~UIChart();
/**
* @brief Obtains the view type.
*
* @return Returns the view type. For details, see {@link UIViewType}.
* @since 1.0
* @version 1.0
*/
UIViewType GetViewType() const override
{
return UI_CHART;
}
/**
* @brief Sets the height for this component.
*
* @param height Indicates the height to set.
* @since 1.0
* @version 1.0
*/
void SetHeight(int16_t height) override;
/**
* @brief Sets the width for this component.
*
* @param width Indicates the width to set.
* @since 1.0
* @version 1.0
*/
void SetWidth(int16_t width) override;
bool OnPreDraw(Rect& invalidatedArea) const override
{
return false;
}
void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
/**
* @brief Adds a data set.
*
* @param dataSerial Indicates the pointer to the data set class. For details, see {@link UIChartDataSerial}.
* @return Returns true if the data set is added successfully; returns false otherwise.
* @see DeleteDataSerial
* @since 1.0
* @version 1.0
*/
virtual bool AddDataSerial(UIChartDataSerial* dataSerial);
/**
* @brief Deletes a data set.
*
* @param dataSerial Indicates the pointer to the data set class. For details, see {@link UIChartDataSerial}.
* @return Returns true if the data set is deleted successfully; returns false otherwise.
* @see AddDataSerial
* @since 1.0
* @version 1.0
*/
virtual bool DeleteDataSerial(UIChartDataSerial* dataSerial);
/**
* @brief Clears all data sets.
*
* @since 1.0
* @version 1.0
*/
virtual void ClearDataSerial();
/**
* @brief Refreshes a chart and redraws the dirty region.
*
* Only the parts that need to be redrawn are refreshed, for example, new data points.
* This function provides better performance than {@link Invalidate}.
*
* @since 1.0
* @version 1.0
*/
virtual void RefreshChart() = 0;
/**
* @brief Obtains the x-axis instance.
*
* @return Returns the x-axis instance.
* @since 1.0
* @version 1.0
*/
UIXAxis& GetXAxis()
{
return xAxis_;
}
/**
* @brief Obtains the y-axis instance.
*
* @return Returns the y-axis instance.
* @since 1.0
* @version 1.0
*/
UIYAxis& GetYAxis()
{
return yAxis_;
}
/**
* @brief Enables chart reverse.
*
* After the chart is reversed, the x-axis aligns with the top of the chart. The pixel position corresponding
* to the data point remains unchanged. Complementary filling is performed on the chart
* (only the part that is not filled previously will be filled).
*
* @param enable Specifies whether to enable chart reverse. Value true means to enable chart reverse,
* and value false means not to enable chart reverse. The default value is false.
* @since 1.0
* @version 1.0
*/
void EnableReverse(bool enable)
{
if (enableReverse_ != enable) {
enableReverse_ = enable;
xAxis_.EnableReverse(enable);
yAxis_.EnableReverse(enable);
}
}
protected:
List list_;
UIXAxis xAxis_;
UIYAxis yAxis_;
bool enableReverse_;
bool needRefresh_;
uint8_t* mixData_;
virtual void DrawDataSerials(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) = 0;
};
/**
* @brief Provides special functions for implementing a bar chart.
*
* @since 1.0
* @version 1.0
*/
class UIChartPillar : public UIChart {
public:
/**
* @brief A constructor used to create a UIChartPillar instance.
*
* @since 1.0
* @version 1.0
*/
UIChartPillar() {}
/**
* @brief A destructor used to delete the UIChartPillar instance.
*
* @since 1.0
* @version 1.0
*/
virtual ~UIChartPillar() {}
/**
* @brief Refreshes a bar chart and redraws the dirty region.
*
* Only the parts that need to be redrawn are refreshed, for example, new data points.
* This function provides better performance than {@link Invalidate}.
*
* @since 1.0
* @version 1.0
*/
void RefreshChart() override;
protected:
void DrawDataSerials(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
private:
static constexpr float DEFAULT_MARK_PERCENTAGE = 0.1f;
};
/**
* @brief Provides special functions for implementing a polyline.
*
* @since 1.0
* @version 1.0
*/
class UIChartPolyline : public UIChart {
public:
/**
* @brief A constructor used to create a UIChartPolyline instance.
*
* @since 1.0
* @version 1.0
*/
UIChartPolyline() : minOpa_(OPA_TRANSPARENT), maxOpa_(OPA_OPAQUE), gradientBottom_(0) {}
/**
* @brief A destructor used to delete the UIChartPolyline instance.
*
* @since 1.0
* @version 1.0
*/
virtual ~UIChartPolyline() {}
/**
* @brief Refreshes a line chart and redraws the dirty region.
*
* Only the parts that need to be redrawn are refreshed, for example, new data points.
* This function provides better performance than {@link Invalidate}.
*
* @since 1.0
* @version 1.0
*/
void RefreshChart() override;
/**
* @brief Sets the opacity range of the fill color gradient.
*
* This function sets the opacity range between the top point and bottom point of the line chart.
* The opacity of each horizontal line is calculated based on the ratio.
*
* @param minOpa Indicates the opacity closest to the x-axis.
* @param maxOpa Indicates the opacity farthest away from the x-axis.
* @since 1.0
* @version 1.0
*/
void SetGradientOpacity(uint8_t minOpa, uint8_t maxOpa)
{
minOpa_ = minOpa;
maxOpa_ = maxOpa;
needRefresh_ = true;
}
/**
* @brief Sets the distance between the bottom edge of the fill color range and the x-axis.
*
* This function fills in the area between the polyline and bottom of the line chart. For a chart that is not
* reversed, if the bottom is above the polyline, there is no filling. For a reversed chart,
* if the bottom is below the polyline, there is no filling.
*
* @param bottom Indicates the bottom of the filling range. The value is the distance to the x-axis.
* @since 1.0
* @version 1.0
*/
void SetGradientBottom(uint16_t bottom)
{
gradientBottom_ = bottom;
}
protected:
void DrawDataSerials(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
private:
struct ChartLine {
Point start;
Point end;
};
struct CrossPointSet {
Point first;
Point second;
Point nextFirst;
bool firstFind;
bool secondFind;
};
constexpr static uint8_t SMOOTH_SLOPE_ANGLE = 3;
constexpr static uint8_t LINE_JOIN_WIDTH = 3;
uint8_t minOpa_;
uint8_t maxOpa_;
uint16_t gradientBottom_;
void GradientColor(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, UIChartDataSerial* data);
void DrawGradientColor(BufferInfo& gfxDstBuffer,
const Rect& invalidatedArea,
UIChartDataSerial* data,
const ChartLine& linePoints,
const ChartLine& limitPoints,
int16_t startY);
void DrawSmoothPolyLine(BufferInfo& gfxDstBuffer,
uint16_t startIndex,
uint16_t endIndex,
const Rect& invalidatedArea,
UIChartDataSerial* data);
void GetDataBySmooth(uint16_t startIndex, uint16_t endIndex, UIChartDataSerial* data);
bool Smooth(uint16_t startPos,
Point& start,
Point& end,
Point& current,
UIChartDataSerial* data,
uint16_t& slope,
uint16_t& preSlope);
void DrawPolyLine(BufferInfo& gfxDstBuffer,
uint16_t startIndex,
uint16_t endIndex,
const Rect& invalidatedArea,
UIChartDataSerial* data);
bool GetLineCrossPoint(const Point& p1, const Point& p2, const Point& p3, const Point& p4, Point& cross);
void FindCrossPoints(const ChartLine& line, const ChartLine& polyLine, CrossPointSet& cross);
void ReMeasure() override;
void CalcVerticalInfo(int16_t top, int16_t bottom, int16_t start, int16_t end, int16_t& y, int16_t& yHeight);
void SetDrawLineCross(BufferInfo& gfxDstBuffer,
const Rect& invalidatedArea,
UIChartDataSerial* data,
CrossPointSet& cross,
BaseGfxEngine* baseGfxEngine,
int16_t startY,
int16_t mixScale);
};
} // namespace OHOS
#endif // GRAPHIC_LITE_UI_CHART_H