プロが教えるわが家の防犯対策術!

JavaScriptでGoogleMAPの表示を行いました。watchPositionを使って位置情報が変化するたびにポインタが移動するようにしています。
今は、その位置情報を元に移動経路を線で結びたいと考えていますがうまくいっていません。
取得したデータの格納方法やPolylineの、使い方を教えていただきたいです。
Polyline以外にもっとふさわしいものがあればお願いします。
なるべく詳しい情報やサンプルお願いしたいです。よろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (9件)

こんにちは。


少し時間が取れましたので、もう少し調べてみました。

単純なラインを引くものを探してみましたが見当たらないようです。(Polylineでカバーできるからかな?)
一方で、ANo2の例では経路のデータを保持するようにしていましたが、Polyline側でもポイントデータを保持しているようなので、どうやら不要なことがわかりました。(無駄に重複するので)
結果的に、新しい座標データをPolylineのPathデータに追加すれば自動的に反映される仕組みになっているようで、逐次の処理は簡単なものになります。

・・・などを踏まえて、ANo2よりはもう少し全体的にそれらしいものを作成してみました。
とは言っても、私は、navigator.geolocationを利用したことがなく、また、テストできる環境にもありません。
ANo2と同様の考えで、navigator.geolocationと似た動作をする(と思う)オブジェクトを作成してテストしています。
それなので、map表示に関する部分については動作確認済と言っても良いと思いますが、geolocation関連部分は未確認です。

※ ブラウザがgeolocationに対応しているかや、位置情報取得時のエラー、あるいは、取得できなかった場合の処理や通信のタイムアウト設定などのチェック等に関しては全て省いていますので、もしも実装なさる場合には、これらの可能性についても対処しておく必要があると思います。
※ レスポンスが頻繁すぎる可能性に配慮して、minInterval以下の間隔での位置情報はスキップするようにしています。
(使ったことがないため、受信頻度がよくわからないので)
※ 現在位置表示は桁揃えしたほうが見やすいと思いますが、とりあえず直のデータです。
※ STARTボタンで追跡を開始、STOPボタンで停止。
※ 移動した際に、現在地をセンター表示するようにしていますが、どちらが良いのかわかりません。

※ 前回同様、インデントは全角空白に置き換えてありますのでご注意。

<!DOCTYPE HTML>
<html lang="ja">
<head><title>sample</title>

<style type-"text/css">
#map_wrap { width: 100%; max-width: 600px; }
#position { padding: 8px; background-color: #CDE; }
#position span { padding-left: 1em; font-size: 90%; }
#map { width: 100%; height: 500px; }
#contorol button { width: 6em; text-align: center; }
#contorol button:last-child { float: right; }
</style>

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false" …

</head>
<body>
<div id="map_wrap">
<div id="position">現在位置:
<span>*** 停止中 ***</span>
</div>

<div id="map">google map</div>

<div id="contorol">
<button type="button">START</button>
<button type="button">STOP</button>
</div>
</div>


<script type="text/javascript">
var Tracker = (function(){

// *** 初期設定・準備処理 ***

var minInterval = 1000; // 情報取得の最少間隔(単位 msec)
var Locator = navigator.geolocation;
var watchID = null;
var MapElement = document.getElementById("map");
var PositionDisp = document.querySelector("#position span");

// マップ 設定
var map = new google.maps.Map( MapElement, { zoom: 15 });

// ポリライン インスタンス作成
var PolyLine = new google.maps.Polyline({
 strokeColor: '#A22', strokeOpacity: 0.55, strokeWeight: 4, map: map
});

// マーカー インスタンス作成
var Markers = createMarker();
function createMarker(){
 var iconURL = "http://labs.google.com/ridefinder/images/";
 var icon1 = new google.maps.Marker({
  icon: iconURL + "mm_20_blue.png", map: map, zIndex: 10
 });
 var icon2 = new google.maps.Marker({
  icon: iconURL + "mm_20_red.png", map: map, zIndex: 12
 });
 return { start: icon1, current: icon2 }
}


// マップ・マーカーの初期表示
var resetMap = function(){
 watchTime = new Date();
 Locator.getCurrentPosition(function(p){
  var pos = { lat: p.coords.latitude, lng: p.coords.longitude };
  map.setCenter(pos);
  Markers.current.setPosition(pos);
  Markers.start.setPosition(pos);
  PolyLine.setPath([new google.maps.LatLng(pos)]);
 });
}

// watchPositionイベント処理
var watchHandler = function(p){
 if((new Date()) - watchTime < minInterval) return;
 watchTime = new Date();
 var pos = { lat: p.coords.latitude, lng: p.coords.longitude };
 map.setCenter(pos);
 Markers.current.setPosition(pos);
 PolyLine.getPath().push(new google.maps.LatLng(pos));
 PositionDisp.innerHTML = "緯度 " + pos.lat + " / 経度 " + pos.lng;
}


// *** 追跡用オブジェクト ***
var tracker = {
 start: function(){
  if(watchID) return;
  resetMap();
  PositionDisp.innerHTML = "*** 受信中 ***";
  watchID = Locator.watchPosition(watchHandler);
 },
 stop: function(){
  Locator.clearWatch(watchID);
  PositionDisp.innerHTML = "*** 停止中 ***";
  watchID = null;
 }
};

resetMap();
return tracker;

})();

