Selecting rectangles of SVG elements (for Raphael)

I ran into the following problem, I hope someone knows how to help me:

I am working with the Raphael JavaScript library . Now I want to have a lot of Raphael's SVG elements to just select more elements with a "rectangle selection" i.e. By dragging the mouse starting from the background of the graph to create a selection rectangle (I hope I was clear enough) and move the elements that are in that rectangle.

Currently I have found something like this (someone posted it from a previous question ):

var paper = Raphael(0, 0, '100%', '100%');

var circle = paper.circle(75, 75, 50);
var rect = paper.rect(150, 150, 50, 50);

var set = paper.set();

set.push(circle, rect);
set.attr({
    fill: 'red',
    stroke: 0
});

var ox = 0;
var oy = 0;
var dragging = false;

set.mousedown(function(event) {
    ox = event.screenX;
    oy = event.screenY;
    set.attr({
        opacity: .5
    });
    dragging = true;
});

set.mousemove(function(event) {
    if (dragging) {
        set.translate(event.screenX - ox, event.screenY - oy);
        ox = event.screenX;
        oy = event.screenY;
    }
});

set.mouseup(function(event) {
    dragging = false;
    set.attr({
        opacity: 1
    });
});

      

This code can be executed on jsfiddle . But as you can see, this selects ALL the elements by simply adding them to the Raphael set.

Now, I think my problem will be solved:

  • Selecting a rectangle
  • Adding nodes that are in a rectangle to a Raphael set
  • Move only selected items (i.e. move only items that are in Raphael's set using set.mousemove)

My problem for now would be the first two problems.

Any ideas how to do this?

Thank you in advance!

+3


source to share


1 answer


Funny problem. You can do this by placing a rectangular "matte" canvas size behind all of your other objects and associating a drag event with it to select other items. (Note that this solution uses a newer version of Raphael, 2.1.0:

var paper = Raphael(0, 0, '100%', '100%');

//make an object in the background on which to attach drag events
var mat = paper.rect(0, 0, paper.width, paper.height).attr("fill", "#FFF");

var circle = paper.circle(75, 75, 50);
var rect = paper.rect(150, 150, 50, 50);
var set = paper.set();

set.push(circle, rect);
set.attr({
    fill: 'red',
    stroke: 0
});
//the box we're going to draw to track the selection
var box;
//set that will receive the selected items
var selections = paper.set();

      

Now let's add a drag event - similar to mouseover events, but with three functions ( see documentation ) and draw a box to keep track of the selection location:

//DRAG FUNCTIONS
//when mouse goes down over background, start drawing selection box
function dragstart (x, y, event) {
    box = paper.rect(x, y, 0, 0).attr("stroke", "#9999FF");    
}

// When mouse moves during drag, adjust box.
// If the drag is to the left or above original point,
// you have to translate the whole box and invert the dx 
// or dy values since .rect() doesn't take negative width or height
function dragmove (dx, dy, x, y, event) {
    var xoffset = 0,
        yoffset = 0;
    if (dx < 0) {
        xoffset = dx;
        dx = -1 * dx;
    }
    if (dy < 0) {
        yoffset = dy;
        dy = -1 * dy;
    }
    box.transform("T" + xoffset + "," + yoffset);
    box.attr("width", dx);    
    box.attr("height", dy);    
}

function dragend (event) {
    //get the bounds of the selections
    var bounds = box.getBBox();
    box.remove();
    reset();
    console.log(bounds);
    for (var c in set.items) {
        // Here, we want to get the x,y vales of each object
        // regardless of what sort of shape it is.
        // But rect uses rx and ry, circle uses cx and cy, etc
        // So we'll see if the bounding boxes intercept instead

        var mybounds = set[c].getBBox();
        //do bounding boxes overlap?
        //is one of this object x extremes between the selection xe xtremes?
        if (mybounds.x >= bounds.x && mybounds.x <= bounds.x2 || mybounds.x2 >= bounds.x && mybounds.x2 <= bounds.x2) {
            //same for y
            if (mybounds.y >= bounds.y && mybounds.y <= bounds.y2 || mybounds.y2 >= bounds.y && mybounds.y2 <= bounds.y2) {
                selections.push(set[c]);       
            }
        }
        selections.attr("opacity", 0.5);
    }
}

function reset () {
    //empty selections and reset opacity;
    selections = paper.set();
    set.attr("opacity", 1);    
}

mat.drag(dragmove, dragstart, dragend);
mat.click(function(e) {
   reset(); 
});

      



Also, you have a new set (selection) that contains all the objects that were selected by dragging with the mouse. Then you can apply your hover events from the original to this set.

Note that this will select circle objects if you click on the corner of their bounding box with your selection box, even if it doesn't overlap with the circle's area. If this is a problem, you can make a special case for the circles.

jsFiddle

+9


source







All Articles