JavaScript сокращение / увеличение круга перехода - PullRequest
9 голосов
/ 20 марта 2011

Мой первый вопрос здесь. :)

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

Я говорю о таком эффекте, как окончание Loony Toons. http://www.youtube.com/watch?v=ZuYIq-J5l9I

Это сжатие в черный цвет, это можно сделать в JavaScript / JQuery?

Ответы [ 4 ]

7 голосов
/ 20 марта 2011

TL: DR

Как мне вообще начать описывать это?Было бы намного проще, если бы стандарт клипа CSS 2 поддерживал что-либо, кроме значения "rect", а именно "circle" или "ellipse", но ... поскольку этого не существует, я приложил все усилия, чтобы что-то собратьвместе это сделает то, что вы просите.Предостережения много.Во-первых, это будет работать только на чем-то с однотонным фоном, если вы хотите, чтобы изображение обрезало фон.Другое - то, что, хотя я и пытался учесть время обновления CSS в разных браузерах, рендеринг все еще не "идеален".Мой первоначальный подход состоял в том, чтобы просто анимировать клип на изображении, которое заменялось, но это не сработало из-за того, как были сделаны обновления в отсечении с помощью функции замедления в плагине, который я нашел.Окончательный подход приведен ниже.

Подход

Идея состоит в том, чтобы установить изображение как свойство background-image контейнера, такого как <div>, с background-position из center center и position контейнера до relative, или что-нибудь нестатичное.Следующее - генерировать элементы отсечения как дочерние элементы контейнера.Первый - это position: absolute изображение обтравочного круга цвета вашего фона, либо прозрачный PNG, либо GIF (я предпочитаю первый), а следующие четыре - это div, также с позициями absolute, которые имеют left, * 1034Атрибуты *, top и bottom установлены в 0 для каждой из соответствующих сторон, которые они будут обрезать.Идея состоит в том, чтобы анимировать top, left, width и height изображения обтравочного круга и синхронизировать ширину и высоту обтравочных элементов с помощью опции обратного вызова шага вызова .animate ()сопоставляя их с текущими значениями left и top.Между анимациями вы изменяете background-image контейнера на новое изображение и затем запускаете анимацию обратно в противоположном направлении.

Это потребовало небольшого перебора в браузерах IE7, 8 и Webkit, когда анимация обрезаласьгораздо более чисто в Firefox и IE9.Это будет переменная adjust, которую вы увидите в рабочем демо.

Пример кода ниже:

Разметка

<div class="imageContainer image1">
    <img class="clip" src="http://www.mysite.com/images/clipCircle.png" />
    <div class="top fill"></div>
    <div class="left fill"></div>
    <div class="right fill"></div>
    <div class="bottom fill"></div>
</div>

CSS

div.imageContainer
{
    background-position: center;
    width: 300px;
    height: 300px;
    position: relative;
}

img.clip
{
    width: 100%;
    height: 100%;
    position: absolute;
}

div.fill
{
    position: absolute;
    background-color: White;
}

div.left, div.right
{
    height: 100%;
    top: 0;
    width: 0;
}

div.left
{
    left: 0;
}

div.right
{
    right: 0;
}

div.top, div.bottom
{
    width: 100%;
    left: 0;
    height: 0;
}

div.top
{
    top: 0;
}

div.bottom
{
    bottom: 0;
}

Сценарий

var speed = 1000;

$clip = $("img.clip");

$clip.animate({
    top: $clip.parent().height() / 2,
    left: $clip.parent().width() / 2,
    width: 0,
    height: 0
}, {
    duration: speed,
    step: function(now, fx) {
        switch (fx.prop) {
        case "top":
            $("div.top").css("height", now);
            $("div.bottom").css("height", now + adjust);    
            break;
        case "left":
            $("div.left").css("width", now);
            $("div.right").css("width", now + adjust);
        }
    },
    complete: function() {
        $(this).parent().addClass("image2");

        $(this).animate({
            top: 0,
            left: 0,
            width: $clip.parent().width(),
            height: $clip.parent().height()
        }, {
            duration: speed,
            step: function(now, fx) {
                switch (fx.prop) {
                case "top":
                    $("div.top").css("height", now);
                    $("div.bottom").css("height", now + adjust);    
                    break;
                case "left":
                    $("div.left").css("width", now);
                    $("div.right").css("width", now + adjust);
                }
            },
            complete: function() {
                $("div.imageContainer > *").removeAttr("style");
            }
        });
    }
});

РЕДАКТИРОВАТЬ:

Решение CSS3

