TL: DR
¿Cómo puedo siquiera empezar a describir este? Sería mucho más fácil si el estándar CSS 2 clip admite algo más que un valor "rect", es decir, un "círculo" o "elipse", pero ... ya que no existe, he hecho todo lo posible para pieza algo juntos harán lo que estás pidiendo. Las advertencias son muchas. Una de ellas es que esto solo funcionará en algo con un fondo de color sólido en caso de que quisiera que la imagen se recortara en segundo plano. Otra es que, aunque traté de dar cuenta del tiempo de actualización de CSS en todos los navegadores, el procesamiento aún no es "perfecto". Mi enfoque inicial fue simplemente animar el clip de la imagen que se estaba reemplazando, pero no funcionó debido a la forma en que se realizaron las actualizaciones al recorte a través de la función de suavizado en el complemento que localicé. El acercamiento final está abajo.
El enfoque
El concepto es la creación de la imagen como un background-image
propiedad de un recipiente como un <div>
con un background-position
de center center
y el position
del recipiente para relative
, o algo no estático. El siguiente es generar los elementos de recorte como elementos secundarios del contenedor. La primera es una imagen de círculo de recorte position: absolute
del color de su fondo, ya sea PNG transparente o GIF (prefiero la primera), y las siguientes cuatro son divs, también con absolute
posiciones que tienen atributos left
, right
, top
y bottom
establecidos a 0 para cada uno de los lados respectivos que cortarán. La idea es animar el top
, left
, width
y height
de la imagen del círculo de recorte y sincronizar el ancho y alto de los divisores de división usando la opción de devolución de pasos de la llamada .animate() haciendo coincidirlos con el left
actual y top
valores. Entre las animaciones, cambie el background-image
del contenedor a la nueva imagen y luego inicie la animación en la dirección opuesta.
Esto requirió un poco de fineessing en IE7, 8 y navegadores Webkit ya que la animación se recortó mucho más limpiamente en Firefox e IE9. Esta sería la variable adjust
que verá en la demostración operativa.
El código de ejemplo es el siguiente:
El marcado de
<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>
El 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:
La solución CSS3
Cuando la compatibilidad entre navegadores es una preocupación menor, CSS3 es una opción (aunque probablemente me propongo ver qué se puede hacer con el nuevo Canvas HTML5 para este tipo de animación). Hay un par de cosas a tener en cuenta:
- La imagen debe estar dentro de un contenedor para poder acortar hacia su centro en lugar de su esquina superior izquierda.
- El atributo border-radius no recortará las imágenes secundarias dentro de un contenedor. Por este motivo, la imagen debe convertirse en el atributo imagen de fondo del contenedor.
- jQuery actualmente no anima correctamente border-radius. Puede reemplazar la funcionalidad animada jQuery actual para ese atributo o crear un objeto de animación borde-radio personalizado para hacer que jQuery se comporte mejor. He optado por este último. El radio del borde de cada esquina debe estar animado por separado.
- La animación de entrada o salida consta de dos segmentos separados y, como resultado, la función de relajación "lineal" probablemente se utilice mejor para obtener resultados más limpios.
El método se comentó en línea a continuación:
El marcado de
<div class="imageContainer image1">
</div>
El 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
}
});
Again, the demo is located here.
Eso se ve muy bien, aunque probablemente también lo necesite para trabajar en segundo plano. Debería haberlo mencionado, pero no sabía en el momento en que publiqué la pregunta. : -/ – GolezTrol
Pero pensé que podría poner la imagen en un div con bordes redondeados (css3) y reducir ese div. La imagen de fondo se truncará en el borde incluso si está redondeada, ¿verdad? Entonces solo necesito animar el tamaño y la posición de ese div y la posición del fondo. En IE y (otros) navegadores más antiguos, se animará como un cuadrado, pero puedo vivir con eso si me da la posibilidad de usar esta animación sobre un fondo. Trataré de descubrir cómo funciona esta animación y cómo puedo ajustarla a mis necesidades. Gracias por la gran cantidad de esfuerzo. – GolezTrol
@GolezTrol Bueno, esto probablemente sea mucho más fácil si no te importan las soluciones de navegador cruzado, por lo que vale. Sin embargo, en el mundo de IE7/8 ... oy ... Sí, esto será un desastre sin Flash o similar. – lsuarez