Documentation
¶
Overview ¶
Package window draws refract charts in a native window.
It is the fourth surface, after the two vector emitters and the browser canvas: a chart on a desktop, panned and zoomed with a mouse rather than exported and opened. The window itself comes from gogpu — windowing, input and lifecycle across Windows, macOS, Linux/X11 and Linux/Wayland, with no cgo — and the chart is rasterized by the same CPU backend that writes a PNG and presented as one texture.
w := window.New(window.Title("Signal"), window.Size(900, 600))
live, _ := p.Live(w.Target())
defer live.Close()
in := live.Input()
err := w.Run(window.Handler{
Frame: live.Draw,
Move: func(x, y float64) { in.Move(x, y) },
Press: func(x, y float64) { in.Down(x, y) },
Release: func(x, y float64) { in.Up(x, y) },
Scroll: func(x, y, d float64) { in.Wheel(x, y, d) },
Resize: func(w, h int) { in.Resize(w, h) },
})
Package show is that same wiring in one call, and is what most callers want.
Why the chart is rasterized on the CPU ¶
Because there is one implementation of every mark, and a window should show what a file would. The GPU is not idle in this arrangement — it composites and presents — and gg's own GPU tier can be switched on underneath, without anything here changing, by importing github.com/timzifer/refract/backend/gg/gpu.
The cost of the arrangement is one texture upload per changed frame. It is paid only when the frame changed: refract repaints nothing when a frame is identical to the last, the rasterizer stamps its buffer with a generation that says whether it did, and the window compares two integers rather than two buffers. Between that and an event-driven loop that blocks on the operating system's queue, a chart nobody is touching costs no CPU at all.
A separate module ¶
Like backend/gg, this is a nested module: importing refract's core still yields a dependency graph with nothing in it but the standard library, and a program that renders SVG on a server links no window layer. It depends on backend/gg as well as on the core, because the rasterizer is where the marks are drawn.
Status ¶
The window layer is young, and so is the GPU stack under it. A chart in a window is v0.6's newest surface and the least proven one; the vector emitters remain the supported path for output that has to be right.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Handler ¶
type Handler struct {
// Frame is called before each present, and is where the chart is drawn.
// Returning an error stops the loop and is what [Window.Run] returns.
Frame func() error
// Move, Press and Release report the pointer. Press and Release are the
// primary button; a window reports no other, because a chart has no use
// for one yet.
Move func(x, y float64)
Press func(x, y float64)
Release func(x, y float64)
// DoubleClick reports two presses in the same place in quick succession,
// which every interactive chart uses to reset the view.
DoubleClick func(x, y float64)
// Scroll reports the wheel, in the browser's pixel convention: positive
// scrolls the content away from the reader. Lines and pages are converted
// to it, so a handler sees one unit whatever the platform counts in.
Scroll func(x, y, delta float64)
// Resize reports the window's new content size in device-independent
// pixels, and Rescale a change of device pixel ratio — dragging a window
// onto a display with a different one.
Resize func(w, h int)
Rescale func(dpr float64)
// Closed is called once, as the window is going away.
Closed func()
}
Handler is what a window reports. Every field is optional, and every callback runs on the goroutine that called Window.Run, one at a time — so a handler may touch a chart without a lock.
Positions are in device-independent pixels relative to the window's content area, which is the same space the chart is laid out in: a point handed to a handler can go straight to Live.Move.
type Option ¶
type Option func(*config)
Option configures a window.
func FollowSize ¶
FollowSize controls whether the chart is redrawn at the window's size when the window is resized. It is on by default; turn it off to keep the chart at the size it was opened with and let the window letterbox it.
func Font ¶
Font supplies the fonts the chart is drawn with, exactly as the file targets take them. See github.com/timzifer/refract/backend/gg.WithFont.
type Window ¶
type Window struct {
// contains filtered or unexported fields
}
Window is a native window a chart is drawn in.
It is two things joined at one seam. Window.Target is a drawing surface — the same CPU rasterizer that writes a PNG, drawing into memory — and Window.Run is an event loop that presents that memory as a texture and reports what the reader does to it. Neither knows what a chart is; the package next door, backend/window/show, is what joins them to a plot.
A Window is used from one goroutine: the one that calls Run, which is the goroutine every callback then runs on.
func New ¶
New returns a window that has not been opened yet.
Nothing is created until Window.Run: a window is opened by running it, and a program that builds one and never runs it has not taken a screen.
func (*Window) Redraw ¶
func (w *Window) Redraw()
Redraw asks for a frame. It is what to call after changing something the window is showing; the loop is event-driven and idle otherwise, which is why a change nobody announces is a change nobody sees.
func (*Window) Run ¶
Run opens the window and runs its event loop until the window is closed.
The loop is event-driven: it blocks on the operating system's event queue and wakes for input, a resize, or a Window.Redraw. A chart that nobody is touching costs nothing, which is the property that makes a window worth having over a browser tab and is why Frame is a callback rather than a polling loop.
Run returns the first error a Frame reported, or the error the window layer failed with. It must be called on the main goroutine on the platforms that insist on it — macOS does — which in Go means from main, before anything else takes over.
func (*Window) ScaleFactor ¶
ScaleFactor reports the display's device pixel ratio.