Drag, drop and shape rotation with Raphael JS

前端 未结 6 757
星月不相逢
星月不相逢 2020-12-08 08:45

I\'m using RaphaelJS 2.0 to create several shapes in a div. Each shape needs to be able to be dragged and dropped within the bounds of the div, independently. Upon double

6条回答
  •  没有蜡笔的小新
    2020-12-08 09:15

    As amadan suggests, it's usually a good idea to create functions when multiple things have the same (initial) attributes/properties. That is indeed the answer to your first question. As for the second question, that is a little more tricky.

    When a Rapheal object is rotated, so is the coordinate plane. For some reason, dmitry and a few other sources on the web seem to agree that it's the correct way to implement it. I, like you, disagree. I've not managed to find an all round good solution but I did mange to create a work around. I'll briefly explain and then show the code.

    • Create a custom attribute to store the current state of rotation
    • Depending on that attribute you decide how to handle the move.

    Providing that you are only going to be rotating shapes by 90 degrees (if not it becomes a lot more difficult) you can determine how the coordinates should be manipulated.

    var R = Raphael("paper", "100%", "100%");
    
    //create the custom attribute which will hold the current rotation of the object {0,1,2,3}
    R.customAttributes.rotPos = function (num) {
        this.node.rotPos = num;
    };
    
    var shape1 = insert_rect(R, 100, 100, 100, 50, { fill: "red", stroke: "none" });
    var shape2 = insert_rect(R, 200, 200, 100, 50, { fill: "green", stroke: "none" });
    var shape3 = insert_rect(R, 300, 300, 100, 50, { fill: "blue", stroke: "none" });
    var shape4 = insert_rect(R, 400, 400, 100, 50, { fill: "black", stroke: "none" });
    
    //Generic insert rectangle function
    function insert_rect(paper,x,y, w, h, attr) {
        var angle = 0;
        var rect = paper.rect(x, y, w, h);  
        rect.attr(attr);
    
        //on createion of the object set the rotation position to be 0
        rect.attr({rotPos: 0});
    
        rect.drag(drag_move(), drag_start, drag_up);
    
        //Each time you dbl click the shape, it gets rotated. So increment its rotated state (looping round 4)
        rect.dblclick(function(){
            var pos = this.attr("rotPos");
            (pos++)%4;
            this.attr({rotPos: pos});
            angle -= 90;
            rect.stop().animate({transform: "r" + angle}, 1000, "<>");
        });
    
        return rect;  
    }
    
    //ELEMENT/SET Dragger functions.
    function drag_start(e) {
        this.ox = this.attr("x");
        this.oy = this.attr("y");
    };
    
    
    //Now here is the complicated bit
    function drag_move() {
        return function(dx, dy) {
    
            //default position, treat drag and drop as normal
            if (this.attr("rotPos") == 0) {
              this.attr({x: this.ox + dx, y: this.oy + dy});
            }
            //The shape has now been rotated -90
            else if (this.attr("rotPos") == 1) {
    
                this.attr({x:this.ox-dy, y:this.oy + dx});
            }           
            else if (this.attr("rotPos") == 2) {
                this.attr({x: this.ox - dx, y: this.oy - dy});
            }
            else if (this.attr("rotPos") == 3) {
                 this.attr({x:this.ox+dy, y:this.oy - dx});
    
            }      
        }
    };
    
    function drag_up(e) {
    }
    

    I can't really think of clear concise way to explain how the drag_move works. I think it's probably best that you look at the code and see how it works. Basically, you just need to work out how the x and y variables are now treated from this new rotated state. Without me drawing lots of graphics I'm not sure I could be clear enough. (I did a lot of turning my head sideways to work out what it should be doing).

    There are a few drawbacks to this method though:

    • It only works for 90degree rotations (a huge amount more calculations would be needed to do 45degrees, nevermind any given degree)
    • There is a slight movement upon drag start after a rotation. This is because the drag takes the old x and y values, which have been rotated. This isn't a massive problem for this size of shape, but bigger shapes you will really start to notice shapes jumping across the canvas.

    I'm assuming the reason that you are using transform is that you can animate the rotation. If this isn't necessary then you could use the .rotate() function which always rotates around the center of the element and so would eliminate the 2nd drawback I mentioned.

    This isn't a complete solution, but it should definitely get you going along the correct path. I would be interested to see a full working version.

    I've also created a version of this on jsfiddle which you can view here: http://jsfiddle.net/QRZMS/3/

    Good luck.

提交回复
热议问题