DragTutorial

Batik Drag Tutorial: How to move shapes in the Canvas

The code provided is a snippet with suggestions, on how to implement a drag operation in a JSVGCanvas. It is identical as the post I submitted in the Batik Mail list. A more detailed drag tutorial is in the works, with explanations about how to handle draggable <g> elements and the transform/translate attribute.

The Post

You need to implement listeners for the mouseevents:

public void registerListeners() {
        // Gets an element from the loaded document.
        // document is your SVGDocument
        elt = document.getElementById("The_Group_ID_That_holds_the_movable_Elements");
        EventTarget t = (EventTarget)elt;

        // Adds  'mouseevent' listeners
        t.addEventListener("mousedown", new OnDownAction(), false);
        t.addEventListener("mousemove", new OnMoveAction(), false);
        t.addEventListener("mouseup", new OnUpAction(), false);
        t.addEventListener("mouseover", new OnOverAction(), false);
        t.addEventListener("click", new OnClickAction(), false);
    }


Next, you need to register a global variable with the state of the DRAG operation, 
and the initial drag point:

protected int drag;
protected Element selectedItem;
protected SVGOMPoint initialDragPoint;
protected final int DRAG_UP = 0;
protected final int DRAG_DOWN = 0;

Next, in the onmousedown event, you set the "drag" variable to  DRAG_DOWN:

public class OnDownAction implements EventListener {
        public void handleEvent(Event evt) {
                //perform select, deselect operations, etc...
                // i.e. assign or validate that you have a draggable item 
                // in the "selectedItem" object (And define "thisNode" element)
                

                //For example, "thisNode" can be:
                SVGLocatable thisNode = (SVGLocatable)evt.getTarget();

                //End of example. The variable thisNode has the element
                // that is the draggableItem. It can be a single Element
                // or a G element.  If you are interested in a G element
                // you may need a method to locate the desired parent
                // of your eventTarget (like parsing the ID attr.) because
                // the eventTarget may only be one single element of a
                // complex shape, and you want to drag the full complex shape.


                drag = DRAG_DOWN;

                // Set the initial drag point
                DOMMouseEvent elEvt = (DOMMouseEvent)evt;
                    int nowToX = elEvt.getClientX();
                    int nowToY = elEvt.getClientY();

                // Convert Screen coordinates to Document Coordinates.
                    SVGOMPoint pt = new SVGOMPoint(nowToX, nowToY);
                    SVGMatrix mat = thisNode.getScreenCTM();  // elem -> screen
                    mat = mat.inverse();                  // screen -> elem
                    initialDragPoint = (SVGOMPoint)pt.matrixTransform(mat);

        }
}

Now, on mouse up, finalize the drag operation:

public class OnUpAction implements EventListener {
        public void handleEvent(Event evt) {
                        drag = DRAG_UP;
        }
}

And Finally, the core of the drag:

public class OnMoveAction implements EventListener {
        public void handleEvent(Event evt) {
                if (drag == DRAG_DOWN) {
                        //Cast the event onto a Batik Mouse event, 
                 //so we can get ccordinates
                        DOMMouseEvent elEvt = (DOMMouseEvent)evt;
                         int nowToX = elEvt.getClientX();
                         int nowToY = elEvt.getClientY();
                        //convert it to a point for use with the Matrix
                        SVGOMPoint pt = new SVGOMPoint(nowToX, nowToY);
                        //Get the items screen coordinates, and apply the transformation
                 // elem -> screen
                        SVGMatrix mat = ((SVGLocatable)evt.getTarget()).getScreenCTM();  

                        mat = mat.inverse();                  // screen -> elem
                        SVGOMPoint dragpt = (SVGOMPoint)pt.matrixTransform(mat);

           /* Now to actually move the objects, there are several approaches:

           a.) If they are individual elements (i.e. no <g>´s), you can simply modify 
               the element attributes X, Y. by:
               "element.setAttribute("x", ""+ dragpt.getX());"

           b.) You can iterate though all the elements in the selection (in case of 
               multiple selections or <g> elements) and individually change the x, y
               attributes of each item, as in a.)

           c.) You can apply a transform on your selected element. To do so you need 
               to perform a matrix transform from previous transforms this object 
               has had. For example, the first time you drag an object, you will add a
               transform attribute such as: transform="translate(dragpt.x, dragpt.y)", 
               but for subsequent drag operations you need to do, for each axis: 
               oldtransformCoordinate + newCordinate
               For a fully functional example of this approach, you can see the Adobe 
               SVGDraw application, found at: 
               http://www.adobe.com/svg/demos/svgDraw/svgDraw/index.html
               Although this demo is purely Javascript-Adobe SVG Viewer application, 
               you may learn a lot at how to handle the DOM and perform multiple 
               operations. Pay specific attention to the Matrix transform methods.
                           
              To analyze easily the Javascript code, i recommend the Eclipse IDE v3.0.2 
              with the jseditor plugin (sourceforge.net/projects/jseditor)
                        */
                }
        }
}

Display

To do

last edited 2005-06-13 13:20:42 by AndresToussaint