JavaScript の EventListener における this について
Firefox 3 にて検証。
あるオブジェクトに属するメソッド(関数オブジェクト)をイベントリスナーとして登録した場合、その登録の方法によってメソッド内で使用される this の意味が違ってくるよという話。
まずはこんなオブジェクトをつくってみる
// MyEventListener オブジェクト作成 var MyEventListener = function() { return this} // MyEventListener オブジェクトにonMouseClickメソッドを追加 MyEventListener.prototype = { onMouseClick: function() { alert(this); } //←ここの this が今回の主役 } // MyEventListener から myEventListener オブジェクトを作成 var myEventListener = new MyEventListener();
そして、myEventListener.onMouseClick をイベントリスナーとして登録してみる
イベントリスナーとして素直に関数名を表記した場合
アラートには "[object HTMLParagraphElement]" と表示される。
この場合、 this = イベントリスナーが登録されたターゲット 。
var div = getElementById("div"); div.addEventListener("click", myEventListener.onMouseClick, false);
イベントリスナーとして無名関数を使用した場合
アラートには "[object Object]" と表示される。
この場合、 this = イベントリスナーオブジェクト 。
var div = getElementById("div"); div.addEventListener("click", function() { myEventListener.onMouseClick() }, false);
いったん無名関数を間にはさむので this の意味が違ってくるのは当然といえば当然なんだろうけど、注意しないといろいろと面倒なことになりそうなのでメモしておきます。
(追記) Mozilla Developer Center に関連情報が書いてあった
https://developer.mozilla.org/ja/DOM/element.addEventListener
メモリに関する問題
メモリ使用量が増大する問題を引き起こす方法に共通していることは、オブジェクトのメソッドをコールバックとして渡すことです。
setTimeout(obj.func, 1000); // |this| が間違って設定される!
document.addEventListener("load", obj.func, false); // |this| が間違って設定される!単純な回避策としては、無名関数をコールバックとして渡す方法があります。
document.addEventListener("load", function(event) { obj.func(event); }, false);
注意すべきなのは、この無名関数はそれを内包する環境にある全ての変数にアクセスすることができ、それらの変数が使用するメモリは、その無名関数が使われる可能性がある限りは (つまりイベントリスナが登録されている限りは) JavaScript エンジンによって解放されないということです。この関数に対して維持される必要があるのは実際には obj だけなのに、JavaScript エンジンは他の変数も維持する事を選択し、その結果メモリの負荷が増大します。removeEventListener を呼び出すか無名関数への参照を全て削除すれば、変数の消費するメモリが解放されるようになります。なので忘れずにそれを行ない、使用されていないメモリが JavaScript エンジンによって効率的に解放されるようにして下さい。
JavaScript で SVG の角を丸める方法のメモ
二次スプライン曲線を利用して少ない手間で角を曲げる方法。
Firefox 3.0.5, Safari 3.2.1, Opera 9.63 にて動作確認済み。
参考サイト
http://www.geocities.co.jp/Playtown-Denei/7552/ScriptLib/roundRoC.html
http://hakuhin.hp.infoseek.co.jp/main/as/math.html
ソース (roundEdge.xml)
<?xml version='1.0'?> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg"> <head> <title>JavaScript で SVG の角を丸める</title> <script type="text/javascript"> <![CDATA[ function roundEdge(path, radius) { //パスをリセット resetPath(); //各ポイントの取得 var A = path.pathSegList.getItem(0); //左の点 var B = path.pathSegList.getItem(1); //真ん中の点 var C = path.pathSegList.getItem(2); //右の点 //任意の2点から角度を割り出す var angle1 = Math.atan2(B.y - A.y, B.x - A.x); //A,B間の角度 var angle2 = Math.atan2(C.y - B.y, C.x - B.x); //B,C間の角度 //二次スプライン曲線用のポイントB1とB2を割り出す var B1x = B.x - (Math.cos(angle1) * radius); var B1y = B.y - (Math.sin(angle1) * radius); var B2x = B.x + (Math.cos(angle2) * radius); var B2y = B.y + (Math.sin(angle2) * radius); //二次スプライン曲線を利用して角を丸める path.setAttribute('d', 'M '+A.x+','+A.y+' L '+B1x+','+B1y+' Q '+B.x+','+B.y+' '+B2x+','+B2y+' L '+C.x+','+C.y); } function resetPath() { document.getElementById('path').setAttribute('d', 'M 73.574464,78.567376 L 172.96453,26.936173 L 509.85816,121.16312'); return false; } function round() { var path = document.getElementById('path'); var radius = Number(document.getElementById('radius').value); if(radius <= 0 || isNaN(radius)) { window.alert('正数を入力してください。'); return false; } roundEdge(path, radius); return false; } ]]> </script> </head> <body> <h1>JavaScript で SVG の角を丸める</h1> <form action="./" onreset="return resetPath();" onsubmit="return round();"> <input type="text" id="radius" value="20" /> <input type="submit" name="submit" value="角を丸める" /> <input type="reset" value="リセット" /> </form> <p> <svg:svg width="600" height="300"> <svg:path d="M 73.574464,78.567376 L 172.96453,26.936173 L 509.85816,121.16312" id="path" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> </svg:svg> </p> </body> </html>
JavaScript で Mac OS X のバージョンを調べる方法
Safari 3 と Firefox 3 で確認済み。(Opera では動作しない*1 )
var _userAgent = navigator.userAgent; // UserAgent を取得 if(_userAgent.indexOf("Mac") != -1 ){ // Mac かどうか判断 var _osVersionSplit = _userAgent.split(" ")[7].split(/[\._;]/); //バージョン部分を分解 var _osVersion = _osVersionSplit[0] + '.' + _osVersionSplit[1]; //バージョンを再結合 } // バージョン判断 if(_osVersion == "10.5") { alert("OS X 10.5 です。"); } else { alert("OS X 10.5 ではありません。"); }
暫定で作ったので、もっとスマートな方法があったら教えてください。
jsViz で画像表示
よしたんのブログ jsViz を試す を参考にしました。
よしたんのブログでは SVG で画像表示してましたが、htmlでの表示方法がわかったのでメモします。
まず JavaScript の変更
サンプルの html中にある JavaScript の以下の箇所を変更する。
nodeElement.style.backgroundImage = "url(http://kylescholz.com/cgi-bin/bubble.pl?title=&r=12&pt=8&b=888888&c=" + color + ")";
↓
nodeElement.style.backgroundImage = "url("+dataNode.image+")";
つぎに xml の変更
これはよしたんのブログに書いてあった方法そのまんま。
やることは、node要素にimageプロパティを追加するだけです。
<root root="true" fixed="true" image="./a.png" color="black"> <node image="./b.png" color="black"></node> <node image="./b.png" color="black"> <node image="./b.png" color="black"></node> <node image="./b.png" color="black"></node> </node> <node image="./b.png" color="black"></node> </root>
JS LOOKBOOK ウィンドウのサイズに併せて拡大縮小するようにした
ブラウザウィンドウのサイズに併せて、ギャラリーが拡大縮小するようにしてみた。*1
http://ynakajima.net/jslookbook/
※Firefox2,IE6,Safari3,Opera9 で確認済み。*2
ウィンドウサイズ取得に関してのメモ
jQuery でウィンドウの高さを取得する場合 $(window).height() と書けばいいはず。
しかし、Firefox だと $(document).height() と同じ値が帰ってくるという困った現象に遭遇。
しょうがないので、windowサイズ取得部分は自力で書いてみた。
if(jQuery.browser.opera) { //Opera (document.documentElement.clientHeightが存在するため先に処理) var _height = document.body.clientHeight; } else if(typeof document.documentElement.clientHeight == 'number') { //Firefox IE Safari3 var _height = document.documentElement.clientHeight; } else if(typeof window.innerHeight == 'number') { //Safari2 var _height = window.innerHeight; } else { //その他のブラウザの場合 var _height = 600; }
JS LOOKBOOK を IE に対応させてみた
昨日つくった、UNIQLO LOOKBOOK の JavaScript版 JS LOOKBOOK を IE に対応させてみた。
http://ynakajima.net/jslookbook/
変更した箇所
- スクロールする部分(#gallery)がはみ出て表示されてしまっていた
- #gallery の親要素 #lookbook に overflow: hidden を指定していたのに反映されていない模様。
- #gallery を div要素でラッピングして、ラッピングした div要素に overflow: hidden; position: relative; widh: 1020px を指定したら解消。
- 参考 http://cssbug.at.infoseek.co.jp/detail/winie/b068.html
UNIQLO の LOOKBOOK を JavaScript で実装してみた
年末年始の課題の一つ、「Flash の勉強として UNIQLO LOOKBOOK をそっくりそのまま作ってみる」に着手する。
しかし、いきなり Flash でやるのも芸がないので使い慣れている JavaScript で試しに実装してみた。
http://ynakajima.net/jslookbook/
※使用している画像は flickr から持ってきた Creative Commons ライセンスのもの。