core/linechart/linechart.go
Functions
func AddSeries
func (w *Widget) AddSeries(label string, color widget.Color) {
w.mu.Lock()
defer w.mu.Unlock()
for _, s := range w.series {
if s.Label == label {
return
}
}
w.series = append(w.series, Series{
Label: label,
Color: color,
Points: make([]DataPoint, 0, w.cfg.maxPoints),
})
w.syncToSignal()
w.SetNeedsRedraw(true)
}
func BackgroundColor
BackgroundColor sets the chart background fill color.
func BackgroundColor(color widget.Color) Option {
return func(c *config) {
c.background = color
}
}
func Children
Children returns nil because a line chart is a leaf widget.
func (w *Widget) Children() []widget.Widget {
return nil
}
func ClearSeries
ClearSeries removes all data points from the named series.
Safe to call from any goroutine.
func (w *Widget) ClearSeries(label string) {
w.mu.Lock()
defer w.mu.Unlock()
for i := range w.series {
if w.series[i].Label == label {
w.series[i].Points = w.series[i].Points[:0]
w.syncToSignal()
w.SetNeedsRedraw(true)
return
}
}
}
func Draw
Draw renders the chart to the canvas.
func (w *Widget) Draw(_ widget.Context, canvas widget.Canvas) {
bounds := w.Bounds()
if bounds.IsEmpty() {
return
}
// Build PaintState from current data.
chartState := w.buildPaintState()
w.painter.PaintChart(canvas, bounds, chartState)
}
func Event
Event handles an input event and returns true if consumed.
LineChart is a display-only widget and does not consume events.
func (w *Widget) Event(_ widget.Context, _ event.Event) bool {
return false
}
func GridColor
GridColor sets the color used for grid lines.
func GridColor(color widget.Color) Option {
return func(c *config) {
c.gridColor = color
}
}
func Layout
Layout calculates the chart's preferred size within the given constraints.
func (w *Widget) Layout(_ widget.Context, constraints geometry.Constraints) geometry.Size {
width := constraints.MaxWidth
if width <= 0 || width == geometry.Infinity {
width = defaultWidth + w.padding*2
}
height := defaultHeight + w.padding*2
return constraints.Constrain(geometry.Sz(width, height))
}
func MaxPoints
MaxPoints sets the rolling window size (number of data points displayed).
Default is 60.
func MaxPoints(n int) Option {
return func(c *config) {
if n > 0 {
c.maxPoints = n
}
}
}
func Mount
Mount creates signal bindings for push-based invalidation.
Implements [widget.Lifecycle].
func (w *Widget) Mount(ctx widget.Context) {
sched := ctx.Scheduler()
if sched == nil {
return
}
if w.cfg.readonlySeriesSignal != nil {
b := state.BindToScheduler(w.cfg.readonlySeriesSignal, w, sched)
w.AddBinding(b)
} else if w.cfg.seriesSignal != nil {
b := state.BindToScheduler(w.cfg.seriesSignal, w, sched)
w.AddBinding(b)
}
}
func New
New creates a new line chart Widget with the given options.
The returned widget is visible and enabled by default.
The default Y range is [0, 100] with a rolling window of 60 points.
func New(opts ...Option) *Widget {
w := &Widget{
padding: defaultPadding,
painter: DefaultPainter{},
}
w.SetVisible(true)
w.SetEnabled(true)
// Default config.
w.cfg.maxPoints = defaultMaxPoints
w.cfg.yMin = defaultYMin
w.cfg.yMax = defaultYMax
w.cfg.background = defaultBackground
w.cfg.gridColor = defaultGridColor
for _, opt := range opts {
opt(&w.cfg)
}
// Apply painter from config if set.
if w.cfg.painter != nil {
w.painter = w.cfg.painter
}
// Copy initial static series into mutable state.
if len(w.cfg.series) > 0 {
w.series = make([]Series, len(w.cfg.series))
copy(w.series, w.cfg.series)
}
return w
}
func Padding
Padding sets the padding around the chart area.
Returns the widget for method chaining.
func (w *Widget) Padding(v float32) *Widget {
w.padding = v
return w
}
func PainterOpt
PainterOpt sets the painter used to render the chart.
Each design system provides its own painter. If not set,
[DefaultPainter] is used.
func PainterOpt(p Painter) Option {
return func(c *config) {
c.painter = p
}
}
func PushValue
PushValue appends a data point to the named series. If the series has
reached MaxPoints, the oldest point is removed (rolling window).
Safe to call from any goroutine.
func (w *Widget) PushValue(label string, value float64) {
w.mu.Lock()
defer w.mu.Unlock()
for i := range w.series {
if w.series[i].Label != label {
continue
}
pts := w.series[i].Points
if len(pts) >= w.cfg.maxPoints {
// Shift left: drop oldest point.
copy(pts, pts[1:])
pts[len(pts)-1] = DataPoint{Value: value}
} else {
pts = append(pts, DataPoint{Value: value})
}
w.series[i].Points = pts
w.syncToSignal()
w.SetNeedsRedraw(true)
return
}
}
func SeriesCount
SeriesCount returns the number of series. Safe to call from any goroutine.
func (w *Widget) SeriesCount() int {
w.mu.Lock()
defer w.mu.Unlock()
return len(w.series)
}
func SeriesData
SeriesData sets the initial static series data.
func SeriesData(s []Series) Option {
return func(c *config) {
c.series = s
}
}
func SeriesFn
SeriesFn sets a dynamic function that returns the current series data.
When set, this takes precedence over the static data but not over
a signal set via [SeriesSignal].
func SeriesFn(fn func() []Series) Option {
return func(c *config) {
c.seriesFn = fn
}
}
func SeriesReadonlySignal
SeriesReadonlySignal binds the chart's series data to a read-only signal.
This is useful for computed signals. When set, this takes highest precedence.
func SeriesReadonlySignal(sig state.ReadonlySignal[[]Series]) Option {
return func(c *config) {
c.readonlySeriesSignal = sig
}
}
func SeriesSignal
SeriesSignal binds the chart's series data to a reactive signal.
This is a TWO-WAY binding: the widget reads series from the signal,
and when PushValue modifies series, the signal is updated.
func SeriesSignal(sig state.Signal[[]Series]) Option {
return func(c *config) {
c.seriesSignal = sig
}
}
func ShowGrid
ShowGrid enables or disables grid lines. Default is false.
func ShowGrid(v bool) Option {
return func(c *config) {
c.showGrid = v
}
}
func ShowLabels
ShowLabels enables or disables Y axis labels. Default is false.
func ShowLabels(v bool) Option {
return func(c *config) {
c.showLabels = v
}
}
func Unmount
Unmount is called when the chart is removed from the widget tree.
Implements [widget.Lifecycle].
func (w *Widget) Unmount() {
// Bindings are cleaned up automatically by WidgetBase.CleanupBindings().
}
func YRange
YRange sets the Y axis range [yMin, yMax].
Default is [0, 100].
func YRange(yMin, yMax float64) Option {
return func(c *config) {
c.yMin = yMin
c.yMax = yMax
}
}
Structs
type DataPoint struct
DataPoint represents a single data value in a series.
type DataPoint struct {
Value float64
}
type Series struct
Series represents a named collection of data points with a display color.
type Series struct {
Label string
Color widget.Color
Points []DataPoint
}
type Widget struct
Widget implements a real-time line chart for visualizing time-series data.
A line chart is created with [New] using functional options:
chart := linechart.New(
linechart.MaxPoints(60),
linechart.YRange(0, 100),
linechart.ShowGrid(true),
)
Data is pushed with [Widget.AddSeries] and [Widget.PushValue], which are
safe to call from any goroutine.
type Widget struct {
widget.WidgetBase
cfg config
painter Painter
// mu protects series data for concurrent PushValue calls.
mu sync.Mutex
series []Series
// Styling overrides set via fluent methods.
padding float32
}
AddSeries adds a named data series with the given color.
If a series with the same label already exists, this is a no-op.
Safe to call from any goroutine.