html5 canvas - анимация объекта по пути - PullRequest
18 голосов
/ 14 февраля 2012

Я немного новичок в Canvas, и простите, если это тривиальный вопрос.

Я бы хотел иметь возможность анимировать объект по пути (определенному как путь Безье), но я не уверен, как это сделать.

Я смотрел на Рафаэля, но не могу понять, как идти по пути со временем.

Cake JS выглядел многообещающе в демоверсии, но я действительно борюсь с документацией, или с ее отсутствием в этом случае.

Кто-нибудь получил какой-нибудь рабочий пример этого?

Ответы [ 3 ]

20 голосов
/ 14 февраля 2012

Используйте код на моем веб-сайте из этот связанный вопрос , но вместо изменения .style.left и т. Д. В обратном вызове сотрите и заново нарисуйте холст с элементомв новом месте (и, возможно, при вращении).

Обратите внимание, что это использует SVG для внутренней интерполяции точек вдоль кривой Безье, но вы можете использовать точки, которые вам дают, для чего угодно (включая рисование на холсте).

Если мой сайт не работает, вот текущий снимок библиотеки:

function CurveAnimator(from,to,c1,c2){
  this.path = document.createElementNS('http://www.w3.org/2000/svg','path');
  if (!c1) c1 = from;
  if (!c2) c2 = to;
  this.path.setAttribute('d','M'+from.join(',')+'C'+c1.join(',')+' '+c2.join(',')+' '+to.join(','));
  this.updatePath();
  CurveAnimator.lastCreated = this;
}
CurveAnimator.prototype.animate = function(duration,callback,delay){
  var curveAnim = this;
  // TODO: Use requestAnimationFrame if a delay isn't passed
  if (!delay) delay = 1/40;
  clearInterval(curveAnim.animTimer);
  var startTime = new Date;
  curveAnim.animTimer = setInterval(function(){
    var now = new Date;
    var elapsed = (now-startTime)/1000;
    var percent = elapsed/duration;
    if (percent>=1){
      percent = 1;
      clearInterval(curveAnim.animTimer);
    }
    var p1 = curveAnim.pointAt(percent-0.01),
        p2 = curveAnim.pointAt(percent+0.01);
    callback(curveAnim.pointAt(percent),Math.atan2(p2.y-p1.y,p2.x-p1.x)*180/Math.PI);
  },delay*1000);
};
CurveAnimator.prototype.stop = function(){
  clearInterval(this.animTimer);
};
CurveAnimator.prototype.pointAt = function(percent){
  return this.path.getPointAtLength(this.len*percent);
};
CurveAnimator.prototype.updatePath = function(){
  this.len = this.path.getTotalLength();
};
CurveAnimator.prototype.setStart = function(x,y){
  var M = this.path.pathSegList.getItem(0);
  M.x = x; M.y = y;
  this.updatePath();
  return this;
};
CurveAnimator.prototype.setEnd = function(x,y){
  var C = this.path.pathSegList.getItem(1);
  C.x = x; C.y = y;
  this.updatePath();
  return this;
};
CurveAnimator.prototype.setStartDirection = function(x,y){
  var C = this.path.pathSegList.getItem(1);
  C.x1 = x; C.y1 = y;
  this.updatePath();
  return this;
};
CurveAnimator.prototype.setEndDirection = function(x,y){
  var C = this.path.pathSegList.getItem(1);
  C.x2 = x; C.y2 = y;
  this.updatePath();
  return this;
};

… и вот как вы можете его использовать:

var ctx = document.querySelector('canvas').getContext('2d');
ctx.fillStyle = 'red';

var curve = new CurveAnimator([50, 300], [350, 300], [445, 39], [1, 106]);

curve.animate(5, function(point, angle) {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.fillRect(point.x-10, point.y-10, 20, 20);
});​

В действии: http://jsfiddle.net/Z2YSt/

8 голосов
/ 15 февраля 2013

Итак, вот подробная версия:

t - любое число от 0 до 1, представляющее время ; p0, p1, p2, p3 объекты start точка, 1-й элемент управления точка, 2-й элемент управления точка и конечная точка соответственно:

var at = 1 - t;
var green1x = p0.x * t + p1.x * at;
var green1y = p0.y * t + p1.y * at;
var green2x = p1.x * t + p2.x * at;
var green2y = p1.y * t + p2.y * at;
var green3x = p2.x * t + p3.x * at;
var green3y = p2.y * t + p3.y * at;
var blue1x = green1x * t + green2x * at;
var blue1y = green1y * t + green2y * at;
var blue2x = green2x * t + green3x * at;
var blue2y = green2y * t + green3y * at;
var finalx = blue1x * t + blue2x * at;
var finaly = blue1y * t + blue2y * at;

Вот шар , использующий по пути в JSfiddle

Имена переменных взяты из этого рисунка, который является лучшим объяснением для кривых Безье: http://en.wikipedia.org/wiki/File:Bezier_3_big.gif

Короткая версия кода внутри функции, готовой для копирования / вставки:

var calcBezierPoint = function (t, p0, p1, p2, p3) {
    var data = [p0, p1, p2, p3];
    var at = 1 - t;
    for (var i = 1; i < data.length; i++) {
        for (var k = 0; k < data.length - i; k++) {
            data[k] = {
                x: data[k].x * at + data[k + 1].x * t,
                y: data[k].y * at + data[k + 1].y * t
            };
        }
    }
    return data[0];
};



Похожие материалы:

1 голос
/ 14 февраля 2012

Я бы не использовал Canvas для этого, если бы вам не пришлось. В SVG встроена анимация по пути. Для работы Canvas требуется немало математики.

Вот один из примеров анимации SVG вдоль пути .

Вот несколько рассуждений об этом для Рафаэля: SVG анимация по пути с Рафаэлем

Обратите внимание, что Рафаэль использует SVG и не HTML5 Canvas.


Один из способов анимирования по безье-траектории в Canvas - это непрерывное деление пополам кривой Безье, записывая средние точки до тех пор, пока у вас не будет много точек (скажем, 50 точек на кривую), которые вы можете анимировать для объекта вдоль этого списка точек. , Ищите разбивающие Безье и подобные запросы для соответствующей математики на этом.

...