textmeasure

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: MPL-2.0 Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	MarkdownFontSize   = d2fonts.FONT_SIZE_M
	MarkdownLineHeight = 1.5

	PaddingLeft_ul_ol_em = 2.
	MarginBottom_ul      = 16.

	MarginTop_li_p  = 16.
	MarginTop_li_em = 0.25
	MarginBottom_p  = 16.

	LineHeight_h           = 1.25
	MarginTop_h            = 24
	MarginBottom_h         = 16
	PaddingBottom_h1_h2_em = 0.3
	BorderBottom_h1_h2     = 1

	Height_hr_em       = 0.25
	MarginTopBottom_hr = 24

	Padding_pre          = 16
	MarginBottom_pre     = 16
	MarginBottom_table   = 16
	LineHeight_pre       = 1.45
	FontSize_pre_code_em = 0.85

	PaddingTopBottom_code_em         = 0.2
	PaddingLeftRight_code_em         = 0.4
	PaddingLeftRight_heading_code_em = 0.2

	PaddingLR_blockquote_em  = 1.
	MarginBottom_blockquote  = 16
	BorderLeft_blockquote_em = 0.25
)

these are css values from github-markdown.css so we can accurately compute the rendered dimensions

View Source
const CODE_LINE_HEIGHT = 1.3
View Source
const SIZELESS_FONT_SIZE = 0
View Source
const TAB_SIZE = 4

Variables

View Source
var Runes []rune

Runes encompasses ASCII, Latin-1, and geometric shapes like black square

Functions

func HeaderToFontScale added in v0.9.0

func HeaderToFontScale(header string) float64

HeaderToFontScale returns github-markdown.css's exact heading size. The legacy measurement path keeps HeaderToFontSize's integer truncation so graph dimensions remain stable, while native SVG painting uses this scale and can reproduce fractional CSS sizes such as h6's 13.6px at a 16px base.

func HeaderToFontSize

func HeaderToFontSize(baseFontSize int, header string) int

func MeasureMarkdown

func MeasureMarkdown(mdText string, ruler *Ruler, fontFamily *d2fonts.FontFamily, monoFontFamily *d2fonts.FontFamily, fontSize int) (width, height int, err error)

func NewAtlas

func NewAtlas(face font.Face, runeSets ...[]rune) *atlas

NewAtlas creates a new atlas containing glyphs of the union of the given sets of runes (plus unicode.ReplacementChar) from the given font face.

Creating an atlas is rather expensive, do not create a new atlas each frame.

Do not destroy or close the font.Face after creating the atlas. atlas still uses it.

func RenderMarkdown

func RenderMarkdown(m string) (string, error)

func ReplaceSubstitutionsMarkdown

func ReplaceSubstitutionsMarkdown(mdText string, variables map[string]string) string
func SafeMarkdownLink(link string) string

SafeMarkdownLink returns link when it is safe to expose as interactive metadata and an empty string for unsafe Markdown URL schemes. PDF and PPTX annotations use the same policy.

Types

type MarkdownColorRole added in v0.9.0

type MarkdownColorRole string

MarkdownColorRole is a semantic Markdown color. It mirrors the roles used by github-markdown.css without coupling text measurement to a D2 theme.

const (
	MarkdownColorNone             MarkdownColorRole = ""
	MarkdownColorForeground       MarkdownColorRole = "foreground"
	MarkdownColorForegroundStroke MarkdownColorRole = "foreground-stroke"
	MarkdownColorMuted            MarkdownColorRole = "muted"
	MarkdownColorMutedStroke      MarkdownColorRole = "muted-stroke"
	MarkdownColorAccent           MarkdownColorRole = "accent"
	MarkdownColorBorder           MarkdownColorRole = "border"
	MarkdownColorBorderMuted      MarkdownColorRole = "border-muted"
	MarkdownColorCanvas           MarkdownColorRole = "canvas"
	MarkdownColorCanvasSubtle     MarkdownColorRole = "canvas-subtle"
	MarkdownColorNeutralMuted     MarkdownColorRole = "neutral-muted"
)