// ボタンへのイベント設定
var buttons = document.querySelectorAll("#contorol button");
google.maps.event.addDomListener(buttons[0], "click", Tracker.start);
google.maps.event.addDomListener(buttons[1], "click", Tracker.stop);

</script>
</body>
</html>
    • good
    • 0
この回答へのお礼

ありがとうございます。PCのgoogleでは表示され、IEでは表示されませんでした。携帯のiPhoneでは、どのブラウザでも表示されず動作確認をすることができませんでした。少しプログラムを変更して解決を試みてみましたがうまくいかずどうすれば表示されますでしょうか?

お礼日時:2016/12/12 12:14
    • good
    • 0

今更ですが、念のため・・・



サイトにアップした時はgoogle mapのサイトkeyを設定していますよね?
    • good
    • 0
この回答へのお礼

設定していませんでしたすみません。https://developers.google.com/maps/web/のキーを取得というところから作成してどのようにはればいいですか?

お礼日時:2016/12/13 19:03

こんにちは。



ANo6にも書きましたように、表示する部分に関してはPC環境でテストしています。(fx43 & IE11)
ただし、geolocation部分は簡易的なエミュレーターでテストしましたので、投稿した内容そのままを再度コピペして、テストし直してみました。
(まぁ、PC環境では動かないのはわかっていますが…)

>PCのgoogleでは表示され、IEでは表示されませんでした。
こちらの環境では、fx、IEとも送信許可のメッセージにOKすると地図が表示されますので、一応、 navigator.geolocationには対応しているものと思われます。
ただし、表示される位置(現在地がセンターになるはず)が大分ずれているので、座標値は正確ではないみたいですね。

STARTを押すと、watchPositionのリクエストを行うので、(移動していない)PCからでは反応が無いはずですが、fxでは現在地が返されていました。(想像では、1度だけはレスポンスがあるようです)
IEでは、予想通り何の反応もなく、上部の現在地表示部分が「*** 受信中 ***」表示に変わるだけというのは、予想通りの結果でした。

>どのブラウザでも表示されず動作確認をすることができませんでした
ANo6の内容のままですと、getCurrentPositionで現在地を取得できないと地図が表示できなくなっています。
最初の「マップ設定」でデフォルトの位置をセンターとして与えておけば、現在位置の送受信とは関係なく、デフォルト位置が表示できるようになるはずと思います。
特殊なことは行っていないつもりですので、上記の修正で初期画面として地図が表示できるようにはならないでしょうか?
もし、表示できるようであれば、怪しいのは位置取得関連かなぁ…

ANo6にも書きましたが、クライアントサイドのnavigator.geolocationの実装状況のチェックや、受信時のエラー処理などは行っていませんので、そこでエラーが発生している可能性があります。あるいは、(一応、調べたつもりですが)位置取得部分のコードが正しくないのかもしれません。
送受信でエラーが発生しているかどうかは、getCurrentPositionやwatchPositionの第二引数のcallbackでチェックできたと思いますが、どのあたりでエラーになっているかわかるでしょうか?
    • good
    • 0

ANo4です。

(あまり時間がないのでごめんなさい)

ご提示のコードをざっとしか拝見していませんが、位置を継続監視するつもりなのにsuccessFuncの中で毎回マップを作成したりマーカーを作成したりする必要があるのでしょうか?

