-
Notifications
You must be signed in to change notification settings - Fork 865
Writing interactive exercises
The interactive
utility module provides some helpful tools for creating interactive exercises. All of the interactions typically take place inside a single graphie element, so to start, you'd create a graphie element to contain your interaction:
<div class="problem">
<div class="graphie">
init({
range: [ [ -5, 5 ], [ -5, 5 ] ]
});
addMouseLayer();
</div>
</div>
The init()
function initializes graphie and the addMouseLayer()
function adds an invisible layer on top of the graph that is used by the interactive utilities to capture mouse events. addMouseLayer()
also does some other setup, so basically if you're using any of the interactive utilities, you want to call this right after the graphie init()
. Note that it will also disable the scratchpad. Normally this won't be a problem, since the user will be using the mouse to interact with your nifty exercise, but it's something to be aware of.
addMouseLayer()
This basically initializes the interactive functions. Call it after the graphie init()
call but before you call any interactive functions.
addMovablePoint( options )
This adds a point to the graph that can be dragged around. It allows automatic constraints on its movement as well as automatically managing line segments that terminate at the point.
Options can be set to control how the point behaves:
-
coord[]
: The initial position of the point -
snapX
,snapY
: The minimum increment the point can be moved -
visible
: Set to false for the point to be invisible. This might be useful since you can still attach line segments to the point and still move the point programmatically. You might also want this to use in defining afixedDistance
orfixedAngle
constraint for another point. -
constraints
: An object describing constraints on the point's movement:-
constraints.fixed
: Set to true to make the point immovable. You can still move it programmatically of course. -
constraints.constrainX
: Set to true to only permit the point to be dragged up and down. -
constraints.constrainY
: Set to true to only permit the point to be dragged left and right. -
constraints.fixedDistance
: This object allows you to constrain the point to always be a fixed distance from another point. In other words, it gives you a point that moves in a circle. SetfixedDistance.dist
to the radius of the circle andfixedDistance.point
to a (possibly invisible) movablePoint or simply a coordinate pair [x, y] that defines the center. -
constraints.fixedAngle
: This object allows you to constrain the point to only move in a straight line at a particular angle. You provide theangle
and the coordinates of thevertex
and anotherref
point point that together define the line along which the point may move.
-
-
normalStyle
,highlightStyle
: Raphael-type style attributes that allow you to override the appearance of the point.
The return value is a movablePoint object that can be used to manipulate the point:
-
The
coord[]
property tells you the current (x, y) position. -
Additionally any of the other options and constraints above can be set after the point is created to change its behavior. For example, you can add or remove a constraint.
-
By adding an
onMove( x, y )
method to the returned object, you can install an event handler that gets called every time the user moves the point. TheonMove()
method is passed the proposedx
andy
coordinates. If you returnfalse
from youronMove()
method, you veto the movement. You can use this to provide custom constraints on where the point can move. If that's not enough, you can also return an array[ x, y ]
that overrides the point's position. -
The returned object also provides a
moveTo( x, y, updateLineEnds )
method that will move the point to a specific (x, y) coordinate with an animation. If you've attached any line segments to the point (see below), you can passtrue
forupdateLineEnds
and the lines will animate along with the point. If you've defined anonMove()
callback, it will get called with the new position.- If you don't want the animation of
moveTo()
or want to do things yourself for some reason, there are some more granular methods:setCoord([ x, y ])
moves the point without any checks, animation, or callbacks. If you're usingsetCoord()
and have any line segments that terminate at the point, you might also want to callupdateLineEnds()
afterwards to automatically redraw all the line segments attached to the point.
- If you don't want the animation of
-
You can connect a
movableLineSegment
(see below) to amovablePoint
. The point is attached to a specific end of the line segment by adding the segment either to the list of lines that start at the point or the list of lines that end at the point:movablePoint.lineStarts.push( movableLineSegment ); - or - movablePoint.lineEnds.push( movableLineSegment );
Normally it's easier to let movableLineSegment
do this for you though
addMovableLineSegment( options )
MovableLineSegment is a line segment that can be dragged around the screen. By attaching a movablePoint
to each (or one) end, the ends can be manipulated individually.
To use with movablePoints, add the movablePoint first, then:
addMovableLineSegment({
pointA: movablePoint1,
pointZ: movablePoint2
});
Or just one end:
addMovableLineSegment({
pointA: movablePoint1,
coordZ: [ 0, 0 ]
});
Include fixed: true
in the options if you don't want the entire line to be draggable (you can still use points to make the endpoints draggable)
Other options supported are:
-
snap
: When dragging the line, the minimum increment it can be moved -
extendLine
: Set to true to extend the line to the edges of the drawing area. In other words it draws a "line" rather than a "line segment" -
normalStyle
,highlightStyle
: Raphael-type style attributes that allow you to override the appearance of the line.
The returned object includes the following properties/methods:
-
lineSegment.coordA
/lineSegment.coordZ
: The coordinates of each end of the line segment -
lineSegment.transform( syncToPoints )
: Repositions the line segment. Call after changing coordA and/or coordZ, or passsyncToPoints = true
to use the current position of the corresponding movablePoints, if the segment was defined using movablePoints
Two points connected by a line segment. The points allow you to drag the ends of the line segment around:
<div class="graphie">
init({
range: [ [ -5, 5 ], [ -5, 5 ] ]
});
addMouseLayer();
graph.point1 = addMovablePoint({
coord: [ -4, 0 ]
});
graph.point2 = addMovablePoint({
coord: [ 4, 0 ]
});
graph.line1 = addMovableLineSegment({
pointA: graph.point1,
pointZ: graph.point2,
fixed: true
});
</div>
A point that moves in a circle. Note that point1
is the center of the circle and is set to be invisible. point2
is the one that is visible and draggable, so we add a constraint that forces it to always stay 4 units from point1
, hence moving in a circle. This also shows a line segment added between the two points to show the radius:
<div class="graphie">
init({
range: [ [ -5, 5 ], [ -5, 5 ] ]
});
addMouseLayer();
graph.point1 = addMovablePoint({
coord: [ 0, 0 ],
visible: false
});
graph.point2 = addMovablePoint({
coord: [ 4, 0 ]
});
graph.point2.constraints.fixedDistance = {
dist: 4,
point: graph.point1
};
graph.line1 = addMovableLineSegment({
pointA: graph.point1,
pointZ: graph.point2,
fixed: true
});
graph.point3 = addMovablePoint({
coord: [ 8, 8 ],
snapY: 1,
snapX: 1,
});
graph.point3.constraints.fixedAngle = {
angle: 0,
vertex: { coord: [ 0, 0 ]},
ref: { coord: [ 20, 20 ]}
}
</div>
Checking the student's answer to an interactive exercise is a little more involved. In most cases you'll need to use the custom
answer type.