TL: DR
Comment puis-je commencer même à décrire celui-ci? Ce serait beaucoup plus facile si la norme CSS 2 supportait autre chose qu'une valeur "rect", à savoir un "cercle" ou une "ellipse" mais ... comme ça n'existe pas, j'ai fait de mon mieux pour arranger quelque chose ensemble, cela fera ce que vous demandez. Les mises en garde sont nombreuses. Le premier est que cela va seulement travailler sur quelque chose avec un fond de couleur unie dans le cas où vous vouliez que l'image se clipse en arrière-plan. Un autre est que, bien que j'aie essayé de tenir compte de la synchronisation des mises à jour CSS entre les navigateurs, le rendu n'est toujours pas "parfait". Mon approche initiale consistait simplement à animer le clip sur l'image qui était remplacée, mais cela n'a pas fonctionné en raison de la façon dont les mises à jour ont été faites à l'écrêtage via la fonction d'accélération du plugin que j'ai localisé. L'approche finale est ci-dessous.
L'approche
Le concept est de définir l'image en tant que propriété background-image
d'un récipient comme un <div>
avec un background-position
de center center
, et le position
du récipient à relative
, ou toute non-statique. La prochaine consiste à générer les éléments de découpage en tant qu'enfants du conteneur. Le premier est une image de cercle de découpage position: absolute
de la couleur de votre fond, soit PNG transparent ou GIF (je préfère l'ancien), et les quatre suivants sont divs, également avec absolute
positions qui ont left
, right
, top
, et bottom
ensemble d'attributs à 0 pour chacun des côtés respectifs qu'ils vont couper. L'idée est d'animer les top
, left
, width
et height
de l'image du cercle de détourage et de synchroniser la largeur et la hauteur des divs de découpage en utilisant l'option de rappel de l'appel .animate() en les faisant correspondre au left
actuel et top
valeurs. Entre les animations, vous modifiez le background-image
du conteneur à la nouvelle image, puis démarrez l'animation dans la direction opposée.
Cela nécessitait un peu de finesse dans les navigateurs IE7, 8 et Webkit, car l'animation était beaucoup plus nette dans Firefox et IE9. Ce sera la variable adjust
que vous verrez dans la démo de travail.
L'exemple de code est ci-dessous:
Le balisage
<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>
Le 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;
}
Le 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 solution CSS3
Lorsque la compatibilité multi-navigateur est moins préoccupante, CSS3 est une option (même si je vous suggère probablement de voir ce qui peut être fait avec le nouveau HTML5 Canvas pour ce genre d'animation). Il y a un certain nombre de choses à noter:
- L'image doit être à l'intérieur d'un conteneur afin de nous permettre de nous rapprocher de son centre plutôt que de son coin supérieur gauche.
- L'attribut border-radius ne coupera pas les images enfants dans un conteneur. Pour cette raison, l'image doit devenir l'attribut background-image du conteneur.
- jQuery n'anime pas correctement le border-radius. Vous pouvez soit remplacer la fonctionnalité d'animation jQuery actuelle pour cet attribut, soit créer un objet d'animation border-radius personnalisé pour rendre jQuery plus sages. J'ai opté pour le dernier. Le rayon de bordure de chaque coin doit être animé séparément.
- L'animation d'entrée ou de sortie se compose de deux segments distincts, et par conséquent, la fonction d'accélération "linéaire" est probablement mieux utilisée pour obtenir des résultats plus nets.
La méthode est commentée en ligne ci-dessous:
Le balisage
<div class="imageContainer image1">
</div>
Le 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);
}
Le 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.
Ça a l'air très bien, même si j'en aurai probablement besoin pour travailler sur un fond aussi. J'aurais dû le mentionner, mais je ne le savais pas au moment où j'ai posté la question. : -/ – GolezTrol
Mais j'ai pensé que je pourrais peut-être mettre l'image dans un div avec (css3) bords arrondis et rétrécir ce div. L'image d'arrière-plan sera tronquée à la frontière même si elle est arrondie, non? Ensuite, j'ai seulement besoin d'animer la taille et la position de ce div et la position de l'arrière-plan. Dans IE et (les autres) anciens navigateurs, il s'anime en carré, mais je peux vivre avec ça si cela me donne la possibilité d'utiliser cette animation sur un fond. Je vais essayer de comprendre comment cette animation fonctionne et comment je peux l'adapter à mes besoins. Merci déjà pour la grande quantité d'efforts. – GolezTrol
@GolezTrol Eh bien, cela devient probablement beaucoup plus facile si vous ne vous souciez pas des solutions multi-navigateur, pour ce que ça vaut. Cependant, dans le monde de IE7/8 ... oy ... Ouais ce sera un bordel sans Flash ou similaire. – lsuarez