lvgl/lvgl

The chart with the faded area line cannot display the value pop-up when pressing a point?

Closed this issue · 5 comments

LVGL version

v9.1.1

What happened?

image

When using lv_example_chart_3,
it can display pop-up values when a point is pressed,
https://github.com/lvgl/lvgl/blob/master/examples/widgets/chart/lv_example_chart_3.c

And when using lv_example_chart_5,
it can create a faded area line.
https://github.com/lvgl/lvgl/blob/master/examples/widgets/chart/lv_example_chart_5.c

However, when combining them together,
the graph with the faded area line fails to display the values correctly when touched.

I wish to create the chart with the faded area line
with the value pop-up when pressing a point.

How to solve the issue ?

How to reproduce?

static void pupup_value_pressed_point(lv_event_t * e);
static void faded_line_chart_designed(lv_event_t * e);

void lv_example_chart_3_with_5(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);

  /* popup value */
  lv_obj_add_event_cb(chart, pupup_value_pressed_point, LV_EVENT_ALL, NULL);

  /* gradient line chart */
  lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
  lv_obj_add_event_cb(chart, faded_line_chart_designed, LV_EVENT_DRAW_TASK_ADDED, 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));
  }
}


void pupup_value_pressed_point(lv_event_t * e)
{
  lv_event_code_t code = lv_event_get_code(e);
  lv_obj_t * chart = (lv_obj_t *) 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 = (int32_t *)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();
      draw_rect_dsc.bg_image_symbol_font = &prasanmit_20;

      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);
  }
}

void faded_line_chart_designed(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_dsc_base_t *)draw_task->draw_dsc;

  if(base_dsc->part == LV_PART_ITEMS && draw_task->type == LV_DRAW_TASK_TYPE_LINE) {
    lv_obj_t * obj = (lv_obj_t *)lv_event_get_target(e);

    lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
    lv_draw_dsc_base_t * base_dsc = (lv_draw_dsc_base_t *)draw_task->draw_dsc;

    const lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
    for(int i = 0; i < base_dsc->id1; i++) {
      ser = lv_chart_get_series_next(obj, ser);
    }
    if(ser == NULL) return;

    /*Draw a triangle below the line witch some opacity gradient*/
    lv_draw_line_dsc_t * draw_line_dsc = (lv_draw_line_dsc_t *)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;

    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) - obj->coords.y1) * 255 / full_h;
    int32_t fract_lower = (int32_t)(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 = (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)obj->coords.y2;
    lv_draw_rect(base_dsc->layer, &rect_dsc, &rect_area);
  }
}

Most probably the issue is that buf is local and if multiple draw_tasks are executed in the event LVGL adds them to a list, and when the rectangle will be drawn later, buf will be already lost.

I suggest using a rectangle drawing followed by a label drawing and set draw_label_dsc->text_local = 1 to make LVGL store a copy of the buffer.

(lv_example_chart_3 should be update too. )

@kisvegabor

image

Thank you very much.
It's OK, now!

Great! May I ask if you have time to update lv_example_chart_3()?

We need some feedback on this issue.

Now we mark this as "stale" because there was no activity here for 14 days.

Remove the "stale" label or comment else this will be closed in 7 days.

As there was no activity here for a while we close this issue. But don't worry, the conversation is still here and you can get back to it at any time.

So feel free to comment if you have remarks or ideas on this topic.