Raphael JS : how to move/animate a path object?

后端 未结 6 927
别跟我提以往
别跟我提以往 2020-12-08 08:53

Somehow this doesn\'t work...

var paper = Raphael(\"test\", 500, 500);

var testpath = paper.path(\'M100 100L190 190\');

var a = paper.rect(0,0,10,10);
a.at         


        
6条回答
  •  死守一世寂寞
    2020-12-08 09:27

    Here's some code that generalises the best of the above answers and gives Raphael paths a simple .attr({pathXY: [newXPos, newYPos]}) attribute similar to .attr({x: newXPosition}) and .animate({x: newXPosition}) for shapes.

    This lets you move your path to a fixed, absolute position or move it by a relative amount in a standard way without hardcoding path strings or custom calculations.


    Edit: Code below works in IE7 and IE8. An earlier version of this failed in IE8 / VML mode due to a Raphael bug that returns arrays to .attr('path') in SVG mode but strings to .attr('path') in VML mode.


    Code

    Add this code (Raphael customAttribute, and helper function) after defining paper, use as below.

    paper.customAttributes.pathXY = function( x,y ) {
      // use with .attr({pathXY: [x,y]});
      // call element.pathXY() before animating with .animate({pathXY: [x,y]})
      var pathArray = Raphael.parsePathString(this.attr('path'));
      var transformArray = ['T', x - this.pathXY('x'), y - this.pathXY('y') ];
        return { 
          path: Raphael.transformPath( pathArray, transformArray) 
        };
    };
    Raphael.st.pathXY = function(xy) { 
       // pass 'x' or 'y' to get average x or y pos of set
       // pass nothing to initiate set for pathXY animation
       // recursive to work for sets, sets of sets, etc
       var sum = 0, counter = 0;
       this.forEach( function( element ){
         var position = ( element.pathXY(xy) );
         if(position){
           sum += parseFloat(position);
           counter++;
         }
       });
       return (sum / counter);
    };
    Raphael.el.pathXY = function(xy) {
       // pass 'x' or 'y' to get x or y pos of element
       // pass nothing to initiate element for pathXY animation
       // can use in same way for elements and sets alike
       if(xy == 'x' || xy == 'y'){ // to get x or y of path
         xy = (xy == 'x') ? 1 : 2;
         var pathPos = Raphael.parsePathString(this.attr('path'))[0][xy];
         return pathPos;
       } else { // to initialise a path's pathXY, for animation
         this.attr({pathXY: [this.pathXY('x'),this.pathXY('y')]});
       }
    };
    

    Usage

    For absolute translation (move to fixed X,Y position) - Live JSBIN demo

    Works with any path or set of paths including sets of sets (demo). Note that since Raphael sets are arrays not groups, it moves each item in the set to the defined position - not the centre of the set.

    // moves to x=200, y=300 regardless of previous transformations
    path.attr({pathXY: [200,300]});
    
    // moves x only, keeps current y position
    path.attr({pathXY: [200,path.pathXY('y')]});
    
    // moves y only, keeps current x position
    path.attr({pathXY: [path.pathXY('x'),300]});
    

    Raphael needs to handle both x and y co-ordinates together in the same customAttribute so they can animate together and so they stay in sync with each other.

    For relative translation (move by +/- X,Y) - Live JSBIN demo

    // moves down, right by 10
    path.attr({pathXY: [ path.pathXY('x')+10, path.pathXY('y')+10 ]},500);
    

    This also works with sets, but again don't forget that Raphael's sets aren't like groups - each object moves to one position relative to the average position of the set, so results may not be what are expected (example demo).


    For animation (move a path to relative or absolute positions)

    Before animating the first time, you need to set the pathXY values, due to a bug/missing feature up to Raphael 2.1.0 where all customAttributes need to be given a numeric value before they are animated (otherwise, they will turn every number into NaN and do nothing, failing silently with no errors, or not animating and jumping straight to the final position).

    Before using .animate({pathXY: [newX,newY]});, run this helper function:

    somePath.pathXY();
    

提交回复
热议问题