21. 图表部件

一、图标部件

  图表可以将数据可视化,更加直观地显示数据、对比数据、分析数据。LVGL 的图表部件支持两种图形:折线图条形图

  图表部件由六个部分组成:

  • 主体部分LV_PART_MAIN):主要设置背景属性和线条(用于分隔线)相关的样式属性。
  • 滚动条部分LV_PART_SCROLLBAR):主要设置缩放图表时使用的滚动条。
  • 相同的成分LV_PART_ITEMS):折线图:设置线属性,如宽度、高度、bg_color 和半径。条形图:背景属性。
  • 指示器LV_PART_INDICATOR):设置折线图和散点图上的点(小圆或小方)的属性。
  • 光标LV_PART_TICKS):设置游标,比如它的宽度、高度、bg_color 和半径。
lv_obj_t * lv_chart_create(lv_obj_t * parent);                                  // 创建图表对象

void lv_chart_set_type(lv_obj_t * obj, lv_chart_type_t type);                   // 为图表设置一个新的类型
lv_chart_type_t lv_chart_get_type(const lv_obj_t * obj);                        // 获取图表的类型

void lv_chart_set_point_count(lv_obj_t * obj, uint32_t cnt);                    // 设置数据线上的点数
uint32_t lv_chart_get_point_count(const lv_obj_t * obj);                        // 获取图表上每条数据线的数据点数字

void lv_chart_set_range(lv_obj_t * obj, lv_chart_axis_t axis, int32_t min, int32_t max);                                    // 设置轴上的最小和最大y值
void lv_chart_set_update_mode(lv_obj_t * obj, lv_chart_update_mode_t update_mode);                                          // 设置图表对象的更新模式

void lv_chart_set_div_line_count(lv_obj_t * obj, uint8_t hdiv, uint8_t vdiv);   // 设置水平和垂直分隔线的数量

void lv_chart_set_x_start_point(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id);                                      // 设置数据数组中x轴起点的索引
uint32_t lv_chart_get_x_start_point(const lv_obj_t * obj, lv_chart_series_t * ser);                                         // 获取数据数组中x轴起点的当前索引

void lv_chart_get_point_pos_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, lv_point_t * p_out);                // 获取图表中一个点的位置

void lv_chart_refresh(lv_obj_t * obj);                                          // 如果图表的数据线发生了变化,请刷新图表

lv_chart_series_t * lv_chart_add_series(lv_obj_t * obj, lv_color_t color, lv_chart_axis_t axis);                            // 添加数据序列到图表
void lv_chart_remove_series(lv_obj_t * obj, lv_chart_series_t * series);                                                    // 从图表中释放并删除数据序列
void lv_chart_hide_series(lv_obj_t * chart, lv_chart_series_t * series, bool hide);                                         // 隐藏/取消隐藏图表的单个数据系列

void lv_chart_set_series_color(lv_obj_t * chart, lv_chart_series_t * series, lv_color_t color);                             // 改变一个数据系列的颜色

lv_chart_series_t * lv_chart_get_series_next(const lv_obj_t * obj, const lv_chart_series_t * ser);                          // 下一个数据系列

lv_chart_cursor_t  * lv_chart_add_cursor(lv_obj_t * obj, lv_color_t color, lv_dir_t dir);                                   // 添加一个给定颜色的游标

void lv_chart_set_cursor_pos(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_point_t * pos);                               // 设置游标在点的坐标

void lv_chart_set_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_chart_series_t * ser, uint32_t point_id);   // 把游标固定在一个点上
lv_point_t lv_chart_get_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor);                                         // 获取游标在点的坐标

void lv_chart_set_all_value(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value);                                        // 用一个值初始化序列中的所有数据点
void lv_chart_set_next_value(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value);                                       // 根据更新模式策略设置下一个点的Y值
void lv_chart_set_next_value2(lv_obj_t * obj, lv_chart_series_t * ser, int32_t x_value, int32_t y_value);                   // 根据更新模式策略设置下一个点的X和Y值

void lv_chart_set_value_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t value);                         // 直接根据索引设置图表序列中单个点的y值
void lv_chart_set_value_by_id2(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t x_value, int32_t y_value);     // 根据索引直接设置图表系列的单个点的x和y值(只能在 LV_CHART_TYPE_SCATTER 类型图表设置)

void lv_chart_set_ext_x_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[]);                                    // 设置用于图表的x数据点的外部数组
int32_t * lv_chart_get_x_array(const lv_obj_t * obj, lv_chart_series_t * ser);                                              // 获取一个系列的x值的数组
void lv_chart_set_ext_y_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[]);                                    // 设置用于图表的y数据点的外部数组
int32_t * lv_chart_get_y_array(const lv_obj_t * obj, lv_chart_series_t * ser);                                              // 获取一个系列的y值的数组

uint32_t lv_chart_get_pressed_point(const lv_obj_t * obj);                      // 获取当前被压点的指数

  我们可以使用 lv_chart_create() 函数 创建图表对象

