Как нарисовать путь вектора прогрессивно?(Raphaël.js) - PullRequest
31 голосов
/ 08 января 2011

Как анимировать векторную траекторию, как будто она рисуется, постепенно? Другими словами, медленно показывать путь пиксель за пикселем.

Я использую Raphaël.js, но если ваш ответ не является специфичным для библиотеки - как, может быть, есть какой-то общий шаблон программирования для подобных вещей (я довольно новичок в векторной анимации) - это приветствуется!


Этолегко сделать с прямыми путями, так же просто, как пример на этой странице ::

path("M114 253").animate({path: "M114 253 L 234 253"});

Но попробуйте изменить код на этой странице, скажем, так: *

path("M114 26").animate({path: "M114 26 C 24 23 234 253 234 253"});

И вы поймете, что я имею в виду.Путь, безусловно, анимируется из его начального состояния (точка "M114 26") до конечного состояния (кривая "C 24 23 234 253 234 253", начиная с точки "M114 26"), но не указанным способом, а не какэто рисуется.

Я не понимаю, как animateAlong может это сделать.Он может анимировать объект вдоль пути, но как я могу сделать так, чтобы этот путь постепенно показывал себя во время анимации объекта вдоль него?


Решение?

(Через ответ peteorpeter .)

Похоже, что в настоящее время лучший способ сделать это - использовать «поддельные» тире с использованием необработанного SVG.Для объяснения см. эту демонстрацию или этот документ , стр. 4.

Как производить прогрессивный рисунок?

Мы должны использовать stroke-dasharray и stroke-dashoffset и знать длину кривой для рисования.Этот код ничего не рисует на экране для круга, эллипса, полилинии, многоугольника или пути:

<[element] style="stroke-dasharray:[curve_length],[curve_length]; stroke-dashoffset:[curve_length]"/>

Если в анимированном элементе значение смещения штрихов уменьшается до 0, мы получаем прогрессивное рисование кривой.

Если вы знаете лучший способ, пожалуйста, оставьте ответ.


Обновление (26 апреля 2012 г.): нашел пример, который хорошо иллюстрирует идею,см. Анимированные кривые Безье .

Ответы [ 11 ]

26 голосов
/ 03 февраля 2012

Может быть, кто-то ищет ответ, как я, уже два дня:

// Draw a path and hide it:
var root = paper.path('M0 50L30 50Q100 100 50 50').hide();
var length = root.getTotalLength();

// Setup your animation (in my case jQuery):
element.animate({ 'to': 1 }, {
    duration: 500,
    step: function(pos, fx) {
        var offset = length * fx.pos;
        var subpath = root.getSubpath(0, offset);
        paper.clear();
        paper.path(subpath);
    }
});

Это помогло мне, только с помощью методов RaphaelJS.

Вот jsFiddleпример в соответствии с просьбой в комментариях, http://jsfiddle.net/eA8bj/

17 голосов
/ 22 февраля 2011

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

Вы можете использовать SVG keyTimes и keySplines .

Вот рабочий пример:

http://www.carto.net/svg/samples/animated_bustrack.shtml

... и вот несколько потенциально полезных объяснений:

http://msdn.microsoft.com/en-us/library/ms533119(v=vs.85).aspx

11 голосов
/ 25 октября 2012

Я хотел бы предложить альтернативное решение Raphael + JS, которое я использовал в своей работе. У него есть несколько преимуществ перед решением Давиденке:

  1. Не очищает бумагу с каждым циклом, позволяя анимированному пути хорошо сосуществовать с другими элементами;
  2. Повторно использует одиночный путь с собственной прогрессивной анимацией Рафаэля, что делает плавную анимацию;
  3. Значительно менее ресурсоемкий.

Вот метод (который можно легко переоборудовать в расширение):

function drawpath( canvas, pathstr, duration, attr, callback )
{
    var guide_path = canvas.path( pathstr ).attr( { stroke: "none", fill: "none" } );
    var path = canvas.path( guide_path.getSubpath( 0, 1 ) ).attr( attr );
    var total_length = guide_path.getTotalLength( guide_path );
    var last_point = guide_path.getPointAtLength( 0 );
    var start_time = new Date().getTime();
    var interval_length = 50;
    var result = path;        

    var interval_id = setInterval( function()
    {
        var elapsed_time = new Date().getTime() - start_time;
        var this_length = elapsed_time / duration * total_length;
        var subpathstr = guide_path.getSubpath( 0, this_length );            
        attr.path = subpathstr;

        path.animate( attr, interval_length );
        if ( elapsed_time >= duration )
        {
            clearInterval( interval_id );
            if ( callback != undefined ) callback();
                guide_path.remove();
        }                                       
    }, interval_length );  
    return result;
}

