# GeoGebra extension for Numbas

An extension for Numbas which integrates [GeoGebra](https://www.geogebra.org) materials. 

To use this extension in a question, tick the "GeoGebra" option on the _Extensions and Scripts_ tab.

All the GeoGebra resources are loaded from [geogebra.org](https://geogebra.org), so this extension *WILL NOT* work offline, or in environments where that domain is blocked or otherwise inaccessible.

**Warning: At the moment, there's no way for this code to detect when the GeoGebra embedding fails, either due to an incorrect ID or a network issue. If you just get "geogebra applet loading..." for a long time, check your browser's console.**

## JME functions

### `geogebra_applet(id or dimensions, [object definitions], [object-part links])` → ggbapplet

*Load a GeoGebra material or create a blank worksheet, and optionally modify or create some objects and set up links between objects and question parts*

The parameters begin with either the ID of a material to load from geogebra.org, or a pair of numbers representing the width and height of a blank applet worksheet.
The material ID is or the URL of the material, such as `https://www.geogebra.org/m/jJ3zQ29z` or `http://ggbm.at/jJ3zQ29z`, or just the random-looking bit, e.g. `jJ3zQ29z`.

The next parameter is an optional dictionary of definitions (or re-definitions) of objects. The definition can be a value on its own, or a dictionary of properties to set.

If you give a dictionary of properties, the following properties are understood:

* `definition` (a value for the object, or a GeoGebra command)
* `caption`
* `color` (any valid CSS color is accepted)
* `visible`
* `label_visible`
* `label_style`
* `fixed`
* `trace`
* `rename`
* `layer`
* `line_style`
* `line_thickness`
* `point_style`
* `point_size`
* `display_style`
* `filling`

The definition can be:

* a number;
* a vector, which produces a point in the GeoGebra applet;
* a string, which is interpreted as a [GeoGebra command](https://www.geogebra.org/manual/en/Commands);
* a list of any of the above types of value.

If the object with the given name is already defined in the applet, then it is updated with the new definition you give. So you can set up your whole worksheet in the GeoGebra editor with placeholder values, and then replace them with the values generated by your question when it runs.

The optional final parameter is a list of links between GeoGebra objects and Numbas parts, in the format `[object or exercise name, part id]`. When the object changes in GeoGebra, the answer input for the corresponding part is updated, and vice versa. 

Be careful about linking dependent objects to part answers: if the student changes the part's answer input, the GeoGebra worksheet can't be updated to reflect that. So only link independent objects to part answers.
If you want to use the position of a dependent object in the marking of a part, use an 'extension' type part and the functions detailed below to get the part's position in a custom marking algorithm.

The object returned by this function can be embedded in any content area just like an HTML value.

##### Example usage

```
geogebra_applet('https://www.geogebra.org/m/jJ3zQ29z',[A: vector(ax,ay), B: vector(bx,by), C: vector(cx,cy)])
```

Loads the given worksheet, and moves points A,B and C to the given positions.

```
geogebra_applet(800,500,[A: ["definition": vector(1,0), "color": "red"]], [["A","p0"]])
```

Creates a blank worksheet with size 800 by 500 pixels, adds an object A at (1,0) and links the position of A with the answer to the first part in the question.

### `geogebra_file(filename, [object definitions], [object-part links])` → ggbapplet

*Load a GeoGebra file from the given file.*

The `filename` parameter can be the name of a resource attached to the question, or the URL of any .ggb file.

The 'object definitions' and 'object-part links' parameters work the same way as for `geogebra_applet`.

### `geogebra_base64(base64, width, height, [object definitions], [object-part links])` → ggbapplet

*Create a GeoGebra applet from the given base64-encoded .ggb file, with the given width and height in pixels.*

If you have the base64-encoded version of a .ggb file, this function will create a GeoGebra applet with the given dimensions and load the given worksheet in it.

One way of obtaining the base 64 string for a GeoGebra applet is to run `ggbApplet.getBase64()` on a page containing the applet. **Note:** the variable won't always be called `ggbApplet` - on geogebra.org, for example, a unique string of digits is appended to the variable name.

The 'object definitions' and 'object-part links' parameters work the same way as for `geogebra_applet`.

### Functions to obtain properties of objects

**Warning: Because of the way GeoGebra loads, these functions only work once the applet has been displayed. That means they don't work during question variable generation. The intended use for these functions is in part marking algorithms.**

The following functions get properties of a named object from a GeoGebra applet created with one of the functions above. They are all have the calling signature `property(app,object name)`, e.g. `value(app,"A")`.

* `value` - a representation of the object's value.
* `x` - the X coordinate
* `y` - the Y coordinate
* `z` - the Z coordinate
* `color` - the color of the object, as a hex string (e.g. `#4D4DFF`)
* `visible` - is the object visible?
* `value_string` - GeoGebra's string representation of the object.
* `definition_string` - the description of the object.
* `command_string` - the command of the object.
* `latex_string` - a string of LaTeX representing the object.
* `type` - the type of the object, e.g. `"point"`, `"numeric"`.
* `exists` - does the object exist in the applet?
* `defined` - is the object's value valid at the moment?
* `layer` - the layer the object is in.
* `line_style`
* `line_thickness`
* `point_style`
* `point_size`
* `caption`
* `label_style`

#### An example marking algorithm

This marking algorithm marks the part as correct if the point `A` is positioned at the coordinates (1,2).
The GeoGebra applet has been defined in the variable `app`.

```
a_pos (The position of the object A, as a vector):
  value(app,"A")

mark:
  feedback("A is at $\\var{latex(a_pos)}$");
  correctif(a_pos=target_position)

interpreted_answer:
  a_pos
```

## JavaScript functions

### `createGeogebraApplet(options,replacements,parts,question)`

`options` is a dictionary of [GeoGebra applet parameters](https://www.geogebra.org/manual/en/Reference:Applet_Parameters). This function returns a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) object which resolves to an object `{app: <GeoGebra applet>, element: <HTML element containing the applet>}`.

You could use this function to load an applet and then manipulate it with the [GeoGebra JavaScript API](https://www.geogebra.org/manual/en/Reference:JavaScript) before embedding it in the page.

Note that because this function returns a promise, the applet will not have finished loading at the time the question is displayed to the student. You'll have to insert the applet in the page yourself once the promise resolves.

### `tokToGeoGebra(token)`

Convert a Numbas JME token to a GeoGebra command.

## `geoGebraToTok(app,name)`

Get a JME token representing the value of a GeoGebra object.

`app` is a `GGBApplet` object, and `name` is the name of the GeoGebra object to convert.

Objects of type 'point' are converted to vectors, 'numeric' to numbers, and everything else to strings.