fc2ブログ

jQueryで、異なる要素のアニメーションを順番に実行する

jQueryでアニメーションを実行する処理でいろいろとハマったので、
昨日と今日と2日がかりで調べたことをまとめる。

jQueryのEffects APIには、animateやslideUp/slideDownなど、durationを指定することでアニメーションを行うメソッドがいくつかある。
同一要素に対してアニメーションを実行すると、アニメーションが順番に実行される。
これは、jQueryが要素ごとにアニメーション処理用のキューを管理しているからで、キューに格納された処理は前の処理が終わらないと実行されない。

アニメーションをメソッドチェーンでつなぐ必要は無く、
$("#id1").fadeOut(500).fadeIn(500).hide(500).show(500)
  .fadeOut(500).fadeIn(500);
でも
$("#id1").fadeOut(500);
$("#id1").fadeIn(500);
$("#id1").hide(500);
$("#id1").show(500);
$("#id1").fadeOut(500);
$("#id1").fadeIn(500);
でも順番に実行される。

ただし、(少なくともjquery-1.4.2では)durationを指定しない処理はキューに格納されないようで、
$("#id1").fadeOut(500).fadeIn(500).hide().show(500)
  .fadeOut(500).fadeIn(500);
とすると hide() と fadeOut(500) が同時に実行されて期待した動きにならない。

さて、本題の「異なる要素のアニメーションを順番に実行する方法」。
要素が異なるとキューも異なるので、
for(var i=0;i<3;i++){
  $("#id"+(i+1)).fadeOut(500).fadeIn(500);
}
とすると、3つの要素が同時に点滅してしまう。

delay()メソッドを使用することで、3つの要素を順番に点滅させることができる。
<注意:delay()メソッドが使用できるのは version 1.4 以降のjQuery>
指定した数字(単位はミリ秒)だけキューの処理を遅延させることができるので、
var interval = 0;
for(var i=0;i<3;i++){
  $("#id"+(i+1)).delay(interval).fadeOut(500).fadeIn(500);
  interval += 1500;
}
とすればいい。
interval に追加する数字により、次の要素が処理するまでの間隔を制御できる。
上記は interval += 1500 なので、次の要素が点滅するまでの間隔は500ミリ秒となる。
<2010/8/1追記>
上記の方法では、要素の数が大きくなると点滅が等間隔にならない場合があります。
修正版を jQueryで、異なる要素のアニメーションを順番に実行する 改 に記述しています。
<追記ここまで>

delay()はあくまでもキューの実行を遅延するので、durationを指定しない処理には効果が無いことに注意する必要がある。
durationを指定しない処理や、アニメーション以外の処理を制御したい場合は、setTimeout等を使ってキューを自作するか、以下のようなプラグインを使用する。
指定した処理をキューに追加して後でまとめて実行する jQuery Delay プラグイン

せっかくなので、処理実行中はロックをかけてイベントを受け付けない処理を、キューを利用して作ってみた。
// lockflgは、既にグローバル変数として初期値falseで宣言されている。
if(lockflg){return false;}  // lockflg == true なら処理しない
lockflg = true;
var interval = 0;
for(var i=0;i<3;i++){
  $("#id"+(i+1)).delay(interval).fadeOut(500).fadeIn(500);
  interval += 1500;
}
$("#id3").fadeIn(1,function(){lockflg = false;});  // lockflgをfalseにするためのダミー処理
最後に処理される要素のキューの最後尾に、害の無いダミーのアニメーションを追加し、そのcallback関数でフラグをオフにする。
こういったダミー処理で行うやり方は推奨されないんだろうなぁ。

ダミーのアニメーションを使わない処理も作ってみた
if(lockflg){return false;}  
lockflg = true;
var interval = 0;
for(var i=0;i<3;i++){
  if(i==2){
    // 最後にlockflgをfalseにする
    $("#id"+(i+1)).delay(interval).fadeOut(500).fadeIn(500,function(){lockflg = false;});
  }else{
    $("#id"+(i+1)).delay(interval).fadeOut(500).fadeIn(500);
  }
  interval += 1500;
}
ダミーを使う場合に比べると、ループのたびに余計な判定が入るが、多分些細な負荷だろう。
スポンサーサイト