ANo1にも書きましたように、WatchPositionのレスポンス間隔がどのくらいの頻度なのか私にはわかりませんが、間隔が短い場合大変なことになりそう…
(google mapってリクエスト回数に制限があったような気がしますが…)

ANo4の例のように、最初に表示しておいて位置情報だけを書き直せば良いように思います。
表示範囲の移動も簡単にできたはずです。
マーカーも同様ですね。
まかーをたくさん表示するのでなければ、最初に作成しておいてその表示位置を移動すればよいだけと思います。


ANo4の例は前半がうるさくてわかりにくかったかも知れませんが、getNextPointが実際のgeolocation.getCurrentPositionに相当するようなイメージで作ったものです。
しかし、getNextPointでは予定のルートが終了したらnullを返すようにして、それでルート表示を終了するような制御をしていますが、実際のgetCurrentPositionには当然ですがそのような仕様はありません。
Ano4は、あくまでも『polyLineを利用した際のマップ上での表示処理』に関するサンプルなので、位置情報取得やその処理はまったく別の話です。
ざっくり言えば、新しいポイントの情報を「経路記録用配列」(routePath)に追加してゆけば、同じように処理することが可能なはずです。

もともとが
>位置情報が変化するたびにポインタが移動するようにしています。
という上でのご質問と思いましたので、そこまでのの処理に関しては理解なさっていらっしゃる前提でいました。


話はかわりますが…
情報としてはかなり古くなってしまっているようですが、geolocationを利用してマップ上にルートを表示なさっている方の解説サイトがありましたので、何かの参考になるかも知れません。
実装のサンプルもあるようです。
(私はPCからなので移動表示の状況は確認できませんが…(笑))
http://kray.jp/blog/geolocation_1/
※ ただし、内容的には初期の頃のものですので、あくまでも考え方や構成の参考です。(コピペなどはしないように)
    • good
    • 0

ANo3です。



>ボタンをクリックしてみても動作しなかったのですが~
多分、ここの投稿の関係で、googleのスクリプト読み込みのURLに改行が入ってしまっているせいではないかと思います。
投稿して気が付いてはいましたが、いずれにしろこのサイトでは、URLはリンク化されて省略表示になってしまうなどあるので、質問者様の方で是正してくださるだろうと・・・

読込のURLはhttp://以降は1行で
 maps.google.com/maps/api/js?sensor=false&libraries=geometry
となるように、修正していただいているでしょうか?

それでも動作しない場合は、スクリプトがエラーで止まっている可能性がありますが、初期状態でマップは表示されているでしょうか?
あるいは、どこでエラーが発生しているかわかりますでしょうか?
一応、こちらの環境では、fx43とIE11で動作を確認しています。
    • good
    • 0
この回答へのお礼

自分のミスでした。正常に動作を確認しました。ありがとうございます。
WatchPositionで取得した位置情報latlngをrouteに格納させるためには
WatchPositionのデータをどのようにいれたらいいのでしょうか?
routeは、var route=[];に変更し、その先がわからない状況です。

// グローバル変数

var syncerWatchPosition = {
count: 0 ,
lastTime: 0 ,
map: null ,
marker: null ,
} ;

