From 02ab66259abeb2bf92593e2af5c87b28da77ff64 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Thu, 13 Sep 2012 23:00:35 -0700 Subject: [PATCH] Yet more input/output work --- _includes/tutorial/building-inputs.md | 4 ++- _includes/tutorial/building-outputs.md | 49 ++++++++++++++++---------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/_includes/tutorial/building-inputs.md b/_includes/tutorial/building-inputs.md index c748bf9e3..a8b36d575 100644 --- a/_includes/tutorial/building-inputs.md +++ b/_includes/tutorial/building-inputs.md @@ -1,6 +1,8 @@ ## Building Inputs -If you have some knowledge of HTML/CSS/JavaScript, you can create your own custom input components that can be reused by others. +Shiny comes equipped with a variety of useful input components, but as you build more ambitious applications, you may find yourself needing input widgets that we don't include. Fortunately, Shiny is designed to let you create your own custom input components. If you can implement it using HTML, CSS, and JavaScript, you can use it as a Shiny input! + +(If you're only familiar with R and not with HTML/CSS/JavaScript, then you will likely find it tough to create all but the simplest custom input components on your own. However, other people can – and hopefully will – bundle up their custom Shiny input components as R packages and make them available to the world.) ### Design the Component diff --git a/_includes/tutorial/building-outputs.md b/_includes/tutorial/building-outputs.md index 7840a4833..d27a9eb19 100644 --- a/_includes/tutorial/building-outputs.md +++ b/_includes/tutorial/building-outputs.md @@ -1,17 +1,43 @@ ## Building Outputs -Similar to custom inputs, if you have some knowledge of HTML/CSS/JavaScript you can also build reusable, custom *output* components. +Right out of the box, Shiny makes it easy to include plots, simple tables, and text as outputs in your application; but we imagine that you'll also want to display outputs that don't fit into those categories. Perhaps you need an interactive [choropleth map](http://en.wikipedia.org/wiki/Choropleth_map) or a [googleVis motion chart](http://code.google.com/p/google-motion-charts-with-r/). -Output values are received from the server and are directed to an *output binding*, which then +Similar to custom inputs, if you have some knowledge of HTML/CSS/JavaScript you can also build reusable, custom output components. And you can bundle up output components as R packages for other Shiny users to use. +### Server-Side Output Functions +Start by deciding the kind of values your output component is going to receive from the user's server side R code. +Whatever value the user's R code returns is going to need to somehow be turned into a JSON-compatible value (Shiny uses [RJSONIO](http://cran.r-project.org/web/packages/RJSONIO/index.html) to do the conversion). If the user's code is naturally going to return something RJSONIO-compatible – like a character vector, a data frame, or even a list that contains atomic vectors – then you can just direct the user to use a regular `reactive` function on the server. However, if the output needs to undergo some other kind of transformation, then you'll need to write a wrapper function for `reactive` that your users will use instead (analogous to `reactivePlot` or `reactiveTable`). +For example, if the user wants to output [time series objects](http://stat.ethz.ch/R-manual/R-patched/library/stats/html/ts.html) then you might create a `reactiveTimeSeries` function that knows how to translate `ts` objects to a simple list or data frame: +
reactiveTimeSeries <- function(func) {
+    reactive(function() {
+        val < func()
+        list(start = tsp(val)[1],
+             end = tsp(val)[2],
+             freq = tsp(val)[3],
+             data = as.vector(val))
+    })
+}
+which would then be used by the user like so: +
output$timeSeries1 <- reactiveTimeSeries(function() {
+    ts(matrix(rnorm(300), 100, 3), start=c(1961, 1), frequency=12)
+})
+
+### Design Output Component Markup +At this point, we're ready to design the HTML markup and write the JavaScript code for our output component. + +For many components, you'll be able to have extremely simple HTML markup, something like this: + +
<div id="timeSeries1" class="timeseries-output"></div>
+ +We'll use the `timeseries-output` CSS class as an indicator that the element is one that we should bind to. When new output values for `timeSeries1` come down from the server, we'll fill up the div with our visualization using JavaScript. ### Write an Output Binding @@ -39,7 +65,7 @@ An output binding object needs to have the following methods: getId(el)
- Return the Shiny output ID for the element el, or null if the element doesn't have an ID and should therefore be ignored. The default implementation in Shiny.InputBinding reads the data-output-id attribute and falls back to the element's id if not present. + Return the Shiny output ID for the element el, or null if the element doesn't have an ID and should therefore be ignored. The default implementation in Shiny.OutputBinding reads the data-output-id attribute and falls back to the element's id if not present.
renderValue(el, data) @@ -59,11 +85,6 @@ An output binding object needs to have the following methods:
If the element el is currently displaying an error, clear it.
-
- showProgress(el, show) -
-
-
### Register Output Binding @@ -71,14 +92,4 @@ An output binding object needs to have the following methods: Once you've created an output binding object, you need to tell Shiny to use it:
Shiny.outputBindings.register(exampleOutputBinding, "yourname.exampleOutputBinding");
-The second argument is a name the user can use to change the priority of the binding. On the off chance that the user has multiple bindings that all want to claim the same HTML element as their own, this call can be used to control the priority of the bindings: - -
Shiny.outputBindings.setPriority("yourname.exampleOutputBinding", 10);
- -Higher numbers indicate a higher priority; the default priority is 0. All of Shiny's built-in input component bindings default to a priority of 0. - -If two bindings have the same priority value, then the more recently registered binding has the higher priority. - -### Example - - +The second argument is a string that uniquely identifies your output binding. At the moment it is unused but future features may depend on it.