JavaScriptで、1からnまでの数字をランダムに並べる

JavaScriptでランダムな数列を作りたいと思って、ちょっと調べた。
Math.random()メソッドを使って実現するやり方がわかったので、せっかくだからブログにまとめる。

1からnまでの整数をランダムに表示したかったら、
Math.floor(Math.random() * n) + 1
を必要な回数だけ繰り返せばよい。

自分がやりたかったことはこれで実現できるのだが、
「1からnまでの整数をランダムに抽出する。ただし、一度抽出した数は抽出対象からはずす」
を実現するやり方を調べた。
つまり、「1からnまでの整数をランダムに並べる」とか「1からnまでの整数を並び替える」やり方。

JavaScriptソースコードは以下のとおり。
var n = 100; // この n の値を必要に応じて変える。とりあえず100にしてみた。

// 1~nまでの整数を順番に配列arrに格納
var arr = [];
for(var i=0; i<n; i++){ arr[i] = i+1; }

// ランダムに並べた結果を配列shuffledarrに格納
var shuffledarr = [];
var randomIndex;
for(var i=0; i<n; i++){
  randomIndex = Math.floor(Math.random()*arr.length);
  shuffledarr[i] = arr[randomIndex];
  arr.splice(randomIndex, 1);
}
まず、1~nまでの整数を順番に配列 arr に格納し、そこから一つランダムに抽出する。
抽出した要素は、Array.splice()メソッドにより配列 arr から削除する。
これをn回繰り返すことで、最終的に配列 arr を並べ替えた結果が配列 shuffledarr に格納される。

最初何も考えずに
for(var i=1; i<=n; i++){ arr[i] = i; }
と書いたら、shuffledarrの一つがundefinedになった。
Math.random()は0以上1未満の乱数を発生させるため、randomIndex は0以上 arr.length 未満の整数になる。
だから配列の添字は0からにしなければならない。
randomIndex に1を足してもいいんだけど、配列の添字を0からにする方が自然だ。

そんなこんなで、自分が作りたいものは全く進捗が出ていない。

JavaScriptの中括弧と大括弧についてまとめた

ネットで見たJavaScriptソースコードに
var arg = [this];
という記述があり、何を意味しているかわからなかった。
そこでJavaScriptの中カッコと大カッコについて調べた。
忘れないうちにブログにまとめておく。

中括弧 { }
・functionやif for構文などで、文のブロックをくくる。
var func = function(){
  ...
};

if ( ... ) {
  ...
} else {
  ...
}

・オブジェクトや連想配列(ハッシュ)を宣言する際に、メンバや要素をくくる。
var obj = {
  property1: 1,
  property2: "test",
  funciton1: function(){ ... }
};

var hash = { number: 1, "住所": "東京都", tel: "03-1234-5678"};

var a = {};
は、a は空のオブジェクトまたは連想配列(ハッシュ)である という意味。

大括弧 [ ]
・配列を宣言する際に要素をくくる
var arr = [1,3,"test"];

・配列、連想配列(ハッシュ)の添字や、オブジェクトのプロパティを指定する
var a1 = arr[1];
var h1 = hash["住所"];
var o1 = obj["property1"];

var b = [];
は、b は空の配列である という意味。

中カッコも大カッコもJavaScriptの正規表現で使用されるが、それについては略。

最初に書いた
var arg = [this];
は、「arg は要素がthisオブジェクト(が指す値)の配列である」 という意味だとわかった。
この場合のthisは、DOM要素が配列で格納されたjQueryオブジェクトだったので、arg はthisが指すDOM要素配列となる。
めでたしめでたし。

jQueryを使って、9個のボックスを3×3に配置

以下のようなページを作ろうと考えた。
「複数のボックスがあり、ボックスが一つずつ点滅する。
ボックスが点滅した順番にクリックすると点数が入る」
昔こんな記憶力ゲームがあったなぁと思って。

とりあえず、ボックスを9個、3×3に配置することにした。
やりかたの候補は以下の3つ。

