Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
TridentTD opened this issue May 1, 2024 · 4 comments
Labels

Comments

@TridentTD
Copy link
Contributor

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);
  }
}
@kisvegabor
Copy link
Member

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. )

@TridentTD
Copy link
Contributor Author

@kisvegabor

image

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

@kisvegabor
Copy link
Member

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

@lvgl-bot
Copy link

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.

@lvgl-bot lvgl-bot added the stale label May 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants