Рафаэль JS: как переместить / оживить объект пути? - PullRequest
12 голосов
/ 08 июня 2011

Почему-то это не работает ...

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

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

Ответы [ 6 ]

29 голосов
/ 25 июня 2012

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

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

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

17 голосов
/ 08 июня 2011

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

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

Писать анимацию немного сложнее, но у вас есть преимущество, заключающееся в бесплатном вращении и масштабировании!

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

10 голосов
/ 09 июня 2011

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

Вам необходимо создать новый путь для анимации.Вы можете сделать это с помощью 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 голосов
/ 23 августа 2012

Ответ 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});

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

2 голосов
/ 05 марта 2013

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

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


Редактировать: Код ниже работает в IE7 и IE8. Более ранняя версия этого не удалась в режиме IE8 / VML из-за ошибки Raphael, которая возвращает массивы в .attr ('path') в режиме SVG, но в .attr ('path') в режиме 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's pathXY, for animation
     this.attr({pathXY: [this.pathXY('x'),this.pathXY('y')]});
   }
};

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

Для абсолютного перевода (переместите в фиксированное положение X, Y) - Live JSBIN 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 вместе в одном и том же пользовательском атрибуте, чтобы они могли анимироваться вместе и чтобы они были синхронизированы друг с другом.

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

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

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


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

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

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

somePath.pathXY();
0 голосов
/ 17 июля 2016

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

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

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

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

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

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

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