Skip to content

Commit ff50422

Browse files
committed
add jsxgraph element
1 parent bb24a6f commit ff50422

12 files changed

Lines changed: 751 additions & 35 deletions

File tree

.changeset/chilly-rules-unite.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@hyperbook/markdown": minor
3+
"hyperbook": minor
4+
"hyperbook-studio": minor
5+
---
6+
7+
Add jsxgraph element

packages/markdown/assets/directive-jsxgraph/client.js

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.directive-jsxgraph {
2+
background: white;
3+
margin-bottom: 16px;
4+
border-radius: 8px;
5+
justify-content: center;
6+
margin: 12px auto;
7+
}

packages/markdown/dev.md

Lines changed: 189 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,198 @@ permaid: webide
55

66
## H5P
77

8-
:::geogebra{showAlgebra}
8+
:::jsxgraph{height="500" width="600" boundingbox="[-10,10,14,-10]" axis=false grid=false}
99

10-
a = Point({1, 2})
10+
```js
11+
var a = board.create("slider", [
12+
[1, 8],
13+
[5, 8],
14+
[0, 1, 4],
15+
]);
16+
var b = board.create("slider", [
17+
[1, 9],
18+
[5, 9],
19+
[0, 0.25, 4],
20+
]);
21+
var c = board.create(
22+
"curve",
23+
[
24+
function (phi) {
25+
return a.Value() + b.Value() * phi;
26+
},
27+
[0, 0],
28+
0,
29+
8 * Math.PI,
30+
],
31+
{ curveType: "polar", strokewidth: 4 }
32+
);
33+
```
1134

1235
:::
1336

