Introduction to shinyjqui

Yang Tang

2017-03-04

The shinyjqui package provides functions to give shiny ui mouse-interactions and animation effects. This vignette provides some general introductions and examples.

The includeJqueryUI function

Please first call includeJqueryUI() in ui of a shiny app before using other shinyjqui functions. This function loads some necessary js and css into the head of a shiny html document.

Interaction funcions

There are five kinds of mouse interactions in jQuery UI library:

Here are the corresponding R wrappers in shinyjqui:

Functions Description Where_to_use
jqui_draggable Enable or disable element’s draggable interaction. server
jqui_draggabled Initialize an element as draggable. ui
jqui_droppable Enable or disable element’s droppable interaction. server
jqui_droppabled Initialize an element as droppable. ui
jqui_resizable Enable or disable element’s resizable interaction. server
jqui_resizabled Initialize an element as resizable. ui
jqui_selectable Enable or disable element’s selectable interaction. server
jqui_selectabled Initialize an element as selectable. ui
jqui_sortable Enable or disable element’s sortable interaction. server
jqui_sortabled Initialize an element as sortable. ui

General usage

For each interaction, there are two functions: -able() and -abled(). They both can make a shiny html element interactive, but should be used in different places. The -abled() functions are designed to be used in ui of a shiny document. They return a modified element (tag, tagList, input or output) with interaction enabled. The -able() functions modify the interactivity of existing (pre-defined in ui) elements and therefore should be placed in server of a shiny document. For example, you can make a textInput draggable either by:

# in shiny ui
jqui_draggabled(textInput('input', 'Input'))

or in this way:

# in shiny ui
textInput('input', 'Input')

# in shiny server, either outside or in observe() or ovservEvent()
jqui_draggable(selector = '#input')

The -able() functions use jQuery selector to identify which element to act on. In the above example, the selector #input refers to the element with id input. So you can make all the shiny inputs draggable by jqui_draggable(selector = '.shiny-bound-input').

For -abled() functions, you can also make multiple elements interactive by wrapping them with tagList():

# in shiny ui, make each element in the tagList draggable
jqui_draggabled(tagList(
  selectInput('sel', 'Select', choices = month.abb),
  checkboxGroupInput('chbox', 'Checkbox', choices = month.abb),
  plotOutput('plot', width = '400px', height = '400px')
))

The -able() functions have a switch parameter. Set it as FALSE to disable the interaction of an element:

# in shiny server
jqui_draggable(selector = '#input', switch = FALSE)

Both -able() and -abled() functions have an options parameter to let you pass interaction-specific options. You can find available options on jQuery UI’s API Documentation page. Some examples about these options are listed in the next few sections.

Once an interaction is turned on and if the target element has an id, you can get access to some pre-defined interaction-specific shiny input values through input$id_suffix, where the id is the id of target element (id attribute for shiny tag, inputId for shiny inputs, outputId for shiny outputs) and the suffix depends on the interaction you enabled. Please see the following table:

Interactions suffix shiny.input.value
draggagle position A list of the element’s left and top distances in px to its parent
droppable dragging The id of an acceptable element that is now dragging
resizable size A list of the element’s size
selectable selected A dataframe containing the id and innerHTML of curently selected elements
sortable order A dataframe containing the id and innerHTML of curently order of elements

You can even customize these shiny input values by including a shiny option in the options parameter. The shiny option is a list in the following format:

shiny_opt = list(
  
  # define the shiny input value input$id_suffix1
  suffix1 = list(
    # on event_type1 run callback1 and send the returned value to input$id_suffix1
    event_type1 = htmlwidgets::JS(callback1),
    # on event_type2 run callback2 and send the returned value to input$id_suffix1
    event_type2 = htmlwidgets::JS(callback2),
    ...
  ),
  
  # define the shiny input value input$id_suffix2
  suffix2 = list(
    ...
  ),
  
  # define other shiny input values
  
)

Each element of the list is also a list that define a shiny input value. Its name is used as siffix in input$id_suffix. Within that list, there are multiple htmlwidgets::JS wrapped javascript callback functions named with corresponding event types. The event triggers the callback to run and the returned value is used to update the shiny input value. The valid event types for each interactions can be found in the API Documentation of jQuery UI. The callcack function takes two arguments, event and ui. The definition of the ui argument can also be found in that document too. Here is a simple example of draggable interaction:

jqui_draggable('#foo', options = list(
  shiny = list(
    # By default, draggable element has a shiny input value showing the element 
    # position (relative to the offset parent). Here, another shiny input
    # value is added. It gives the element offset (position relative to the 
    # document). Using input$foo_offset to get access to it . 
    offset = list(
      # return the initiated offset value when the draggable is created
      dragcreate = htmlwidgets::JS('function(event, ui) { return $(event.target).offset(); };'),
      # update the offset value while dragging
      drag = htmlwidgets::JS('function(event, ui) { return $(event.target).offset(); };')
    )
  )
))

