Back to Top
Room A
WEB - HTML
  • Twitter
  • Facebook
  • Pinterest
  • Hatena
  • instagram
  • YouTube

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]);   //文字列 -> 数値化
}

座標情報を数値化しないと、描画に失敗して↓の様に???って事になります。

描画失敗例:1

描画失敗例:2

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解除時の背景色初期化が必要。