как оптимизировать анимацию snap svg

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

  1. есть хороший пример обнаружения близости в оснастке
  2. есть дополнительная информация об оптимизации анимации в snap svg. Это было нелегко найти.

Вот рабочий пример анимации:

http://jsfiddle.net/heaversm/sbj4W/1/

и вот что, как я считаю, можно оптимизировать:


Каждый круг вызывает свою собственную функцию анимации — все круги были добавлены в группу, и я предполагаю, что есть способ применить случайное движение ко всем членам группы, который более эффективен, чем вызов функции для каждого элемента. внутри группы.

for (var i=0; i<this.drawingConfig.circles.amount;i++){
  ...
  this.animateSingle(circleShape);
}

Функция близости неудобна — для каждого круга, для каждого цикла обновления мне приходится перебирать массив всех остальных кругов и выяснять, достаточно ли близки координаты X и Y, чтобы провести линию. Кроме того, это означает, что вы получаете повторяющиеся линии, потому что каждый круг будет рисовать линию к своим соседям, вместо того, чтобы иметь одну общую линию между ними.

for (var i=0;i<circles.length;i++){
  var nextCircle = circles[i].node;
  var nextCircleX = nextCircle.cx.baseVal.value;
  var distance = Math.abs(nextCircleX-thisCircleX);
  var proximity = mainModule.drawingConfig.circles.proximity;
  if (distance < proximity){

    var nextCircleY = nextCircle.cy.baseVal.value;
    var thisCircleY = shape.node.cy.baseVal.value;
    var distanceY = Math.abs(nextCircleY - thisCircleY);
    if (distanceY < proximity){

      var line = mainModule.s.line(thisCircleX, thisCircleY, nextCircleX, nextCircleY).attr({stroke: '#a6a8ab', strokeWidth: '1px'});
      mainModule.drawingConfig.circles.circleGroup.add(line);
    }
  }
}

Соответственно, функция анимации каждого круга очищает все линии на экране. В идеале все круги должны использовать одну функцию обновления, и в этой функции вы должны очищать линии.

Snap.animate(startX, animX, function (val) {

  var lines = Snap.selectAll('line');
  lines.remove();

  ...

}, mainModule.drawingConfig.circles.animTime);

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


person mheavers    schedule 03.06.2014    source источник
comment
Вы можете попробовать сжать его. Кроме этого, я думаю, вам следует попробовать CodeReview...   -  person Zach Saucier    schedule 04.06.2014
comment
Я никогда не слышал о проверке кода - спасибо, Зак.   -  person mheavers    schedule 04.06.2014


Ответы (1)


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

http://jsfiddle.net/heaversm/fJ6fj/

    var mainModule = {
  s: Snap("#svg"),
  drawingConfig: {
    circles: {
      amount: 20,
      sizeMin: 10,
      sizeMax: 20,
      proximity: 100,
      circleGroup: null,
      circleArray: [],
      animTime: 2000
    },
    canvas: {
      width: 800,
      height: 600
    }
  },

  init: function(){
    //this.sizeCanvas();
    this.makeCircles();
  },

  sizeCanvas: function(){
    $('#svg').width(800).height(600);
  },

  makeCircles: function(){
    this.drawingConfig.circles.circleGroup = this.s.g();

    for (var i=0; i<this.drawingConfig.circles.amount;i++){
      var circleX = this.randomNumber(0, this.drawingConfig.canvas.width);
      var circleY = this.randomNumber(0, this.drawingConfig.canvas.height);
      var circleRadius = this.randomNumber(this.drawingConfig.circles.sizeMin,this.drawingConfig.circles.sizeMax);
      var circleFill = '#'+Math.floor(Math.random()*16777215).toString(16);
      var circleShape = this.s.circle(circleX, circleY, circleRadius);
      circleShape.attr({
        fill: circleFill
      });
      this.drawingConfig.circles.circleGroup.add(circleShape);

      var circleIncline = this.setIncline();
      var circleObj = { incline: circleIncline, shape: circleShape };

      this.drawingConfig.circles.circleArray.push(circleObj);

    }

    this.update();


  },

  setIncline: function(){
    return { incX: this.randomNumber(-5,5), incY: this.randomNumber(-5,5) }
  },

  update: function(){

    var lines = Snap.selectAll('line');
    lines.remove();

    for (var i=0; i<this.drawingConfig.circles.amount; i++){
      var circle = this.drawingConfig.circles.circleArray[i];
      var circleX = circle.shape.node.cx.animVal.value;
      var circleY = circle.shape.node.cy.animVal.value;
      this.move(circle,circleX,circleY);

      for (var j=0;j<i;j++){
        if (i != j){
          var circle2 = this.drawingConfig.circles.circleArray[j];
          var circle2X = circle2.shape.node.cx.animVal.value;
          var circle2Y = circle2.shape.node.cy.animVal.value;
          var dist = mainModule.distance(circleX,circleY,circle2X,circle2Y);
          if (dist <= mainModule.drawingConfig.circles.proximity){ //
            var lineWeight = 10/dist;
            var line = mainModule.s.line(circleX, circleY, circle2X, circle2Y).attr({stroke: '#a6a8ab', strokeWidth: '1px'});
          }

          if (dist <= 10) { //collision
            circle.incline = mainModule.setIncline();
            circle2.incline = mainModule.setIncline();
          }

        }
      }

    }

    setTimeout(function(){ mainModule.update(); },10);

  },

  distance: function(circleX,circleY,circle2X,circle2Y){
    var distX = circle2X - circleX;
    var distY = circle2Y - circleY;
    distX = distX*distX;
    distY = distY*distY;
    return Math.sqrt(distX + distY);
  },

  move: function(circle,curX,curY){
    if (curX > this.drawingConfig.canvas.width || curX < 0) {
      circle.incline.incX = -circle.incline.incX;
    }
    if (curY > this.drawingConfig.canvas.height || curY < 0) {
      circle.incline.incY = -circle.incline.incY;
    }
    curX = curX + circle.incline.incX;
    curY = curY + circle.incline.incY;

    if (curX > this.drawingConfig.canvas.width) {
      curX = this.drawingConfig.canvas.width;
      circle.incline = this.setIncline();
    } else if (curX < 0) {
      curX = 0;
      circle.incline = this.setIncline();
    }

    if (curY > this.drawingConfig.canvas.height) {
      curY = this.drawingConfig.canvas.height;
      circle.incline = this.setIncline();
    } else if (curY < 0) {
      curY = 0;
      circle.incline = this.setIncline();
    }

    circle.shape.attr({ cx: curX, cy: curY });

  },

  randomNumber: function(min,max){
    return Math.floor(Math.random()*(max-min+1)+min);
  },

  getBounds: function(shape){
    shapeBox = shape.node.getBoundingClientRect();
  }

}

mainModule.init();
person mheavers    schedule 05.06.2014