【问题标题】:Draggables and Resizables in SVGSVG 中的可拖动和可调整大小
【发布时间】:2011-04-06 13:33:48
【问题描述】:

我想让一个 svg 元素(路径、矩形或圆形)能够被拖动并给它调整大小的句柄。

但与 HTML DOM 不同,并非所有元素都有左上角 x,y 坐标以及围绕内容的框的宽度和高度。这使得进行通用的调整大小或拖动过程很不方便。

将每条路径或圆圈绘制在自己的 svg 对象中以给我一个可以玩的盒子是个好主意吗?

在 SVG 中通常如何实现可拖动/调整大小?

【问题讨论】:

    标签: javascript svg raphael


    【解决方案1】:

    注意:对于拖动和调整大小,您必须为某些不同类型的元素分别设置大小写。看看 the example I provide later on,它在同一组函数中处理椭圆和矩形的拖动。


    要使元素可拖动,请使用:

    element.drag(move, start, up);
    

    三个参数是对处理移动(拖动)、启动(鼠标向下)和停止(鼠标向上)的函数的引用。

    例如制作一个可拖动的圆圈(来自文档):

    window.onload = function() {
    var R = Raphael("canvas", 500, 500);    
    var c = R.circle(100, 100, 50).attr({
        fill: "hsb(.8, 1, 1)",
        stroke: "none",
        opacity: .5
    });
    var start = function () {
        // storing original coordinates
        this.ox = this.attr("cx");
        this.oy = this.attr("cy");
        this.attr({opacity: 1});
    },
    move = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({cx: this.ox + dx, cy: this.oy + dy});
    },
    up = function () {
        // restoring state
        this.attr({opacity: .5});
    };
    c.drag(move, start, up);    
    };​
    

    jsFiddle example


    在上面的示例中,oxoy 属性被附加到元素上以跟踪其位置,这些属性与 dxdy 一起用于更改元素的位置被拖动的元素。

    A more complicated drag and drop回答this question

    要使对象可调整大小,您只需为调整大小创建第二组拖放方法,并根据拖动调整大小调整目标元素heightwidth

    这是我写的一个完整的拖放和可调整大小的框:

    jsFiddle example of drag and drop and resizeable box

    window.onload = function() {
    var R = Raphael("canvas", 500, 500),
        c = R.rect(100, 100, 100, 100).attr({
                fill: "hsb(.8, 1, 1)",
                stroke: "none",
                opacity: .5,
                cursor: "move"
            }),
        s = R.rect(180, 180, 20, 20).attr({
                fill: "hsb(.8, .5, .5)",
                stroke: "none",
                opacity: .5
            }),
        // start, move, and up are the drag functions
        start = function () {
            // storing original coordinates
            this.ox = this.attr("x");
            this.oy = this.attr("y");
            this.attr({opacity: 1});
    
            this.sizer.ox = this.sizer.attr("x");
            this.sizer.oy = this.sizer.attr("y");
            this.sizer.attr({opacity: 1});
        },
        move = function (dx, dy) {
            // move will be called with dx and dy
            this.attr({x: this.ox + dx, y: this.oy + dy});
            this.sizer.attr({x: this.sizer.ox + dx, y: this.sizer.oy + dy});        
        },
        up = function () {
            // restoring state
            this.attr({opacity: .5});
            this.sizer.attr({opacity: .5});        
        },
        rstart = function () {
            // storing original coordinates
            this.ox = this.attr("x");
            this.oy = this.attr("y");
    
            this.box.ow = this.box.attr("width");
            this.box.oh = this.box.attr("height");        
        },
        rmove = function (dx, dy) {
            // move will be called with dx and dy
            this.attr({x: this.ox + dx, y: this.oy + dy});
            this.box.attr({width: this.box.ow + dx, height: this.box.oh + dy});
        };   
        // rstart and rmove are the resize functions;
        c.drag(move, start, up);
        c.sizer = s;
        s.drag(rmove, rstart);
        s.box = c;
    };​
    

    包含的事件处理程序(您当然可以与.node()一起使用更多)和拖放说明在页面底部in the documentation.

    您只需制作一个 Raphael 画布,然后每个项目将是一个不同的元素。只需将它们分配给变量,以便您可以处理它们,就像上面的示例一样(c 用于引用创建的圆元素)。

    为了响应 cmets,这里是一个简单的拖放 + 可调整大小的圆圈。诀窍是圆圈使用属性cxcy 进行定位,使用r 进行大小。机制几乎相同......椭圆会稍微复杂一些,但这只是使用正确属性的问题。

    jsFiddle example of drag and drop and resizeable circle

    window.onload = function() {
        var R = Raphael("canvas", 500, 500),
            c = R.circle(100, 100, 50).attr({
                fill: "hsb(.8, 1, 1)",
                stroke: "none",
                opacity: .5
            }),
            s = R.circle(125, 125, 15).attr({
                fill: "hsb(.8, .5, .5)",
                stroke: "none",
                opacity: .5
            });
        var start = function () {
            // storing original coordinates
            this.ox = this.attr("cx");    
            this.oy = this.attr("cy");
    
            this.sizer.ox = this.sizer.attr("cx");    
            this.sizer.oy = this.sizer.attr("cy")
    
            this.attr({opacity: 1});
            this.sizer.attr({opacity: 1});
        },
        move = function (dx, dy) {
            // move will be called with dx and dy
            this.attr({cx: this.ox + dx, cy: this.oy + dy});
            this.sizer.attr({cx: this.sizer.ox + dx, cy: this.sizer.oy + dy});
        },
        up = function () {
            // restoring state
            this.attr({opacity: .5});
            this.sizer.attr({opacity: .5});
        },
        rstart = function() {
            // storing original coordinates
            this.ox = this.attr("cx");
            this.oy = this.attr("cy");        
    
            this.big.or = this.big.attr("r");
        },
        rmove = function (dx, dy) {
            // move will be called with dx and dy
            this.attr({cx: this.ox + dy, cy: this.oy + dy});
            this.big.attr({r: this.big.or + Math.sqrt(2*dy*dy)});
        };
        c.drag(move, start, up);    
        c.sizer = s;
        s.drag(rmove, rstart);
        s.big = c;
    };
    

    【讨论】:

    • 嗨,上面的例子很好,但我希望进一步扩展它。我希望能够使用可调整大小的圆圈。我已经设法让 rect 正常工作,但为此苦苦挣扎。我认为我的问题源于 rmove 方法,因为当我设置 this.box 宽度和高度时,圆圈没有其他选择。您知道的任何想法或任何可能的教程。谢谢。
    • @Adam - 对于圆和椭圆,您只需使用中心点 cxcy 以及半径。这是一个如何处理矩形和椭圆以进行拖动的示例 ==> jsfiddle.net/vPyjc (查看“拖动器”函数,它使用 if shapes[ind].type == "rect" 来检查形状的类型并分别处理每一个。- ---- 这意味着您基本上必须编写单独的代码来处理椭圆的拖动和调整大小(使用半径和中心坐标而不是框)。
    • 对不起,我可能没有说清楚。拖动形状我没有任何问题。有问题的是调整大小。我可以像上面的示例一样调整矩形的大小,但我无法使用可拖动的形状调整圆/椭圆的大小,即使我选择了正确的属性。我认为问题出在 .box 上,因为圆圈没有宽度和高度属性。
    • @Adam - 我明白了。这就是为什么我说要使用cxcy 和圆的半径。通过r 访问半径属性,您可以使用它而不是框来调整圆的大小 - 这是一个快速调整圆大小的示例:jsfiddle.net/EqrQZ(当然,您需要添加一个句柄来调整大小示例) - 请注意,我正在使用 r 来调整圆圈的大小。 - box 只是更大对象的副本,您必须自己创建它...查看最后一行代码 ==> s.box = c;
    • 啊,现在一切都说得通了,我已经开始工作了。感谢所有的帮助。我可能应该在一个问题中问它,这样你就可以得到代表。谢谢:)
    【解决方案2】:

    看看Raphael.FreeTransform,它似乎可以满足您的需求。

    【讨论】:

      【解决方案3】:

      试试 Graphiti 这里是链接:Draw2d and Graphiti

      它基于 Raphael,非常易于使用。

      【讨论】:

        【解决方案4】:

        还有这个用于 SVG.js 的插件。

        https://github.com/svgdotjs/svg.resize.js

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-01-16
          • 1970-01-01
          • 2011-04-20
          • 1970-01-01
          • 2016-02-02
          • 1970-01-01
          • 2014-04-07
          • 2014-04-15
          相关资源
          最近更新 更多