September 13, 2016

Goals of this talk

Why haven't I built my own Shiny widgets?

Why haven't I installed this awesome drag and drop package?

Why R?

  • Easy to learn?
  • Great stats packages?
  • Large user community?
  • It's free?
Data %>% Insights

Why Shiny?

Data %>% Insights %>% Dashboard!

But if you just want to share your insights, why not just use pandoc/knitr/Rmarkdown?

Why did RStudio build Shiny?

If I want others to interact with my R code, why do I need HTML and Javascript?

Data %>% Insights %<>% Dashboard!

ShinyDND

  • create draggable elements and style with css
dragUI("mydrag", "Element Name", style = "background-color:red", class = "dragelement")
  • create a drop area with an internal grid
dropUI("mydrop", row_n = 4, col_n = 3)
  • create a set of draggable elements
dragSetUI("mydragset", textval = names(mtcars))
  • make dropping things reactive
observeEvent(input$mydrop, {
    output$myplot = renderPlot(input$drop_xval, input$drop_yval)
})

Available on CRAN (shinyDND) or devtools::install_github('ayayron/shinydnd')

Defining the drag and drop elements

dragUI <- function (id, ..., style = NULL, class = "dragelement") {
    dragUI = htmltools::tags$div(id = id, class = class, draggable = TRUE, 
        style = style, list(...))
    htmltools::attachDependencies(dragUI, shinyDNDDep) }
dropUI <- function (id, style = NULL, class = "dropelement", row_n = 1, col_n = 1) {
    if (row_n > 1 | col_n > 1) {
        row_pct = 100/row_n; col_pct = 100/col_n;
        div_element = htmltools::tags$div(style = paste0("height:", 
            row_pct, "%;", "width:", col_pct, "%;", "display:table-cell;"))
        div_row = list(htmltools::tags$div(rep(list(div_element), 
            col_n), style = paste0("height:", row_pct, "%;", 
            "width:", col_pct, "%;", "display:table-row;")))
        divlist = rep(div_row, row_n)
    }
  ...

Defining the drag and drop functionality - In JS

//on document ready doesn't work with newly created renderUI() elements
$(document).bind('DOMNodeInserted', function(){ 
  $(".dropelement").on("dragover",function(e){
    e.preventDefault();
  });
  $(".dragelement").on("dragstart",function(e){
    e.originalEvent.dataTransfer.setData("Text",e.target.id);
  });
  $(".dropelement").on("drop",function(e){
    e.preventDefault();
    var data=e.originalEvent.dataTransfer.getData("Text");
    e.target.appendChild(document.getElementById(data));
    var el = $(e.target);
    el.trigger("change");
  });
});

Extending Shiny.inputBindings() to build reactivity

var dragDropBinding = new Shiny.InputBinding();
// Create reactivity for a drop element
$.extend(dragDropBinding, {
  find: function(scope) {return $(scope).find(".dropelement");},
  getValue: function(el) {return $(el).text();},
  setValue: function(el) {$(el).text();},
  subscribe: function(el, callback) {
    $(el).on("change", function(e) {callback();});},
  unsubscribe: function(el) {$(el).off(".dragDropBinding");},
  getType: function() {return "dragdropshiny.dropper";}
});

Shiny.inputBindings.register(dragDropBinding);

Attach dependencies to bring it all together

.onAttach <- function(...) {
    # register the js input handler to make the element reactive
    shiny::registerInputHandler("dragdropshiny.dropper", function(data,...) {
        if (is.null(data) | data == "")
          return(NULL)
        else
          return(data)
    }, force = TRUE)

  # Create link to javascript and css files for package, referenced below
  shiny::addResourcePath("shinydnd", system.file("www", package = "shinyDND"))
}

# htmlDependency js and css will be used in other functions with attachDependency
shinyDNDDep = htmltools::htmlDependency("shinyDND", packageVersion("shinyDND"), 
    src = c("href" = "shinydnd"), script = "dragndrop.js", stylesheet = "dragndrop.css")

ShinyDND

Don't need 's, need PRs!

  • Would be great to add more examples where people are using it; I'd be happy to add links to the Readme.
  • Let me know of any issues/missing functionality (with solutions even better!)
  • Tell RStudio you want it in Shiny

Be a Shiny Pioneer!

Good Artists Copy; Great Artists (take open source tools built in other languages and adapt them to be available in their language of choice)

  • Think small: shiny, like other software development, uses small/flexible functions/elements to allow developers to build complex systems
  • learn from others:
    • building input (shiny.rstudio.com/articles/building-inputs.html)
    • shinyjs (github.com/daattali/shinyjs)
    • shinyBS (github.com/ebailey78/shinyBS)
    • radiant (github.com/vnijs/radiant)

Thank you!

ayayron.shinyapps.io/ShinyDND_BARUG_Lightning_Talk_Sept2016