map + area + excanvas.js で RollOver効果/Ver.1.0
以前、はてなブログで記事にした<map>と<area>タグを使ったリンクでのマウスhover時のRollOver効果を実現するHTMLです。
便宜的にHTML内に直接JavaScript(JS)のコードを記述していますが、JS部分を別ページに分離した方がスッキリすると思います。HTML4.01でも動作するハズですが未検証です。jQueryが使えるならば、jQueryを使った方がコードを簡潔に記述できます。
単一要素対応版
ちなみに下記のコードでは、<map>と<area>オブジェクトが1ページ内に複数存在する場合は正常に動作しません。
1ページ内に複数の<map>と<area>オブジェクトが存在する場合はコチラを参考にして下さい。(`・ω・´) キリッ
map_area_1.html : Sample Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<title>CANVAS TEST for MAP+AREA</title>
<!--[if lte IE 8]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
</head>
<body>
<h1><map> + <area> + excanvas.js で RollOver効果/Ver.1.0</h1>
<h2>::: 1 on 1 :::</h2>
<div id="map1">
<img id="base_map" src="test1.gif" alt="3element" width="400" height="200" border="0" usemap="#Map" />
<map name="Map" id="Map">
<area id="SQ" shape="rect" coords="114,6,308,95" href="#" alt="長方形" />
<area id="CI" shape="circle" coords="67,136,50" href="#" alt="円" />
<area id="PE" shape="poly" coords="341,31,294,187,383,187" href="#" alt="三角形" />
</map>
</div>
<script type="text/javascript"><!--
window.onload = function area_event(){
var map_tag = document.getElementById("Map"); //<map>のid="Map"限定
var area_tag = map_tag.getElementsByTagName("area"); //id="Map"の<area>を全走査
for( i=0; i< area_tag.length; i++ ){
if( area_tag[i].addEventListener ){
area_tag[i].addEventListener('mouseover', draw_img, false );
area_tag[i].addEventListener('mouseout', dele_img, false );
}else if( area_tag[i].attachEvent ){ //for under IE9
area_tag[i].attachEvent('onmouseover', draw_img );
area_tag[i].attachEvent('onmouseout', dele_img );
}else{
area_tag[i].onmouseover = draw_img;
area_tag[i].onmouseout = dele_img;
}
}
}
/*図形描画*/
function draw_img(evt){
var map1 = document.getElementById("map1"); //<div>:id取得
if( !map1 ){
return false;
}else{
var area_obj = new Object(); //初期化
}
if( evt.currentTarget ){
area_obj.id = evt.currentTarget.id;
area_obj.shape = evt.currentTarget.shape;
area_obj.coords = evt.currentTarget.coords;
}else{
area_obj.id = evt.srcElement.id;
area_obj.shape = evt.srcElement.shape.toLowerCase();
area_obj.coords = evt.srcElement.coords;
}
xy = area_obj.coords.split(","); //座標配列化
for( j in xy ){
xy[j] = parseInt(xy[j]); //文字列 -> 数値化
}
var img_W = document.getElementById("base_map").width; //map-imgのW
var img_H = document.getElementById("base_map").height; //map-imgのH
var newid = "new_"+document.getElementById("Map").name; //Map name属性取得 -> canvas id生成
var canvas = document.getElementById(newid); //<canvas>:id取得 -> 多重生成防止
if( !canvas ){
var canvas = document.createElement("canvas"); //canvas要素生成
map1.appendChild(canvas);
if( document.uniqueID ){ //for IE6/7/8 Check.
canvas = G_vmlCanvasManager.initElement(canvas);
}
}
if( !canvas.getContext ){
return false;
}else{
map1.style.zIndex = "1";
map1.style.position = "relative";
canvas.setAttribute("id", newid);
canvas.setAttribute("width", img_W);
canvas.setAttribute("height", img_H);
canvas.style.opacity = "1.0";
canvas.style.zIndex = "-100";
canvas.style.top = "0px";
canvas.style.left = "0px";
canvas.style.position = "absolute";
canvas.style.backgroundColor = "#EEEEEE";
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle = 'rgba(10,255,10,0.5)'; //図形:色:RGBa指定
//ctx.fillStyle = 'rgb(10,255,10)'; //図形:色:RGB指定
if( area_obj.shape == "rect" ){
ctx.fillRect( xy[0], xy[1], xy[2]-xy[0], xy[3]-xy[1] );
}else if( area_obj.shape == "circle" ){
ctx.arc( xy[0], xy[1], xy[2], 0, Math.PI*2, false );
}else if( area_obj.shape == "poly" ){
ctx.moveTo( xy[0], xy[1] ); //始点指示
for( i=2; i<xy.length; i=i+2 ){ //(x,y)loop
ctx.lineTo( xy[i], xy[i+1] );
}
ctx.closePath();
}
ctx.fill();
}
}
/*図形消去*/
function dele_img(evt){
var img_W = document.getElementById("base_map").width;
var img_H = document.getElementById("base_map").height;
var newid = "new_"+document.getElementById("Map").name; //Map name属性取得 -> canvas id生成
var canvas = document.getElementById(newid); //<canvas>:id取得
if( !canvas || !canvas.getContext ){
return false;
}else{
var ctx = canvas.getContext('2d');
ctx.clearRect(0,0,img_W,img_H); //全カンバス図形消去(0,0,幅,高さ)
canvas.style.backgroundColor = "";
}
}
//-->
</script>
</body>
</html>
上記のHTMLでは、excanvas.jsやマッピング対象の画像をHTMLと同じディレクトリに置いていますが、実際には別のディレクトリに置くケースが多いと思うので、その場合は各ファイルのリンク先(src=""の部分)を変更する必要があります。
以下の解説(?)は、はてブに掲載していたモノです。
自分がハマった箇所は【青】で、他の選択肢もあると思う部分は【緑】で、備忘録も兼ねてハマった状況などを書出してみました。
excanvas.js
<!--[if lte IE 8]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
IE8以下の場合のみexcanvas.jsをloadする。
IE 6/7/8 の場合のhover要素特定
area_tag[i].attachEvent('onmouseover', draw_img ); area_tag[i].attachEvent('onmouseout', dele_img );
IE 6/7/8では attachEvent の挙動が異なる…( ̄□ ̄;)
参考:MDN - EventTarget.addEventListener()
IE 6/7/8 以外の処理
if( evt.currentTarget ){
IE 6/7/8 ではevt.currentTargetがfalse(偽)となる。
IE 6/7/8 の処理
area_obj.id = evt.srcElement.id;{
IE 6/7/8 はsrcElementで要素取得
図形情報の小文字化
area_obj.shape = evt.srcElement.shape.toLowerCase();
IE6では図形情報が大文字で取得される様なので、toLowerCase() で図形情報を小文字化しないとIE6に於いて描画条件分岐で失敗する。
座標情報の数値化
for( j in xy ){ xy[j] = parseInt(xy[j]); //文字列 -> 数値化 }
座標情報を数値化しないと、描画に失敗して↓の様に???って事になります。
IE 6/7/8 の特定 & excanvas.js使用時の初期化
if( document.uniqueID ){ //for IE6/7/8 Check. canvas = G_vmlCanvasManager.initElement(canvas); }
document.uniqueID はInternet Explorer のみがサポートしているので、ブラウザの特定に使用。
excanvas.js 使用時に G_vmlCanvasManager.initElement() で初期化しないと描画に失敗。
CSS:z-index(map側)
map1.style.zIndex = "1";
事前にCSSでz-indexを指定している場合は不要。
CSS:opacityとz-index(canvas側)
canvas.style.opacity = "1.0"; canvas.style.zIndex = "-100";
opacity は必要に応じて設定。z-index の値は必ず <map> 側の方が上層に来るように指定。
canvasの背景色
canvas.style.backgroundColor = "#EEEEEE";
hover状態以外の図形が透過図形となっているか確認のため追加。画像全体の背景色を変える必要が無いならば不要。
四角形の座標指定
ctx.fillRect( xy[0], xy[1], xy[2]-xy[0], xy[3]-xy[1] );
<area> と <canvas> では四角形の座標指定方法が異なるので、<area>の座標をそのまま放り込むと???となる。
canvasの背景色:初期化
canvas.style.backgroundColor = "";
描画時に背景色指定した場合、hover解除時の背景色初期化が必要。