This commit is contained in:
Alexander Wang 2022-12-21 21:58:56 -08:00
parent 716f9d428a
commit 3a9a784342
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
6 changed files with 856 additions and 28 deletions

View file

@ -9,6 +9,7 @@ import (
"oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes" "oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/d2themes/d2themescatalog" "oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/util-go/go2"
) )
func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) { func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) {
@ -16,8 +17,7 @@ func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2
diagram := d2target.NewDiagram() diagram := d2target.NewDiagram()
if fontFamily == nil { if fontFamily == nil {
defaultFont := d2fonts.SourceSansPro fontFamily = go2.Pointer(d2fonts.SourceSansPro)
fontFamily = &defaultFont
} }
diagram.FontFamily = fontFamily diagram.FontFamily = fontFamily

View file

@ -825,13 +825,13 @@ func findMeasured(mtexts []*d2target.MText, t1 *d2target.MText) *d2target.TextDi
return nil return nil
} }
func getMarkdownDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText) (*d2target.TextDimensions, error) { func getMarkdownDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText, fontFamily *d2fonts.FontFamily) (*d2target.TextDimensions, error) {
if dims := findMeasured(mtexts, t); dims != nil { if dims := findMeasured(mtexts, t); dims != nil {
return dims, nil return dims, nil
} }
if ruler != nil { if ruler != nil {
width, height, err := textmeasure.MeasureMarkdown(t.Text, ruler) width, height, err := textmeasure.MeasureMarkdown(t.Text, ruler, fontFamily)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -862,8 +862,7 @@ func getTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2
style = d2fonts.FONT_STYLE_ITALIC style = d2fonts.FONT_STYLE_ITALIC
} }
if fontFamily == nil { if fontFamily == nil {
defaultFont := d2fonts.SourceSansPro fontFamily = go2.Pointer(d2fonts.SourceSansPro)
fontFamily = &defaultFont
} }
w, h = ruler.Measure(fontFamily.Font(t.FontSize, style), t.Text) w, h = ruler.Measure(fontFamily.Font(t.FontSize, style), t.Text)
} }
@ -902,7 +901,7 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
dims = d2target.NewTextDimensions(width, height) dims = d2target.NewTextDimensions(width, height)
} else { } else {
var err error var err error
dims, err = getMarkdownDimensions(mtexts, ruler, obj.Text()) dims, err = getMarkdownDimensions(mtexts, ruler, obj.Text(), fontFamily)
if err != nil { if err != nil {
return err return err
} }

View file

@ -45,7 +45,7 @@ func TestSketch(t *testing.T) {
`, `,
}, },
{ {
name: "chess", name: "twitter",
script: `timeline mixer: "" { script: `timeline mixer: "" {
explanation: |md explanation: |md
## **Timeline mixer** ## **Timeline mixer**

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 649 KiB

View file

@ -66,8 +66,6 @@ var HeaderToFontSize = map[string]int{
"h6": FONT_SIZE_H6, "h6": FONT_SIZE_H6,
} }
var HeaderFonts map[string]d2fonts.Font
func RenderMarkdown(m string) (string, error) { func RenderMarkdown(m string) (string, error) {
var output bytes.Buffer var output bytes.Buffer
if err := markdownRenderer.Convert([]byte(m), &output); err != nil { if err := markdownRenderer.Convert([]byte(m), &output); err != nil {
@ -77,11 +75,6 @@ func RenderMarkdown(m string) (string, error) {
} }
func init() { func init() {
HeaderFonts = make(map[string]d2fonts.Font)
for header, fontSize := range HeaderToFontSize {
HeaderFonts[header] = d2fonts.SourceSansPro.Font(fontSize, d2fonts.FONT_STYLE_BOLD)
}
markdownRenderer = goldmark.New( markdownRenderer = goldmark.New(
goldmark.WithRendererOptions( goldmark.WithRendererOptions(
goldmarkHtml.WithUnsafe(), goldmarkHtml.WithUnsafe(),
@ -90,7 +83,7 @@ func init() {
) )
} }
func MeasureMarkdown(mdText string, ruler *Ruler) (width, height int, err error) { func MeasureMarkdown(mdText string, ruler *Ruler, fontFamily *d2fonts.FontFamily) (width, height int, err error) {
render, err := RenderMarkdown(mdText) render, err := RenderMarkdown(mdText)
if err != nil { if err != nil {
return width, height, err return width, height, err
@ -111,11 +104,9 @@ func MeasureMarkdown(mdText string, ruler *Ruler) (width, height int, err error)
}() }()
} }
font := d2fonts.SourceSansPro.Font(MarkdownFontSize, d2fonts.FONT_STYLE_REGULAR)
// TODO consider setting a max width + (manual) text wrapping // TODO consider setting a max width + (manual) text wrapping
bodyNode := doc.Find("body").First().Nodes[0] bodyNode := doc.Find("body").First().Nodes[0]
bodyAttrs := ruler.measureNode(0, bodyNode, font) bodyAttrs := ruler.measureNode(0, bodyNode, fontFamily, MarkdownFontSize)
return int(math.Ceil(bodyAttrs.width)), int(math.Ceil(bodyAttrs.height)), nil return int(math.Ceil(bodyAttrs.width)), int(math.Ceil(bodyAttrs.height)), nil
} }
@ -201,7 +192,12 @@ func (b *blockAttrs) isNotEmpty() bool {
} }
// measures node dimensions to match rendering with styles in github-markdown.css // measures node dimensions to match rendering with styles in github-markdown.css
func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) blockAttrs { func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.FontFamily, fontSize int) blockAttrs {
if fontFamily == nil {
fontFamily = go2.Pointer(d2fonts.SourceSansPro)
}
font := fontFamily.Font(fontSize, d2fonts.FONT_STYLE_REGULAR)
var parentElementType string var parentElementType string
if n.Parent != nil && n.Parent.Type == html.ElementNode { if n.Parent != nil && n.Parent.Type == html.ElementNode {
parentElementType = n.Parent.Data parentElementType = n.Parent.Data
@ -253,7 +249,8 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) bloc
isCode := false isCode := false
switch n.Data { switch n.Data {
case "h1", "h2", "h3", "h4", "h5", "h6": case "h1", "h2", "h3", "h4", "h5", "h6":
font = HeaderFonts[n.Data] fontSize = HeaderToFontSize[n.Data]
font = fontFamily.Font(HeaderToFontSize[n.Data], d2fonts.FONT_STYLE_BOLD)
originalLineHeight := ruler.LineHeightFactor originalLineHeight := ruler.LineHeightFactor
ruler.LineHeightFactor = LineHeight_h ruler.LineHeightFactor = LineHeight_h
defer func() { defer func() {
@ -264,6 +261,7 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) bloc
case "b", "strong": case "b", "strong":
font.Style = d2fonts.FONT_STYLE_BOLD font.Style = d2fonts.FONT_STYLE_BOLD
case "pre", "code": case "pre", "code":
fontFamily = go2.Pointer(d2fonts.SourceCodePro)
font.Family = d2fonts.SourceCodePro font.Family = d2fonts.SourceCodePro
font.Style = d2fonts.FONT_STYLE_REGULAR font.Style = d2fonts.FONT_STYLE_REGULAR
isCode = true isCode = true
@ -280,7 +278,7 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) bloc
// first create blocks from combined inline elements, then combine all blocks // first create blocks from combined inline elements, then combine all blocks
// current will be non-nil while inline elements are being combined into a block // current will be non-nil while inline elements are being combined into a block
for child := n.FirstChild; child != nil; child = child.NextSibling { for child := n.FirstChild; child != nil; child = child.NextSibling {
childBlock := ruler.measureNode(depth+1, child, font) childBlock := ruler.measureNode(depth+1, child, fontFamily, fontSize)
if child.Type == html.ElementNode && isBlockElement(child.Data) { if child.Type == html.ElementNode && isBlockElement(child.Data) {
if current != nil { if current != nil {
@ -354,7 +352,7 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) bloc
switch n.Data { switch n.Data {
case "blockquote": case "blockquote":
block.width += (2*PaddingLR_blockquote_em + BorderLeft_blockquote_em) * float64(font.Size) block.width += (2*PaddingLR_blockquote_em + BorderLeft_blockquote_em) * float64(fontSize)
block.marginBottom = go2.Max(block.marginBottom, MarginBottom_blockquote) block.marginBottom = go2.Max(block.marginBottom, MarginBottom_blockquote)
case "p": case "p":
if parentElementType == "li" { if parentElementType == "li" {
@ -366,7 +364,7 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) bloc
block.marginBottom = go2.Max(block.marginBottom, MarginBottom_h) block.marginBottom = go2.Max(block.marginBottom, MarginBottom_h)
switch n.Data { switch n.Data {
case "h1", "h2": case "h1", "h2":
block.height += PaddingBottom_h1_h2_em * float64(font.Size) block.height += PaddingBottom_h1_h2_em * float64(fontSize)
} }
case "li": case "li":
block.width += PaddingLeft_ul_ol block.width += PaddingLeft_ul_ol
@ -386,8 +384,8 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, font d2fonts.Font) bloc
block.marginBottom = go2.Max(block.marginBottom, MarginBottom_pre) block.marginBottom = go2.Max(block.marginBottom, MarginBottom_pre)
case "code": case "code":
if parentElementType != "pre" { if parentElementType != "pre" {
block.width += 2 * PaddingLeftRight_code_em * float64(font.Size) block.width += 2 * PaddingLeftRight_code_em * float64(fontSize)
block.height += 2 * PaddingTopBottom_code_em * float64(font.Size) block.height += 2 * PaddingTopBottom_code_em * float64(fontSize)
} }
case "hr": case "hr":
block.height += Height_hr block.height += Height_hr

10
main.go
View file

@ -14,10 +14,12 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"go.uber.org/multierr" "go.uber.org/multierr"
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/util-go/xmain" "oss.terrastruct.com/util-go/xmain"
"oss.terrastruct.com/d2/d2lib" "oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2plugin" "oss.terrastruct.com/d2/d2plugin"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2svg" "oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/d2themes" "oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/d2themes/d2themescatalog" "oss.terrastruct.com/d2/d2themes/d2themescatalog"
@ -210,11 +212,15 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketc
} }
layout := plugin.Layout layout := plugin.Layout
diagram, _, err := d2lib.Compile(ctx, string(input), &d2lib.CompileOptions{ opts := &d2lib.CompileOptions{
Layout: layout, Layout: layout,
Ruler: ruler, Ruler: ruler,
ThemeID: themeID, ThemeID: themeID,
}) }
if sketch {
opts.FontFamily = go2.Pointer(d2fonts.HandDrawn)
}
diagram, _, err := d2lib.Compile(ctx, string(input), opts)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }