Javascript SVG 中的可拖动和可调整大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3614200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:26:28  来源:igfitidea点击:

Draggables and Resizables in SVG

javascriptsvgraphael

提问by Boris Yeltz

I want to make an svg element (path, rect, or circle) be able to be draggable and give it resize handles.

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

But unlike HTML DOM, not all elements have an upper left hand corner x,y coordinate and a width and height for a box surrounding the content. This makes it inconvenient to make a generic resize or drag procedure.

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

Is it a good idea to have each path or circle be drawn inside its own svg object to give me a box to play with?

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

How is draggable/resizable typically implemented in SVG?

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

回答by Peter Ajtai

Note: For both drag and resize, you'll have to make separate cases for certain different types of elements. Take a look in the example I provide later onthat handles the dragging of both ellipses and rectangles in the same set of functions.

注意:对于拖动和调整大小,您必须为某些不同类型的元素制作单独的案例。看看我稍后提供的示例该示例处理同一组函数中椭圆和矩形的拖动。



To make an element dragable you use:

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

element.drag(move, start, up);

The three arguments are references to the functions that handle moving (dragging), starting (mouse down), and the stopping (mouseup).

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

For example to make a draggable circle (from the documentation):

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

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

jsFiddle 示例



In the above example, the oxand oyproperties are tacked on to the element to keep track of its location, and these properties in conjunction with dxand dyare used to change the location of the element as it's being dragged.

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

A more complicated drag and dropto answer this question.

一个更复杂的拖放来回答这个问题

To make an object resizeable, you would simply create a second set of drag and drop methods for the resizer and just adjust the target elements heightand widthbased on dragging the resizer.

要使对象可调整大小,您只需为调整器创建第二组拖放方法,只需调整目标元素heightwidth基于拖动调整器即可。

Here's a full of one drag and drop and resizeable box I wrote up:

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

jsFiddle example of drag and drop and resizeable box

jsFiddle 拖放和可调整大小框的示例

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

The included event handlers (you can use more of course in conjunction with .node()) and the drag and drop description is at the bottom of the page in the documentation.

包含的事件处理程序(您当然可以结合使用更多.node())和拖放描述位于文档页面的底部。

You would simply make one Raphael canvas, and then each item would be a different element. Just assign them to variables so you can handle them, like in the example above ( cwas used to refer to the created circle element ).

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

In response to comments here is a simple drag and drop + resize able circle. The trick is that circles use the attributes cxand cyfor positioning and rfor size. The mechanics are pretty much the same... an ellipse would be slightly more complicate, but again it's just a question of working with the right attributes.

为了回应评论,这里是一个简单的拖放+调整大小的圆圈。诀窍是圆圈使用属性cx以及cy定位和r大小。机制几乎相同......椭圆会稍微复杂一些,但这只是使用正确属性的问题。

jsFiddle example of drag and drop and resizeable circle

jsFiddle 拖放和可调整大小的圆圈示例

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

回答by Elbert Alias

Have a look at Raphael.FreeTransformwhich seems to do what you're after.

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

回答by JS Rocker

Try Graphiti here is the link : Draw2d and Graphiti

尝试 Graphiti 这里是链接:Draw2d 和 Graphiti

It is based on Raphael and very easy to use.

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

回答by Paul LeBeau

There is also this plugin for SVG.js.

SVG.js 也有这个插件。

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

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