🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Google マップ

Google Mapは、Google社がオンラインで提供している地図・ローカル検索サービスです。GIS(Geographic Information System:地理情報システム)の中の「WebGIS」に該当します。地図・航空写真・地形の表示方式があり、それぞれユーザーが縮尺を調整して表示させることができます。地域の情報サービスを検索する機能やルート検索の機能も搭載されています。

Q&A

解決済

1回答

2495閲覧

google Mapで複数のinfoWindowをループでclose()で閉じることができない

pegy

総合スコア245

Google マップ

Google Mapは、Google社がオンラインで提供している地図・ローカル検索サービスです。GIS(Geographic Information System:地理情報システム)の中の「WebGIS」に該当します。地図・航空写真・地形の表示方式があり、それぞれユーザーが縮尺を調整して表示させることができます。地域の情報サービスを検索する機能やルート検索の機能も搭載されています。

0グッド

0クリップ

投稿2019/10/24 14:50

編集2019/10/25 03:18

Google Mapで以下のように、すべてのinfoWindowを非表示させようとオブジェクトをループさせてすべての要素にclose()を適用しようとしたところ動作をいたしませんでした。

原因を探るべく具体的に試しに一つ
infoWindow["k2"][0].close();//これは消える
を実行したところ["k2"][0]の要素は非表示になることがわかりました。

ただし、
infoWindow[markerKeys[i]][j].close();//これは消えない
で["k2"][0]のループに入っても消えてくれません。もちろん他のinfoWindowもすべて消えてくれません。

オブジェクトの中身に相違があるのかと以下の検証を実行しました。
console.log(infoWindow["k2"][0]==infoWindow[markerKeys[i]][j]);
すると["k2"][0]のループで正しくtrueが返されることが確認できました。

この状況から、["k2"][0]に限らず、ループ処理の場合だけclose()が動作しない理由がわからないのですが、同じような現象を経験したことがある方や、原因がわかる方がいらっしゃればお力添えをお願いできますでしょうか。

何卒、よろしくお願い申し上げます。

javascript