・テーブルを使って配置
display: table; display: table-row; display: table-cell;
border-collapse: separate; border-spacing: 3px;
あたりを使う。

・floatを使って配置
float: left; clear: left;
margin-left: 3px; margin-top: 3px;
あたりを使う。

・positionを使って配置
position: absolute;
top: なんたらpx; left なんたらpx;
あたりを使う。

jQueryを使わずに、手打ちでHTMLとCSSを組んでやってみたところ、
テーブルもfloatも、行が変わるごとに display: table-row; や clear: left; を入れるのが何か気に入らない。
あと、テーブルもfloatもレイアウトの自由度が低い。
というわけで、positionを採用。

例によってHTMLには
<div class="main"></div>
だけ記述して、jQueryでボックスを配置した。

CSSは以下のとおり。
/* 背景 */
.main {
  display: block;
  border-style: solid;
  border-width: 1px;
  position: relative;
  margin-left: auto;
  margin-right: auto;
}

/* ボックス */
.box {
  display: block;
  border-style: solid;
  position: absolute;
}

JavaScriptのソースコードは以下のようになった。
当然と言えば当然なのだが、処理のほとんどがtopとleftの値を求める処理だ。
(function($) {
/* 定数 */
var aconst = {
  boxsidenum: 3,  // boxの一辺の個数 3x3
  boxwidth: 100,  // boxノードの width と height
  boxmargine: 3,  // boxノードの上左マージン
  boxbordwdh: 1  // boxノードの線の太さ
}
var boxcolord = new Array(略);  // boxの色

/* boxの行番号と列番号を求める
* boxnum boxの番号(1からの連番)
* return {raw: 行番号, col: 列番号}
*/
var getposition = function(boxnum){
  var rtnobj = {raw: 0, col: 0};
  if(isNaN(boxnum)){return rtnobj;}
  rtnobj.raw = Math.floor((boxnum -1) / aconst.boxsidenum) + 1;
  var remainder = boxnum % aconst.boxsidenum;
  if (remainder == 0){
    rtnobj.col = aconst.boxsidenum;
  }else{
    rtnobj.col = remainder;
  }
  return rtnobj;
};

$(document).ready(function() {
  // 親ノードを作成
  var $div = $("div.main:first");  // 親ノード
  var mainwidth;  // 親ノードの width と height
  mainwidth = aconst.boxsidenum * (aconst.boxwidth + aconst.boxmargine + aconst.boxbordwdh * 2) + aconst.boxmargine;
  $div.css({"width": mainwidth + "px", "height": mainwidth + "px"});
      
  // boxノードを作成
  var $box;  // boxノード
  var boxnum = aconst.boxsidenum * aconst.boxsidenum;  // boxの個数
  var boxposition;  // ボックスの行番号と列番号 {raw: 行番号, col: 列番号}
  var topval,leftval;  // boxノードのtopとleftの値
  for(var i = 0; i < boxnum; i++){
    $box = $("<div/>").addClass("box");
    boxposition = getposition(i+1);
    topval = (boxposition.raw -1) * (aconst.boxwidth + aconst.boxmargine + aconst.boxbordwdh * 2) + aconst.boxmargine;
    leftval = (boxposition.col -1) * (aconst.boxwidth + aconst.boxmargine + aconst.boxbordwdh * 2) + aconst.boxmargine;
    $box.css({"backgroundColor": boxcolord[i],
        "width": aconst.boxwidth + "px", "height": aconst.boxwidth + "px",
        "borderWidth": aconst.boxbordwdh + "px",
        "top": topval + "px", "left": leftval + "px"});
    $div.append($box);
  }
});

})(jQuery);
うわ、同名の変数boxnumを別の意味で使ってる。

これだけのことをやるのに1時間半かかりました。明日はどこまでできるかな。

jQueryでDOM要素を作成・追加してanimate

昨日の続き。

HTMLには
<div class="main"></div>
だけ記述して、クリックして動かすボックスをjQueryで作成することにした。

<2010/8/6 追記>
このページはソースコードを紹介しているだけです。
jQueryでDOM要素を作成し、DOMツリーを構築する方法については、こちらの記事で詳細をまとめました。
<追記ここまで>

