Grab Those Handles!

I have a graph with a line drawn on it.  I want to user to be able to change the orientation of the line by “clicking and dragging”.  To do this need to implement drag-handles.  Here’s how … 

Implementing Drag Line

lsgFirst let me introduce the code.  It is listed at the end of the last post.

The line is drawn using the Line function which is applied to the FrameBox of the graph by sending the Add Graphics Script message.  Here is the relevant section of code:

Notice that the arguments for the Line function are two lists, corresponding to the coordinates of the points p1 and p2 that delimit the line.

There is an alternative notation:

Line( xMatrix, yMatrix )

This notation will be more convenient, so here is a re-write of the code to exploit the x and y matrices for the two data points.  I’m also taking the opportunity to express the y coordinates explicitly as a function of the x-values:

I’ve done this because I want to replace Line with Drag Line, and this new function only takes matrices:

Drag Line as the name suggests, allows the user to drag the position of the line.  The line can be dragged by clicking on the end points.  To make this easier it helps to adjust the scale of the axes to be from -0.1 to +1.1.  Here is an illustration of how the dragging works:


Implementing Drag handles

Whilst this implements the functionality that I’m looking for, it’s not self-evident that the line is draggable.  I’d like a visual cue to that effect in the form of drag handles.  In which case, I don’t need the Drag Line function so I can return to using Line.  Note: it works with the new matrix notation which will prove to be useful:

I would like to have drag handles at either end of the line, but also one in the middle, to make it easy to shift the line up and down without adjusting the slope.  To illustrate how to code the handles I will start with only this central handle.  It is added to the graphics script by using the Handle function.

Handle( xPos, yPos, DragScript, MouseUpScript )

I want the handle to be plotted at the mid-point of the line.  Here are the relevant new lines of code:

The variables pcx and pcy define the coordinate of the handle.  When a drag operation is performed the function DoDrag is invoked, so I need to define this function – for now, just as a “stub”.

A drag operation is performed when  the user clicks in the area of the drag handle and then moves the mouse whilst keeping the mouse button depressed.

I nearly wrote “when the handle is moved by the user the function DoDrag is invoked”.  But this is not correct.  The drag operation generates new sets of (x,y) coordinates but does not move the location of the drag handle – I need to do this within the DoDrag function.  This video illustrates what I mean:

To move the handle I want the DoDrag function to update the coordinates associated with the matrix that defines the y coordinates of the line:

Where y is the new coordinate generated by the drag event and parsed to the DoDrag function as an argument.  The vertical displayment delta of the handle can be calculated:

This displacement can applied to the end-points of the line so that the line is also shifted.  Here is the full definition of the DoDrag function:

Here it is in action:

Adding A Twist

The centre drag handle is convenient for shifting the line up and down.  Adding drag handles to either end of the line allows the orientation of the line to be adjusted.  Conveniently these handles share the same coordinates as those used to define the line.

The drag event invokes the function DoTwist and for convenience I’ve added an additional argument pos that will tell me which of the two handles was selected.

And Finally

That completes the implementation of the grab handles, but there is one final piece of work to do, which relates to the original goal of this project:

The line is being used to define a binary response which is visualised by colouring the data points either red or green depending on their position relative to the line.  I already implemented this in the previous post, but now I need to update my code to react to the drag events.  I’ll take a look at that in the next post.


Share the joy:

Leave a Reply