Skip to main content

Section 14 Interactive Elements, Authored in Javascript

View Source

When outputting Web page versions, it is possible to embed a variety of dynamic interactive elements. In a /PDF version, these will necessarily need to be replaced by some static substitute, such as a screenshot. See Section 3 for the specifics of embedding instances of the Sage Cell Server, which is more elaborate, and not entirely similar.

Interactives in this section are those for which you provide code you have authored. Generally, the libraries involved to support this have open licenses, though the player for GeoGebra may be an exception. Creating these assumes some familiarity with HTML and Javascript. See Section 15 for more interactives that are perhaps simpler to create or use.

(2018-06-22) Almost everything in this section is under active development and not stable yet. Feel free to experiment and make suggestions and requests. This page takes a while to completely load, so be patient.

Subsection 14.1 HTML5 Canvas

HTML5 introduced the <canvas> element, which can be thought of a blank slate, a place to draw or write on. So PreTeXt has the <slate> element for a similar purpose. Generally, but not exclusively, HTML5 writes on a <canvas> using the Javascript language. We demonstrate this approach to interactive diagrams in this subsection.

The following examples are from David Austin's excellent Understanding Linear Algebra 1  textbook, which can be found at

David's contribution of examples, and assistance designing the PreTeXt elements is greatly appreciated. Alright, let's learn some linear algebra. Yes, there are some learning opportunities in this subsection.

Let \(\vec{x}\) be represented by the red arrow, and \(A\vec{x}\) by the grey arrow, for some particular \(2\times 2\) matrix \(A\text{.}\) Drag the tip of the red arrow to see the grey arrow change.

Figure 14.1. A simple eigenvector demonstration

The interactive in Figure 14.1 shows a vector \(\vec{x}\) in red, and the matrix-vector product \(A\vec{x}\) in grey, for a particular \(2\times 2\) matrix \(A\text{.}\) The four entries of the matrix \(A\) are coded into the interactive. Can you deduce \(A\) simply by using the interactive? Which theorem is the key?

Let \(\vec{x}\) be represented by the red arrow, and \(A\vec{x}\) by the grey arrow, for a \(2\times 2\) matrix \(A\text{.}\) Drag the tip of the red arrow to see the grey arrow change. Or drag the blue sliders to change the numerical values of the four entries of the \(2\times 2\) matrix \(A\text{.}\) You will not see the grey vector until you change the matrix using one of the two sliders on the left. Why is that? What are the eigenvectors of the initial matrix?

Figure 14.3. Eigenvector demonstration

The next example has ten <slate> elements communicating with each other, and arranged with the layout features of a <sidebyside> (see Section 25).

Parameters \(a\text{,}\) \(b\text{,}\) \(d\text{,}\) and \(e\text{,}\) form a \(2\times 2\) matrix \(A\text{,}\) while \(c\) and \(f\) form a vector \(\vec{b}\text{.}\) The two views of Woody shows the effect of the mapping

\begin{equation*} \vec{x}\mapsto A\vec{x} + \vec{b}\text{.} \end{equation*}
Figure 14.4. Affine Transformations

Warning 14.5.

If your <interactive> employs a <slate> with a @surface attribute whose value is html, then you are advised to augment each top-level (HTML) element within the <slate> with the attribute:


This will identify all of the elements within the <slate> as HTML elements and not as PreTeXt elements. The danger is that elements with the same name in both languages, such as <li> and <table>, will be mis-identified. This could be harmless, but could also create chaos, such as disrupting numbering of PreTeXt elements.

See the source code of this document for examples: Figure 14.4 Figure 14.11, Figure 14.15.

Note that the HTML that is output can vary slightly from your source in small, harmless ways, such as empty (self-closing) elements being output with both an opening and a closing tag. Please report any significant discrepancies. Soon this requirement will be enforced in the code.

The following example was contributed by Rick Roesler. The <figure> is comprised of four <stack> elements within a <sidebyside>. By varying the time in the top box, the reader can observe the displacement, velocity, and acceleration of a ball thrown upward with an initial velocity of 30 m/s.

