Рафаэль 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);
});
Я могу перемещать прямоугольники таким образом, но не пути, почему это так и как я могу перемещать объект пути??
Ответы
Ответ 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);