Подтвердить что ты не робот

Рафаэль JS: как перемещать/анимировать объект пути?

Как-то это не работает...

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

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

var a = paper.rect(0,0,10,10);
a.attr('fill', 'silver');

a.mousedown( function() {
  testpath.animate({x: 400}, 1000);
});

Я могу перемещать прямоугольники таким образом, но не пути, почему это так и как я могу перемещать объект пути??

4b9b3361

Ответ 1

С последней версией Raphael вы можете сделать это:

var _transformedPath = Raphael.transformPath('M100 100L190 190', 'T400,0');
testpath.animate({path: _transformedPath}, 1000);

Это избавит вас от необходимости иметь clone временный объект.

Ответ 2

Кажется, что объект path не получает значение x, y - поэтому ваша анимация, вероятно, все еще работает, но ничего не делает. Попробуйте вместо этого активировать функцию пути:

testpath.animate({path:'M400 100L490 190'},1000);

Это немного сложнее написать анимацию, но вы можете получить бесплатную ротацию и масштабирование!

BTW: Я уверен, что это всего лишь пример, но в вашем предыдущем коде testpath он попадает в глобальную область видимости, потому что вы не инициализируетесь как var testpath

Ответ 3

Решено, с спасибо за Руду!

Вам нужно создать новый путь для анимации. Вы можете сделать это с помощью clone(), а затем применить преобразования к этому клону. Кажется очень сложным для простого движения, как это, но он работает...

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

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

var a = paper.rect(0,0,10,10);
a.attr('fill', 'silver');

a.mousedown( function() {

  var temp = testpath.clone();
  temp.translate(400,0);
  testpath.animate({path: temp.attr('path')}, 1000);
  temp.remove();

});

Ответ 4

Ответ TimDog был лучшим решением.

Кроме того, просто помните, что преобразование строки в этом случае означает, что оно добавит 400 точек к каждой координате точки пути/линии X и 0 указывает на каждую координату Y.

Это означает, что M100 100L190 190 превратится в M500 100L590 190.

Итак, если вам нужно переместить элемент пути в другую позицию, следует рассчитать разницу между текущей позицией и новыми координатами позиции. Вы можете использовать первый элемент для этого:

var newCoordinates = [300, 200],
curPos = testpath.path[0],
newPosX = newCoordinates[0] - curPos[1],
newPosY = newCoordinates[1] - curPos[2];

var _transformedPath = Raphael.transformPath(testpath.path, "T"+newPosX+","+newPosY);
testpath.animate({path: _transformedPath});

Надеюсь, это поможет кому-то.

Ответ 5

Вот некоторый код, который обобщает лучший из приведенных выше ответов и дает пути Рафаэля простой .attr({pathXY: [newXPos, newYPos]}) атрибут, похожий на .attr({x: newXPosition}) и .animate({x: newXPosition}) для фигур.

Это позволяет вам перемещать ваш путь к фиксированной, абсолютной позиции или перемещать ее относительной величиной стандартным способом без строк пути жесткого кодирования или пользовательских вычислений.


Изменить: Код ниже работает в IE7 и IE8. Ранняя версия этого отказала в режиме IE8/VML из-за ошибка Raphael, возвращающая массивы в .attr('path') в режиме SVG, но строки. attr ( "путь" ) в режиме VML.


код

Добавьте этот код (Raphael customAttribute и вспомогательную функцию) после определения paper, используйте, как показано ниже.

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 pathXY, for animation
     this.attr({pathXY: [this.pathXY('x'),this.pathXY('y')]});
   }
};

Использование

Для абсолютного перевода (переместить в фиксированное положение X, Y) - Live JSBIN demo

Работает с любым путем или набор путей, включая наборы множеств (demo). Обратите внимание, что поскольку набор Рафаэля - это массивы, а не группы, он перемещает каждый элемент в наборе в определенную позицию, а не в центр набора.

// 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]});

Рафаэль должен обрабатывать как координаты x, так и y вместе в одном и том же customAttribute, чтобы они могли анимировать вместе, и поэтому они остаются в синхронизации друг с другом.

Для относительного перевода (переместите на +/- X, Y) - Live JSBIN demo

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

Это также работает с наборами, но опять же не забывайте, что множества Рафаэля не похожи на группы - каждый объект перемещается в одну позицию относительно средней позиции набора, поэтому результаты могут быть не такими, какие ожидаются (пример демонстрации).


Для анимации (перемещение пути в относительные или абсолютные позиции)

Перед анимацией в первый раз вам необходимо установить значения paспасибоY из-за ошибки/отсутствующей функции до Raphael 2.1.0, где всем customAttributes необходимо присвоить числовое значение, прежде чем они будут анимированные (в противном случае они превратят каждое число в NaN и ничего не сделают, провалив молча без ошибок или не оживуют и прыгают прямо в конечную позицию).

Перед использованием .animate({pathXY: [newX,newY]}); запустите эту вспомогательную функцию:

somePath.pathXY();

Ответ 6

Еще один способ - использовать атрибут "transform" :

testpath.animate({transform: "t400,0"}, 1000);

чтобы переместить путь вправо на 400 пикселей по отношению к исходной позиции.

Это должно работать для всех фигур, включая пути и прямоугольники.

Обратите внимание, что:

  • "transform" атрибут не зависит от x, y, cx, cy и т.д. Таким образом, эти атрибуты не обновляются с помощью анимации выше.
  • Значение атрибута "transform" всегда основывается на исходной позиции, а не на текущей позиции. Если вы примените анимацию ниже после анимации выше, она будет перемещать ее на 800 пикселей влево относительно, вместо того чтобы переместить ее обратно в исходное положение.

    testpath.animate({transform: "t-400,0"}, 1000);