Use the time slider in the top panel to vary the time from 0 sec to 6 sec. Observe how the displacement, velocity, and acceleration vary with time.

Figure 14.6. 1-Dimensional Kinematics

Subsection 14.2 D3.js

D3 is a Javascript library for “Data-Driven Documents”, which might greatly enhance some data you wish to display. In short, it uses the animation capabilities of SVG. Available examples seem sensitive to the version of the library, so we have examples using different versions. Use the @version attribute on <interactive> to specify the version number. The default is 5.

The first example uses the force layout and collision detection from Version 3. (The necessary commands are very different in Version 4.) Pretend you are a working shepherding dog. Can you separate, and catch, one of the herd?

This is adapted from a block 2  by Mike Bostock 3  with a GPL license. A similar demonstration, only using an HTML5 canvas is at

Place your mouse/pointer at the center of the interactive to repel the 200 circles.

Figure 14.7. Force layout and collision detection

Similar, but different, this demonstration of a graph layout uses Version 4 of the library. Technical notes:

  • We have changed the size of the nodes, and their number, to fit in a smaller space.

  • The Javascript script uses introspection to size itself, which would be a good general practice.

This is adapted from a block 4  by shimizu 5  with a GPL license.

Drag a vertex to a new location to see the graph adjust its layout.

Figure 14.8. Graph Layout

Can you move the vertices to new locations such that the resulting graph is planar? (In other words, no edges cross?)

Finally an example that actually uses some data. Here is the description from the original block 6  by Martin Chorley 7  with an MIT License.

This visualisation uses a D3 force simulation to show the Twitter relationships between the Assembly Members in the Welsh Assembly in terms of the number of times each assembly member has mentioned another assembly member in a tweet.

Twitter relationships were mined on 22/03/2017, and are representative of the conversational relationships on that date. Links between AMs represent a conversational relationship: one AM has mentioned the other. Party colour indicates the direction of the mention.

Hover over the nodes to fade out non-connected nodes.

