wip
This commit is contained in:
parent
716f9d428a
commit
3a9a784342
6 changed files with 856 additions and 28 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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**
|
||||||
|
|
|
||||||
825
d2renderers/d2sketch/testdata/twitter/sketch.exp.svg
vendored
Normal file
825
d2renderers/d2sketch/testdata/twitter/sketch.exp.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 649 KiB |
|
|
@ -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
10
main.go
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue