skip to main content
Charts > Programmer's documentation > Developing with the JViews Charts SDK > Interacting With Charts > Writing your own interactor
 
Writing your own interactor
When writing your own interactor, you can use and extend the source code of the built-in JViews Charts interactors. You find this source code in the <installdir>/jviews-charts/samples/interactor/src/ directory.
This example is extracted from the stock sample. The source code of this example can be found in <installdir>/jviews-charts/samples/stock/src/stock/ZoomScaleInteractor.java directory.
The ZoomScaleInteractor class defined in this example allows the user to zoom a given portion of the display area by selecting the area to zoom in on the scale itself instead of on the plot area.
1. Extend the IlvChartInteractor class.
public class ZoomScaleInteractor extends IlvChartInteractor
{ ... }
2. Define the attributes of the class.
private boolean swap = false; protected IlvStyle
style; protected int axisIdx; protected double start; protected
double end;
The axisIdx attribute specifies the axis index on which the zoom is performed (-1 = x-axis). The bounds of the zoomed area are defined by the start and end attributes. This data is updated each time the mouse is dragged.
3. Add the constructor.
/** * Create new ZoomScaleInteractor associatedwith the specified axis
* that zoom in on a BUTTON1 event and zoomout on SHIFT+BUTTON1. */
public ZoomScaleInteractor(int axisIdx) {
    super(axisIdx != -1 ? axisIdx : 0, MouseEvent.BUTTON1_MASK);
    this.axisIdx = axisIdx;
    renderer = new IlvStyle(new BasicStroke(5),IlvColor.magenta); ...
An interactor is always attached to a unique y-axis. Indeed, since several y-axes may coexist on the same chart, an interactor needs to know on which y-axis the interactions are performed, so that conversions from display space to data space (and vice versa) are possible. This y-axis is referenced at the IlvChartInteractor level using its index and is the first parameter of the constructor.
We want to handle both mouse motion events and mouse click events, as well as key events (to handle cancellation using ‘ESC’ key):
     ... enableEvents(AWTEvent.MOUSE_EVENT_MASK
| AWTEvent.MOUSE_MOTION_EVENT_MASK |
      AWTEvent.KEY_EVENT_MASK); }
4. Filter the events.
Since the interaction is performed on the scale, the interactor is only interested in the events that occur within the scale bounds:
public boolean isHandling(int x, int y) {
   return (getScale() != null) ? getScale().getBounds(scaleBounds).contains(x,y) : false; }
5. Process the events.
In the processMouseEvent method, we define that the interaction starts when the left mouse button has been pressed, calling the startOperation method.
The event coordinate is converted to a data value on the scale, and the start and end attributes are initialized to the previous and next steps of the scale, respectively.
public void processMouseEvent(MouseEvent evt)
 {
    double value;
    switch (evt.getID()) {
        case MouseEvent.MOUSE_PRESSED: ... startOperation(evt);
          value = getScale().toValue(evt.getX(),evt.getY());
          start = getScale().getStepsDefinition().previousStep(value);
          end = getScale().getStepsDefinition().incrementStep(start);
          drawGhost();
          evt.consume();
...
          break; ... }
The drawGhost method is then called. This method allows you to have a visual feedback of the interaction by temporarily drawing over the chart area.
Mouse dragged events are handled as follows:
public void processMouseMotionEvent(MouseEventevt) {
  if (evt.getID() == MouseEvent.MOUSE_DRAGGED && isInOperation()){
    drawGhost();
    double value = getScale().toValue(evt.getX(),evt.getY());
    computeStartEnd(value);
    drawGhost();
    evt.consume(); } }
First erase the previous ghost (note that it has effects only in XOR mode), then compute the new start and end values, and finally draw the new ghost.
The zoom is effectively performed when the button is released.
public void processMouseEvent(MouseEvent evt)
{ ... case MouseEvent.MOUSE_RELEASED: if (!isInOperation())
                break;
      value = getScale().toValue(evt.getX(),evt.getY());
      computeStartEnd(value);
      drawGhost();
      zoomScale();
endOperation(evt);
evt.consume();
break; ... }
The new start and end values are computed, the scale is zoomed, and the interaction is set as ended. Finally, we want to cancel the interaction that is performed when the ‘ESC’ key is pressed:
public void processKeyEvent(KeyEvent evt)
{ if (evt.getID() == KeyEvent.KEY_PRESSED && evt.getKeyCode()== KeyEvent.VK_ESCAPE )
{ if (isInOperation()) drawGhost();
    abort();
    evt.consume(); } }
If the interactor is in operation, the ghost is erased (it has only effects in XOR mode), and the interaction state is set as aborted, with the abort method implemented as follows:
protected void abort() { super.abort();
    swap = false; /* Disable ghost drawing operation */ setAllowDrawGhost(false);
}
6. Draw a ghost.
A ghost can be drawn either in XOR mode or in Paint mode, depending on the value of the interactor xorGhost property. By default, most of the default interactors draw their ghost in paint mode. In a general manner, XOR mode should be avoided due to the poor control it gives on the drawing.
To be able to draw a ghost, an interactor must first enable the draw ghost mechanism, calling the setAllowDrawGhost method with true as parameter, and disable it when the interaction ends. This is performed by the startOperation and endOperation methods:
protected void endOperation(MouseEvent evt)
{ super.endOperation(evt);
swap = false; /* Disable ghost drawing operation */
setAllowDrawGhost(false); } protected void
startOperation(MouseEvent evt) {
super.startOperation(evt);
  /* Enable ghost drawing operation */
setAllowDrawGhost(true);
}
NOTE When overriding one of the startOperation, endOperation or abort methods, do not forget to call the corresponding super method since it performs several required internal initializations.

Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.