チュートリアル

はてなブックマークに追加 livedoorクリップに追加 Yahoo!ブックマークに追加 del.icio.usに追加 イザ!ブックマーク ニフティクリップに追加 Choixにブックマーク Buzzurlに追加

今日から作れる ガジェットって何?をクリアした人のための ガジェットHOW TO MAKE

サンプルで学ぶ「iGoogle Gadgets」の作り方 iGoogle ガジェット

iGoolge版GadgetsPepperをサンプルにしながら、iGoogle Gadgetsの作り方について学びます。先ず、ガジェットを使ってみて動作を確認したいという方は「ガジェットのインストール方法」へ、主要な6つの機能がどのように実装されているか概要を知りたい方は「主要機能の実装方法へ」、ソースコードをじっくり読みたい方は「ソースコードの詳説」へとお進みください。ソースコードの詳説では、解説アイコンにマウスをあてると、その部分の解説が表示されます。


ガジェットのインストール方法

Webブラウザで http://www.google.com/ig を開きます。画面の右上にある「コンテンツを追加」から画面左下にある「RSSフィードを追加」をクリックします。表示されたテキストボックスに、GadgetsPepperのURLである

     
 

    http://www.tkrb.jpt/gadgets/pepper/ig/pepper.xml

 
     

を指定して「追加」ボタンを押します。インストールが完了すると、自分のiGoogleページにGadgetsPepperが追加されています。

主要機能の実装方法

主要機能の実装方法
機能 実装方法
(1)地図を移動 地図表示にはGoogle Maps APIを利用しています。テキストボックスに地名を入力し、エンターキーもしくは検索ボタンを押すと、findAddress()が呼び出されます。iGoogleガジェットは表示するたび毎に、URLが変わる(http://22.gmodules.com/など、数字が変化する)ので、地名やランドマークによる検索を実現するGoogleのジオコーディングAPI、GClientGeocoderが使用できません。そのため、地名を条件にグルメサーチAPIを呼び出し、得られるグルメ店の緯度経度を地図の中心点としています。中心点の再設定は
256: googleMaps.setCenter( new GLatLng( latitude, longitude ) );
で行っています。
(2)ジャンルを選択 ガジェットロード処理load()内の、
49: _IG_FetchXmlContent(urlGenreMaster, function (response) {省略});
でジャンルマスターを検索し、返ってきたXMLをonGenreLoad()でパースします。GenreName(ジャンル名)ノード、GenreCD(ジャンルコード)ノードを抽出し、その2つを使って、プルダウンリストの内容をセットします。
(3)グルメ店を検索 読込ボタンが押されると、onFindShops()が呼び出されます。実際の検索はfindAtPoint()内で行っており、地図中心点の緯度経度とジャンルコードを用いURLを組み立て、
172: _IG_FetchXmlContent(url, function (response) {省略});
でグルメサーチAPIを呼び出します。結果のXMLにはグルメ店情報が含まれます。
(4)詳細画面を表示 グルメ店の緯度経度を用い、地図上にグルメ店の位置を表すマーカーをセットします。この時、マーカーにイベントリスナーを追加し、それがクリックされたときにsetShopInfo()が呼び出されるようにします。setShopInfo()内で、グルメ店の詳細表示用のレイヤをvisibleにし、グルメ店詳細情報を表示します。
(5)背景画面の変更 ガジェットにどのようなオプション設定ができるかはタグ内で定義します。GadgetsPepperでは背景画像の選択ができるようにしてあります。選択したオプションは、
327 var n = prefs.getInt("backcolor");
のように参照します。
(6)状態の保存と復帰 状態の保存は、unload()が呼ばれるタイミングで行います。実際の処理はsaveState()内で行っており、最後に実行された検索の地図中心点の緯度経度、料理ジャンル、背景画像番号をCookieに保存します。
93: setCookie( "search_latitude", lastSearchPoint.y );
94: setCookie( "search_longitude", lastSearchPoint.x );
97: setCookie( "search_genre", lastSearchGenre );
保存した内容の復帰はload()が呼ばれるタイミング、loadState()内で行います。

注)Cookieについて
今回のサンプルプログラムはデータの保存にCookieを用いており、セキュリティ設定によっては「状態の保存と復帰」が機能しません。以下、 Internet Explorer 6.0を例にCookieの設定方法をご案内します。

  • 「ツール」メニューの「インターネットオプション」を選びます。
  • 「インターネットオプション」ウィンドウで「プライバシー」のタブをクリックします。
  • 「詳細設定」をクリックします。
  • 「プライバシー設定の詳細」ウィンドウで「自動Cookie処理を上書きする」にチェックをします。
  • 「ファーストパーティのcookie」「サードパーティのcookie」の両方について、「受け入れる」を選択します。

