## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  message = FALSE,
  warning = FALSE
)

## DOT rendering helper
.dot_available <- nzchar(Sys.which("dot"))

## CSS font-family chain ordered for cross-platform Helvetica-likeness:
## Helvetica resolves on macOS and Adobe-installed environments; Arial
## is Microsoft's metric-equivalent of Helvetica and resolves on Windows;
## Liberation Sans and DejaVu Sans cover Linux distributions; sans-serif
## is the universal CSS generic family that browsers always resolve.
.sans_chain <- "Helvetica, Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif"

render_dot <- function(dot_str, width = "100%", fmt = c("svg", "png"),
                       dpi = 150, sans_serif = TRUE) {
  fmt <- match.arg(fmt)
  if (.dot_available) {
    out <- paste0(knitr::fig_path(paste0(".", fmt)))
    fig_dir <- dirname(out)
    if (!dir.exists(fig_dir)) dir.create(fig_dir, recursive = TRUE)
    dot_in <- tempfile(fileext = ".dot")
    writeLines(dot_str, dot_in)
    args <- c(paste0("-T", fmt))
    if (fmt == "png") args <- c(args, paste0("-Gdpi=", dpi))
    args <- c(args, shQuote(dot_in), "-o", shQuote(out))
    system2("dot", args, stdout = NULL, stderr = NULL)

    ## Post-process SVG
    if (isTRUE(sans_serif) && fmt == "svg" && file.exists(out)) {
      svg_text <- paste(readLines(out, warn = FALSE), collapse = "\n")
      svg_text <- gsub('font-family="(Helvetica|Times)[^"]*"',
                       sprintf('font-family="%s"', .sans_chain),
                       svg_text, perl = TRUE)
      svg_text <- gsub("font-family='(Helvetica|Times)[^']*'",
                       sprintf("font-family=\"%s\"", .sans_chain),
                       svg_text, perl = TRUE)
      writeLines(svg_text, out)
    }

    knitr::include_graphics(out, dpi = NA)
  } else if (requireNamespace("DiagrammeR", quietly = TRUE)) {
    DiagrammeR::grViz(dot_str, width = width)
  } else {
    cat(dot_str)
  }
}

## ----setup--------------------------------------------------------------------
library(selecta)

## ----eval = FALSE-------------------------------------------------------------
# library(DiagrammeR)

## -----------------------------------------------------------------------------
example1 <- enroll(n = 500) |>
    phase("Enrollment") |>
    exclude("Ineligible", n = 65,
            reasons = c("Age < 18" = 30, "No consent" = 35),
            included_label = "Eligible") |>
    phase("Analysis") |>
    endpoint("Final cohort")

dot_str <- flowchart(example1, engine = "dot")
dot_str

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_str)

## -----------------------------------------------------------------------------
example2 <- enroll(n = 1200, label = "Assessed for eligibility") |>
    phase("Enrollment") |>
    exclude("Excluded", n = 300,
            reasons = c("Not meeting criteria" = 160,
                        "Declined" = 90, "Other" = 50)) |>
    phase("Allocation") |>
    allocate(labels = c("Drug A", "Placebo"), n = c(450, 450)) |>
    phase("Follow-up") |>
    exclude("Lost to follow-up", n = c(20, 20)) |>
    phase("Analysis") |>
    endpoint("Analyzed")

dot_2arm <- flowchart(example2, engine = "dot")
cat(dot_2arm)

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_2arm)

## -----------------------------------------------------------------------------
example3 <- sources(
    previous  = c("Previous review" = 12, "Previous reports" = 15),
    databases = c("PubMed" = 1234, "Embase" = 567, "CENTRAL" = 89),
    other     = c("Citation search" = 55, "Websites" = 34),
    headers   = c(previous  = "Previous studies",
                  databases = "Databases and registers",
                  other     = "Other methods")
) |>
    combine("Records identified", n = 2006) |>
    exclude("Duplicates removed", n = 352,
            included_label = "Records screened") |>
    exclude("Records excluded", n = 1100) |>
    endpoint("Studies included in review")

dot_prisma <- flowchart(example3, engine = "dot")
cat(dot_prisma)

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_prisma)

## -----------------------------------------------------------------------------
dot_palette <- flowchart(example3, engine = "dot",
                         box_fill           = "#fffbe6",  # warm cream
                         side_fill          = "#ffe0e0",  # light pink
                         source_fill        = "#fff5cc",  # pale yellow
                         source_header_fill = "#1f5b3a",  # dark green
                         source_header_text = "#ffffff",  # white text
                         border_col         = "#5a3a1a",  # warm brown
                         arrow_col          = "#5a3a1a")

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_palette)

## -----------------------------------------------------------------------------
dot_cf <- flowchart(example1, engine = "dot", count_first = TRUE)

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_cf)

## -----------------------------------------------------------------------------
dot_rich <- flowchart(example1, engine = "dot", formatting = "rich")

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_rich)

## -----------------------------------------------------------------------------
dot_times <- flowchart(example1, engine = "dot",
                       font_family = "Times-Roman")

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_times, sans_serif = FALSE)

## -----------------------------------------------------------------------------
dot_lr <- gsub("rankdir=TB", "rankdir=LR", dot_str)

## ----echo = FALSE, out.width = "100%"-----------------------------------------
render_dot(dot_lr)

## -----------------------------------------------------------------------------
dot_via_plot <- plot(example1, engine = "dot")
identical(dot_via_plot, dot_str)

## ----eval = FALSE-------------------------------------------------------------
# # SVG with cross-platform sans-serif rendering (default)
# flowsave(example1, "consort.svg", engine = "dot")
# 
# # PDF output (Helvetica baked into the file at render time)
# flowsave(example1, "consort.pdf", engine = "dot")
# 
# # PNG output at a requested DPI
# flowsave(example1, "consort.png", engine = "dot", dpi = 300)
# 
# # Raw DOT source for downstream editing or external tools
# flowsave(example1, "consort.dot", engine = "dot")

## ----eval = FALSE-------------------------------------------------------------
# flowsave(example1, "consort.svg", engine = "dot",
#          font_family = "Times-Roman", sans_serif = FALSE)

## ----eval = FALSE-------------------------------------------------------------
# library(DiagrammeR)
# 
# grViz(dot_str)

## ----eval = FALSE-------------------------------------------------------------
# widget <- DiagrammeR::grViz(dot_str)
# htmlwidgets::saveWidget(widget, "consort_diagram.html", selfcontained = TRUE)

## ----eval = FALSE-------------------------------------------------------------
# tmp <- tempfile(fileext = ".html")
# htmlwidgets::saveWidget(DiagrammeR::grViz(dot_str), tmp, selfcontained = TRUE)
# webshot2::webshot(tmp, file = "consort_diagram.png",
#                   vwidth = 800, vheight = 1000, delay = 0.5)