14-
Das ist ein Test
37+
:::jsxgraph{}
38+
39+
```js
40+
var p1 = board.create("point", [0, 0], { name: "X", size: 4 });
41+
var p2 = board.create("point", [2, -1], { name: "B", size: 4 });
42+
var p3 = board.create("point", [-2, -3], { name: "C", size: 4 });
43+
var p4 = board.create("point", [-1, -1], { name: "D", size: 4 });
44+
var p5 = board.create("point", [3, 1], { name: "E", size: 4 });
45+
46+
var poly = board.create("polygon", ["X", "B", "C", "D", "E"], {
47+
borders: { strokeColor: "black" },
48+
});
49+
```
50+
51+
:::
52+
53+
:::jsxgraph{boundingbox="[-1.5,28.5,28.5,-1.5]"}
54+
55+
```js
56+
// Define sliders to dynamically change parameters of the equations and create text elements to describe them
57+
s = board.create(
58+
"slider",
59+
[
60+
[20.0, 26.0],
61+
[25.0, 26.0],
62+
[0.0, 0.3, 1.0],
63+
],
64+
{ name: "ε1", strokeColor: "black", fillColor: "black" }
65+
);
66+
st = board.create("text", [20, 25, "Birth rate predators"], { fixed: true });
67+
u = board.create(
68+
"slider",
69+
[
70+
[20.0, 24.0],
71+
[25.0, 24.0],
72+
[0.0, 0.7, 1.0],
73+
],
74+
{ name: "ε2", strokeColor: "black", fillColor: "black" }
75+
);
76+
ut = board.create("text", [20, 23, "Death rate predators"], { fixed: true });
77+
78+
o = board.create(
79+
"slider",
80+
[
81+
[10.0, 26.0],
82+
[15.0, 26.0],
83+
[0.0, 0.1, 1.0],
84+
],
85+
{ name: "γ1", strokeColor: "black", fillColor: "black" }
86+
);
87+
ot = board.create("text", [10, 25, "Death rate preys/per predator"], {
88+
fixed: true,
89+
});
90+
p = board.create(
91+
"slider",
92+
[
93+
[10.0, 24.0],
94+
[15.0, 24.0],
95+
[0.0, 0.3, 1.0],
96+
],
97+
{ name: "γ2", strokeColor: "black", fillColor: "black" }
98+
);
99+
pt = board.create("text", [10, 23, "Reproduction rate pred./per prey"], {
100+
fixed: true,
101+
});
102+
103+
// Dynamic initial value as gliders on the y-axis
104+
startpred = board.create("glider", [0, 10, board.defaultAxes.y], {
105+
name: "Preys",
106+
strokeColor: "red",
107+
fillColor: "red",
108+
});
109+
startprey = board.create("glider", [0, 5, board.defaultAxes.y], {
110+
name: "Predators",
111+
strokeColor: "blue",
112+
fillColor: "blue",
113+
});
114+
115+
// Variables for the JXG.Curves
116+
var g3 = null;
117+
var g4 = null;
118+
119+
// Initialise ODE and solve it with JXG.Math.Numerics.rungeKutta()
120+
function ode() {
121+
// evaluation interval
122+
var I = [0, 25];
123+
// Number of steps. 1000 should be enough
124+
var N = 1000;
125+
126+
// Right hand side of the ODE dx/dt = f(t, x)
127+
var f = function (t, x) {
128+
var bpred = s.Value(); //0.3;
129+
var bprey = u.Value(); //0.7;
130+
var dpred = o.Value(); //0.1;
131+
var dprey = p.Value(); //0.3;
132+
133+
var y = [];
134+
y[0] = x[0] * (bpred - dpred * x[1]);
135+
y[1] = -x[1] * (bprey - dprey * x[0]);
136+
137+
return y;
138+
};
139+
140+
// Initial value
141+
var x0 = [startpred.Y(), startprey.Y()];
142+
143+
// Solve ode
144+
var data = JXG.Math.Numerics.rungeKutta("euler", x0, I, N, f);
145+
146+
// to plot the data against time we need the times where the equations were solved
147+
var t = [];
148+
var q = I[0];
149+
var h = (I[1] - I[0]) / N;
150+
for (var i = 0; i < data.length; i++) {
151+
data[i].push(q);
152+
q += h;
153+
}
154+
155+
return data;
156+
}
157+
158+
// get data points
159+
var data = ode();
160+
161+
// copy data to arrays so we can plot it using JXG.Curve
162+
var t = [];
163+
var dataprey = [];
164+
var datapred = [];
165+
for (var i = 0; i < data.length; i++) {
166+
t[i] = data[i][2];
167+
datapred[i] = data[i][0];
168+
dataprey[i] = data[i][1];
169+
}
170+
171+
// Plot Predator
172+
g3 = board.create("curve", [t, datapred], {
173+
strokeColor: "red",
174+
strokeWidth: "2px",
175+
});
176+
g3.updateDataArray = function () {
177+
var data = ode();
178+
this.dataX = [];
179+
this.dataY = [];
180+
for (var i = 0; i < data.length; i++) {
181+
this.dataX[i] = t[i];
182+
this.dataY[i] = data[i][0];
183+
}
184+
};
185+
186+
// Plot Prey
187+
g4 = board.create("curve", [t, dataprey], {
188+
strokeColor: "blue",
189+
strokeWidth: "2px",
190+
});
191+
g4.updateDataArray = function () {
192+
var data = ode();
193+
this.dataX = [];
194+
this.dataY = [];
195+
for (var i = 0; i < data.length; i++) {
196+
this.dataX[i] = t[i];
197+
this.dataY[i] = data[i][1];
198+
}
199+
};
200+
```
15201

16-
:::geogebra{perspective="G" height=400 width=700 coordsystem="-10,10,-2,8"}
17-
18-
a = Slider[-5,5]
19-
SetCoords(a, 450, 370)
20-
f_a(x) = x^2 * a + a * x
21-
22202
:::

packages/markdown/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"dexie": "^4.0.11",
8787
"dexie-export-import": "^4.1.4",
8888
"h5p-standalone": "^3.8.0",
89+
"jsxgraph": "^1.11.1",
8990
"live-server": "^1.2.2",
9091
"lunr": "^2.3.9",
9192
"lunr-languages": "^1.14.0",

