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

Сделать слова пульсирующими и изменить место случайным образом

Я делаю этот плагин, который принимает слова и заставляет их пульсировать на экране:

Сначала они появляются и растут, затем исчезают, меняются местами и снова появляются

Рабочий плагин:

+ function($) {

  var Pulsate = function(element) {
    var self = this;
    
    self.element = element;
    self.max = 70;
    self.min = 0;
    self.speed = 500;
    self.first = true;
    self.currentPlace;
    self.possiblePlaces = [
      {
        id: 0,
        top: 150,
        left: 150,
      },
      {
        id: 1,
        top: 250,
        left: 250,
      },
      {
        id: 2,
        top: 350,
        left: 350,
      },
      {
        id: 3,
        top: 250,
        left: 750,
      },
      {
        id: 4,
        top: 450,
        left: 950,
      }
    ];
    
  };
  
  Pulsate.prototype.defineRandomPlace = function() {
    var self = this;
    self.currentPlace = self.possiblePlaces[Math.floor(Math.random() * self.possiblePlaces.length)];
    
    if(!self.possiblePlaces) self.defineRandomPlace;
    
    
    
    self.element.css('top', self.currentPlace.top + 'px');
    self.element.css('left', self.currentPlace.left + 'px');
  };
  
  Pulsate.prototype.animateToZero = function() {
    var self = this;
    
    self.element.animate({
      'fontSize': 0,
      'queue': true
    }, self.speed, function() {
      self.defineRandomPlace();
    });
    
  };
  
  Pulsate.prototype.animateToRandomNumber = function() {
    var self = this;
    
    self.element.animate({
      'fontSize': Math.floor(Math.random() * (70 - 50 + 1) + 50),
      'queue': true
    }, self.speed, function() {
      self.first = false;
      self.start();
    });
  };
  
  Pulsate.prototype.start = function() {
    var self = this;
    
    if (self.first) self.defineRandomPlace();
    if (!self.first) self.animateToZero();
    
    self.animateToRandomNumber();
  };


  $(window).on('load', function() {
    $('[data-pulsate]').each(function() {
      var element = $(this).data('pulsate') || false;
      
      if (element) {
        element = new Pulsate($(this));
        element.start();
      }

    });

  });

}(jQuery);
body {
  background: black;
  color: white;
}

.word {
  position: absolute;
  text-shadow: 0 0 5px rgba(255, 255, 255, 0.9);
  font-size: 0px;
}


.two {
  position: absolute;
  color: white;
  left: 50px;
  top: 50px;
}
div {
  margin-left: 0px;
}
<span class="word" data-pulsate="true">Love</span>
<span class="word" data-pulsate="true">Enjoy</span>
<span class="word" data-pulsate="true">Huggs</span>





<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
4b9b3361

Ответ 1

Мое решение состоит в том, чтобы разделить страницу на воображаемые строки и запретить более одного слова в одной строке. Пожалуйста, проверьте это.

Примечание: поскольку в настоящее время код не поддерживает пересчет строк при изменении размера документа, полное представление страницы не будет отображаться правильно. Нажмите "перезагрузить фрейм" или попробуйте JSFiddle или smth.

var pulsar = {
  // Delay between words appearance
  delay: 400,
  // Word animation do not really depend on pulsar.delay,
  // but if you set pulsar.delay small and wordAnimationDuration long
  // some words will skip their turns. Try 1, 2, 3...
  wordAnimationDuration: 400 * 3,
  // Depending on maximum font size of words we calculate the number of rows
  // to which the window can be divided
  maxFontSize: 40,
  start: function () {
    this.computeRows();
    this.fillWords();
    this.animate();
  },
  // Calculate the height or row and store each row properties in pulsar.rows
  computeRows: function () {
    var height = document.body.parentNode.clientHeight;
    var rowsCount = Math.floor(height/this.maxFontSize);
    this.rows = [];
    for (var i = 0; i < rowsCount; i++) {
      this.rows.push({
        index: i,
        isBusy: false
      });   
    }
  },
  // Store Word instances in pulsar.words
  fillWords: function () {
    this.words = [];
    var words = document.querySelectorAll('[data-pulsate="true"]');
    for (var i = 0; i < words.length; i++) {
      this.words.push(new Word(words[i], this.wordAnimationDuration, this.maxFontSize));
    }
  },
  // When it comes time to  animate another word we need to know which row to move it in
  // this random row should be empty at the moment
  getAnyEmptyRowIndex: function () {
    var emptyRows = this.rows.filter(function(row) {
      return !row.isBusy;
    });
    if (emptyRows.length == 0) {
      return -1;
    }
    var index = emptyRows[Math.floor(Math.random() * emptyRows.length)].index;
    this.rows[index].isBusy = true;
    return index;
  },
  // Here we manipulate words in order of pulsar.words array
  animate: function () {
    var self = this;
    this.interval = setInterval(function() {
      var ri = self.getAnyEmptyRowIndex();
      if (ri >= 0) {
        self.words.push(self.words.shift());
        self.words[0].animate(ri, function () {
          self.rows[ri].isBusy = false;
        });
      }
    }, this.delay);
  }
}

function Word (span, duration, maxFontSize) {
  this.span = span;
  this.inAction = false;
  this.duration = duration;
  this.maxFontSize = maxFontSize;
}

