use scale flag for no-fit and customizing zoom

This commit is contained in:
Gavin Nishizawa 2023-06-15 15:53:23 -07:00
parent b8436358fb
commit 8563cf83c6
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
5 changed files with 84 additions and 34 deletions

View file

@ -80,6 +80,9 @@ Renders the diagram to look like it was sketched by hand
.It Fl -center Ar flag
Center the SVG in the containing viewbox, such as your browser screen
.Ns .
.It Fl -scale Ar fit
Set a fixed render scale (e.g. 0.5 to halve rendered size). If none provided, SVG will fit to screen
.Ns .
.It Fl -font-regular
Path to .ttf file to use for the regular font. If none provided, Source Sans Pro Regular is used
.Ns .

View file

@ -107,6 +107,7 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
if err != nil {
return err
}
scaleFlag := ms.Opts.String("SCALE", "scale", "", "fit", "set a fixed render scale (e.g. 0.5 to halve rendered size). If none provided, SVG will fit to screen.")
fontRegularFlag := ms.Opts.String("D2_FONT_REGULAR", "font-regular", "", "", "path to .ttf file to use for the regular font. If none provided, Source Sans Pro Regular is used.")
fontItalicFlag := ms.Opts.String("D2_FONT_ITALIC", "font-italic", "", "", "path to .ttf file to use for the italic font. If none provided, Source Sans Pro Regular-Italic is used.")
@ -232,6 +233,14 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
}
ms.Log.Debug.Printf("using dark theme %s (ID: %d)", match.Name, *darkThemeFlag)
}
var scale *float64
if scaleFlag != nil && *scaleFlag != "fit" {
f, err := strconv.ParseFloat(*scaleFlag, 64)
if err != nil || f <= 0. {
return xmain.UsageErrorf("-scale must a positive floating point number or \"fit\".")
}
scale = &f
}
plugin, err := d2plugin.FindPlugin(ctx, ps, *layoutFlag)
if err != nil {
@ -282,6 +291,7 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
Center: *centerFlag,
ThemeID: *themeFlag,
DarkThemeID: darkThemeFlag,
Scale: scale,
}
if *watchFlag {
@ -665,14 +675,20 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug
func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([]byte, error) {
toPNG := getExportExtension(outputPath) == PNG
var scale *float64
if opts.Scale != nil {
scale = opts.Scale
} else if toPNG {
scale = go2.Pointer(1.)
}
svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
MasterID: opts.MasterID,
SetDimensions: toPNG,
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
MasterID: opts.MasterID,
Scale: scale,
})
if err != nil {
return nil, err
@ -746,11 +762,18 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
// make the bg fill within the png transparent so that the pdf bg fill is the only bg color present
diagram.Root.Fill = "transparent"
var scale *float64
if opts.Scale != nil {
scale = opts.Scale
} else {
scale = go2.Pointer(1.)
}
svg, err = d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
SetDimensions: true,
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
Scale: scale,
})
if err != nil {
return nil, err
@ -837,12 +860,20 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present
// make the bg fill within the png transparent so that the pdf bg fill is the only bg color present
diagram.Root.Fill = "transparent"
var scale *float64
if opts.Scale != nil {
scale = opts.Scale
} else {
scale = go2.Pointer(1.)
}
var err error
svg, err = d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
SetDimensions: true,
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
Scale: scale,
})
if err != nil {
return nil, err
@ -1076,11 +1107,18 @@ func buildBoardIDToIndex(diagram *d2target.Diagram, dictionary map[string]int, p
func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, ruler *textmeasure.Ruler, page playwright.Page, diagram *d2target.Diagram) (svg []byte, pngs [][]byte, err error) {
if !diagram.IsFolderOnly {
var scale *float64
if opts.Scale != nil {
scale = opts.Scale
} else {
scale = go2.Pointer(1.)
}
svg, err = d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
SetDimensions: true,
Pad: opts.Pad,
Sketch: opts.Sketch,
Center: opts.Center,
Scale: scale,
})
if err != nil {
return nil, nil, err

View file

@ -35,12 +35,16 @@ function init(reconnectDelay) {
let width = parseInt(svgEl.getAttribute("width"), 10);
let height = parseInt(svgEl.getAttribute("height"), 10);
if (isInit) {
if (width > height) {
if (width > window.innerWidth) {
ratio = window.innerWidth / width;
if (msg.scale) {
ratio = msg.scale;
} else {
if (width > height) {
if (width > window.innerWidth) {
ratio = window.innerWidth / width;
}
} else if (height > window.innerHeight) {
ratio = window.innerHeight / height;
}
} else if (height > window.innerHeight) {
ratio = window.innerHeight / height;
}
// Scale svg fit to zoom
isInit = false;

View file

@ -83,8 +83,9 @@ type watcher struct {
}
type compileResult struct {
SVG string `json:"svg"`
Err string `json:"err"`
SVG string `json:"svg"`
Scale *float64 `json:"scale,omitEmpty"`
Err string `json:"err"`
}
func newWatcher(ctx context.Context, ms *xmain.State, opts watcherOpts) (*watcher, error) {
@ -372,8 +373,9 @@ func (w *watcher) compileLoop(ctx context.Context) error {
w.ms.Log.Error.Print(errs)
}
w.broadcast(&compileResult{
SVG: string(svg),
Err: errs,
SVG: string(svg),
Scale: w.renderOpts.Scale,
Err: errs,
})
if firstCompile {

View file

@ -75,8 +75,8 @@ type RenderOpts struct {
ThemeID int64
DarkThemeID *int64
Font string
// disables the fit to screen behavior and ensures the exported svg has the exact dimensions
SetDimensions bool
// the svg will be scaled by this factor, if unset the svg will fit to screen
Scale *float64
// MasterID is passed when the diagram should use something other than its own hash for unique targeting
// Currently, that's when multi-boards are collapsed
@ -1648,7 +1648,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
pad := DEFAULT_PADDING
themeID := DEFAULT_THEME
darkThemeID := DEFAULT_DARK_THEME
setDimensions := false
var scale *float64
if opts != nil {
pad = opts.Pad
if opts.Sketch {
@ -1660,7 +1660,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
}
themeID = opts.ThemeID
darkThemeID = opts.DarkThemeID
setDimensions = opts.SetDimensions
scale = opts.Scale
}
buf := &bytes.Buffer{}
@ -1851,8 +1851,11 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
}
var dimensions string
if setDimensions {
dimensions = fmt.Sprintf(` width="%d" height="%d"`, w, h)
if scale != nil {
dimensions = fmt.Sprintf(` width="%d" height="%d"`,
int(math.Ceil((*scale)*float64(w))),
int(math.Ceil((*scale)*float64(h))),
)
}
alignment := "xMinYMin"