// 成功した時の関数
function successFunc( position )
{



// 位置情報
var latlng = new google.maps.LatLng( position.coords.latitude , position.coords.longitude ) ;

// Google Mapsに書き出し
//if( syncerWatchPosition.map == null )
//{
// 地図の新規出力
syncerWatchPosition.map = new google.maps.Map( document.getElementById( 'map-canvas' ) , {
zoom: 17 , // ズーム値
center: latlng , // 中心座標 [latlng]
} ) ;
// マーカーの新規出力
syncerWatchPosition.marker = new google.maps.Marker( {
map: syncerWatchPosition.map ,
position: latlng ,
} ) ;

function Init(){
// 現在位置を取得する
navigator.geolocation.watchPosition( successFunc , errorFunc , optionObj ) ;
}

お礼日時:2016/12/07 16:34

ANo1、2です。



ちょっとだけ時間ができたので、Polylineについてだけ少し調べました。
他にもっと良い方法があるかもしれませんが・・・
方法としては、都度ルートの描画全体を更新する方法です。

疑似的にルートを移動しながら位置を返す関数を作ったら、そっちの方が長くなっちゃった。(汗)
なので、スクリプトの前半はあまり関係ないです。「マップ表示」以降の部分がテストの本体で、実際にルートを更新しているのは一番最後のintervalで繰り返しているところです。

※ 書きっぱなしなので、かなり適当なのと、構成が悪いとかはご容赦。
※ ルートは記録するようにしていますが(routePath)、発生する側でも同じ配列を準備として作っていますので、この例だと同じデータをコピーしているようなことになってしまっています。
※ 左上のボタンを押すとスタートします。

(インデントを全角空白にしてありますのでご注意)

<!DOCTYPE HTML>
<html lang="ja">
<head><title>test sample</title>

<script type="text/javascript" src="http://maps.google.com/maps/api/js?

sensor=false&libraries=geometry"></script>

</head>
<body>

<div>
<button type="button" value="test" onclick="hoge()">テスト START</button>
</div>
<div id="map" style="width:800px; height:600px;">google map</div>

<script type="text/javascript">
// 模擬のルートデータ
var route = [
[ 35.6837, 139.7674 ], [ 35.6836, 139.7673 ], [ 35.6833, 139.7671 ],
[ 35.6831, 139.7670 ], [ 35.6830, 139.7669 ], [ 35.6827, 139.7661 ],
[ 35.6827, 139.7659 ], [ 35.6829, 139.7653 ], [ 35.6829, 139.7651 ],
[ 35.6825, 139.7650 ], [ 35.6819, 139.7647 ], [ 35.6815, 139.7646 ],
[ 35.6809, 139.7644 ], [ 35.6804, 139.7642 ], [ 35.6796, 139.764 ],
[ 35.6793, 139.7639 ], [ 35.6780, 139.7634 ], [ 35.6779, 139.7634 ],
[ 35.6769, 139.7631 ], [ 35.6758, 139.7627 ], [ 35.6757, 139.7635 ],
[ 35.6756, 139.7635 ], [ 35.6755, 139.7635 ], [ 35.6753, 139.7631 ],
[ 35.6751, 139.7628 ]
];

var initRouteData = function(){
 var p, r = [];
 p = route.map(function(pt){ return new google.maps.LatLng(pt[0], pt[1]); });
 r[0] = p[0];
 p.reduce(function(prev, current){
  var n = google.maps.geometry.spherical.computeDistanceBetween(prev, current);
  n = (n / 30) | 0;
  n = n<1?1:n;  
  var dLat = (current.lat() - prev.lat())/n, dLng = (current.lng() - prev.lng())/n;
  for(var i=1; i<=n; i++){
   r.push(new google.maps.LatLng(dLat * i + prev.lat(), dLng * i + prev.lng()));
  }
  return current;
 });
 return r;
}

// 模擬ルート上の位置を順次返す関数
var getNextPoint = (function(){
 var RD = initRouteData(), index = 0;
 return function(){ return index<RD.length? RD[index++]:null; }
})();


// マップ表示
var map = new google.maps.Map( document.getElementById("map"), {
zoom: 16,
center: new google.maps.LatLng( 35.6798, 139.7641 )
});

// 経路記録用配列
var routePath = [ getNextPoint() ];

// ポリラインインスタンス作成
var polyLine = new google.maps.Polyline({
 path: routePath,
 strokeColor: '#006644',
 strokeOpacity: 0.6,
 strokeWeight: 6,
 map: map
});

//適当な間隔で位置を取得して表示してみるテスト
function hoge(){
 var intervalID = setInterval(function(){
  var p = getNextPoint();
  if(p === null){
   clearInterval( intervalID );
  } else {
   routePath.push(p);
   polyLine.setPath( routePath );
  }
 }, 1000);
}
</script>
</body>
</html>
    • good
    • 0
この回答へのお礼

貴重なお時間頂きありがとうございます。
申し訳ないのですが、ボタンをクリックしてみても動作しなかったのですがどうしたらよろしいでしょか。自分の操作ミスでしたら失礼いたしました。

お礼日時:2016/12/07 08:03

ANo1です。



>LatLngの値を変数におきかえて描画していくことは可能でしょうか?
そのまま変数にして関数化しておいて、必要に応じて呼び出せば良いのではないでしょうか?

>その上、移動するたびにそれを更新していかなくてはなりません。
移動したら、全部を更新するか、追加される部分だけ付け加えるか2通りの考え方があると思います。

>B→Cに行った場合A→Bの線はきえてしまうでしょうか?
確認はしていませんが、一つの(Polyline等の)インスタンスを使いまわそうとすると、更新されることになるので、消えてしまうと推測します。
既に描画したものを残して追加する方法の場合は、新しいインスタンスで描画するか、同じインスタンスで書き直すようなイメージになるのではないでしょうか?
ANo1ではPolylineと書きましたが、記憶では、CircleやRectangle描画用のクラスもあったように記憶しています。(こちらの方がさらに扱いやすかったように思います。)
追加するのならポリラインではなく単なる線分でも良いので、丸や四角と同様に線分があればそちらを利用する手もありそうですね。(Lineがあったかの記憶がありません)

追加のパターンが良いのか、1つのインスタンスで扱う方が良いのかは、描画後にどのような処理をなさりたいかによっても変わってくると思います。(データを記録しておくか否かも同様ですね)
私もAPIをよくわかっているわけではなく、前述のリファレンスを見ながら試行錯誤してみる程度です。それなので、リファレンスをよく見てみれば、もっと便利なものがあるのかもしれません。

>なるべく詳しい情報やサンプルお願いしたいです
前記のgoogleサイト以上に詳細な情報はないものと思います。
ご紹介しませんでしたが、サイトにはリファレンス以外にサンプル等も豊富にありますので、そのあたりを眺めて似たようなものを参考にする方法もありかと思います。

※ 今週はほとんど時間がなく、こちらで試してみる時間がとれないので、申し訳ありませんが、ご自分でいろいろ試してみたり他の方の回答を待つなどをしてください。
    • good
    • 0

こんにちは



>取得したデータの格納方法やPolylineの、使い方を~
データは順次配列にいれて記録するか、あるいは、ラインを引くだけで後で参照する必要がなければ、配列は不要で、前回のポイントさえ記録しておけばよいことになりますね。
watchPositionを利用したことがないので、どのくらいの間隔でレスポンスがあるのかわかりませんが、ネットで利用例を見てみると、適当な時間間隔で取得している例が多いですね。(多分、全部処理すると間隔が短すぎるのだと推測します)

google map の javascrit API に関しては、以下のGooglサイトに詳細な説明があります。
https://developers.google.com/maps/documentation …
(どうも、ページ内リンクが上手く動作しないようなので、申し訳ありませんが、必要な記事へのスクロールは自前でお願いします)

実は、ルートを表示してくれる DirectionsRenderer classというのが用意されていて、ルート検索の結果などを表示する際には大変便利なのですが、ルートデータが専用のMVCObjectになっているため、ご質問の場合はデータを作成する手間が返って面倒になりそうな気がします。
ですので、ご質問の通りPolylineを利用するのが良いのではないでしょうか。
(上記リファレンスのPolyline class をご参照ください)

以前、Polylineを利用した回答をしたことがありますのでご参考までに。
https://oshiete.goo.ne.jp/qa/8800586.html
ルートを探索して、その結果を解析し、Polylineを利用してルートを表示しています。
ルート表示以外の余分な部分が多いので、わかりにくいかも知れませんが、Polylineの利用部分だけを抜き出せば比較的単純なのがわかると思います。
    • good
    • 1
この回答へのお礼

詳しい回答をいただき本当にありがとうございます。
色々書き加えてはみましたが応用力が低く、うまくいきませんでした。
A(移動前の座標)→B(現在地の座標)を線で結びたいために、


// 1つ目の線(Polyline)のインスタンスを作成する
// [ new google.maps.Polyline() ]の引数にオプションオブジェクトを指定する
polylines[0] = new google.maps.Polyline( {
map: map ,
path: [
new google.maps.LatLng( 35.794507 , 139.790788 ) ,
new google.maps.LatLng( 35.794007 , 139.791788 ) ,
] ,
} ) ;


のLatLngをどのように書き換えればいいのかわかりません。その上、移動するたびにそれを更新していかなくてはなりません。LatLngの値を変数におきかえて描画していくことは可能でしょうか?
watchPositionで常にLatLngが更新されているので、更新されるたびに格納し、描画していきたいと考えています。
アドバイスや、実例を頂けると助かります。丁寧に説明をいただいたのに再度質問で申し訳ござません。お返事をまっております。


/////////////
B→Cに行った場合A→Bの線はきえてしまうでしょうか?
その場合、最後にまとめて線をひきたいです。
fujillinさんの考えをお聞かせいただけないでしょうか。

お礼日時:2016/12/05 22:18

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


人気Q&Aランキング