├── README.Rmd ├── README.md ├── global.R ├── life_exp.csv ├── server.R ├── ui.R └── www ├── busy.js ├── google-analytics.js ├── loader.gif ├── md5.js ├── passwdInputBinding.js ├── rocky.wav ├── sound.js └── style.css /README.Rmd: -------------------------------------------------------------------------------- 1 | ## Shiny tips and trics application 2 | 3 | ### Data 4 | 5 | The dataset contains the life expectanncy of males and females in different countries in the world. It is based on babies that are born in 2015. I downloaded the dataset from 6 | [wikipedia](https://en.wikipedia.org/wiki/List_of_countries_by_life_expectancy) 7 | 8 | 9 | ```{r} 10 | 'data.frame': 171 obs. of 7 variables: 11 | $ country : chr "Afghanistan" "Albania" "Algeria" "Angola" ... 12 | $ region : chr "Asia" "Europe" "Africa" "Africa" ... 13 | $ population: int 32526562 2896679 39666519 25021974 91818 43416755 3017712 23968973 8544586 9753968 ... 14 | $ male : num 59.3 75.1 73.8 50.9 74.1 72.7 71.6 80.9 79 69.6 ... 15 | $ female : num 61.9 80.7 77.5 54 78.6 79.9 77.7 84.8 83.9 75.8 ... 16 | $ lat : num 33.9 41.2 28 -11.2 17.1 ... 17 | $ lon : num 67.71 20.17 1.66 17.87 -61.8 ... 18 | ``` 19 | 20 | ### Functionality 21 | 22 | * Tab datatable: displays the data and includes export options, show/hide columns 23 | * Tab Leaflet: displays the data on a map 24 | * Tab plotly: displays the data in a bar chart using the plotly library 25 | * Tab Contineous update: a plot that is updating every 2 sec using reactive timer 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Shiny tips and trics application 2 | 3 | This application contains functionality and patterns that I am using frequently using in my apps. You can view it live at 4 | [my website](http://www.gerinberg.com/shiny/shinytips) 5 | 6 | ### Functionality 7 | 8 | * A multi-tabbed application (base shiny) 9 | * Filtering of data through the use of sliders (base shiny) 10 | * CSS integration 11 | * Displaying and R-Markdown document 12 | * Displaying data in a table using DataTable package 13 | * Display data on a map with markers and circles using Leaflet package 14 | * Enabling/disabling components with shinyJS package 15 | * A simple login page 16 | * Download functionality 17 | * A contineous updating plot 18 | * [Google analytics](https://shiny.rstudio.com/articles/google-analytics.html) 19 | * Play an audio file 20 | * Busy indicator 21 | 22 | ### Data 23 | 24 | The dataset contains the life expectanncy of males and females in different countries in the world. It is based on babies that are born in 2015. I downloaded the dataset from 25 | [wikipedia](https://en.wikipedia.org/wiki/List_of_countries_by_life_expectancy) 26 | 27 | Please let me know if you have any questions or recommendations for improvement! 28 | -------------------------------------------------------------------------------- /global.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(shinyjs) 3 | library(leaflet) 4 | library(DT) 5 | library(ggplot2) 6 | library(plotly) 7 | -------------------------------------------------------------------------------- /life_exp.csv: -------------------------------------------------------------------------------- 1 | country,region,population,male,female,lat,lon 2 | Afghanistan,Asia,32526562,59.3,61.9,33.93911,67.709953 3 | Albania,Europe,2896679,75.1,80.7,41.153332,20.168331 4 | Algeria,Africa,39666519,73.8,77.5,28.033886,1.659626 5 | Angola,Africa,25021974,50.9,54,-11.202692,17.873887 6 | Antigua and Barbuda,Americas,91818,74.1,78.6,17.060816,-61.796428 7 | Argentina,Americas,43416755,72.7,79.9,-38.416097,-63.616672 8 | Armenia,Asia,3017712,71.6,77.7,40.069099,45.038189 9 | Australia,Oceania,23968973,80.9,84.8,-25.274398,133.775136 10 | Austria,Europe,8544586,79,83.9,47.516231,14.550072 11 | Azerbaijan,Asia,9753968,69.6,75.8,40.143105,47.576927 12 | Bahamas,Americas,388019,72.9,79.1,25.03428,-77.39628 13 | Bahrain,Asia,1377237,76.2,77.9,26.0667,50.5577 14 | Bangladesh,Asia,160995642,70.6,73.1,23.684994,90.356331 15 | Barbados,Americas,284215,73.1,77.9,13.193887,-59.543198 16 | Belarus,Europe,9495826,66.5,78,53.709807,27.953389 17 | Belgium,Europe,11299192,78.6,83.5,50.503887,4.469936 18 | Belize,Americas,359287,67.5,73.1,17.189877,-88.49765 19 | Benin,Africa,10879829,58.8,61.1,9.30769,2.315834 20 | Bhutan,Asia,774830,69.5,70.1,27.514162,90.433601 21 | Bolivia,Americas,10724705,68.2,73.3,-16.290154,-63.588653 22 | Bosnia and Herzegovina,Europe,3810416,75,79.7,43.915886,17.679076 23 | Botswana,Africa,2262485,63.3,68.1,-22.328474,24.684866 24 | Brazil,Americas,207847528,71.4,78.7,-14.235004,-51.92528 25 | Bulgaria,Europe,7149787,71.1,78,42.733883,25.48583 26 | Burkina Faso,Africa,18105570,59.1,60.5,12.238333,-1.561593 27 | Burundi,Africa,11178921,57.7,61.6,-3.373056,29.918886 28 | Cabo Verde,Africa,520502,71.3,75,15.120142,-23.6051868 29 | Cambodia,Asia,15577899,66.6,70.7,12.565679,104.990963 30 | Cameroon,Africa,23344179,55.9,58.6,7.369722,12.354722 31 | Canada,Americas,35939927,80.2,84.1,56.130366,-106.346771 32 | Central African Republic,Africa,4900274,50.9,54.1,6.611111,20.939444 33 | Chad,Africa,14037472,51.7,54.5,15.454166,18.732207 34 | Chile,Americas,17948141,77.4,83.4,-35.675147,-71.542969 35 | China,Asia,1376048943,74.6,77.6,35.86166,104.195397 36 | Colombia,Americas,48228704,71.2,78.4,4.570868,-74.297333 37 | Comoros,Africa,788474,61.9,65.2,-11.6455,43.3333 38 | Congo,Africa,4620330,63.2,66.3,-4.038333,21.758664 39 | Costa Rica,Americas,4807850,77.1,82.2,9.748917,-83.753428 40 | Croatia,Europe,4240317,74.7,81.2,45.1,15.2 41 | Cuba,Americas,11389562,76.9,81.4,21.521757,-77.781167 42 | Cyprus,Asia,1165300,78.3,82.7,35.126413,33.429859 43 | Czech Republic,Europe,10543186,75.9,81.7,49.817492,15.472962 44 | Democratic Republic of the Congo,Africa,77266814,58.3,61.5,-4.038333,21.758664 45 | Denmark,Europe,5669081,78.6,82.5,56.26392,9.501785 46 | Djibouti,Africa,887861,61.8,65.3,11.825138,42.590275 47 | Dominican Republic,Americas,10528391,70.9,77.1,18.735693,-70.162651 48 | Ecuador,Americas,16144363,73.5,79,-1.831239,-78.183406 49 | Egypt,Africa,91508084,68.8,73.2,26.820553,30.802498 50 | El Salvador,Americas,6126583,68.8,77.9,13.794185,-88.89653 51 | Equatorial Guinea,Africa,845060,56.6,60,1.650801,10.267895 52 | Eritrea,Africa,5227791,62.4,67,15.179384,39.782334 53 | Estonia,Europe,1312558,72.7,82,58.595272,25.013607 54 | Ethiopia,Africa,99390750,62.8,66.8,9.145,40.489673 55 | Fiji,Oceania,892145,67,73.1,-17.713371,178.065032 56 | Finland,Europe,5503457,78.3,83.8,61.92411,25.748151 57 | France,Europe,64395345,79.4,85.4,46.227638,2.213749 58 | Gabon,Africa,1725292,64.7,67.2,-0.803689,11.609444 59 | Gambia,Africa,1990924,59.8,62.5,13.443182,-15.310139 60 | Georgia,Asia,3999812,70.3,78.3,32.1656221,-82.9000751 61 | Germany,Europe,80688545,78.7,83.4,51.165691,10.451526 62 | Ghana,Africa,27409893,61,63.9,7.946527,-1.023194 63 | Greece,Europe,10954617,78.3,83.6,39.074208,21.824312 64 | Grenada,Americas,106825,71.2,76.1,12.1165,-61.679 65 | Guatemala,Americas,16342897,68.5,75.2,15.783471,-90.230759 66 | Guinea,Africa,12608590,58.2,59.8,9.945587,-9.696645 67 | Guinea-Bissau,Africa,1844325,57.2,60.5,11.803749,-15.180413 68 | Guyana,Americas,767085,63.9,68.5,4.860416,-58.93018 69 | Haiti,Americas,10711067,61.5,65.5,18.971187,-72.285215 70 | Honduras,Americas,8075060,72.3,77,15.199999,-86.241905 71 | Hungary,Europe,9855023,72.3,79.1,47.162494,19.503304 72 | Iceland,Europe,329425,81.2,84.1,64.963051,-19.020835 73 | India,Asia,1311050527,66.9,69.9,20.593684,78.96288 74 | Indonesia,Asia,257563815,67.1,71.2,-0.789275,113.921327 75 | Iran,Asia,79109272,74.5,76.6,32.427908,53.688046 76 | Iraq,Asia,36423395,66.2,71.8,33.223191,43.679291 77 | Ireland,Europe,4688465,79.4,83.4,53.1423672,-7.6920536 78 | Israel,Asia,8064036,80.6,84.3,31.046051,34.851612 79 | Italy,Europe,59797685,80.5,84.8,41.87194,12.56738 80 | Jamaica,Americas,2793335,73.9,78.6,18.109581,-77.297508 81 | Japan,Asia,126573481,80.5,86.8,36.204824,138.252924 82 | Jordan,Asia,7594547,72.5,75.9,30.585164,36.238414 83 | Kazakhstan,Asia,17625226,65.7,74.7,48.019573,66.923684 84 | Kenya,Africa,46050302,61.1,65.8,-0.023559,37.906193 85 | Kiribati,Oceania,112423,63.7,68.8,1.8709422,-157.3628595 86 | Kuwait,Asia,3892115,73.7,76,29.31166,47.481766 87 | Kyrgyzstan,Asia,5939962,67.2,75.1,41.20438,74.766098 88 | Latvia,Europe,1970503,69.6,79.2,56.879635,24.603189 89 | Lebanon,Asia,5850743,73.5,76.5,33.854721,35.862285 90 | Lesotho,Africa,2135022,51.7,55.4,-29.609988,28.233608 91 | Liberia,Africa,4503438,59.8,62.9,6.428055,-9.429499 92 | Libya,Africa,6278438,70.1,75.6,26.3351,17.228331 93 | Lithuania,Europe,2878405,68.1,79.1,55.169438,23.881275 94 | Luxembourg,Europe,567110,79.8,84,49.815273,6.129583 95 | Madagascar,Africa,24235390,63.9,67,-18.766947,46.869107 96 | Malawi,Africa,17215232,56.7,59.9,-13.254308,34.301525 97 | Malaysia,Asia,30331007,72.7,77.3,4.210484,101.975766 98 | Maldives,Asia,363657,76.9,80.2,1.9772276,73.536101 99 | Mali,Africa,17599694,58.2,58.3,17.570692,-3.996166 100 | Malta,Europe,418670,79.7,83.7,35.937496,14.375416 101 | Mauritania,Africa,4067564,61.6,64.6,21.00789,-10.940835 102 | Mauritius,Africa,1273212,71.4,77.8,-20.348404,57.552152 103 | Mexico,Americas,127017224,73.9,79.5,23.634501,-102.552784 104 | Mongolia,Asia,2959134,64.7,73.2,46.862496,103.846656 105 | Montenegro,Europe,625781,74.1,78.1,42.708678,19.37439 106 | Morocco,Africa,34377511,73.3,75.4,31.791702,-7.09262 107 | Mozambique,Africa,27977863,55.7,59.4,-18.665695,35.529562 108 | Myanmar,Asia,53897154,64.6,68.5,21.916221,95.955974 109 | Namibia,Africa,2458830,63.1,68.3,-22.95764,18.49041 110 | Nepal,Asia,28513700,67.7,70.8,28.394857,84.124008 111 | Netherlands,Europe,16924929,80,83.6,52.132633,5.291266 112 | New Zealand,Oceania,4528526,80,83.3,-40.900557,174.885971 113 | Nicaragua,Americas,6082032,71.5,77.9,12.865416,-85.207229 114 | Niger,Africa,19899120,60.9,62.8,17.607789,8.081666 115 | Nigeria,Africa,182201962,53.4,55.6,9.081999,8.675277 116 | Norway,Europe,5210967,79.8,83.7,60.472024,8.468946 117 | Oman,Asia,4490541,75,79.2,21.4735329,55.975413 118 | Pakistan,Asia,188924874,65.5,67.5,30.375321,69.345116 119 | Panama,Americas,3929141,74.7,81.1,8.9823792,-79.5198696 120 | Papua New Guinea,Oceania,7619321,60.6,65.4,-6.314993,143.95555 121 | Paraguay,Americas,6639123,72.2,76,-23.442503,-58.443832 122 | Peru,Americas,31376670,73.1,78,-9.189967,-75.015152 123 | Philippines,Asia,100699395,65.3,72,12.879721,121.774017 124 | Poland,Europe,38611794,73.6,81.3,51.919438,19.145136 125 | Portugal,Europe,10349803,78.2,83.9,39.399872,-8.224454 126 | Qatar,Asia,2235355,77.4,80,25.354826,51.183884 127 | Romania,Europe,19511324,71.4,78.8,45.943161,24.96676 128 | Rwanda,Africa,11609666,60.9,71.1,-1.940278,29.873888 129 | Saint Lucia,Americas,184999,72.6,77.9,13.909444,-60.978893 130 | Saint Vincent and the Grenadines,Americas,109462,71.3,75.2,13.2528179,-61.1971628 131 | Samoa,Oceania,193228,70.9,77.5,-13.759029,-172.104629 132 | Sao Tome and Principe,Africa,190344,65.6,69.4,0.18636,6.613081 133 | Saudi Arabia,Asia,31540372,73.2,76,23.885942,45.079162 134 | Senegal,Africa,15129273,64.6,68.6,14.497401,-14.452362 135 | Serbia,Europe,8850975,72.9,78.4,44.016521,21.005859 136 | Seychelles,Africa,96471,69.1,78,-4.679574,55.491977 137 | Sierra Leone,Africa,6453184,49.3,50.8,8.460555,-11.779889 138 | Singapore,Asia,5603740,80,86.1,1.352083,103.819836 139 | Slovakia,Europe,5426258,72.9,80.2,48.669026,19.699024 140 | Slovenia,Europe,2067526,77.9,83.7,46.151241,14.995463 141 | Solomon Islands,Oceania,583591,67.9,70.8,-9.64571,160.156194 142 | Somalia,Africa,10787104,53.5,56.6,5.152149,46.199616 143 | South Africa,Africa,54490406,59.3,66.2,-30.559482,22.937506 144 | South Sudan,Africa,12339812,56.1,58.6,6.8769919,31.3069788 145 | Spain,Europe,46121699,80.1,85.5,40.463667,-3.74922 146 | Sri Lanka,Asia,20715010,71.6,78.3,7.873054,80.771797 147 | Sudan,Africa,40234882,62.4,65.9,12.862807,30.217636 148 | Suriname,Americas,542975,68.6,74.7,3.919305,-56.027783 149 | Swaziland,Africa,1286970,56.6,61.1,-26.522503,31.465866 150 | Sweden,Europe,9779426,80.7,84,60.128161,18.643501 151 | Switzerland,Europe,8298663,81.3,85.3,46.818188,8.227512 152 | Syrian Arab Republic,Asia,18502413,59.9,69.9,34.802075,38.996815 153 | Tajikistan,Asia,8481855,66.6,73.6,38.861034,71.276093 154 | Thailand,Asia,67959359,71.9,78,15.870032,100.992541 155 | Timor-Leste,Asia,1184765,66.6,70.1,-8.874217,125.727539 156 | Togo,Africa,7304578,58.6,61.1,8.619543,0.824782 157 | Tonga,Oceania,106170,70.6,76.4,-21.178986,-175.198242 158 | Trinidad and Tobago,Americas,1360088,67.9,74.8,10.691803,-61.222503 159 | Tunisia,Africa,11253554,73,77.8,33.886917,9.537499 160 | Turkey,Asia,78665830,72.6,78.9,38.963745,35.243322 161 | Turkmenistan,Asia,5373502,62.2,70.5,38.969719,59.556278 162 | Uganda,Africa,39032383,60.3,64.3,1.373333,32.290275 163 | Ukraine,Europe,44823765,66.3,76.1,48.379433,31.16558 164 | United Arab Emirates,Asia,9156963,76.4,78.6,23.424076,53.847818 165 | United Kingdom,Europe,64715810,79.4,83,55.378051,-3.435973 166 | Uruguay,Americas,3431555,73.3,80.4,-32.522779,-55.765835 167 | Uzbekistan,Asia,29893488,66.1,72.7,41.377491,64.585262 168 | Vanuatu,Oceania,264652,70.1,74,-15.376706,166.959158 169 | Venezuela,Americas,31108083,70,78.5,6.42375,-66.58973 170 | Yemen,Asia,26832215,64.3,67.2,15.552727,48.516388 171 | Zambia,Africa,16211767,59,64.7,-13.133897,27.849332 172 | Zimbabwe,Africa,15602751,59,62.3,-19.015438,29.154857 173 | -------------------------------------------------------------------------------- /server.R: -------------------------------------------------------------------------------- 1 | source("global.R") 2 | 3 | credentials <- list("test" = "098f6bcd4621d373cade4e832627b4f6") 4 | ZOOM_LEVEL <- 3 5 | 6 | shinyServer(function(input, output, session) { 7 | source('ui.R') #login page 8 | 9 | USER <- reactiveValues(Logged = FALSE) 10 | INIT <- FALSE 11 | 12 | observeEvent(input$.login, { 13 | 14 | error <- FALSE 15 | user <- input$.username 16 | pwd <- input$.password 17 | if(user == "" | pwd == ""){ 18 | error <- TRUE 19 | } 20 | if(!error){ 21 | if (!is.null(credentials[[user]]) && credentials[[user]] == pwd){ 22 | USER$Logged <- TRUE 23 | } else { 24 | error <- TRUE 25 | } 26 | } 27 | if(error){ 28 | show("message") 29 | output$message = renderText("Invalid user name or password") 30 | delay(5000, hide("message", anim = TRUE, animType = "fade")) 31 | } 32 | }) 33 | 34 | # Output the main content panel 35 | output$content = renderUI( 36 | ifelse(USER$Logged, uiNormal(), uiLogin()) 37 | ) 38 | 39 | # reactive expression for data 40 | data <- reactive({ 41 | range_m <- input$life_exp_m 42 | range_f <- input$life_exp_f 43 | df_filtered <- df %>% filter(male >= range_m[1]) %>% filter(male <= range_m[2]) %>% filter(female >= range_f[1]) %>% filter(female <= range_f[2]) 44 | return(df_filtered) 45 | }) 46 | 47 | # map with locations of facilities 48 | output$map <- renderLeaflet({ 49 | df <- data() 50 | if(nrow(df) > 0){ 51 | leaflet() %>% 52 | addTiles() %>% 53 | setView(lng = df[1,]$lon, lat = df[1,]$lat, zoom = ZOOM_LEVEL) %>% 54 | addMarkers(data = df, lat = ~lat, lng = ~lon) %>% 55 | addCircles(data = df[1,], lng = ~lon, lat = ~lat, weight = 1, radius = ~(input$distance * 1000)) 56 | } 57 | }) 58 | 59 | # print content of data 60 | output$df_contents <- DT::renderDataTable(rownames = FALSE, extensions = 'Buttons',{ 61 | df 62 | }, options = list(pageLength = 50, 63 | paging = TRUE, 64 | dom = 'Blfrtip', 65 | buttons = list('csv', 'print', 'pdf', 66 | list(extend = 'excel', exportOptions = list(columns = ':visible')), 67 | list(extend = 'colvis', text='Show/Hide Columns', collectionLayout='fixed two-column') 68 | ) 69 | ) 70 | ) 71 | 72 | # plotly content 73 | output$plot <- renderPlotly({ 74 | df <- data() 75 | m <- list(l = 150, r = 0, b = 150, t = 50, pad = 4) 76 | plot_ly(df, y = ~country, x = ~male, type = 'bar', name = 'Male') %>% 77 | add_trace(x = ~female, name = 'Female') %>% 78 | layout(title = "Life expectancy per country", yaxis = list(title = ''), xaxis = list(title = 'Age (years)'), barmode = 'group', margin = m) 79 | }) 80 | 81 | observeEvent(input$showDataTab, { 82 | if(!INIT){ 83 | show(selector = "a[data-value=DataTable]") 84 | INIT <<- TRUE 85 | } else{ 86 | # switch tab if currently on data tab 87 | if (input$main == "DataTable"){ 88 | updateTabsetPanel(session, inputId = 'main', selected = 'Leaflet') 89 | } 90 | toggle(selector = "a[data-value=DataTable]") 91 | } 92 | }) 93 | 94 | # update the map markers and view on location selectInput changes 95 | observeEvent(c(input$location, input$distance), { 96 | proxy <- leafletProxy("map") 97 | if (nrow(df) > 0){ 98 | # Add markers for chosen facility and the ones within chosen distance x 99 | df <- data() 100 | df_circle <- df[df$country == input$location,] 101 | proxy %>% clearShapes() %>% clearPopups() %>% 102 | addCircles(data = df_circle, lng = ~lon, lat = ~lat, weight = 1, radius = ~(input$distance * 1000)) %>% 103 | setView(lng = df_circle[1,'lon'], lat = df_circle[1,'lat'], zoom = ZOOM_LEVEL) # update the center of the map with the location of the selected facility (use current zoom level) 104 | } 105 | }) 106 | 107 | # When map is clicked, show a popup with info 108 | observeEvent(input$map_marker_click, { 109 | event <- input$map_marker_click 110 | loc <- df[df$lat == as.numeric(event$lat) & df$lon == as.numeric(event$lng),] 111 | content <- paste("Country:", loc$country, "
", "Male:", loc$male, "
", "Female:", loc$female) 112 | leafletProxy("map") %>% clearPopups() %>% addPopups(event$lng, event$lat, content, layerId = event$id) 113 | }) 114 | 115 | # when sliders are changed, update dropdown 116 | observeEvent(c(input$life_exp_f, input$life_exp_m), { 117 | updateSelectInput(session, "location", choices = data()$country) 118 | }) 119 | 120 | # Reactive timer 121 | autoInvalidate <- reactiveTimer(3000) 122 | 123 | # Generate a new histogram each time the timer fires 124 | output$contPlot <- renderPlot({ 125 | autoInvalidate() 126 | hist(rnorm(10), xlab = "Value", main = "Histogram of a random normal distribution with 10 observations") 127 | }) 128 | 129 | observeEvent(input$playSound, { 130 | disable("playSound") 131 | js$playMusic() 132 | }) 133 | observeEvent(input$stopSound, { 134 | enable("playSound") 135 | js$stopMusic() 136 | }) 137 | observeEvent(input$showProgress, { 138 | Sys.sleep(5) 139 | }) 140 | 141 | }) -------------------------------------------------------------------------------- /ui.R: -------------------------------------------------------------------------------- 1 | source("global.R") 2 | 3 | df <- read.csv("life_exp.csv", stringsAsFactors = FALSE) 4 | 5 | uiLogin <- function(req){ 6 | tagList( 7 | fluidRow( 8 | column(12, 9 | fluidRow(column(width=6, offset = 3, 10 | div( 11 | HTML("

