source("setup.R") set.seed(123)
This document describes how to use embedded Javascript to control a WebGL display in an HTML document. For more general information, see rgl Overview.
We start with two simple examples. The next section gives reference information.
Consider the simple plot of the iris data. We
insert a code chunk with label plot3d
(which will be used below).
with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) subid <- currentSubscene3d()
We might like a button on the web page to cause a change to the display, e.g. a rotation of the plot. First we add buttons, with the "onclick" event set to a function described below:
<button type="button" onclick="rotate(10)">Forward</button> <button type="button" onclick="rotate(-10)">Backward</button>
which produces these buttons:
We stored the subscene number that is currently active in
subid
in the code chunk above, and use it as r rinline("subid")
in the script below.
The rotate()
function makes use of the global <prefix>rgl
object. The knitr
WebGL support sets the prefix to the
code chunk label, so the global is called plot3drgl
:
<script type="text/javascript"> var rotate = function(angle) { plot3drgl.userMatrix[`r rinline("subid", script=TRUE)`].rotate(angle, 0,1,0); plot3drgl.drawScene(); } </script>
We can also change the contents of the plot using a button. For example, we can redo the previous plot, but with the three species as separate "spheres" objects and buttons to toggle them:
sphereid <- with(subset(iris, Species == "setosa"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211)) with(subset(iris, Species == "versicolor"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211)) with(subset(iris, Species == "virginica"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211)) aspect3d(1,1,1) decorate3d() subid <- currentSubscene3d()
toggleButton(sphereid, label = "setosa", prefix = "toggle", subscene = subid) toggleButton(sphereid+1, label = "versicolor", prefix = "toggle", subscene = subid) toggleButton(sphereid+2, label = "virginica", prefix = "toggle", subscene = subid)
Note that we need to use results="asis"
for the button code. I didn't
use it above, but normally we would use echo=FALSE
; then the buttons
will end up side-by-side:
toggleButton(sphereid, "setosa", "toggle", subid) toggleButton(sphereid+1, "versicolor", "toggle", subid) toggleButton(sphereid+2, "virginica", "toggle", subid)
An alternate control to achieve the same thing is a slider. This can be a little tricker to implement, because the subset needs to include all objects, not just some of them:
subsetSlider(list(setosa = sphereid, versicolor = sphereid + 1, virginica = sphereid + 2, all = sphereid + 0:2), prefix = "slider", subscene = subid)
rgl
allows user defined mouse controls. For these to work
within WebGL, you will need to write a Javascript version as
well as the R version.
For example, the help page for r linkfn("rgl.setMouseCallbacks")
defines
a pan3d
function to set a callback for panning a scene:
open3d(useNULL=TRUE)
pan3d <- function(button) { start <- list() begin <- function(x, y) { start$userMatrix <<- par3d("userMatrix") start$viewport <<- par3d("viewport") start$scale <<- par3d("scale") start$projection <<- rgl.projection() start$pos <<- rgl.window2user( x/start$viewport[3], 1 - y/start$viewport[4], 0.5, projection = start$projection) } update <- function(x, y) { xlat <- (rgl.window2user( x/start$viewport[3], 1 - y/start$viewport[4], 0.5, projection = start$projection) - start$pos)*start$scale mouseMatrix <- translationMatrix(xlat[1], xlat[2], xlat[3]) par3d(userMatrix = start$userMatrix %*% t(mouseMatrix) ) } rgl.setMouseCallbacks(button, begin, update) cat("Callbacks set on button", button, "of rgl device", rgl.cur(), "\n") } pan3d(3)
TODO: DESCRIBE HOW TO WRITE THIS IN JAVASCRIPT
rglClass
In writing the writeWebGL()
function, I haven't tried to prevent access to
anything. On the other hand, I haven't provided access to
everything. The parts documented here should remain relatively stable
(unless indicated otherwise). Users may also consult the source
to writeWebGL
, but should be aware that anything that isn't documented
here is subject to change without notice.
r indexclass("rglClass")
As documented in r linkfn("writeWebGL")
, the call
writeWebGL(..., prefix = "<prefix>")
will create a global object on the output page with name
<prefix>rgl
and Javascript class rglClass
.
This class has a large number of properties and methods, some of which are designed
to be available for use by other code on the web page.
Most of the properties are stored as Javascript Array
objects, indexed
by the rgl
id of the subscene to which they apply. There
are also Javascript methods attached to the rglClass
class.
r indexmethods("drawScene")
After any change that will affect the display, code should
call <prefix>rgl.drawScene()
to redraw the scene.
r indexmethods(c("inSubscene", "addToSubscene", "delFromSubscene"))
These methods each take two arguments: id
and subscene
,
which should be the rgl
ids of an object and a subscene.
inSubscene
tests whether id
is already included in the
subscene, and the others
add it or delete it from the subscene.
r indexproperties(c("FOV", "listeners", "userMatrix", "zoom"))
These correspond to the
r linkfn("par3d")
properties with the same names.
FOV
and zoom
are arrays of numbers. userMatrix
is an array
of CanvasMatrix4
objects (documented in the file
system.file("WebGL/CanvasMatrix.src.js")
.listeners
item is itself an array of subscene ids that "listen"
to mouse actions, i.e. listeners[19]
would contain all
subscene ids that respond to mouse actions in subscene 19.r indexproperties("viewport")
This property also corresponds to the
r linkfn("par3d")
property, but should be considered to be
read-only.
r indexproperties(c("drawFns", "clipFns"))
These two arrays contain the code to display
each object in the scene. The functions in the
drawFns
array are called for each object
each time it is displayed. The clipFns
functions
are called when objects being clipped are drawn.
The following rglClass
properties and methods are described in this document:
writeIndex(cols = 5)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.