Snap SVG:拖动组不会更新元素

时间:2014-11-17 00:06:53

标签: javascript snap.svg

JSFiddle:JSFiddle

当拖动一组对象时,单个对象'位置属性似乎没有得到更新。无论我使用默认的drag()处理程序还是定义我自己的。即使是BBox集团的运营似乎也没有更新。代码:

var s = Snap("#svg");

var move = function (dx, dy, posx, posy) {
    this.attr({
        x: posx,
        y: posy
    });
    //this.transform("t" + dx + "," + dy);
};
var block = s.rect(100, 100, 100, 100);
var circle = s.circle(100, 100, 50);
var group = s.g(block, circle);

//group.drag(move, function () {}, function () {});
group.drag();
//block.drag(move, function () {}, function () {});

//just a way to keep info coming w/o an interminable script
document.addEventListener('mousemove', function (e) {
    bbox = block.getBBox();
    block_x = block.attr("x");
    block_y = block.attr("y");
    gbbox = group.getBBox();
    console.log("block is at " + block_x + "," + block_y,
        "   Block Bbbox is at " + bbox.x + "," + bbox.y,
        "   Group Bbbox is at " + gbbox.x + "," + gbbox.y);


}, false);

如果我只定义一个对象(例如,一个矩形)并将其从组中删除,并通过我自己的"移动"函数用于拖动调用,并包括设置" x"和" y"显式属性,然后工作。但是,如果我将矩阵包含在一个组中,那么...我无法弄清楚如何做到这一点,并且我已经尝试了一些方法(请参阅多个注释掉的行显示我和#39 ;尝试过)。我需要知道rect子组元素在拖动后最终的位置,或者至少是整个组的BBox。这些似乎都没有得到更新 - 即我放入的控制台日志永远显示相同的数字,无论我在哪里移动对象。

有人可以帮忙吗?

JSFiddle:JSFiddle

3 个答案:

答案 0 :(得分:1)

我认为这是因为它们是两个不同的东西,所以它们实际上并不是可以互换的。

拖动处理程序使用转换。转换不会影响任何其他属性,它只是元素的一个属性(在本例中是组元素)。

getBBox将在其当前变换空间中工作,请注意这可能与客户端不同(例如,如果svg被放大/缩小)。所以它们是两种略有不同的方法,它们可以做不同的事情。

如果需要相对于客户端窗口的边界框,请使用getBoundingClientRect。如果在元素当前坐标空间中需要边界框,请使用getBBox。

答案 1 :(得分:1)

代码也使用snap.svg.zpd,因此可以进行缩放。问题在于onStopMove功能。当组被移动时会触发事件。在组中是一个圆圈(this.select('#main-inner-circle')),它在组内没有预定义的位置。我试图在移动组后获得该内圈的正确cx和cy。

self.onMove = function (dx, dy, ev, x, y) {
            var clientX, clientY;
            var tdx, tdy;
            if ((typeof dx == 'object') && (dx.type == 'touchmove')) {
                clientX = dx.changedTouches[0].clientX;
                clientY = dx.changedTouches[0].clientY;
                dx = clientX - this.data('ox');
                dy = clientY - this.data('oy');
            }

            var snapInvMatrix = this.transform().diffMatrix.invert();
            snapInvMatrix.e = snapInvMatrix.f = 0;
            tdx = snapInvMatrix.x(dx, dy);
            tdy = snapInvMatrix.y(dx, dy);            

            this.transform("t" + [tdx, tdy] + this.data('ot'));
        }

        self.onStartMove = function (x, y, ev) {
            if ((typeof x == 'object') && (x.type == 'touchstart')) {
                x.preventDefault();
                this.data('ox', x.changedTouches[0].clientX);
                this.data('oy', x.changedTouches[0].clientY);
            }

            this.data('ot', this.transform().local);
            if (callbacks.onStartMove) {
                callbacks.onStartMove();
            }
        }

        self.onStopMove = function () {
            var self = this.select('#main-inner-circle');
            this.data('ot', this.transform().local);
            //self.data('ot', self.transform().local);
            console.log(self.getTransformedBBox());
            console.log(this.getBBox());
            //console.log($(self.node).offset().left - $(self.node).parent().offset().left);
            var bBox = this.getBBox();
            //var x = bBox.x + $(self.node).offset().left - $(self.node).parent().offset().left + self.getBBox().width / 2;
            //var y = bBox.y + $(self.node).offset().top - $(self.node).parent().offset().top + self.getBBox().height / 2;
            model.updateElementCoordinates(index, $(this.node).attr("rel"), { x: self.getTransformedBBox().cx, y: self.getTransformedBBox().cy });

            if (callbacks.onStopMove) {
                callbacks.onStopMove();
            }
        }

答案 2 :(得分:0)

为了发布这个问题,我创建了JSFiddle,但遗漏了关键的snap.svg定义......

<script src="http://snapsvg.io/assets/js/snap.svg-min.js"></script>

...那么,那么group.getBBox()方法实际上是有效的。但是:

显然,使用getBBox()非常慢 - 比在分组对象之前访问“x”属性要慢得多。我所知道的是,如果我使用getBBox(),我的代码会慢慢爬行(我在屏幕上有很多对象)。

在同一帖子中进一步向下提到[“使用snap.svg获取svg组的坐标”1建议使用getBoundingClientRect(),这也很好 AND 足够快!我的新工作小提琴显示了所有这些方法:New JSFiddle

所以,未来的用户:使用.node.getBoundingClientRect()。