плавная анимация JavaScript от X, Y до X1, Y1 - PullRequest
6 голосов
/ 17 сентября 2011

Я бы хотел неуклюже переместить изображение (или элемент) из его фактического положения X, Y в X1, Y1.

Когда расстояние между X и X1 равно тому, что между Y и Y1 легко.Но что, если разница в X, скажем, 100px, а Y diff - 273px?

Будучи новичком в Javascript, я не хочу заново изобретать колесо!Кроме того, так как я учусь, я НЕ хочу использовать jQuery или лайки.Я хочу чистый JavaScript.

Пожалуйста, предоставьте простой скрипт: -)

Ответы [ 4 ]

7 голосов
/ 17 сентября 2011

Одно решение:

function translate( elem, x, y ) {
    var left = parseInt( css( elem, 'left' ), 10 ),
        top = parseInt( css( elem, 'top' ), 10 ),
        dx = left - x,
        dy = top - y,
        i = 1,
        count = 20,
        delay = 20;

    function loop() {
        if ( i >= count ) { return; }
        i += 1;
        elem.style.left = ( left - ( dx * i / count ) ).toFixed( 0 ) + 'px';
        elem.style.top = ( top - ( dy * i / count ) ).toFixed( 0 ) + 'px';
        setTimeout( loop, delay );
    }

    loop();
}

function css( element, property ) {
    return window.getComputedStyle( element, null ).getPropertyValue( property );
}

Живая демоверсия: http://jsfiddle.net/qEVVT/1/

3 голосов
/ 17 сентября 2011

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

Лучший способ сделать это - встать на плечи других и использовать то, что было изобретено ранее.В наши дни я бы никогда не попытался написать это сам с нуля.Он используется в переходах / анимациях CSS3, но они пока не поддерживаются повсеместно.Его можно использовать или анализировать в jQuery и YUI3.Мой первый выбор - использовать одну из фреймворков, которая обладает богатым набором возможностей.Вам не нужно использовать фреймворк для чего-то еще, вы можете просто использовать его для анимации, если хотите.YUI3 даже позволит вам создать библиотеку, в которой будет как можно меньше кода для того, что вы хотите.jQuery не очень большой для начала.

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

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

Теперь, если вы хотите сделать что-то кроме линейного ослабления, естьочевидно, еще более сложный.

Firefox и Chrome также реализовали несколько новых экспериментальных API, чтобы помочь с плавной анимацией.Я обнаружил это сам, глядя на исходный код jQuery, потому что он использует его, когда он доступен.В Chrome он называется webkitRequestAnimationFrame, и вы можете прочитать об этом здесь в блоге Firefox .

1 голос
/ 17 сентября 2011

Если вы ориентируетесь на современные браузеры, переходы CSS облегчают жизнь (например, для Firefox, для других браузеров измените префикс -moz):

<body>
    <input type="button" onclick="move()" value="press" />
    <div id="sq" style="position:absolute; top:50px; left:50px; height:50px; width:50px; background-color:Black; -moz-transition : all 0.8s ease 0s;" />
</body>

И сценарий

 function move() {
            var sq = document.getElementById("sq");
            sq.style.left = "300px";
            sq.style.top = "150px";
        }
0 голосов
/ 17 сентября 2011

Если бы я собирался написать это с нуля, я бы начал с чего-то вроде этого:

function linearEase(start, end, percent) {
    return start + ((end - start) * percent);
}

function animateTo(settings) {
    var elem = settings.element;
    var ease = settings.ease;

    var start = { left: elem.offsetLeft, top: elem.offsetTop };

    var lastTime = new Date().getTime();
    var timeLeft = settings.totalTime;

    function update() {
        var currentTime = new Date().getTime();
        var elapsed = currentTime - lastTime;
        timeLeft -= elapsed;
        lastTime = currentTime;

        var percentDone = 1 - timeLeft/settings.totalTime;

        elem.style.top = ease(start.top, settings.top, percentDone) + "px" ;
        elem.style.left = ease(start.left, settings.left, percentDone) + "px" ;

        if(timeLeft > 0) {
            setTimeout(update, 33);
        }   
    }

    update();
}

Например, чтобы переместить div в (50,50) в течение следующих двух секунд.

var elem = document.getElementById("animatable");

setTimeout(function() {
    animateTo({
        element: elem, 
        left: 50, 
        top: 50, 
        totalTime: 2000,
        ease: linearEase
    })
}, 10);

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

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

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

В любом случае, скрипка здесь

...