Представьте, что у меня есть окно просмотра с определенной шириной и высотой.Я клонирую элемент, находящийся вне поля зрения с правой стороны, и пролетаю его через окно просмотра в случайном y
положении с кодом, подобным следующему:
...
.css({
'left': BASE_NODE_INIT_LEFT_PX,
'top' : rand(BASE_NODE_INIT_TOP_MIN_PX, BASE_NODE_INIT_TOP_MAX_PX) + 'px',
'width': _width + 'px',
'height': _height + 'px',
})
.animate({
left: BASE_NODE_ANIMATE_DISTANCE_X_PX
}
...
Достаточно простая анимация.Вот забавная часть: на каждом шаге я хотел бы применить некоторую физику к этому элементу.
Примерно так:
...
step:function(currentStep){
if($(this).data('animating-wind') !== true)
{
$(this).data('animating-wind',true);
var wind = (rand(1,2) == 2) ? '+=' + rand(1, 100) + 'px' : '-=' + rand(1, 100) + 'px';
$(this).animate({
'top': wind,
'text-indent': wind,
},{
duration: 500,
complete: function(){
$(this).data('animating-wind',false);
},
queue: false
});
}
}
...
В основном, вместо того, чтобы лететь прямо поперек справа налево, он замедляется, ускоряется, поднимается и опускается случайным образом, как ям намерения.
Проблема, с которой я сталкиваюсь, заключается в том, что иногда «ветер» достаточно сильный, чтобы элемент все еще был виден в окне просмотра, когда количество шагов достигло общего рассчитанного шага, и он просто исчезнет (что происходит в моем complete:function(){ ...$(this).remove(); ...}
Очевидно, что происходит то, что JQuery думает, что анимация завершена, потому что он рассчитал шаги и сказал: «Я анимирую этот объект так много пикселей за эти много миллисекунд за эти много шагов -это там ". Но анимация ветра находится вне очереди анимации , поэтому этот процесс анимации не имеет смысла.
Я хотел бы начать анимацию и просто продолжать анимацию доэлемент покинул область просмотра в любом направлении - как только он больше не будет виден ни с начальной траектории полета, ни из-за ветра, уносящего его с экрана, я обнаружу его и вызову обратный вызов onComplete
. Единственное, что я могудумать о том, чтобы поместить эту анимацию внутри функции и в complete:function(){}
сделать рекурсивныйЯ позвонил сам себе, затем внутри step:function(){}
я бы сделал проверку «видно в окне просмотра» и позвонил бы stop(true,false)
, если true
.Это просто кажется очень дорогой проверкой - выполнение этого вычисления более 100 раз за 400-1200 мс может сделать анимацию прерывистой, поэтому я ищу более элегантное решение.
TL; DR: Как мне продолжать анимировать что-то, пока оно еще не достигло своего пункта назначения из-за установки на него дополнительных анимаций?
ОБНОВЛЕНИЕ: Я применил @ mu слишкомИдея Шорта и пришла с этим:
/**
* Create a new clone of the master div for user interaction. Position it
* randomly off the canvas, and animate it across at a random speed.
*/
function spawn_target() {
spawn_timeout = setTimeout(function() {
var bonus = (rand(1, BONUS_ODDS) == BONUS_ODDS) ? ' ' + BONUS_CLASS : '';
var _img_src = (bonus.length > 0) ? BONUS_NODE_IMG_SRC : BASE_NODE_IMG_SRC;
var _width = $('#' + BASE_NODE_ID).width();
_width = Math.floor(rand(_width / 3, _width));
var _height = _width;
var _framerate = 10 - Math.floor(_height/10);
var _clone = $('#' + BASE_NODE_ID).clone().addClass(CLONE_CLASS + bonus).attr('id', CLONE_ID).appendTo('#' + CANVAS_ID).css({
'left': BASE_NODE_INIT_LEFT_PX,
'top': rand(BASE_NODE_INIT_TOP_MIN_PX, BASE_NODE_INIT_TOP_MAX_PX) + 'px',
'width': _width + 'px',
'height': _height + 'px',
})
$(_clone).children('img').attr('src', _img_src);
/**
* Handle the actual flight across the viewport
* @param object _this The clone we are animating manually
* @return object pointer This contains the interval so we can clear it later
*/
function fly(_this) {
var animating_wind = false;
var pointer = {
timer_id: null
};
pointer.timer_id = setInterval(function() {
// Get rid of the node if it is no longer visible in the viewport
if (!$(_this).is(':onviewport')) {
clearInterval(pointer.timer_id);
$(_this).remove();
adj_game_data(GAME_DATA_LIVES_ID, -1);
check_lives();
spawn_target();
}
// Move node along with slight realism
var distance = rand(FLY_DISTANCE_MIN, FLY_DISTANCE_MAX);
$(_this).css('left', '-=' + distance + 'px');
// Only trigger the wind animation when it is idle
if (animating_wind !== true) {
animating_wind = true;
// Setup the wind physics
var _wind_power = rand(WIND_POWER_MIN, WIND_POWER_MAX);
var _wind_dir = (rand(1, 2) == 2) ? '+=' : '-=';
// Override wind direction to keep node inside viewport
if(($(_this).offset().top + $(_this).height() + _wind_power) > CANVAS_HEIGHT)
{
_wind_dir = '-=';
}
if(($(_this).offset().top - _wind_power) < CANVAS_TOP_BUFFER_PX)
{
_wind_dir = '+=';
}
var _wind = _wind_dir + _wind_power + 'px';
// Apply the wind physics and don't let the node break the top or bottom
// boundaries of the viewport
$(_this).animate({
'top': _wind
}, {
duration: WIND_ANIMATION_DURATION,
complete: function() {
animating_wind = false;
},
queue: false
});
}
}, _framerate);
return pointer;
}
$(_clone).data('interval', fly(_clone));
}, rand(SPAWN_TARGET_TIMEOUT_MIN, SPAWN_TARGET_TIMEOUT_MAX));
}
Вот что у меня есть: http://jsfiddle.net/AlienWebguy/DmtQ7/embedded/result/
Мне нравится эта идея, хотя, похоже, в JQuery должно быть что-то встроенное.на что я и надеялся.Теперь вместо $(obj).stop()
мне нужно clearInterval($(obj).data('interval').timer_id);
.* царапает голову ...