Search code examples
d3.jsshinyshiny-serverhtmlwidgets

How to modify a js variable within a shiny server (htmlwidgets/R)


This question is more conceptual than explicit to a particular piece of code so I guess there's no toy-code this time.

I have a rather large shiny app that uses some d3.js scripts. The D3 objects access a few global variables when their update functions are called. I'd like to control these variables from the Shiny server - is this possible?


Solution

  • This app assumes the global variable was assigned to the window. Then it uses a custom message handler to create the original variable (#1) and another to manipulate the value of that variable (#2).

    Edited to have message sent back to R with the state of the global variable.

    R Code:

    library(shiny)
    
    ui <- fluidPage(
    
    # Application title
    titlePanel("Global Variable Manipulation"),
    
      mainPanel(
        sliderInput("data", "Element", min = 0, max = 100, value = 0),
        actionButton("go", "GO"),
        textOutput("var"),
        singleton(
          tags$head(tags$script(src = "message-handler.js"))
        ),
        singleton(
          tags$head(tags$script(src = "message-handler2.js"))
        ),
        singleton(
          tags$head(tags$script(src = "back-to-shiny.js"))
        )
      )
    
    )
    
    
    server <- function(input, output, session) {
    
      observe({
        session$sendCustomMessage(type = 'testmessage',
                                  message = list(a = 1, b = 'text',
                                                 controller = input$data))
      })
    
      observeEvent(input$go,{
        session$sendCustomMessage(type = 'changeMessage',
                                  message = list(2))
      })
    
      output$var <- renderPrint({
        input$jsvalue
      })
    }
    
    # Run the application 
    shinyApp(ui = ui, server = server)
    

    message-handler.js code:

    Shiny.addCustomMessageHandler("testmessage",
      function(message) {
         window.globalVar = message.controller
        alert(JSON.stringify(window.globalVar));
      }
    );
    

    message-handler2.js code:

    Shiny.addCustomMessageHandler("changeMessage",
      function(message) {
        window.globalVar = window.globalVar-message;
        alert(JSON.stringify(window.globalVar));
      }
    );
    

    back-to-shiny.js code:

    setInterval(function(){
        var message = window.globalVar;   
        Shiny.onInputChange("jsvalue", message);
    },0);