This shiny app contains some tips and tricks that you can use in your application. Most of these are solutions I am frequently using in my apps. It contains: 12 |

13 |

") 28 | ) 29 | )), 30 | hr(), 31 | fluidRow(column(width=3, offset = 4, 32 | wellPanel(id = "login", 33 | textInput(".username", "Username:"), 34 | passwordInput(".password", "Password:"), 35 | div("Please login with test/test", align = "center"), p(), 36 | div(actionButton(".login", "Log in"), style="text-align: center;"), style = "opacity: 0.72" 37 | ), 38 | textOutput("message") 39 | )) 40 | ) 41 | ) 42 | ) 43 | } 44 | 45 | # Sidebar with a slider input for number of bins 46 | uiNormal <- function(req){ 47 | tagList( 48 | sidebarLayout( 49 | sidebarPanel( 50 | selectInput('location', 'Country', choices = unique(df$country)), 51 | sliderInput("distance", "Distance (kms):", min = 0, max = 10000, value = 1000), 52 | sliderInput("life_exp_m", "Life expectancy male:", min = min(df$male), max = max(df$male), value = c(min(df$male), 60)), 53 | sliderInput("life_exp_f", "Life expectancy female:", min = min(df$female), max = max(df$female), value = c(min(df$female), 60)), 54 | checkboxInput("showDataTab", "Show DataTable Tab", TRUE), 55 | hr(), 56 | actionButton("playSound", "Play song"), 57 | actionButton("stopSound", "Stop song"), 58 | actionButton("showProgress", "Show in progress"), 59 | p(), 60 | div(class = "busy", p("In progress.."), img(src="loader.gif")), 61 | width = 3 62 | ), 63 | 64 | # Show a plot of the generated distribution 65 | mainPanel( 66 | tabsetPanel(id='main', 67 | tabPanel('Documentation', includeMarkdown('README.Rmd')), 68 | tabPanel("DataTable", dataTableOutput('df_contents')), 69 | tabPanel("Leaflet", fluidRow(leafletOutput("map", height = "700px"))), 70 | tabPanel("Plotly", fluidRow(plotlyOutput("plot", height = "700px"))), 71 | tabPanel("Contineous update", fluidRow(plotOutput("contPlot"))) 72 | ) 73 | ) 74 | ) 75 | ) 76 | } 77 | 78 | shinyUI(fluidPage( 79 | # Add Javascript 80 | tags$head( 81 | tags$link(rel="stylesheet", type="text/css",href="style.css"), 82 | tags$script(type="text/javascript", src = "md5.js"), 83 | tags$script(type="text/javascript", src = "busy.js"), 84 | tags$script(type="text/javascript", src = "passwdInputBinding.js"), 85 | tags$script(type="text/javascript", src = "google-analytics.js") 86 | ), 87 | useShinyjs(), 88 | extendShinyjs(script = "www/sound.js", functions = c("playMusic", "stopMusic")), 89 | HTML(" 90 |
91 |

