JavaScript缩小/增长圈转换

时间:2011-03-19 22:21:03

标签: javascript jquery image transition geometry

我的第一个问题。 :)

我正在寻找两个图像之间的过渡,其中图像首先以圆形缩小,然后圆圈再次包含另一个图像。这很难解释,我可能会使用错误的词语,因为我在Interwebz上找不到任何关于它的内容。

我说的是Loony Toons结尾的效果。 http://www.youtube.com/watch?v=ZuYIq-J5l9I

那缩小到黑色,可以在JavaScript / JQuery中完成吗?

4 个答案:

答案 0 :(得分:7)

<强> TL:DR

我怎么开始描述这个?如果CSS 2剪辑标准除了“rect”值之外还支持任何东西,即“圆圈”或“椭圆”,但是......因为那不存在,我会尽力做点什么一起做你要问的事。警告很多。一个是,如果您希望图片剪辑到背景,这只能用于具有纯色背景的东西。另一个原因是,虽然我试图考虑跨浏览器的CSS更新时间,但渲染仍然不是“完美”。我最初的方法是简单地为被替换的图像上的剪辑设置动画,但是由于通过我所在的插件中的缓动功能对剪辑进行更新的方式,这不起作用。最后的方法如下。

方法

这个概念是将图像设置为容器的background-image属性,例如<div> background-position center centerposition的{​​{1}}容器到relative,或任何非静态的容器。接下来是生成剪辑元素作为容器的子元素。第一个是背景颜色的position: absolute剪裁圆圈图像,透明的PNG或GIF(我更喜欢前者),接下来的四个是div,也有absoluteleft个位置right 1}},topbottomtop属性设置为0,表示他们将剪切的每个边。我们的想法是为裁剪圆图像的leftwidthheightleft设置动画,并使用步骤回调同步裁剪div的宽度和高度.animate()调用的选项,将它们与当前topbackground-image值相匹配。在动画之间,您将容器的adjust更改为新图像,然后以相反的方向返回动画。

这需要在IE7,8和Webkit浏览器中略微调整,因为动画在Firefox和IE9中更加干净。这将是您在工作演示中看到的<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> 变量。

示例代码如下:

标记

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;
}

CSS

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");
            }
        });
    }
});

脚本

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

修改

CSS3解决方案

当跨浏览器兼容性不太受关注时,CSS3是一个选项(虽然我可能会建议看看这种动画的新HTML5 Canvas可以做些什么)。有几点需要注意:

  • 图像必须位于容器内,以便我们可以向中心而不是左上角进行剪辑。
  • border-radius属性不会剪切容器内的子图像。因此,图像必须成为容器的background-image属性。
  • jQuery目前没有正确设置border-radius动画。您可以替换该属性的当前jQuery动画功能,也可以构建自定义border-radius动画对象以使jQuery更加良好。我选择了后者。每个角的边界半径必须单独设置动画。
  • 动画输入或输出由两个独立的段组成,因此“线性”缓动功能可能最适合用于最干净的结果。

该方法在下面注释:

标记

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);
}

CSS

// 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}}

Again, the demo is located here.

答案 1 :(得分:1)

我来到这里,我希望它很有趣:http://www.netzgesta.de/transm/。转换circles_out有一个圆圈可以完成我认为的工作。

答案 2 :(得分:0)

你走了。 http://jquery.malsup.com/cycle/查看缩放。可以通过圆形部分来解决问题。

答案 3 :(得分:0)

我尝试了更多,并提出了使用<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);
}