
前回の雛型ひな形には問題があると書きました。クリックして穴が開いたら、その穴の部分をクリックしてみてください。左上に穴が開いてしまいますよね。
この原因はなんでしょう?
座標取得にはevent.offsetXとevent.offsetYを使用しました。これには「イベントを呼び出したエレメント上の位置の取得」とありますね。onclickイベントハンドラはgbox0エレメントにあります。穴が開いた時にはana1.gif画像とana2.gif画像がその子エレメントとして存在します。穴画像部分をクリックすると、実際にイベント発生したエレメントは穴画像のエレメントなのです。するとこの穴画像上の座標がzxとzyに入ります。gbox0上の座標ではなくなるんですね。
ではこれを解決するには?
event.offsetXとevent.offsetYを使用せず、event.xとevent.yを使用します。
修正案
[ソース]
<HTML>
<head>
<meta http-equiv="content-type"
content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type"
content="text/css">
<title>Gunshot</title>
</head>
<body
id="body1" style="margin:0px; padding:0px; overflow:hidden">
<img
src="aki1.jpg" id="gazou1" style="position:absolute;
z-index:1; top:0px; left:0px; width:expression(document.body.clientWidth); height:expression(document.body.clientHeight)">
<div
id="gbox0" onclick="imgadd()"
style="position:absolute; z-index:2; left:0px; top:0px;
filter:chroma(color=#ff0000); width:expression(document.body.clientWidth); height:expression(document.body.clientHeight)">
<img id="img2" src="aki2.jpg"
style="position:absolute; z-index:1; top:0px; left:0px; width:expression(document.body.clientWidth);
height:expression(document.body.clientHeight)"></div>
<img
id="a1" src="ana1.gif" style="width:50px; height:50px; visibility: hidden;">
<img
id="a2" src="ana2.gif" style="width:50px; height:50px; visibility: hidden;">
<script>
var zx
var zy
function imgadd(){
zx=event.x
zy=event.y
status="X座標="+zx+";
Y座標="+zy
gbox0.insertAdjacentHTML("BeforeEnd","<img
src='"+a1.src+"'
style='position:absolute; left:"+(zx-74)+"px;
top:"+(zy-72)+"px;
z-index:1'><img
src='"+a2.src+"'
style='position:absolute; left:"+(zx-59)+"px;
top:"+(zy-59)+"px;
z-index:2'>")
}
</script>
</body>
</html>
「ダブルクリックで大きな穴が開く。」今回のテーマです。
ダブルクリック・・・ondblclickというイベントハンドラがありますので、これを使用します。今回はダブルクリックの時とクリックの時に同じ関数を使用することにします。但し、クリックなのか、ダブルクリックなのか、区別するための手段が必要です。そこで関数に引数を与えて実行させることを学びます。
引数・・・パラメータとも呼びます。関数に値を与えて実行させる際に、その値を受け取るための器を引数といいます。変数同様の使い方をしますが、その関数内でしか利用できません。
function 関数名(引数1,引数2,・・・){処理}
処理の部分で引数を変数のように使用して、呼び出し側から与えられた値を引数に受け取り処理します。
<script>
function menseki(r){
status="円の面積="+Math.PI*r*r
}
menseki(12)
</script>
上の例では関数menseki()のrが引数です。menseki(12)という命令により、12という値を引数rに受け取ります。処理の部分はステータスバーに円の面積を計算して表示するものです。menseki(15)を呼び出せば半径15の円の面積が求められますね。
引数は,で区切り複数作成できます。
imgadd()関数に引数を作成し、クリックの時は引数として1を、ダブルクリックの時は引数に2を与えるようにしてはいかがでしょう?この引数の値を表示サイズの拡大率に使えないか・・・な?
引数をscとして書き換えてみましょう。leftとtopの位置計算部分はsc分乗算してしまえばよさそうですね。サイズも変えなければならないので、元々のサイズ(ana1.gifは152×152、ana2.gifは118×118でした)からsc分乗算しましょう。
function imgadd(sc){
zx=event.x
zy=event.y
status="X座標="+zx+";
Y座標="+zy
gbox0.insertAdjacentHTML("BeforeEnd","<img
src='"+a1.src+"'
style='position:absolute; left:"+(zx-74*sc)+"px;
top:"+(zy-72*sc)+"px;
z-index:1; width:"+152*sc+"px; height:"+152*sc+"px'><img
src='"+a2.src+"'
style='position:absolute; left:"+(zx-59*sc)+"px;
top:"+(zy-59*sc)+"px;
z-index:2; width:"+118*sc+"px; height:"+118*sc+"px'>")
}
クリックでは等倍ですから、onclick="imgadd(1)"として引数に1を渡します。ダブルクリックの時は3倍にしましょうか?ondblclick="imgadd(3)"でいかが?気に入らなければ引数に渡す値を変えるだけです。
[ソース]
<HTML>
<head>
<meta http-equiv="content-type"
content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type"
content="text/css">
<title>Gunshot</title>
</head>
<body
id="body1" style="margin:0px; padding:0px; overflow:hidden">
<img
src="aki1.jpg" id="gazou1" style="position:absolute;
z-index:1; top:0px; left:0px; width:expression(document.body.clientWidth); height:expression(document.body.clientHeight)">
<div
id="gbox0" onclick="imgadd(1)"
ondblclick="imgadd(3)" style="position:absolute; z-index:2; left:0px; top:0px;
filter:chroma(color=#ff0000); width:expression(document.body.clientWidth); height:expression(document.body.clientHeight)">
<img id="img2" src="aki2.jpg"
style="position:absolute; z-index:1; top:0px; left:0px; width:expression(document.body.clientWidth);
height:expression(document.body.clientHeight)"></div>
<img
id="a1" src="ana1.gif" style="width:50px; height:50px; visibility: hidden;">
<img
id="a2" src="ana2.gif" style="width:50px; height:50px; visibility: hidden;">
<script>
var zx
var zy
function imgadd(sc){
zx=event.x
zy=event.y
status="X座標="+zx+";
Y座標="+zy
gbox0.insertAdjacentHTML("BeforeEnd","<img
src='"+a1.src+"'
style='position:absolute; left:"+(zx-74*sc)+"px;
top:"+(zy-72*sc)+"px;
z-index:1; width:"+152*sc+"px; height:"+152*sc+"px'><img
src='"+a2.src+"'
style='position:absolute; left:"+(zx-59*sc)+"px;
top:"+(zy-59*sc)+"px;
z-index:2; width:"+118*sc+"px; height:"+118*sc+"px'>")
}
</script>
</body>
</html>
クリックで普通サイズ、ダブルクリックで三倍
・・・面積比では9倍です。
参考:もしscに小数点を含む場合どうなるか、皆さん確認してみてくださいね。onclick="imgadd(1.3)"などにしてみるのもleftやtopあるいはwidthやheightに小数点が含まれる場合どうなるのか確認できることでしょう。・・・小数点以下は無視されるが答えです。
クリックまたはダブルクリックすると「バキューン」と音が出る
メールに使用するということで対策しなければなりません。OutlookExpressは、imgタグのsrc属性とbgsoundタグのsrc属性及びbodyのbacground属性に指定されたファイルしか取り込みません(HTMLに使っているファイルとして送れない)。
またその属性においてもファイルの種類に制限があります(bgsoundのsrcではmidiファイルかwavファイルのみ)。
ここではwavファイル(gun.wav)を添付されるようにしてクリックまたはダブルクリックの時のみ再生するようにします。
およそ見当は付いていると思いますが、関数imgadd()の処理部分で再生できるようにしておけば、クリックまたはダブルクリックで音が出ます。
まずbgsoundタグでwavファイルを再生するようにします。スクリプトでbgsoundエレメントを操作しますから、やはりidをつけましょう。bgsoundタグでの属性として、再生回数(loop)と音量(volume)、及びバランス(balance)があります。
bgsoundタグはhead内だけで使用できるとMSDNにはありますが、実際にはbodyタグ内に書いても問題ありません。
音量は-10000〜0で、0で最大-10000で最小です。loopは再生回数を指定します。
「loop属性:1以上の値で回数指定します(loop=5など)。loop属性を省略した時またはloopまたはloop=0とすると一回になります。-1またはimfiniteを指定すると無限繰り返し再生します(loop=infinite)。loop=とすると0回になります。」・・・MSDNより。しかし現在(ie6)では0回というのはだめなようです。英語MSDNには1回になっており、翻訳された日本語MSDNは間違いが時々見つかるので注意ください。
ここではkoop=1とします。値は""で囲んでもokです(loop="3")。
<bgsound id="bang" src="gun.wav" loop="1" volume="0">
スクリプトでこのサウンドのsrcを変数soundに入れます。そしてすぐにこのsrc属性値をNULL(何も入っていない状態)にします。NULLにするには""を代入します。
<script>
var sound=bang.src
bang.src=""
</script>
このbgsoundタグで音を再生するにはbangエレメントですからsrcに変数soundの内容を与えます。これはimgadd()関数に入れるのはお分かりですね。
bang.src=sound
ということで完成させましょう。
[ソース]
<HTML>
<head>
<meta http-equiv="content-type"
content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type"
content="text/css">
<title>Gunshot</title>
</head>
<body
id="body1" style="margin:0px; padding:0px; overflow:hidden">
<bgsound
id="bang" src="gun.wav" loop="1"
volume="0">
<script>
var
sound=bang.src
bang.src=""
</script>
<img
src="aki1.jpg" id="gazou1" style="position:absolute;
z-index:1; top:0px; left:0px; width:expression(document.body.clientWidth); height:expression(document.body.clientHeight)">
<div
id="gbox0" onclick="imgadd(1)" ondblclick="imgadd(3)"
style="position:absolute; z-index:2; left:0px; top:0px;
filter:chroma(color=#ff0000); width:expression(document.body.clientWidth); height:expression(document.body.clientHeight)">
<img id="img2" src="aki2.jpg"
style="position:absolute; z-index:1; top:0px; left:0px; width:expression(document.body.clientWidth);
height:expression(document.body.clientHeight)"></div>
<img
id="a1" src="ana1.gif" style="width:50px; height:50px; visibility: hidden;">
<img
id="a2" src="ana2.gif" style="width:50px; height:50px; visibility: hidden;">
<script>
var zx
var zy
function imgadd(sc){
bang.src=sound
zx=event.x
zy=event.y
status="X座標="+zx+";
Y座標="+zy
gbox0.insertAdjacentHTML("BeforeEnd","<img
src='"+a1.src+"'
style='position:absolute; left:"+(zx-74*sc)+"px;
top:"+(zy-72*sc)+"px;
z-index:1; width:"+152*sc+"px; height:"+152*sc+"px'><img
src='"+a2.src+"'
style='position:absolute; left:"+(zx-59*sc)+"px;
top:"+(zy-59*sc)+"px;
z-index:2; width:"+118*sc+"px; height:"+118*sc+"px'>")
}
</script>
</body>
</html>
完成です。
ついでながら12回でinnerHTMLでも可能と書きましたが、実際にはできませんでした。原因はダブルクリックではクリックイベントも発生します。クリック処理でプロパティ書き換えがされている時にダブルクリック処理がされないようです。
gbox0.innerHTML+="<img src='"+a1.src+"' style='position:absolute; left:"+(zx-74*sc)+"px; top:"+(zy-72*sc)+"px; z-index:1; width:"+152*sc+"px; height:"+152*sc+"px'><img src='"+a2.src+"' style='position:absolute; left:"+(zx-59*sc)+"px; top:"+(zy-59*sc)+"px; z-index:2; width:"+118*sc+"px; height:"+118*sc+"px'>"
これはa+=b・・・a+bをaに代入すると同じで、gbox0.innerHTML=gbox0.innerHTML+"テキスト"
結局現在のinnerHTMLの内容はそのままに書き足すような処理になります。
クリックで普通サイズ、ダブルクリックで三倍:音付きのinnerHTML版
・・・ダブルクリックはだめですね。
このひな形ではクリックとダブルクリックの衝突でだめですが、innerHTMLでの手段もありえます。
さて講座11で「@包括エレメントに含まれるサブエレメントをオブジェクトとして扱う」は後で説明すると書きましたので、ここで説明します。僕のHTMLメールひな形作成ソフト「ぴあにしも」では、素材として登録した時にimgエレメントにHTMLではidをつけておりません。idはスクリプトで後から付け足しています。一方、OutlookExpressではimgエレメントにidをつけていても。編集画面で画像を変更してしまうと、idが消えてしまいます。idを使ってimgエレメントを参照する必要がある時にidが消えてしまうと都合が悪いので、スクリプトでidを付加するように設計しました。
そこでidを後から付加する方法を説明します。
<img src="hogehoge.jpg">
<img src="hoge.gif">
このような場合にidを追加したいわけですが、どうすればいいのか考えます。
InternetExplorerのDHTML機能として、HTMLドキュメント上の全ての要素に対してアクセスできるよう設計されているとあります。実際にドキュメント上のあらゆるエレメントやテキストなどにアクセスするための機能を提供しています。
例えばドキュメント上のエレメントはdocument.allによりbodyに限らずhead内にあるタグに対してもアクセスできます。
下記ボタンをクリックするとこのページのタイトルが出ます。
[ソース]
<p><input type="button" name="b1" value="タイトルは?"
onclick="alert('このページのタイトルは「'+tn[0].innerHTML+'」です。')"></p>
<script>
var
tn=document.all.tags("title")
</script>
前置きが長くなりました。
imgエレメントを配置し、そのimgエレメントにidを付加します。
<img src="hogehoge.jpg">
<img src="hoge.gif">
<script>
var imgtag=document.all.tags("img")
imgtag[0].setAttribute("id","hogehoge")
imgtag[1].setattribute("id","hoge")
</script>
setAttributeメソッドのMSDN解説をみましょう。
パラメータ 解説 attrName 属性名を指定する。 value 属性に設定する文字列、数字、論理値。 caseSensitive オプション。大文字小文字を区別して属性を検索するかどうかを論理値で指定する。TRUEの場合はattrNameでの大文字小文字を区別し、指定した通りの名前を持つ属性だけを見つける。このパラメータのデフォルトはTRUEである。省略可能。
複数の属性が同じ名前(大文字小文字でのみ区別できる)を持っていて、caseSensitiveがFALSEの場合、このメソッドは最初の属性(最初の属性がこの名前で作られているものとする)に値を設定する。他の全ての同じ名前の属性は無視される。
このことを理解した上で、ソースを見ます。
var imgtag=document.all.tags("img")・・・これはimgtagという変数(オブジェクト)を用意し、ドキュメント上のimgタグであるエレメントをコレクションとしてimgtagに入れます。これによりimgエレメント全てがimgtagに入ります。imgエレメントはimgtagのコレクションとしてインデックス番号で扱えるようになります。
imgtag[0].setAttribute("id","hogehoge")・・・インデックスが0であるエレメントに"hogehoge"というidをセットします。
imgtag[1].setattribute("id","hoge")・・・インデックスが0であるエレメントに"hoge"というidをセットします。
HTMLドキュメント上に現れる順番にコレクション番号は0から付いていきます。object[インデックス番号]でエレメントを示すことが可能になります。
「応用」
allとchildrenの違いは既に講座11で説明しました。エレメントとしてのオブジェクトの最上位はdocumentになります。
「質問」:idがdiv1のエレメントが包括エレメントになっている場合、その内包されているエレメントにidを番号付きでつけなさい。付加するidはchild0のようにchildにコレクション番号付きにすること。
「考え方」
div1エレメントに含まれる内包エレメントはいくつあるのか、またそのタグ名はなんなのかまったくわかりませんね。それでもidをつけよという質問です。
ますdiv1エレメントの内包エレメントをdiv1エレメントのコレクションとしてオブジェクト変数に入れましょう。
var div1c=div1.all
次は、div1に内包されるエレメントの総数はいくつになるのかですが、これも実は既に説明済みです。コレクションの数はlengthプロパティで取得できますね。
従ってオブジェクトdiv1cのコレクション数はdiv1c.lengthです。
一番目のエレメントにはchild0と付けなさい、二番目はchild1というidを付けなさい。・・・・最後尾のエレメントは?childという文字列にコレクション総数の1引いた数値を連結すればいいことに気がつきます。何故なら一番目が0、二番目が1、div1c.length番目がdiv1c.length-1ですから。例えば総数が10個あれば最後尾のコレクション番号は9です。
ということで"child"+番号をidにしてしまえということになります。
変数(ここではiを用いました)を用いてそのiが0からスタート。idを"child"+iとしてセットすればいいわけです。iはdiv1c.length-1になるまでという条件付になります。
if条件分岐構文でも可能ですが、for〜繰り返し構文で解答例です。
※コレクションの要素全てを掌握して処理できるfor〜inでも可能です(実はその方が総数を調べるlengthが必要なく簡単ですが、内容的には混乱するので割愛)。
<script>
var div1c=div1.all
for(i=0;i<div1c.length;i++){
div1c[i].setAttribute("id","child"+i)
}
</script>
サンプルのソース
<HTML>
<head>
<meta http-equiv="content-type"
content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type"
content="text/css">
<title>setAttribute</title>
</head>
<body>
<div
id="div1">
<img
src="aki2.jpg">
<img src="ana1.gif">
<img src="ana2.gif">
<div>
<img src="aki1.jpg">
</div>
<p>サブエレメントのタグ名を調べる</p>
</div>
<script>
var
str=""
var div1c=div1.all
for(i=0;i<div1c.length;i++){
div1c[i].setAttribute("id","child"+i)
str+="idが"+div1c[i].id+"のタグ名は="+div1c[i].tagName+"です。<br>"
}
document.write(str)
</script>
</body>
</html>
※object.tagName・・・エレメントのタグ名を取得する(Nが大文字であることに注意!)---()がないのでプロパティ
音楽や音を何かのアクションに結び付けて再生したい場合は、bgsoundタグにidを付けておけば、扱いが楽になります。しかし、OEではサウンドファイル参照はフルパスでなければなりません。厄介なことにOE編集画面で「書式」=>「背景」=>「サウンド」から音を付け直した場合もidが消えてしまいます。setAttribute()メソッドでidを後からつける方法は、この場合にもとても便利です。
<bgsound src="midiファイル(フルパスで)" volume="0"
loop="inifinite">
<bgsound src="サウンドファイル(フルパスで)wav"
volume="0" loop="1">
<script>
var sound=document.all.tags("bgsound")
sound[1].setAttribute("id","bang")
var
gunshot=bang.src
bang.src=""
</script>
midiファイルがある場合、またはmidiファイルを後からつける可能性がある場合、bgsoundタグを二つ記述しましょう。一番目のbgsoundエレメントの内容はOEの編集画面で、「書式」=>「背景」=>「サウンド」から選択したファイルがsrcとして入ります。もしこのダミーbgsoundタグがないと、wavを付けたいbgsoudタグのsrcが書き換えられてしまいます。
soundという配列オブジェクトにはドキュメント上にある全てのbgsoundエレメントがコレクションとして要素に加わりますね。
sound[1]は二番目のbgsoundエレメントを指しますから、そのエレメントにbangというidをセッティングします。
gunshotという変数にはbangエレメントのsrcが入ります。
bangエレメントのsrcはgunshot変数に保存しているので、bangエレメントのsrcをNULLにします。
後は音を再生したい部分でbang.src=gunshotを実行させればいいことがわかります。
midi側bgsoundエレメントはsound[0]であることは言うまでもありません。
次回からマウスカーソルにまつわりつく、マウスチェイサーを題材にしてみます。