type MarkdownFontRole added in v0.9.0

type MarkdownFontRole string

MarkdownFontRole lets an SVG renderer select the correct embedded D2 font. Font sizes are kept separately on each primitive.

const (
	MarkdownFontRegular      MarkdownFontRole = "regular"
	MarkdownFontSemibold     MarkdownFontRole = "semibold"
	MarkdownFontBold         MarkdownFontRole = "bold"
	MarkdownFontItalic       MarkdownFontRole = "italic"
	MarkdownFontMono         MarkdownFontRole = "mono"
	MarkdownFontMonoSemibold MarkdownFontRole = "mono-semibold"
	MarkdownFontMonoBold     MarkdownFontRole = "mono-bold"
	MarkdownFontMonoItalic   MarkdownFontRole = "mono-italic"
)

type MarkdownLayout added in v0.9.0

type MarkdownLayout struct {
	Width, Height int
	Primitives    []MarkdownPrimitive
	// Corpus contains the visible source text used by the primitives. Renderers
	// embedding subset fonts should include it.
	Corpus string
}

MarkdownLayout contains the exact dimensions used by D2 layout and the positioned primitives used to paint those dimensions. MeasureMarkdown calls LayoutMarkdown, ensuring measurement and rendering share one code path.

func LayoutMarkdown added in v0.9.0

func LayoutMarkdown(mdText string, ruler *Ruler, fontFamily *d2fonts.FontFamily, monoFontFamily *d2fonts.FontFamily, fontSize int) (*MarkdownLayout, error)

LayoutMarkdown parses Markdown once, measures it with D2's existing box model, and paints that same box model into native SVG primitives.

func (*MarkdownLayout) SVG added in v0.9.0

SVG serializes a MarkdownLayout as native SVG elements. It deliberately emits a fragment rather than an <svg> document so d2svg can translate and theme it inside a diagram.

type MarkdownPrimitive added in v0.9.0

type MarkdownPrimitive struct {
	Kind MarkdownPrimitiveKind

	X, Y, X2, Y2        float64
	Width, Height       float64
	Radius, StrokeWidth float64

	Text       string
	Font       MarkdownFontRole
	FontSize   float64
	FillRole   MarkdownColorRole
	StrokeRole MarkdownColorRole
	Link       string
	LinkTitle  string
	Decoration MarkdownTextDecoration
	// SyntheticBold/SyntheticItalic preserve inherited CSS axes when the
	// innermost Markdown element selects a different concrete D2 font family.
	// For example, em > strong uses the bold face with a synthetic slant, while
	// strong > em uses the italic face with synthetic weight.
	SyntheticBold   bool
	SyntheticItalic bool
	// TextLength fits the glyphs to Width. CSS paints a discretionary soft
	// hyphen at one third of an em even inside D2's monospace code face.
	TextLength bool
}

MarkdownPrimitive is a serializer-neutral native SVG drawing operation.

Text uses X/Y as the baseline origin and Width/Height as its measured box. Rect uses X/Y/Width/Height/Radius. Line uses X/Y and X2/Y2. FillRole and StrokeRole are semantic so light/dark themes can serialize the same layout.

type MarkdownPrimitiveKind added in v0.9.0

type MarkdownPrimitiveKind string

MarkdownPrimitiveKind identifies the kind of native SVG primitive in a MarkdownLayout. The layout package intentionally does not choose concrete colors so that renderers can map the semantic roles to their active theme.

const (
	MarkdownTextPrimitive MarkdownPrimitiveKind = "text"
	MarkdownRectPrimitive MarkdownPrimitiveKind = "rect"
	MarkdownLinePrimitive MarkdownPrimitiveKind = "line"
)

type MarkdownSVGOptions added in v0.9.0