Draggable

Draggable element can be moved by mouse. You can custom the movement by options:

# drag only horizontally
jqui_draggable('#foo', options = list(axis = 'x'))
# make movement snapping to a 80 x 80 grid
jqui_draggable('#foo', options = list(grid = c(80, 80)))

Droppable

With the droppable interaction enabled, the element can sense the behavior of accepted draggable elements and make changes (e.g. change display style) accordingly:

jqui_droppable('#foo', options = list(
  accept = '#bar', # Which draggable element to monitor.
  classes = list(
    `ui-droppable-active` = 'ui-state-active', # change class when draggable element is dragging
    `ui-droppable-hover` = 'ui-state-hover' # change class when draggable element is dragging over
  ),
  drop = htmlwidgets::JS(
    'function(event, ui){$(this).addClass("ui-state-highlight");}'
  ) # change class when draggable element is dropped in
))

Note: When passing a javascrip callback function to the opations parameter, please wrap it with htmlwidgets::JS() so that it can be evaled correctly.

Resizable

You can change the size of a resizable element by dragging the resize-handles around it. Several examples are listed here:

# keep aspect ratio when resizing
jqui_resizable('#foo', options = list(aspectRatio = TRUE))

# Limit the resizable element to a maximum or minimum height or width
jqui_resizable('#foo', options = list(minHeight = 100, maxHeight = 300,
                                      minWidth = 200, maxWidth = 400))

# make the two plotOutputs resize synchronously
jqui_resizabled(plotOutput('plot1', width = '400px', height = '400px'), 
                options = list(alsoResize = '#plot2')),
jqui_resizabled(plotOutput('plot2', width = '400px', height = '400px'), 
                options = list(alsoResize = '#plot1'))

Selectable

The selectable interaction make target element’s children selectable. You can select by click, Ctrl+click or dragging a box (lasso selection). The selected elements may change display styles if specified in options:

# highlight the selected plotOutput
jqui_selectabled(
  div(
    plotOutput('plot1', width = '400px', height = '400px'),
    plotOutput('plot2', width = '400px', height = '400px')
  ),
  options = list(classes = list(`ui-selected` = 'ui-state-highlight'))
)

Sortable

The sortable interaction makes target element’s children sortable. You can re-arrange them by drag and drop. Some examples here:

# change opacity while sorting
jqui_sortable('#foo', options = list(opacity = 0.5))

# only items with class "items" inside the element become sortable
jqui_sortable('#foo', options = list(items = '> .items'))

# connect two sortable elements, so that items in one element can be dragged to another
jqui_sortable('#foo1', options = list(connectWith = '#foo2'))
jqui_sortable('#foo2', options = list(connectWith = '#foo1'))

shinyjqui has a function called orderInput(). You can use it to display the order of a vector in shiny and users can change the order by drag and drop. The changed items order is send back to server as an input value. Please see the Vignette orderInput for details.

Animation effects functions

These functions apply an animation effect to an element:

Functions Description Where_to_use
jqui_effect Let element(s) to show an animation immediately. server
jqui_show Display hidden element(s) with an animation server
jqui_hide Hide element(s) with an animation server

The above three functions use jQuery selector to locate the target element(s) and should be used in server.

The effect parameter accept a string that defines which animation effect to apply. You can get a full list of animation effects by get_jqui_effects():

##  [1] "blind"     "bounce"    "clip"      "drop"      "explode"  
##  [6] "fade"      "fold"      "highlight" "puff"      "pulsate"  
## [11] "scale"     "shake"     "size"      "slide"     "transfer"

There is a live demo for each effect here. Note: The transfer effect can only be used in jqui_effect().

The options parameter accept a list of effect specific options. Please find more details here. The complete parameter accept a javascript callback function which will be called after the animation. Please wrap it with htmlwidgets::JS().

Here are some examples:

# in shiny ui
plotOutput('foo', width = '400px', height = '400px')

# in shiny server
jqui_effect('#foo', effect = 'bounce') # bounces the plot
jqui_effect('#foo', effect = 'scale', options = list(percent = 50)) # scale to 50%
jqui_hide('#foo', effect = 'size', options = list(width = 200, height = 60)) # resize then hide
jqui_show('#foo', effect = 'clip') # show the plot by clipping

Classes animation functions

These functions change shiny elements’ class(es) while animating all style changes:

Functions Description Where_to_use
jqui_add_class Add class(es) to element(s) while animating all style changes. server
jqui_remove_class Remove class(es) from element(s) while animating all style changes. server
jqui_switch_class Add and remove class(es) to element(s) while animating all style changes. server

Similar to the animation effects functions, these functions need a jQuery selector and please use them in server.

The easing parameter defines the speed style of the animation progresses. More details can be found here