Когда кросс-браузерная совместимость не так важна, вариант CSS3 - это вариант (хотя я бы посоветовал посмотреть, что можно сделать с новым HTML5 Canvas для этого вида)анимации).Обратите внимание на пару моментов:

  • Изображение должно быть внутри контейнера, чтобы мы могли обрезать его центр, а не его верхний левый угол.
  • Граница -Атрибут radius не будет обрезать дочерние изображения внутри контейнера.По этой причине изображение должно стать атрибутом background-image контейнера.
  • jQuery в настоящее время неправильно анимирует border-radius.Вы можете либо заменить текущую функциональность анимации jQuery для этого атрибута, либо создать собственный анимационный объект с радиусом границы, чтобы сделать jQuery более корректным.Я выбрал последнее.Границы радиуса каждого угла должны быть анимированы отдельно.
  • Анимация в или из состоит из двух отдельных сегментов, и в результате "линейная" функция ослабления, вероятно, лучше всего использовать для самых чистых результатов.

Метод прокомментирован ниже:

Разметка

<div class="imageContainer image1">
</div>

CSS

div.imageContainer
{
    background-position: 0px 0px;
    background-repeat: no-repeat;
    width: 300px;
    height: 300px;
    position: absolute;
    top: 0;
    left: 0;
}

div.image1
{
    background-image: url(http://www.mysite.com/images/myFirstImage.png);
}

div.image2
{
    background-image: url(http://www.mysite.com/images/mySecondImage.png);
}

The Script

// Total animation speed in or out will be speed * 1.5
var speed = 600;

// Store a reference to the object to be clipped
var $clip = $("div")

// A function to build a mapping object for border radius parameters
var buildRadiusObj = function(value) {

    // Dimension an option object
    var opts = {};

    // Use specialized Mozilla CSS attributes when needed
    var attributes = $.browser.mozilla ?
        ["-moz-border-radius-topleft",
         "-moz-border-radius-bottomleft",
         "-moz-border-radius-topright",
         "-moz-border-radius-bottomright"] :
        ["border-top-left-radius",
         "border-bottom-left-radius",
         "border-top-right-radius",
         "border-bottom-right-radius"];

    // Build the option object
    $.each(attributes, function(i, key) {
        opts[key] = value;
    });

    // Return the result
    return opts;
}

$clip.animate(buildRadiusObj($clip.width() * 0.5), {    // Animate the border radius until circular
    duration: speed * 0.5,
    easing: "linear"
}).animate({                                            // Resize and reposition the container
    width: 0,
    left: $clip.width() / 2,
    height: 0,
    top: $clip.height() / 2
}, {
    duration: speed,
    easing: "linear",
    step: function(now, fx) {                           // Synch up the background-position
        if (fx.prop == "top") {
            $(this).css("background-position", "-" + $(this).css("top") + " -" + $(this).css("left"));
        }
    },
    complete: function() {                              // Swap the image
        $(this).addClass("image2");
    }
}).animate({                                            // Restore position and size
    width: $clip.width(),
    left: 0,
    height: $clip.height(),
    top: 0
}, {
    duration: speed,
    easing: "linear",
    step: function(now, fx) {                           // Synch the background-position
        if (fx.prop == "top") {
            $(this).css("background-position", "-" + $(this).css("top") + " -" + $(this).css("left"));
        }
    },
    complete: function() {                              // Remove inline styles but reapply border-radius
        $(this).removeAttr("style").css(buildRadiusObj($clip.width() * 0.5));
    }
}).animate(buildRadiusObj(0), {                         // Restore border-radius to block
    duration: speed * 0.5,
    easing: "linear",
    complete: function() {
        $(this).removeAttr("style");                    // Remove inline styles
    }
});

Опять демо находится здесь.

1 голос
/ 20 марта 2011

Я сталкивался с этим, я надеюсь, что это интересно: http://www.netzgesta.de/transm/. Переход circles_out с одним кругом может сделать работу, я думаю.

0 голосов
/ 20 марта 2011

Я попробовал еще немного и предложил идею использования элемента <canvas>.

Пожалуйста, смотрите результат по адресу: http://jsfiddle.net/3MG8e/2/.

var cv = $('canvas')[0];
var ctx = cv.getContext('2d');
ctx.fillStyle = 'black';

var int = null;
var t = -1;
var amount = 50;
var time = 1000;
var size = 0;

var im = new Image();
im.src = "http://burzak.com/proj/fxcanvas/docs/images/mario2.png";
im.onload = function() {
    size = im.width;
    int = setInterval(update, time / amount);
}

function update() {
    if(++t >= amount) {
        clearInterval(int);
    }
    ctx.fillRect(0, 0, cv.width, cv.height);
    ctx.beginPath();
    ctx.arc(size/2, size/2,
            size/2 - t * (size/2) / amount,
            0, Math.PI*2,
            false);
    ctx.clip();
    ctx.drawImage(im, 0, 0, size, size);
}
0 голосов
/ 20 марта 2011

Вот, пожалуйста. http://jquery.malsup.com/cycle/ Проверьте масштаб. Что-то можно решить с помощью части круга.

...