ramnathv / slidify

Generate reproducible html5 slides from R markdown
http://www.slidify.org
844 stars 338 forks source link

Interactive Slide Decks #222

Closed ramnathv closed 11 years ago

ramnathv commented 11 years ago

I have pared down interactive slide decks to their bare minimum. A few more things that remain.

Hooks

Currently, the following code needs to be inserted into every interactive slide deck. I want to figure out an elegant way by which this can be made the default for interactive slides. One way is to extend the idea of a widget to R files that are sourced before slidifying. So for example, config.yml can contain a link to an R file that gets sourced in a local environment.

```{r setup, echo = F, cache = F, tidy = F}
knit_hooks$set(source = function(x, options){
  if (!is.null(options$interactive) && (options$interactive)){
    paste0("<textarea class='interactive' id='interactive{{slide.num}}' 
       data-cell='{{slide.num}}' data-results='", 
       options$results, "' style='display:none'>", 
      x, "</textarea>")
  } else {
    stringr::str_c("\n\n```", tolower(options$engine), "\n", x, "```\n\n")
  }
})
opts_chunk$set(tidy = FALSE, eval = FALSE, interactive = TRUE, results = 'asis')
ramnathv commented 11 years ago

Here is more code in server.R that needs to be packaged for easy reuse. Some are utility functions, while some need to be in shinyServer

require(shiny)
.slidifyEnv = new.env()
runCode <- function(code){
  require(knitr)
  chunk = paste('```{r echo = F,message = F, comment = NA, results = "asis"}\n', 
   code, "\n```", collapse = '\n')
  out = knit(text = chunk, envir = .slidifyEnv)
  markdown::markdownToHTML(text = out, fragment = TRUE)
}

# Function to dynamically extract cell numbers for all interactive cells
getCells <- function(){
  require(XML)
  doc = htmlParse('www/index.html')
  cells = getNodeSet(doc, '//textarea')
  as.numeric(sapply(cells, xmlGetAttr, 'data-cell'))
}

make_opencpu_version = function(){
  doc = paste(readLines('www/index.html', warn = F), collapse = '\n')
  doc = gsub('action-button', 'iBtn', doc, fixed = TRUE)
  doc = gsub('libraries/', 'www/libraries/', doc, fixed = TRUE)
  doc = gsub('./assets/', 'www/assets/', doc, fixed = TRUE)
  cat(doc, file = 'index.html')
}

shinyServer(function(input, output, session){
  print('Running Server')
  cells = getCells()
  invisible(lapply(cells, function(i){
    output[[paste0('knitResult', i)]] <- reactive({
      if (input[[paste0('runCode', i)]] != 0)
        return(isolate({
          print('running code')
          runCode(input[[paste0('interactive', i)]])
        }))
    })
    outputOptions(output, paste0('knitResult', i), suspendWhenHidden = F)
  }))
})
ramnathv commented 11 years ago

It would be nice if I can use runApp and specify ui and server as functions. It would then be possible to write a function that would automagically add these things.

ramnathv commented 11 years ago

This is DONE in the dev version.