I am trying to implement into.js multipage functionality on a Shiny app.
The code bellow is an attempt that does not work. The first tab works nicely, the popup for the second page is displayed but without switching the tab.
ui.R
library(shiny)
shinyUI(tagList(
tags$head(
HTML("<link rel='stylesheet' type='text/css' href='css/introjs.min.css'>")
),
navbarPage("Old Faithful Geyser Data",
tabPanel(id = "fTab", "First tab",
HTML("<h1 data-step='1' data-intro='This is a tooltip!'>Basic Usage</h1>"),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
plotOutput("distPlot"),
HTML("<a id='startButton' class='btn btn-large btn-success' href='javascript:void(0);'>Help</a>")
),
tabPanel(tabName = "sTab", "Second tab", id = "tt",
HTML("<h1 data-step='2' data-intro='This is a second tooltip!'>Basic Usage</h1>"),
sliderInput("bins2",
"Number of bins:",
min = 1,
max = 50,
value = 30),
plotOutput("distPlot2")
)
),
HTML("<script type='text/javascript' src='js/intro.min.js'></script>"),
HTML("<script type='text/javascript'>document.getElementById('startButton').onclick = function() {
introJs().setOption('doneLabel', 'Next page').start().oncomplete(function() {
window.location.hash = '#!tt?multipage=true';
});
};</script>")
))
server.R
library(shiny)
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
output$distPlot2 <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins2 + 1)
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
})
The js and css files from intro.js are in the js and css folders inside the www folder. The intro.js files may be found here
My guess is that I am doing something wrong in the function in the javascript code at the bottom of ui.R. I have tried to adapt the example from here by replacing the window.location.href with window.location.hash and referencing the tab id which is "tt".
@warmoverflow gave an excellent answer. Here is a version of the same answer using rintrojs
:
library(shiny)
library(rintrojs)
ui = shinyUI(tagList(
introjsUI(),
navbarPage(
"Old Faithful Geyser Data",
tabPanel(
id = "fTab",
"First tab",
introBox(
h1("Basic Usage"),
data.step = 1,
data.intro = "This is a tooltip"
),
sliderInput(
"bins",
"Number of bins:",
min = 1,
max = 50,
value = 30
),
plotOutput("distPlot"),
actionButton("startButton", "Help")
),
tabPanel(
tabName = "sTab",
"Second tab",
id = "tt",
introBox(
h1("Basic Usage 2"),
data.step = 2,
data.intro = "This is a second tooltip"
),
sliderInput(
"bins2",
"Number of bins:",
min = 1,
max = 50,
value = 30
),
plotOutput("distPlot2")
)
)
))
server = shinyServer(function(input, output, session) {
output$distPlot <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x,
breaks = bins,
col = 'darkgray',
border = 'white')
})
output$distPlot2 <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins2 + 1)
hist(x,
breaks = bins,
col = 'darkgray',
border = 'white')
})
observeEvent(input$startButton, {
introjs(
session,
events = list(
"onchange" = "if (this._currentStep==0) {
$('a[data-value=\"Second tab\"]').removeClass('active');
$('a[data-value=\"First tab\"]').addClass('active');
$('a[data-value=\"First tab\"]').trigger('click');
}
if (this._currentStep==1) {
$('a[data-value=\"First tab\"]').removeClass('active');
$('a[data-value=\"Second tab\"]').addClass('active');
$('a[data-value=\"Second tab\"]').trigger('click');
}"
)
)
})
})
shinyApp(ui = ui, server = server)
The tabs don't switch if you go back to the first step of the tour though, so the code only works going forwards through the tour.
NOTE: in rintrojs
version 0.1.2.900 and higher, raw javascript needs to be wrapped in I()
Here is the working solution. Note that you need to
intro.js
will display all steps before next page
is clickedui.R (server.R unchanged)
library(shiny)
shinyUI(tagList(
tags$head(
HTML("<link rel='stylesheet' type='text/css' href='css/introjs.min.css'>")
),
navbarPage("Old Faithful Geyser Data",
tabPanel(id = "fTab", "First tab",
HTML("<h1 data-step='1' data-intro='This is a tooltip!'>Basic Usage</h1>"),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
plotOutput("distPlot"),
HTML("<a id='startButton' class='btn btn-large btn-success' href='javascript:void(0);'>Help</a>")
),
tabPanel(tabName = "sTab", "Second tab", id = "tt",
HTML("<h1 data-step='2' data-intro='This is a second tooltip!'>Basic Usage</h1>"),
sliderInput("bins2",
"Number of bins:",
min = 1,
max = 50,
value = 30),
plotOutput("distPlot2")
)
),
HTML("<script type='text/javascript' src='js/intro.min.js'></script>"),
HTML("<script type='text/javascript'>document.getElementById('startButton').onclick = function() {
introJs().onchange(function(targetElement) {
if (this._currentStep==0) {
$('a[data-value=\"Second tab\"]').removeClass('active');
$('a[data-value=\"First tab\"]').addClass('active');
$('a[data-value=\"First tab\"]').trigger('click');
}
if (this._currentStep==1) {
$('a[data-value=\"First tab\"]').removeClass('active');
$('a[data-value=\"Second tab\"]').addClass('active');
$('a[data-value=\"Second tab\"]').trigger('click');
}
}).start();
};</script>")
))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With