/**
 * @brief 创建图表对象
 * 
 * @param parent 指向父部件的指针
 * @return lv_obj_t* 指向图表部件的指针
 */
lv_obj_t * lv_chart_create(lv_obj_t * parent);

  图表的类型分为两种,这两种类型分为 折线图条形图,这些图表的类型是由函数 lv_chart_set_type() 函数设置。

/**
 * @brief 为图表设置一个新的类型
 * 
 * @param obj 指向图表部件的指针
 * @param type 图标的类型
 */
void lv_chart_set_type(lv_obj_t * obj, lv_chart_type_t type);

  该函数可设置四种模式,这些模式如下表所示:

enum _lv_chart_type_t {
    LV_CHART_TYPE_NONE,         // 隐藏数据显示
    LV_CHART_TYPE_LINE,         // 点与点连接成线(折线图)
    LV_CHART_TYPE_BAR,          // 条形图
    LV_CHART_TYPE_SCATTER,      // X/Y图画点和点之间的线
};

  数据序列 是指绘制在图表上的一组相关值。在不同类型的图表中,数据序列的表示方式各不相同:

  • 条形图:数据序列由一系列具有相同填充(颜色或纹理)的条形表示。
  • 折线图(也称为图形):数据序列用单线表示。

  数据序列简单来讲就是图表具有多少通道绘制数值。图表的数据序列可调用函数 lv_chart_add_series() 添加。

/**
 * @brief 添加数据序列到图表
 * 
 * @param obj 指向图表部件的指针
 * @param color 设置数据序列的颜色
 * @param axis 表示数据序列缩放方向
 * @return lv_chart_series_t* 数据序列的指针
 */
lv_chart_series_t * lv_chart_add_series(lv_obj_t * obj, lv_color_t color, lv_chart_axis_t axis);

  有关数据缩放方向枚举值如下:

enum _lv_chart_axis_t {
    LV_CHART_AXIS_PRIMARY_Y     = 0x00,     // 左轴
    LV_CHART_AXIS_SECONDARY_Y   = 0x01,     // 右轴
    LV_CHART_AXIS_PRIMARY_X     = 0x02,     // 底部
    LV_CHART_AXIS_SECONDARY_X   = 0x04,     // 顶部
    _LV_CHART_AXIS_LAST
};

  默认情况下,图表部件只支持 10 个数据点,如果我们具有 11 个数据,那么图表先显示前 10 个数据,而第 11 个数据会将图表的 10 个数据逐一往左移位,最后把第一个数据点的数值去除了。

  这些数据点类似于一个数组(其实它是一个连续内存的内存块),该数组默认长度为 10,所以上图的数据点可以存放 10 个元素,如果第 11 给元素加载到数据点中,则该数组的数值往左移位,最后把原本第一位的元素除去,新的元素插入该数组的最后一位。

  虽然图表部件默认只支持 10 个数据点,但是我们可以手动设置图表可支持的数据点,这些数据点的数量由用户决定。我们调用函数 lv_chart_set_point_count()设置该图表所支持的数据点

/**
 * @brief 设置数据线上的点数
 * 
 * @param obj 指向图表部件的指针
 * @param cnt 数据线上的点数
 */
void lv_chart_set_point_count(lv_obj_t * obj, uint32_t cnt);

  我们可以使用 lv_chart_set_ext_y_array() 函数和 lv_chart_set_ext_x_array() 函数 添加数据到图表中。函数 lv_chart_set_ext_y_array() 是为 Y 轴数据点设置一个外部阵列,该函数一般用在折线图和条形图类型。函数 lv_chart_set_ext_x_array()是为 X 轴数据点设置一个外部阵列,该函数一般用在 LV_CHART_TYPE_SCATTER 类型上。

/**
 * @brief 设置用于图表的x数据点的外部数组
 * 
 * @param obj 指向图表部件的指针
 * @param ser 指向数据序列的指针
 * @param array 外部数据数组
 */
void lv_chart_set_ext_x_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[]);
/**
 * @brief 设置用于图表的y数据点的外部数组
 * 
 * @param obj 指向图表部件的指针
 * @param ser 指向数据序列的指针
 * @param array 外部数据数组
 */
void lv_chart_set_ext_y_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[]);

  我们还可以使用 lv_chart_set_next_value() 函数 设置图表的下一个数值

/**
 * @brief 根据更新模式策略设置下一个点的Y值
 * 
 * @param obj 指向图表部件的指针
 * @param ser 指向数据序列的指针
 * @param value 下一个点的值
 */
void lv_chart_set_next_value(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value); 

  上述的模式是由 lv_chart_set_update_mode() 函数设置,图表会根据这些模式来设置添加数据的方式。

/**
 * @brief 设置图表对象的更新模式
 * 
 * @param obj 指向图表部件的指针
 * @param update_mode 更新模式
 */
void lv_chart_set_update_mode(lv_obj_t * obj, lv_chart_update_mode_t update_mode);

  其中,更新模式 的可选值如下:

