JohnCoene / cicerone

🏛️ Give tours of your Shiny apps
https://cicerone.john-coene.com
Other
187 stars 7 forks source link

Issue with hide/show elements #14

Closed fmmattioni closed 3 years ago

fmmattioni commented 4 years ago

Hi John!

I was trying to solve this issue for the last hour without much success. Perhaps is not even an issue with cicerone, but I would like to get your thoughts on this.

I have an app that uses bs4Dash and on each step of the data analysis I have a new bs4Dash::bs4Card(), which I always minimize once the go button is pressed and then the next card shows up, and so on...

I was trying to build a guide in the app with cicerone and the issue is the transition from one card to another, where the first gets minimized and then the second appears on the screen. I remember having a similar issue with rintrojs, so I am not sure what to do here.

cicerone ```r guide <- cicerone::Cicerone$ new(id = "guide")$ step( el = "plot_1", title = "Title Plot 1", description = "This is plot 1" )$ step( el = "next_2", title = "Title", show_btns = FALSE, description = "Click 'Next' to continue." )$ step( el = "plot_2", title = "Title Plot 2", description = "This is plot 2" )$ step( el = "next_3", title = "Title", show_btns = FALSE, description = "Click 'Next' to continue." )$ step( el = "plot_3", title = "Title Plot 3", description = "This is plot 3" ) ```
app ```r library(shiny) library(bs4Dash) library(cicerone) library(shinyjs) library(magrittr) library(ggplot2) shiny::shinyApp( ui = bs4DashPage( sidebar_collapsed = TRUE, navbar = bs4DashNavbar(), sidebar = bs4DashSidebar(), controlbar = NULL, footer = bs4DashFooter(), title = "test", body = bs4DashBody( use_cicerone(), useShinyjs(), bs4Card( inputId = "card_1", title = "Card 1", width = NULL, collapsible = TRUE, closable = FALSE, actionButton(inputId = "cicerone", label = "Start tour"), plotOutput(outputId = "plot_1"), actionButton(inputId = "next_2", label = "Next") ), bs4Card( inputId = "card_2", title = "Card 2", width = NULL, collapsible = TRUE, plotOutput(outputId = "plot_2"), actionButton(inputId = "next_3", label = "Next") ) %>% shinyjs::hidden(), bs4Card( inputId = "card_3", title = "Card 3", width = NULL, collapsible = TRUE, plotOutput(outputId = "plot_3") ) %>% shinyjs::hidden() ) ), server = function(input, output, session) { observeEvent(input$cicerone, { # initialise then start the guide guide$init()$start() }) output$plot_1 <- renderPlot({ mtcars %>% ggplot(aes(mpg, hp)) + geom_point() }) observeEvent(input$next_2, { updatebs4Card(inputId = "card_1", session = session, action = "toggle") shinyjs::show(id = "card_2", anim = TRUE) session$sendCustomMessage("cicerone-next", list(id = "guide")) }) output$plot_2 <- renderPlot({ req(input$next_2) mtcars %>% ggplot(aes(mpg, hp)) + geom_point() }) observeEvent(input$next_3, { updatebs4Card(inputId = "card_2", session = session, action = "toggle") shinyjs::show(id = "card_3", anim = TRUE) session$sendCustomMessage("cicerone-next", list(id = "guide")) }) output$plot_3 <- renderPlot({ req(input$next_3) mtcars %>% ggplot(aes(mpg, hp)) + geom_point() }) } ) ```

Thanks in advance! Felipe

fmmattioni commented 4 years ago

Hi John!

Just a quick comment on this: do you think it is worth it to call the refresh method every time cicerone highlights an element?

I have just given it a quick try in the code, but with no success. However, when I type driver.guide.refresh(); in the console, it works.

What do you think?

JohnCoene commented 4 years ago

Hi Felipe, sorry I looked into this but couldn't find a way.

If what you suggest works could you try to place this like so.

guide <- Cicerone$
  new(id = "guide")$
  step(
    "step1",
    "Hello",
    "This is the first step",
    on_highlighted = "function(){
      driver[0].refresh();
    }"
  )

