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

Html5 canvas - анимация объекта по пути

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

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

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

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

У кого-нибудь есть рабочий пример?

4b9b3361

Ответ 1

Используйте код на моем веб-сайте из этого связанного вопроса, но вместо этого изменения .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/

Ответ 2

Итак, вот вербальная версия:

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

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

Имена переменных взяты из этого gif, который является лучшим объяснением для кривых Безье: 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];
};



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

Ответ 3

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

Вот один пример анимации SVG по пути.

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

Обратите внимание, что Raphael использует SVG и не холст HTML5.


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