Raphael JS - 保持两个对象之间的路径

5
我已经为 Raphael JS 创建了一个插件。它基本上允许您调用 paper.connect(obj1,obj2,colour)
这将在两个对象之间绘制一条线,并在对象动画时保持该线。 这是我迄今为止想出的东西。它可以工作,但性能不太好,您有什么其他建议来实现同样的功能吗?
Raphael.fn.connect = function(obj1, obj2, colour) {
    // list of paths each object has
    obj1.connections = []
    obj2.connections = []
    // get the bounding box of each object
    var box1 = obj1.getBBox()
    var box2 = obj2.getBBox()
    // create a line/path from object 1 to object 2
    var p = this.path("M" + (box1.x + box1.width / 2) + ","
            + (box1.y + box1.height / 2) + "L" + (box2.x + box2.width / 2)
            + "," + (box2.y + box2.height / 2))
    // adjust attributes of the path
    p.attr({
        stroke : colour,
        "stroke-linecap" : "round",
        "stroke-opacity" : Math.max(obj1.attr('opacity'), obj2.attr('opacity'))
    })
    // set the start and end element for this path
    p.startElement = obj1;
    p.endElement = obj2;
    // add the path to each of the object
    obj1.connections.push(p)
    obj2.connections.push(p)
    // mark each object as being connected
    obj1.connected = true;
    obj2.connected = true;
    // listen for the Raphael frame event
    eve.on("raphael.anim.frame.*", function(obj) {
        // if the object the frame event is fired on is connected
        if (this.connected) {
            // for each connection on this object
            for ( var c in this.connections) {
                var path = this.connections[c]; // temp path
                var b1 = path.startElement.getBBox(); // get the current
                                                        // location of start
                                                        // element
                var b2 = path.endElement.getBBox();// get the current location
                                                    // of end element
                // move the path to the new locations
                path.attr({
                    path : "M " + (b1.x + b1.width / 2) + " "
                            + (b1.y + b1.height / 2) + "L "
                            + (b2.x + b2.width / 2) + " "
                            + (b2.y + b2.height / 2),
                    opacity : Math.max(path.startElement.attr('opacity'),
                            path.endElement.attr('opacity'))
                });
            }
        }
    });
}

我并不确定这是否是最佳方法,但这是我第一次使用Raphael,所以我只是根据阅读Raphael源代码完成了所有操作...


不知道性能如何,但这节省了我一些时间,谢谢。 - Andreas Gohr
1
可能不是最佳方法。最终我使用div来绘制“线条”,并使用CSS和一点数学计算、移动和旋转div。结果更加灵活,因为它是一个div,你可以很容易地用CSS来操作它。请参见http://cogrow.it以获取示例。我很快就会清理并发布代码。 - zcourts
目前,使用相同的对象第二次调用.connect()会导致第一次连接断开(因为obj{1|2}.connections被重置)。您可以通过将前几行更改为if (!obj1.connections) obj1.connections = []if (!obj2.connections) obj2.connections = []来解决此问题。 - Dan
2
不确定这是一个合适的问题,但是为一些非常有用的代码点赞。 - Armand
1个回答

1
在我们的应用程序中,我们有一条线条工具。我们将带有2个可移动端点的直线放置在纸张上。
我们应用程序中的所有形状都有一个关联的VisualModel,其中包含它们内部的所有几何数据。这些VisualModels也兼作演员。任何演员都可以订阅其他演员,当发生更改时,所有感兴趣的方块都会做出响应。
这种系统允许通过重新绘制功能更改线的路径,该功能在任何连接对象修改其X / Y坐标时调用。
connecting_line.js(redraw)
redraw: function() {
    var x1 = this.shapeView1.visualModel.get('x'),
        y1 = this.shapeView1.visualModel.get('y'),
        x2 = this.shapeView2.visualModel.get('x'),
        y2 = this.shapeView2.visualModel.get('y'),
        pathData;

    pathData = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;

    this.line.attr({
        path: pathData,
        fill: '#000000',
        stroke: LineConstants.COLOR,
        'stroke-width': LineConstants.THICKNESS
    });
}

我们创建了一个名为“movable”的mixin。这个mixin可以让你的形状具有可移动性。这个mixin会更新x/y坐标,并触发一个“change”事件,你的线条类会接收到这个事件。

movable.js

handleDraggging: function(delta) {
    this.shape.move(delta);
}

move: function(delta) {
    //... compute movement based on delta
    this.visualModel.set('x', xPosition);
    this.visualModel.set('y', yPosition);
}

connecting_line.js

initialize: function(shapeView1, shapeView2) {
    // ...
    this.shapeView1 = shapeView1;
    this.shapeView2 = shapeView2;

    this.listenTo(shapeView1.visualModel, 'change:x change:y', this.redraw);
    this.listenTo(shapeView2.visualModel, 'change:x change:y', this.redraw);
}

这个功能的性能很棒。你可以前往eventbrite.com查看它的实际效果,创建一个事件,启用预留座位(第二步),添加一个新地图,在左侧点击“对象”并在纸上画一条线。


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