SVG元素的矩形选择(用于Raphael)

8

我遇到了以下问题,希望有人能帮助我:

我正在使用JavaScript库Raphael。现在,我想做的是,当我有许多Raphael SVG元素时,通过“矩形选择”简单地选择更多元素,即从图的背景开始拖动鼠标以创建选择矩形(我希望我足够清楚),并移动在此矩形中的元素。

目前,我找到了像这样的东西(有人从我的之前的一个问题发表了这个):

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
    });
});

这段代码可以在jsfiddle上执行。但是,正如你所看到的,它通过将所有元素添加到 Raphael set 中选择了所有元素。

现在,我认为我的问题将通过以下解决:

  1. 进行矩形选择
  2. 将在矩形内的节点添加到 Raphael set 中
  3. 仅移动所选项目(即仅移动在 Raphael set 中的项目与 set.mousemove)

我现在的问题集中在前两个问题上。

有任何想法吗?

先感谢您!


如果您将d3与Raphael结合使用,可以使用https://github.com/mbostock/d3/wiki/Selections#wiki-filter来实现此目的。 - cmonkey
谢谢你的回答,但我不想将d3与Raphael结合使用,这会使事情变得更加复杂。还有其他的想法吗? - Belphegor
1个回答

14

有趣的问题。您可以通过在所有其他对象后面放置与画布大小相同的矩形“垫子”,并为其附加拖动事件来选择其他元素来解决此问题。 (请注意,此解决方案使用较新版本的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();

现在,我们添加了一个拖动事件——类似于鼠标悬停事件,但有三个函数(查看文档),并绘制一个框来跟踪选择区域:
//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's x extremes between the selection's 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(); 
});

就像这样,您现在有了一个包含鼠标拖动选择的每个对象的新集合。然后,您可以将原始的mouseover事件应用于该集合。
请注意,如果您的选择框刚好碰到圆形对象的边界框角落,即使它不与圆形的区域重叠,它也会选择圆形对象。如果这是一个问题,您可以为圆形对象制定特殊情况。 jsFiddle

很棒的答案,Chris。我已经使用了它。我正在对我的选定区域应用缩放,但偏移不正确。 - Matthew Shaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接