From 666f839977924d2d65e62f68657d630979c4227e Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 16 Oct 2023 23:43:27 +0200 Subject: [PATCH] docs(chart): update chart example --- examples/widgets/chart/lv_example_chart_1.c | 36 ++-- examples/widgets/chart/lv_example_chart_2.c | 155 ++++----------- examples/widgets/chart/lv_example_chart_3.c | 141 ++++++------- examples/widgets/chart/lv_example_chart_4.c | 88 +++------ examples/widgets/chart/lv_example_chart_5.c | 207 ++++++++++++-------- examples/widgets/chart/lv_example_chart_8.c | 137 +++---------- examples/widgets/chart/lv_example_chart_9.c | 46 ----- examples/widgets/lv_example_widgets.h | 9 +- src/draw/lv_draw.c | 29 ++- src/draw/sw/lv_draw_sw_line.c | 3 + src/widgets/chart/lv_chart.c | 14 +- src/widgets/scale/lv_scale.c | 12 +- tests/ref_imgs/line_1.png | Bin 4384 -> 4385 bytes 13 files changed, 342 insertions(+), 535 deletions(-) delete mode 100644 examples/widgets/chart/lv_example_chart_9.c diff --git a/examples/widgets/chart/lv_example_chart_1.c b/examples/widgets/chart/lv_example_chart_1.c index f489564f5..a0d0d1b5c 100644 --- a/examples/widgets/chart/lv_example_chart_1.c +++ b/examples/widgets/chart/lv_example_chart_1.c @@ -1,6 +1,9 @@ #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*/ @@ -11,32 +14,17 @@ void lv_example_chart_1(void) 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_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_SECONDARY_Y); + 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); - /*Set the next points on 'ser1'*/ - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 30); - lv_chart_set_next_value(chart, ser1, 70); - lv_chart_set_next_value(chart, ser1, 90); + 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[0] = 90; - ser2->y_points[1] = 70; - ser2->y_points[2] = 65; - ser2->y_points[3] = 65; - ser2->y_points[4] = 65; - ser2->y_points[5] = 65; - ser2->y_points[6] = 65; - ser2->y_points[7] = 65; - ser2->y_points[8] = 65; - ser2->y_points[9] = 65; + /*Directly set points on 'ser2'*/ + ser2->y_points[i] = lv_rand(50, 90); + } lv_chart_refresh(chart); /*Required after direct set*/ } diff --git a/examples/widgets/chart/lv_example_chart_2.c b/examples/widgets/chart/lv_example_chart_2.c index 3b1e09725..d638f46ed 100644 --- a/examples/widgets/chart/lv_example_chart_2.c +++ b/examples/widgets/chart/lv_example_chart_2.c @@ -1,131 +1,56 @@ #include "../../lv_examples.h" -//TODO should be a chart feature -#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES && 0 - -static lv_obj_t * chart1; -static lv_chart_series_t * ser1; -static lv_chart_series_t * ser2; - -static void draw_event_cb(lv_event_t * e) -{ - lv_obj_t * obj = lv_event_get_target(e); - - /*Add the faded area before the lines are drawn*/ - 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) { - /*Add a line mask that keeps the area below the line*/ - lv_draw_mask_line_param_t line_mask_param; - lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y, - LV_DRAW_MASK_LINE_SIDE_BOTTOM); - int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL); - - /*Add a fade effect: transparent bottom covering top*/ - lv_coord_t h = lv_obj_get_height(obj); - lv_draw_mask_fade_param_t fade_mask_param; - lv_draw_mask_fade_init(&fade_mask_param, &obj->coords, LV_OPA_COVER, obj->coords.y1 + h / 8, LV_OPA_TRANSP, - obj->coords.y2); - int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL); - - /*Draw a rectangle that will be affected by the mask*/ - lv_draw_rect_dsc_t draw_rect_dsc; - lv_draw_rect_dsc_init(&draw_rect_dsc); - draw_rect_dsc.bg_opa = LV_OPA_20; - draw_rect_dsc.bg_color = dsc->line_dsc->color; - - lv_area_t a; - a.x1 = dsc->p1->x; - a.x2 = dsc->p2->x - 1; - a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y); - a.y2 = obj->coords.y2; - lv_draw_rect(dsc->layer, &draw_rect_dsc, &a); - - /*Remove the masks*/ - lv_draw_mask_free_param(&line_mask_param); - lv_draw_mask_free_param(&fade_mask_param); - lv_draw_mask_remove_id(line_mask_id); - lv_draw_mask_remove_id(fade_mask_id); - } - /*Hook the division lines too*/ - else if(dsc->part == LV_PART_MAIN) { - if(dsc->line_dsc == NULL || dsc->p1 == NULL || dsc->p2 == NULL) return; - - /*Vertical line*/ - if(dsc->p1->x == dsc->p2->x) { - dsc->line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1); - if(dsc->id == 3) { - dsc->line_dsc->width = 2; - dsc->line_dsc->dash_gap = 0; - dsc->line_dsc->dash_width = 0; - } - else { - dsc->line_dsc->width = 1; - dsc->line_dsc->dash_gap = 6; - dsc->line_dsc->dash_width = 6; - } - } - /*Horizontal line*/ - else { - if(dsc->id == 2) { - dsc->line_dsc->width = 2; - dsc->line_dsc->dash_gap = 0; - dsc->line_dsc->dash_width = 0; - } - else { - dsc->line_dsc->width = 2; - dsc->line_dsc->dash_gap = 6; - dsc->line_dsc->dash_width = 6; - } - - if(dsc->id == 1 || dsc->id == 3) { - dsc->line_dsc->color = lv_palette_main(LV_PALETTE_GREEN); - } - else { - dsc->line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1); - } - } - } -} - -static void add_data(lv_timer_t * timer) -{ - LV_UNUSED(timer); - static uint32_t cnt = 0; - lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90)); - - if(cnt % 4 == 0) lv_chart_set_next_value(chart1, ser2, lv_rand(40, 60)); - - cnt++; -} +#if LV_USE_CHART && LV_BUILD_EXAMPLES /** - * Add a faded area effect to the line chart and make some division lines ticker + * Use lv_scale to add ticks to a scrollable chart */ void lv_example_chart_2(void) { - /*Create a chart1*/ - chart1 = lv_chart_create(lv_screen_active()); - lv_obj_set_size(chart1, 200, 150); - lv_obj_center(chart1); - lv_chart_set_type(chart1, LV_CHART_TYPE_LINE); /*Show lines and points too*/ + /*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); - lv_chart_set_div_line_count(chart1, 5, 7); + /*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); - lv_obj_add_event(chart1, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL); - lv_obj_add_flag(chart1, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS); + /*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); - lv_chart_set_update_mode(chart1, LV_CHART_UPDATE_MODE_CIRCULAR); /*Add two data series*/ - ser1 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y); - ser2 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_SECONDARY_Y); + 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 < 10; i++) { - lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90)); - lv_chart_set_next_value(chart1, ser2, lv_rand(30, 70)); + 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_timer_create(add_data, 200, NULL); + lv_chart_refresh(chart); /*Required after direct set*/ } #endif diff --git a/examples/widgets/chart/lv_example_chart_3.c b/examples/widgets/chart/lv_example_chart_3.c index c595cbcb4..ddfe8db3d 100644 --- a/examples/widgets/chart/lv_example_chart_3.c +++ b/examples/widgets/chart/lv_example_chart_3.c @@ -1,85 +1,86 @@ #include "../../lv_examples.h" -#if LV_USE_CHART && LV_BUILD_EXAMPLES && 0 +#if LV_USE_CHART && LV_BUILD_EXAMPLES -//static void draw_event_cb(lv_event_t * e) -//{ -// lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e); -// if(!lv_obj_draw_part_check_type(dsc, &lv_chart_class, LV_CHART_DRAW_PART_TICK_LABEL)) return; -// -// if(dsc->id == LV_CHART_AXIS_PRIMARY_X && dsc->text) { -// const char * month[] = {"Jan", "Febr", "March", "Apr", "May", "Jun", "July", "Aug", "Sept", "Oct", "Nov", "Dec"}; -// lv_snprintf(dsc->text, dsc->text_length, "%s", month[dsc->value]); -// } -//} + +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); + } +} /** - * Add ticks and labels to the axis and demonstrate scrolling + * Show the value of the pressed points */ void lv_example_chart_3(void) { - lv_obj_t * main_cont = lv_obj_create(lv_screen_active()); - lv_obj_set_size(main_cont, 200, 150); - - lv_obj_t * wrapper = lv_obj_create(main_cont); - lv_obj_remove_style_all(wrapper); - lv_obj_set_size(wrapper, 800, lv_pct(100)); - lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN); - /*Create a chart*/ - 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); + lv_obj_t * chart; + chart = lv_chart_create(lv_screen_active()); + lv_obj_set_size(chart, 200, 150); + lv_obj_center(chart); - 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, 50, 0); + lv_obj_add_event(chart, event_cb, LV_EVENT_ALL, NULL); + lv_obj_refresh_ext_draw_size(chart); - 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); + /*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_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_SECONDARY_Y); - - /*Set the next points on 'ser1'*/ - lv_chart_set_next_value(chart, ser1, 31); - lv_chart_set_next_value(chart, ser1, 66); - lv_chart_set_next_value(chart, ser1, 10); - lv_chart_set_next_value(chart, ser1, 89); - lv_chart_set_next_value(chart, ser1, 63); - lv_chart_set_next_value(chart, ser1, 56); - lv_chart_set_next_value(chart, ser1, 32); - lv_chart_set_next_value(chart, ser1, 35); - lv_chart_set_next_value(chart, ser1, 57); - lv_chart_set_next_value(chart, ser1, 85); - lv_chart_set_next_value(chart, ser1, 22); - lv_chart_set_next_value(chart, ser1, 58); - - lv_coord_t * ser2_array = lv_chart_get_y_array(chart, ser2); - /*Directly set points on 'ser2'*/ - ser2_array[0] = 92; - ser2_array[1] = 71; - ser2_array[2] = 61; - ser2_array[3] = 15; - ser2_array[4] = 21; - ser2_array[5] = 35; - ser2_array[6] = 35; - ser2_array[7] = 58; - ser2_array[8] = 31; - ser2_array[9] = 53; - ser2_array[10] = 33; - ser2_array[11] = 73; - - lv_chart_refresh(chart); /*Required after direct set*/ + 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 diff --git a/examples/widgets/chart/lv_example_chart_4.c b/examples/widgets/chart/lv_example_chart_4.c index 796e523af..585fe52bf 100644 --- a/examples/widgets/chart/lv_example_chart_4.c +++ b/examples/widgets/chart/lv_example_chart_4.c @@ -1,85 +1,45 @@ #include "../../lv_examples.h" -#if LV_USE_CHART && LV_BUILD_EXAMPLES +#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES -static void event_cb(lv_event_t * e) +static void draw_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); + lv_draw_task_t * draw_task = lv_event_get_draw_task(e); + lv_draw_dsc_base_t * base_dsc = draw_task->draw_dsc; - 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; + 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_LOG_USER("Selected point %d", (int)id); + 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]; - 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); + 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); } } + /** - * Show the value of the pressed points + * Recolor the bars of a chart based on their value */ void lv_example_chart_4(void) { - /*Create a chart*/ - lv_obj_t * chart; - chart = lv_chart_create(lv_screen_active()); - lv_obj_set_size(chart, 200, 150); + /*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_obj_add_event(chart, event_cb, LV_EVENT_ALL, NULL); - lv_obj_refresh_ext_draw_size(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); - /*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)); + for(i = 0; i < 24; i++) { + lv_chart_set_next_value(chart, ser, lv_rand(10, 90)); } } diff --git a/examples/widgets/chart/lv_example_chart_5.c b/examples/widgets/chart/lv_example_chart_5.c index 85a03dc36..a54042ac8 100644 --- a/examples/widgets/chart/lv_example_chart_5.c +++ b/examples/widgets/chart/lv_example_chart_5.c @@ -1,99 +1,146 @@ #include "../../lv_examples.h" -#if LV_USE_CHART && LV_USE_SLIDER && LV_BUILD_EXAMPLES && 0 -static lv_obj_t * chart; -/* Source: https://github.com/ankur219/ECG-Arrhythmia-classification/blob/642230149583adfae1e4bd26c6f0e1fd8af2be0e/sample.csv*/ -static const lv_coord_t ecg_sample[] = { - -2, 2, 0, -15, -39, -63, -71, -68, -67, -69, -84, -95, -104, -107, -108, -107, -107, -107, -107, -114, -118, -117, - -112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10, 4, 7, 1, -3, 0, 14, 24, 30, 25, 19, - 13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25, 14, 15, 19, 28, 31, 26, 23, 25, 31, - 39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33, 19, -1, -27, -55, -67, -72, -71, -63, - -49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288, 274, 255, 212, 173, 143, 117, 82, 39, - -13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -123, -123, -129, -139, -148, -153, - -159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -473, -517, -556, -592, -612, -620, - -620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -222, -167, -114, -70, -47, -28, -4, 12, - 38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89, 88, 91, 96, 97, 91, 83, 78, 82, 88, 95, - 96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115, 110, 96, 85, 73, 64, 69, 76, 79, - 78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67, 73, 79, 74, 63, 57, 56, 58, 61, 55, - 48, 45, 46, 55, 62, 55, 49, 43, 50, 59, 63, 57, 40, 31, 23, 25, 27, 31, 35, 34, 30, 36, 34, 42, 38, 36, 40, 46, 50, - 47, 32, 30, 32, 52, 67, 73, 71, 63, 54, 53, 45, 41, 28, 13, 3, 1, 4, 4, -8, -23, -32, -31, -19, -5, 3, 9, 13, 19, - 24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -3, -11, -20, -47, -100, -194, -236, - -212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27, 19, 17, 21, 20, 19, 19, 22, 36, 40, - 35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -5, -10, -19, -32, -42, -55, -60, - -68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -50, -45, -35, -20, -3, 12, 20, 25, - 26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9, 9, -3, -1, -18, -50, -108, -190, - -272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60, 58, 103, 129, 139, 155, 170, 173, - 178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226, 224, 232, 233, 232, 224, 219, 219, - 223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283, 271, 263, 252, 243, 226, 210, 197, - 186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7, -11, -14, -18, -29, -37, -44, -50, - -58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -52, -59, -69, -76, -76, -69, -67, - -74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -17, -13, -10, -11, -13, -20, -20, - -12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21, 20, 18, 19, 19, 19, 16, 15, 13, 14, - 9, 3, -5, -9, -5, -3, -2, -3, -3, 2, 8, 9, 9, 5, 6, 8, 8, 7, 4, 3, 4, 5, 3, 5, 5, 13, 13, 12, 10, 10, 15, 22, 17, - 14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -18, -16, -9, -4, -5, -10, -9, -8, - -3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -33, -19, 0, 17, 24, 9, -17, -47, - -63, -67, -59, -52, -51, -50, -49, -42, -26, -21, -15, -20, -23, -22, -19, -12, -8, 5, 18, 27, 32, 26, 25, 26, 22, - 23, 17, 14, 17, 21, 25, 2, -45, -121, -196, -226, -200, -118, -9, 73, 126, 131, 114, 87, 60, 42, 29, 26, 34, 35, 34, - 25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -26, -25, -21, -15, -10, -13, -13, - -19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119, -124, -129, -132, -146, -146, -138, - -124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2, 4, 0, 1, 4, 3, 10, 11, 10, 2, -4, - 0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7, 12, 17, 11, 0, -6, -9, -8, -7, -5, - -6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -60, -67, -65, -54, -35, -11, 30, - 84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239, 197, 163, 136, 109, 77, 34, -18, -50, - -66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -171, -169, -174, -175, -178, -191, - -202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -565, -596, -619, -623, -623, -614, - -599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96, -57, -29, -8, 10, 31, 45, 60, 65, - 70, 74, 76, 79, 82, 79, 75, 62, - }; +#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES -static void slider_x_event_cb(lv_event_t * e) -{ - lv_obj_t * obj = lv_event_get_target(e); - int32_t v = lv_slider_get_value(obj); - // lv_chart_set_zoom_x(chart, v); -} - -static void slider_y_event_cb(lv_event_t * e) -{ - lv_obj_t * obj = lv_event_get_target(e); - int32_t v = lv_slider_get_value(obj); - // lv_chart_set_zoom_y(chart, v); -} +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); /** - * Display 1000 data points with zooming and scrolling. - * See how the chart changes drawing mode (draw only vertical lines) when - * the points get too crowded. + * Add a faded area effect to the line chart and make some division lines ticker */ void lv_example_chart_5(void) { /*Create a chart*/ - chart = lv_chart_create(lv_screen_active()); + 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_align(chart, LV_ALIGN_CENTER, -30, -30); - lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -1000, 1000); + lv_obj_set_style_pad_all(chart, 0, 0); + lv_obj_set_style_radius(chart, 0, 0); + lv_obj_center(chart); - /*Do not display points on the data*/ - lv_obj_set_style_size(chart, 0, 0, LV_PART_INDICATOR); + 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 pcnt = sizeof(ecg_sample) / sizeof(ecg_sample[0]); - lv_chart_set_point_count(chart, pcnt); - lv_chart_set_ext_y_array(chart, ser, (lv_coord_t *)ecg_sample); + uint32_t i; + for(i = 0; i < 10; i++) { + lv_chart_set_next_value(chart, ser, lv_rand(10, 80)); + } +} - lv_obj_t * slider; - slider = lv_slider_create(lv_screen_active()); - lv_slider_set_range(slider, LV_SCALE_NONE, LV_SCALE_NONE * 10); - lv_obj_add_event(slider, slider_x_event_cb, LV_EVENT_VALUE_CHANGED, NULL); - lv_obj_set_size(slider, 200, 10); - lv_obj_align_to(slider, chart, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); +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; - slider = lv_slider_create(lv_screen_active()); - lv_slider_set_range(slider, LV_SCALE_NONE, LV_SCALE_NONE * 10); - lv_obj_add_event(slider, slider_y_event_cb, LV_EVENT_VALUE_CHANGED, NULL); - lv_obj_set_size(slider, 10, 150); - lv_obj_align_to(slider, chart, LV_ALIGN_OUT_RIGHT_MID, 20, 0); + 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 diff --git a/examples/widgets/chart/lv_example_chart_8.c b/examples/widgets/chart/lv_example_chart_8.c index b998046c5..8e01373d9 100644 --- a/examples/widgets/chart/lv_example_chart_8.c +++ b/examples/widgets/chart/lv_example_chart_8.c @@ -1,132 +1,47 @@ #include "../../lv_examples.h" -//TODO Should be a chart feature -#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES && 0 +#if LV_USE_CHART && LV_DRAW_SW_COMPLEX && LV_BUILD_EXAMPLES -/* A struct is used to keep track of the series list because later we need to draw to the series in the reverse order to which they were initialised. */ -typedef struct { - lv_obj_t * obj; - lv_chart_series_t * series_list[3]; -} stacked_area_chart_t; -static stacked_area_chart_t stacked_area_chart; - -/** - * Callback which draws the blocks of colour under the lines - **/ -static void draw_event_cb(lv_event_t * e) +static void add_data(lv_timer_t * t) { - lv_obj_t * obj = lv_event_get_target(e); + lv_obj_t * chart = t->user_data; + lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL); - /*Add the faded area before the lines are drawn*/ - lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e); - if(dsc->part == LV_PART_ITEMS) { - if(!dsc->p1 || !dsc->p2) - return; + lv_chart_set_next_value(chart, ser, lv_rand(10, 90)); - /*Add a line mask that keeps the area below the line*/ - lv_draw_mask_line_param_t line_mask_param; - lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y, - LV_DRAW_MASK_LINE_SIDE_BOTTOM); - int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL); + uint16_t p = lv_chart_get_point_count(chart); + uint16_t s = lv_chart_get_x_start_point(chart, ser); + lv_coord_t * a = lv_chart_get_y_array(chart, ser); - /*Draw a rectangle that will be affected by the mask*/ - lv_draw_rect_dsc_t draw_rect_dsc; - lv_draw_rect_dsc_init(&draw_rect_dsc); - draw_rect_dsc.bg_opa = LV_OPA_COVER; - draw_rect_dsc.bg_color = dsc->line_dsc->color; + 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_area_t a; - a.x1 = dsc->p1->x; - a.x2 = dsc->p2->x; - a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y); - a.y2 = obj->coords.y2 - - 13; /* -13 cuts off where the rectangle draws over the chart margin. Without this an area of 0 doesn't look like 0 */ - lv_draw_rect(dsc->layer, &draw_rect_dsc, &a); - - /*Remove the mask*/ - lv_draw_mask_free_param(&line_mask_param); - lv_draw_mask_remove_id(line_mask_id); - } + lv_chart_refresh(chart); } /** - * Helper function to round a fixed point number - **/ -static int32_t round_fixed_point(int32_t n, int8_t shift) -{ - /* Create a bitmask to isolates the decimal part of the fixed point number */ - int32_t mask = 1; - for(int32_t bit_pos = 0; bit_pos < shift; bit_pos++) { - mask = (mask << 1) + 1; - } - - int32_t decimal_part = n & mask; - - /* Get 0.5 as fixed point */ - int32_t rounding_boundary = 1 << (shift - 1); - - /* Return either the integer part of n or the integer part + 1 */ - return (decimal_part < rounding_boundary) ? (n & ~mask) : ((n >> shift) + 1) << shift; -} - -/** - * Stacked area chart + * Circular line chart with gap */ void lv_example_chart_8(void) { /*Create a stacked_area_chart.obj*/ - stacked_area_chart.obj = lv_chart_create(lv_screen_active()); - lv_obj_set_size(stacked_area_chart.obj, 200, 150); - lv_obj_center(stacked_area_chart.obj); - lv_chart_set_type(stacked_area_chart.obj, LV_CHART_TYPE_LINE); - lv_chart_set_div_line_count(stacked_area_chart.obj, 5, 7); - lv_obj_add_event(stacked_area_chart.obj, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); + 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); - /* Set range to 0 to 100 for percentages. Draw ticks */ - lv_chart_set_range(stacked_area_chart.obj, LV_CHART_AXIS_PRIMARY_Y, 0, 100); - lv_chart_set_axis_tick(stacked_area_chart.obj, LV_CHART_AXIS_PRIMARY_Y, 3, 0, 5, 1, true, 30); - - /*Set point size to 0 so the lines are smooth */ - lv_obj_set_style_size(stacked_area_chart.obj, 0, 0, LV_PART_INDICATOR); - - /*Add some data series*/ - stacked_area_chart.series_list[0] = lv_chart_add_series(stacked_area_chart.obj, lv_palette_main(LV_PALETTE_RED), - LV_CHART_AXIS_PRIMARY_Y); - stacked_area_chart.series_list[1] = lv_chart_add_series(stacked_area_chart.obj, lv_palette_main(LV_PALETTE_BLUE), - LV_CHART_AXIS_PRIMARY_Y); - stacked_area_chart.series_list[2] = lv_chart_add_series(stacked_area_chart.obj, lv_palette_main(LV_PALETTE_GREEN), - LV_CHART_AXIS_PRIMARY_Y); - - for(int point = 0; point < 10; point++) { - /* Make some random data */ - uint32_t vals[3] = {lv_rand(10, 20), lv_rand(20, 30), lv_rand(20, 30)}; - - int8_t fixed_point_shift = 5; - uint32_t total = vals[0] + vals[1] + vals[2]; - uint32_t draw_heights[3]; - uint32_t int_sum = 0; - uint32_t decimal_sum = 0; - - /* Fixed point cascade rounding ensures percentages add to 100 */ - for(int32_t series_index = 0; series_index < 3; series_index++) { - decimal_sum += (((vals[series_index] * 100) << fixed_point_shift) / total); - int_sum += (vals[series_index] * 100) / total; - - int32_t modifier = (round_fixed_point(decimal_sum, fixed_point_shift) >> fixed_point_shift) - int_sum; - - /* The draw heights are equal to the percentage of the total each value is + the cumulative sum of the previous percentages. - The accumulation is how the values get "stacked" */ - draw_heights[series_index] = int_sum + modifier; - - /* Draw to the series in the reverse order to which they were initialised. - Without this the higher values will draw on top of the lower ones. - This is because the Z-height of a series matches the order it was initialised */ - lv_chart_set_next_value(stacked_area_chart.obj, stacked_area_chart.series_list[3 - series_index - 1], - draw_heights[series_index]); - } + 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_chart_refresh(stacked_area_chart.obj); + lv_timer_create(add_data, 300, chart); + } #endif diff --git a/examples/widgets/chart/lv_example_chart_9.c b/examples/widgets/chart/lv_example_chart_9.c deleted file mode 100644 index c307f1f2d..000000000 --- a/examples/widgets/chart/lv_example_chart_9.c +++ /dev/null @@ -1,46 +0,0 @@ -#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 = t->user_data; - 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); - lv_coord_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_9(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_size(chart, 200, 150); - lv_obj_center(chart); - - lv_chart_set_point_count(chart, 30); - 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 < 30; i++) { - lv_chart_set_next_value(chart, ser, lv_rand(10, 90)); - } - - lv_timer_create(add_data, 300, chart); - -} - -#endif diff --git a/examples/widgets/lv_example_widgets.h b/examples/widgets/lv_example_widgets.h index 5fa560de5..8baf55e84 100644 --- a/examples/widgets/lv_example_widgets.h +++ b/examples/widgets/lv_example_widgets.h @@ -56,14 +56,13 @@ void lv_example_canvas_6(void); void lv_example_canvas_7(void); void lv_example_chart_1(void); -//void lv_example_chart_2(void); -//void lv_example_chart_3(void); +void lv_example_chart_2(void); +void lv_example_chart_3(void); void lv_example_chart_4(void); -//void lv_example_chart_5(void); +void lv_example_chart_5(void); void lv_example_chart_6(void); void lv_example_chart_7(void); -//void lv_example_chart_8(void); -void lv_example_chart_9(void); +void lv_example_chart_8(void); void lv_example_checkbox_1(void); void lv_example_checkbox_2(void); diff --git a/src/draw/lv_draw.c b/src/draw/lv_draw.c index 326c4c944..0e39f9339 100644 --- a/src/draw/lv_draw.c +++ b/src/draw/lv_draw.c @@ -94,15 +94,6 @@ void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t) lv_draw_global_info_t * info = &_draw_info; - /*Let the draw units set their preference score*/ - t->preference_score = 100; - t->preferred_draw_unit_id = 0; - lv_draw_unit_t * u = info->unit_head; - while(u) { - if(u->evaluate_cb) u->evaluate_cb(u, t); - u = u->next; - } - /*Send LV_EVENT_DRAW_TASK_ADDED and dispatch only on the "main" draw_task *and not on the draw tasks added in the event. *Sending LV_EVENT_DRAW_TASK_ADDED events might cause recursive event sends @@ -113,9 +104,29 @@ void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t) if(base_dsc->obj && lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) { lv_obj_send_event(base_dsc->obj, LV_EVENT_DRAW_TASK_ADDED, t); } + + /*Let the draw units set their preference score*/ + t->preference_score = 100; + t->preferred_draw_unit_id = 0; + lv_draw_unit_t * u = info->unit_head; + while(u) { + if(u->evaluate_cb) u->evaluate_cb(u, t); + u = u->next; + } + lv_draw_dispatch(); info->task_running = false; } + else { + /*Let the draw units set their preference score*/ + t->preference_score = 100; + t->preferred_draw_unit_id = 0; + lv_draw_unit_t * u = info->unit_head; + while(u) { + if(u->evaluate_cb) u->evaluate_cb(u, t); + u = u->next; + } + } } void lv_draw_dispatch(void) diff --git a/src/draw/sw/lv_draw_sw_line.c b/src/draw/sw/lv_draw_sw_line.c index 0b8407224..fc8de43e8 100644 --- a/src/draw/sw/lv_draw_sw_line.c +++ b/src/draw/sw/lv_draw_sw_line.c @@ -229,6 +229,9 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(lv_draw_unit_t * draw_unit, cons if(dash_cnt > dsc->dash_width) { blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_TRANSP; } + else { + blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_FULL_COVER; + } if(dash_cnt >= dsc->dash_gap + dsc->dash_width) { dash_cnt = 0; diff --git a/src/widgets/chart/lv_chart.c b/src/widgets/chart/lv_chart.c index f96af0c60..c36dde22a 100644 --- a/src/widgets/chart/lv_chart.c +++ b/src/widgets/chart/lv_chart.c @@ -200,9 +200,9 @@ uint32_t lv_chart_get_point_count(const lv_obj_t * obj) uint32_t lv_chart_get_x_start_point(const lv_obj_t * obj, lv_chart_series_t * ser) { LV_ASSERT_NULL(ser); - lv_chart_t * chart = (lv_chart_t *)obj; + LV_UNUSED(obj); - return chart->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0; + return ser->start_point; } 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) @@ -256,7 +256,7 @@ void lv_chart_get_point_pos_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint3 p_out->x += lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width; p_out->x -= lv_obj_get_scroll_left(obj); - uint32_t start_point = lv_chart_get_x_start_point(obj, ser); + uint32_t start_point = chart->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0; id = ((int32_t)start_point + id) % chart->point_cnt; int32_t temp_y = 0; temp_y = (int32_t)((int32_t)ser->y_points[id] - chart->ymin[ser->y_axis_sec]) * h; @@ -763,6 +763,7 @@ static void draw_div_lines(lv_obj_t * obj, lv_layer_t * layer) line_dsc.p1.y = (int32_t)((int32_t)h * i) / (chart->hdiv_cnt - 1); line_dsc.p1.y += y_ofs; line_dsc.p2.y = line_dsc.p1.y; + line_dsc.base.id1 = i; lv_draw_line(layer, &line_dsc); } @@ -783,6 +784,7 @@ static void draw_div_lines(lv_obj_t * obj, lv_layer_t * layer) line_dsc.p1.x = (int32_t)((int32_t)w * i) / (chart->vdiv_cnt - 1); line_dsc.p1.x += x_ofs; line_dsc.p2.x = line_dsc.p1.x; + line_dsc.base.id1 = i; lv_draw_line(layer, &line_dsc); } @@ -842,7 +844,7 @@ static void draw_series_line(lv_obj_t * obj, lv_layer_t * layer) line_dsc.base.id2 = 0; point_dsc_default.base.id2 = 0; - lv_coord_t start_point = lv_chart_get_x_start_point(obj, ser); + lv_coord_t start_point = chart->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0; line_dsc.p1.x = x_ofs; line_dsc.p2.x = x_ofs; @@ -980,7 +982,7 @@ static void draw_series_scatter(lv_obj_t * obj, lv_layer_t * layer) line_dsc.color = ser->color; point_dsc_default.bg_color = ser->color; - lv_coord_t start_point = lv_chart_get_x_start_point(obj, ser); + lv_coord_t start_point = chart->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0; line_dsc.p1.x = x_ofs; line_dsc.p2.x = x_ofs; @@ -1107,7 +1109,7 @@ static void draw_series_bar(lv_obj_t * obj, lv_layer_t * layer) _LV_LL_READ(&chart->series_ll, ser) { if(ser->hidden) continue; - lv_coord_t start_point = lv_chart_get_x_start_point(obj, ser); + lv_coord_t start_point = chart->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0; col_a.x1 = x_act; col_a.x2 = col_a.x1 + col_w - 1; diff --git a/src/widgets/scale/lv_scale.c b/src/widgets/scale/lv_scale.c index 08731c51d..e872f2c1d 100644 --- a/src/widgets/scale/lv_scale.c +++ b/src/widgets/scale/lv_scale.c @@ -388,7 +388,7 @@ static void scale_draw_indicator(lv_obj_t * obj, lv_event_t * event) uint32_t total_tick_count = scale->total_tick_count; uint32_t tick_idx = 0; uint32_t major_tick_idx = 0; - for(tick_idx = 0; tick_idx <= total_tick_count; tick_idx++) { + for(tick_idx = 0; tick_idx < total_tick_count; tick_idx++) { /* A major tick is the one which has a label in it */ bool is_major_tick = false; if(tick_idx % scale->major_tick_every == 0) is_major_tick = true; @@ -477,7 +477,7 @@ static void scale_draw_indicator(lv_obj_t * obj, lv_event_t * event) uint32_t label_gap = 15U; /* TODO: Add to style properties */ uint32_t tick_idx = 0; uint32_t major_tick_idx = 0; - for(tick_idx = 0; tick_idx <= scale->total_tick_count; tick_idx++) { + for(tick_idx = 0; tick_idx < scale->total_tick_count; tick_idx++) { /* A major tick is the one which has a label in it */ bool is_major_tick = false; if(tick_idx % scale->major_tick_every == 0) is_major_tick = true; @@ -844,7 +844,8 @@ static void scale_get_tick_points(lv_obj_t * obj, const uint32_t tick_idx, bool /* Increment the tick offset depending of its index */ else if(0 != tick_idx) { const lv_coord_t scale_total_height = lv_obj_get_height(obj) - (pad_top + pad_bottom + tick_pad_top + tick_pad_bottom); - lv_coord_t offset = ((lv_coord_t) tick_idx * (lv_coord_t) scale_total_height) / (lv_coord_t) scale->total_tick_count; + lv_coord_t offset = ((lv_coord_t) tick_idx * (lv_coord_t) scale_total_height) / (lv_coord_t)( + scale->total_tick_count - 1); vertical_position -= offset; } else { /* Nothing to do */ } @@ -864,7 +865,8 @@ static void scale_get_tick_points(lv_obj_t * obj, const uint32_t tick_idx, bool /* Increment the tick offset depending of its index */ else if(0U != tick_idx) { const lv_coord_t scale_total_width = lv_obj_get_width(obj) - (pad_right + pad_left + tick_pad_right + tick_pad_left); - lv_coord_t offset = ((lv_coord_t) tick_idx * (lv_coord_t) scale_total_width) / (lv_coord_t) scale->total_tick_count; + lv_coord_t offset = ((lv_coord_t) tick_idx * (lv_coord_t) scale_total_width) / (lv_coord_t)( + scale->total_tick_count - 1); horizontal_position += offset; } else { /* Nothing to do */ } @@ -1139,7 +1141,7 @@ static void scale_find_section_tick_idx(lv_obj_t * obj) /* Section handling */ uint32_t tick_idx = 0; - for(tick_idx = 0; tick_idx <= total_tick_count; tick_idx++) { + for(tick_idx = 0; tick_idx < total_tick_count; tick_idx++) { bool is_major_tick = false; if(tick_idx % scale->major_tick_every == 0) is_major_tick = true; diff --git a/tests/ref_imgs/line_1.png b/tests/ref_imgs/line_1.png index 4b3be8ae9a2841679acc141d767c26490de11033..b4510ab1b409c706f972f6eaa6167025e9a66202 100644 GIT binary patch literal 4385 zcmeHL`#;nBAOCEoku)Nb3_0amx)9|yPC`z|Ia@o+v7x0%gos9_({U7+gEkwG0#n^2*QNd!dUMf5~ z6z>`s_uCHI8#eSmINr%p*opk%8fl98<%P+NjEoM3o8qPMxgw`T$ww6L zMDGqeJG;u(8F61rxlT2M4;Q%?hZFplEyj6+sS87wZF6&T-;^EZEeaDQ{r6ZAa}3$L z$opF+%kqMgEvrt53_xhy`0>Dr=Ihpn%7f-4HIwLI$-An^q-X<64_^{&O2FbpwY9g? zof6x-85HSow%bEO*{xf*aO~-4NaOy;ap9q%L(<{i!+u3zz{zLLj@9avXGU!R`?n{cXEQj}J zT5VCQl~3L5`?Dz9bBd+erluypXcw{fE1vGCj}m3gKyd2ZS3V(xq|orJ+6WB zEuP6~+NMw$%55l+83?0@uS zaZYx_A-bHL5{b5SZT8ODDvvj-KS!~~F%A#B$*8EP$ab9527J>G*vB3&S4VMVSc zK9U#J_fW^&ugLM#-!hv06OfH}~- z;!P>VHwSIPZI0yiF;eG8r3~j0S%2?8;pUq+O9r1#!W{pq4Bhi8s>Xc`ZAsr9H_~_8V*CFJQ4%Gvd|zF7a8@ z7*g5PFJ{kka&kOcZoX9K)V~ua7%li@=~B(RqMZ7N(QbhhS(}4Kc@}yzcO?MOLgW&3 z%sf9#$|)q5i057bchB>!M&Ca<>$W8SS%$isrCXBW(oMb4bDzj4C>RZr^!_7!u21BI z926uXa6ZGs!x^iMSksN4%#YkuTe>&9i{zfCh2PZu02V3E)GhIsf23#?nsWC?@cJfe zWqzaB#hqrJU-gq%c`h0@cQ5j-?y*=Mt_vKw6|TWsJGnt55=mRaUS7FQP?xWxVp~Cp z9X)z9c^DA_UULApCZulcdUhU}qL;1tFT|BhkA>{C%rn{m_9CGVd&?cUw{SlJFfHe_g&Ba<`v zR>SktaR_bjdin&Ta26% zHaNyG`(v3%bq@UY?b|bwf$_#8%xi0-|E+*&3}vcmaA6vEJ7~2Ny%epn5p^64u3_Oz zavwn8VC~1C=2!sZ0Lfk~8K}v#B_=47t%~e98XoSH2fSglZk@#=w8#g}J{}ep*3i)4 z_tT2~+l_x;p~ksg)feSIOif4V*)HDb%kvW}Y|B|9*(L&K$Z^kVI@>K!^`$+b8 zSXPEW%m4m_$H#YFY{FQAlsh{+i(7>Bvy$#ZL}ji~aJDIpMq8K>#{se~>2R5V9n)PT z7`XuDK||nvJONTAXaiLPtf}2v{$K-KrrJOb69;Fj^P&gqlBZcZG-}}OJ9mU5BYW~} zpDs!P`AXB!Y5h00xw^VKJ5K-!VT##r@EZX9^f{A&-1}M{4G5eLLN6fK94`QHH$UhT zgV!tNR%vxpq82*nezrl61anQmdBk%|(=U2dm!9iz-nF&0Db4ha{KCTOIH8|VDk%A} z?_rcR0EC3I6Z}BVu^1IQe^Ph*3LB=4A(xp1hQ$eeIyOubs%o1KzKYFi7O%1(gTo*q zf))3e+>%>TQj$JSbv5OV*}J$rIX#Y3S~D{%YYDW>;+9gc?34YXh2a1vD%KWITiJ>% zQ3F4TroiY*egvQjY?b^Jy@EXR8+(qOI(3Rd=?A>ia`n3>CMIeo>-rvp153EPwBT#A za{h`r-X2u$J6<$H$>0fodLROqwLt(~s|s~JrlM!};!o~AphVl@;Df%tzMw6R2UVN7 zhdDoE<$zkdtumz#V&il9v*UsLuFr!m$))aqRf<<8zYQ5kq5G1z6%9%Z`dfqW zsYw%WD*~;lb)SpAI4fNY?k#mgn|1?^o&C8|P)p@QR}etNB)EpiN;yhho1j=;YHIRP zO2)}YDQ^^mbt$SnDoZ}33kMDy5Dz{b1mW{Q_qe2m4;eZCE%A*AT>gJd>Y8%vfo{6I z2M@aD!V`b6sNaqE0m%Y4Uk2i&@AL9HT=pi*(1FD&q|@JnTgT{HcegcoACNC-i2}`; z32@SN&|kCDmdShbyH4_4vXBr07l_5q(BKfP^&={J zkYEk|*OBuO#+O7^w}F_OxRse;C5~NnGBveMzCO9JwY62lwl*MnErbDhA(PfWwIGw9 zNHFMkus&@YRTa|O%!QzOgdT(eXdpEm<%LhV^82Fi6nuBV_d@vI3%<9*|NDucfRP;v WHX0>xK7dajkdLR|-f|C8`u_kq6NFFz literal 4384 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