
LVGL:拓展部件——图表 lv_chart
一、概述
此控件是用于可视化数据点的基础图形对象。具有以下特性:
- 分割线:图表内部可以包含划分刻度区域的垂直或水平分割线。
- 双Y轴:支持配置两个Y轴,方便对比展示不同尺度的数据。
- 轴刻度及刻度文字:X轴和Y轴可以带有刻度标记以及对应的文本标签。
- 光标:图表支持添加光标功能,便于高亮和精确读取数据点。当图表滚动时,光标的位置不变。
- 滚动和缩放:允许用户对图表进行滚动浏览和放大缩小操作。
1.1、图表对大量数据的处理
在处理大量数据点时,如果数据点的数量超过了图表水平方向上的像素数,图表会采取一种优化策略来有效绘制大量数据。具体来说,当每个像素需要表示多个数据点(例如每像素10个点)时,LVGL将会搜索这些点中的最小值和最大值,并在这两个值对应的位置之间绘制一条垂直线,确保不会遗漏任何峰值或谷值。即在这种情况下,LVGL不是逐点绘制连续的曲线,而是通过抽样找到代表区间内的最高和最低数据点,以这种方式近似显示整个数据集的趋势,从而保证在有限的屏幕空间内高效且直观地展现大数据量的信息。这种做法有助于提高性能并避免由于数据点过多导致的图形渲染延迟问题。
二、包含组件元素
- LV_PART_MAIN:背景部分。这部分使用了典型的背景样式属性,同时也包括线条样式属性(用于绘制分割线)。
- LV_PART_SCROLLBAR:滚动条部分。当图表被缩放后,会展示滚动条。
- LV_PART_ITEMS:线型或柱状的数据点集。对于:
- 线型图表:line 相关属性用于定义线条外观,而 width、height、bg_color、radius 则用来设置数据点的外观样式。
- 柱状图表:使用典型背景样式属性来设置柱子(bar)的样式。
- LV_PART_INDICATOR:用于线性和散点图表上的数据点指示器(通常是小圆形或方形)。
- LV_PART_CURSOR:光标的样式。采用 line 样式属性。width、height、bg_color、radius 可用于设置光标点的外观样式。
- LV_PART_TICKS:line 和 text 相关属性设置轴刻度线。
三、相关函数
1、void lv_chart_set_type(lv_obj_t *obj, lv_chart_type_t type)
设置图表类型。
- LV_CHART_TYPE_NONE:隐藏图表内容。
- LV_CHART_TYPE_LINE:折线图,通过线段连接数据点的方式来展示数据的变化趋势。
- LV_CHART_TYPE_BAR:柱状图,用柱形的高度来表示数据大小。
- LV_CHART_TYPE_SCATTER:散点图,在二维平面上绘制单个数据点,也可以选择性地用线条连接某些点来展示可能存在的关联关系。
lv_obj_t * chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE);
lv_chart_set_point_count(chart,20);//图表上点的个数
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 300);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 20;++i)
{
lv_chart_set_next_value(chart, series, lv_rand(0, 300));
}
lv_obj_t * chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
lv_chart_set_point_count(chart,20);//图表上点的个数
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 300);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 20;++i)
{
lv_chart_set_next_value(chart, series, lv_rand(0, 300));
}
lv_obj_t * chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);
lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS);//去除点间的连线
lv_chart_set_point_count(chart,20);//图表上点的个数
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 200);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1000);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 20;++i)
{
lv_chart_set_next_value2(chart, series, lv_rand(0, 200), lv_rand(0, 1000));
}
2、void lv_chart_set_point_count(lv_obj_t *obj, uint16_t cnt)
设置图表上显示的点的个数。
3、void lv_chart_set_range(lv_obj_t *obj, lv_chart_axis_t axis, lv_coord_t min, lv_coord_t max)
设置图表的某一坐标轴的最小值和最大值。
- LV_CHART_AXIS_PRIMARY_Y:主要Y轴。一般是图表左侧的垂直轴,用于展示数据的纵坐标值。
- LV_CHART_AXIS_SECONDARY_Y:次要Y轴。通常位于图表右侧,也用于展示数据的纵坐标值,但与主要Y轴独立,可以设置不同的刻度和范围。
- LV_CHART_AXIS_PRIMARY_X:主要X轴。一般是图表底部的水平轴,用于展示数据的横坐标值。
- LV_CHART_AXIS_SECONDARY_X:次要X轴。
4、void lv_chart_set_update_mode(lv_obj_t *obj, lv_chart_update_mode_t update_mode)
设置图表的更新模式。
- LV_CHART_UPDATE_MODE_SHIFT:每当有新数据到来时,图表会将现有的所有数据向左(即时间或顺序上的早期方向)移动一位,腾出最右侧的位置给新数据。这样做的效果就像数据在图表上不断向右滚动,始终保持固定数量的数据点在图表上显示。
- LV_CHART_UPDATE_MODE_CIRCULAR:图表数据缓冲区被视为一个循环队列。当新数据添加到图表时,如果缓冲区已满,则最早进入缓冲区的数据点将被替换掉,新数据会在缓冲区中按循环方式添加,确保图表总是显示最新的一组数据点。在这种模式下,图表可视化的数据点总数维持不变,只是内容随新数据的输入而更新。
5、void lv_chart_set_div_line_count(lv_obj_t *obj, uint8_t hdiv, uint8_t vdiv)
设置图表分隔线数量。
6、void lv_chart_set_zoom_x(lv_obj_t *obj, uint16_t zoom_x)
void lv_chart_set_zoom_y(lv_obj_t *obj, uint16_t zoom_y)
设置图表在X轴和Y轴方向上的缩放级别。
256 表示不进行缩放,图表将以原始大小显示;512 表示在对应方向上双倍缩放,以此类推。
垂直方向不变,水平方向放大1.5倍:
7、void lv_chart_set_axis_tick(lv_obj_t *obj, lv_chart_axis_t axis, lv_coord_t major_len, lv_coord_t minor_len, lv_coord_t major_cnt, lv_coord_t minor_cnt, bool label_en, lv_coord_t draw_size)
设置图表坐标轴相关显示选项。
lv_obj_t * chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);
lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS);//去除点间的连线
lv_chart_set_point_count(chart,20);//图表上点的个数
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 200);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1000);
lv_chart_set_div_line_count(chart,10,10);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 25, 5, 10, 5, true, 80);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 20;++i)
{
lv_chart_set_next_value2(chart, series, lv_rand(0, 200), lv_rand(0, 1000));
}
8、void lv_chart_set_x_start_point(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id)
设置绘制开始的第一个点的索引。
可以向一个点集中添加多个点,但可以自定义绘制从哪个点开始。
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); // 设置为线型图表
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 20);
lv_chart_set_point_count(chart,10);//图表上点的个数
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 10;++i)
{
lv_chart_set_next_value(chart, series, i);
}
这里添加了0-9共10个点,设置从第一个点开始绘制:
lv_chart_set_x_start_point(chart,series,1);
9、void lv_chart_get_point_pos_by_id(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id, lv_point_t *p_out)
获取图表中指定序列的某个点的位置信息。
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); // 设置为线型图表
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 20);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 20);
lv_chart_set_point_count(chart,10);//图表上点的个数
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 10;++i)
{
lv_chart_set_next_value(chart, series, i);
}
lv_point_t point_position;
lv_chart_get_point_pos_by_id(chart, series, 5, &point_position);
printf("Point at index %d is located at (%d, %d)\n", 5, point_position.x, point_position.y);
10、void lv_chart_refresh(lv_obj_t *obj)
刷新图表对象的内容,一般用在图表的数据曲线发生更改之后。
11、lv_chart_series_t *lv_chart_add_series(lv_obj_t *obj, lv_color_t color, lv_chart_axis_t axis)
在图表上分配和添加一个新的数据集(曲线)。
参数2用来指定新添加的数据集在图表上的显示颜色。
参数3是曲线所依附的Y轴。
12、void lv_chart_remove_series(lv_obj_t *obj, lv_chart_series_t *series)
从图表对象中移除和释放指定曲线。
13、void lv_chart_hide_series(lv_obj_t *chart, lv_chart_series_t *series, bool hide)
隐藏/显示图表中的曲线。
14、void lv_chart_set_series_color(lv_obj_t *chart, lv_chart_series_t *series, lv_color_t color)
设置曲线颜色。
15、lv_chart_series_t *lv_chart_get_series_next(const lv_obj_t *chart, const lv_chart_series_t *ser)
获取图表对象中下一个曲线的函数。
参数2是指向当前曲线的指针。如果为NULL,那么函数将返回图表中的第一个曲线。
此函数用于遍历图表的所有曲线。
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); // 设置为线型图表
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_series_t *first_series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t *second_series = lv_chart_add_series(chart, lv_color_hex(0x00ff00), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t *current_series = lv_chart_get_series_next(chart, NULL);
while(current_series)
{
uint8_t red = (current_series->color.full >> 16) & 0xFF;
uint8_t green = (current_series->color.full >> 8) & 0xFF;
uint8_t blue = current_series->color.full & 0xFF;
uint8_t alpha = (current_series->color.full >> 24) & 0xFF;
printf("Color (RGBA): #%02X%02X%02X%02X\n", alpha, red, green, blue);
current_series = lv_chart_get_series_next(chart, current_series);
}
16、lv_chart_cursor_t *lv_chart_add_cursor(lv_obj_t *obj, lv_color_t color, lv_dir_t dir)
向图表添加一个光标。
参数2是颜色,参数3是光标方向:
- LV_DIR_NONE:不绘制光标。
- LV_DIR_RIGHT、LV_DIR_UP、LV_DIR_LEFT、LV_DIR_DOWN:右、上、左、下。
- LV_DIR_HOR:水平方向(等于 LV_DIR_LEFT | LV_DIR_RIGHT)。
- LV_DIR_VER:垂直方向(等于 LV_DIR_UP | LV_DIR_DOWN)。
- LV_DIR_ALL:所有方向。
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); // 设置为线型图表
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 20);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 20);
lv_chart_set_point_count(chart,10);//图表上点的个数
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 25, 5, 10, 5, true, 80);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 25, 5, 10, 5, true, 80);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 10;++i)
{
lv_chart_set_next_value(chart, series, i);
}
lv_chart_cursor_t *cursor = lv_chart_add_cursor(chart, lv_color_hex(0x00ff00), LV_DIR_ALL);
lv_point_t point = {200, 150};
lv_chart_set_cursor_pos(chart, cursor, &point);
lv_chart_set_zoom_x(chart,512);
17、void lv_chart_set_cursor_pos(lv_obj_t *chart, lv_chart_cursor_t *cursor, lv_point_t *pos)
设置光标位置。位置单位是像素。坐标是基于图表数据区域的左上角(即去除边框和内边距后的起始点),而非整个图表对象的绝对位置。
18、void lv_chart_set_cursor_point(lv_obj_t *chart, lv_chart_cursor_t *cursor, lv_chart_series_t *ser, uint16_t point_id)
图表中的光标固定到某个曲线中的特定数据点。
如果参数4是 LV_CHART_POINT_NONE 则解除光标与任何数据点的关联。
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); // 设置为线型图表
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 20);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 20);
lv_chart_set_point_count(chart,10);//图表上点的个数
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 25, 5, 10, 5, true, 80);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 25, 5, 10, 5, true, 80);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 10;++i)
{
lv_chart_set_next_value(chart, series, i);
}
lv_chart_cursor_t *cursor = lv_chart_add_cursor(chart, lv_color_hex(0x00ff00), LV_DIR_ALL);
lv_point_t point = {200, 150};
lv_chart_set_cursor_pos(chart, cursor, &point);
lv_chart_set_zoom_x(chart,512);
lv_chart_set_cursor_point(chart,cursor,series,3);
19、lv_point_t lv_chart_get_cursor_point(lv_obj_t *chart, lv_chart_cursor_t *cursor)
获取图表中光标的当前坐标。
20、void lv_chart_set_all_value(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t value)
将图表中指定曲线(数据集)的所有数据点的值初始化为给定的数值。
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); // 设置为线型图表
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 20);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 20);
lv_chart_set_point_count(chart,10);//图表上点的个数
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 25, 5, 10, 5, true, 80);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 25, 5, 10, 5, true, 80);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 10;++i)
{
lv_chart_set_next_value(chart, series, i);
}
lv_chart_set_all_value(chart, series, 10);
21、void lv_chart_set_next_value(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t value)
在图表中指定曲线的下一个数据点设置新的Y轴坐标值。
22、void lv_chart_set_next_value2(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t x_value, lv_coord_t y_value)
类似,设置新的X和Y轴坐标值。仅用于 LV_CHART_TYPE_SCATTER 类型曲线。
23、void lv_chart_set_value_by_id(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id, lv_coord_t value)
直接通过索引来设置图表中指定曲线中某个数据点Y值。
24、void lv_chart_set_value_by_id2(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id, lv_coord_t x_value, lv_coord_t y_value)
类似,设置X和Y值。仅用于 LV_CHART_TYPE_SCATTER 类型曲线。
25、void lv_chart_set_ext_x_array(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t array[])
void lv_chart_set_ext_y_array(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t array[])
设置图表中指定曲线X值、Y值数组。
26、uint32_t lv_chart_get_pressed_point(const lv_obj_t *obj)
获取当前按下的数据点。不适用于散点图。
void handle_chart_press(lv_event_t *e)
{
lv_obj_t *chart = lv_event_get_target(e); // 获取触发事件的图表对象
// 检查是否有数据点被按下
uint32_t pressed_point_index = lv_chart_get_pressed_point(chart);
if (pressed_point_index == LV_CHART_POINT_NONE)
{
std::cout<<"没有按下点"<<std::endl;
}
else
{
std::cout<<"Pressed data point index - "<<pressed_point_index<<std::endl;
}
}
int main(int argc, char **argv)
{
lv_init();
hal_init();
lv_log_register_print_cb(esp32_log_cb);
{
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
lv_obj_set_size(chart, 400, 300);
lv_obj_center(chart);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 20);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 20);
lv_chart_set_point_count(chart,10);//图表上点的个数
lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS);//去除点间的连线
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 25, 5, 10, 5, true, 80);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 25, 5, 10, 5, true, 80);
lv_chart_series_t * series = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
for(int i = 0;i < 10;++i)
{
lv_chart_set_next_value(chart, series, i);
}
lv_obj_add_event_cb(chart, handle_chart_press, LV_EVENT_PRESSED, NULL);
}
while (1)
{
lv_timer_handler();
usleep(5 * 1000);
}
return 0;
}
更多推荐
所有评论(0)