d2/d2renderers/d2latex/latex.go

82 lines
1.8 KiB
Go
Raw Normal View History

2022-11-27 17:17:29 +00:00
package d2latex
import (
_ "embed"
"fmt"
2022-11-27 21:54:41 +00:00
"math"
"regexp"
"strconv"
2022-11-27 17:17:29 +00:00
2022-12-03 20:13:56 +00:00
"github.com/dop251/goja"
2022-12-01 19:32:57 +00:00
"oss.terrastruct.com/util-go/xdefer"
2022-11-27 17:17:29 +00:00
)
2022-11-28 19:46:21 +00:00
var pxPerEx = 8
2022-11-27 17:17:29 +00:00
//go:embed polyfills.js
var polyfillsJS string
//go:embed setup.js
var setupJS string
//go:embed mathjax.js
var mathjaxJS string
2022-11-28 19:46:21 +00:00
// Matches this
// <svg style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="563" height="326" viewBox="-100 -100 563 326"><style type="text/css">
2022-11-27 21:54:41 +00:00
var svgRe = regexp.MustCompile(`<svg[^>]+width="([0-9\.]+)ex" height="([0-9\.]+)ex"[^>]+>`)
2022-11-28 06:52:48 +00:00
func Render(s string) (_ string, err error) {
defer xdefer.Errorf(&err, "latex failed to parse")
2022-12-03 20:13:56 +00:00
vm := goja.New()
2022-11-27 17:17:29 +00:00
2022-12-03 20:13:56 +00:00
if _, err := vm.RunString(polyfillsJS); err != nil {
2022-11-27 17:17:29 +00:00
return "", err
}
2022-12-03 20:13:56 +00:00
if _, err := vm.RunString(mathjaxJS); err != nil {
2022-11-27 17:17:29 +00:00
return "", err
}
2022-12-03 20:13:56 +00:00
if _, err := vm.RunString(setupJS); err != nil {
2022-11-27 17:17:29 +00:00
return "", err
}
2022-12-03 20:13:56 +00:00
val, err := vm.RunString(fmt.Sprintf(`adaptor.innerHTML(html.convert(`+"`"+"%s`"+`, {
2022-11-28 19:46:21 +00:00
em: %d,
ex: %d,
2022-12-03 20:13:56 +00:00
}))`, s, pxPerEx*2, pxPerEx))
2022-11-27 17:17:29 +00:00
if err != nil {
return "", err
}
return val.String(), nil
}
2022-11-27 21:54:41 +00:00
2022-11-28 06:52:48 +00:00
func Measure(s string) (width, height int, err error) {
defer xdefer.Errorf(&err, "latex failed to parse")
2022-11-27 21:54:41 +00:00
svg, err := Render(s)
if err != nil {
return 0, 0, err
}
dims := svgRe.FindAllStringSubmatch(svg, -1)
if len(dims) != 1 || len(dims[0]) != 3 {
return 0, 0, fmt.Errorf("svg parsing failed for latex: %v", svg)
}
wEx := dims[0][1]
hEx := dims[0][2]
wf, err := strconv.ParseFloat(wEx, 64)
if err != nil {
return 0, 0, fmt.Errorf("svg parsing failed for latex: %v", svg)
}
hf, err := strconv.ParseFloat(hEx, 64)
if err != nil {
return 0, 0, fmt.Errorf("svg parsing failed for latex: %v", svg)
}
2022-11-28 19:46:21 +00:00
return int(math.Ceil(wf * float64(pxPerEx))), int(math.Ceil(hf * float64(pxPerEx))), nil
2022-11-27 21:54:41 +00:00
}