/** 
  * @row {Numer} is a number of imaginary row to place the word into
  * @callback {Function} to call on animation end
  */
Word.prototype.animate = function (row, callback) {
  var self = this;
  // Skip turn if the word is still busy in previous animation
  if (self.inAction) {
    return;   
  }
  var start = null,
      dur = self.duration,
      mfs = self.maxFontSize,
      top = row * mfs,
      // Random left offset (in %)
      left = Math.floor(Math.random() * 90),
      // Vary then font size within half-max size and max size
      fs = mfs - Math.floor(Math.random() * mfs / 2);

  self.inAction = true;
  self.span.style.top = top + 'px';
  self.span.style.left = left + '%';

  function step (timestamp) {
    if (!start) start = timestamp;
    var progress = timestamp - start;
    // Calculate the factor that will change from 0 to 1, then from 1 to 0 during the animation process
    var factor = 1 - Math.sqrt(Math.pow(2 * Math.min(progress, dur) / dur - 1, 2));
    self.span.style.fontSize = fs * factor + 'px';
    if (progress < dur) {
      window.requestAnimationFrame(step);
    }
    else {
      self.inAction = false;
      callback();
    }
  }
  window.requestAnimationFrame(step);
}

pulsar.start();
body {
    background: black;
    color: white;
}

.word {
    position: absolute;
    text-shadow: 0 0 5px rgba(255, 255, 255, 0.9);
    font-size: 0px;
    /* To make height of the .word to equal it font size */
    line-height: 1;
}
<span class="word" data-pulsate="true">Love</span>
<span class="word" data-pulsate="true">Enjoy</span>
<span class="word" data-pulsate="true">Huggs</span>
<span class="word" data-pulsate="true">Peace</span>

Ответ 2

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

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

  • Разделите тот же список possiblePlaces между всеми экземплярами.
  • Сдвиньте первый элемент из очереди и нажмите его на конец, когда он будет сделан каждый раз, вместо случайного выбора в defineRandomPlace.

Фрагмент выделения # 2:

// shift a position off the front
self.currentPlace = possiblePlaces.shift();

self.element.css('top', self.currentPlace.top + 'px');
self.element.css('left', self.currentPlace.left + 'px');

// push it back on the end
possiblePlaces.push(self.currentPlace);

Если вы хотите, чтобы это было действительно случайным, вам нужно случайным образом выбрать и удалить элемент из массива, а не возвращать его в массив до тех пор, пока он не будет использован. Вам также необходимо всегда гарантировать, что у вас больше possiblePlaces, чем у вас есть элементы dom для размещения на странице.

Так же:

Pulsate.prototype.defineRandomPlace = function() {
  var self = this;
  var newPlace = possiblePlaces.splice(Math.floor(Math.random()*possiblePlaces.length), 1)[0];

  if (self.currentPlace) {
    possiblePlaces.push(self.currentPlace);
  }

  self.currentPlace = newPlace;

  self.element.css('top', self.currentPlace.top + 'px');
  self.element.css('left', self.currentPlace.left + 'px');
};

См. http://codepen.io/anon/pen/bdBBPE

Ответ 3

Я обновил ваш конструктор плагинов. Обратите внимание на переменную Pulsate.possiblePlaces, я изменил объявление переменной таким образом, чтобы иметь возможность обмениваться переменными данными для всего экземпляра объекта вашего плагина.

var Pulsate = function(element) {
    var self = this;

    self.element = element;
    self.max = 70;
    self.min = 0;
    self.speed = 500;
    self.first = true;
    self.currentPlace;
    Pulsate.possiblePlaces = [
        {
            id: 0,
            top: 150,
            left: 150,
        },
        {
            id: 1,
            top: 250,
            left: 250,
        },
        {
            id: 2,
            top: 350,
            left: 350,
        },
        {
            id: 3,
            top: 250,
            left: 750,
        },
        {
            id: 4,
            top: 450,
            left: 950,
        }
    ];

};

Я добавил атрибут occupied в возможные места, чтобы идентифицировать те, которые уже заняты. Если случайный currentPlace уже занят, повторите поиск случайного места.

Pulsate.prototype.defineRandomPlace = function() {
    var self = this;
    self.currentPlace = Pulsate.possiblePlaces[Math.floor(Math.random() * Pulsate.possiblePlaces.length)];

    if(!Pulsate.possiblePlaces) self.defineRandomPlace;


    if (!self.currentPlace.occupied) {
        self.currentPlace.occupied = true;
        self.element.css('top', self.currentPlace.top + 'px');
        self.element.css('left', self.currentPlace.left + 'px');
    } else {
        self.defineRandomPlace();
    }
};

Каждый раз, когда элемент скрыт, установите для атрибута occupied значение false.

Pulsate.prototype.animateToZero = function() {
    var self = this;

    self.element.animate({
        'fontSize': 0,
        'queue': true
    }, self.speed, function() {
        self.currentPlace.occupied = false;
        self.defineRandomPlace();
    });

 };

Ответ 4

Небольшой намек f = 0,5px x = 100px t = 0,5s

x / f = 200
200/2 * t * 0.5 = f(shrink->expand until 100px square) per 0.5 seconds