И вот два примера его использования на моем сайте: один для Path Transformation , а другой для Progressive Lettering .

6 голосов
/ 21 марта 2011

Используя атрибут " pathLength ", мы можем установить виртуальную длину пути.С этого момента мы можем использовать эту виртуальную длину в "stroke-dasharray".Таким образом, если мы установим «pathLength» на 100 единиц, мы можем установить для «stroke-dasharray» значение «50,50», что будет точно 50%, 50% пути!

Существует одна проблема с этимподход: единственный браузер, который поддерживает этот атрибут, это Opera 11.

Здесь - пример анимации рисования с плавной кривой без JavaScript или жестко заданной длины (работает правильно только в Opera 11)

5 голосов
/ 09 марта 2016

Я создал сценарий для этого: Scribble.js , основанный на этой замечательной dasharray/dashoffset технике .

Просто создайте его экземпляр над кучейSVG <path> s:

var scribble = new Scribble(paths, {duration: 3000});
scribble.erase();
scribble.draw(function () {
    // done
});

-

Примечание: полный USAGE код здесь: https://gist.github.com/abernier/e082a201b0865de1a41f#file-index-html-L31

Наслаждайтесь;)

3 голосов
/ 24 марта 2012

Решение Anton & Peteorpeter, к сожалению, ломается в Chrome, когда пути усложняются. Это хорошо для карты автобуса в этой связанной демонстрации. Посмотрите на этот анимированный «лепесток цветка», созданный мной jsfiddle, который правильно рисует в FF10 и Safari5, но неуверенно мерцает в Chrome:

http://jsfiddle.net/VjMvz/

(Это все HTML и встроенный SVG, без JavaScript.)

Я все еще ищу не-Flash решение для этого. AnimateAlong, очевидно, не будет сокращать то, что я делаю. Raphael.js может работать, хотя это грозит очень быстро превратиться в спагетти с обратным вызовом.

Davidenke, можете ли вы опубликовать рабочий jsfiddle с вашим решением? Я просто не могу заставить его работать. Я получаю сообщение об ошибке в Chrome 18, что у узлов, для которых установлено «display: none» с вашим «.hide», нет метода «getTotalLength».

2 голосов
/ 01 февраля 2011

К сожалению, как вы, похоже, согласны, вы, вероятно, не можете сделать это элегантно в Рафаэле.чтобы поддерживать IE для этой конкретной функции, вы можете отказаться от Raphael API и напрямую манипулировать SVG .Тогда, возможно, вы могли бы настроить маску , чтобы ехать по дорожке и раскрывать линию в естественном темпе.

В IE вы могли бы грациозно ухудшиться, чтобы просто показать путь, используя Рафаэля, без анимации.

1 голос
/ 02 августа 2013

Просто обновление, вы можете попробовать Lazy Line Painter

1 голос
/ 03 мая 2011

Я просто делал именно это.Первое, что я попробовал, было решение Антона, но производительность отстой.

В конце концов, самый простой способ получить желаемый результат - использовать альтернативный синтаксис "ключевой кадр" для функции animate.

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

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

затем сделайте что-то вроде:

path.anmimate ({keyFrameObject, timeframe});

вам не нужен ключевой кадр для каждого пикселя, который вы хотите нарисовать.Поработав с параметрами, я обнаружил, что значение 100px на ключевой кадр работает для сложности / размера того, что я пытался «нарисовать»

0 голосов
/ 10 января 2011

Хорошо, вот мои мысли по этому поводу ... Решение слишком далеко от идеального.

Чтобы постепенно показать среднее значение пути, мы должны показать его, например, точка за точкой. И векторные пути состоят не из точек, а из кривых, поэтому мне кажется, что нет «естественного» способа постепенно «нарисовать» путь в векторной графике. (Хотя я довольно новичок в этом и могу ошибаться.)

Единственным способом было бы как-то преобразовать путь в несколько точек и показать их одну за другой.

В настоящее время мой обходной путь - это нарисовать путь, сделать его невидимым, разбить его на несколько подпутей и показать эти подпути по одному.

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

...