It could be fixed but is a lot of work that I'm sorry I cannot put in right now :(

fmmattioni commented 4 years ago

Hi John!

Oh, don't be sorry at all! I actually don't need this fixed now.. I found a work-around that the cards are not hidden anymore if the guide mode is on. So, I am just curious if I could help fix it.

The above didn't work. If I find something that could help in this direction I am going to post here, but as I said, I am just trying to help - so please don't feel pressured at all  😃

Thanks again for the great package!

fmmattioni commented 4 years ago

OK, I have found a temporary solution.. I am sure there is a "more appropriate" or "more official" way of doing it, but here is my thought about what is going on:

I guess the problem is that refresh needs to be triggered only after the UI gets updated. The way I found to do it for now is simply to wait one second before triggering refresh.

So, the following achieves the desired result:

guide <- Cicerone$
  new(id = "guide")$
  step(
    "step1",
    "Hello",
    "This is the first step",
    on_highlighted = "window.setInterval(()=>{
     driver.guide.overlay.refresh();
     }, 1000)"
  )

The other problem was that driver[0] does not work for selecting the guide. So I had to use the id directly in the function.

Related issue: https://github.com/kamranahmedse/driver.js/issues/130

Thanks, John!

JohnCoene commented 4 years ago

Thanks for your patience Felipe, I'll look into a better way when I get the time.

JohnCoene commented 3 years ago

Here is the best solution I could come up with.

Use the newly added on_next to toggle all cards at the end of the tour: doing it each card messes the highlight I'm afraid.

devtools::load_all()

guide <- cicerone::Cicerone$
  new(id = "guide")$
  step(
    el = "plot_1",
    title = "Title Plot 1",
    description = "This is plot 1"
  )$
  step(
    el = "plot_2",
    title = "Title Plot 2",
    description = "This is plot 2"
  )$
  step(
    el = "plot_3",
    title = "Title Plot 3",
    description = "This is plot 3",
    on_next = "function(){
      $('#card_1').CardWidget('toggle');
      $('#card_2').CardWidget('toggle');
      $('#card_3').CardWidget('toggle');
    }"
  )

library(shiny)
library(bs4Dash)

shiny::shinyApp(
  ui = bs4DashPage(
    sidebar_collapsed = TRUE,
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(),
    controlbar = NULL,
    footer = bs4DashFooter(),
    title = "test",
    body = bs4DashBody(

      use_cicerone(),

      bs4Card(
        inputId = "card_1", 
        title = "Card 1", 
        width = NULL,
        collapsible = TRUE,
        closable = FALSE,

        actionButton(inputId = "cicerone", label = "Start tour"),

        plotOutput(outputId = "plot_1"),

        actionButton(inputId = "next_2", label = "Next")
      ),

      bs4Card(
        inputId = "card_2", 
        title = "Card 2", 
        width = NULL,
        collapsible = TRUE,

        plotOutput(outputId = "plot_2"),

        actionButton(inputId = "next_3",  label = "Next")
      ),
      bs4Card(
        inputId = "card_3", 
        title = "Card 3", 
        width = NULL,
        collapsible = TRUE,

        plotOutput(outputId = "plot_3")
      )
    )
  ),
  server = function(input, output, session) {

    observeEvent(input$cicerone, {
      # initialise then start the guide
      guide$init()$start()
    })

    output$plot_1 <- renderPlot({
      mtcars %>% 
        ggplot(aes(mpg, hp)) +
        geom_point()
    })

    output$plot_2 <- renderPlot({
      mtcars %>% 
        ggplot(aes(mpg, hp)) +
        geom_point()
    })

    output$plot_3 <- renderPlot({

      mtcars %>% 
        ggplot(aes(mpg, hp)) +
        geom_point()
    })

  }
)
fmmattioni commented 3 years ago

Dear @JohnCoene,

This looks quite nice!!! Thank you very much for looking into this! I will incorporate it into my new app!

👏👏👏👏