Class ui.CanvasViewport
A viewport that maps a virtual coordinate space onto a Canvas.
This viewport is useful if a canvas is displayed in a TUI panel for example and you want to draw using a fixed logical coordinate system that is independent of the actual canvas pixel dimensions. The viewport applies a linear transformation to map virtual coordinates to the underlying canvas pixel coordinates, optionally preserving aspect ratio with letterboxing/pillarboxing.
Responsibility: pure coordinate transformation. This class translates drawing calls expressed in a user-defined virtual pixel space into the underlying Canvas's physical pixel space. It owns no scene data and records no operations; the caller is responsible for re-issuing draw calls whenever the canvas dimensions change (e.g. on panel resize).
What it is NOT:
- Not a scene graph or display list. It does not remember what was drawn.
- Not responsible for creating or managing the Canvas lifetime.
- Not responsible for rendering or writing to the terminal.
Virtual coordinate space:
Coordinates are 0-based, with origin (0, 0) at the top-left, x increasing
to the right and y increasing downward — matching the Canvas pixel convention.
The virtual space has a fixed logical size (width × height) set at
construction. Drawing calls use these logical coordinates regardless of the
physical canvas dimensions.
Scale modes: When the virtual aspect ratio does not match the physical canvas pixel aspect ratio, the viewport applies one of the following scale modes:
scale_modes.stretch: x and y are scaled independently to fill the canvas exactly. The image may be distorted.scale_modes.fit: uniform scale so the virtual space fits entirely within the canvas. Unused bands (letterbox / pillarbox) are left blank. No clipping.scale_modes.fill: uniform scale so the virtual space fills the canvas completely. Content that falls outside the canvas bounds is clipped (silently ignored, matching Canvas out-of-bounds behaviour).
Resize handling: The viewport holds a reference to a Canvas. When the panel is resized, the caller should replace the canvas via set_canvas and then re-issue all drawing calls.
Example usage:
local Canvas = require "terminal.ui.canvas" local CanvasViewport = require "terminal.ui.canvasviewport" -- Inside a Panel content callback, called on every render (including resize): local c = Canvas({ width = panel.inner_width, height = panel.inner_height }) local vp = CanvasViewport({ canvas = c, width = 300, height = 300, scale_mode = CanvasViewport.scale_modes.fit, anchor = CanvasViewport.anchors.center, }) vp:line({ x1 = 0, y1 = 0, x2 = 299, y2 = 299 }) -- diagonal in virtual space -- position cursor and write c:render() as usual
Fields
| ui.canvasviewport.anchors | Anchor constants; center or top_left determine the alignment of the virtual space within the
canvas when scale_mode is fit or fill. |
| ui.canvasviewport.scale_modes | Scale mode constants; stretch, fit, or fill determine how the virtual
coordinate space is mapped to the underlying canvas when their aspect ratios do not match. |
Methods
| ui.canvasviewport:arc (opts) | Draw an arc using virtual-space coordinates. |
| ui.canvasviewport:circle (opts) | Draw a circle using virtual-space coordinates. |
| ui.canvasviewport:ellipse (opts) | Draw an ellipse using virtual-space coordinates. |
| ui.canvasviewport:get_scale () | Return the current scale factors applied to virtual coordinates. |
| ui.canvasviewport:init (opts) | Create a new CanvasViewport. |
| ui.canvasviewport:line (opts) | Draw a line between two virtual-space pixels. |
| ui.canvasviewport:polygon (opts) | Draw a polygon from an array of virtual-space {x, y} points. |
| ui.canvasviewport:set (x, y) | Set (illuminate) a pixel at a virtual coordinate. |
| ui.canvasviewport:set_canvas (canvas) | Replace the underlying canvas. |
| ui.canvasviewport:unset (x, y) | Clear (extinguish) a pixel at a virtual coordinate. |
Fields
- ui.canvasviewport.anchors
-
Anchor constants;
centerortop_leftdetermine the alignment of the virtual space within the canvas whenscale_modeisfitorfill. Withcenterthe virtual space is centered in the canvas, and withtop_leftthe virtual space is aligned to the top-left corner of the canvas. This has no effect whenscale_modeisstretchsince the virtual space always fills the canvas in that mode. - ui.canvasviewport.scale_modes
-
Scale mode constants;
stretch,fit, orfilldetermine how the virtual coordinate space is mapped to the underlying canvas when their aspect ratios do not match.
Methods
- ui.canvasviewport:arc (opts)
-
Draw an arc using virtual-space coordinates.
Scales the centre and radii into physical canvas pixels, then delegates to Canvas:arc.
Angles are passed through unchanged; they describe the same geometric direction
regardless of scale.
Note: angles are drawn clockwise, see Canvas:arc for details.
Parameters:
- opts
- x number Centre virtual pixel column, 0-based.
- y number Centre virtual pixel row, 0-based.
- rx number Horizontal radius in virtual pixels.
- ry number Vertical radius in virtual pixels.
- angle_start number Start angle in radians.
- angle_end number End angle in radians (must be >= angle_start).
- erase boolean If truthy, unset pixels instead of setting them. (default false)
- opts
- ui.canvasviewport:circle (opts)
-
Draw a circle using virtual-space coordinates.
Convenience wrapper around ellipse with equal horizontal and vertical radii.
With
scale_modes.fitorscale_modes.fillthe uniform scale preserves the circular shape. Withscale_modes.stretchthe circle maps to an ellipse on the canvas.Parameters:
- opts
- x number Centre virtual pixel column, 0-based.
- y number Centre virtual pixel row, 0-based.
- r number Radius in virtual pixels.
- fill boolean If truthy, fill the interior. (default false)
- erase boolean If truthy, unset pixels instead of setting them. (default false)
- opts
- ui.canvasviewport:ellipse (opts)
-
Draw an ellipse using virtual-space coordinates.
The virtual radii are scaled independently per axis, so a circle in virtual
space becomes an ellipse on the canvas when
scale_modeisscale_modes.stretch.Parameters:
- opts
- x number Centre virtual pixel column, 0-based.
- y number Centre virtual pixel row, 0-based.
- rx number Horizontal radius in virtual pixels.
- ry number Vertical radius in virtual pixels.
- fill boolean If truthy, fill the interior. (default false)
- erase boolean If truthy, unset pixels instead of setting them. (default false)
- opts
- ui.canvasviewport:get_scale ()
-
Return the current scale factors applied to virtual coordinates.
Useful for callers that need to reason about resolution (e.g. to decide
whether to simplify a dense dataset before drawing).
Returns:
- number sx Scale factor applied to x (physicalpx / virtualpx).
- number sy Scale factor applied to y (physicalpx / virtualpx).
- ui.canvasviewport:init (opts)
-
Create a new CanvasViewport.
Do not call this method directly, call on the class instead.
Parameters:
- opts
- canvas Canvas The underlying Canvas to draw into.
- width number Virtual space width in logical pixels.
- height number Virtual space height in logical pixels.
- scale_mode string One of CanvasViewport.scale_modes. (default scale_modes.stretch)
- anchor
string
Alignment of the virtual space within the
canvas when
scale_modeisscale_modes.fitorscale_modes.fill. One of CanvasViewport.anchors. (default anchors.center)
Usage:
local vp = CanvasViewport({ canvas = c, width = 300, height = 300, scale_mode = CanvasViewport.scale_modes.fit, anchor = CanvasViewport.anchors.center, })
- opts
- ui.canvasviewport:line (opts)
-
Draw a line between two virtual-space pixels.
Parameters:
- opts
- x1 number Start virtual pixel column, 0-based.
- y1 number Start virtual pixel row, 0-based.
- x2 number End virtual pixel column, 0-based.
- y2 number End virtual pixel row, 0-based.
- erase boolean If truthy, unset pixels instead of setting them. (default false)
- opts
- ui.canvasviewport:polygon (opts)
-
Draw a polygon from an array of virtual-space
{x, y}points. 1 point draws a dot, 2 points draw a line, 3+ points draw a closed polygon by default.Parameters:
- opts
- points
table
Array of
{x, y}virtual pixel coordinate pairs, 0-based. - open boolean If truthy, do not close the path back to the first point. (default false)
- fill boolean If truthy, fill the interior of the polygon. (default false)
- erase boolean If truthy, unset pixels instead of setting them. (default false)
- points
table
Array of
- opts
- ui.canvasviewport:set (x, y)
-
Set (illuminate) a pixel at a virtual coordinate.
Out-of-bounds virtual coordinates (after mapping) are silently ignored.
Parameters:
- x number Virtual pixel column, 0-based.
- y number Virtual pixel row, 0-based.
- ui.canvasviewport:set_canvas (canvas)
-
Replace the underlying canvas.
Call this when the panel has been resized and a new Canvas has been created
with updated dimensions. Scale factors are recomputed immediately.
Parameters:
- canvas Canvas The new Canvas instance.
- ui.canvasviewport:unset (x, y)
-
Clear (extinguish) a pixel at a virtual coordinate.
Out-of-bounds virtual coordinates (after mapping) are silently ignored.
Parameters:
- x number Virtual pixel column, 0-based.
- y number Virtual pixel row, 0-based.