JSXGraph Wiki Examples
A growing collection of interactive examples ported from the JSXGraph upstream wiki. Each example highlights the slider-driven interactivity that makes JSXGraph distinctive: drag the on-board sliders to update parameters in real time.
This page tracks the wishlist from issue #6.
1. Draggable exponential function
A draggable anchor point A whose coordinates (A.X(), A.Y()) parameterize an exponential f(x) = A.Y()^(x / A.X()). The clever bit: at x = A.X() the formula collapses to A.Y()^1 = A.Y(), so A always lies on the curve by construction — drag it anywhere and the curve follows.
using JSXGraph
board("wiki_exp", xlim=(-3, 3), ylim=(-1, 10)) do brd
A = point(1.0, exp(1); name="A", color="red", size=4)
push!(brd, A)
push!(brd, functiongraph(@jsf x -> A.Y()^(x / A.X()); strokeColor="blue", strokeWidth=2))
end
2. Lituus
The Lituus is the polar spiral r(φ) = √(k/φ) with k controlled by a slider. As k grows the spiral widens; as k → 0 it collapses onto the origin.
The standalone polar constructor creates its own board, which keeps us from putting a slider alongside it. Instead we build the polar curve manually as a parametric one — x(t) = r(t)·cos(t), y(t) = r(t)·sin(t) — so the slider captured inside @jsf flows through both component functions at render time.
board("wiki_lituus", xlim=(-3, 5), ylim=(-3, 9)) do brd
k = slider([1, 8], [5, 8], [0, 1, 4]; name="k")
push!(brd, k)
push!(brd, curve(
@jsf(t -> sqrt(k / t) * cos(t)),
@jsf(t -> sqrt(k / t) * sin(t)),
0.0001, 8π;
strokeColor="purple", strokeWidth=1,
))
end
3. P-Norm unit ball
The unit "circle" in the p-norm is the implicit curve |x|^p + |y|^p = 1. A slider varies p continuously between 0.5 and 5.0, morphing the shape from a four-pointed star (p < 1) through a Euclidean circle (p = 2) to a square (p → ∞).
board("wiki_pnorm", xlim=(-1.5, 1.5), ylim=(-1.5, 1.5)) do brd
p = slider([-1.3, 1.3], [1.3, 1.3], [0.5, 2.0, 5.0]; name="p")
push!(brd, p)
push!(brd, implicitcurve(@jsf (x, y) -> abs(x)^p + abs(y)^p - 1;
strokeColor="darkred", strokeWidth=2))
end
4. Slider-driven polynomial
A quartic a·x⁴ + b·x³ + c·x² + d·x with one slider per coefficient. Drag the sliders to reshape the curve in real time.
board("wiki_poly", xlim=(-4, 4), ylim=(-10, 10)) do brd
a = slider([-3, 8], [3, 8], [-2, 0.5, 2]; name="a")
b = slider([-3, 7], [3, 7], [-3, 0, 3]; name="b")
c = slider([-3, 6], [3, 6], [-3, 0, 3]; name="c")
d = slider([-3, 5], [3, 5], [-3, 0, 3]; name="d")
push!(brd, a, b, c, d)
push!(brd, functiongraph(@jsf x -> a * x^4 + b * x^3 + c * x^2 + d * x;
strokeColor="darkred", strokeWidth=2))
end
5. Power series for sine
A slider N controls the truncation order of the Taylor series for sin(t). Drag N from 0 upward and watch the polynomial approximation extend its agreement with sin(t) further from the origin.
@jsf does not transpile Julia for / while loops to JavaScript (they live in UNSUPPORTED_EXPR_HEADS), so the truncated-series body is written as a raw JSXGraph.JSFunction. The placeholder marker __JSF_REF_s__ is substituted at render time to the slider's JS variable (with .Value() auto-appended for sliders), the same mechanism the @jsf macro uses internally for captured element references.
board("wiki_taylor", xlim=(-10, 10), ylim=(-3, 3)) do brd
# Reference sin(t) in light gray
push!(brd, functiongraph(@jsf t -> sin(t); strokeColor="#cccccc", strokeWidth=2))
# Slider for truncation order N ∈ [0, 10]
s = slider([-9, -2.5], [9, -2.5], [0, 1, 10]; name="N", snapWidth=1)
push!(brd, s)
# Truncated Taylor sum: sum_{k=0}^{N} (-1)^k · t^(2k+1) / (2k+1)!
# Written as raw JS because @jsf cannot transpile for-loops.
code = """function(t){
var v = 0, k, sv = __JSF_REF_s__ + 1, a;
for (k = 0; k < sv; k++) {
a = 1;
for (var j = 1; j <= 2*k + 1; j++) a *= j;
v += Math.pow(-1, k) * Math.pow(t, 2*k + 1) / a;
}
return v;
}"""
fn = JSXGraph.JSFunction(code, "", JSXGraph.JSFunction[], Dict{String,Any}("__JSF_REF_s__" => s))
push!(brd, functiongraph(fn; strokeColor="blue", strokeWidth=2))
end
6. Riemann sums (n, start, end sliders)
Three sliders drive the left-endpoint Riemann sum approximating ∫ₐᵇ sin(x) dx:
n— number of subintervalsstart— lower boundaend— upper boundb
The shaded curve segment between a and b (drawn with functiongraph) updates together with the rectangles as the bounds slide.
JSXGraph's functiongraph and riemannsum expect their range parents (xmin, xmax, n) to be either a literal number or a function returning a number, not a slider element reference. We wrap each slider in a tiny no-arg lambda — @jsf () -> a_slider — which transpiles to function(){return el_xxx.Value();} thanks to the slider-auto-deref in JSXGraph.jl. This matches the JSXGraph wiki idiom verbatim.
The functiongraph's 3-parent form (f, xmin, xmax) isn't exposed in the public API yet, so the example reaches for the internal JSXGraph._create_element("functiongraph", (f, xmin, xmax), …).
board("wiki_riemann", xlim=(-8, 8), ylim=(-4, 4)) do brd
n = slider([1, 3], [5, 3], [1, 10, 50]; name="n", snapWidth=1)
a = slider([1, 2], [5, 2], [-10, -3, 0]; name="start")
b = slider([1, 1], [5, 1], [0, π, 10]; name="end")
push!(brd, n, a, b)
f = @jsf x -> sin(x)
get_a = @jsf () -> a
get_b = @jsf () -> b
get_n = @jsf () -> n
# functiongraph plotted only between the slider-driven bounds
push!(brd, JSXGraph._create_element("functiongraph", (f, get_a, get_b),
Dict(:strokeColor => "blue",
:strokeWidth => 2)))
# left-endpoint Riemann sum with bounds and subdivision count driven
# by the same sliders
push!(brd, riemannsum(f, get_n, "left";
a=get_a, b=get_b,
fillColor="yellow", fillOpacity=0.4))
end
7. Linear inequalities (half-planes)
The wiki page demonstrates the inequality element on linear boundaries, specifying each line in its homogeneous-coordinate form c + b·x + a·y = 0. The shaded side is the … ≤ 0 half-plane by default; inverse=true flips it to … ≥ 0.
The 3-coefficient line(c, b, a) constructor (added in v0.5.3) accepts this form directly.
board("wiki_ineq", xlim=(-5, 5), ylim=(-5, 5)) do brd
# Line `2x - y + 3 = 0` (i.e. y = 2x + 3); shade `2x - y + 3 ≤ 0`
l1 = line(3, 2, -1)
push!(brd, l1)
push!(brd, inequality(l1; fillColor="yellow"))
# Line `x - 3 = 0` (i.e. x = 3); shade `x ≥ 3` via `inverse=true`
l2 = line(-3, 1, 0; strokeColor="black")
push!(brd, l2)
push!(brd, inequality(l2; fillColor="red", inverse=true))
end