improve code measurement and rendering

This commit is contained in:
Gavin Nishizawa 2023-06-19 14:17:34 -07:00
parent f021d3cdd0
commit 14afd8c433
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
4 changed files with 38 additions and 13 deletions

View file

@ -903,16 +903,21 @@ func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Rul
func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily, labelDims d2target.TextDimensions, withLabelPadding bool) (*d2target.TextDimensions, error) { func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily, labelDims d2target.TextDimensions, withLabelPadding bool) (*d2target.TextDimensions, error) {
dims := d2target.TextDimensions{} dims := d2target.TextDimensions{}
dslShape := strings.ToLower(obj.Shape.Value)
if withLabelPadding { if dslShape == d2target.ShapeCode {
fontSize := obj.Text().FontSize
// 0.5em padding on each side
labelDims.Width += fontSize
labelDims.Height += fontSize
} else if withLabelPadding {
labelDims.Width += INNER_LABEL_PADDING labelDims.Width += INNER_LABEL_PADDING
labelDims.Height += INNER_LABEL_PADDING labelDims.Height += INNER_LABEL_PADDING
} }
switch strings.ToLower(obj.Shape.Value) { switch dslShape {
default: default:
return d2target.NewTextDimensions(labelDims.Width, labelDims.Height), nil return d2target.NewTextDimensions(labelDims.Width, labelDims.Height), nil
case d2target.ShapeText: case d2target.ShapeText:
w := labelDims.Width w := labelDims.Width
if w < MIN_SHAPE_SIZE { if w < MIN_SHAPE_SIZE {
@ -1308,7 +1313,10 @@ func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2
var w int var w int
var h int var h int
if t.Language != "" { if t.Language != "" {
w, h = ruler.Measure(d2fonts.SourceCodePro.Font(t.FontSize, d2fonts.FONT_STYLE_REGULAR), t.Text) originalLineHeight := ruler.LineHeightFactor
ruler.LineHeightFactor = 1.3
w, h = ruler.MeasureMono(d2fonts.SourceCodePro.Font(t.FontSize, d2fonts.FONT_STYLE_REGULAR), t.Text)
ruler.LineHeightFactor = originalLineHeight
// count empty leading and trailing lines since ruler will not be able to measure it // count empty leading and trailing lines since ruler will not be able to measure it
lines := strings.Split(t.Text, "\n") lines := strings.Split(t.Text, "\n")
@ -1329,10 +1337,6 @@ func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2
} }
} }
h += t.FontSize * (leadingLines + trailingLines) h += t.FontSize * (leadingLines + trailingLines)
// padding
w += 12
h += 12
} else { } else {
style := d2fonts.FONT_STYLE_REGULAR style := d2fonts.FONT_STYLE_REGULAR
if t.IsBold { if t.IsBold {

View file

@ -199,6 +199,7 @@ func init() {
Family: SourceSansPro, Family: SourceSansPro,
Style: FONT_STYLE_REGULAR, Style: FONT_STYLE_REGULAR,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Regular.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Regular.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -207,6 +208,7 @@ func init() {
Family: SourceCodePro, Family: SourceCodePro,
Style: FONT_STYLE_REGULAR, Style: FONT_STYLE_REGULAR,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Bold.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Bold.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -215,6 +217,7 @@ func init() {
Family: SourceCodePro, Family: SourceCodePro,
Style: FONT_STYLE_BOLD, Style: FONT_STYLE_BOLD,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Semibold.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Semibold.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -223,6 +226,7 @@ func init() {
Family: SourceCodePro, Family: SourceCodePro,
Style: FONT_STYLE_SEMIBOLD, Style: FONT_STYLE_SEMIBOLD,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Italic.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Italic.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -231,6 +235,7 @@ func init() {
Family: SourceCodePro, Family: SourceCodePro,
Style: FONT_STYLE_ITALIC, Style: FONT_STYLE_ITALIC,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Bold.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Bold.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -239,6 +244,7 @@ func init() {
Family: SourceSansPro, Family: SourceSansPro,
Style: FONT_STYLE_BOLD, Style: FONT_STYLE_BOLD,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Semibold.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Semibold.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -247,6 +253,7 @@ func init() {
Family: SourceSansPro, Family: SourceSansPro,
Style: FONT_STYLE_SEMIBOLD, Style: FONT_STYLE_SEMIBOLD,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Italic.ttf") b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Italic.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -255,6 +262,7 @@ func init() {
Family: SourceSansPro, Family: SourceSansPro,
Style: FONT_STYLE_ITALIC, Style: FONT_STYLE_ITALIC,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/ArchitectsDaughter-Regular.ttf") b, err = fontFacesFS.ReadFile("ttf/ArchitectsDaughter-Regular.ttf")
if err != nil { if err != nil {
panic(err) panic(err)
@ -267,6 +275,7 @@ func init() {
Family: HandDrawn, Family: HandDrawn,
Style: FONT_STYLE_ITALIC, Style: FONT_STYLE_ITALIC,
}] = b }] = b
b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Bold.ttf") b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Bold.ttf")
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -1263,14 +1263,18 @@ func drawShape(writer io.Writer, diagramHash string, targetShape d2target.Shape,
rectEl.Height = float64(targetShape.Height) rectEl.Height = float64(targetShape.Height)
rectEl.Stroke = targetShape.Stroke rectEl.Stroke = targetShape.Stroke
rectEl.ClassName = "shape" rectEl.ClassName = "shape"
rectEl.Style = fmt.Sprintf(`fill:%s`, style.Get(chroma.Background).Background.String()) rectEl.Style = fmt.Sprintf(`fill:%s;stroke-width:%d;`,
style.Get(chroma.Background).Background.String(),
targetShape.StrokeWidth,
)
fmt.Fprint(writer, rectEl.Render()) fmt.Fprint(writer, rectEl.Render())
// Padding // Padding = 0.5em
fmt.Fprint(writer, `<g transform="translate(6 6)">`) padding := float64(targetShape.FontSize) / 2.
fmt.Fprintf(writer, `<g transform="translate(%f %f)">`, padding, padding)
lineHeight := 1.3
for index, tokens := range chroma.SplitTokensIntoLines(iterator.Tokens()) { for index, tokens := range chroma.SplitTokensIntoLines(iterator.Tokens()) {
// TODO mono font looks better with 1.2 em (use px equivalent), but textmeasure needs to account for it. Not obvious how that should be done fmt.Fprintf(writer, "<text class=\"text-mono\" x=\"0\" y=\"%fem\">", 1+lineHeight*float64(index))
fmt.Fprintf(writer, "<text class=\"text-mono\" x=\"0\" y=\"%fem\" xml:space=\"preserve\">", 1*float64(index+1))
for _, token := range tokens { for _, token := range tokens {
text := svgEscaper.Replace(token.String()) text := svgEscaper.Replace(token.String())
attr := styleAttr(svgStyles, token.Type) attr := styleAttr(svgStyles, token.Type)

View file

@ -214,6 +214,14 @@ func (t *Ruler) scaleUnicode(w float64, font d2fonts.Font, s string) float64 {
return w return w
} }
func (t *Ruler) MeasureMono(font d2fonts.Font, s string) (width, height int) {
originalBoundsWithDot := t.boundsWithDot
t.boundsWithDot = true
width, height = t.Measure(font, s)
t.boundsWithDot = originalBoundsWithDot
return width, height
}
func (t *Ruler) Measure(font d2fonts.Font, s string) (width, height int) { func (t *Ruler) Measure(font d2fonts.Font, s string) (width, height int) {
w, h := t.MeasurePrecise(font, s) w, h := t.MeasurePrecise(font, s)
w = t.scaleUnicode(w, font, s) w = t.scaleUnicode(w, font, s)