// Define the id of your board in BOARDID
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
This example is licensed under a Creative Commons Attribution 4.0 International License.
Please note that you have to mention The Center of Mobile Learning with Digital Technology in the credits.
/*
This example is licensed under a
Creative Commons Attribution 4.0 International License.
https://creativecommons.org/licenses/by/4.0/
Please note that you have to mention
The Center of Mobile Learning with Digital Technology
in the credits.
*/
const BOARDID = 'your_div_id'; // Insert your id here!
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
<div id="board-0-wrapper" class="jxgbox-wrapper " style="width: 100%; ">
<div id="board-0" class="jxgbox" style="aspect-ratio: 2 / 1; width: 100%;" data-ar="2 / 1"></div>
</div>
<script type = "text/javascript">
/*
This example is licensed under a
Creative Commons Attribution 4.0 International License.
https://creativecommons.org/licenses/by/4.0/
Please note that you have to mention
The Center of Mobile Learning with Digital Technology
in the credits.
*/
const BOARDID = 'board-0';
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
</script>
<jsxgraph width="100%" aspect-ratio="2 / 1" title="Cannon ball simulation" description="This construction was copied from JSXGraph examples database: https://jsxgraph.uni-bayreuth.de/share/" useGlobalJS="false">
/*
This example is licensed under a
Creative Commons Attribution 4.0 International License.
https://creativecommons.org/licenses/by/4.0/
Please note that you have to mention
The Center of Mobile Learning with Digital Technology
in the credits.
*/
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
</jsxgraph>
/*
This example is licensed under a
Creative Commons Attribution 4.0 International License.
https://creativecommons.org/licenses/by/4.0/
Please note that you have to mention
The Center of Mobile Learning with Digital Technology
in the credits.
*/
const BOARDID = 'your_div_id'; // Insert your id here!
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
<div id="board-0-wrapper" class="jxgbox-wrapper " style="width: 100%; ">
<div id="board-0" class="jxgbox" style="aspect-ratio: 2 / 1; width: 100%;" data-ar="2 / 1"></div>
</div>
<script type = "text/javascript">
/*
This example is licensed under a
Creative Commons Attribution 4.0 International License.
https://creativecommons.org/licenses/by/4.0/
Please note that you have to mention
The Center of Mobile Learning with Digital Technology
in the credits.
*/
const BOARDID = 'board-0';
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
</script>
<jsxgraph width="100%" aspect-ratio="2 / 1" title="Cannon ball simulation" description="This construction was copied from JSXGraph examples database: https://jsxgraph.uni-bayreuth.de/share/" useGlobalJS="false">
/*
This example is licensed under a
Creative Commons Attribution 4.0 International License.
https://creativecommons.org/licenses/by/4.0/
Please note that you have to mention
The Center of Mobile Learning with Digital Technology
in the credits.
*/
var board = JXG.JSXGraph.initBoard(BOARDID, {
boundingbox: [0, 10, 20, 0],
showCopyright: false,
showNavigation: false
}),
bottom = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/1/13/Cannon_bottom.png', [0, 0.3],
[2, 1]
], {
layer: 1, fixed: true
}),
muzzle = board.create('image', ['https://jsxgraph.uni-bayreuth.de/wiki/images/e/e4/Cannon_muzzle.png', [0, 1.05],
[3, 0.75]
], {
layer: 0, fixed: true
}),
shootButton,
resetButton,
rot, rp, cp, cc, cannonball, cbanim, solution, velocity,
animTime = function() {
return 3000;
},
fAngle = function() {
return Math.atan2(cp.Y() - rp.Y(), cp.X() - rp.X());
},
fSolution = function(x) {
var b = fAngle(),
g = 9.81 / 2;
return Math.tan(b) * (x - cannonball.X()) - g * (Math.pow((x - cannonball.X()) / (velocity.Value() * Math.cos(b)), 2)) + cannonball.Y();
},
fAnim = function(t) {
var i = Math.floor(solution.points.length * t / animTime()) /*3 + 17*t/animTime()*/ ,
s = NaN;
if (JXG.exists(solution.points[i]) && solution.points[i].usrCoords[2] > 0) {
s = solution.points[i].usrCoords.slice(1);
}
return s;
},
shoot = function() {
cannonball.setAttribute({
visible: false
});
cbanim.setAttribute({
visible: true
});
cbanim.moveTo([cannonball.X(), cannonball.Y()]);
cbanim.moveAlong(fAnim, animTime(), {
callback: function() {
// this is executed when the animation is finished
}
});
},
resetFunc = function() {
board.stopAllAnimation();
cbanim.setAttribute({
visible: false
});
cannonball.setAttribute({
visible: true
});
};
board.options.animationDelay = 50;
velocity = board.create('slider', [
[1, 9.5],
[6, 9.5],
[0, 5, 15]
], {
name: 'Velocity'
});
cp = board.create('point', [1.4, 1.4], {
fixed: true,
visible: false
});
cc = board.create('circle', [cp, 1.25], {
visible: false
});
rp = board.create('glider', [0, 1.4, cc], {
withLabel: false,
showInfobox: false,
color: 'black'
});
rot = board.create('transform', [fAngle, cp], {
type: 'rotate'
});
rot.bindTo(muzzle);
cannonball = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true
});
cbanim = board.create('point', [3, 1.4], {
size: 8,
strokeColor: 'black',
fillColor: 'gray',
withLabel: false,
fixed: true,
visible: false
});
rot.bindTo(cannonball);
solution = board.create('plot', [fSolution, function() {
return cannonball.X();
}, 20], {
visible: true,
doAdvancedPlot: false
});
board.create('text', [1, 7, () => 'angle = ' + (180 * fAngle() / Math.PI).toFixed(1) + '°'], {fontSize: 20});
shootButton = board.create('button', [10, 9.5, 'Shoot', shoot]);
resetButton = board.create('button', [12, 9.5, 'Reset', resetFunc]);
</jsxgraph>