type MarkdownSVGOptions struct {
	Class       string
	RolePaint   map[MarkdownColorRole]MarkdownSVGPaint
	FontClasses map[MarkdownFontRole]string
	// DisableLinks emits linked text without inner <a> elements. d2svg uses
	// this when a Markdown label is already wrapped by a shape/connection link.
	DisableLinks bool
	// Underline applies D2's style.underline to every Markdown text primitive.
	Underline bool
}

MarkdownSVGOptions controls native SVG serialization without affecting layout. A renderer can override role paints and font classes to match its theme/font embedding scheme.

type MarkdownSVGPaint added in v0.9.0

type MarkdownSVGPaint struct {
	Class string
	Color string
}

MarkdownSVGPaint controls how a semantic role is emitted by SVG. Class is optional; Color is an SVG paint value such as "currentColor", "#fff", or a CSS variable.

type MarkdownTextDecoration added in v0.9.0

type MarkdownTextDecoration string
const (
	MarkdownTextDecorationNone        MarkdownTextDecoration = ""
	MarkdownTextDecorationLineThrough MarkdownTextDecoration = "line-through"
)

type Ruler

type Ruler struct {
	// Orig specifies the text origin, usually the top-left dot position. Dot is always aligned
	// to Orig when writing newlines.
	Orig *geo.Point

	// Dot is the position where the next character will be written. Dot is automatically moved
	// when writing to a Ruler object, but you can also manipulate it manually
	Dot *geo.Point

	// lineHeight is the vertical distance between two lines of text.
	//
	// Example:
	//   txt.lineHeight = 1.5 * txt.atlas.lineHeight
	LineHeightFactor float64
	// contains filtered or unexported fields
}

Ruler allows for effiecient and convenient text drawing.

To create a Ruler object, use the New constructor:

txt := text.New(pixel.ZV, text.NewAtlas(face, text.ASCII))

As suggested by the constructor, a Ruler object is always associated with one font face and a fixed set of runes. For example, the Ruler we created above can draw text using the font face contained in the face variable and is capable of drawing ASCII characters.

Here we create a Ruler object which can draw ASCII and Katakana characters:

txt := text.New(0, text.NewAtlas(face, text.ASCII, text.RangeTable(unicode.Katakana)))

Similarly to IMDraw, Ruler functions as a buffer. It implements io.Writer interface, so writing text to it is really simple:

fmt.Print(txt, "Hello, world!")

Newlines, tabs and carriage returns are supported.

Finally, if we want the written text to show up on some other Target, we can draw it:

txt.Draw(target)

Ruler exports two important fields: Orig and Dot. Dot is the position where the next character will be written. Dot is automatically moved when writing to a Ruler object, but you can also manipulate it manually. Orig specifies the text origin, usually the top-left dot position. Dot is always aligned to Orig when writing newlines. The Clear method resets the Dot to Orig.

func NewRuler

func NewRuler() (*Ruler, error)

New creates a new Ruler capable of drawing runes contained in the provided atlas. Orig and Dot will be initially set to orig.

Here we create a Ruler capable of drawing ASCII characters using the Go Regular font.

ttf, err := parseFont(goregular.TTF)
if err != nil {
    panic(err)
}
face := ttf.newFace(14)
txt := text.New(orig, text.NewAtlas(face, text.ASCII))

func (*Ruler) HasFontFamilyLoaded

func (r *Ruler) HasFontFamilyLoaded(fontFamily *d2fonts.FontFamily) bool

func (*Ruler) Measure

func (t *Ruler) Measure(font d2fonts.Font, s string) (width, height int)

func (*Ruler) MeasureMono

func (t *Ruler) MeasureMono(font d2fonts.Font, s string) (width, height int)

func (*Ruler) MeasurePrecise

func (t *Ruler) MeasurePrecise(font d2fonts.Font, s string) (width, height float64)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL