如何使jQuery的工作拖拉SVG元素在Chrome没有得到补偿? (Firefox是OK)(H

2019-09-17 06:50发布

我尝试写一些代码,允许SVG元素被上拖动。 这是与jQuery,jQuery UI的和jQuery SVG很容易,而在Firefox中工作正常,但在Chrome中,当我拖动SVG元素,偏移显然加入到它的坐标。 我什么都看不到我做错了,或者发现这方面的任何已知的bug。

我已经构造说明该问题的一个小例子:

<html>
  <head>
    <title>Foo</title>
    <style type="text/css">
    </style>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
    <script type="text/javascript" src="http://keith-wood.name/js/jquery.svg.js"></script>
    <script type="text/javascript">
$(function() {
    var svgOnLoad = function () {
        var svg = $('#canvas').svg('get');
        $('#piece')
            .draggable()
            .bind('drag', function (event, ui) {
                // Update transform manually, since top/left style props don't work on SVG
                var t = event.target.transform.baseVal;
                if (t.numberOfItems == 0) {
                    t.appendItem(svg.root().createSVGTransform());
                }
                t.getItem(0).setTranslate(ui.position.left, ui.position.top);
            });
    }
    $('#canvas').svg({loadURL: "foo.svg", onLoad: svgOnLoad});
});
    </script>
  </head>
  <body>
    <div id="canvas" style="width: 100%; height: 100%;"></div>
  </body>
</html>

其中foo.svg就是:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1"
    xmlns="http://www.w3.org/2000/svg"
    width="450" height="450">
    <rect id="piece" width="50" height="50" x="100" y="100" />
</svg>

在线版本,可以发现:

http://jsfiddle.net/rrthomas/v477X/2/

Answer 1:

问题是,你是不是开始在SVG画布的位置0,0。 可以实现通过减去来自物体的x和y的属性所期望的结果。 当你计算出你的拖累手册您要重新定位整个SVG元素,而不仅仅是矩形。

在这里看到: http://jsfiddle.net/v477X/6/

注:不同的浏览器似乎要尝试翻译的元素将被返回不同的对象。 该解决方案工作在WebKit浏览器。 在这一点上,看来你有2种选择。 修改您的选择器选择相同的元件,(特别是线t.getItem(0)),或确定所述用户是在当前观看该浏览器中,并添加偏移量,如果它是webkit的。 就个人而言,我会用后者去,因为这样你可以设置一个变量,并检查它。

在这里看到如何检测浏览器引擎: 如果浏览器Chrome的使用jQuery如何检测?



Answer 2:

似乎是在jQueryUI的这里的错误:在非WebKit浏览器,该ui.position对象使用绝对坐标,而在其他浏览器中它是一个从ui.originalPosition偏移。 我不知道这是正确的; 这个bug是该行为是不一致的。 我已提起诉讼,在错误报告:

http://bugs.jqueryui.com/ticket/8335

因此,该解决方法是存储顶级元素的原始坐标,并设置坐标 - 设定WebKit浏览器的平移变换时(ui.position ui.originalPosition + origCoords)。 (Jlange的答案使用x和我的小例子,它在那里工作蛮好用的矩形Y的属性,但不与更复杂的对象工作一)不得有x和y的属性(例如,如果顶层元素是AG元素)和b)在返回的坐标似乎不是那些顶级元素的反正(我怕我不知道为什么))最小的代码如下:

var svgOnLoad = function () {
var svg = $('#canvas').svg('get');
    $('#piece')
        .draggable()
            .on({
                dragstart: function (event, ui) {
                    var tlist = this.transform.baseVal;
                        if (tlist.numberOfItems == 0) {
                            tlist.appendItem(svg.root().createSVGTransform());
                        }
                        var tm = tlist.getItem(0).matrix;
                        var pos = {left: tm.e, top: tm.f};
                        $.data(this, 'originalPosition', pos);
                    },
                    drag: function (event, ui) {
                        // Update transform manually, since top/left style props don't work on SVG
                        var tlist = this.transform.baseVal;
                        var CTM = this.getCTM();
                        var p = svg.root().createSVGPoint();
                        p.x = ui.position.left + CTM.e;
                        p.y = ui.position.top + CTM.f;
                        if ($.browser.webkit) { // Webkit gets SVG-relative coords, not offset from element
                            var origPos = $.data(this, 'originalPosition');
                            p.x -= ui.originalPosition.left - origPos.left;
                            p.y -= ui.originalPosition.top - origPos.top;
                        }
                        p = p.matrixTransform(CTM.inverse());
                        tlist.getItem(0).setTranslate(p.x, p.y);
                    }});
};
$('#canvas').svg({onLoad: svgOnLoad});

