89 lines
2.3 KiB
Go
89 lines
2.3 KiB
Go
|
package canvas
|
||
|
|
||
|
// Text rendering functions using the HTML 5 canvas.
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
|
||
|
"git.kirsle.net/apps/doodle/lib/render"
|
||
|
)
|
||
|
|
||
|
// FontFilenameToName converts a FontFilename to its CSS font name.
|
||
|
//
|
||
|
// The CSS font name is set to the base of the filename, without the .ttf
|
||
|
// file extension. For example, "fonts/DejaVuSans.ttf" uses the CSS font
|
||
|
// family name "DejaVuSans" and that's what this function returns.
|
||
|
//
|
||
|
// Fonts must be defined in the index.html style sheet when serving the
|
||
|
// wasm build of Doodle.
|
||
|
//
|
||
|
// If filename is "", returns "serif" as a sensible default.
|
||
|
func FontFilenameToName(filename string) string {
|
||
|
if filename == "" {
|
||
|
return "DejaVuSans,serif"
|
||
|
}
|
||
|
return strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
|
||
|
}
|
||
|
|
||
|
// DrawText draws text on the canvas.
|
||
|
func (e *Engine) DrawText(text render.Text, point render.Point) error {
|
||
|
font := FontFilenameToName(text.FontFilename)
|
||
|
e.canvas.ctx2d.Set("font",
|
||
|
fmt.Sprintf("%dpx %s,serif", text.Size, font),
|
||
|
)
|
||
|
|
||
|
e.canvas.ctx2d.Set("textBaseline", "top")
|
||
|
|
||
|
write := func(dx, dy int, color render.Color) {
|
||
|
e.canvas.ctx2d.Set("fillStyle", color.ToHex())
|
||
|
e.canvas.ctx2d.Call("fillText",
|
||
|
text.Text,
|
||
|
int(point.X)+dx,
|
||
|
int(point.Y)+dy,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// Does the text have a stroke around it?
|
||
|
if text.Stroke != render.Invisible {
|
||
|
e.canvas.ctx2d.Set("fillStyle", text.Stroke.ToHex())
|
||
|
write(-1, -1, text.Stroke)
|
||
|
write(-1, 0, text.Stroke)
|
||
|
write(-1, 1, text.Stroke)
|
||
|
write(1, -1, text.Stroke)
|
||
|
write(1, 0, text.Stroke)
|
||
|
write(1, 1, text.Stroke)
|
||
|
write(0, -1, text.Stroke)
|
||
|
write(0, 1, text.Stroke)
|
||
|
}
|
||
|
|
||
|
// Does it have a drop shadow?
|
||
|
if text.Shadow != render.Invisible {
|
||
|
write(1, 1, text.Shadow)
|
||
|
}
|
||
|
|
||
|
// Draw the text itself.
|
||
|
write(0, 0, text.Color)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// ComputeTextRect computes and returns a Rect for how large the text would
|
||
|
// appear if rendered.
|
||
|
func (e *Engine) ComputeTextRect(text render.Text) (render.Rect, error) {
|
||
|
font := FontFilenameToName(text.FontFilename)
|
||
|
e.canvas.ctx2d.Set("font",
|
||
|
fmt.Sprintf("%dpx %s,serif", text.Size, font),
|
||
|
)
|
||
|
|
||
|
measure := e.canvas.ctx2d.Call("measureText", text.Text)
|
||
|
rect := render.Rect{
|
||
|
// TODO: the only TextMetrics widely supported in browsers is
|
||
|
// the width. For height, use the text size for now.
|
||
|
W: int32(measure.Get("width").Int()),
|
||
|
H: int32(text.Size),
|
||
|
}
|
||
|
return rect, nil
|
||
|
}
|