una transiciones sirven salida que power poner para movimiento las imagen efectos diapositiva darle como animaciĆ³n animaciones animacion javascript jquery canvas html5-canvas

javascript - transiciones - para que sirven las animaciones en power point



Quiero hacer animaciĆ³n de un objeto a lo largo de un camino particular (2)

Tengo que mover el pequeño rectángulo en el camino. El rectángulo se mueve después de un clic dentro del lienzo.

No puedo animarlo ya que el objeto simplemente salta al punto requerido.

Encuentra el código en Fiddle .

HTML

<canvas id="myCanvas" width=578 height=200></canvas>

CSS

#myCanvas { width:578px; height:200px; border:2px thin; }

JavaScript

var myRectangle = { x: 100, y: 20, width: 25, height: 10, borderWidth: 1 }; $(document).ready(function () { $(''#myCanvas'').css("border", "2px solid black"); var canvas = document.getElementById(''myCanvas''); var context = canvas.getContext(''2d''); var cntxt = canvas.getContext(''2d''); drawPath(context); drawRect(myRectangle, cntxt); $(''#myCanvas'').click(function () { function animate(myRectangle, canvas, cntxt, startTime) { var time = (new Date()).getTime() - startTime; var linearSpeed = 10; var newX = Math.round(Math.sqrt((100 * 100) + (160 * 160))); if (newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) { myRectangle.x = newX; } context.clearRect(0, 0, canvas.width, canvas.height); drawPath(context); drawRect(myRectangle, cntxt); // request new frame requestAnimFrame(function () { animate(myRectangle, canvas, cntxt, startTime); }); } drawRect(myRectangle, cntxt); myRectangle.x = 100; myRectangle.y = 121; setTimeout(function () { var startTime = (new Date()).getTime(); animate(myRectangle, canvas, cntxt, startTime); }, 1000); }); }); $(document).keypress(function (e) { if (e.which == 13) { $(''#myCanvas'').click(); } }); function drawRect(myRectangle, cntxt) { cntxt.beginPath(); cntxt.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height); cntxt.fillStyle = ''cyan''; cntxt.fill(); cntxt.strokeStyle = ''black''; cntxt.stroke(); }; function drawPath(context) { context.beginPath(); context.moveTo(100, 20); // line 1 context.lineTo(200, 160); // quadratic curve context.quadraticCurveTo(230, 200, 250, 120); // bezier curve context.bezierCurveTo(290, -40, 300, 200, 400, 150); // line 2 context.lineTo(500, 90); context.lineWidth = 5; context.strokeStyle = ''blue''; context.stroke(); };


Si vas a utilizar las curvas de Bezier incorporadas en el lienzo, igual deberías hacer las matemáticas tú mismo.

Puede utilizar esta implementación de una spline cardinal y tener todos los puntos devueltos precalculados.

Un ejemplo de uso es esta pequeña salchicha-móvil moviéndose a lo largo de la pendiente (generada con la spline cardinal anterior):

Demostración completa aquí (copia y copia como desee).

Lo principal que necesita es cuando tiene la matriz de puntos para encontrar dos puntos que desea usar para el objeto. Esto nos dará el ángulo del objeto:

cPoints = quantX(pointsFromCardinalSpline); //see below //get points from array (dx = current array position) x1 = cPoints[dx]; y1 = cPoints[dx + 1]; //get end-points from array (dlt=length, must be an even number) x2 = cPoints[dx + dlt]; y2 = cPoints[dx + dlt + 1];

Para evitar el estiramiento en pendientes más pronunciadas, recalculamos la longitud según el ángulo. Para obtener un ángulo aproximado usamos el punto final original para obtener un ángulo, luego calculamos una nueva longitud de la línea basada en la longitud deseada y este ángulo:

var dg = getLineAngle(x1, y1, x2, y2); var l = ((((lineToAngle(x1, y2, dlt, dg).x - x1) / 2) |0) * 2); x2 = cPoints[dx + l]; y2 = cPoints[dx + l + 1];

Ahora podemos trazar el "automóvil" a lo largo de la pendiente restando su altura vertical de las posiciones y.

Lo que notará al hacer esto es que el "automóvil" se mueve a velocidad variable. Esto se debe a la interpolación de la spline cardinal.

Podemos suavizarlo para que la velocidad se vea más uniforme al cuantizar el eje x. Todavía no será perfecto, ya que en pendientes pronunciadas, la distancia y entre puntos será mayor que en una superficie plana; realmente necesitaríamos una cuantización cuadrática, pero para este propósito solo hacemos el eje x.

Esto nos da una nueva matriz con nuevos puntos para cada posición x:

function quantX(pts) { var min = 99999999, max = -99999999, x, y, i, p = pts.length, res = []; //find min and max of x axis for (i = 0; i < pts.length - 1; i += 2) { if (pts[i] > max) max = pts[i]; if (pts[i] < min) min = pts[i]; } max = max - min; //this will quantize non-existng points function _getY(x) { var t = p, ptX1, ptX2, ptY1, ptY2, f, y; for (; t >= 0; t -= 2) { ptX1 = pts[t]; ptY1 = pts[t + 1]; if (x >= ptX1) { //p = t + 2; ptX2 = pts[t + 2]; ptY2 = pts[t + 3]; f = (ptY2 - ptY1) / (ptX2 - ptX1); y = (ptX1 - x) * f; return ptY1 - y; } } } //generate new array per-pixel on the x-axis //note: will not work if curve suddenly goes backwards for (i = 0; i < max; i++) { res.push(i); res.push(_getY(i)); } return res; }

Las otras dos funciones que necesitamos es la que calcula el ángulo de una línea y la que calcula los puntos finales en función del ángulo y la longitud:

function getLineAngle(x1, y1, x2, y2) { var dx = x2 - x1, dy = y2 - y1, th = Math.atan2(dy, dx); return th * 180 / Math.PI; } function lineToAngle(x1, y1, length, angle) { angle *= Math.PI / 180; var x2 = x1 + length * Math.cos(angle), y2 = y1 + length * Math.sin(angle); return {x: x2, y: y2}; }


Aquí se muestra cómo mover un objeto a lo largo de un camino particular

La animación implica movimiento a lo largo del tiempo. Por lo tanto, para cada "cuadro" de su animación necesita saber la coordenada XY donde dibujar su objeto en movimiento (rectángulo).

Este código toma un porcentaje completo (0.00 a 1.00) y devuelve la coordenada XY, que es ese porcentaje a lo largo del segmento de ruta. Por ejemplo:

  • 0.00 devolverá el XY al comienzo de la línea (o curva).
  • 0.50 devolverá el XY en el medio de la línea (o curva).
  • 1.00 devolverá el XY al final de la línea (o curva).

Aquí está el código para obtener el XY en el porcentaje especificado a lo largo de una línea:

// line: percent is 0-1 function getLineXYatPercent(startPt,endPt,percent) { var dx = endPt.x-startPt.x; var dy = endPt.y-startPt.y; var X = startPt.x + dx*percent; var Y = startPt.y + dy*percent; return( {x:X,y:Y} ); }

Aquí está el código para obtener el XY en el porcentaje especificado a lo largo de una curva de bezier cuadrática:

// quadratic bezier: percent is 0-1 function getQuadraticBezierXYatPercent(startPt,controlPt,endPt,percent) { var x = Math.pow(1-percent,2) * startPt.x + 2 * (1-percent) * percent * controlPt.x + Math.pow(percent,2) * endPt.x; var y = Math.pow(1-percent,2) * startPt.y + 2 * (1-percent) * percent * controlPt.y + Math.pow(percent,2) * endPt.y; return( {x:x,y:y} ); }

Aquí está el código para obtener el XY en el porcentaje especificado a lo largo de una curva de bezier cúbica:

// cubic bezier percent is 0-1 function getCubicBezierXYatPercent(startPt,controlPt1,controlPt2,endPt,percent){ var x=CubicN(percent,startPt.x,controlPt1.x,controlPt2.x,endPt.x); var y=CubicN(percent,startPt.y,controlPt1.y,controlPt2.y,endPt.y); return({x:x,y:y}); } // cubic helper formula at percent distance function CubicN(pct, a,b,c,d) { var t2 = pct * pct; var t3 = t2 * pct; return a + (-a * 3 + pct * (3 * a - a * pct)) * pct + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct + (c * 3 - c * 3 * pct) * t2 + d * t3; }

Y así es como lo combinas para animar los diversos segmentos de tu camino

// calculate the XY where the tracking will be drawn if(pathPercent<25){ var line1percent=pathPercent/24; xy=getLineXYatPercent({x:100,y:20},{x:200,y:160},line1percent); } else if(pathPercent<50){ var quadPercent=(pathPercent-25)/24 xy=getQuadraticBezierXYatPercent({x:200,y:160},{x:230,y:200},{x:250,y:120},quadPercent); } else if(pathPercent<75){ var cubicPercent=(pathPercent-50)/24 xy=getCubicBezierXYatPercent({x:250,y:120},{x:290,y:-40},{x:300,y:200},{x:400,y:150},cubicPercent); } else { var line2percent=(pathPercent-75)/25 xy=getLineXYatPercent({x:400,y:150},{x:500,y:90},line2percent); } // draw the tracking rectangle drawRect(xy);

Aquí está el código de trabajo y un Fiddle: http://jsfiddle.net/m1erickson/LumMX/

<!doctype html> <html lang="en"> <head> <style> body{ background-color: ivory; } canvas{border:1px solid red;} </style> <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" /> <script src="http://code.jquery.com/jquery-1.9.1.js"></script> <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script> <script> $(function() { var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); // set starting values var fps = 60; var percent=0 var direction=1; // start the animation animate(); function animate() { // set the animation position (0-100) percent+=direction; if(percent<0){ percent=0; direction=1; }; if(percent>100){ percent=100; direction=-1; }; draw(percent); // request another frame setTimeout(function() { requestAnimationFrame(animate); }, 1000 / fps); } // draw the current frame based on sliderValue function draw(sliderValue){ // redraw path ctx.clearRect(0,0,canvas.width,canvas.height); ctx.lineWidth = 5; ctx.beginPath(); ctx.moveTo(100, 20); ctx.lineTo(200, 160); ctx.strokeStyle = ''red''; ctx.stroke(); ctx.beginPath(); ctx.moveTo(200, 160); ctx.quadraticCurveTo(230, 200, 250, 120); ctx.strokeStyle = ''green''; ctx.stroke(); ctx.beginPath(); ctx.moveTo(250,120); ctx.bezierCurveTo(290, -40, 300, 200, 400, 150); ctx.strokeStyle = ''blue''; ctx.stroke(); ctx.beginPath(); ctx.moveTo(400, 150); ctx.lineTo(500, 90); ctx.strokeStyle = ''gold''; ctx.stroke(); // draw the tracking rectangle var xy; if(sliderValue<25){ var percent=sliderValue/24; xy=getLineXYatPercent({x:100,y:20},{x:200,y:160},percent); } else if(sliderValue<50){ var percent=(sliderValue-25)/24 xy=getQuadraticBezierXYatPercent({x:200,y:160},{x:230,y:200},{x:250,y:120},percent); } else if(sliderValue<75){ var percent=(sliderValue-50)/24 xy=getCubicBezierXYatPercent({x:250,y:120},{x:290,y:-40},{x:300,y:200},{x:400,y:150},percent); } else { var percent=(sliderValue-75)/25 xy=getLineXYatPercent({x:400,y:150},{x:500,y:90},percent); } drawRect(xy,"red"); } // draw tracking rect at xy function drawRect(point,color){ ctx.fillStyle="cyan"; ctx.strokeStyle="gray"; ctx.lineWidth=3; ctx.beginPath(); ctx.rect(point.x-13,point.y-8,25,15); ctx.fill(); ctx.stroke(); } // draw tracking dot at xy function drawDot(point,color){ ctx.fillStyle=color; ctx.strokeStyle="black"; ctx.lineWidth=3; ctx.beginPath(); ctx.arc(point.x,point.y,8,0,Math.PI*2,false); ctx.closePath(); ctx.fill(); ctx.stroke(); } // line: percent is 0-1 function getLineXYatPercent(startPt,endPt,percent) { var dx = endPt.x-startPt.x; var dy = endPt.y-startPt.y; var X = startPt.x + dx*percent; var Y = startPt.y + dy*percent; return( {x:X,y:Y} ); } // quadratic bezier: percent is 0-1 function getQuadraticBezierXYatPercent(startPt,controlPt,endPt,percent) { var x = Math.pow(1-percent,2) * startPt.x + 2 * (1-percent) * percent * controlPt.x + Math.pow(percent,2) * endPt.x; var y = Math.pow(1-percent,2) * startPt.y + 2 * (1-percent) * percent * controlPt.y + Math.pow(percent,2) * endPt.y; return( {x:x,y:y} ); } // cubic bezier percent is 0-1 function getCubicBezierXYatPercent(startPt,controlPt1,controlPt2,endPt,percent){ var x=CubicN(percent,startPt.x,controlPt1.x,controlPt2.x,endPt.x); var y=CubicN(percent,startPt.y,controlPt1.y,controlPt2.y,endPt.y); return({x:x,y:y}); } // cubic helper formula at percent distance function CubicN(pct, a,b,c,d) { var t2 = pct * pct; var t3 = t2 * pct; return a + (-a * 3 + pct * (3 * a - a * pct)) * pct + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct + (c * 3 - c * 3 * pct) * t2 + d * t3; } }); // end $(function(){}); </script> </head> <body> <canvas id="canvas" width=600 height=300></canvas> </body> </html>