This document describes the original ways to embed
We mainly assume that the HTML document is produced from R markdown source using
rmarkdown, though some methods don’t require this. This format mixes text with Markdown markup with chunks of R code.
There are two ways to embed an
rgl scene in the document. The older one is to use the chunk option
webgl = TRUE. With that option, whatever
rgl scene is active at the end of the chunk will be embedded. See the
setupKnitr help page.
The second way is to use a call to
rglwidget. Each call to this function will insert a scene into the document. Do not set
webgl = TRUE. That is the recommended method, and is described in User Interaction in WebGL.
The second method is easier for me to maintain, and will receive more support in the future, but for now both methods are supported, and there are examples of both in this document.
Most browsers now support WebGL, but it may be disabled by default. See http://get.webgl.org for help on a number of different browsers.
If you are using the internal browser in RStudio, support varies by version. I believe it is enabled by default in Windows versions, but until recently was not enabled in Mac OSX versions. You can run this command in Terminal:
defaults write org.rstudio.RStudio WebKitWebGLEnabled -bool YES
to enable it. I do not have much experience with RStudio in Linux, but it does seem that WebGL is enabled there.
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 and call the
rglwidget function with optional argument
<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
in the script below.
knitr substitutes the value 1 when it processes the document.
document.getElementById to retrieve the
<div> component of the web page containing the scene. It will have a component named
rglinstance which contains information about the scene that we can modify:
If we had used
webGL=TRUE in the chunk header, the
knitr WebGL support would create a global object with a name of the form
<chunkname>rgl. For example, if the code chunk was named
plot3d, the object would be called
plot3drgl, and this code would work:
We can also change the contents of the plot using
toggleButton (or the more recent
toggleWidget). 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) axesid <- decorate3d() subid <- currentSubscene3d()
Note that we need to use
results="asis" for the button code.
Normally we would also use
echo=FALSE, though I didn’t do so above; then the buttons will end up side-by-side. We also add another button to toggle the axes:
par3dinterpSetter generates a function that approximates the result of
propertySlider or your own custom code.
play3dexample) rotates the scene in a complex way.
par3dinterp. Because of this, we need to output 15 steps from
par3dinterpSetter so that the distortions of linear interpolation are not visible.
clipplaneSlider. This function allows the user to control the location of a clipping plane by moving a slider. Both it and
par3dinterpSetter are implemented using the more general
Less general than
vertexSetter. This function sets attributes of individual vertices in a scene. For example, to set the x-coordinate of the closest point in the setosa group, and modify its colour from black to white,
A related function is
ageSetter, though it uses a very different specification of the attributes. It is used when the slider controls the “age” of the scene, and attributes of vertices change with their age.
Rather than giving an example, we will illustrate the very similar function
ageControl, embedded in a
playwidget. We will show a point moving along a curve. In the original scene we need to specify multiple colours so that the colour is not fixed, and can be controlled by the slider. We also give two
ageControl calls in a list;
playwidget("ageExample", list( ageControl(births = time, ages = c(0, 0, 50), colors = c("gray", "red", "gray"), objids = lineid), ageControl(births = 0, ages = time, vertices = xyz, objids = sphereid)), start = 0, stop = max(time) + 20, rate = 50, components = c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label"), loop = TRUE)
The final function of this type is
matrixSetter, for setting up multiple controls to modify a matrix, typically
userMatrix. This is used when complex manipulation of a matrix requires several controls.
TODO: give an example here.
NB: This section has not been updated recently, and is not current.
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.
As documented in
writeWebGL, the call
will create a global object on the output page with name
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.
Array objects, indexed by the
After any change that will affect the display, code should call
<prefix>rgl.drawScene() to redraw the scene.
These methods each take two arguments:
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.
This function takes a subscene id as argument, and returns an
Array containing all of the ids displayed in that subscene.
This takes an
Array of ids and a subscene id as arguments, and sets the contents of the subscene to the ids.
These correspond to the
par3d properties with the same names.
zoomare arrays of numbers.
userMatrixis an array of
CanvasMatrix4objects (documented in the file
system.file("htmlwidgets/lib/CanvasMatrix/CanvasMatrix.src.js", package = "rgl").
listenersitem is itself an array of subscene ids that “listen” to mouse actions, i.e.
listenerswould contain all subscene ids that respond to mouse actions in subscene 19.
This property also corresponds to the
par3d property, but should be considered to be read-only.
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.
Most of the data about each object in a scene is contained in the
values property. This is an array, indexed by object id. The individual entries are numeric arrays. Though they are singly-indexed, the entries are meant to be interpreted as matrices stored by row. The first 3 columns are generally the coordinates of a vertex, and remaining columns correspond to other values from
offsets property gives the (0-based) offset of the first column for a particular attribute in a named object. Not all columns will be present in every object; if not present, the corresponding
offsets entry will be
-1. The entries are
|vofs||Offset to 3 columns of vertex data in XYZ order|
|cofs||Offset to 4 columns of colour data in RGBA order|
|nofs||Offset to 3 columns of normal data|
|radofs||Offset to 1 column of sphere radius data|
|oofs||Offset to 2 columns of text or sprite origin data|
|tofs||Offset to 2 columns of texture coordinates|
|stride||Total number of columns in
For example, to find the blue colour entry for vertex
i in an object, one would first check if
-1, indicating that no colour information was present. If not, the entry could be found using
values[offsets["stride"]*(i-1) + offsets["cofs"] + 2]
i is specified using 1-based vertex counting as in R, and writes
offsets instead of the fully specified
<prefix>rgl.offsets for clarity.
values need to be pushed to the graphics system to be reflected in the scene; see the calls to
gl.bufferData in the source to
propertySlider for details.
The following functions and
rglClass properties and methods are described in this document: