├── .Rbuildignore ├── LICENSE ├── .gitignore ├── .github └── FUNDING.yml ├── NAMESPACE ├── inst └── htmlwidgets │ ├── lib │ └── vis-4.16.1 │ │ ├── img │ │ ├── network │ │ │ ├── cross.png │ │ │ ├── minus.png │ │ │ ├── plus.png │ │ │ ├── cross2.png │ │ │ ├── upArrow.png │ │ │ ├── backIcon.png │ │ │ ├── deleteIcon.png │ │ │ ├── downArrow.png │ │ │ ├── editIcon.png │ │ │ ├── leftArrow.png │ │ │ ├── rightArrow.png │ │ │ ├── addNodeIcon.png │ │ │ ├── connectIcon.png │ │ │ ├── zoomExtends.png │ │ │ └── acceptDeleteIcon.png │ │ └── timeline │ │ │ └── delete.png │ │ └── vis.min.css │ ├── timevisBasic.yaml │ └── timevisBasic.js ├── timevisBasic.Rproj ├── DESCRIPTION ├── man ├── timevis-shiny.Rd └── timevis.Rd ├── R └── timevisBasic.R └── README.md /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2016 2 | COPYRIGHT HOLDER: Dean Attali 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: daattali 4 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(renderTimevis) 4 | export(timevis) 5 | export(timevisOutput) 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/cross.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/minus.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/plus.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/cross2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/cross2.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/upArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/upArrow.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/timeline/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/timeline/delete.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/backIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/backIcon.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/deleteIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/deleteIcon.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/downArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/downArrow.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/editIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/editIcon.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/leftArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/leftArrow.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/rightArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/rightArrow.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/addNodeIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/addNodeIcon.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/connectIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/connectIcon.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/zoomExtends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/zoomExtends.png -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/img/network/acceptDeleteIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daattali/timevisBasic/HEAD/inst/htmlwidgets/lib/vis-4.16.1/img/network/acceptDeleteIcon.png -------------------------------------------------------------------------------- /inst/htmlwidgets/timevisBasic.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: vis 3 | version: 4.16.1 4 | src: htmlwidgets/lib/vis-4.16.1 5 | script: vis.min.js 6 | stylesheet: vis.min.css 7 | 8 | - name: timeline 9 | version: 0.1 10 | src: htmlwidgets 11 | -------------------------------------------------------------------------------- /timevisBasic.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | PackageRoxygenize: rd,collate,namespace 19 | -------------------------------------------------------------------------------- /inst/htmlwidgets/timevisBasic.js: -------------------------------------------------------------------------------- 1 | /*********************************************************************/ 2 | /* Dean Attali 2016 */ 3 | /* timevis */ 4 | /* Create timeline visualizations in R using htmlwidgets and vis.js */ 5 | /*********************************************************************/ 6 | 7 | HTMLWidgets.widget({ 8 | 9 | name : 'timevisBasic', 10 | type : 'output', 11 | 12 | factory : function(el, width, height) { 13 | 14 | var elementId = el.id; 15 | var container = document.getElementById(elementId); 16 | var timeline = new vis.Timeline(container, [], {}); 17 | 18 | return { 19 | 20 | renderValue: function(x) { 21 | timeline.itemsData.add(x.items); 22 | }, 23 | 24 | resize : function(width, height) { 25 | // we won't be implementing a resize function 26 | } 27 | 28 | }; 29 | } 30 | }); -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: timevisBasic 2 | Title: Helper Package To Learn Advanced 'htmlwidgets' Tips 3 | Version: 0.1 4 | Authors@R: c( 5 | person("Dean", "Attali", email = "daattali@gmail.com", 6 | role = c("aut", "cre"), comment = "R interface"), 7 | person(family = "Almende B.V.", role = c("aut", "cph"), 8 | comment = "vis.js library, http://visjs.org, http://www.almende.com/home") 9 | ) 10 | Description: The 'timevis' package is an htmlwidget that lets you create 11 | timeline visualizations. This package includes a very basic implementation 12 | of the 'timevis' package and is used as an educational tool for teaching 13 | advanced 'htmlwidgets' tips. See 14 | http://deanattali.com/blog/advanced-htmlwidgets-tips for the tutorial. 15 | URL: https://github.com/daattali/timevisBasic 16 | Depends: 17 | R (>= 3.1.0) 18 | Imports: 19 | htmltools (>= 0.2.6), 20 | htmlwidgets (>= 0.6), 21 | jsonlite, 22 | magrittr, 23 | methods, 24 | rmarkdown, 25 | shiny 26 | Suggests: 27 | knitr (>= 1.7) 28 | License: MIT + file LICENSE 29 | Encoding: UTF-8 30 | LazyData: true 31 | RoxygenNote: 5.0.1 32 | -------------------------------------------------------------------------------- /man/timevis-shiny.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/timevisBasic.R 3 | \name{timevis-shiny} 4 | \alias{renderTimevis} 5 | \alias{timevis-shiny} 6 | \alias{timevisOutput} 7 | \title{Shiny bindings for timevis} 8 | \usage{ 9 | timevisOutput(outputId, width = "100\%", height = "auto") 10 | 11 | renderTimevis(expr, env = parent.frame(), quoted = FALSE) 12 | } 13 | \arguments{ 14 | \item{outputId}{output variable to read from} 15 | 16 | \item{width, height}{Must be a valid CSS unit (like \code{'100\%'}, 17 | \code{'400px'}, \code{'auto'}) or a number, which will be coerced to a 18 | string and have \code{'px'} appended. \code{height} will probably not 19 | have an effect; instead, use the \code{height} parameter in 20 | \code{\link[timevis]{timevis}}.} 21 | 22 | \item{expr}{An expression that generates a timevis} 23 | 24 | \item{env}{The environment in which to evaluate \code{expr}.} 25 | 26 | \item{quoted}{Is \code{expr} a quoted expression (with \code{quote()})? This 27 | is useful if you want to save an expression in a variable.} 28 | } 29 | \description{ 30 | Output and render functions for using timevis within Shiny 31 | applications and interactive Rmd documents. 32 | } 33 | 34 | -------------------------------------------------------------------------------- /man/timevis.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/timevisBasic.R 3 | \name{timevis} 4 | \alias{timevis} 5 | \title{Create a basic timeline visualization} 6 | \usage{ 7 | timevis(data = list(), width = NULL, height = NULL, elementId = NULL) 8 | } 9 | \description{ 10 | Create a basic timeline visualization 11 | } 12 | \examples{ 13 | # Example 1 - no data 14 | timevis() 15 | 16 | # Example 2 - with data 17 | 18 | # The data to use UNTIL you implement tip 3 (implementing 'dataframeToD3()') 19 | data <- list(list(content = "today", start = Sys.Date()), 20 | list(content = "tomorrow", start = Sys.Date() + 1)) 21 | # The data to use AFTER you implement tip 3 (implementing 'dataframeToD3()') 22 | # data <- data.frame(content = c("today", "tomorrow"), 23 | # start = c(Sys.Date(), Sys.Date() + 1)) 24 | timevis(data) 25 | 26 | # Example 3 - in a Shiny app 27 | library(shiny) 28 | shinyApp( 29 | ui = timevisOutput("timeline"), 30 | server = function(input, output) { 31 | output$timeline <- renderTimevis( 32 | timevis(data) 33 | ) 34 | } 35 | ) 36 | } 37 | \seealso{ 38 | \href{http://daattali.com/shiny/timevis-demo/}{Demo Shiny app} 39 | } 40 | 41 | -------------------------------------------------------------------------------- /R/timevisBasic.R: -------------------------------------------------------------------------------- 1 | #' Create a basic timeline visualization 2 | #' 3 | #' @seealso \href{http://daattali.com/shiny/timevis-demo/}{Demo Shiny app} 4 | #' @examples 5 | #' # Example 1 - no data 6 | #' timevis() 7 | #' 8 | #' # Example 2 - with data 9 | #' 10 | #' # The data to use UNTIL you implement tip 3 (implementing 'dataframeToD3()') 11 | #' data <- list(list(content = "today", start = Sys.Date()), 12 | #' list(content = "tomorrow", start = Sys.Date() + 1)) 13 | #' # The data to use AFTER you implement tip 3 (implementing 'dataframeToD3()') 14 | #' # data <- data.frame(content = c("today", "tomorrow"), 15 | #' # start = c(Sys.Date(), Sys.Date() + 1)) 16 | #' timevis(data) 17 | #' 18 | #' # Example 3 - in a Shiny app 19 | #' library(shiny) 20 | #' shinyApp( 21 | #' ui = timevisOutput("timeline"), 22 | #' server = function(input, output) { 23 | #' output$timeline <- renderTimevis( 24 | #' timevis(data) 25 | #' ) 26 | #' } 27 | #' ) 28 | #' @export 29 | timevis <- function(data = list(), width = NULL, height = NULL, elementId = NULL) { 30 | items <- data 31 | 32 | # forward options using x 33 | x = list( 34 | items = items 35 | ) 36 | 37 | # create widget 38 | htmlwidgets::createWidget( 39 | name = 'timevisBasic', 40 | x, 41 | width = width, 42 | height = height, 43 | package = 'timevisBasic', 44 | elementId = elementId 45 | ) 46 | } 47 | 48 | #' Shiny bindings for timevis 49 | #' 50 | #' Output and render functions for using timevis within Shiny 51 | #' applications and interactive Rmd documents. 52 | #' 53 | #' @param outputId output variable to read from 54 | #' @param width,height Must be a valid CSS unit (like \code{'100\%'}, 55 | #' \code{'400px'}, \code{'auto'}) or a number, which will be coerced to a 56 | #' string and have \code{'px'} appended. \code{height} will probably not 57 | #' have an effect; instead, use the \code{height} parameter in 58 | #' \code{\link[timevis]{timevis}}. 59 | #' @param expr An expression that generates a timevis 60 | #' @param env The environment in which to evaluate \code{expr}. 61 | #' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This 62 | #' is useful if you want to save an expression in a variable. 63 | #' 64 | #' @name timevis-shiny 65 | #' @export 66 | timevisOutput <- function(outputId, width = '100%', height = 'auto') { 67 | htmlwidgets::shinyWidgetOutput(outputId, 'timevisBasic', width, height, package = 'timevisBasic') 68 | } 69 | 70 | #' @rdname timevis-shiny 71 | #' @export 72 | renderTimevis <- function(expr, env = parent.frame(), quoted = FALSE) { 73 | if (!quoted) { expr <- substitute(expr) } # force quoted 74 | htmlwidgets::shinyRenderWidget(expr, timevisOutput, env, quoted = TRUE) 75 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # timevisBasic - Helper package to learn advanced 'htmlwidgets' tips 2 | 3 | The [`timevis`](https://github.com/daattali/timevis) package is an htmlwidget that lets you create timeline visualizations. This package includes a very basic implementation of the `timevis` package and is used as an educational tool for teaching advanced htmlwidgets tips. 4 | 5 | ## Tutorial 6 | 7 | [>> Click here to read the full tutorial <<](http://deanattali.com/blog/advanced-htmlwidgets-tips) 8 | 9 | The code in this package is used as the starting point for the tutorial above. Every tip in the tutorial will walk you through adding a useful feature to the package, and you can see the final result of each step as a [separate branch](https://github.com/daattali/timevisBasic/branches/all) in this repo. 10 | 11 | ## Example code 12 | 13 | The `master` branch of this repo has the most basic htmlwidget possible, and there are [12 other branches](https://github.com/daattali/timevisBasic/branches/all), corresponding to the 12 steps in the tutorial. Each branch has the complete code from its corresponding step, so that you can see it in a real working app to be convinced that what I wrote in the tutorial really does work. 14 | 15 | Since each tip in the tutorial results in a more and more feature-heavy widget, I will give you an example code usage for every step. Don't forget to include `library(shiny)` to make all the sample codes work. 16 | 17 | ### Example code for the initial project (what you can run right now) 18 | 19 | Using the code in the master branch, the following simple app should give you a minimal timeline widget. 20 | 21 | ``` 22 | data <- list(list(content = "today", start = Sys.Date()), 23 | list(content = "tomorrow", start = Sys.Date() + 1)) 24 | shinyApp( 25 | ui = timevisOutput("timeline"), 26 | server = function(input, output) { 27 | output$timeline <- renderTimevis( 28 | timevis(data) 29 | ) 30 | } 31 | ) 32 | ``` 33 | 34 | ### Example code for tip 1: 35 | 36 | [See the code changes for tip 1](https://github.com/daattali/timevisBasic/compare/tip1-rendervalue-x-name#diff) 37 | 38 | Tip 1 was a very small change so the previous code will still work the same way. 39 | 40 | ### Example code for tip 2: 41 | 42 | [See the code changes for tip 2](https://github.com/daattali/timevisBasic/compare/tip1-rendervalue-x-name...tip2-custom-html#diff) 43 | 44 | The previous code will still work, but now you should be able to see zoom in and zoom out buttons (though we didn't make those buttons functional). 45 | 46 | ### Example code for tip 3: 47 | 48 | [See the code changes for tip 3](https://github.com/daattali/timevisBasic/compare/tip2-custom-html...tip3-dataframeToD3#diff) 49 | 50 | We added `dataframeToD3()` function, so now our data frame can be simplified, but the app code remains the same. 51 | 52 | ``` 53 | data <- data.frame(content = c("today", "tomorrow"), 54 | start = c(Sys.Date(), Sys.Date() + 1)) 55 | shinyApp( 56 | ui = timevisOutput("timeline"), 57 | server = function(input, output) { 58 | output$timeline <- renderTimevis( 59 | timevis(data) 60 | ) 61 | } 62 | ) 63 | ``` 64 | 65 | ### Example code for tip 4: 66 | 67 | [See the code changes for tip 4](https://github.com/daattali/timevisBasic/compare/tip3-dataframeToD3...tip4-rendervalue-multiple-times#diff) 68 | 69 | In this tip, we made sure the widget only renders the latest data, rather than all the previous data as well. Run the following shiny app now, and try running it prior to tip 4 to see the difference. 70 | 71 | ``` 72 | shinyApp( 73 | ui = fluidPage( 74 | textInput("text", "Text", "Hello"), 75 | timevisOutput("timeline") 76 | ), 77 | server = function(input, output) { 78 | output$timeline <- renderTimevis({ 79 | data <- data.frame(content = input$text, start = Sys.Date()) 80 | timevis(data) 81 | }) 82 | } 83 | ) 84 | ``` 85 | 86 | ### Example code for tip 5: 87 | 88 | [See the code changes for tip 5](https://github.com/daattali/timevisBasic/compare/tip4-rendervalue-multiple-times...tip5-init-once#diff) 89 | 90 | Run the same code as before, and you'll see that the initialization message runs only once. 91 | 92 | ### Example code for tip 6: 93 | 94 | [See the code changes for tip 6](https://github.com/daattali/timevisBasic/compare/tip5-init-once...tip6-shinyMode#diff) 95 | 96 | If you run the same Shiny app code as before, you'll get a message telling you that you're inside a Shiny app. If you simply run `timevis()` in the console, the widget will render, but you will not be told you're in Shiny. 97 | 98 | ### Example code for tip 7a: 99 | 100 | [See the code changes for tip 7a](https://github.com/daattali/timevisBasic/compare/tip6-shinyMode...tip7a-widget-to-r-data#diff) 101 | 102 | You can now select events in the timeline (by clicking on them) and the event ID (which just looks like random text) will be passed back to R. 103 | 104 | ``` 105 | data <- data.frame(content = c("today", "tomorrow"), 106 | start = c(Sys.Date(), Sys.Date() + 1)) 107 | 108 | shinyApp( 109 | ui = fluidPage( 110 | timevisOutput("timeline"), 111 | textOutput("selected") 112 | ), 113 | server = function(input, output) { 114 | output$timeline <- renderTimevis({ 115 | timevis(data) 116 | }) 117 | output$selected <- renderText({ 118 | input$timeline_selected 119 | }) 120 | } 121 | ) 122 | ``` 123 | 124 | ### Example code for tip 7b: 125 | 126 | [See the code changes for tip 7b](https://github.com/daattali/timevisBasic/compare/tip7a-widget-to-r-data...tip7b-javascript-to-r-handler#diff) 127 | 128 | The data from the timeline can now be passed back into R whenever it changes (you can double click anywhere to create a new item, or click on an item to delete it). 129 | 130 | ``` 131 | data <- data.frame(content = c("today", "tomorrow"), 132 | start = c(Sys.Date(), Sys.Date() + 1)) 133 | 134 | shinyApp( 135 | ui = fluidPage( 136 | timevisOutput("timeline"), 137 | tableOutput("data") 138 | ), 139 | server = function(input, output) { 140 | output$timeline <- renderTimevis({ 141 | timevis(data) 142 | }) 143 | output$data <- renderTable({ 144 | input$timeline_data 145 | }) 146 | } 147 | ) 148 | ``` 149 | 150 | ### Example code for tip 8a: 151 | 152 | [See the code changes for tip 8a](https://github.com/daattali/timevisBasic/compare/tip7b-javascript-to-r-handler...tip8a-api-basic#diff) 153 | 154 | We just implemented a simple API function `setWindow()`, which we can call in a Shiny app. 155 | 156 | ``` 157 | shinyApp( 158 | ui = fluidPage( 159 | timevisOutput("timeline"), br(), 160 | actionButton("btn", "Set window between yesterday and tomorrow") 161 | ), 162 | server = function(input, output) { 163 | output$timeline <- renderTimevis({ 164 | timevis() 165 | }) 166 | observeEvent(input$btn, { 167 | setWindow("timeline", start = Sys.Date() - 1, end = Sys.Date() + 1) 168 | }) 169 | } 170 | ) 171 | ``` 172 | 173 | ### Example code for tip 8b: 174 | 175 | [See the code changes for tip 8b](https://github.com/daattali/timevisBasic/compare/tip8a-api-basic...tip8b-api-abstract#diff) 176 | 177 | Nothing user-facing has changed, we just abstracted a lot of the API code. The previous app code should still work. 178 | 179 | ### Example code for tip 8c: 180 | 181 | [See the code changes for tip 8c](https://github.com/daattali/timevisBasic/compare/tip8b-api-abstract...tip8c-api-chain#diff) 182 | 183 | We can now chain API functions with `%>%` to make it easy to call multiple functions consecutively. 184 | 185 | ``` 186 | shinyApp( 187 | ui = fluidPage( 188 | timevisOutput("timeline"), br(), 189 | actionButton("btn", "Add a blue line at midnight last night and set window between yesterday and tomorrow") 190 | ), 191 | server = function(input, output) { 192 | output$timeline <- renderTimevis({ 193 | timevis() 194 | }) 195 | observeEvent(input$btn, { 196 | setWindow("timeline", start = Sys.Date() - 1, end = Sys.Date() + 1) %>% 197 | addCustomTime(Sys.Date()) 198 | }) 199 | } 200 | ) 201 | ``` 202 | 203 | ### Example code for tip 8d: 204 | 205 | [See the code changes for tip 8d](https://github.com/daattali/timevisBasic/compare/tip8c-api-chain...tip8d-api-not-just-shiny#diff) 206 | 207 | You can now call API functions directly on an htmlwidget rather than using an ID, and they are also chain-able. This means that API functions can even be called on timeline widgets that are rendered outside of Shiny. 208 | 209 | ``` 210 | timevis() %>% 211 | setWindow(start = Sys.Date() - 1, end = Sys.Date() + 1) %>% 212 | addCustomTime(Sys.Date()) 213 | ``` 214 | 215 | After implementing all these tips, the app is a lot more useful. Hopefully you can now translate this knowledge into your own htmlwidget! 216 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vis-4.16.1/vis.min.css: -------------------------------------------------------------------------------- 1 | .vis-background,.vis-labelset,.vis-timeline{overflow:hidden}.vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis [class*=span]{min-height:0;width:auto}div.vis-configuration{position:relative;display:block;float:left;font-size:12px}div.vis-configuration-wrapper{display:block;width:700px}div.vis-configuration-wrapper::after{clear:both;content:"";display:block}div.vis-configuration.vis-config-option-container{display:block;width:495px;background-color:#fff;border:2px solid #f7f8fa;border-radius:4px;margin-top:20px;left:10px;padding-left:5px}div.vis-configuration.vis-config-button{display:block;width:495px;height:25px;vertical-align:middle;line-height:25px;background-color:#f7f8fa;border:2px solid #ceced0;border-radius:4px;margin-top:20px;left:10px;padding-left:5px;cursor:pointer;margin-bottom:30px}div.vis-configuration.vis-config-button.hover{background-color:#4588e6;border:2px solid #214373;color:#fff}div.vis-configuration.vis-config-item{display:block;float:left;width:495px;height:25px;vertical-align:middle;line-height:25px}div.vis-configuration.vis-config-item.vis-config-s2{left:10px;background-color:#f7f8fa;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s3{left:20px;background-color:#e4e9f0;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s4{left:30px;background-color:#cfd8e6;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-header{font-size:18px;font-weight:700}div.vis-configuration.vis-config-label{width:120px;height:25px;line-height:25px}div.vis-configuration.vis-config-label.vis-config-s3{width:110px}div.vis-configuration.vis-config-label.vis-config-s4{width:100px}div.vis-configuration.vis-config-colorBlock{top:1px;width:30px;height:19px;border:1px solid #444;border-radius:2px;padding:0;margin:0;cursor:pointer}input.vis-configuration.vis-config-checkbox{left:-5px}input.vis-configuration.vis-config-rangeinput{position:relative;top:-5px;width:60px;padding:1px;margin:0;pointer-events:none}.vis-panel,.vis-timeline{padding:0;box-sizing:border-box}input.vis-configuration.vis-config-range{-webkit-appearance:none;border:0 solid #fff;background-color:rgba(0,0,0,0);width:300px;height:20px}input.vis-configuration.vis-config-range::-webkit-slider-runnable-track{width:300px;height:5px;background:#dedede;background:-moz-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dedede),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-o-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:linear-gradient(to bottom,#dedede 0,#c8c8c8 99%);filter:progid: DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8', GradientType=0);border:1px solid #999;box-shadow:#aaa 0 0 3px 0;border-radius:3px}input.vis-configuration.vis-config-range::-webkit-slider-thumb{-webkit-appearance:none;border:1px solid #14334b;height:17px;width:17px;border-radius:50%;background:#3876c2;background:-moz-linear-gradient(top,#3876c2 0,#385380 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#3876c2),color-stop(100%,#385380));background:-webkit-linear-gradient(top,#3876c2 0,#385380 100%);background:-o-linear-gradient(top,#3876c2 0,#385380 100%);background:-ms-linear-gradient(top,#3876c2 0,#385380 100%);background:linear-gradient(to bottom,#3876c2 0,#385380 100%);filter:progid: DXImageTransform.Microsoft.gradient( startColorstr='#3876c2', endColorstr='#385380', GradientType=0);box-shadow:#111927 0 0 1px 0;margin-top:-7px}input.vis-configuration.vis-config-range:focus{outline:0}input.vis-configuration.vis-config-range:focus::-webkit-slider-runnable-track{background:#9d9d9d;background:-moz-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#9d9d9d),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-o-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:linear-gradient(to bottom,#9d9d9d 0,#c8c8c8 99%);filter:progid: DXImageTransform.Microsoft.gradient( startColorstr='#9d9d9d', endColorstr='#c8c8c8', GradientType=0)}input.vis-configuration.vis-config-range::-moz-range-track{width:300px;height:10px;background:#dedede;background:-moz-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dedede),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-o-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:linear-gradient(to bottom,#dedede 0,#c8c8c8 99%);filter:progid: DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8', GradientType=0);border:1px solid #999;box-shadow:#aaa 0 0 3px 0;border-radius:3px}input.vis-configuration.vis-config-range::-moz-range-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:-moz-focusring{outline:#fff solid 1px;outline-offset:-1px}input.vis-configuration.vis-config-range::-ms-track{width:300px;height:5px;background:0 0;border-color:transparent;border-width:6px 0;color:transparent}input.vis-configuration.vis-config-range::-ms-fill-lower{background:#777;border-radius:10px}input.vis-configuration.vis-config-range::-ms-fill-upper{background:#ddd;border-radius:10px}input.vis-configuration.vis-config-range::-ms-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:focus::-ms-fill-lower{background:#888}input.vis-configuration.vis-config-range:focus::-ms-fill-upper{background:#ccc}.vis-configuration-popup{position:absolute;background:rgba(57,76,89,.85);border:2px solid #f2faff;line-height:30px;height:30px;width:150px;text-align:center;color:#fff;font-size:14px;border-radius:4px;-webkit-transition:opacity .3s ease-in-out;-moz-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out}.vis-configuration-popup:after,.vis-configuration-popup:before{left:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.vis-configuration-popup:after{border-color:rgba(136,183,213,0);border-left-color:rgba(57,76,89,.85);border-width:8px;margin-top:-8px}.vis-configuration-popup:before{border-color:rgba(194,225,245,0);border-left-color:#f2faff;border-width:12px;margin-top:-12px}.vis-timeline{position:relative;border:1px solid #bfbfbf;margin:0}.vis-panel{position:absolute;margin:0}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right,.vis-panel.vis-top{border:1px #bfbfbf}.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-top{border-left-style:solid;border-right-style:solid}.vis-panel>.vis-content{position:relative}.vis-panel .vis-shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis-itemset,.vis-labelset,.vis-labelset .vis-label{position:relative;box-sizing:border-box}.vis-panel .vis-shadow.vis-top{top:-1px;left:0}.vis-panel .vis-shadow.vis-bottom{bottom:-1px;left:0}.vis-labelset .vis-label{left:0;top:0;width:100%;color:#4d4d4d;border-bottom:1px solid #bfbfbf}.vis-labelset .vis-label.draggable{cursor:pointer}.vis-labelset .vis-label:last-child{border-bottom:none}.vis-labelset .vis-label .vis-inner{display:inline-block;padding:5px}.vis-labelset .vis-label .vis-inner.vis-hidden{padding:0}.vis-itemset{padding:0;margin:0}.vis-itemset .vis-background,.vis-itemset .vis-foreground{position:absolute;width:100%;height:100%;overflow:visible}.vis-axis{position:absolute;width:100%;height:0;left:0;z-index:1}.vis-foreground .vis-group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis-foreground .vis-group:last-child{border-bottom:none}.vis-overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block}.vis-item.vis-point.vis-selected,.vis-item.vis-selected{background-color:#FFF785}.vis-item.vis-selected{border-color:#FFC200;z-index:2}.vis-editable.vis-selected{cursor:move}.vis-item.vis-box{text-align:center;border-style:solid;border-radius:2px}.vis-item.vis-point{background:0 0}.vis-item.vis-dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis-item.vis-range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis-item.vis-background{border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis-item .vis-item-overflow{position:relative;width:100%;height:100%;padding:0;margin:0;overflow:hidden}.vis-item .vis-delete,.vis-item .vis-delete-rtl{background:url(img/timeline/delete.png) center no-repeat;height:24px;top:-4px;cursor:pointer}.vis-item.vis-range .vis-item-content{position:relative;display:inline-block}.vis-item.vis-background .vis-item-content{position:absolute;display:inline-block}.vis-item.vis-line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis-item .vis-item-content{white-space:nowrap;box-sizing:border-box;padding:5px}.vis-item .vis-delete{position:absolute;width:24px;right:-24px}.vis-item .vis-delete-rtl{position:absolute;width:24px;left:-24px}.vis-item.vis-range .vis-drag-left{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;left:-4px;cursor:w-resize}.vis-item.vis-range .vis-drag-right{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;right:-4px;cursor:e-resize}.vis-range.vis-item.vis-readonly .vis-drag-left,.vis-range.vis-item.vis-readonly .vis-drag-right{cursor:auto}.vis-time-axis{position:relative;overflow:hidden}.vis-time-axis.vis-foreground{top:0;left:0;width:100%}.vis-time-axis.vis-background{position:absolute;top:0;left:0;width:100%;height:100%}.vis-time-axis .vis-text{position:absolute;color:#4d4d4d;padding:3px;overflow:hidden;box-sizing:border-box;white-space:nowrap}.vis-time-axis .vis-text.vis-measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis-time-axis .vis-grid.vis-vertical{position:absolute;border-left:1px solid}.vis-time-axis .vis-grid.vis-vertical-rtl{position:absolute;border-right:1px solid}.vis-time-axis .vis-grid.vis-minor{border-color:#e5e5e5}.vis-time-axis .vis-grid.vis-major{border-color:#bfbfbf}.vis-current-time{background-color:#FF7F6E;width:2px;z-index:1}.vis-custom-time{background-color:#6E94FF;width:2px;cursor:move;z-index:1}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor{border-color:#e5e5e5}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major{border-color:#bfbfbf}.vis-data-axis .vis-y-axis.vis-major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-major.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-minor.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis-data-axis .vis-y-axis.vis-title.vis-measure{padding:0;margin:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title.vis-left{bottom:0;-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left bottom;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.vis-data-axis .vis-y-axis.vis-title.vis-right{bottom:0;-webkit-transform-origin:right bottom;-moz-transform-origin:right bottom;-ms-transform-origin:right bottom;-o-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.vis-legend{background-color:rgba(247,252,255,.65);padding:5px;border:1px solid #b3b3b3;box-shadow:2px 2px 10px rgba(154,154,154,.55)}.vis-legend-text{white-space:nowrap;display:inline-block}.vis-graph-group0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis-graph-group1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis-graph-group2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis-graph-group3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis-graph-group4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis-graph-group5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis-graph-group6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis-graph-group7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis-graph-group8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis-graph-group9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis-timeline .vis-fill{fill-opacity:.1;stroke:none}.vis-timeline .vis-bar{fill-opacity:.5;stroke-width:1px}.vis-timeline .vis-point{stroke-width:2px;fill-opacity:1}.vis-timeline .vis-legend-background{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis-timeline .vis-outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis-timeline .vis-icon-fill{fill-opacity:.3;stroke:none}div.vis-color-picker{position:absolute;top:0;left:30px;margin-top:-140px;margin-left:30px;width:310px;height:444px;z-index:1;padding:10px;border-radius:15px;background-color:#fff;display:none;box-shadow:rgba(0,0,0,.5) 0 0 10px 0}div.vis-color-picker div.vis-arrow{position:absolute;top:147px;left:5px}div.vis-color-picker div.vis-arrow::after,div.vis-color-picker div.vis-arrow::before{right:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.vis-color-picker div.vis-arrow:after{border-color:rgba(255,255,255,0);border-right-color:#fff;border-width:30px;margin-top:-30px}div.vis-color-picker div.vis-color{position:absolute;width:289px;height:289px;cursor:pointer}div.vis-color-picker div.vis-brightness{position:absolute;top:313px}div.vis-color-picker div.vis-opacity{position:absolute;top:350px}div.vis-color-picker div.vis-selector{position:absolute;top:137px;left:137px;width:15px;height:15px;border-radius:15px;border:1px solid #fff;background:#4c4c4c;background:-moz-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4c4c4c),color-stop(12%,#595959),color-stop(25%,#666),color-stop(39%,#474747),color-stop(50%,#2c2c2c),color-stop(51%,#000),color-stop(60%,#111),color-stop(76%,#2b2b2b),color-stop(91%,#1c1c1c),color-stop(100%,#131313));background:-webkit-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-o-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-ms-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:linear-gradient(to bottom,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);filter:progid: DXImageTransform.Microsoft.gradient( startColorstr='#4c4c4c', endColorstr='#131313', GradientType=0)}div.vis-color-picker div.vis-initial-color,div.vis-color-picker div.vis-new-color{width:140px;height:20px;top:380px;font-size:10px;color:rgba(0,0,0,.4);line-height:20px;position:absolute;vertical-align:middle}div.vis-color-picker div.vis-new-color{border:1px solid rgba(0,0,0,.1);border-radius:5px;left:159px;text-align:right;padding-right:2px}div.vis-color-picker div.vis-initial-color{border:1px solid rgba(0,0,0,.1);border-radius:5px;left:10px;text-align:left;padding-left:2px}div.vis-color-picker div.vis-label{position:absolute;width:300px;left:10px}div.vis-color-picker div.vis-label.vis-brightness{top:300px}div.vis-color-picker div.vis-label.vis-opacity{top:338px}div.vis-color-picker div.vis-button{position:absolute;width:68px;height:25px;border-radius:10px;vertical-align:middle;text-align:center;line-height:25px;top:410px;border:2px solid #d9d9d9;background-color:#f7f7f7;cursor:pointer}div.vis-color-picker div.vis-button.vis-cancel{left:5px}div.vis-color-picker div.vis-button.vis-load{left:82px}div.vis-color-picker div.vis-button.vis-apply{left:159px}div.vis-color-picker div.vis-button.vis-save{left:236px}div.vis-color-picker input.vis-range{width:290px;height:20px} --------------------------------------------------------------------------------