1/* 2var windows={ 3c1:{0._sf{省略}} 4k1:{0._sf{省略}} 5k2:{0._sf{省略},1._sf{省略}} 6} 7*/ 8 9$(function(){ 10 $('.ckClose').on('click',function(){ 11 var windowKeys=Object.keys(windows); 12 var windowLen=windowKeys.length; 13 for (var i = 0; i < windowLen; i++) { 14 for (var j = 0, innerLen=Object.keys(windows[windowKeys[i]]).length; j <innerLen ; j++) { 15 console.log(infoWindow["k2"][0]==infoWindow[windowKeys[i]][j]);//ここで違いを検証 16 infoWindow["k2"][0].close();//これは消える 17 infoWindow[windowKeys[i]][j].close();//これは消えない 18 } 19 } 20 }) 21})

以下の通り、具体的なコードを開示させていただきます。
$('.ckClose').on('click',function()の箇所が上記の具体的な質問の箇所です。私のGoogle Chrome(バージョン: 77.0.3865.120(Official Build) (64 ビット))のDeveloper Tool上では特段のエラーは出力されていません。

html

1<div id="map" class="web_map"></div> 2 3<div class="btnWrapper"> 4 <div id="" class="btn displayIcon ckOpen">X</div 5 <div id="" class="btn displayIcon ckClose">X</div> 6</div>

Javascript

1var map; 2var mObj ={}; 3var marker = {}; 4var infoWindow = {}; 5 6 7 mObj.k1= 8 [ 9 { 10 lat:35.639014, 11 lng:139.638741, 12 icon:"./z_icon/1_k.png" 13 } 14 ]; 15 16 mObj.c1= 17 [ 18 { 19 lat:35.631350, 20 lng:139.646900, 21 icon:"./z_icon/1_c.png" 22 } 23 ]; 24 25 mObj.k2= 26 [ 27 { 28 lat:35.562416, 29 lng:139.614346, 30 icon:"./z_icon/2_k.png" 31 }, 32 { 33 lat:35.757992, 34 lng:139.827880, 35 icon:"./z_icon/2_k.png" 36 } 37 ]; 38 39 mObj.c3= 40 [ 41 { 42 lat:35.591418, 43 lng:139.546924, 44 icon:"./z_icon/3_c.png" 45 } 46 ]; 47 48// console.log(mObj); 49 50function initialize() { 51 var latlng = new google.maps.LatLng(35.680552, 139.766923); 52 var opts = { 53 zoom: 11, 54 center: latlng, 55 mapTypeId: google.maps.MapTypeId.ROADMAP 56 }; 57 map = new google.maps.Map(document.getElementById("map"), opts); 58 59var mObjKeys=Object.keys(mObj); 60var keyLen=mObjKeys.length; 61 62 for (var i = 0; i < keyLen; i++) { 63 for (var j = 0; j < mObj[mObjKeys[i]].length; j++) { 64 if(j==0){ 65 marker[mObjKeys[i]]={[j]:new google.maps.Marker({ 66 position: new google.maps.LatLng({lat:mObj[mObjKeys[i]][j]['lat'],lng:mObj[mObjKeys[i]][j]['lng']}), 67 map: map, 68 icon:new google.maps.MarkerImage(mObj[mObjKeys[i]][j]['icon'],null,null,null,new google.maps.Size(41, 41)) 69 }) 70 } 71 infoWindow[mObjKeys[i]]={[j]: new google.maps.InfoWindow({ // 吹き出しの追加 72 content:mObj[mObjKeys[i]][j]['contents'] 73 }) 74 } 75 76 } else if(j>0){ 77 marker[mObjKeys[i]][j]=new google.maps.Marker({ 78 position: new google.maps.LatLng({lat:mObj[mObjKeys[i]][j]['lat'],lng:mObj[mObjKeys[i]][j]['lng']}), 79 map: map, 80 icon:new google.maps.MarkerImage(mObj[mObjKeys[i]][j]['icon'],null,null,null,new google.maps.Size(41, 41)) 81 }); 82 infoWindow[mObjKeys[i]][j]= new google.maps.InfoWindow({ // 吹き出しの追加 83 content:mObj[mObjKeys[i]][j]['contents'] 84 }); 85 } 86 markerEvent(i,j) 87 function markerEvent(i,j){ 88 marker[mObjKeys[i]][j].addListener('click', function() { // マーカーをクリックしたとき 89 infoWindow[mObjKeys[i]][j].open(map,marker[mObjKeys[i]][j]); // 吹き出しの表示 90 }); 91 } 92 } 93 } 94} 95 96console.log(infoWindow); 97/* 98{ 99 c1:{0:_.Sf} 100 c3:{0:_.Sf} 101 k1:{0:_.Sf} 102 k2:{0:_.Sf,1:_.Sf} 103} 104*/ 105/*ckCloseボタンによりすべてのMarkerを削除する*/ 106$(function(){ 107 $('.ckClose').on('click',function(){ 108 var markerKeys=Object.keys(marker); 109 var markerLen=markerKeys.length; 110 for (var i = 0; i < markerLen; i++) { 111 for (var j = 0, innerLen=Object.keys(marker[markerKeys[i]]).length; j <innerLen ; j++) { 112 marker[markerKeys[i]][j].setMap(null); 113 infoWindow[markerKeys[i]][j].close();//ここが動作しない 114 infoWindow["k2"][0].close();//これは動作する 115      console.log(infoWindow[markerKeys[i]][j]==infoWindow["k2"][0])//["k2"][0]のループの時にはtrueを返す 116 } 117 } 118 }) 119}) 120 121/*ckOpenボタンによりすべてのMarkerを表示する*/ 122$(function(){ 123 $('.ckOpen').on('click',function(){ 124 var markerKeys=Object.keys(marker); 125 var markerLen=markerKeys.length; 126 for (var i = 0; i < markerLen; i++) { 127 for (var j = 0, innerLen=Object.keys(marker[markerKeys[i]]).length; j <innerLen ; j++) { 128 marker[markerKeys[i]][j].setMap(map); 129 } 130 } 131 }) 132})

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mix-peach

2019/10/25 01:44

質問の説明文内に例示されている部分的なコードと、ご提示コードでは使っている変数が異なるようですが、実際に動作しないコードをご提示いただいていますか? また、close()実行で消えない時に、何かエラーは出ていないのでしょうか? あと、infoWindowの定義場所と中身の作成コードの追記、windowsは定義可能なところまでサンプルを実データに近づけてもらえると回答者が検証しやすくなると思います。
pegy

2019/10/25 03:21 編集

コメントを頂きまことにありがとうございます。 最小化しようと努めたのですがかえってわかりづらく申し訳ございません。コードの全貌を記載させていただきました。なお、もう一点ご指摘にあったエラーについては、上記のコードで動作させた結果についても、Developer ToolのConsole上、何も出力されておりません。 よろしくお願い申し上げます。
mix-peach

2019/10/25 05:25

「インフォウィンドウが消えない」現象の発生手順と内容は、 【手順】 ①initialize()の実行で、地図とマーカーが初期表示された状態で、地図上のマーカーをクリックして、インフォウィンドウを表示する ②.ckCloseクリックで、全マーカ・インフォウィンドウを非表示にする ③.ckOpenクリックで再表示する 【現象の内容】 → ③で、インフォウインドウが出た状態のままになっている ということで合ってますか?それとも他の手順で発生する別の現象でしょうか?(後者であれば発生手順を詳しく教えてほしいです)
pegy

2019/10/25 05:38

コメント頂き誠にありがとうございます。 申し訳ございません、ご指摘の重要な情報を開示することを失念しておりました。 仰って頂いた内容の通り(前者)です。 宜しくお願い申し上げます。
guest

回答1

0

ベストアンサー

どうやら、インフォウィンドウの.close()は、
地図上に表示されているものがあれば、閉じますよ! という処理のようです。

なので、処理順序さえ変えれば、期待する動作になりました。

javascript

1 $('.ckClose').on('click',function(){ 2 var markerKeys=Object.keys(marker); 3 var markerLen=markerKeys.length; 4 for (var i = 0; i < markerLen; i++) { 5 for (var j = 0, innerLen=Object.keys(marker[markerKeys[i]]).length; j <innerLen ; j++) { 6 infoWindow[markerKeys[i]][j].close();//インフォウィンドウを閉じてから 7 marker[markerKeys[i]][j].setMap(null);//マーカーを消す 8 } 9 } 10 })

なお、infoWindow["k2"][0].close();//これは消えるこちらですが、
実は「期待した通りに動いていた」わけではなく、infoWindow["k2"][0]がLoop処理の1件目ではないので、infoWindow["k2"][0]に限って、
・インフォウィンドウを消す
・マーカーを消す
の順番で処理が行われた為、「たまたま期待する動作になっていた」ということになります。

元の処理順序のまま、for文の外に出してみると

javascript

1 $('.ckClose').on('click',function(){ 2 var markerKeys=Object.keys(marker); 3 var markerLen=markerKeys.length; 4 for (var i = 0; i < markerLen; i++) { 5 for (var j = 0, innerLen=Object.keys(marker[markerKeys[i]]).length; j <innerLen ; j++) { 6 marker[markerKeys[i]][j].setMap(null);//マーカーを消す 7 infoWindow[markerKeys[i]][j].close();//インフォウィンドウを閉じる 8 } 9 } 10 infoWindow["k2"][0].close();//これでは消えないのです 11 })

期待する動作になりませんので、このコードのみでインフォウィンドウが消えるわけではないことが分かるはず。。。

以上、ご参考までに・・!


追記です。

close()メソッドが表示を前提にしているという仕様

こちらは断言できる程js内部は確認してないので、「・・のようです」と書きました・・。
が一応、close()メソッド自体は、表示有無にかかわらず実行出来てエラーにならないことと、実際には表示されているときしか閉じられないことの2点からそのように判断をした感じです。

今回の場合は、動作確認用に書いたコードが「うまくいっちゃった」のが、原因解明できなくなってしまった主な原因ですよね。
自らの罠にはまることは、たぶんベテランさんでもたまに起きちゃうので仕方ないと思います。
ただそこから打開策まで辿り着くための、経験値等が足りないだけ・・かなぁと。

本当は、「やりたいけど、できないことだけをミニマム」で実行して、動作確認してみたらよかっただけなのです。(これ、teratailで回答者さん側の助言でよく見かけると思います)

今回の話で言うなら、

javascript

1//マーカーを消すところを一旦コメントアウトする 2// marker[markerKeys[i]][j].setMap(null);//マーカーを消す 3 infoWindow[markerKeys[i]][j].close();//インフォウィンドウを閉じる

こうするだけで、「ループでclose()で閉じることができない」と思っていた

infoWindow[markerKeys[i]][j].close();//インフォウィンドウを閉じる

ここには、実際には問題がないことに気づけます。
気づけさえすれば、

上手く行かない時と何がちがうのか

「マーカーを先に消している」ことだけ違う

じゃあ「マーカーを先に消している」ことが、上手く行かない原因なのだろうから、後で消してみてはどうだろう・・

と打開策に辿り着けたハズ・・・です!多分! ^^


常に一つだけ表示したいのであれば、複数をオブジェクトにして保持して置かなくても良いのでは?と思いますが、
現状維持かつ、ループが面倒というのであれば、

javascript

1function markerEvent(i,j){ 2 if(nowInfoWindow){ nowInfoWindow.close(); } 3 nowInfoWindow = infoWindow[mObjKeys[i]][j]; 4 marker[mObjKeys[i]][j].addListener('click', function() { // マーカーをクリックしたとき 5 nowInfoWindow.open(map,marker[mObjKeys[i]][j]); // 吹き出しの表示 6 }); 7}

とするだけでも良さそうかなと思います(nowInfoWindowは先頭で宣言を追加してくださいね)。

が、新しい変数を使いたくなければ、おとなしくループするしかないかも・・・
ただし、ループの場合、オブジェクトの中身が多くなればなっただけ処理が重たくなっていく可能性が高いですので、その点ご注意を。。。

投稿2019/10/25 07:56

編集2019/10/30 05:36
mix-peach

総合スコア1910

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pegy

2019/10/25 12:12

ありがとうございます。仰る通り順番を変えるだけで実装することができました! さて、今回の件に関しては、close()メソッドが表示を前提にしているという仕様であるということかと思うのですが、どのようにしてその答えにたどり着いたのがもしよければご参考にご教示いただけませんでしょうか? Google Map APIのインストラクションを読んでもわからず、またエラー出力もないのでお手上げ状態だったのですが、どのようなアプローチやプロセスでこういった状況から原因にたどり着くことができるのがをぜひ勉強をさせていただきたく、よろしくお願い申し上げます。
pegy

2019/10/25 13:24

また、ここで質問すべき内容か改めて質問を立てるべきか迷ったのですが、自分はマーカーやインフォウィンドウについてそれぞれすべてユニークなものを割り当てているのでオブジェクトの中に入れて添字であるk1やk2と言ったものを割り当てるとともにすべてのマーカーやウィンドウを処理したい場合にはオブジェクトの中身をループ処理させています。一方で特定のマーカーやインフォウィンドウを処理したい場合にはk1を指定すると言った具合です。 ここで、 markerEvent(i,j)関数を作成した通り、それぞれのマーカーをクリックしたらそれぞれにユニークなインフォウィンドウが開きます、またその際に既に開いているwindowを閉じたい(開いているウィンドウは常に一つという状態にしたいと考えております。 function markerEvent(i,j){ marker[mObjKeys[i]][j].addListener('click', function() { // マーカーをクリックしたとき      /*infowWIndow[mObjKeys[i]][j]以外のすべての吹き出しをclose()*/ infoWindow[mObjKeys[i]][j].open(map,marker[mObjKeys[i]][j]); // 吹き出しの表示 }); } として吹き出し表示の間にclose()を入れたいのですが、上述の都合でそれぞれのマーカーに固有のインフォウィンドをループでつけているため通常であればopenする前のif(infowindow) infowindow.close();のようなことができません。  ・一つ表示したら既に表示しているインフォウィンドウはclose()したい  ・ただし、インフォウィンドウはそれぞれ添字を割り当てられた複数種類存在する と言う場合、これをうまく実装するアイデアが思い浮かばず、もし思いつくものがあればお知恵をいただければ嬉しいです。 重ねて申し訳ございませんが、 よろしくお願い申し上げます。
pegy

2019/10/25 13:45

上記の2つ目の質問についてですが、ループ処理の中で全く別のループ処理を入れることで実装できました。 ただ、すごく読み取りづらいコードで深いループ処理なので、この実装方法が本当に適切であるのかとても自分で懐疑的です。。 そもそもインフォウィンドウについて複数のマーカーがある場合、オブジェクトを作って要素を与えて個別に割り当てるようなやり方(infowindow[mObjKeys[i]][j])の記事は探してもあまり出てこないためちょっと自分の考え方自体を疑っています。 一応、このようなケースで実装できたコードは下記の通りです。 markerEvent(i,j) function markerEvent(i,j){ marker[mObjKeys[i]][j].addListener('click', function() { // マーカーをクリックしたとき var keys =Object.keys(infoWindow) var keylen =keys.length for (var k = 0; k < keylen; k++) { for (var l = 0; l < Object.keys(infoWindow[keys[k]]).length; l++) { infoWindow[keys[k]][l].close();//一旦すべてのinfowindowオブジェクトに含まれる要素 をループにより非表示とする } } infoWindow[mObjKeys[i]][j].open(map,marker[mObjKeys[i]][j]); // 吹き出しの表示 }); }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問