チュートリアル

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

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

サンプルで学ぶ「Google Desktop Gadget」の作り方 Google Desktop Gadget ガジェット

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


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

Google Desktop Gadgetsの実行にはGoogle Desktopが必要です。Google Desktopのインストールはダウンロードページ http://desktop.google.com/ から行ってください。
Google Desktopに追加できるガジェットは通常、拡張子が"gg"となっています。このファイルをダブルクリックすると、Google Desktopにガジェットを追加することができます。このようにして追加するガジェットはGoogle Desktop専用のガジェットですが、このほかに、iGoogle用のガジェットをGoogle Desktopに追加する方法も有ります。今回作成したGoogle Desktop版GadgetsPepperは、後者の方法をとっています。具体的には、Google Desktopの「ガジェットを追加」画面の右上検索ボックスにiGoogle版GadgetsPepperのURLを指定します。

     
 

    http://www.tkrb.jp/gadgets/pepper/gd/pepper.xml

 
     

を入力してください。検索するとGadgetsPepperが表示され、追加ボタンを押すと、Google Desktopのサイドバーにそれが追加されます。

主要機能の実装方法

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

ソースコード詳説

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