ウィンドウ幅に合わせて画像をアニメーションで再配置する

2017-07-10

海外のホームページを見ていたとき、ウィンドウ幅に応じて画像の羅列がカラム数を増減しつつアニメーション移動するというデザインを見かけました。思わず「かっけーー」と思い、思っただけでどう作っているのか等は考えなかったのですが、ここ最近で3件程、このようなデザインのご相談が有りました。

こういうのです。

サンプル

どうせプラグインが有るんだろうとか、ソースコードをパクっちまえ、とかは自分の力にならないので、悩んでみる事にします。

  • アニメーションするのだから、画像は絶対位置で配置し、指定した位置へアニメーションで移動させれば良いのだろう
  • 画像をラップしている枠の幅を1列に配置したい画像枚数で割ればleftからの絶対位置は計算出来る
  • 全体の枚数を1列の枚数で割れば行数が解るので、topからの絶対位置は計算出来る
  • 案件によって表示する幅やカラム数が変わるだろうから、それは自由に指定したい
  • とりあえず画像は真四角にして計算し易いようにしよう
  • レスポンシブデザインに連携するようにしなくてはダメだ
  • なら@mediaの幅をtriggerとしてアニメーションさせるようにするか

こんな感じで考えてみました。

/*
* imagesLoaded() jquery plugin
* https://gist.github.com/paulirish/268257
*/
$.fn.imagesLoaded = function(callback){
var elems = this.filter('img'),
len   = elems.length,
blank = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
elems.bind('load.imgloaded',function(){
if (--len <= 0 && this.src !== blank){ 
elems.unbind('load.imgloaded');
callback.call(elems,this); 
}
}).each(function(){
if (this.complete || this.complete === undefined){
var src = this.src;
this.src = blank;
this.src = src;
}  
}); 
return this;
};
(function($){
$.fn.moving = function(options) {
var settings = $.extend( {
media1: 5,
media2: 4,
media3: 2,
trigger1:959,
trigger2:768,
trigger3:500,
}, options);
var imageRow = new Array;
var animete  = false;
var onLoad  = function(obj){
//画像データを配列化しておく
var move = $("#"+obj.attr('id')+' img');
for(var i=0; i<move.length; i++){
imageRow[i] = move[i].src;
}
checkWindow(obj,null);
}
function checkWindow(obj,resize){
var move = "#"+obj.attr('id'); 
var movingWidth = $(move).width() * 1;
//ブラウザの幅に応じて分割数をセット
var row = settings.media1;
if(movingWidth < settings.trigger1) //959px
row = settings.media1;
if(movingWidth < settings.trigger2) //768px
row = settings.media2;
if(movingWidth < settings.trigger3) //500px
row = settings.media3;
var imgSize = Math.floor(movingWidth / row); //movingの幅を分割数で割り、画像一枚の幅を計算
var imgLength = $(move+' img').length; //画像枚数
$("#container").height( Math.ceil((imgLength / row)) * imgSize); //総枚数を分割数で割った値に画像高さ(=幅)を掛けてmoving高さを計算
//初回表示の場合はいったん空にして後から再配置
if(!resize){
$(move+' li').remove();
}
//画像配列を1列の枚数で分割 *array_chunkっぽいの
var chunks = [],
i = 0,
n = imageRow.length;
while (i < n) {
chunks.push(imageRow.slice(i, i += row));
}
var imgTop = 0; //縦の絶対位置
var dummy  = 0;
for(var i=0; i<chunks.length; i++){
for(var j=0; j<chunks[i].length; j++){
var posLeft = Math.floor(imgSize*j); //左からの位置
var posTop  = Math.floor(imgTop);
var dummyId = 'id'+dummy;
//初期表示の場合はアニメーション無
if(!resize){
//初回はid振っておく
$('<li id="'+dummyId+'"></li>').html('<img src="'+chunks[i][j]+'">').appendTo(move).css({"width":imgSize,"height":imgSize,"top":posTop,"left":posLeft});
}
//ウインド幅変更時はアニメーションさせる
else{
animete = true;
$('#'+dummyId).css({"width":imgSize,"height":imgSize});
$('#'+dummyId).animate({
top: posTop,left: posLeft
},{
complete: function(){
animete = false;
$('#'+dummyId).stop();
$('#'+dummyId).queue([]);
}
});
}
dummy++;
}
imgTop = imgTop+imgSize;
}
}
var obj = $(this);
var timer = false;
$(window).resize(function(){
if(animete == true) return; //アニメーション中は実行しない
//ウインドサイズ変更が終わったときに実行
if (timer !== false) {
clearTimeout(timer);
}
timer = setTimeout(function() {
checkWindow(obj,true);
}, 200);
});
$("body img").imagesLoaded(function(){
onLoad( obj );//初回実行
});
};
})(jQuery);

 

ちなみにCSSは以下の程度で。

ul {
margin: 0px;
padding: 0px; }
ul li {
position: absolute;
margin: 0px;
padding: 0px;
list-style: none; }
ul li img {
width: 100%;
height: auto;
vertical-align: bottom; }
#container {
width: 1200px;
position: relative;
overflow: hidden;
margin: 0px auto; }
@media screen and (max-width: 959px) {
#container {
width: 96%; } }

 

HTMLの方で設定を行います。

   $(function(){
$('#moving').moving({
media1: 5,
media2: 3,
media3: 2,
trigger1:959,
trigger2:768,
trigger3:500,
});
});

trigger*は移動アニメーションを実行するタイミングで、media*はその時の横列数となります。

 

短いソースコードなので解説はしませんが、このくらいシンプルなのを書いておけば応用が効きそうです。あと、画像枚数が多かったり重たいと読込時にみっともないので、imagesLoaded() jquery pluginを使わせて頂いています。

ウィンドウの幅を変えるってケースがいったいどれくらいあるのだろうか?また、そのときアニメーションさせる事で、どのような効果が得られるのか?という点には疑問を持ちますが、格好良いことには間違いありませんので、何かの参考になれば良いかなぁ。