Start地点、Goal地点近傍のトラックポイントを消去する。
変更履歴:
・経路(トラック)に沿って、消去するようにした(今までは、経路に関係なく、近ければ消去していた)。(2015-11-08)
・オブジェクト指向化した(コンストラクタを作成した)。(2015-11-08)
・メインのコードをhtmlファイルに記載するようにした。(2015-11-08)
応用例(GpxClipper:gpxファイルを加工するウェブアプリ)
◆html
70,71行目:ボタンのクリックで gpx_clip() を実行する。
19行目以降:xmlファイル(sample.xml)の読み込み。
29行目:コンストラクタGpxClipを用いてインスタンスgpxclipを作成する。
36行目:gpxclipを初期化する。
37行目:描画する。
xml ファイルの読み込みには、jQuery の $.ajax を使う。
29-37行目:ファイルを読み込んだ後に実行するスクリプト
19行目以降:xmlファイル(sample.xml)の読み込み。
29行目:コンストラクタGpxClipを用いてインスタンスgpxclipを作成する。
36行目:gpxclipを初期化する。
37行目:描画する。
xml ファイルの読み込みには、jQuery の $.ajax を使う。
29-37行目:ファイルを読み込んだ後に実行するスクリプト
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <link rel=icon href=../_img/BlueSky_favicon.png sizes="16x16" type="image/png">
- <title>gpxClipper</title>
- <script src="http://maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false"></script>
- <script src="jquery.js"></script>
- <script src="gpxClipperTest.js"></script>
- <script src="gmOverlayHtml.js"></script>
- <!--
- http://www.atmarkit.co.jp/ait/articles/1112/16/news135.html
- -->
- <script>
- $(function() {
- url_gpx = "sample.xml";
- // XMLファイル読み込み開始
- $.ajax({
- url: url_gpx,
- cache:false,
- dataType:"xml",
- error: function(XMLHttpRequest, textStatus, errorThrown){
- alert('読み込みエラー!');
- },
- success:function(data){
- var gpxclip = new GpxClip({
- xml: data,
- // typeId: google.maps.MapTypeId.HYBRID,
- // pathInit: { weight: 1 },
- startButtonId: "start",
- goalButtonId: "goal"
- });
- gpxclip.init();
- gpxclip.draw();
- }
- });
- });
- </script></head>
- <style type="text/css">
- * {
- margin: 0;
- padding: 0;
- }
- html, body {
- height: 100%;
- }
- body {
- overflow: hidden;
- background-color: ivory;
- }
- p {
- background-color: #99cc00
- }
- #map_canvas {
- height: 100%;
- }
- </style>
- <body>
- <input id="start" type="button" value="Startの周辺削除" onclick="gpx_clip(LatLngStart)" style="width:100px" >
- <input id="goal" type="button" value="Goalの周辺削除" onclick="gpx_clip(LatLngGoal)" style="width:100px" >
- <span>半径</span>
- <input type="text" id="clip" value="100" size="3">
- <span>(m) 以内の点を削除</span>
- <div id="map_canvas"></div>
- </body>
- </html>
◆コンストラクタ(GpxClip)
optionsとdefaultsにより、プロパティを設定する。
関数(メソッド)はprototypeで設定する。
関数(メソッド)はprototypeで設定する。
- var GpxClip = function(options) { // ver.2.1
- var defaults = {
- typeId: google.maps.MapTypeId.ROADMAP, // マップタイプ
- timeFontSize: "16px", // 時間表示のフォントサイズ
- period: 30, // 30分ごとに時間を表示
- pathInit: { // 読み込んだxmlのトラックポイント
- color: "Blue", // 線の色
- opacity: 0.5, // 線の透過度
- weight: 5 // 線の幅
- },
- path: { // クリップしたトラックポイント
- image: new google.maps.MarkerImage( // Markerのイメージ
- 'images/point.png', // marker image
- new google.maps.Size(16,16), // marker size
- new google.maps.Point(0,0), // marker origin
- new google.maps.Point(8,8) // marker anchor
- )
- },
- start: { // スタートポイント
- mark: {
- offsetX: -64,
- offsetY: -48,
- content: '<img src="images/start.png">'
- }
- },
- goal: { // ゴールポイント
- mark: {
- offsetX: 0,
- offsetY: -48,
- content: '<img src="images/goal.png">'
- }
- }
- };
- $.extend(true, this, defaults, options); // デフォルトオプションと渡されたオプションのマージ
- this.period = this.period*60*1000; // 分→msに変換
- };
初期処理(GpxClip.prototype.init)
5-11行:出力用のxmlを作成する。13-50行:xmlファイルから緯度(Lat)、経度(Lng)、日時を取り込んで、初期のポイント(self.pathInit.point)、クリップ後のポイント(self.path.point)を初期化する。
28行:marker の一括消去用の配列を定義する。
30-35:Google Map を描画。
52-56行:Start地点、Goal地点を初期化する。
58-64行:トラックを描画。
66-73行:ボタンの設定。
- GpxClip.prototype.init = function(){
- var self = this;
- // $(self.xml).find("name").each(function(){
- // $(this).text("gpxClipper");
- // });
- // <name>タグのテキストが日本語の場合エラーがでるので、すべてgpxClipperに変更するようにした。 2014-12-14
- // 問題なくなっていたので、コメントアウトした 2016-05-13
- // 日本語があるとUTF-8、ないとShift-JISで保存されるようである。
- var serializer = new XMLSerializer();
- var xmlString = serializer.serializeToString(self.xml);
- setBlobUrl("download", xmlString);
- self.path.point = [];
- self.pathInit.point = [];
- $(self.xml).find("trkpt").each(function(i){
- var Lat = this.getAttribute("lat");
- var Lng = this.getAttribute("lon");
- var LatLng = new google.maps.LatLng(Lat,Lng);
- var date = new Date($(this).find("time").text());
- self.pathInit.point.push(LatLng);
- self.path.point[i] = {
- latlng: LatLng,
- date: date,
- }
- });
- self.markerList = new google.maps.MVCArray();
- var layout = new GmLayout('map_canvas', self.path.point);
- self.map = new google.maps.Map(document.getElementById('map_canvas'),{
- zoom: layout.zoom,
- center: layout.center,
- mapTypeId: self.typeId
- });
- $(self.xml).find("trkpt").each(function(i){
- self.path.point[i].marker = new google.maps.Marker({
- position: self.path.point[i].latlng,
- map: self.map,
- icon: self.path.image
- });
- self.path.point[i].infobox = self.setInfobox (self.path.point[i]);
- });
- self.path.point[0].distance = 0;
- for ( i=1; i<self.path.point.length; i++) {
- self.path.point[i].distance = self.path.point[i-1].distance
- + google.maps.geometry.spherical.computeDistanceBetween(self.path.point[i].latlng, self.path.point[i-1].latlng);
- }
- self.start.distance = self.path.point[0].distance;
- self.goal.distance = self.path.point[self.path.point.length-1].distance;
- self.start.index = 0;
- self.goal.index = self.path.point.length-1;
- var flightPath = new google.maps.Polyline({
- path: self.pathInit.point,
- strokeColor: self.pathInit.color,
- strokeOpacity: self.pathInit.opacity,
- strokeWeight: self.pathInit.weight
- });
- flightPath.setMap(self.map);
- $('#'+self.startButtonId).on( "click", function(){
- self.distanceClip = $("#clip").val();
- self.clipStart();
- });
- $('#'+self.goalButtonId).on( "click", function(){
- self.distanceClip = $("#clip").val();
- self.clipGoal();
- });
- }
描画(GpxClip.prototype.draw)
gpxファイルをGoogle Map 上に描画する。
- GpxClip.prototype.draw = function (){
- var self = this;
- // トラックポイントのマークを表示
- var trkptLength = $(self.xml).find("trkpt").length;
- for ( i=self.start.index; i<self.goal.index+1; i++) {
- self.path.point[i].marker.setMap(self.map);
- self.markerList.push(self.path.point[i].marker);
- self.setMarkerInfo(self.path.point[i].marker, self.path.point[i].infobox) ;
- }
- // Startのマークを表示
- var i = self.start.index;
- var infobox = self.setInfobox (self.path.point[i]);
- infobox.setMap(self.map);
- self.markerList.push(infobox);
- var mark = new GMOverlayHtml({
- map: self.map,
- position: self.path.point[i].latlng,
- offsetX: self.start.mark.offsetX,
- offsetY: self.start.mark.offsetY,
- content: self.start.mark.content
- });
- mark.setMap(self.map);
- self.markerList.push(mark);
- var min = self.path.point[i].date.getTime() % self.period;
- var nextTime = (self.path.point[i].date.getTime() - min) + self.period;
- for ( i = 0; i < self.path.point.length; i++ ) {
- if(self.path.point[i].date.getTime() > nextTime){
- var infobox = self.setInfobox (self.path.point[i]);
- infobox.setMap(self.map);
- var min = self.path.point[i].date.getTime() % self.period;
- var nextTime = (self.path.point[i].date.getTime() - min) + self.period;
- }
- }
- // Goalのマークを表示
- var i = self.goal.index;
- var infobox = self.setInfobox (self.path.point[i]);
- infobox.setMap(self.map);
- self.markerList.push(infobox);
- var mark = new GMOverlayHtml({
- map: self.map,
- position: self.path.point[i].latlng,
- offsetX: self.goal.mark.offsetX,
- offsetY: self.goal.mark.offsetY,
- content: self.goal.mark.content
- });
- mark.setMap(self.map);
- self.markerList.push(mark);
- }
その他のプロトタイプ
- GpxClip.prototype.setInfobox = function (point) {
- var self = this;
- var date = point.date;
- var $content = $('<p></p>').css({
- fontSize: self.timeFontSize
- }).text(
- date.getHours() + ':' + date.getMinutesString()
- );
- var infobox = new GMOverlayHtml({
- map: self.map,
- position: point.latlng,
- offsetX: 0,
- offsetY: -16,
- content: $content[0].outerHTML
- });
- return infobox;
- }
- // gpxの各点に時刻を表示(mouseover時)
- GpxClip.prototype.setMarkerInfo = function (marker, infobox) {
- var self = this;
- google.maps.event.addListener(marker, 'mouseover', function() {
- infobox.setMap(self.map);
- self.markerList.push(infobox);
- });
- google.maps.event.addListener(marker, 'mouseout', function() {
- infobox.setMap(null);
- });
- }
- GpxClip.prototype.clipStart = function(){
- var self = this;
- var cnt=0;
- $(self.xml).find("trkpt").each(function(i){
- var distance = self.path.point[i+self.start.index].distance-self.start.distance;
- if ( distance < self.distanceClip ) {
- $(this).remove();
- cnt++;
- }
- });
- self.start.index = self.start.index + cnt;
- self.start.distance = self.path.point[self.start.index].distance;
- var serializer = new XMLSerializer();
- var xmlString = serializer.serializeToString(self.xml);
- setBlobUrl("download", xmlString);
- self.markerList.forEach(function(marker, idx) {
- marker.setMap(null);
- });
- self.draw();
- }
- GpxClip.prototype.clipGoal = function(){
- var self = this;
- var cnt=0;
- $(self.xml).find("trkpt").each(function(i){
- var distance = self.goal.distance-self.path.point[i+self.start.index].distance;
- if ( distance < self.distanceClip ) {
- $(this).remove();
- cnt++;
- }
- });
- self.goal.index = self.goal.index - cnt;
- self.goal.distance = self.path.point[self.goal.index].distance;
- var serializer = new XMLSerializer();
- var xmlString = serializer.serializeToString(self.xml);
- setBlobUrl("download", xmlString);
- self.markerList.forEach(function(marker, idx) {
- marker.setMap(null);
- });
- self.draw();
- }
Google Maps API のzoom, center を適当な値に設定する関数〔リンク〕
10-13行目:Math.max.apply(null,配列), Math.min.apply(null,配列) は配列の中から最大値、最小値を求める関数。
20-21行目:360°が 256×2zoom に対応していることを利用している〔リンク〕。
- function gmLayout(arrLatLng){
- var arrLat = new Array() ;
- var arrLng = new Array() ;
- for ( i = 0; i < arrLatLng.length; i++ ) {
- arrLat[i] = arrLatLng[i].lat();
- arrLng[i] = arrLatLng[i].lng();
- }
- var maxLat = Math.max.apply(null,arrLat);
- var maxLng = Math.max.apply(null,arrLng);
- var minLat = Math.min.apply(null,arrLat);
- var minLng = Math.min.apply(null,arrLng);
- var ctrLat = (maxLat+minLat)/2;
- var ctrLng = (maxLng+minLng)/2;
- var rangeLat = maxLat-minLat;
- var rangeLng = maxLng-minLng;
- var zoomLat = Math.floor( Math.log(360/rangeLat*$(document).height()/256) / Math.log(2) );
- var zoomLng = Math.floor( Math.log(360/rangeLng*$(document).width()/256) / Math.log(2) );
- this.zoom = Math.min ( zoomLat, zoomLng );
- this.center = new google.maps.LatLng(ctrLat,ctrLng);
- }
分を2桁の文字列に変換するプロトタイプ〔リンク〕
- Date.prototype.getMinutesString = function(){
- var minutes = this.getMinutes();
- if ( minutes < 10 ) {
- minutes = "0" + minutes;
- }
- return minutes;
- }
以上