[Howto] [v9.1.0] How can the chart with the faded area line display the value of the pressed points?

Description

What MCU/Processor/Board and compiler are you using?

Windows

What LVGL version are you using?

v9.1.0

What do you want to achieve?

display the value of the pressed point for the faded line chart.

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