Shiny tips&trics

92 | 93 | Created by 94 | Ger Inberg 95 | • 96 | April 2017 97 | • 98 | More apps by Ger 99 | 100 |
"), 101 | div(titlePanel("Shiny tips & tricks"), align = "center"), 102 | uiOutput("content"))) 103 | -------------------------------------------------------------------------------- /www/busy.js: -------------------------------------------------------------------------------- 1 | setInterval(function(){ 2 | if ($('html').attr('class')=='shiny-busy') { 3 | setTimeout(function() { 4 | if ($('html').attr('class')=='shiny-busy') { 5 | $('div.busy').show() 6 | } 7 | }, 1000) 8 | } else { 9 | $('div.busy').hide() 10 | } 11 | }, 100) -------------------------------------------------------------------------------- /www/google-analytics.js: -------------------------------------------------------------------------------- 1 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 2 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 3 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 4 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 5 | 6 | ga('create', 'UA-100322335-1', 'auto'); 7 | ga('send', 'pageview'); 8 | 9 | -------------------------------------------------------------------------------- /www/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginberg/shinytips/864e20d6280191cbb49706bbc2210917b1016d21/www/loader.gif -------------------------------------------------------------------------------- /www/md5.js: -------------------------------------------------------------------------------- 1 | // Downloaded from: http://www.myersdaily.org/joseph/javascript/md5.js; 2 | 3 | function md5cycle(x, k) { 4 | var a = x[0], b = x[1], c = x[2], d = x[3]; 5 | 6 | a = ff(a, b, c, d, k[0], 7, -680876936); 7 | d = ff(d, a, b, c, k[1], 12, -389564586); 8 | c = ff(c, d, a, b, k[2], 17, 606105819); 9 | b = ff(b, c, d, a, k[3], 22, -1044525330); 10 | a = ff(a, b, c, d, k[4], 7, -176418897); 11 | d = ff(d, a, b, c, k[5], 12, 1200080426); 12 | c = ff(c, d, a, b, k[6], 17, -1473231341); 13 | b = ff(b, c, d, a, k[7], 22, -45705983); 14 | a = ff(a, b, c, d, k[8], 7, 1770035416); 15 | d = ff(d, a, b, c, k[9], 12, -1958414417); 16 | c = ff(c, d, a, b, k[10], 17, -42063); 17 | b = ff(b, c, d, a, k[11], 22, -1990404162); 18 | a = ff(a, b, c, d, k[12], 7, 1804603682); 19 | d = ff(d, a, b, c, k[13], 12, -40341101); 20 | c = ff(c, d, a, b, k[14], 17, -1502002290); 21 | b = ff(b, c, d, a, k[15], 22, 1236535329); 22 | 23 | a = gg(a, b, c, d, k[1], 5, -165796510); 24 | d = gg(d, a, b, c, k[6], 9, -1069501632); 25 | c = gg(c, d, a, b, k[11], 14, 643717713); 26 | b = gg(b, c, d, a, k[0], 20, -373897302); 27 | a = gg(a, b, c, d, k[5], 5, -701558691); 28 | d = gg(d, a, b, c, k[10], 9, 38016083); 29 | c = gg(c, d, a, b, k[15], 14, -660478335); 30 | b = gg(b, c, d, a, k[4], 20, -405537848); 31 | a = gg(a, b, c, d, k[9], 5, 568446438); 32 | d = gg(d, a, b, c, k[14], 9, -1019803690); 33 | c = gg(c, d, a, b, k[3], 14, -187363961); 34 | b = gg(b, c, d, a, k[8], 20, 1163531501); 35 | a = gg(a, b, c, d, k[13], 5, -1444681467); 36 | d = gg(d, a, b, c, k[2], 9, -51403784); 37 | c = gg(c, d, a, b, k[7], 14, 1735328473); 38 | b = gg(b, c, d, a, k[12], 20, -1926607734); 39 | 40 | a = hh(a, b, c, d, k[5], 4, -378558); 41 | d = hh(d, a, b, c, k[8], 11, -2022574463); 42 | c = hh(c, d, a, b, k[11], 16, 1839030562); 43 | b = hh(b, c, d, a, k[14], 23, -35309556); 44 | a = hh(a, b, c, d, k[1], 4, -1530992060); 45 | d = hh(d, a, b, c, k[4], 11, 1272893353); 46 | c = hh(c, d, a, b, k[7], 16, -155497632); 47 | b = hh(b, c, d, a, k[10], 23, -1094730640); 48 | a = hh(a, b, c, d, k[13], 4, 681279174); 49 | d = hh(d, a, b, c, k[0], 11, -358537222); 50 | c = hh(c, d, a, b, k[3], 16, -722521979); 51 | b = hh(b, c, d, a, k[6], 23, 76029189); 52 | a = hh(a, b, c, d, k[9], 4, -640364487); 53 | d = hh(d, a, b, c, k[12], 11, -421815835); 54 | c = hh(c, d, a, b, k[15], 16, 530742520); 55 | b = hh(b, c, d, a, k[2], 23, -995338651); 56 | 57 | a = ii(a, b, c, d, k[0], 6, -198630844); 58 | d = ii(d, a, b, c, k[7], 10, 1126891415); 59 | c = ii(c, d, a, b, k[14], 15, -1416354905); 60 | b = ii(b, c, d, a, k[5], 21, -57434055); 61 | a = ii(a, b, c, d, k[12], 6, 1700485571); 62 | d = ii(d, a, b, c, k[3], 10, -1894986606); 63 | c = ii(c, d, a, b, k[10], 15, -1051523); 64 | b = ii(b, c, d, a, k[1], 21, -2054922799); 65 | a = ii(a, b, c, d, k[8], 6, 1873313359); 66 | d = ii(d, a, b, c, k[15], 10, -30611744); 67 | c = ii(c, d, a, b, k[6], 15, -1560198380); 68 | b = ii(b, c, d, a, k[13], 21, 1309151649); 69 | a = ii(a, b, c, d, k[4], 6, -145523070); 70 | d = ii(d, a, b, c, k[11], 10, -1120210379); 71 | c = ii(c, d, a, b, k[2], 15, 718787259); 72 | b = ii(b, c, d, a, k[9], 21, -343485551); 73 | 74 | x[0] = add32(a, x[0]); 75 | x[1] = add32(b, x[1]); 76 | x[2] = add32(c, x[2]); 77 | x[3] = add32(d, x[3]); 78 | 79 | } 80 | 81 | function cmn(q, a, b, x, s, t) { 82 | a = add32(add32(a, q), add32(x, t)); 83 | return add32((a << s) | (a >>> (32 - s)), b); 84 | } 85 | 86 | function ff(a, b, c, d, x, s, t) { 87 | return cmn((b & c) | ((~b) & d), a, b, x, s, t); 88 | } 89 | 90 | function gg(a, b, c, d, x, s, t) { 91 | return cmn((b & d) | (c & (~d)), a, b, x, s, t); 92 | } 93 | 94 | function hh(a, b, c, d, x, s, t) { 95 | return cmn(b ^ c ^ d, a, b, x, s, t); 96 | } 97 | 98 | function ii(a, b, c, d, x, s, t) { 99 | return cmn(c ^ (b | (~d)), a, b, x, s, t); 100 | } 101 | 102 | function md51(s) { 103 | txt = ''; 104 | var n = s.length, 105 | state = [1732584193, -271733879, -1732584194, 271733878], i; 106 | for (i=64; i<=s.length; i+=64) { 107 | md5cycle(state, md5blk(s.substring(i-64, i))); 108 | } 109 | s = s.substring(i-64); 110 | var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; 111 | for (i=0; i>2] |= s.charCodeAt(i) << ((i%4) << 3); 113 | tail[i>>2] |= 0x80 << ((i%4) << 3); 114 | if (i > 55) { 115 | md5cycle(state, tail); 116 | for (i=0; i<16; i++) tail[i] = 0; 117 | } 118 | tail[14] = n*8; 119 | md5cycle(state, tail); 120 | return state; 121 | } 122 | 123 | function md5blk(s) { /* I figured global was faster. */ 124 | var md5blks = [], i; /* Andy King said do it this way. */ 125 | for (i=0; i<64; i+=4) { 126 | md5blks[i>>2] = s.charCodeAt(i) 127 | + (s.charCodeAt(i+1) << 8) 128 | + (s.charCodeAt(i+2) << 16) 129 | + (s.charCodeAt(i+3) << 24); 130 | } 131 | return md5blks; 132 | } 133 | 134 | var hex_chr = '0123456789abcdef'.split(''); 135 | 136 | function rhex(n) 137 | { 138 | var s='', j=0; 139 | for(; j<4; j++) 140 | s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] 141 | + hex_chr[(n >> (j * 8)) & 0x0F]; 142 | return s; 143 | } 144 | 145 | function hex(x) { 146 | for (var i=0; i> 16) + (y >> 16) + (lsw >> 16); 163 | return (msw << 16) | (lsw & 0xFFFF); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /www/passwdInputBinding.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | // Password Input 3 | var passwordInputBinding = new Shiny.InputBinding(); 4 | $.extend(passwordInputBinding, { 5 | find: function(scope) { 6 | return $(scope).find('input[type="password"]'); 7 | }, 8 | getId: function(el) { 9 | return Shiny.InputBinding.prototype.getId.call(this, el) || el.name; 10 | }, 11 | getValue: function(el) { 12 | return md5(el.value); 13 | }, 14 | setValue: function(el, value) { 15 | el.value = value; 16 | }, 17 | subscribe: function(el, callback) { 18 | $(el).on('keyup.passwordInputBinding input.passwordInputBinding', function(event) { 19 | callback(true); 20 | }); 21 | $(el).on('change.passwordInputBinding', function(event) { 22 | callback(false); 23 | }); 24 | }, 25 | unsubscribe: function(el) { 26 | $(el).off('.passwordInputBinding'); 27 | }, 28 | getRatePolicy: function() { 29 | return { 30 | policy: 'debounce', 31 | delay: 250 32 | }; 33 | } 34 | }); 35 | Shiny.inputBindings.register(passwordInputBinding, 'shiny.passwordInput'); 36 | }) 37 | 38 | -------------------------------------------------------------------------------- /www/rocky.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginberg/shinytips/864e20d6280191cbb49706bbc2210917b1016d21/www/rocky.wav -------------------------------------------------------------------------------- /www/sound.js: -------------------------------------------------------------------------------- 1 | var soundPlayer = null; 2 | 3 | shinyjs.playMusic = function() { 4 | soundPlayer = new Audio("rocky.wav"); 5 | soundPlayer.addEventListener('ended', function() { 6 | this.currentTime = 0; 7 | this.play(); 8 | }, false); 9 | soundPlayer.play(); 10 | }; 11 | 12 | shinyjs.stopMusic = function() { 13 | soundPlayer.pause(); 14 | soundPlayer.currentTime = 0; 15 | }; -------------------------------------------------------------------------------- /www/style.css: -------------------------------------------------------------------------------- 1 | #message { 2 | color: red; 3 | text-align: center; 4 | font-weight: bold; 5 | } 6 | 7 | #login { 8 | margin-top: 20px; 9 | } 10 | 11 | .well { 12 | padding: 12px; 13 | margin-bottom: 5px; 14 | } 15 | 16 | #headerSection { 17 | margin: -20px 0 20px; 18 | color: #FAFAFA; 19 | padding: 10px 10px; 20 | box-shadow: 0 0 7px #000; 21 | background: gray; 22 | } 23 | #headerSection a { 24 | color: white !important; 25 | text-decoration: underline; 26 | } 27 | --------------------------------------------------------------------------------