2015-03-20 6 views
10

Sto utilizzando R lucido per creare applicazioni Web e alcuni di essi sfruttano le grandi funzionalità di opuscolo.Come visualizzare i popup (avanzati) personalizzati per il volantino in Shiny?

Vorrei creare un popup personalizzato e avanzato, ma non so come procedere.

Si può vedere quello che posso fare nel progetto che ho creato per questo post su github, o direttamente in shinyapp.io here

Più complesso è il pop-up è, il più strano è il mio codice, come sto sorta di combinare R e HTML in modo strano (vedere il modo in cui mi definisco il mio custompopup'i' in server.R) ..

c'è un modo migliore di procedere? Quali sono le buone pratiche per creare tali popup? Se ho intenzione di visualizzare un grafico a seconda del marker cliccato, dovrei costruirlo tutti in anticipo, o è possibile costruirlo "al volo"? Come posso farlo?

Mille grazie in anticipo per le vostre opinioni su questo, non esitate a condividere la vostra risposta qui o per cambiare direttamente i miei esempi github!

saluti

+0

Il fattore limitante qui è che 'popup' prende solo qualcosa che si riduce a una stringa. Ciò significa che puoi usare qualunque HTML tu voglia e anche JavaScript inline, ma non R, che è una specie di punto. Se lavori con il volantino nel suo JavaScript nativo potresti probabilmente andare oltre, ma a un certo punto diventa assurdo. Un modo molto più semplice di presentare le stesse informazioni è di rendere reattivo un pannello separato sul pennarello cliccato, in modo da poter codificare le informazioni specifiche dei marker in R. Forse rubare [questa formattazione] (http://shiny.rstudio.com/ galleria/SuperZip-example.html). – alistaire

+0

Non so se questo è ancora aperto, ma puoi fornire un esempio riproducibile con la tua app lucida. – MLavoie

+0

Ciao @MLavoie, il codice per la riproducibilità è disponibile sul mio account github (vedi il post iniziale, ci sono 2 link: github e shinyapps.io). Cordiali saluti – cho7tom

risposta

5

Credo che questo post ha ancora qualche rilevanza. Quindi ecco la mia soluzione su come aggiungere quasi ogni output di interfaccia possibile ai popup di opuscoli.

possiamo raggiungere questo fare le seguenti operazioni:

  • Inserire l'elemento dell'interfaccia utente popup come carattere all'interno del campo pop-up standard di foglio. Come personaggio significa, non è il shiny.tag, ma semplicemente un normale div. Per esempio. il classico uiOutput("myID") diventa <div id="myID" class="shiny-html-output"><div>.

  • I popup vengono inseriti in uno speciale div, nel pannello di selezione foglio . Aggiungiamo un EventListener per monitorare se il suo contenuto cambia. (Nota: Se il popup scompare, che si intendono tutti i bambini di questa div vengono rimossi, quindi questo non è un problema di visibilità, ma di esistenza.)

  • Quando un bambino è allegato, vale a dire un popup è apparendo, noi leghiamo tutti gli input/output lucidi all'interno del popup. Quindi, il senza vita uiOutput è pieno di contenuti come dovrebbe essere. (Uno avrei sperato che lucida lo fa automaticamente, ma non riesce a registrare questa uscita, dal momento che è compilato dal Volantini backend.)

  • Quando il pop-up è cancellato, Brillante, inoltre, non unbind esso. Questo è problematico, se si apre nuovamente il popup e si genera un'eccezione (ID duplicato). Una volta eliminato dal documento, non può più essere non associato.Quindi fondamentalmente lo clona l'elemento eliminato a uno smaltimento- div dove può essere non associato correttamente e quindi cancellarlo definitivamente.

Ho creato un'applicazione di esempio che (credo) mostra tutte le potenzialità di questa soluzione e spero che è stato progettato abbastanza facile, che chiunque può adattarlo. La maggior parte di questa app è per show, quindi ti prego di perdonare che ha parti irrilevanti.

library(leaflet) 
library(shiny) 

runApp(
    shinyApp(
    ui = shinyUI(
     fluidPage(

     # Copy this part here for the Script and disposal-div 
     uiOutput("script"), 
     tags$div(id = "garbage"), 
     # End of copy. 

     leafletOutput("map"), 
     verbatimTextOutput("Showcase") 
    ) 
    ), 

    server = function(input, output, session){ 

     # Just for Show 
     text <- NULL 
     makeReactiveBinding("text") 

     output$Showcase <- renderText({text}) 

     output$popup1 <- renderUI({ 
     actionButton("Go1", "Go1") 
     }) 

     observeEvent(input$Go1, { 
     text <<- paste0(text, "\n", "Button 1 is fully reactive.") 
     }) 

     output$popup2 <- renderUI({ 
     actionButton("Go2", "Go2") 
     }) 

     observeEvent(input$Go2, { 
     text <<- paste0(text, "\n", "Button 2 is fully reactive.") 
     }) 

     output$popup3 <- renderUI({ 
     actionButton("Go3", "Go3") 
     }) 

     observeEvent(input$Go3, { 
     text <<- paste0(text, "\n", "Button 3 is fully reactive.") 
     }) 
     # End: Just for show 

     # Copy this part. 
     output$script <- renderUI({ 
     tags$script(HTML(' 
      var target = document.querySelector(".leaflet-popup-pane"); 

      var observer = new MutationObserver(function(mutations) { 
      mutations.forEach(function(mutation) { 
       if(mutation.addedNodes.length > 0){ 
       Shiny.bindAll(".leaflet-popup-content"); 
       }; 
       if(mutation.removedNodes.length > 0){ 
       var popupNode = mutation.removedNodes[0].childNodes[1].childNodes[0].childNodes[0]; 

       var garbageCan = document.getElementById("garbage"); 
       garbageCan.appendChild(popupNode); 

       Shiny.unbindAll("#garbage"); 
       garbageCan.innerHTML = ""; 
       }; 
      });  
      }); 

      var config = {childList: true}; 

      observer.observe(target, config); 
     ')) 
     }) 
     # End Copy 

     # Function is just to lighten code. But here you can see how to insert the popup. 
     popupMaker <- function(id){ 
     as.character(uiOutput(id)) 
     } 

     output$map <- renderLeaflet({ 
     leaflet() %>% 
      addTiles() %>% 
      addMarkers(lat = c(10, 20, 30), lng = c(10, 20, 30), popup = lapply(paste0("popup", 1:3), popupMaker)) 
     }) 
    } 
), launch.browser = TRUE 
) 

Nota: Ci si potrebbe chiedere, perché lo script viene aggiunto dal lato server. Ho riscontrato che, in caso contrario, l'aggiunta di EventListener non riesce, perché la mappa Leaflet non è ancora stata inizializzata. Scommetto che con qualche conoscenza di jQuery non c'è bisogno di fare questo trucco.

Risolvere questo è stato un lavoro duro, ma penso che ne valesse la pena, ora che le mappe Leaflet hanno qualche utilità in più. Divertiti con questa soluzione e chiedi se ci sono domande a riguardo!

Problemi correlati