{ return c.ctx.Truthy() }
{
c.element.Set("width", int(width))
c.element.Set("height", int(height))
}
{
if r.fillColor != "" {
c.ctx.Set("fillStyle", r.fillColor)
c.ctx.Call("fillRect", r.X, r.Y, r.Width, r.Height)
}
if r.strokeColor != "" && r.strokeWidth > 0 {
c.ctx.Set("lineWidth", r.strokeWidth)
c.ctx.Set("strokeStyle", r.strokeColor)
c.ctx.Call("strokeRect", r.X, r.Y, r.Width, r.Height)
}
}
{
c.ctx.Call("beginPath")
c.ctx.Call("arc", circle.X, circle.Y, circle.Radius, 0, math.Pi*2, false)
if circle.fillColor != "" {
c.ctx.Set("fillStyle", circle.fillColor)
c.ctx.Call("fill")
}
if circle.strokeColor != "" && circle.strokeWidth > 0 {
c.ctx.Set("lineWidth", circle.strokeWidth)
c.ctx.Set("strokeStyle", circle.strokeColor)
c.ctx.Call("stroke")
}
}
{
if line.strokeColor == "" || line.strokeWidth <= 0 {
return
}
c.ctx.Call("beginPath")
c.ctx.Call("moveTo", line.X1, line.Y1)
c.ctx.Call("lineTo", line.X2, line.Y2)
c.ctx.Set("lineWidth", line.strokeWidth)
c.ctx.Set("strokeStyle", line.strokeColor)
c.ctx.Call("stroke")
}
NewCanvas binds a DOM canvas element to the drawing helpers.
{
if el.IsNull() || el.IsUndefined() {
return Canvas{}, false
}
ctx := el.Call("getContext", "2d")
if !ctx.Truthy() {
return Canvas{}, false
}
return Canvas{impl: &canvas2D{element: el, ctx: ctx}}, true
}
NewCanvas is unavailable outside WebAssembly builds.
{ return Canvas{}, false }
{ return false }
{}
{ return r.validState }
{
r.width = width
r.height = height
}
{ r.rects = append(r.rects, rect) }
{ r.circles = append(r.circles, circle) }
{ r.lines = append(r.lines, line) }
{
impl := &recorder{validState: true}
canvas := Canvas{impl: impl}
rect := Rectangle(0, 0, 10, 20).Fill("#111111").Stroke("#ffffff", 2)
circle := Disc(1, 2, 3).Fill("#eeeeee").Stroke("#000000", 1.5)
line := Segment(-1, -1, 1, 1).Stroke("#ff00ff", 3)
canvas.Draw(rect, nil, circle, line)
if got := len(impl.rects); got != 1 {
t.Fatalf("expected 1 rect, got %d", got)
}
if got := len(impl.circles); got != 1 {
t.Fatalf("expected 1 circle, got %d", got)
}
if got := len(impl.lines); got != 1 {
t.Fatalf("expected 1 line, got %d", got)
}
if impl.rects[0].fillColor != "#111111" || impl.rects[0].strokeColor != "#ffffff" || impl.rects[0].strokeWidth != 2 {
t.Fatalf("unexpected rect payload: %#v", impl.rects[0])
}
if impl.circles[0].fillColor != "#eeeeee" || impl.circles[0].strokeColor != "#000000" || impl.circles[0].strokeWidth != 1.5 {
t.Fatalf("unexpected circle payload: %#v", impl.circles[0])
}
if impl.lines[0].strokeColor != "#ff00ff" || impl.lines[0].strokeWidth != 3 {
t.Fatalf("unexpected line payload: %#v", impl.lines[0])
}
}
{
canvas := Canvas{}
if canvas.Valid() {
t.Fatal("expected zero-value canvas to be invalid")
}
canvas.Draw(Rectangle(0, 0, 1, 1))
canvas.SetSize(10, 20)
}
{
impl := &recorder{validState: true}
canvas := Canvas{impl: impl}
canvas.SetSize(640, 480)
if impl.width != 640 || impl.height != 480 {
t.Fatalf("expected setSize delegation, got width=%f height=%f", impl.width, impl.height)
}
}
{
impl := &recorder{validState: false}
canvas := Canvas{impl: impl}
if canvas.Valid() {
t.Fatal("expected canvas to report invalid when impl invalid")
}
impl.validState = true
if !canvas.Valid() {
t.Fatal("expected canvas to report valid after impl change")
}
}
Canvas represents a 2D drawing surface built on top of a canvas element.
Valid reports whether the canvas is ready for drawing commands.
{
if c.impl == nil {
return false
}
return c.impl.valid()
}
SetSize updates the backing canvas dimensions.
{
if c.impl == nil {
return
}
c.impl.setSize(width, height)
}
Draw executes the provided commands in order when the canvas is valid.
{
if !c.Valid() {
return
}
for _, cmd := range cmds {
if cmd != nil {
cmd.draw(c)
}
}
}
{
if c.impl == nil {
return
}
c.impl.drawRect(r)
}
{
if c.impl == nil {
return
}
c.impl.drawCircle(circle)
}
{
if c.impl == nil {
return
}
c.impl.drawLine(line)
}
Command represents a draw instruction that can be executed on a Canvas.
Rect describes a rectangle drawing command.
Fill configures the fill color for the rectangle.
{
r.fillColor = color
return r
}
Stroke configures the stroke color and width for the rectangle outline.
{
r.strokeColor = color
r.strokeWidth = width
return r
}
{
c.drawRect(*r)
}
Rectangle returns a rectangle command builder for the given bounds.
{
return &Rect{X: x, Y: y, Width: width, Height: height}
}
Circle describes a circle drawing command.
Fill configures the fill color for the circle.
{
c.fillColor = color
return c
}
Stroke configures the stroke color and width for the circle outline.
{
c.strokeColor = color
c.strokeWidth = width
return c
}
{
canvas.drawCircle(*c)
}
Disc returns a circle command builder centered at the provided coordinates.
{
return &Circle{X: x, Y: y, Radius: radius}
}
Line describes a line segment drawing command.
Stroke configures the stroke color and width for the line.
{
l.strokeColor = color
l.strokeWidth = width
return l
}
{
c.drawLine(*l)
}
Segment returns a line command builder for the provided endpoints.
{
return &Line{X1: x1, Y1: y1, X2: x2, Y2: y2}
}
import "math"
import "github.com/rfwlab/rfw/v1/dom"
dom
import "github.com/rfwlab/rfw/v1/js"
js
import "testing"