shinyjqui
package provides APIs to the jQuery UI
JavaScript library that can be used to add mouse-interactions and animation effects to shiny app. The vignette provides general introductions and examples of them.
There are five kinds of mouse interactions in jQuery UI
library:
Draggable: Allow elements to be moved using the mouse.
Droppable: Create targets for draggable elements.
Resizable: Change the size of an element using the mouse.
Selectable: Use the mouse to select elements, individually or in a group.
Sortable: Reorder elements in a list or grid using the mouse.
The R wrappers provided in this package are jqui_draggable()
, jqui_droppable()
, jqui_resizable()
, jqui_selectable()
and jqui_sortable()
, which are designed to add corresponding interaction effects to shiny ui element(s).
These mouse interaction functions can be used in either shiny ui
(ui mode) or server
function (server mode)
In ui mode, the functions accept a shiny ui object (tag, tagList, input or output) and return a modified one with mouse interaction effect attached. For example:
# create a draggable textInput in shiny ui
ui <- fluidPage(
jqui_draggable(textInput("foo", "Input"))
)
In server mode, the functions add, modify or remove the interactivity of an existing (pre-defined in ui
) ui element:
# create a textInput in shiny ui without mouse interaction
ui <- fluidPage(
textInput("foo", "Input")
)
# make the ui element with id "foo" draggable
server <- function(input, output) {
jqui_draggable(ui = "#foo", operation = "enable")
}
The ui mode is the most straight forward way to create an ui element with mouse interactions, however, the server mode is more flexible. For example, in server mode, you can reactively control element’s interactivity through observe()
or observEvent()
, you can use a jQuery selector or even a JavaScript expression to locate the target element(s), and you can control the interaction effects with the operation
parameter. (see introduction in the following sections).
ui
parameterThis parameter ui
determine the target ui element(s) to be manipulated. The following table summarized the type of object it accepts in different context:
Mode | Type | Example |
---|---|---|
ui | A shiny.tag or shiny.tag.list object |
tags$p('hello world') , textInput('caption', 'Caption', 'Data Summary') , plotOutput('myplot') |
server | A string of jQuery_selector | '#id1,#id2,#id3' , '.shiny-plot-output' , 'div > p' |
server | A htmlwidgets::JS() wrapped javascript expression that returns a jQuery object |
JS("$('#id').children()") |
non-shiny | A static htmlwidget object |
plot_ly(z = ~volcano, type = "surface") |
operation
parameterThis parameter is valid only in server mode. It determines how to manipulate the interaction, which includes:
enable
: Initiate the corresponding mouse interaction to the target(s).disable
: Initiate the interaction if not and temporary disable it (only set the options).destory
: Completely remove the interaction.save
: Initiate the interaction if not and save the current interaction state.load
: Initiate the interaction if not and restore the target(s) to an user defined interaction state or the last saved state.enable
is the default setting of the parameter. save
and load
can be used to save and restore the state (e.g. size, position, order) of an element. More details in the Vignette Save and restore
.
options
parameterThe options
parameter can be used to further specify the behavior of interaction. The full list of the available options can be found in jQuery UI’s API Documentation page. Here are some examples:
Draggable element can be moved by mouse. You can custom its movement by some options:
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', # jQuery selector to define which draggable element to monitor. Accept anything if not set.
classes = list(
`ui-droppable-active` = 'ui-state-focus', # change class when draggable element is dragging
`ui-droppable-hover` = 'ui-state-highlight' # change class when draggable element is dragging over
),
drop = JS(
'function(event, ui){$(this).addClass("ui-state-active");}'
) # a javascrip callback to change class when draggable element is dropped in
))
Note: When passing a JavaScript callback function to the opations
parameter, please wrap it with JS()
so that it can be evaluated correctly.
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_resizable(plotOutput('plot1', width = '400px', height = '400px'),
options = list(alsoResize = '#plot2')),
plotOutput('plot2', width = '400px', height = '400px')
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
:
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'))
shiny
optionsIn shiny, the user input values are send back to server in the form of input$<id>
. Similarly, once enabled, the interaction-specific state values are returned to server and can be accessed by input$<id>_<suffix>
, where the id
is the element id (id
attribute for shiny tag, inputId
for shiny inputs, outputId
for shiny outputs) and the suffix
depends on the type of interaction enabled. The currently deployed interaction state values are listed here:
Interaction_type | suffix | The_returned_shiny_input_value |
---|---|---|
draggable | position | A list of the element’s left and top distances (in pixels) to its parent element |
draggable | is_dragging | TRUE or FALSE that indicate whether the element is dragging |
droppable | dragging | The id of an acceptable element that is now dragging |
droppable | over | The id of the last acceptable element that is dragged over |
droppable | drop | The id of the last acceptable element that is dropped |
droppable | dropped | The ids of all acceptable elements that is currently dropped |
droppable | out | The id of the last acceptable element that is dragged out |
resizable | size | A list of the element’s current size |
resizable | is_resizing | TRUE or FALSE that indicate whether the element is resizing |
selectable | selected | A dataframe containing the id and innerText of curently selected items |
selectable | is_selecting | TRUE or FALSE that indicate whether the element is selecting (e.g. during lasso selection) |
sortable | order | A dataframe containing the id and innerText of items in the current order |
You can even customize what value to be send back by including a shiny
option in the options
parameter. This option should be created in the following format. You may combine it with other interaction-specific options before passing to the options
parameter:
shiny_opt = list(
# define shiny input value input$id_suffix1
suffix1 = list(
# on event_type1 run callback1 and send the returned value to input$id_suffix1
event_type1 = JS(callback1),
# on event_type2 or event_type3 run callback2 and send the returned value to input$id_suffix1
`event_type2 event_type3` = JS(callback2),
...
),
# define another shiny input value input$id_suffix2
suffix2 = list(
...
),
# define more shiny input values
)
# pass the shiny option to draggable
jqui_draggable('#foo', options = list(
shiny = shiny_opt,
#other draggable-specific options
))
The shiny option list is composed by multiple suffix
definition units. The unit name is used as suffix
in input$<id>_<suffix>
. Within each unit, there are multiple JS()
wrapped JavaScript callback functions named with corresponding event types. The event triggers the callback and the returned value is send to server in the form of input$<id>_<suffix>
. The valid event types for each interactions can be found in the API Documentation of jQuery UI. The callback functions take two parameters, event
and ui
. The definition of the ui
parameter can also be found in the document too. Here is an example:
# server
jqui_draggable('#foo', options = list(
shiny = list(
# By default, draggable element has a shiny input value showing the
# element's position (relative to the parent element). Here, another shiny
# input value (input$foo_offset) is added. It gives the element's offset
# (position relative to the document).
offset = list(
# return the updated offset value when the draggable is created or dragging
`dragcreate drag` = JS('function(event, ui) {return $(event.target).offset();}'),
)
)
))
When customizing shiny input values by shiny option and callbacks, you may want to get the id of certain element in JavaScript. For simple shiny tag (e.g. tags$div
), element.attr("id")
just works fine, however, things become more complicated for shiny inputs (e.g. textInput
). The id attribute of most shiny inputs is hidden inside a div container. You may use jQuery function .find()
to locate it. The shinyjqui
package comes with an internal JavaScript function shinyjqui.getId()
which will take care of this. You can just simply pass in any shiny element, either simple tag, shiny input or shiny output. It will use the appropriate way to find out the id.
jQuery UI library comes with 15 internal animation effects. You can get a full list of them by R function get_jqui_effects()
:
#> [1] "blind" "bounce" "clip" "drop" "explode" "fade"
#> [7] "fold" "highlight" "puff" "pulsate" "scale" "shake"
#> [13] "size" "slide" "transfer"
There is a live demo for each effect here. By use following functions, you can apply these effects to a shiny ui element as well:
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 |
jqui_toggle | Display or hide element(s) with an animation | server |
The above functions works only in server mode.
The effect
parameter accept a string that defines which animation effect to apply. 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 JS()
.
Here are some examples:
# ui
plotOutput('foo', width = '400px', height = '400px')
# 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
These functions can be used to change shiny element’s 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 are all server-only.
The easing
parameter defines the speed style of the animation progresses. More details can be found here