ソースコード詳説

code    
 
  1: pepper.xml
  2:
  3: <?xml version="1.0" encoding="UTF-8" ?>
  4: <Module>
  5: <ModulePrefs title="Gadgets Pepper" directory_title="Gadgets Pepper" description="" screenshot="" title_url="" author="" author_email="" author_link="" author_location="" author_affiliation="None" scrolling="false" height="230" />解説
  6: <UserPref name="backcolor">解説
  7:  display_name="背景画像の変更"
  8:  datatype="enum"
  9:  default_value="1">
 10:  <EnumValue value="1" display_value="モザイク模様(赤)"/>
 11:  <EnumValue value="2" display_value="モザイク模様(緑)"/>
 12:  <EnumValue value="3" display_value="空と雲の風景"/>
 13:  <EnumValue value="4" display_value="花柄模様"/>
 14:  <EnumValue value="5" display_value="バブル模様(パープル)"/>
 15: </UserPref>
 16: <Content type="html">
 17: <![CDATA[
 18:  <link href="http://www.tkrb.jp/gadgets/pepper/ig/HotStyle.css" rel="stylesheet" type="text/css" />
 19:  <script src="http://maps.google.com/maps?file=api&v=2&key=(API KEY)" type="text/javascript" charset="utf-8"></script>
 20:  <script type="text/javascript" src="http://www.tkrb.jp/gadgets/pepper/ig/HotScript.js"></script>解説
 21:  <script type="text/javascript">
 22:  
 23:  //変数宣言
 24:  //
 25:  var prefs = new _IG_Prefs(__MODULE_ID__);解説
 26:  var urlGourmetSearch = "http://api.hotpepper.jp/GourmetSearch/V110/?key=guest";
 27:  var urlGenreMaster = "http://api.hotpepper.jp/Genre/V110/?key=guest";
 28:  var site_url = "http://www.tkrb.jp/gadgets/pepper/ig/";
 29:  var googleMaps = null;
 30:  var shopNodeList = null;
 31:  var curShopNode = 0;
 32:  var lastSearchPoint = new GLatLng( 35.681074, 139.767079 );
 33:  var lastSearchGenre = null;
 34:  var initZoom = 13;
 35:  var idIntervalTimer = null;
 36:
 37:  // 画面ロード時の処理
 38:  //
 39:  function load(){
 40:    try{
 41:      loadState();
 42:      if( GBrowserIsCompatible() ){
 43:        googleMaps = new GMap2( _gel( "map" ) );解説
 44:        googleMaps.addControl( new GSmallMapControl() );
 45:        googleMaps.enableScrollWheelZoom();
 46:        if( lastSearchPoint )
 47:          googleMaps.setCenter( lastSearchPoint, initZoom, G_NORMAL_MAP );
 48:      }
 49:      _IG_FetchXmlContent(urlGenreMaster, function (response) {解説
 50:        if (response == null || typeof(response) != "object" || response.firstChild == null) {
 51:          return;
 52:        }else{
 53:          onGenreLoad( response );
 54:        }
 55:      });
 56:      setDockState();
 57:      if( lastSearchPoint != null )
 58:        findAtPoint( lastSearchPoint, lastSearchGenre );
 59:    }
 60:    catch( e ){document.writeln( e );}
 61:  }
 62:
 63:  // ジャンル一覧を取得する処理
 64:  //
 65:  function onGenreLoad( response ){
 66:    try{
 67:      var elmSel = _gel( "genreSelect" );解説
 68:      genreNodeList = response.getElementsByTagName( "Genre" );
 69:      if( genreNodeList == null )
 70:        return;
 71:      for( var i = 0 ; i < genreNodeList.length ; i++ ){
 72:        var node = genreNodeList.item( i );
 73:        var ndName = node.getElementsByTagName( "GenreName" );
 74:        var ndCD = node.getElementsByTagName( "GenreCD" );
 75:        if( ndName != null && ndCD != null ){
 76:          var opt = document.createElement( "OPTION" );
 77:          elmSel.options.add( opt ); 解説
 78:          opt.text = ndName.item(0).firstChild.nodeValue;
 79:          opt.value = ndCD.item(0).firstChild.nodeValue;
 80:          if( opt.value == lastSearchGenre )
 81:            opt.selected = true;
 82:        }
 83:      }
 84:    }
 85:    catch( e ){}
 86:  }
 87:
 88:   // クッキーに状態を保存する処理
 89:   //
 90:   function saveState(){
 91:    try{
 92:      if( lastSearchPoint != null ){
 93:        setCookie( "search_latitude", lastSearchPoint.y ); 解説
 94:        setCookie( "search_longitude", lastSearchPoint.x );
 95:      }
 96:      if( lastSearchGenre != null ){
 97:        setCookie( "search_genre", lastSearchGenre );
 98:      }
 99:    }
100:    catch( e ){}
101:  }
102:
103:  // 画面がアンロード時の処理
104:  //
105:  function unload(){
106:    saveState();
107:    GUnload();
108:  }
109:
110:  // クッキーから状態をロードする処理
111:  //
112:  function loadState(){
113:    try{
114:      var search_latitude = getCookie( "search_latitude" );
115:      var search_longitude = getCookie( "search_longitude" );
116:      lastSearchGenre = getCookie( "search_genre" );
117:      if( ! isNullOrEmpty( search_latitude ) && ! isNullOrEmpty( search_longitude ) )
118:        lastSearchPoint = new GLatLng( parseFloat( search_latitude ), parseFloat( search_longitude ) );
119:    }
120:    catch( e ){}
121:  }
122:
123:  // クッキーに値を設定する関数
124:  //
125:  function setCookie(fieldId,value){
126:    var expires = new Date()
127:    expires.setTime(expires.getTime() + (1*24*60*60*1000))
128:    document.cookie=fieldId+"="+escape(value)+"; expires="+expires.toGMTString()
129:  }
130:
131:  // クッキーから値を取得する関数
132:  //
133:  function getCookie(fieldId){
134:    var tmp=(document.cookie+";").match(fieldId+"=([^;]*);")
135:    if(tmp!=null){
136:      return unescape(tmp[1])
137:    }else{
138:      return null
139:    }
140:  }
141:
142:  // 数字を0詰めする関数
143:  //
144:  function format(Num, Format){
145:    var s = new String(Num);
146:    var z = "";
147:    for(c = 0 ; c < Format - s.length ; c++){
148:      z = z + "0";
149:    }
150:    return (z + s);
151:  }
152:
153:  // 現在時刻を表示する処理
154:  //
155:  function showCurrentTime(){
156:    var date = new Date();
157:    var y = date.getFullYear();
158:    var mo = date.getMonth();
159:    var d = date.getDate();
160:    var h = date.getHours();
161:    var m = date.getMinutes();
162:    var s = date.getSeconds();
163:    _gel( "timeView" ).innerHTML = format(y,4) + "." + format(mo+1,2) + "." + format(d,2) + " " + format(h,2) + ":" + format(m,2); 解説
164:  }
165:
166:  // お店を検索する処理
167:  //
168:  function findAtPoint( pt, genre ){
169:    var url = urlGourmetSearch + "&Latitude=" + pt.y + "&Longitude=" + pt.x;
170:     if( ! isNullOrEmpty( genre ) )
171:      url = url + "&GenreCD=" + genre;
172:    _IG_FetchXmlContent(url, function (response) {
173:      if (response == null || typeof(response) != "object" || response.firstChild == null) {
174:        return;
175:      }else{
176:        onXmlLoad( response , true, false);
177:      }
178:    });
179:  }
180:
181:  // お店情報読み込みボタンを押した時の処理
182:  //
183:  function onFindShops()
184:  {
185:    try{
186:      lastSearchPoint = googleMaps.getCenter();
187:      lastSearchGenre = _gel( "genreSelect" ).value; 解説
188:      findAtPoint( lastSearchPoint, lastSearchGenre );
189:    }
190:    catch( e ){}
191:  }
192:
193:  // 住所検索のテキストボックス上でキーを押した時の処理
194:  //
195:  function onKeydown(){
196:    if(event.keyCode == 13){findAddress();}
197:  }
198:
199:  // 住所検索のテキストボックスにフォーカスが移った時の処理
200:  //
201:  function focusAddress()
202:  {
203:    if (document.getElementById( "address" ).value == "(地名・ランドマークを指定)")
204:      document.getElementById( "address" ).value = "";
205:  }
206:
207:  // 住所検索を行うときの処理
208:  //
209:  function findAddress(){
210:    try{
211:      if (document.getElementById( "address" ).value == "(地名・ランドマークを指定)") return;
212:      var address = _gel( "address" ).value;
213:      if( isNullOrEmpty( address ) )
214:        return;
215:      var url = urlGourmetSearch + "&ShopAddress=" + encodeURL( address );
216:      _IG_FetchXmlContent(url, function (response) { 解説
217:        if (response == null || typeof(response) != "object" || response.firstChild == null) {
218:          return;
219:        }else{
220:          onXmlLoad( response , false, true);
221:        }
222:      });
223:    }
224:    catch( e ){}
225:  }
226:
227:  // 地図にマーカーを追加する処理
228:  //
229:  function addMarker( pt, idx ){
230:    var marker = new GMarker( pt );
231:    GEvent.addListener( marker, "click", function(){ 解説
232:        setShopInfo( idx );
233:      });
234:    googleMaps.addOverlay( marker ); 解説
235:  }
236:
237:  // ホットペッパーAPIの検索結果にもとづいてXMLを解析する処理
238:  //
239:  function onXmlLoad( response, bSetMarker, bForceCenter ){
240:    try{
241:      shopNodeList = response.getElementsByTagName( "Shop" );
242:      if( shopNodeList == null )
243:        return;
244:      googleMaps.clearOverlays();
245:      for( var i = 0 ; i < shopNodeList.length ; i++ ){
246:        var node = shopNodeList.item(i);
247:        var ndLatitude = node.selectSingleNode( "Latitude" );
248:        var ndLongitude = node.selectSingleNode( "Longitude" );
249:        if( ndLatitude != null && ndLongitude != null ){
250:          var latitude = parseFloat( ndLatitude.text );    // 経度
251:          var longitude = parseFloat( ndLongitude.text );    // 緯度
252:          if( bSetMarker ){
253:            addMarker( new GPoint( longitude, latitude ), i );
254:          }
255:          if( bForceCenter ){
256:            googleMaps.setCenter( new GLatLng( latitude, longitude ) );
257:            bForceCenter = true;
258:          }
259:        }
260:      }
261:    }
262:    catch( e ){}
263:  }
264:
265:  // お店情報を表示する処理
266:  //
267:  function setShopInfo( idx ){
268:    if( shopNodeList == null || idx < 0 || shopNodeList.length <= idx )
269:      return;
270:    curShopNode = idx;
271:    _gel("shop").style.visibility = "visible"; 解説
272:    _gel("genreSelect").style.visibility = "hidden";
273:    node = shopNodeList.item( idx );
274:    var ndShopName = node.selectSingleNode( "ShopName" );
275:    var ndShopURL = node.selectSingleNode( "ShopUrl" );
276:    var ndGenreCatch = node.selectSingleNode( "GenreCatch" );
277:    var ndPictureURL;
278:    ndPictureURL = node.selectSingleNode( "PictureUrl/PcLargeImg" );
279:    if( ndShopName != null )
280:      _gel( "shopName" ).innerHTML = ndShopName.text;
281:    if( ndShopURL != null )
282:      _gel( "shopName" ).setAttribute( "href", ndShopURL.text );
283:    if( ndGenreCatch != null )
284:      _gel( "genreCatch" ).innerHTML = ndGenreCatch.text;
285:    if( ndPictureURL != null )
286:      _gel( "shopPicture" ).setAttribute( "src", ndPictureURL.text );
287:    if( ( curShopNode + 1 ) < shopNodeList.length )
288:      _gel("btnNext").style.visibility = "inherit";
289:    else
290:      _gel("btnNext").style.visibility = "hidden";
291:    if( curShopNode > 0 )
292:      _gel("btnPrev").style.visibility = "inherit";
293:    else
294:      _gel("btnPrev").style.visibility = "hidden";
295:  }
296:
297:  // 前のお店情報に移動する
298:  //
299:  function prevShop(){
300:    if( curShopNode > 0 ){
301:      setShopInfo( curShopNode -1 );
302:    }
303:  }
304:
305:  // 次のお店情報に移動する
306:  //
307:  function nextShop(){
308:    if( ( curShopNode + 1 ) < shopNodeList.length ){
309:      setShopInfo( curShopNode + 1 );
310:    }
311:  }
312:
313:  // お店情報表示を閉じる
314:  //
315:  function closeShopInfo(){
316:    _gel("shop").style.visibility = "hidden"; 解説
317:    _gel("genreSelect").style.visibility = "visible";
318:  }
319:
320:  // 画面の状態を設定
321:  //
322:  function setDockState(){
323:    _gel( "shopName" ).style.fontSize = "10px";
324:    _gel( "genreCatch" ).style.fontSize = "10px";
325:    _gel( "base").style.width = "210px";
326:    _gel( "base").style.height = "210px";
327:    var n = prefs.getInt("backcolor");
328:    if (IsFireFox() == false) {
329:      _gel( "titlelogo" ).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "titlelogo.png)"; 解説
330:      _gel( "findaddress" ).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "findaddress.png)";
331:      _gel( "findshop" ).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "findshop.png)";
332:      _gel( "close" ).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "close.png)";
333:      _gel( "btnPrev" ).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "prev.png)";
334:      _gel( "btnNext" ).style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "next.png)";
335:      _gel( "titlelogo" ).style.backgroundImage = "none";
336:      _gel( "findaddress" ).style.backgroundImage = "none";
337:      _gel( "findshop" ).style.backgroundImage = "none";
338:      _gel( "close" ).style.backgroundImage = "none";
339:      _gel( "btnPrev" ).style.backgroundImage = "none";
340:      _gel( "btnNext" ).style.backgroundImage = "none";
341:      if( n != null ){
342:        switch( n ){ 解説
343:          case 2:
344:            _gel("base").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "b2.png)";
345:            _gel( "timeView" ).style.color = "#8B795E";
346:            break;
347:          case 3:
348:            _gel("base").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "b3.png)";
349:            _gel( "timeView" ).style.color = "#BFCBD4";
350:            break;
351:          case 4:
352:            _gel("base").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "b4.png)";
353:            _gel( "timeView" ).style.color = "#8B795E";
354:            break;
355:          case 5:
356:            _gel("base").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "b5.png)";
357:            _gel( "timeView" ).style.color = "#F2D7E7";
358:            break;
359:          default:
360:            _gel("base").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + site_url + "b1.png)";
361:            _gel( "timeView" ).style.color = "#8B795E";
362:            break;
363:        }
364:      }
365:      _gel("base").style.backgroundImage = "none";
366:      _gel( "address").style.position = "relative";
367:      _gel( "findaddress").style.position = "relative";
368:      _gel( "findshop").style.position = "relative";
369:      _gel( "close").style.position = "relative";
370:      _gel( "btnPrev").style.position = "relative";
371:      _gel( "btnNext").style.position = "relative";
372:      _gel( "genreSelect").style.position = "relative";
373:    }else{
374:      if( n != null ){
375:        switch( n ){
376:          case 2:
377:            _gel("base").style.backgroundImage = "url(" + site_url + "b2.png)";
378:            _gel( "timeView" ).style.color = "#8B795E";
379:            break;
380:          case 3:
381:            _gel("base").style.backgroundImage = "url(" + site_url + "b3.png)";
382:            _gel( "timeView" ).style.color = "#BFCBD4";
383:            break;
384:          case 4:
385:            _gel("base").style.backgroundImage = "url(" + site_url + "b4.png)";
386:            _gel( "timeView" ).style.color = "#8B795E";
387:            break;
388:          case 5:
389:            _gel("base").style.backgroundImage = "url(" + site_url + "b5.png)";
390:            _gel( "timeView" ).style.color = "#F2D7E7";
391:            break;
392:          default:
393:            _gel("base").style.backgroundImage = "url(" + site_url + "b1.png)";
394:            _gel( "timeView" ).style.color = "#8B795E";
395:            break;
396:        }
397:      }
398:      _gel( "base" ).style.backgroundRepeat = 'no-repeat';
399:      _gel( "titlelogo" ).style.backgroundImage = "url(" + site_url + "titlelogo.png)";
400:      _gel( "findaddress" ).style.backgroundImage = "url(" + site_url + "findaddress.png)";
401:      _gel( "findshop" ).style.backgroundImage = "url(" + site_url + "findshop.png)";
402:      _gel( "close" ).style.backgroundImage = "url(" + site_url + "close.png)";
403:      _gel( "btnPrev" ).style.backgroundImage = "url(" + site_url + "prev.png)";
404:      _gel( "btnNext" ).style.backgroundImage = "url(" + site_url + "next.png)";
405:      _gel( "titlelogo" ).style.backgroundRepeat = 'no-repeat';
406:      _gel( "findaddress" ).style.backgroundRepeat = 'no-repeat';
407:      _gel( "findshop" ).style.backgroundRepeat = 'no-repeat';
408:      _gel( "close" ).style.backgroundRepeat = 'no-repeat';
409:      _gel( "btnPrev" ).style.backgroundRepeat = 'no-repeat';
410:      _gel( "btnNext" ).style.backgroundRepeat = 'no-repeat';
411:    }
412:    idIntervalTimer = setInterval( "showCurrentTime()", 1000 ); 解説
413:  }
414:  </script>
415:
416: <body onload="load()" onunload="unload()">
417: <div align="center" style="width:100%;margin:auto;">
418:   <div id="base">
419:     <table width="100%" cellpadding="3px" cellspacing="3px">
420:       <tr>
421:         <td colspan="2">
422:         <table cellpadding="0" cellspacing="0" border="0">
423:           <tr>
424:             <td valign="top" align="left" width="110px"><span id="titlelogo" style="width: 110px; height: 10px;"></span></td>
425:             <td valign="top" align="right" width="85px"><span style="font-size: 9px; width: 85px;" id="timeView"></span></td>
426:           <tr>
427:         </table>
428:         </td>
429:       </tr>
430:       <tr>
431:         <td><input id="address" style="width:150px;" type="text" value="(地名・ランドマークを指定)" onfocus="focusAddress()" onKeyDown="onKeydown()"/></td>
432:         <td><span id="findaddress" style="cursor:hand;width:41px;height:20px;" onclick="findAddress()"></span></td>
433:       </tr>
434:       <tr>
435:         <td colspan="2"><div id="map" style="width:196px;height:115px;" onmousedown=""></div></td>
436:       </tr>
437:       <tr>
438:         <td>
439:         <select id="genreSelect" style="width:150px;"><option value="">全てのジャンル</option></select>
440:         </td>
441:         <td align="left">
442:         <span id="findshop" style="cursor:hand;width:41px;height:20px;" onclick="onFindShops()"></span>
443:         </td>
444:       </tr>
445:       <tr>
446:         <td align="right" colspan="2">
447:         <div id="poweredby" style="color:#363636;font-size: 9px; text-align:right;" >Powered by ホットペッパー.jp</div>
448:         </td>
449:       </tr>
450:     </table>
451:   </div>
452:   <div id="shop">
453:     <table width="100%" height="30px" cellpadding="2px" cellspacing="2px">
454:       <tr valign="top" style="height:30px;">
455:         <td valign="bottom">
456:           <a id="shopName" target="_blank"></a>
457:         </td>
458:         <td align="right" valign="top">
459:           <div id="close" style="cursor:hand;width:21px;height:21px;" onclick="closeShopInfo()"></div>
460:         </td>
461:       </tr>
462:     </table>
463:     <table width="100%" cellpadding="2px" cellspacing="2px" border="0">
464:       <tr valign="top" style="height:73px;">
465:         <td style="text-align:left;width:85px;" >
466:           <img id="shopPicture" src="null" alt="写真" style="width:70px;height:70px;"/></td>
467:         <td align="left">
468:           <span id="genreCatch"></span>
469:         </td>
470:       </tr>
471:       <tr>
472:         <td valign="bottom" align="left">
473:           <span id="btnPrev" style="cursor:hand;width:22px;height:22px;" onclick="prevShop()"></span>
474:         </td>
475:         <td valign="bottom" align="right">
476:           <span id="btnNext" style="cursor:hand;width:22px;height:22px;" onclick="nextShop()"></span>
477:         </td>
478:       </tr>
479:     </table>
480:   </div>
481: </div>
482: </body>
483: </html>
484: ]]>
485: </Content>
486: </Module> ガジェットのタイトルなど、ガジェット属性情報を設定します。 設定できるオプションを定義しています。GadgetPepperでは、背景画像を選ぶことができるようにしています。 HotScript.jsを読み込みます。HotScript.jsではXMLHttpRequestオブジェクトの生成、変数のnullの判定、URLエンコードなど、プログラムで繰り返し使用されるファンクションをまとめて記述しています。 オプション設定を読み込むための準備。_IG_Prefs()を呼ぶことによって、ユーザー設定のオブジェクトにアクセスすることができるようになります。 Google Maps APIで地図の表示、コントロールボタンの追加、中心点の移動を行います。 ホットペッパーAPIを呼び出し、ジャンル一覧を取得します。 ドキュメント要素genreSelectを変数に設定します。iGoogleでは、document.getElementById()の変わりに_gel()という専用の関数を使用します。 ホットペッパーAPIで取得したジャンル一覧をプルダウンメニューにセットします。 最後に検索された場所の緯度経度、料理ジャンルをCookieに保存します。 ガジェットの右上に表示される日付と時間をセットします。 iGoogleで、ホットペッパーAPIのようなWebサービスからXMLデータを取得する場合、固有の関数_IG_FetchXmlContent()を使います。通常、閲覧しているドメイン外のURLを直接参照しようとするとブラウザでセキュリティーエラーが出ますが、この関数を使用することでそれを回避できます。この関数がプロキシとして動作してくれるようです。 ジャンル選択プルダウンリストの現在の選択値を取得します。ここでも_gel()を用います。 マーカーにイベントリスナーを追加します。マーカーをクリックした時に、呼ばれる関数をここで設定します。 グルメ店の緯度経度を用い、地図上にグルメ店の位置を表すマーカーを表示します。 グルメ店の詳細情報を表示するため、詳細情報レイヤ<div id="shopquot;gt;のvisibilityスタイルをvisibleにします。この際、詳細情報レイヤのpositionを絶対位置指定(absolute)にし、ちょうど地図の上に重ねて表示することで、地図画面と詳細画面が切り変わったように見せています。 visibilityスタイルをhiddenにすることで、グルメ店の詳細情報レイヤを閉じます。 IE7、FireFoxで扱える透過PNGがIE6ではサポートされません。そこで、Filter機能を使い、IE6でも透過PNGが表示できるようにしています。FilterはIE7でも使用できますが、FireFoxでは使用できないため、正確に動作させるために、ブラウザごとに条件分岐しています。FireFoxかどうかの判定は、IsFireFox()で行っています。 オプション設定を取得します。GadgetPepperの場合、背景画像の番号を取得し、その値によって処理を振り分けています。 ガジェット右上に表示される日時を再表示する間隔を設定します。
 
Google Gadget チュートリアル Google Desktop Gadget チュートリアル Live Gadget チュートリアル Vista Sidebar Gadget チュートリアル Y! Widget チュートリアル