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

Как нарисовать векторный путь постепенно? (Raphaël.js)

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

Я использую 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. Он может анимировать объект вдоль пути, но как я могу сделать этот путь, чтобы постепенно проявлять себя, когда объект анимируется вдоль него?


Решение?

(Via ответ peteorpeter.)

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

Как произвести прогрессивный чертеж?

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

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

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

<circle cx="200" cy="200" r="115"
    style="fill:none; stroke:blue; stroke-dasharray:723,723; stroke-dashoffset:723">
    <animate begin="0" attributeName="stroke-dashoffset"
        from="723" to="0" dur="5s" fill="freeze"/>
</circle>

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


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

4b9b3361

Ответ 2

Возможно, кто-то ищет ответ, как я, в течение двух дней:

// 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/

Ответ 3

Эврика! (Может быть, если вы согласитесь, что вам удобно выйти за пределы дружественного царства Рафаэля в чистую землю 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

Ответ 4

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

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

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

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, а другой для Прогрессивная надпись.

Ответ 5

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

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

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

Ответ 6

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

http://jsfiddle.net/VjMvz/

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

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

Дэвиденке, можете ли вы опубликовать рабочий файл с вашим решением? Я просто не могу заставить его работать. Я получаю ошибку в Chrome 18, что узлы, которые настроены на "display: none" с вашим ".hide", не имеют метода getTotalLength.

Ответ 7

К сожалению, как вы, кажется, согласны, вы, вероятно, не можете сделать это элегантно в Рафаэле.

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

Вы можете грамотно деградировать в IE, чтобы просто показать путь с помощью Raphael без анимации.

Ответ 8

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

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

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

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

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

path.anmimate({keyFrameObject, timeframe});

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

Ответ 9

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

Ответ 11

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

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

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

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

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