enum _lv_chart_update_mode_t {
    LV_CHART_UPDATE_MODE_SHIFT,         // 将旧数据移到左边,并将新数据添加到右边
    LV_CHART_UPDATE_MODE_CIRCULAR,      // 以循环的方式添加新数据
};

  我们还可以使用 lv_chart_set_all_value() 函数把 所有的数据都初始化为一个数值

/**
 * @brief 用一个值初始化序列中的所有数据点
 * 
 * @param obj 指向图表部件的指针
 * @param ser 指向数据序列的指针
 * @param value 初始化值
 */
void lv_chart_set_all_value(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value);

  我们还可以使用 lv_chart_set_value_by_id() 函数 修改某个数据点的数值

/**
 * @brief 直接根据索引设置图表序列中单个点的y值
 * 
 * @param obj 指向图表部件的指针
 * @param ser 指向数据序列的指针
 * @param id 数据序列的索引
 * @param value 修改后的值
 */
void lv_chart_set_value_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t value);

  我们还可以使用 lv_chart_add_series() 函数所返回的数据序列指针的成员变量 y_points 或者 x_points 数组设置数值。

/**
 * @brief 添加数据序列到图表
 * 
 * @param obj 指向图表部件的指针
 * @param color 设置数据序列的颜色
 * @param axis 表示数据序列的方向
 * @return lv_chart_series_t* 数据序列的指针
 */
lv_chart_series_t * lv_chart_add_series(lv_obj_t * obj, lv_color_t color, lv_chart_axis_t axis);

  垂直范围 是指图表所添加的数据不能超出这个范围。图表默认的垂直范围为 0 ~ 100,我们可以手动调用函数 lv_chart_set_range() 函数 设置垂直范围。设置垂直范围的数据序列必须是 LV_CHART_AXIS_PRIMARYLV_CHART_AXIS_SECONDARY

/**
 * @brief 设置轴上的最小和最大y值
 * 
 * @param obj 指向图表部件的指针
 * @param axis 轴
 * @param min 最小值
 * @param max 最大值
 */
void lv_chart_set_range(lv_obj_t * obj, lv_chart_axis_t axis, int32_t min, int32_t max);

  分隔线是用于辅助数据图表提升投射关联的。应用分隔线能够提升数据信息的可阅读性,分隔线给予了二种作用:一是拓宽标值标尺至数据可视化目标中,便于观查数据信息值之尺寸;二是提升数据可视化目标中间的较为基本。

  LVGL 的图表部件默认设置为 3 条水平分隔线和 5 条垂直分隔线,如果某边有可见的边框且该边没有填充,则分割线将绘制在边框的顶部。图表部件 分割线 是调用函数 lv_chart_set_div_line_count() 设置。

/**
 * @brief 设置水平和垂直分隔线的数量
 * 
 * @param obj 指向图表部件的指针
 * @param hdiv 水平分割线的数量
 * @param vdiv 垂直分割线的数量
 */
void lv_chart_set_div_line_count(lv_obj_t * obj, uint8_t hdiv, uint8_t vdiv);

  如果用户想让绘图从一个点开始而不是默认值 point[0] 点开始,我们可以使用函数 lv_chart_set_x_start_point() 设置一个替代索引。

/**
 * @brief 设置数据数组中x轴起点的索引
 * 
 * @param obj 指向图表部件的指针
 * @param ser 指向数据序列的指针
 * @param id 起始点的索引
 */
void lv_chart_set_x_start_point(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id);

二、实验例程

#include "lvgl.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"

int main(void)
{
    int32_t data[15] = {0};

    HAL_Init();
    System_Clock_Init(8, 336, 2, 7);
    Delay_Init(168);

    SPI_Simulate_Init();
    // SRAM_Init();
    TIM_Base_Init(&g_tim6_handle, TIM6, 83, 999);
    __HAL_TIM_CLEAR_IT(&g_tim6_handle, TIM_IT_UPDATE);                          // 清除更新中断标志位
    HAL_TIM_Base_Start_IT(&g_tim6_handle);                                      // 使能更新中断,并启动计数器

    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    // 测试代码
    for (uint32_t i = 0; i < sizeof(data) / sizeof(data[0]); i++)
    {
        data[i] = i + 1;
    }
  

    lv_obj_t *chart = lv_chart_create(lv_scr_act());                            // 创建图表部件

    lv_obj_center(chart);                                                       // 设置图表部件居中对齐

    lv_chart_set_type(chart, LV_CHART_TYPE_LINE);                               // 设置图表类型
    lv_chart_set_point_count(chart, 15);                                        // 设置数据轴上的点
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -30, 30);                // 设置左轴 Y 方向的最大最小值

    lv_chart_series_t *series = lv_chart_add_series(chart, lv_color_hex(0x00BFFF), LV_CHART_AXIS_PRIMARY_Y);   // 添加数据序列到图表
    lv_chart_set_ext_y_array(chart, series, data);                              // 设置数据序列

    while (1)
    {
        lv_timer_handler();
        Delay_ms(5);
    }
  
    return 0;
}
posted @ 2024-08-05 20:18  星光映梦  阅读(30)  评论(0编辑  收藏  举报