packages/markdown/postbuild.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,19 @@ async function postbuild() {
170170
src: path.join("./node_modules", "h5p-standalone", "dist"),
171171
dst: path.join("./dist", "assets", "directive-h5p"),
172172
},
173+
{
174+
src: path.join("./node_modules", "jsxgraph", "distrib", "jsxgraph.css"),
175+
dst: path.join("./dist", "assets", "directive-jsxgraph", "jsxgraph.css"),
176+
},
177+
{
178+
src: path.join(
179+
"./node_modules",
180+
"jsxgraph",
181+
"distrib",
182+
"jsxgraphcore.js",
183+
),
184+
dst: path.join("./dist", "assets", "directive-jsxgraph", "jsxgraphcore.js"),
185+
},
173186
];
174187

175188
for (let asset of assets) {

packages/markdown/src/process.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import remarkDirectivePyide from "./remarkDirectivePyide";
5454
import { i18n } from "./i18n";
5555
import remarkDirectiveWebide from "./remarkDirectiveWebide";
5656
import remarkDirectiveH5P from "./remarkDirectiveH5P";
57+
import remarkDirectiveJSXGraph from "./remarkDirectiveJSXGraph";
5758

5859
export const remark = (ctx: HyperbookContext) => {
5960
i18n.init(ctx.config.language || "en");
@@ -93,6 +94,7 @@ export const remark = (ctx: HyperbookContext) => {
9394
remarkDirectiveGeogebra(ctx),
9495
remarkDirectiveWebide(ctx),
9596
remarkDirectiveH5P(ctx),
97+
remarkDirectiveJSXGraph(ctx),
9698
remarkCode(ctx),
9799
remarkMath,
98100
/* needs to be last directive */
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Register directive nodes in mdast:
2+
/// <reference types="mdast-util-directive" />
3+
//
4+
import { HyperbookContext } from "@hyperbook/types";
5+
import { Root } from "mdast";
6+
import { visit } from "unist-util-visit";
7+
import { VFile } from "vfile";
8+
import { isDirective, registerDirective, requestJS } from "./remarkHelper";
9+
import { toText } from "./mdastUtilToText";
10+
import hash from "./objectHash";
11+
12+
export default (ctx: HyperbookContext) => () => {
13+
const name = "jsxgraph";
14+
return (tree: Root, file: VFile) => {
15+
visit(tree, function (node) {
16+
if (isDirective(node)) {
17+
if (node.name !== name) return;
18+
19+
const data = node.data || (node.data = {});
20+
const {
21+
id = hash(node),
22+
height = 600,
23+
width = 800,
24+
boundingbox = [-5, 5, 5, -5],
25+
keepaspetcratio = false,
26+
showNavigation = false,
27+
zoom = true,
28+
pan = true,
29+
keyboard = true,
30+
axis = true,
31+
grid = true,
32+
} = node.attributes || {};
33+
34+
registerDirective(
35+
file,
36+
name,
37+
["client.js"],
38+
["jsxgraph.css", "style.css"]
39+
);
40+
41+
requestJS(file, ["directive-jsxgraph", "jsxgraphcore.js"]);
42+
43+
data.hName = "div";
44+
45+
data.hProperties = {
46+
class: "directive-jsxgraph",
47+
style: `max-height: ${height}px; max-width: ${width}px; aspect-ratio: ${width}/${height};`,
48+
id: `jsxgraph-${id}`,
49+
};
50+
51+
const value = toText(node);
52+
data.hChildren = [
53+
{
54+
type: "element",
55+
tagName: "script",
56+
properties: {},
57+
children: [
58+
{
59+
type: "raw",
60+
value: `
61+
{
62+
const board = JXG.JSXGraph.initBoard('jsxgraph-${id}', {
63+
boundingbox: ${typeof boundingbox !== "string" ? JSON.stringify(boundingbox) : boundingbox},
64+
keepaspectcratio: ${keepaspetcratio},
65+
axis: ${axis},
66+
showCopyright: false,
67+
showNavigation: ${showNavigation},
68+
zoom: ${zoom},
69+
pan: ${pan},
70+
keyboard: ${keyboard},
71+
grid: ${grid},
72+
});
73+
74+
${value}
75+
}
76+
`,
77+
},
78+
],
79+
},
80+
];
81+
}
82+
});
83+
};
84+
};

0 commit comments

Comments
 (0)