Rather than using intermediate nodes to create curved links (as in Mike Bostock's block), this adds curves by adding a calculated control point for each edge.

Technical notes:

  • Once the nodes organize themselves (automatically in the beginning), they cannot be moved.

  • We have adjusted the margins in an attempt to keep names visible on the right side, but without giving up too much space.

  • We have adjust the repelling force, and the collision buffer, to better fit the available space.

  • This example required its own CSS, which we have included as part of the <interactive>.

  • The data collected from the Twitter analysis is contained in a JSON file, mention_network.json, and where the script loads that file, it has a hardcoded path. So this example is a bit brittle, should that file move.

Hover on the name of an Assembly Member to concentrate on their tweet mentions.

Figure 14.10. Tweet mentions within the Welsh Assembly

Subsection 14.3 SVG

Entirely similar to using an HTML5 canvas element (14.1), it is possible to control an SVG element with Javascript. This example is from Mark McClure.

Look carefully at the source and rendering of this example as HTML. The functions to choose from via radio buttons, and the change in \(x\text{,}\) denoted later as \(h\text{,}\) are being rendered as mathematics by the Javascript MathJax library. However, this cannot be accomplished with simply $...$ nor by simply \(...\), but instead by using the \(...\) and then also wrapping that in a <span> element with a @class attribute set to process-math. (The latter is how we instruct MathJax as to which parts of a page to process, or not). So to have MathJax render a nice \(x^2\) in this context (math inside HTML inside a <slate> inside an <interactive>) would be accomplished with

<span class="process-math">x^2</span>

Select a function with the radio buttons, then use the checkbox to add the secant line. The denominator of the difference quotient, \(h\text{,}\) can be adjusted with the slider and the red point will react to the different values. The green point is the point of tangency, and can be dragged with the mouse.

Figure 14.11. Tangent and secant slopes

When discussing the derivative as a limit, we think of the point of tangency as being fixed (the green point in 14.11) and the “other” point defining the secant line as changing (the red point in 14.11). Switch it up! Fix a large value of \(h\) (positive or negative) and then change the point of tangency (the green point). Discuss what you observe.

Subsection 14.4 JSXGraph

JSXGraph 8  is a “cross-browser JavaScript library for interactive geometry, function plotting, charting, and data visualization in the web browser.” Now a <slate> will be what JSXGraph calls a board. Again, you use Javascript to write onto a <slate>, but have some powerful shortcuts available from the JSXGraph library. For this reason, PreTeXt calls JSXGraph a “language”, similar in may respects to how Sage is a language, but is really a Python library. So realize that the syntax for using JSXGraph is that of Javascript.

Place Javascript inside a file that is specified with the @source attribute of the <interactive> element. Then just be certain that @xml:id of the <interactive> element is passed as the HTML id in an (early) call to JSXGraph's initBoard() method.

The plot below is the curve \(r=a+b\theta\) in polar coordinates, for \(0\leq\theta\leq 8\pi\text{.}\) It may be manipulated with the sliders to control the shape of the curve. Point \(A\) is contrained to the curve, but may be dragged to a new location. At \(A\) the tangent line and normal line are plotted as dashed red lines. Use the controls in the lower left to adjust the viewing window. This Archimedean Spiral 9  is taken from the JSXGraph example wiki 10 . The code could be written in 7 lines. Width is 80% and aspect ratio is 4:3.

Drag the sliders to change the parameters \(a\) and \(b\text{.}\) Controls in the lower-right will adjust the viewing window.

Figure 14.13. The Archimedian Spiral \(r = a + b\theta\text{,}\) \(0\leq\theta\leq 8\pi\)

Here is a more elaborate example, from the JSXGraph Showcase 11 , titled Infinity 12 .

There are two active sliders to control the shape and shading of the graphic, and hovering the mouse near one of the edges will highlight the entirety of one of the 30 quadrangles. Finally, each of the four red corners may be dragged to a new location. Code is 47 lines. Width is 60% and aspect ratio is the default, 1:1, i.e. a square.

Drag the sliders to change the pattern, and drag any of the four red corners to change the overall shape.

Figure 14.14. Infinity, from the JSXGraph Showcase

Here are the two new examples. They have been included in a sidebyside layout element with equal widths (see Section 25) so they can be placed horizontally across the page. They are not wrapped as figures, so cannot be cross-referenced. These are again from the JSXGraph example wiki 13 , the left being Fermat's Spiral and the right being a demonstration of B-splines.

Drag the slider to change the curve.

Any of the 8 red control points may be moved anywhere.

Finally, a piecewise function you can control, with traces of the domain values and range values in two other JSXGraph boards. Boards and HTML buttons have been laid out using the sidebyside layout element.

The slider of the left panel will trace out the piecewise function. Simultaneously, the domain will be traced in the middle panel, and the range in the right panel.

Figure 14.15. Piecewise Function

Generally, we load an interactive into an HTML iframe to sandbox (isolate) it from other interactives. We does this for your own protection. So, for example, one interactive cannot talk to another. If two <slate> need to communicate, then they are related, and should be placed into a single <interactive>, allowed to layout themselves, or grouped within a <sidebyside> allowing finer control. Even if we have this under control, you might still enjoy reading Your JS is a Mess 14  at

Subsection 14.5 JessieCode

JessieCode 15  is a scripting language for JSXGraph. It provides the core geometric and graphing features of JSXGraph without accessing the underlying JavaScript. In order to use JessieCode, you simply create the HTML <div> element as you would for any other JSXGraph interactive plot and then provide the JessieCode script, which focuses on the geometric elements.

Because JessieCode is provided by JSXGraph, the interactive platform is jsxgraph. The <slate>, however, uses @surface with value jessiecode. The script can be embedded directly in your code. As usual, you would need to remember to escape the special characters. JessieCode uses < and > for inequalities as well as for declaring objects used to style geometric elements, and && is the boolean AND operator. Alternatively, you can provide the file as a separate resource, providing the URL with a @source attribute. Attributes defining the JSXBoard at the time it is created should be included as attributes of the <slate>, including @boundingbox, @axis, and @grid.

For this first example, the JessieCode was included directly in the XML source as the contents of the associated slate.

Use the sliders to set the parameters of the quadratic \(f(x)=ax^2+bx+c\text{.}\) Drag the point \(A\) on the graph and the point \(P\) to define a line. Try to make the line tangent at the point at \(A\) and observe the resulting slope of the tangent line.

Figure 14.16. Finding the Tangent Line of a Quadratic Function

For this second example, the JessieCode was included through an associated script file, loaded by the browser.

Drag the point \(B\) to move the point on the graph and change the secant line. Notice that there is no well-defined limiting tangent line as \(x \to 0\text{.}\)

Figure 14.17. Graph of a function that is continuous but not differentiable at \(x=0\) because the slope of the secant line has no limit.

Subsection 14.6 Sage Interacts

Sage, and the Sage Cell Server, support interactive demonstrations, called interacts.

  • The interactive elements are nearly trivial to construct.

  • An interact is simply a single Python function (acted on by a decorator).

  • You have the full mathematical power of Sage at your disposal, so can do some very powerful computations with high precision (or exactly).

  • The interface is not as polished as what you can achieve with Javascript libraries.

  • Graphics refresh with a round-trip to the server, so are not nearly as fluid as with other tools.

Note that each interact is insulated from the others, unlike our other employment of the Sage Cell Server.

This example is by Marshall Hampton, taken from the Sage interact wiki 16 , specifically Numerical integrals with the midpoint rule 17 .

Figure 14.18. Numerical integrals using the midpoint rule

Subsection 14.7 Geogebra

To embed a GeoGebra applet as-is from GeoGebra's Classroom Resources site (by material ID), see Subsection 15.1. To design your own applet (either from scratch, or modifying something that already exists in one of those three forms) you may use one of Geogebra's “Apps” to embed the material in your document. (But note, use of the App comes with licensing restrictions.) PreTeXt will handle most of the technical details for you.

Do one of the following:

  1. Identify a material ID from GeoGebra's Classroom Resources site. You might even make the material yourself on that site.

  2. Obtain a .ggb file from GeoGebra. You might construct something on a desktop installation of GeoGebra and save it. If you have a base64-encoded string for a GeoGebra applet, but you don't have a .ggb file, you can decode the string and save the result. For example, at

  3. Obtain a base64 encoded string for a GeoGebra applet. You might first open a .ggb file in a desktop installation of GeoGebra, and push ctrl-shift-B (command-shift-B on a Mac) and then the string will be in your clipboard.

  4. None of the above, with the intention to make an applet from scratch.

Then mimic the examples that follow, using GeoGebra API commands documented at Geogebra API Manual 18 , but do not include the ggbApplet. or applet. used in examples to prefix the functions—that part of the code will be provided automatically by PreTeXt.

Jack Green created an applet on the Classroom Resources site with ID D4s2v4ft, which you may view at Suppose you would like to use this in your project, but change something about it. We will change something trivial, making the \(y\)-axis ticks be separated \(5\) apart instead of \(10\) apart. We also decide we want a different aspect ratio and overall width. One gotcha: the original applet is loaded and then PreTeXt uses @width and @aspect attributes to resize the viewing window using the top left corner as an anchor. This does not rescale axes and that may leave you with important elements missing from the viewing window. So here we reset the viewing window to return to values that are in the original. Lastly, we disable zooming, which is not helpful for this applet. To do each of these things, we rely on the GeoGebra API manual at Geogebra API Manual 19 . It is important to use one command per line.

Figure 14.19. GeoGebra: modified material ID

The same can be done with a .ggb file. Here we use two provided by David Rosoff, and one provided by Tevian Dray. The path to the file needs to be relative. First, David's original.

Figure 14.20. GeoGebra: .ggb file

Now we modify David's applet in a few ways.

Figure 14.21. GeoGebra: modified from .ggb file
Figure 14.22. GeoGebra: modified from .ggb file

In this one provided by Tevian Dray, we make no modifications (except for those imposed by the scaling). You will need to zoom out a bit, and then pan over some, to see all the pieces.

Drag some of the points and some of the circles to change them, and watch the remainder react.

Figure 14.23. GeoGebra: a constructive “proof” that SAS congruence holds in Euclidean geometry (from Tevian Dray)

You could also use a base64-encoded string of the .ggb file. You might come across such a string somewhere, or you might generate one by opening a .ggb file in a desktop installation of GeoGebra, and pushing ctrl-shift-B (command-shift-B on a Mac) to get the string in your clipboard. If you do this, you could use a @base64 attribute in place of the @source attribute in the previous example. We don't do that here because such a string is generally over 5000 characters long and we are keeping the sample article source a bit cleaner.

Lastly, you may just wish to build something from scratch using GeoGebra API. Note that for accessibilty reasons, some objects are rendered unselectable with the setFixed command. Perhaps this should have been done with the previous examples, but that is more difficult when you do not know all of their names.

Figure 14.24. GeoGebra: from scratch

Subsection 14.8 IFrames

An iframe is an HTML element that allows embedding of a complete web page within another one. Here we use this device to provide interactive 3D diagrams built with other tools.

We begin with a Jupyter notebook hosted on News of success on other hosts for Jupyter notebook servers will allow us to expand this description. We use a Sage kernel and create a 3D surface suggested by Juan Carlos Bustamante:

plot3d(x^2 - y^2, (x,-1,1), (y,-1,1), color="orange", mesh=true)

News of other computational engines that produce similar graphics will also allow us to further expand this description. Note that for the case of Sage 3D plots, support for the <sageplot> element makes this even easier. For example, see 9.19.

A button in the lower right allows for several options, one is Save as HTML, which will produce a complete self-contained web page we can recycle. We save this file with our other externally-created images, in a directory that we choose to name iframe—you can use another name. Then we make an <interactive> with an @iframe attribute that has the filename, starting from iframe/ (in other words, do not include the name of your managed directory of external images).

Figure 14.25. Sage+Jupyter iframe

Note that the downloaded file has links to specific versions of the three.js library, which are beyond our control, and beyond your control. So there is a future where these images may need updating. You could put your source code into a (large) comment with your project's source for safe-keeping in the future.

Subsection 14.9 threejs

An example using the threejs 3D Javascript library. This is one of the project's examples 20 , licensed with an MIT License, with minimal modifications. We get several of the necessary libraries from the site.

Figure 14.26. threejs webgl_geometry_extrude_splines example

The following two examples are meant to be instructive (only). The end result is accomplished in a much more straightforward way be the method in Subsection 14.8. We illustrate a way to get a three.js image out of an HTML page as a Javascript file and render it on a PreTeXt <slate>. We follow the second method in a blog post from the \(n\)-Category Cafe 21 .

  1. Open a Jupyter Notebook that utilizes a Sage kernel. This can be done easily at CoCalc 22  (and for free initially).

  2. Sketch a surface using Sage code. We recycle the suggestion from Juan Carlos Bustamante in Subsection 14.8:

    plot3d(x^2 - y^2, (x,-1,1), (y,-1,1), color="orange", mesh=true)

  3. Look for a button (in the lower-right) which will provide a menu option Save as HTML. Save the resulting HTML file, and open a copy in a text editor.

  4. You are now looking for two HTML script elements. One will tell you just which version of three.js is being used, vis a @src attribute. For the second example below we located

    The @r122 will likely be a version number, which is a good thing for the longevity of your work. This will get used in the @source attribute of your <interactive>, which will have @platform set to javascript.

    The second script element is likely huge and has many generic functions defined it. There may be a huge variable full of data points computed by Sage. Copy the contents of this script element into a new Javascript file (so use a .js extension). Do not edit in any way until you read further. Once adjusted, this file too gets specified in the @source attribute of your <interactive>.

  5. Your <interactive> needs a <slate> element for the graphic to draw on, and you will need to give it a proper @xml:id attribute, plus teh @surface will be set to div. Then you need to edit the Javascript file to connect the graphic with the slate, via IDs in your PreTeXt source and on teh HTML div created by the slate. Look at the provided examples to see how. Do not make any other edits to this file, even if tempted.

  6. Study the two examples below, and mimic how they were constructed.

First, the example given in the blog post referenced above.

Figure 14.27. threejs catenoid surface, from \(n\)-Category Cafe

Second, the example from JC Bustamante.

Figure 14.28. threejs saddle by Sage