cssは以下のとおり。
/* 背景 */
.main {
  display: block;
  width: 500px;
  height: 300px;
  position: relative;
  margin-left: auto;
  margin-right: auto;
}
/* 動かすボックス */
.box {
  display: block;
  width: 100px;
  height: 100px;
  position: absolute;
  left: 0px;
}

ボックス作成部分のソースコードは以下のようになった。
var boxcolor = new Array("#66FFFF","#66CCFF","#6699FF");  // 動かすboxの色

$(document).ready(function() {
  // 動かすboxを構築
  var $div = $("div.main:first");  // 親ノード
  var $box;  // boxノード
  for(var i = 0; i < boxcolor.length; i++){
    $box = $("<div/>").addClass("box");
    $box.css("background-color",boxcolor[i]);
    $box.css("top",String(100 * i) + "px");
    $div.append($box);
  }
  $("div.box").click(movebox);
});

ボックスをクリックしたときの動作部分は以下のとおり。
右側に動いたのをクリックすると左側に戻る処理をどうやって実装しようかと考えたが、安易にフラグを使用した。
/* 定数 */
var aconst = {
  moveAttr: "moved",    // 要素にセットする属性名
  moveAfter: "400px",    // move後の offset left
  moveBefore: "0px",    // move前の offset left

  pdur: "normal",    // animateのduration 数値で指定する場合はミリ秒
  peasing: "swing"  // animateのeasing
}

var movebox = function(){
  var movedflg = $(this).attr(aconst.moveAttr);  // move後 "true" move前 "false"
  var leftval;  // animate後のleftの値
  if(movedflg == "true"){
    // move後
    leftval = aconst.moveBefore;
    movedflg = "false";
  }else{
    // move前
    leftval = aconst.moveAfter;
    movedflg = "true";
  }
  $(this).animate({left: leftval}, aconst.pdur, aconst.peasing,
    function(){$(this).attr(aconst.moveAttr,movedflg);} );
}

true/false のフラグを該当ボックスの属性にセットするのだが、セットするとbooleanではなくstringになるので怪しいソースになってしまった。フラグの値を"right","left"にした方がよかったか。

今日は大してハマらずにサクサクできた。jQueryのプラグインを1つ読んだことがかなり効いてる。

jQueryで何か動かすものを作ってみたが・・・

jQueryの animate 関数を使って何か動くページを作ることにした。
とりあえず、<div>でボックスを作ってそれを動かすことにする。

append関数などを使って、jQueryでガシガシとDOMを構築しようと思ったが、思ったイメージを実現するのに時間がかかり断念。
ゼロから作るのだから、細かく分けて少しずつ実現していこう。
ということで、ボックスはHTMLに直接書いて、属性はCSSに直接書いた。

書いたJavaScriptコードはこれだけ。
(function($) {

var animetest = {
  movebox: function(){
  $(this).animate({left: "400px"});
  }
}

$(document).ready(function() {
  $("div.box1").click(animetest.movebox);
});

})(jQuery);

わざわざ animetest.movebox を外部で定義しなくても、これだけなら
$("div.box1").click(function(){$(this).animate({left: "400px"});});
でいいんだけど、これから機能を追加していく予定なので。

Firebugを使ってテストしてみたら見事にハマった。
animate関数を使うところにブレイクポイントをセットして、jQueryの中へステップインするとアニメーションされない。
そして一時的にCPU使用率が100%になって固まる。
実行ステップを見てると、何となく変な動きをしている。
jQueryの中へステップインしなければきちんとアニメーションされる。
ネットで調べてみたところ、Firebugのバグっぽい?よくわからないので放置。

今日調べてわかったCSSのテクニック
・text-align: center; のように、ブロック要素を中央揃えで表示する方法
margin-left: auto;
margin-right: auto;
をCSSで設定する。
ただしIE6では中央揃えが行われない場合がある。
IE6対策方法もあったけど、CSSが複雑になるので多分自分は使わない。

CSS2の勉強とりあえず一段落

CSS とはなんだろうかを読了。
テーブル関連は「使うときにちゃんと見よう」と読み飛ばしたが、それ以外は一応理解できるまで読んだ。
理解が怪しいところはここでサンプルの動作確認をした。

