JavaScript 收缩/增长循环过渡

发布于 2024-10-23 20:10:49 字数 287 浏览 1 评论 0原文

我的第一个问题在这里。 :)

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

我说的是像《疯狂卡通》结局这样的效果。 http://www.youtube.com/watch?v=ZuYIq-J5l9I

缩小到-黑色,可以用 JavaScript/JQuery 完成吗?

My first question here. :)

I'm looking for a transitions between two images where the image first shrinks in a circle shape and then the circle grows again containing the other image. It's hard to explain, and I may be using the wrong words, because I can't find anything about it on the Interwebz.

I'm talking about an effect like the Loony Toons ending.
http://www.youtube.com/watch?v=ZuYIq-J5l9I

That shrinking-to-black, can it be done in JavaScript/JQuery?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

雅心素梦 2024-10-30 20:10:49

TL:DR


- Cross-browser: [**See a working demo
here**](http://jsfiddle.net/lthibodeaux/8DSjz/).
Well, mostly working... and
cross-browser. Could do worse. ;]
- Purely CSS3 Solution: [**See a working demo
here**](http://jsfiddle.net/lthibodeaux/8DSjz/16/)

我该如何开始描述这个呢?如果 CSS 2 剪辑标准支持除“矩形”值之外的任何内容(即“圆”或“椭圆”),那就容易多了,但是……因为这不存在,所以我已经尽力拼凑一些东西在一起就可以完成你所要求的事情。需要注意的地方有很多。一是,如果您希望图片剪辑到背景上,这仅适用于具有纯色背景的内容。另一个问题是,虽然我尝试考虑跨浏览器的 CSS 更新时间,但渲染仍然不“完美”。我最初的方法是简单地对要替换的图像上的剪辑进行动画处理,但这不起作用,因为通过我找到的插件中的缓动功能对剪辑进行了更新。最终的方法如下。

方法

这个概念是将图像设置为容器的 background-image 属性,例如带有

center center 的背景位置,以及容器的positionrelative,或任何非静态的内容。接下来是生成剪辑元素作为容器的子元素。第一个是背景颜色的 position:absolute 剪贴圆图像,透明 PNG 或 GIF(我更喜欢前者),接下来的四个是 div,也带有 absolute< /code> 位置,每个位置的 leftrighttopbottom 属性均设置为 0他们将剪裁各自的侧面。这个想法是对剪切圆图像的 topleftwidthheight 进行动画处理并同步使用 .animate() 调用的步骤回调选项将剪辑 div 的宽度和高度与当前 lefttop 值进行匹配。在动画之间,您将容器的 background-image 更改为新图像,然后以相反的方向启动动画。

这需要在 IE7、8 和 Webkit 浏览器中进行一些处理,因为动画在 Firefox 和 IE9 中剪辑得更加干净。这将是您将在工作演示中看到的 调整 变量。

示例代码如下:

标记

<div class="imageContainer image1">
    <img class="clip" src="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 可以为此类动画做些什么)。有几点需要注意:

  • 图像必须位于容器内,以便我们可以向其中心而不是左上角进行剪辑。
  • border-radius 属性不会剪切容器内的子图像。因此,图像必须成为容器的background-image属性。
  • jQuery 目前无法正确设置边框半径的动画。您可以替换该属性的当前 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(/images/myFirstImage.png);
}

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

脚本

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

演示位于此处。

TL:DR


- Cross-browser: [**See a working demo
here**](http://jsfiddle.net/lthibodeaux/8DSjz/).
Well, mostly working... and
cross-browser. Could do worse. ;]
- Purely CSS3 Solution: [**See a working demo
here**](http://jsfiddle.net/lthibodeaux/8DSjz/16/)

How do I even begin to describe this one? It would be a lot easier if the CSS 2 clip standard supported anything besides a "rect" value, namely a "circle" or "ellipse" but... since that doesn't exist, I've done my best to piece something together that will do what you're asking. The caveats are many. One is that this is only going to work on something with a solid color background in the event you wanted the picture to clip to the background. Another is that while I've tried to account for the CSS update timing across browsers, the rendering still isn't "perfect." My initial approach was to simply animate the clip on the image that was getting replaced, but that didn't work due to the way updates were made to the clipping via the easing function in the plugin I located. The final approach is below.

The Approach

The concept is to set the image as a background-image property of a container like a <div> with a background-position of center center, and the position of the container to relative, or anything non-static. The next is to generate the clipping elements as children of the container. The first is a position: absolute clipping circle image of the color of your background, either transparent PNG or GIF (I prefer the former), and the next four are divs, also with absolute positions that have left, right, top, and bottom attributes set to 0 for each of the respective sides they will clip. The idea is to animate the top, left, width, and height of the clipping circle image and synch up the width and height of the clipping divs using the step callback option of the .animate() call by matching them to the current left and top values. Between animations, you change the background-image of the container to the new image and then start the animation back in the opposite direction.

This required a little finessing in IE7, 8, and Webkit browsers as the animation clipped much more cleanly in Firefox and IE9. This would be the adjust variable you'll see in the working demo.

The sample code is below:

The Markup

<div class="imageContainer image1">
    <img class="clip" src="clipCircle.png" />
    <div class="top fill"></div>
    <div class="left fill"></div>
    <div class="right fill"></div>
    <div class="bottom fill"></div>
</div>

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

The Script

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

EDIT:

The CSS3 Solution

When cross-browser compatibility is less of a concern, CSS3 is an option (although I'd probably suggest seeing what can be done with the new HTML5 Canvas for this kind of animation). There are a couple things to note:

  • The image must be inside a container in order to allow us to clip toward its center rather than its top left corner.
  • The border-radius attribute will not clip the child images inside a container. For this reason, the image must become the background-image attribute of the container.
  • jQuery does not currently animate border-radius correctly. You can either replace the current jQuery animate functionality for that attribute or build a custom border-radius animation object to make jQuery more well-behaved. I have opted for the latter. Each corner's border-radius must be animated separately.
  • The animation in or out consists of two separate segments, and as a result the "linear" easing function is probably best used for cleanest results.

The method is commented inline below:

The Markup

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

The 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(/images/myFirstImage.png);
}

div.image2
{
    background-image: url(/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
    }
});

Again, the demo is located here.

红玫瑰 2024-10-30 20:10:49

我遇到了这个,我希望它很有趣:http://www.netzgesta.de/transm/。我认为带有一个圆圈的过渡 circles_out 可以完成这项工作。

I came this across, I hope it is interesting: http://www.netzgesta.de/transm/. The transition circles_out with one circle could do the job I think.

夢归不見 2024-10-30 20:10:49

干得好。 http://jquery.malsup.com/cycle/ 查看缩放效果。可以用圆圈部分解决一些问题。

Here you go. http://jquery.malsup.com/cycle/ Check out the zoom. Something can be worked out with the circle part.

嗼ふ静 2024-10-30 20:10:49

我尝试了更多,并提出了使用 元素的想法。

请在以下位置查看结果: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);
}

I tried some more and came up with the idea of using a <canvas> element.

Please see the result at: 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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文