真人版在: http://jsfiddle.net/rrthomas/v477X/



Answer 3:

最近,我花了几天这个问题锤击,我想出了工作得相当好,我的解决方案。 这绝对是一个黑客,并且将无法正常工作在所有情况下。

此链接有如何在一般的解决这个问题一个很好的描述,那绝对是“更好”的解决方案。 不过,我想使用jQuery的可拖动的优秀API保持。

你可以看到我在小提琴做了一个快速模拟了这里 。 其核心思想是使用你保持在您想要拖动SVG元素正好徘徊代理股利。 然后,你改变SVG元素的x,y坐标为拖动代理股利。 事情是这样的:

$('#proxy').on('drag', function(e)
    {
        t = $('#background');
        prox = $('#proxy');
        t.attr('x', t.attr('x')*1
                   + prox.css('left').slice(0,-2)*1
                   - prox.data('position').left)
            .attr('y', t.attr('y')*1
                      + prox.css('top').slice(0,-2)*1
                      - prox.data('position').top);
        prox.data('position',{top : prox.css('top').slice(0,-2)*1,
                              left: prox.css('left').slice(0,-2)*1}
                  );
    });

在我的情况下,SVG元素,我想拖总是充满整个屏幕上的某个广场上,所以这是很容易在目标定位代理股利。 在其他情况下,它可能会更加困难。 它也不会太难用了“遏制”选项,以确保您不要拖到框架外的背景...它只是需要一些细致的数学,你必须遏制重置每个阻力之间。



Answer 4:

用这个:

<html>
<head>
    <title>Foo</title>
    <style type="text/css">
    </style>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
    <script type="text/javascript" src="http://keith-wood.name/js/jquery.svg.js"></script>
    <script type="text/javascript">
        $(function ()
            {
            var svg = $('#canvas').svg().svg('get');
            $('#piece')
                    .draggable()
                    .on({
                        dragstart: function (event, ui)
                            {
                            var t = this.transform.baseVal;
                            if (t.numberOfItems == 0)
                                { t.appendItem(svg.root().createSVGTransform()); }
                            var tm = t.getItem(0).matrix;
                            var dx = tm.e - ui.position.left;
                            var dy = tm.f - ui.position.top;
                            $.data(this, 'dragTo', function dragTo(newPos)
                                {
                                tm.e = newPos.left + dx;
                                tm.f = newPos.top + dy;
                                });
                            },
                        drag: function (event, ui)
                            { $.data(this, 'dragTo')(ui.position); }});
            });
    </script>
</head>
<body>
<div id="canvas" style="width: 100%; height: 100%;">
    <svg version="1.1"
         xmlns="http://www.w3.org/2000/svg"
         width="450" height="450">
        <rect id="piece" width="50" height="50" x="0" y="0" style="position:absolute"/>
    </svg>
</div>
</body>
</html>


Answer 5:

我有一个类似的问题。 我发现,由于某些原因,Chrome的转换变换属性为CSS样式属性。 因此,它创建了一个CSS样式- CSS的引擎调整坐标-那么SVG引擎然后尝试应用转换:转换。 之后,两人彼此干扰。

在CSS似乎有优先权。 这里是在这个codepen。
http://codepen.io/dax006/pen/ONNWXv

我的理论是,当CSS样式是由Chrome的更新,它不断地被破坏和重建,以及SVG有时那些时刻之间溜进在变换分析:翻译()。 Chrome会抓住新的转换值,并将其应用于CSS,现在您的转换,因为CSS是在路上将无法正常工作。

从理论上讲变换:翻译应该在创建CSS完全一样的瞬间被摧毁,但事实并非如此。 简单地检查元素,你会看到的CSS样式改变的坐标都存在着和变换属性。

<rect y="100" x="100" height="50" width="50" id="piece" style="position: relative; left: -15px; top: -13px;" transform="translate(-15, -13)"/>

一定要看看这篇文章,并在底部的链接。 https://css-tricks.com/svg-animation-on-css-transforms/



文章来源: How do I make dragging SVG elements in Chrome with jQuery work without getting offsets? (Firefox is OK)