Getting Current Image Name of SlickR Slideshow in Shiny Using MutationObserver API

Understanding SlickR Slideshow in Shiny

Introduction

SlickR is a popular JavaScript library used to create smooth and efficient image carousels. In this article, we will explore how to get the current image name of a SlickR slideshow in a Shiny application.

Shiny is an R framework for building web applications. It allows us to create interactive web pages with ease, using R code as the backend logic. SlickR is a crucial component in creating visually appealing and engaging web pages.

Problem Statement

In the given example, we have a Shiny application that displays a slideshow of images using SlickR. However, when we try to get the current image name, we encounter an issue. We need to find a way to retrieve this information without modifying the SlickR library itself.

Solution Overview

To solve this problem, we will use JavaScript and R together. The main concept employed here is the MutationObserver API in JavaScript, which allows us to observe changes to the DOM (Document Object Model) of an HTML element.

We will create a JavaScript function that uses MutationObserver to detect when the .slick-current class is added or removed from an image element. When this happens, we will update the Shiny application’s backend logic to reflect the current image index.

Using MutationObserver

First, let us define the JavaScript code that uses MutationObserver:

js <- "
$(document).ready(function(){
  var ss = document.getElementById('slickr');
  // create an observer instance
  var observer = new MutationObserver(function(mutations) {
    var index = $(ss).find('.slick-current').data('slick-index');
    Shiny.setInputValue('imageIndex', parseInt(index)+1);
  });
  // configuration of the observer
  var config = {subtree: true, attributes: true};
  // observe 
  observer.observe(ss, config);
})
"

In this code:

  • We first select the #slickr element using document.getElementById.
  • We create a new instance of MutationObserver and pass a function as its callback.
  • Inside the callback function:
    • We find the .slick-current class within the #slickr element and extract its data attribute, which contains the current image index.
    • We update Shiny’s input value for 'imageIndex' by incrementing the extracted index.

Next, we need to integrate this JavaScript code with our Shiny application. This involves adding a new script tag to the tags$head() section of our UI and passing the defined JavaScript code as its content.

Integrating MutationObserver into Shiny

To use MutationObserver in Shiny, we will modify our existing server function:

server <- function(input, output) {

  imgs <- list.files("~/", pattern=".png", full.names = TRUE)

  # Render the SlickR output
  output[["slickr"]] <- renderSlickR({
    slickR(imgs)
  })

  # Create a text output to display the current image name
  output[["imgName"]] <- renderText({
    paste0("CURRENT IMAGE: ", basename(imgs[input[["imageIndex"]]]))
  })

  # Set up MutationObserver in the UI
  ui <- fluidPage(
    tags$head(tags$script(HTML(js))),
    textOutput("imgName"),
    tags$hr(),
    slickROutput("slickr", width="500px")
  )

}

In this updated code:

  • We add a new tags$head() section that includes the JavaScript code.
  • We render a textOutput to display the current image name based on the imageIndex value from the Shiny input.

With these modifications, our application now uses MutationObserver to get the current image index and displays it in real-time.

Alternative Solution

Another approach to solving this problem is by using an event handler for the setPosition event emitted by SlickR. This method is simpler but does not use MutationObserver. Here’s how you can do it:

js <- "
$(document).ready(function(){
  $('#slickr').on('setPosition', function(event, slick) {
    var index = slick.currentSlide + 1;
    Shiny.setInputValue('imageIndex', index);
  });
})"

This JavaScript code attaches an event handler to the #slickr element for the setPosition event. Whenever this event occurs, it updates Shiny’s input value with the new image index.

Conclusion

In conclusion, we have discussed how to get the current image name of a SlickR slideshow in a Shiny application using JavaScript and R together. By utilizing the MutationObserver API, we can achieve real-time updates to the current image index without modifying the SlickR library itself.

We’ve also explored an alternative solution that uses the setPosition event emitted by SlickR, which is simpler but less flexible than the first approach.

Both methods provide a robust and efficient way to update the Shiny application in response to changes to the slideshow.


Last modified on 2024-03-06