Canvas
A picture the size of the widget that your own code draws on: points, lines, shapes, text, a graph
nothing else draws. It is LVGL's lv_canvas. Its pixels are a buffer of its own, taken
when its screen is built - from PSRAM where the board has it switched on, otherwise from the chip's
own RAM - and freed when the screen is deleted. The designer gives it the colour it starts as; what is
drawn on it after that is your code's.
| Setting | Default | What it does |
|---|---|---|
| Pixels | Colour - 2 bytes a pixel | What each pixel holds. Colour and transparency is 4 bytes a pixel (3 on LVGL 8 with a 16-bit display), and wherever nothing is drawn what is behind the canvas shows through. |
| Starts as | white | The colour every pixel is when the screen is built, and what Clear canvas puts back unless it is given a colour of its own. |
| Starting opacity | 255 | With transparency only: 0 is clear, 255 solid. |
What it costs
The buffer is the widget's width × height × the bytes a pixel, so the size of the box is the memory it takes: 120 × 80 in colour is 18.8 KB, a whole 320 × 240 screen is 150 KB, and with transparency twice that. On a board with PSRAM switched on that is easily had. On one without it comes out of the chip's own RAM, which LVGL, its draw buffer, Wi-Fi and everything else share - the Problems tab says how much the design's canvases take, warns past 32 KB and says it is an error when they cannot fit. A canvas whose buffer cannot be had is drawn empty and says so on LVGL's log; nothing stops. A screen that is not Temporary keeps its canvases' buffers once it has been shown.
Drawing on it
Each canvas is declared in ui.h like any widget (ui_Canvas1), and the
export's lw_canvas.h adds three calls: ui_canvas_buffer(canvas) (its pixels,
or NULL when there was not the memory), ui_canvas_clear(canvas, colour, opacity) and
ui_canvas_attach(), which the screen calls. The README of the export has an example for
the design's own LVGL version. In short, on LVGL 9 a pixel is lv_canvas_set_px() and
anything else is drawn through a layer (lv_canvas_init_layer(), lv_draw_rect(),
lv_draw_line(), lv_draw_label(), lv_canvas_finish_layer()); on
LVGL 8 there are lv_canvas_set_px_color(), lv_canvas_draw_rect(),
lv_canvas_draw_line() and the rest. Draw once the screen is built (a Screen loaded event
calling a function of yours is the place) and only while ui_canvas_buffer() is not NULL.
On MicroPython the buffer is a bytearray the screen module keeps, and the canvas is
ui.ui_Canvas1: ui.ui_Canvas1.set_px(10, 10, lv.color_hex(0xFF0000), 255).
ESPHome has a canvas of its own that starts empty and is drawn on by ESPHome's actions; this export
does not write it yet, so the widget is greyed there.
The Clear canvas action wipes it to the colour it starts as, or to one of the event's own, from any event or automation.
Example: a sketch pad that is cleared by a button
- Drag a Canvas onto the screen, name it
Pad, and make it200×120. - Under Canvas settings set Starts as to a light grey,
#ECEFF1. - Drag a Button under it, caption
Clear, and give it a Clicked event with the action Clear canvas, CanvasPad, To The colour it starts as. - Give the canvas a Pressed event that calls a function of yours,
pad_draw, and inui_events.cset the pixel under the finger, so each tap leaves a dot: on LVGL 9lv_indev_get_point(lv_indev_active(), &p), take the canvas'slv_obj_get_coords()corner off it, andlv_canvas_set_px(ui_Pad, x, y, lv_color_hex(0x263238), LV_OPA_COVER). Tick Clickable under Flags so it takes a press.