floatで段組してるCSSを見て、なぜ段組ができるかを理解できる程度にはなった。

実際に使ってみないことには身につかないので、何か作ってみたいのだが、これと言って作りたいものが浮かばない。
使い道のあるページじゃなくて、とりあえず何か動かしてみるテストページでも作るか。

CSSの max-width/min-width/max-height/min-height についてまとめてみた

昨日に引き続き、CSS とはなんだろうか を読んだ。
displayやpositionといった視覚フォーマットモデルに関する部分は、文章を読むだけでは理解しづらい。
サンプルを例示している以下のサイトが役に立った。
スタイルシート(CSS)|PHP & JavaScript Room

今日は max-width/min-width/max-height/min-height でハマった。
widthやheightの値がこの範囲で変化するのだが、「何によって変化するのか?」がわからなかった。
そこで次のようなテストページを作ってwidth/height関連の値を変化させて実験してみた。
(前略)
<style TYPE="text/css">
<!--
.parent { max-width: 500px; min-width: 200px; max-height: 30em; min-height: 20em; background-color: green;}
.child { width: 300px; height: 40em; background-color: yellow;}
-->
</style></head>
<body>
<div class="parent"><div class="child"></div></div>
</body></html>
結果は次のようになった。

<注意>Firefox3.6.7での結果です。他のブラウザでは異なる結果になるかもしれません。
以下は、親要素が<body>の要素についてです。
・要素のwidth
ウインドウの大きさによって変わる。子要素のwidthには無関係。
ウインドウの大きさに合わせて、min-width から max-width まで変化する。
ウインドウを大きくするにつれて大きくなり、最大max-widthまで大きくなる。
ウインドウを小さくするにつれて小さくなり、最小min-widthまで小さくなる。(それよりもウインドウが小さくなると横スクロールバーが表示される)
子要素のwidth > 親要素のwidth の場合、子要素がどう表示されるかは親要素のoverflowに従う。

・要素のheight
子要素のheightによって変わる。ウインドウの大きさには無関係。
子要素のheight < min-height の場合、要素のheightは min-height になる。
max-height > 子要素のheight > min-height の場合、要素のheightは子要素のheightになる。
子要素のheight > max-height の場合、要素のheightは max-height になる。
子要素のheight > max-height の場合、子要素がどう表示されるかは親要素のoverflowに従う。

widthとheightの動作がこのようにまるっきり違うことは、HTMLにちょっと詳しい人には常識なんだろうな。
そんなわけで、今日は3時間かけて 2-4.視覚効果 までしか読めませんでした。

CSS2の勉強開始

CSS2の勉強に着手した。
前回のブログから2日間の空白があるが気にしない。

とりあえず、このサイトを一通り読んでみる。
CSS とはなんだろうか
last modified: 04th/Apr./2004 というのが気になるが、CSS2なので特に古くは無いのかなと思う。

1時間半ほど読んで、2.1 ボックス・モデル まで読了。
あと3時間ほどかければ全部読めるかな。

CSSを動的に変化させて動きのあるページを作るための勉強だが、
どんなページを作ろうかイメージが湧いてこない。
勉強しているうちに湧いてくるだろうか。

jQueryプラグインのソースコードを読む(4日目にして完了)

昨日に引き続き、あるjQueryプラグインのソースコードを読んだ。
調べることもあまり無く、244行(空行コメント行含む)を1時間かけて読み、晴れてソースコードを読了した。

4日間(計9時間)かけてソースコードを読んで
 var $obj = $('<div/>') のようにjQueryオブジェクトを作成して、
 DOM操作系のjQuery関数をガンガン使ってDOMを構築するテクニック
を学んだ気になった。

CSSと animate 関数を使って何か作りたいけど、明日は時間取れるかなぁ。
プロフィール

himax64

Author: 南西
30代後半の無職です。
就活もせずダラダラ生きてます。
作ったもの

最新記事
人気記事
検索フォーム
カテゴリ
月別アーカイブ
最新コメント
最新トラックバック
RSSリンクの表示
QRコード
QRコード
カウンター