Chart(图表) (lv_chart)
Overview(概述)
显示原文
Charts are a basic object to visualize data points. Currently Line charts (connect points with lines and/or draw points on them) and Bar charts are supported.
Charts can have: - division lines - 2 y axis - axis ticks and texts on ticks - cursors - scrolling and zooming
图表是可以将数据点可视化的基本对象。目前支持折线图(用折线连接点和/或在其上绘制点)和柱状图。
图表可以有:
分割线
2 y轴
轴刻度和文本刻度
光标
滚动和缩放
Parts and Styles(部分和样式)
显示原文
LV_PART_MAIN
The background of the chart. Uses all the typical background and line (for the division lines) related style properties. Padding makes the series area smaller. For column chartspad_column
sets the space between the columns of the adjacent indices.LV_PART_SCROLLBAR
The scrollbar used if the chart is zoomed. See the Base object's documentation for details.LV_PART_ITEMS
Refers to the line or bar series.Line chart: The line properties are used by the lines.
width
,height
,bg_color
andradius
is used to set the appearance of points.Bar chart: The typical background properties are used to style the bars.
pad_column
sets the space between the columns on the same index.
LV_PART_INDICATOR
Refers to the points on line and scatter chart (small circles or squares).LV_PART_CURSOR
Line properties are used to style the cursors.width
,height
,bg_color
andradius
are used to set the appearance of points.
LV_PART_MAIN
图表的背景。使用所有典型的 背景和 Line (用于分割线)相关样式。 Padding 使series区域更小。可通过pad_column
设置相邻索引之间的间隔。LV_PART_SCROLLBAR
缩放图表时使用的滚动条。看有关详细信息,请参阅 基本对象的文档。LV_PART_ITEMS
指线或柱状条:折线图: line 属性由折线使用。
width
,height
,bg_color
和radius
用于设置点的外观。柱状图:典型的背景属性用于设置进度条。
pad_column
设置相邻索引的间隔。
LV_PART_INDICATOR
指折线图和散点图上的点 (小圆圈或正方形)。LV_PART_CURSOR
Line 属性用于设置游标的样式。width
,height
,bg_color
andradius
用于设置点的外观。
Usage(用法)
Chart type(图表类型)
显示原文
The following data display types exist:
LV_CHART_TYPE_NONE
: Do not display any data. Can be used to hide the series.LV_CHART_TYPE_LINE
: Draw lines between the data points and/or points (rectangles or circles) on the data points.LV_CHART_TYPE_BAR
: Draw bars.LV_CHART_TYPE_SCATTER
: X/Y chart drawing point's and lines between the points. .
You can specify the display type with lv_chart_set_type(chart, LV_CHART_TYPE_...).
存在以下数据显示类型:
LV_CHART_TYPE_NONE
: 不显示任何数据。可用于隐藏 series。LV_CHART_TYPE_LINE
: 根据数据点的数量和xy轴的大小,平均间隔绘制数据点(矩形或者圆形)并且在点与点之间绘制线条连接。LV_CHART_TYPE_BAR
: 根据数据点的数量和xy轴的大小,平均间隔绘制柱状条。LV_CHART_TYPE_SCATTER
:根据给定的x、y坐标绘制出其在xy轴上的点和线。
你可以使用 lv_chart_set_type(chart, LV_CHART_TYPE_...) 指定显示类型。
Data series(Series数据)
显示原文
You can add any number of series to the charts by
lv_chart_add_series(chart, color, axis). This allocates an
lv_chart_series_t
structure which contains the chosen color
and
an array for the data points. can have the following values:
LV_CHART_AXIS_PRIMARY_Y
: Left axisLV_CHART_AXIS_SECONDARY_Y
: Right axisLV_CHART_AXIS_PRIMARY_X
: Bottom axisLV_CHART_AXIS_SECONDARY_X
: Top axis
axis
tells which axis's range should be used to scale the values.
lv_chart_set_ext_y_array(chart, ser, value_array) makes the chart
use an external array for the given series. value_array
should look
like this: int32_t * value_array[num_points]
. The array size
needs to be large enough to hold all the points of that series. The
array's pointer will be saved in the chart so it needs to be global,
static or dynamically allocated. Note: you should call
lv_chart_refresh(chart) after the external data source has been
updated to update the chart.
The value array of a series can be obtained with
lv_chart_get_y_array(chart, ser), which can be used with
ext_array
or normal arrays.
For LV_CHART_TYPE_SCATTER
type
lv_chart_set_ext_x_array(chart, ser, value_array) and
lv_chart_get_x_array(chart, ser) can be used as well.
你可以通过函数 lv_chart_add_series(chart, color, axis) 向图表添加任意数量的series。这将分配一个 lv_chart_series_t
结构,其中包含数据点的数组。 axis
可以具有以下值:
axis
指示应使用哪个轴的范围来缩放值。
lv_chart_set_ext_y_array(chart, ser, value_array) 制作图表对给定series使用外部数组。 value_array
应该看起来像 int32_t * value_array[num_points]
。数组大小需要足够大以容纳该series的所有点。这 array 的指针将保存在图表中,因此它需要是全局的, 静态或动态分配。注意:你应该 lv_chart_refresh(chart) 在外部数据源已更新被以更新图表。
一个 serie 的值数组可以通过接口 lv_chart_get_x / y_array(chart, ser) 获得。
对于 LV_CHART_TYPE_SCATTER
类型可以通过 lv_chart_set_ext_x / y_array(chart, ser, value_array) 设置,以及 lv_chart_get_x / y_array(chart, ser) 获取。
Modify the data(修改数据)
显示原文
You have several options to set the data of series:
Set the values manually in the array like
ser1->points[3] = 7
and refresh the chart withlv_chart_refresh(chart)
.Use lv_chart_set_value_by_id(chart, ser, id, value) where
id
is the index of the point you wish to update.Use the lv_chart_set_next_value(chart, ser, value).
Initialize all points to a given value with lv_chart_set_all_value(chart, ser, value).
Use LV_CHART_POINT_NONE
as value to make the library skip drawing
that point, column, or line segment.
For LV_CHART_TYPE_SCATTER
type
lv_chart_set_value_by_id2(chart, ser, id, value) and
lv_chart_set_next_value2(chart, ser, x_value, y_value) can be used
as well.
有几个选项可以设置series数据:
在数组中手动设置值,例如
ser1->points[3] = 7
,并使用lv_chart_refresh(chart)
刷新图表。使用 lv_chart_set_value_by_id(chart, ser, id, value) 其中id是要更新的点的索引。id
使用 lv_chart_set_next_value(chart, ser, value)。
使用 lv_chart_set_all_value(chart, ser, value) 将所有点初始化为给定值。
使用 LV_CHART_POINT_NONE
作为值可使库跳过该点,列或线段的绘制。
对于 LV_CHART_TYPE_SCATTER
类型 lv_chart_set_value_by_id2(chart, ser, id, value) 和 lv_chart_set_next_value2(chart, ser, x_value, y_value) 也可以使用。
Update modes(更新模式)
显示原文
lv_chart_set_next_value()
can behave in two ways depending on update
mode:
LV_CHART_UPDATE_MODE_SHIFT
: Shift old data to the left and add the new one to the right.LV_CHART_UPDATE_MODE_CIRCULAR
: Add the new data in circular fashion, like an ECG diagram.
The update mode can be changed with lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_...).
lv_chart_set_next_value()
可以以两种方式运行,具体取决于 更新模式 :
LV_CHART_UPDATE_MODE_SHIFT
: 将旧数据向左移动,将新数据添加到右侧。LV_CHART_UPDATE_MODE_CIRCULAR
: 以循环方式添加新数据,如心电图。
更新模式可以通过 lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_...)。
Number of points(点数)
显示原文
The number of points in the series can be modified by lv_chart_set_point_count(chart, point_num). The default value is 10. Note: this also affects the number of points processed when an external buffer is assigned to a series, so you need to be sure the external array is large enough.
series中的点数可以通过 lv_chart_set_point_count(chart, point_num) 进行修改。默认值为 10。注意:这也会影响外部处理的点数缓冲区被分配给一个series,所以你需要确保外部数组足够大。
Handling large number of points(处理很密集的点)
显示原文
On line charts, if the number of points is greater than the pixels horizontally, the Chart will draw only vertical lines to make the drawing of large amount of data effective. If there are, let's say, 10 points to a pixel, LVGL searches the smallest and the largest value and draws a vertical lines between them to ensure no peaks are missed.
在折线图上,如果点数大于水平方向上的像素范围,图表将只绘制垂直线来让大量数据的绘制有效。比如,每像素10个点,LVGL搜索最小值和最大值,并在它们之间画一条垂直线,以确保没有遗漏峰值。。
Vertical range(垂直范围)
显示原文
You can specify the minimum and maximum values in y-direction with
lv_chart_set_range(chart, axis, min, max). axis
can be
LV_CHART_AXIS_PRIMARY
(left axis) or LV_CHART_AXIS_SECONDARY
(right axis).
The value of the points will be scaled proportionally. The default range is: 0..100.
你可以使用 lv_chart_set_range(chart, axis, min, max) 指定 y 方向的最小值和最大值。 axis
可以是(左轴)或(右轴)。LV_CHART_AXIS_PRIMARY
(左轴) 或 LV_CHART_AXIS_SECONDARY
(右轴).
点的值将按比例缩放。默认范围是:0..100。
Division lines(分割线)
显示原文
The number of horizontal and vertical division lines can be modified by lv_chart_set_div_line_count(chart, hdiv_num, vdiv_num). The default settings are 3 horizontal and 5 vertical division lines. If there is a visible border on a side and no padding on that side, the division line would be drawn on top of the border and therefore it won't be drawn.
水平和垂直分割线的数量可以通过 lv_chart_set_div_line_count(chart, hdiv_num, vdiv_num) 进行修改。默认设置为 3 条水平分割线和 5 条垂直分割线。如果一侧有可见的边框,并且该侧没有填充,则分割线将绘制在边框的顶部,因此不会绘制。
Override default start point for series(覆盖series的默认起点)
显示原文
If you want a plot to start from a point other than the default which is
point[0]
of the series, you can set an alternative index with the
function lv_chart_set_x_start_point(chart, ser, id) where id
is
the new index position to start plotting from.
Note that LV_CHART_UPDATE_MODE_SHIFT
also changes the
start_point
.
如果希望绘图从series的默认点以外的点 point[0]
开始,则可以使用函数 lv_chart_set_x_start_point(chart, ser, id) 其中 id
是要从中开始绘图的新索引位置。
请注意, LV_CHART_UPDATE_MODE_SHIFT
也会更改 start_point
。
Tick marks and labels(刻度线和标签)
显示原文
With the help of Scale, vertical and horizontal scales can be added in a very flexible way. See the example below to learn more.
借助 Scale 控件,可以非常灵活地添加垂直和水平刻度。请参阅后面的示例以了解用法参考。
Zoom(缩放)
显示原文
To zoom the chart all you need to is wrapping it into a parent container and set the chart's width or height to larger value. This way the chart will be scrollable on its parent.
要缩放图表,你只需将其包装到父容器中,并将图表的宽度或高度设置为更大的值。这样,图表将在其父级上得到放大的效果并可滚动查看。
Cursor(光标)
显示原文
A cursor can be added with lv_chart_cursor_t * c1 = lv_chart_add_cursor(chart, color, dir);
.
The possible values of dir
LV_DIR_NONE/RIGHT/UP/LEFT/DOWN/HOR/VER/ALL
or their OR-ed values to
tell in which direction(s) should the cursor be drawn.
lv_chart_set_cursor_pos(chart, cursor, &point) sets the position of
the cursor. pos
is a pointer to an lv_point_t
variable. E.g.
lv_point_t point = {10, 20}
. If the chart is scrolled the cursor
will remain in the same place.
lv_chart_get_point_pos_by_id(chart, series, id, &point_out) gets the coordinate of a given point. It's useful to place the cursor at a given point.
lv_chart_set_cursor_point(chart, cursor, series, point_id) sticks the cursor at a point. If the point's position changes (new value or scrolling) the cursor will move with the point.
可以使用 lv_chart_cursor_t * c1 = lv_chart_add_cursor(chart, color, dir);
添加光标。 dir
的值可以是 LV_DIR_NONE/RIGHT/UP/LEFT/DOWN/HOR/VER/ALL
或它们的OR-ed 值,用于指示应在哪个方向上绘制光标。
lv_chart_set_cursor_pos(chart, cursor, &point) 设置光标的位置。pos
是指向 lv_point_t
变量的指针。例如 lv_point_t point = {10, 20}
。如果滚动图表,光标将保持在同一位置。
lv_chart_get_point_pos_by_id(chart, series, id, &point_out) 获取给定点的坐标。将光标放在给定的位置很有用。
lv_chart_set_cursor_point(chart, cursor, series, point_id) 将光标粘在一个点上。如果点的位置发生变化(新值或滚动),光标将随点移动。
Events(事件)
显示原文
LV_EVENT_VALUE_CHANGED
Sent when a new point is clicked pressed. lv_chart_get_pressed_point(chart) returns the zero-based index of the pressed point.
See the events of the Base object too.
Learn more about Events(事件).
LV_EVENT_VALUE_CHANGED
单击按下新点时发送。lv_chart_get_pressed_point(chart) 返回从零开始的索引按下的点。
另请参阅 基本对象 的事件。
详细了解更多 Events(事件)。
Keys(按键)
对象类型不处理任何 按键。
了解有关 Keys(按键) 的更多信息。
Example
Line Chart
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
/**
* A very basic line chart
*/
void lv_example_chart_1(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_screen_active());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/
/*Add two data series*/
lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_SECONDARY_Y);
int32_t * ser2_y_points = lv_chart_get_y_array(chart, ser2);
uint32_t i;
for(i = 0; i < 10; i++) {
/*Set the next points on 'ser1'*/
lv_chart_set_next_value(chart, ser1, lv_rand(10, 50));
/*Directly set points on 'ser2'*/
ser2_y_points[i] = lv_rand(50, 90);
}
lv_chart_refresh(chart); /*Required after direct set*/
}
#endif
Axis ticks and labels with scrolling
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
/**
* Use lv_scale to add ticks to a scrollable chart
*/
void lv_example_chart_2(void)
{
/*Create a container*/
lv_obj_t * main_cont = lv_obj_create(lv_screen_active());
lv_obj_set_size(main_cont, 200, 150);
lv_obj_center(main_cont);
/*Create a transparent wrapper for the chart and the scale.
*Set a large width, to make it scrollable on the main container*/
lv_obj_t * wrapper = lv_obj_create(main_cont);
lv_obj_remove_style_all(wrapper);
lv_obj_set_size(wrapper, lv_pct(300), lv_pct(100));
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
/*Create a chart on the wrapper
*Set it's width to 100% to fill the large wrapper*/
lv_obj_t * chart = lv_chart_create(wrapper);
lv_obj_set_width(chart, lv_pct(100));
lv_obj_set_flex_grow(chart, 1);
lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_Y, 0, 400);
lv_chart_set_point_count(chart, 12);
lv_obj_set_style_radius(chart, 0, 0);
/*Create a scale also with 100% width*/
lv_obj_t * scale_bottom = lv_scale_create(wrapper);
lv_scale_set_mode(scale_bottom, LV_SCALE_MODE_HORIZONTAL_BOTTOM);
lv_obj_set_size(scale_bottom, lv_pct(100), 25);
lv_scale_set_total_tick_count(scale_bottom, 12);
lv_scale_set_major_tick_every(scale_bottom, 1);
lv_obj_set_style_pad_hor(scale_bottom, lv_chart_get_first_point_center_offset(chart), 0);
static const char * month[] = {"Jan", "Febr", "March", "Apr", "May", "Jun", "July", "Aug", "Sept", "Oct", "Nov", "Dec", NULL};
lv_scale_set_text_src(scale_bottom, month);
/*Add two data series*/
lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_lighten(LV_PALETTE_GREEN, 2), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_darken(LV_PALETTE_GREEN, 2), LV_CHART_AXIS_PRIMARY_Y);
/*Set the next points on 'ser1'*/
uint32_t i;
for(i = 0; i < 12; i++) {
lv_chart_set_next_value(chart, ser1, lv_rand(10, 60));
lv_chart_set_next_value(chart, ser2, lv_rand(50, 90));
}
lv_chart_refresh(chart); /*Required after direct set*/
}
#endif
Show the value of the pressed points
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
static void event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * chart = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
lv_obj_invalidate(chart);
}
if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
int32_t * s = lv_event_get_param(e);
*s = LV_MAX(*s, 20);
}
else if(code == LV_EVENT_DRAW_POST_END) {
int32_t id = lv_chart_get_pressed_point(chart);
if(id == LV_CHART_POINT_NONE) return;
LV_LOG_USER("Selected point %d", (int)id);
lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);
while(ser) {
lv_point_t p;
lv_chart_get_point_pos_by_id(chart, ser, id, &p);
int32_t * y_array = lv_chart_get_y_array(chart, ser);
int32_t value = y_array[id];
char buf[16];
lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"$%d", value);
lv_draw_rect_dsc_t draw_rect_dsc;
lv_draw_rect_dsc_init(&draw_rect_dsc);
draw_rect_dsc.bg_color = lv_color_black();
draw_rect_dsc.bg_opa = LV_OPA_50;
draw_rect_dsc.radius = 3;
draw_rect_dsc.bg_image_src = buf;
draw_rect_dsc.bg_image_recolor = lv_color_white();
lv_area_t chart_obj_coords;
lv_obj_get_coords(chart, &chart_obj_coords);
lv_area_t a;
a.x1 = chart_obj_coords.x1 + p.x - 20;
a.x2 = chart_obj_coords.x1 + p.x + 20;
a.y1 = chart_obj_coords.y1 + p.y - 30;
a.y2 = chart_obj_coords.y1 + p.y - 10;
lv_layer_t * layer = lv_event_get_layer(e);
lv_draw_rect(layer, &draw_rect_dsc, &a);
ser = lv_chart_get_series_next(chart, ser);
}
}
else if(code == LV_EVENT_RELEASED) {
lv_obj_invalidate(chart);
}
}
/**
* Show the value of the pressed points
*/
void lv_example_chart_3(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_screen_active());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
lv_obj_add_event_cb(chart, event_cb, LV_EVENT_ALL, NULL);
lv_obj_refresh_ext_draw_size(chart);
/*Zoom in a little in X*/
// lv_chart_set_scale_x(chart, 800);
/*Add two data series*/
lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart, ser1, lv_rand(60, 90));
lv_chart_set_next_value(chart, ser2, lv_rand(10, 40));
}
}
#endif
Recolor bars based on their value
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES
static void draw_event_cb(lv_event_t * e)
{
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
if(base_dsc->part != LV_PART_ITEMS) {
return;
}
lv_draw_fill_dsc_t * fill_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_dsc) {
lv_obj_t * chart = lv_event_get_target(e);
int32_t * y_array = lv_chart_get_y_array(chart, lv_chart_get_series_next(chart, NULL));
int32_t v = y_array[base_dsc->id2];
uint32_t ratio = v * 255 / 100;
fill_dsc->color = lv_color_mix(lv_palette_main(LV_PALETTE_GREEN), lv_palette_main(LV_PALETTE_RED), ratio);
}
}
/**
* Recolor the bars of a chart based on their value
*/
void lv_example_chart_4(void)
{
/*Create a chart1*/
lv_obj_t * chart = lv_chart_create(lv_screen_active());
lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
lv_chart_set_point_count(chart, 24);
lv_obj_set_style_pad_column(chart, 2, 0);
lv_obj_set_size(chart, 260, 160);
lv_obj_center(chart);
lv_chart_series_t * ser = lv_chart_add_series(chart, lv_color_hex(0xff0000), LV_CHART_AXIS_PRIMARY_Y);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
uint32_t i;
for(i = 0; i < 24; i++) {
lv_chart_set_next_value(chart, ser, lv_rand(10, 90));
}
}
#endif
Faded area line chart with custom division lines
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES
static void hook_division_lines(lv_event_t * e);
static void add_faded_area(lv_event_t * e);
static void draw_event_cb(lv_event_t * e);
/**
* Add a faded area effect to the line chart and make some division lines ticker
*/
void lv_example_chart_5(void)
{
/*Create a chart*/
lv_obj_t * chart = lv_chart_create(lv_screen_active());
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/
lv_obj_set_size(chart, 200, 150);
lv_obj_set_style_pad_all(chart, 0, 0);
lv_obj_set_style_radius(chart, 0, 0);
lv_obj_center(chart);
lv_chart_set_div_line_count(chart, 5, 7);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
lv_chart_series_t * ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart, ser, lv_rand(10, 80));
}
}
static void draw_event_cb(lv_event_t * e)
{
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
if(base_dsc->part == LV_PART_ITEMS && lv_draw_task_get_type(draw_task) == LV_DRAW_TASK_TYPE_LINE) {
add_faded_area(e);
}
/*Hook the division lines too*/
if(base_dsc->part == LV_PART_MAIN && lv_draw_task_get_type(draw_task) == LV_DRAW_TASK_TYPE_LINE) {
hook_division_lines(e);
}
}
static void add_faded_area(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
lv_area_t coords;
lv_obj_get_coords(obj, &coords);
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
const lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
lv_color_t ser_color = lv_chart_get_series_color(obj, ser);
/*Draw a triangle below the line witch some opacity gradient*/
lv_draw_line_dsc_t * draw_line_dsc = lv_draw_task_get_draw_dsc(draw_task);
lv_draw_triangle_dsc_t tri_dsc;
lv_draw_triangle_dsc_init(&tri_dsc);
tri_dsc.p[0].x = draw_line_dsc->p1.x;
tri_dsc.p[0].y = draw_line_dsc->p1.y;
tri_dsc.p[1].x = draw_line_dsc->p2.x;
tri_dsc.p[1].y = draw_line_dsc->p2.y;
tri_dsc.p[2].x = draw_line_dsc->p1.y < draw_line_dsc->p2.y ? draw_line_dsc->p1.x : draw_line_dsc->p2.x;
tri_dsc.p[2].y = LV_MAX(draw_line_dsc->p1.y, draw_line_dsc->p2.y);
tri_dsc.bg_grad.dir = LV_GRAD_DIR_VER;
int32_t full_h = lv_obj_get_height(obj);
int32_t fract_uppter = (int32_t)(LV_MIN(draw_line_dsc->p1.y, draw_line_dsc->p2.y) - coords.y1) * 255 / full_h;
int32_t fract_lower = (int32_t)(LV_MAX(draw_line_dsc->p1.y, draw_line_dsc->p2.y) - coords.y1) * 255 / full_h;
tri_dsc.bg_grad.stops[0].color = ser_color;
tri_dsc.bg_grad.stops[0].opa = 255 - fract_uppter;
tri_dsc.bg_grad.stops[0].frac = 0;
tri_dsc.bg_grad.stops[1].color = ser_color;
tri_dsc.bg_grad.stops[1].opa = 255 - fract_lower;
tri_dsc.bg_grad.stops[1].frac = 255;
lv_draw_triangle(base_dsc->layer, &tri_dsc);
/*Draw rectangle below the triangle*/
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.bg_grad.dir = LV_GRAD_DIR_VER;
rect_dsc.bg_grad.stops[0].color = ser_color;
rect_dsc.bg_grad.stops[0].frac = 0;
rect_dsc.bg_grad.stops[0].opa = 255 - fract_lower;
rect_dsc.bg_grad.stops[1].color = ser_color;
rect_dsc.bg_grad.stops[1].frac = 255;
rect_dsc.bg_grad.stops[1].opa = 0;
lv_area_t rect_area;
rect_area.x1 = (int32_t)draw_line_dsc->p1.x;
rect_area.x2 = (int32_t)draw_line_dsc->p2.x - 1;
rect_area.y1 = (int32_t)LV_MAX(draw_line_dsc->p1.y, draw_line_dsc->p2.y) - 1;
rect_area.y2 = (int32_t)coords.y2;
lv_draw_rect(base_dsc->layer, &rect_dsc, &rect_area);
}
static void hook_division_lines(lv_event_t * e)
{
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
lv_draw_line_dsc_t * line_dsc = lv_draw_task_get_draw_dsc(draw_task);
/*Vertical line*/
if(line_dsc->p1.x == line_dsc->p2.x) {
line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1);
if(base_dsc->id1 == 3) {
line_dsc->width = 2;
line_dsc->dash_gap = 0;
line_dsc->dash_width = 0;
}
else {
line_dsc->width = 1;
line_dsc->dash_gap = 6;
line_dsc->dash_width = 6;
}
}
/*Horizontal line*/
else {
if(base_dsc->id1 == 2) {
line_dsc->width = 2;
line_dsc->dash_gap = 0;
line_dsc->dash_width = 0;
}
else {
line_dsc->width = 2;
line_dsc->dash_gap = 6;
line_dsc->dash_width = 6;
}
if(base_dsc->id1 == 1 || base_dsc->id1 == 3) {
line_dsc->color = lv_palette_main(LV_PALETTE_GREEN);
}
else {
line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1);
}
}
}
#endif
Show cursor on the clicked point
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
static lv_obj_t * chart;
static lv_chart_series_t * ser;
static lv_chart_cursor_t * cursor;
static void value_changed_event_cb(lv_event_t * e)
{
static int32_t last_id = -1;
lv_obj_t * obj = lv_event_get_target(e);
last_id = lv_chart_get_pressed_point(obj);
if(last_id != LV_CHART_POINT_NONE) {
lv_chart_set_cursor_point(obj, cursor, NULL, last_id);
}
}
/**
* Show cursor on the clicked point
*/
void lv_example_chart_6(void)
{
chart = lv_chart_create(lv_screen_active());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, 0, -10);
// lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 6, 5, true, 40);
// lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 10, 5, 10, 1, true, 30);
lv_obj_add_event_cb(chart, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_refresh_ext_draw_size(chart);
cursor = lv_chart_add_cursor(chart, lv_palette_main(LV_PALETTE_BLUE), LV_DIR_LEFT | LV_DIR_BOTTOM);
ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart, ser, lv_rand(10, 90));
}
// lv_chart_set_scale_x(chart, 500);
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Click on a point");
lv_obj_align_to(label, chart, LV_ALIGN_OUT_TOP_MID, 0, -5);
}
#endif
Scatter chart
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
static void draw_event_cb(lv_event_t * e)
{
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
if(base_dsc->part == LV_PART_INDICATOR) {
lv_obj_t * obj = lv_event_get_target(e);
lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
lv_draw_rect_dsc_t * rect_draw_dsc = lv_draw_task_get_draw_dsc(draw_task);
uint32_t cnt = lv_chart_get_point_count(obj);
/*Make older value more transparent*/
rect_draw_dsc->bg_opa = (LV_OPA_COVER * base_dsc->id2) / (cnt - 1);
/*Make smaller values blue, higher values red*/
int32_t * x_array = lv_chart_get_x_array(obj, ser);
int32_t * y_array = lv_chart_get_y_array(obj, ser);
/*dsc->id is the tells drawing order, but we need the ID of the point being drawn.*/
uint32_t start_point = lv_chart_get_x_start_point(obj, ser);
uint32_t p_act = (start_point + base_dsc->id2) % cnt; /*Consider start point to get the index of the array*/
lv_opa_t x_opa = (x_array[p_act] * LV_OPA_50) / 200;
lv_opa_t y_opa = (y_array[p_act] * LV_OPA_50) / 1000;
rect_draw_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED),
lv_palette_main(LV_PALETTE_BLUE),
x_opa + y_opa);
}
}
static void add_data(lv_timer_t * timer)
{
lv_obj_t * chart = lv_timer_get_user_data(timer);
lv_chart_set_next_value2(chart, lv_chart_get_series_next(chart, NULL), lv_rand(0, 200), lv_rand(0, 1000));
}
/**
* A scatter chart
*/
void lv_example_chart_7(void)
{
lv_obj_t * chart = lv_chart_create(lv_screen_active());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS); /*Remove the lines*/
lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);
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_point_count(chart, 50);
lv_chart_series_t * ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
uint32_t i;
for(i = 0; i < 50; i++) {
lv_chart_set_next_value2(chart, ser, lv_rand(0, 200), lv_rand(0, 1000));
}
lv_timer_create(add_data, 100, chart);
}
#endif
Circular line chart with gap
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES
static void add_data(lv_timer_t * t)
{
lv_obj_t * chart = lv_timer_get_user_data(t);
lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);
lv_chart_set_next_value(chart, ser, lv_rand(10, 90));
uint16_t p = lv_chart_get_point_count(chart);
uint16_t s = lv_chart_get_x_start_point(chart, ser);
int32_t * a = lv_chart_get_y_array(chart, ser);
a[(s + 1) % p] = LV_CHART_POINT_NONE;
a[(s + 2) % p] = LV_CHART_POINT_NONE;
a[(s + 2) % p] = LV_CHART_POINT_NONE;
lv_chart_refresh(chart);
}
/**
* Circular line chart with gap
*/
void lv_example_chart_8(void)
{
/*Create a stacked_area_chart.obj*/
lv_obj_t * chart = lv_chart_create(lv_screen_active());
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_CIRCULAR);
lv_obj_set_style_size(chart, 0, 0, LV_PART_INDICATOR);
lv_obj_set_size(chart, 280, 150);
lv_obj_center(chart);
lv_chart_set_point_count(chart, 80);
lv_chart_series_t * ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
/*Prefill with data*/
uint32_t i;
for(i = 0; i < 80; i++) {
lv_chart_set_next_value(chart, ser, lv_rand(10, 90));
}
lv_timer_create(add_data, 300, chart);
}
#endif