javascript - create - ¿Cómo dibujar una ruta vectorial progresivamente?(Raphael.js)
svg animation generator (11)
¿Cómo animar una ruta vectorial como si estuviera siendo dibujada progresivamente? En otras palabras, muestre lentamente la ruta píxel por píxel.
Estoy usando Raphaël.js
, pero si tu respuesta no es específica de la biblioteca, tal vez haya algún patrón de programación general para hacer ese tipo de cosas (soy bastante nuevo para la animación vectorial), ¡es bienvenido!
Es fácil de hacer con rutas rectas, tan fácil como un ejemplo en esa página ::
path("M114 253").animate({path: "M114 253 L 234 253"});
Pero intente cambiar el código en esa página, por ejemplo, de esta manera ::
path("M114 26").animate({path: "M114 26 C 24 23 234 253 234 253"});
Y verás a qué me refiero. La ruta está ciertamente animada desde su estado inicial (punto "M114 26") hasta el estado final (curva "C 24 23 234 253 234 253" comenzando en el punto "M114 26"), pero no de la manera especificada en cuestión, no como está siendo dibujado.
No veo cómo animateAlong
puede hacer eso. Puede animar un objeto a lo largo de un camino, pero ¿cómo puedo hacer que este camino se muestre gradualmente mientras se está animando el objeto a lo largo de él?
¿La solución?
(A través de la respuesta del petererpetero )
Parece que actualmente la mejor manera de hacerlo es mediante guiones ''falsos'' usando SVG sin formato. Para la explicación, vea esta demostración o este documento , página 4.
¿Cómo producir un dibujo progresivo?
Tenemos que usar
stroke-dasharray
ystroke-dashoffset
y saber la longitud de la curva para dibujar. Este código no dibuja nada en la pantalla de círculo, elipse, polilínea, polígono o ruta:
<[element] style="stroke-dasharray:[curve_length],[curve_length]; stroke-dashoffset:[curve_length]"/>
Si en el elemento animado stroke-dashoffset disminuye a 0, obtenemos un dibujo progresivo de la curva.
<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>
Si conoce una mejor manera, por favor deje una respuesta.
Actualización (26 de abril de 2012): Encontré un ejemplo que ilustra bien la idea, ver Animated Bézier Curves .
¿Has probado el animateAlong de Raphael? Puedes verlo en acción en una página de demostración .
Bien, aquí está mi opinión sobre esto ... La solución está muy lejos de ser ideal.
Para mostrar gradualmente el camino, debemos mostrarlo, como punto por punto. Y las rutas vectoriales no consisten en puntos, sino en curvas, por lo que me parece que no hay una forma "natural" de "dibujar" gradualmente la ruta en gráficos vectoriales. (Aunque soy bastante nuevo en esto y puedo estar equivocado)
La única manera sería convertir de alguna manera un camino a una serie de puntos y mostrarlos uno por uno.
Actualmente, mi solución es dibujar una ruta, hacerla invisible, dividirla en varios subcampos y mostrar los subtrazos uno por uno.
Esto no es difícil de hacer con Raphael, pero tampoco es elegante, y bastante lento en caminos grandes. No acepto mi respuesta, esperando que haya una mejor manera ...
Desafortunadamente, como pareces estar de acuerdo, probablemente no puedas hacer esto elegantemente en Raphael.
Sin embargo , si, por un golpe de %deity%
no necesita soportar IE para esta característica en particular, podría renunciar a la API de Raphael y manipular el SVG directamente . Entonces, tal vez, podría aparejar una mask para andar a lo largo del camino y revelar la línea a un ritmo natural.
Podrías degradar con gracia en IE para simplemente mostrar la ruta usando Raphael, sin animación.
Eureka! (Tal vez, suponiendo que te sientas cómodo saliendo del ámbito amistoso de Raphael en tierra SVG pura ...)
Puede utilizar los tiempos clave de SVG y las líneas clave .
Aquí hay un ejemplo de trabajo:
http://www.carto.net/svg/samples/animated_bustrack.shtml
... y aquí hay una explicación potencialmente útil:
http://msdn.microsoft.com/en-us/library/ms533119(v=vs.85).aspx
La solución de Anton & Peteorpeter lamentablemente se descompone en Chrome cuando los caminos se complican. Está bien para el mapa de autobuses en esa demostración vinculada. Mira este animado jsfiddle de "pétalos de flores" que he creado, que se dibuja correctamente en FF10 y Safari5, pero parpadea de forma incontrolable en Chrome:
(Esto es todo HTML y SVG en línea, no hay javascript).
Todavía estoy buscando una solución que no sea Flash para esto. AnimateAlong obviamente no lo cortará por lo que estoy haciendo. Raphael.js podría funcionar, aunque amenaza con convertirse rápidamente en spaghetti de devolución de llamada.
Davidenke, ¿puedes publicar un jsfiddle de trabajo con tu solución? Simplemente no puedo hacer que funcione. Recibo un error en Chrome 18 de que los nodos que están configurados para "mostrar: ninguno" con su ".hide" no tienen el método ''getTotalLength''.
Me gustaría ofrecer una solución alternativa, solo de Raphael + JS, que he utilizado en gran medida en mi propio trabajo. Tiene varias ventajas sobre la solución de davidenke:
- No borra el papel con cada ciclo, permitiendo que el camino animado coexista bien con otros elementos;
- Reutiliza una única ruta con la propia animación progresiva de Raphael, lo que facilita las animaciones;
- Sustancialmente menos intensivo en recursos.
Este es el método (que podría ser fácilmente rediseñado en una extensión):
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;
}
Y aquí hay dos ejemplos de su uso en mi sitio: uno para Path Transformation y el otro para Progressive Lettering .
Solo una actualización de esto, podrías probar Lazy Line Painter
Tal vez alguien está buscando una respuesta, como yo por dos días:
// 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);
}
});
Eso hizo el truco para mí, solo mediante el uso de métodos de RaphaelJS.
Aquí hay un ejemplo jsFiddle como se solicita en los comentarios, http://jsfiddle.net/eA8bj/
Usando el atributo " pathLength " podemos establecer la longitud virtual de la ruta. A partir de entonces podemos usar esta longitud virtual en "stroke-dasharray". Entonces, si establecemos "pathLength" en 100 unidades, podemos establecer "stroke-dasharray" en "50,50", que será exactamente el 50%, ¡el 50% de la ruta!
Hay un problema con este enfoque: el único navegador que admite este atributo es Opera 11.
Here hay un ejemplo de animación de drawable de curva suave sin javascript o longitud codificada. (Funciona correctamente solo en Opera 11)
solo estaba haciendo exactamente esto. Lo primero que probé fue la solución de Anton, pero el rendimiento apesta.
Al final, la forma más fácil de obtener el resultado que quería era usar la sintaxis alternativa de "fotograma clave" para la función animada.
dibuje la ruta final de forma invisible, luego genere un conjunto completo de marcos clave utilizando getSubpath en un bucle.
crea una nueva ruta que sea visible e iguale al primer fotograma clave.
luego haz algo como:
path.animate ({keyFrameObject, timeframe});
no debería necesitar un fotograma clave para cada píxel que desea dibujar. Después de jugar con los parámetros, encontré que un valor de 100 píxeles por fotograma clave funcionaba para la complejidad / tamaño de lo que estaba tratando de "dibujar"
dasharray/dashoffset
un script para esto: Scribble.js , basado en esta gran técnica de dasharray/dashoffset
.
Solo ejemplifícalo con un montón de SVG <path>
s:
var scribble = new Scribble(paths, {duration: 3000});
scribble.erase();
scribble.draw(function () {
// done
});
-
NB: Código de USAGE
completo aquí: https://gist.github.com/abernier/e082a201b0865de1a41f#file-index-html-L31
Disfrutar;)