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
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.
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_...).
Data 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. axis
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: lv_coord_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.
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.
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_...).
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.
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.
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.
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.
Override default start point for 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
.
Tick marks and labels
Ticks and labels can be added to the axis with lv_chart_set_axis_tick(chart, axis, major_len, minor_len, major_cnt, minor_cnt, label_en, draw_size).
axis
can beLV_CHART_AXIS_X/PRIMARY_Y/SECONDARY_Y
major_len
is the length of major ticks -minor_len
is the length of minor ticksmajor_cnt
is the number of major ticks on the axisminor_cnt
in the number of minor ticks between two major tickslabel_en
true
: enable label drawing on major ticksdraw_size
extra size required to draw the tick and labels (start with 20 px and increase if the ticks/labels are clipped)
Zoom
The chart can be zoomed independently in x and y directions with
lv_chart_set_zoom_x(chart, factor) and
lv_chart_set_zoom_y(chart, factor). If factor
is 256 there is no
zoom. 512 means double zoom, etc. Fractional values are also possible
but < 256 value is not allowed.
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.
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.LV_EVENT_DRAW_PART_BEGIN
andLV_EVENT_DRAW_PART_END
are sent with the following types:LV_CHART_DRAW_PART_DIV_LINE_INIT
Used before/after drawn the div lines to add masks to any extra drawings. The following fields are set:part
:LV_PART_MAIN
line_dsc
LV_CHART_DRAW_PART_DIV_LINE_HOR
,LV_CHART_DRAW_PART_DIV_LINE_VER
Used for each horizontal and vertical division lines.part
:LV_PART_MAIN
id
: index of the linep1
,p2
: points of the lineline_dsc
LV_CHART_DRAW_PART_LINE_AND_POINT
Used on line and scatter charts for lines and points.part
:LV_PART_ITEMS
id
: index of the pointvalue
: value ofid
th pointp1
,p2
: points of the linedraw_area
: area of the pointline_dsc
rect_dsc
sub_part_ptr
: pointer to the series
LV_CHART_DRAW_PART_BAR
Used on bar charts for the rectangles.part
:LV_PART_ITEMS
id
: index of the pointvalue
: value ofid
th pointdraw_area
: area of the pointrect_dsc
:sub_part_ptr
: pointer to the series
LV_CHART_DRAW_PART_CURSOR
Used on cursor lines and points.part
:LV_PART_CURSOR
p1
,p2
: points of the lineline_dsc
rect_dsc
draw_area
: area of the points
LV_CHART_DRAW_PART_TICK_LABEL
Used on tick lines and labels.part
:LV_PART_ITEMS
id
: axisvalue
: value of the ticktext
:value
converted to decimal orNULL
for minor ticksline_dsc
,label_dsc
,
See the events of the Base object too.
Learn more about Events.
Keys
No Keys are processed by the object type.
Learn more about 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);
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
# Create a chart
chart = lv.chart(lv.screen_active())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.LINE) # Show lines and points too
# Add two data series
ser1 = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
ser2 = chart.add_series(lv.palette_main(lv.PALETTE.GREEN), lv.chart.AXIS.SECONDARY_Y)
print(ser2)
# Set next points on ser1
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,30)
chart.set_next_value(ser1,70)
chart.set_next_value(ser1,90)
# Directly set points on 'ser2'
ser2.y_points = [90, 70, 65, 65, 65, 65, 65, 65, 65, 65]
chart.refresh() # Required after direct set
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
pass
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) {
lv_coord_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);
lv_coord_t * y_array = lv_chart_get_y_array(chart, ser);
lv_coord_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 a;
a.x1 = chart->coords.x1 + p.x - 20;
a.x2 = chart->coords.x1 + p.x + 20;
a.y1 = chart->coords.y1 + p.y - 30;
a.y2 = chart->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(chart, event_cb, LV_EVENT_ALL, NULL);
lv_obj_refresh_ext_draw_size(chart);
/*Zoom in a little in X*/
// lv_chart_set_zoom_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
pass
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 = draw_task->draw_dsc;
if(base_dsc->part == LV_PART_ITEMS && draw_task->type == LV_DRAW_TASK_TYPE_FILL) {
lv_draw_fill_dsc_t * fill_dsc = draw_task->draw_dsc;
lv_obj_t * chart = lv_event_get_target(e);
lv_coord_t * y_array = lv_chart_get_y_array(chart, lv_chart_get_series_next(chart, NULL));
lv_coord_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_scr_act());
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(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
#!/opt/bin/lv_micropython -i
import lvgl as lv
def event_cb(e):
code = e.get_code()
chart = e.get_target_obj()
if code == lv.EVENT.VALUE_CHANGED:
chart.invalidate()
if code == lv.EVENT.REFR_EXT_DRAW_SIZE:
# s = lv.coord_t.__cast__(e.get_param())
# print("s: {:d}".format(s))
e.set_ext_draw_size(20)
elif code == lv.EVENT.DRAW_POST_END:
id = chart.get_pressed_point()
if id == lv.CHART_POINT_NONE :
return
# print("Selected point {:d}".format(id))
ser = chart.get_series_next(None)
while(ser) :
p = lv.point_t()
chart.get_point_pos_by_id(ser, id, p)
# print("point coords: x: {:d}, y: {:d}".format(p.x,p.y))
y_array = chart.get_y_array(ser)
value = y_array[id]
buf = lv.SYMBOL.DUMMY + "{:2d}".format(value)
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
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()
coords = lv.area_t()
chart.get_coords(coords)
# print("coords: x1: {:d}, y1: {:d}".format(coords.x1, coords.y1))
a = lv.area_t()
a.x1 = coords.x1 + p.x - 20
a.x2 = coords.x1 + p.x + 20
a.y1 = coords.y1 + p.y - 30
a.y2 = coords.y1 + p.y - 10
# print("a: x1: {:d}, x2: {:d}, y1: {:d}, y2: {:d}".format(a.x1,a.x2,a.y1,a.y2))
draw_ctx = e.get_draw_ctx()
draw_ctx.rect(draw_rect_dsc, a)
ser = chart.get_series_next(ser)
elif code == lv.EVENT.RELEASED:
chart.invalidate()
#
# Show the value of the pressed points
#
# Create a chart
chart = lv.chart(lv.screen_active())
chart.set_size(200, 150)
chart.center()
chart.add_event(event_cb, lv.EVENT.ALL, None)
chart.refresh_ext_draw_size()
# Zoom in a little in X
#chart.set_zoom_x(800)
# Add two data series
ser1 = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
ser2 = chart.add_series(lv.palette_main(lv.PALETTE.GREEN), lv.chart.AXIS.PRIMARY_Y)
for i in range(10):
chart.set_next_value(ser1, lv.rand(60, 90))
chart.set_next_value(ser2, lv.rand(10, 40))
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(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 = draw_task->draw_dsc;
if(base_dsc->part == LV_PART_ITEMS && draw_task->type == LV_DRAW_TASK_TYPE_LINE) {
add_faded_area(e);
}
/*Hook the division lines too*/
if(base_dsc->part == LV_PART_MAIN && draw_task->type == 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_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = draw_task->draw_dsc;
const lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
/*Draw a triangle below the line witch some opacity gradient*/
lv_draw_line_dsc_t * draw_line_dsc = draw_task->draw_dsc;
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;
lv_coord_t full_h = lv_obj_get_height(obj);
lv_coord_t fract_uppter = (LV_MIN(draw_line_dsc->p1.y, draw_line_dsc->p2.y) - obj->coords.y1) * 255 / full_h;
lv_coord_t fract_lower = (LV_MAX(draw_line_dsc->p1.y, draw_line_dsc->p2.y) - obj->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 = draw_line_dsc->p1.x;
rect_area.x2 = draw_line_dsc->p2.x - 1;
rect_area.y1 = LV_MAX(draw_line_dsc->p1.y, draw_line_dsc->p2.y) - 1;
rect_area.y2 = obj->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 = draw_task->draw_dsc;
lv_draw_line_dsc_t * line_dsc = draw_task->draw_dsc;
/*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
pass
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(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_zoom_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
pass
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 = draw_task->draw_dsc;
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 = draw_task->draw_dsc;
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*/
lv_coord_t * x_array = lv_chart_get_x_array(obj, ser);
lv_coord_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_UNUSED(timer);
lv_obj_t * chart = timer->user_data;
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(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
pass