Chart tick label text for fixed point data

Description

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

Raspberry Pi 4 with Linux Frame Buffer

What LVGL version are you using?

v8.0

What do you want to achieve?

I am trying to display sensor data stored as integers representing a fixed point value (integers between 0 and 1400 representing sensor values from 0.00 to 14.00). I can display this data easily with the chart widget however I want the text on the tick labels to match the true fixed point value not the integer value.

What have you tried so far?

My current solution is modifying the line in lv_chart.c that sets the label text from

lv_snprintf(dsc.text, sizeof(dsc.text), "%d", tick_value);

to

uint8_t scale_factor = 100;
lv_snprintf(dsc.text, sizeof(dsc.text), "%d.%d", tick_value/scale_factor, tick_value%scale_factor);

This method works but it feels like a hack and I would prefer not to branch from the source widgets. Is there a “correct” way to achieve this?

The other two alternatives I have thought of are:

  1. Disable the tick labels and create them from scratch manually.
  2. Use an empty secondary axis to create the labels.

Code to reproduce

    lv_obj_t *chart;
    lv_obj_t *series_ph;

    //Create chart
    chart = lv_chart_create(lv_scr_act());
    lv_chart_set_type(chart, LV_CHART_TYPE_LINE);
    lv_obj_set_size(chart, 200, 200);
    lv_obj_center(chart);

    //Add data
    series_ph = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_CIRCULAR);
    lv_chart_set_point_count(chart, 50);
    lv_chart_set_all_value(chart, series_ph, 700);

    //Setup primary y axis
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1400);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 8, 2, true, 50);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 10, 5, 3, 5, true, 20);

In v8 you should be able to use LV_EVENT_DRAW_PART_BEGIN for this purpose. As you can see in the implementation here, you have access to the original value in dsc.value and you can store the resulting format in dsc.text.

Something like this should work (but I have not tested it):

void chart_event(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_DRAW_PART_BEGIN) {
        lv_obj_draw_part_dsc_t * dsc = lv_event_get_param(e);
        if(dsc->part == LV_PART_TICKS) {
            /* customize as you wish */
            lv_snprintf(dsc->text, sizeof(dsc->text), "%d", dsc->value);
        }
    }
}

This worked perfectly. Thanks for helping!