Рафаэль 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);
});
Я могу перемещать ректы таким образом, но не путями, почему так, и как мне тогда перемещать объект пути?!
6 ответов
С последней версией Raphael вы можете сделать это:
var _transformedPath = Raphael.transformPath('M100 100L190 190', 'T400,0');
testpath.animate({path: _transformedPath}, 1000);
Это избавляет вас от необходимости clone
временный объект.
Кажется path
объект не получает x
,y
значение - так что ваша анимация, вероятно, все еще работает, но ничего не делает. Попробуйте вместо этого анимировать функцию пути:
testpath.animate({path:'M400 100L490 190'},1000);
Писать анимацию немного сложнее, но у вас есть преимущество, когда вы получаете вращение и масштабирование бесплатно!
Кстати, я уверен, что это всего лишь пример, но в приведенном выше коде testpath
попадает в глобальную область, потому что вы не инициализируете как var testpath
Решено, спасибо Руду!
Вам нужно создать новый путь для анимации. Вы можете сделать это с помощью 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();
});
Ответ 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});
Надеюсь, это кому-нибудь поможет.
Вот код, который обобщает лучшие из приведенных выше ответов и дает простым путям Рафаэля .attr({pathXY: [newXPos, newYPos]})
атрибут похож на .attr({x: newXPosition})
а также .animate({x: newXPosition})
для фигур.
Это позволяет вам переместить ваш путь в фиксированное абсолютное положение или переместить его на относительную величину стандартным способом без жесткого кодирования строк пути или пользовательских вычислений.
Изменить: код ниже работает в IE7 и IE8. Более ранняя версия этого не удалась в режиме IE8 / VML из-за ошибки Рафаэля, которая возвращает массивы в.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, где всем customAttributes нужно дать числовое значение, прежде чем они будут анимированы (в противном случае они превратят каждое число в NaN и ничего не делайте, молча проваливайтесь без ошибок или не оживляйте и прыгайте прямо в конечную позицию).
Перед использованием .animate({pathXY: [newX,newY]});
, запустите эту вспомогательную функцию:
somePath.pathXY();
Еще один способ - использовать атрибут transform:
testpath.animate({transform: "t400,0"}, 1000);
переместить путь вправо на 400 пикселей относительно исходного положения.
Это должно работать для всех фигур, включая контуры и прямоугольники.
Обратите внимание, что:
- Атрибут "transform" не зависит от x, y, cx, cy и т. д. Таким образом, эти атрибуты не обновляются анимацией выше.
Значение атрибута "transform" всегда основывается на исходной позиции, а не на текущей позиции. Если вы примените анимацию ниже после анимации выше, она переместится на 800px влево относительно, вместо того, чтобы вернуть ее в исходное положение.
testpath.animate({transform: "t-400,0"}, 1000);