DD; Custom Click Validator

クリックする要素が矩形でない場合、ほんとうにその要素をつかんだかどうかを厳密に判別したい場合があると仮定する。

このような場合に使用するのが、TAHOO.util.DDによういされたclickValidator()。
YUIのサンプルは、クリックする対象を円(gifで描画されたもの)として、この使い方を概説している。
画面は以下。

ソースコードは平易なので、注釈つきの全文を以下に示す。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>Ajax_Sampling</TITLE>
<style type="text/css"> 
/* 全体に関わるスタイル */
.dd-demo {
    position:relative;
    border:4px solid #666;
    text-align:center;
    color:#fff;
    cursor:move;
    height:100px;
    width:100px;
}

/* 円のスタイル */
#dd-demo-1 { 
    background:url(scripts/yui/dragdrop/assets/circle.gif) 0 0 no-repeat;
    border:0px solid black;
    z-index:10;
    cursor:default;
}

/* 矩形のスタイル */
#dd-demo-2 { 
    background:#A0B9A6;
    top:10px; left:180px;
    border:0px solid black;
    cursor:default;
}
</style>

<!-- 読み込むjs --> 
<script type="text/javascript" src="scripts/yui/yahoo-dom-event/yahoo-dom-event.js" >
</script> 
<script type="text/javascript" src="scripts/yui/dragdrop/dragdrop-min.js" >
</script> 
<script type="text/javascript" src="scripts/yui/animation/animation-min.js" >
</script> 

<script type="text/javascript">
// 変数定義とAlias
var dd, dd2, clickRadius = 46, startPos,
Event=YAHOO.util.Event, Dom=YAHOO.util.Dom;

YAHOO.util.Event.onDOMReady(function() {

	// 円の要素オブジェクトの取得
	var el = Dom.get("dd-demo-1");
	// 開始位置の退避
	startPos = Dom.getXY(el);

	// 円をDDオブジェクトとする。
	dd = new YAHOO.util.DD(el);

	// our custom click validator let's us prevent clicks outside
	// of the circle (but within the element) from initiating a
	// drag.
	// DD.clickValidatorのOverride.
	dd.clickValidator = function(e) {

    	// DDオブジェクトの占めるRegion(矩形)を得る。(1)
    	var el = this.getEl();
    	var region = Dom.getRegion(el);

    	// get the radius of the largest circle that can fit inside
		// (訳)以下の幅、高さの領域に入る最も大きい円の半径を得るには、
    	// var w = region.right - region.left;
    	// var h = region.bottom - region.top;
    	// var r = Math.round(Math.min(h, w) / 2);
    	//-or- just use a well-known radius
		// で求めるか、もしくは、よく知られた(既知の)直系を用いる。
    	var r = clickRadius;

    	// クリックされた位置の取得
    	var x1 = Event.getPageX(e), y1 = Event.getPageY(e);

    	// (1)で得た矩形の中心を求める
    	var x2 = Math.round((region.right+region.left)/2);
    	var y2 = Math.round((region.top+region.bottom)/2);

    	// I don't want text selection even if the click does not
    	// initiate a drag
    	// Eventのデフォルトの動きを抑止する。
    	Event.preventDefault(e);

    	// クリック位置のX(X1)−矩形の中心のX(X2)=R1
    	// クリック位置のy(Y1)−矩形の中心のy(Y2)=R2
    	// R1*R1 + R2*R2 <= r*r*の評価がtrueなら円内でのクリック。
		// trueが戻れば、validClickとみなされる。
    	return ( ((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) <= r*r );
	};

	// (注) id は Dropされた要素のid
	dd.onDragDrop = function(e, id) {
    	// DDオブジェクト(の座標)を、落とされた要素の座標とする。
    	Dom.setXY(this.getEl(), Dom.getXY(id));
	}

	dd.onInvalidDrop = function(e) {
		// おかしな位置に落としたら、退避している開始位置に
		// Motionを使ってもどる。
		new YAHOO.util.Motion( 
        	this.id, { 
            	points: { 
                	to: startPos
            	}
        	}, 
        	0.3, 
        	YAHOO.util.Easing.easeOut 
    	).animate();

	}

	dd2 = new YAHOO.util.DDTarget("dd-demo-2");

});

</script>
</HEAD>

<BODY>
<div id="dd-demo-1" class="dd-demo"><br/>DD</div>
<div id="dd-demo-2" class="dd-demo">DDTarget</div>

</BODY>
</HTML>