jQueryとcanvasを使ってイメージマップでhoverすると色かわるみたいな〜

サンプルはこちら→W7工廠分室|トップページ
■目的
イメージマップってマウス乗っても色変わらないし〜、ロールオーバー時の画像を1つずつ用意するのって面倒だし〜
・・・とかそういう場合にどうぞ。
図で表すとこうなります。既存のイメージマップの下にcanvasを(以下略w)

■仕様
・XHTML1.0, HTML4.01/5で動作します
・ブラウザは各種最新版でチェック、IE6〜IE8もチェック
・altへのアクション(ツールチップ的な説明)も考えていたのですが、別ツールのほうがいいと思いやめましたw
■不具合
IE7でimg要素とcanvas要素が少しずれる(imgのopacity=0でもいいかも)
IE9のDOCTYPE無指定で動作しない←IE判定部分をかえれば多分いけます
・IE6のHTML5で動作しない
■注意事項
・img要素はz-index:1以上であること
・usemap属性名は小文字(useMapはだめ)かつ属性値にピリオドなし(usemap="#***.***"はだめ)
・img要素の親要素(liやdivなど)にposition:relativeがかかります。
・area要素の属性にcolor='rgba(赤, 緑, 青, 0.7)'を入れればhover時に部分ごとに色を変えることもできます。
(ここは勝手に属性でっちあげてるので、HTMLの仕様に反していると思いますが・・・使い勝手を考えると外せません。)
■更新履歴
2012-06-04 特定環境でのエラー現象(ChromeとWindowsとIntel Atomの組み合わせでcanvasの描画がおかしいとか〜 - w7工廠
2012-03-14
・shape.toLowerCase();を移動(取得時に変換・・・あたりまえですね)
canvascss設定でposition:absolute;わすれてましたw(これをつけるととんでもないことにw)
・動作チェックしました。
・記事を整理しました。
2012-02-18
・コードに解説(コメント)追加しました。
2012-01-23
・Rect描画はIEでもできてました(汗)→RectのIE処理削除
・beginPath(),fill()の位置を変更。
IE判定をjQueryのみにしました。
・coordsを文字列で渡していたので数値変換を追加しました。(これをしないとIE6で円が半円になるという・・・)
・上記を確認するためにhtml(地図版)の左上に四角・右上に丸のareaを追加。
・「_引数」を「引数」に修正←分かる人には分かる勘違い
2012-01-08
・クラスっぽくしたついでにタイトルも変更しました
 (area mapとjQueryとcanvasを使ってクリッカブルマップロールオーバーとか〜 - w7工廠)
2011-10-05
・IE6対応(areaの値が大文字(poly→POLYなど)で渡されていたのでtoLowerCaseを追加しました)


■内容
XHTML(head)

<script type="text/javascript" src="jquery.js"></script>
<!--[if lte IE8]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
<script type="text/javascript" src="jq_imgMapToCanvas.js"></script>

XHTML(body)

<div>
    <img class="imgMapToCanvas" usemap="#***" src="画像" width="幅" height="高さ" border="0"/>
</div>
<map name="***" id="***">
   <area 
	shape="rectまたはcircleまたはpoly" 
	color='rgba(200, 200, 0, 0.7)'  //色を付けたいとき 
	coords="座標" 
	href="リンク"
   />
</map>

JavaScript (jq_imgMapToCanvas.js)

/* jq_imgMapToCanvas.js 2010-12-15→2012-01-23*/
$(function(){
	imgMapToCanvasInit();
	$("area").hover( //図形の形・座標取得→描画・消去 (ここから先thisはarea要素を示す)	
		function(e){//area:hover時
			var id="canvas_"+$(this).parent().attr("name");//hoverになったareaのmapのname属性からidを取得
			var shape=$(this).attr("shape").toLowerCase();//circleまたはpolyまたはrect、IE6は大文字取得なので小文字変換
			var coords=$(this).attr("coords").split(",");//areaのcoords(座標)をカンマ区切りで配列に格納
			for(i in coords){coords[i]=parseInt(coords[i]);}//文字列→数値
                           //areaから色取得(area色情報無しの場合初期値)
			var color=$(this).attr("color");//色取得
			if(!color){color='rgba(255, 100, 0, 0.7)';}//areaに色指定していない場合の初期値
			imgMapToCanvasDraw(id,shape,coords,color);//値をdrawする
		},
		function(e){//area:hover解除時にid指定→クリア
			var id="canvas_"+$(this).parent().attr("name");//hoverになったareaのmapのname属性からidを取得
			imgMapToCanvasClear(id);//値をclearする
		}
	);
});
function imgMapToCanvasInit(){
	$("img.imgMapToCanvas").each(function(){//すべてのimgMapToCanvas設定されたimg要素を処理
		//親(divやliなど)をrelative
		$(this).parent().css("position","relative");//div要素をposition:relativeに設定
		//イメージ属性
		var position=$(this).position();
		var height=$(this).attr("height");//img高さ=canvas高さ
		var width=$(this).attr("width");//img幅=canvas幅
		var src="url("+$(this).attr("src")+")";//img画像名=canvas背景
		var useMap=$(this).attr("usemap").split("#")[1];//usemap属性から#をとる
		var id="canvas_"+useMap;//上記をcanvasのidとする(canvas_***)
		//canvas設置
		var canvas = document.createElement("canvas");//canvas要素生成
		$(canvas).attr({"id":id,"width":width,"height":height});//canvasの幅・高さ設定
		$(this).before(canvas);//img要素の前にcanvasを設置
		if (!jQuery.support.opacity) {//IEの場合
			canvas = G_vmlCanvasManager.initElement(canvas);//IEの場合のcanvas初期化
		}
		//canvasに透明度1,z-indexを背面,positionを設定,背景にimg要素
		$("canvas#"+id)
                  .css({"opacity":"1.0","zIndex":"1","position":"absolute","top":position.top,"left":position.left,"backgroundImage":src});
		//img要素を透明度0.1(うっすらと),z-indexを前面,positionを設定
		$(this)
                  .css({"opacity":"0.1","zIndex":"100","position":"absolute","top":position.top,"left":position.left});
	});
}
function imgMapToCanvasDraw(id,shape,coords,color){
	var canvas = document.getElementById(id);
	if (!canvas || !canvas.getContext) {return false;}
	var ctx = canvas.getContext('2d');
	ctx.beginPath();
	ctx.fillStyle = color;
	switch(shape){
		case "rect"://矩形の場合
			ctx.fillRect(coords[0],coords[1],coords[2]-coords[0],coords[3]-coords[1]);//(x1,y1,x2,y2)
			break;
		case "circle"://円の場合
			ctx.arc(coords[0],coords[1],coords[2],0,Math.PI*2,false);//(x,y,r,開始角度,終了角度,描画方向)
			break;
		case "poly"://不定形の場合
			ctx.moveTo(coords[0],coords[1]);//最初の点
			for(var i=2;i<coords.length;i=i+2){//(x,y)を繰り返す
				ctx.lineTo(coords[i],coords[i+1]);
			}
			ctx.closePath();
			break;
	}
	ctx.fill();
}
function imgMapToCanvasClear(id){
	var canvas = document.getElementById(id);
	if (!canvas || !canvas.getContext) {return false;}
	var ctx = canvas.getContext('2d');
	var width=$(canvas).attr("width");
	var height=$(canvas).attr("height");
	ctx.clearRect(0,0,width,height); //全カンバス図形消去(0,0,幅,高さ)
}