シンボル(SVG)を直線に沿ったアニーメーションで移動する |Google Maps API v3
GoogleMapsAPIで描画したポリライン上に沿って、
ポリラインシンボルを描画し、アニメーションで動かして表現をすることができます。
ここでは矢印をポリラインに沿って動かすサンプルでご紹介します。
地図の表示
以下は指定した座標(「姫路城」と「三の丸広場南」)を、
結ぶポリラインを表示しています。
ポリラインの上に「Λ」マークを描画し、
2点間を移動するアニメーションを描画します。
初期状態では10ミリ秒単位で描画を行い、
ポリライン全体を200分割したコマ数でシンボルを移動します。
ポリライン上を3回アニメーションしたのち、停止します。
以下のフィールドに「半角数字」で値を入力し、
「再度実行する」をクリックすると設定した速度でアニメーションが行われます。
補足
地図上にポリラインを表示(「姫路城」と「三の丸広場南」を結ぶ直線)する
方法については以下でご紹介しています。
またポリライン上にSVGパスを表示する手順については、
以下でご紹介しています。
描画するSVGシンボルは独自にSVGパスで指定して描画できるものであれば、
表示することができますが、5種類は定数で指定することができます。
表示したシンボルを動かす処理についてここでは補足します。
基本的に「window.setInterval」にてSVGパスの描画位置を、
ポリライン全体のうち0%~100%の間で指定することで、
疑似的にアニメーション表示を行っているものです。
上記のサンプルで、以下の値などに指定すると、
10%ずつ矢印が進みますので、コマ送りに見えるのが分かる事と思います。
- 更新頻度(ミリ秒・半角):200
- 全体の分割数(半角):10
シンボルのインターバル描画を実際に行っている部分が以下の部分です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//描画処理 function drawSymbol(line, options){ var icons = line.get('icons'); Intervalcount = (Intervalcount +1) % options.div_num +1; icons[0].offset = (Intervalcount / options.pos) + '%'; //Intervalcount = (Intervalcount + 1) % 200; //icons[0].offset = (Intervalcount / 2) + '%'; line.set('icons', icons); if(Intervalcount / 2 == 1){ //1%位置から描画開始(回数をカウント) interval_cnt = interval_cnt +1; } if(interval_cnt > options.loopcnt ){ //指定回数でインターバル停止 window.clearInterval(intervalID); icons[0].offset = C_HOME_POS; //描画停止位置 Intervalcount = 0; interval_cnt = 0; intervalID = null; } } |
4行目で、ラインを生成した際に描画済みのシンボルを取得しています。
Intervalcountはインターバル実行が行われる度に計算されます。
分割数(options.div_num)で指定した値の余りを求めて格納していますので、
常に分割数で指定した値の範囲内でカウントが繰り返されます。
1 |
Intervalcount = (Intervalcount +1) % options.div_num +1; |
options.posは分割数を100で割った1描画当たりのパーセントが格納されており、
Intervalcountをそれを割って、現在のシンボル描画位置のパーセントを割り出しています。
1 |
icons[0].offset = (Intervalcount / options.pos) + '%'; |
この辺の処理は数値固定で書かれた、
以下のサンプルソースを見た方が理解しやすいかと思います。
Animating Symbols | Google Maps JavaScript API | Google Developers
基本的にはインターバル実行で繰り返し、
シンボルの描画位置(パーセント指定)を毎回少しずつずらす処理をしているだけです。
2017/01/26追記
以下のサンプルコードではインターバル処理の呼び出し部に、
第三パラメータを含む形の関数呼び出しを利用しています。
以下のような処理方法ですが、このままではIEでは動作しません。
その為、IEに影響のないような記述方法を採用されることをお勧めします。
サンプルコード
HTML
HTMLではGoogle Mapを表示するエリア(<div id=”gmap_canvas”></div>)を配置しています。
エリアを囲んでいる「<div class=”aspect”></div>」部分は、
ページ表示用の高さ制御用のタグです。
1 |
<div class="aspect"><div id="gmap_canvas" class="g_canvas"></div><span id="ver" style="font-size: 0.8em; color: gray;"></span></div> |
CSS
CSSではclass=”aspect”に対して、 幅100%を指定し、 高さをビューポートの50%としています。 GoogleMapを表示するエリア(id=”gmap_canvas”)のサイズを、 class=”aspect”に対しての幅・高さを100%として指定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<style type="text/css"> .aspect{ width:100%; height:50vw; } .aspect_normal, .aspect_dot, .aspect_key, .aspect_dotkey{ width:100%; height:25vw; } #gmap_canvas, #gmap_canvas_normal, #gmap_canvas_dot, #gmap_canvas_key, #gmap_canvas_dotkey, div.g_canvas{ width:100%; height:100%; } </style> |
JavaScript
上記の補足説明の通りです。
ここでは便宜上、JavaScriptのファイル上からボタンを出力しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
<label>更新頻度(ミリ秒・半角):<input type="text" class ="gmap_btn" id="refresh" value="10" style="width:50px;ime-mode:disabled;"/></label> <label>全体の分割数(半角):<input type="text" class ="gmap_btn" id="divnum" value="200" style="width:50px;ime-mode:disabled;"/></label> <label>表示回数(半角):<input type="text" class ="gmap_btn" id="loopcnt" value="3" style="width:50px;ime-mode:disabled;"/></label> <button class ="gmap_btn" id="del" onclick="animateSymbol(0);"/>再度実行する</button> <script type="text/javascript"> //global var markers = []; var gmap_canvas; var map_div = document.getElementById("gmap_canvas"); var points = [ {location:"三の丸広場南(姫路城)", latlng:{lat:34.836508 , lng:134.693319},icon: "https://mt.google.com/vt/icon/name=icons/onion/SHARED-mymaps-container-bg_4x.png,icons/onion/SHARED-mymaps-container_4x.png,icons/onion/1535-camera-photo_4x.png&highlight=ff000000,0288d1,ff000000&scale=2.0"}, {location:"姫路城", latlng:{lat: 34.839450, lng:134.693903},icon: "https://mt.google.com/vt/icon/name=icons/onion/SHARED-mymaps-pin-container-bg_4x.png,icons/onion/SHARED-mymaps-pin-container_4x.png,icons/onion/1899-blank-shape_pin_4x.png&highlight=ff000000,e65100,ff000000&scale=2.0"} ]; var lcnt = points.length; var Intervalcount = 0; var intervalID; var interval_cnt = 0; var pline; const C_HOME_POS = '55%'; //地図を描画 function init(){ gmap_canvas = new google.maps.Map(map_div,{ center: {lat:34.838037, lng:134.693454}, zoom : 18, mapTypeId : google.maps.MapTypeId.ROADMAP }); dropMakers(); animateSymbol(); } //init() end //マーカーの生成と表示 function create_marker(options){ //ここで生成したマーカーを順次格納する var maker = new google.maps.Marker(options); markers.push(maker); } //マーカーを表示 function dropMakers(){ //新たに生成 var i=0; for (i=0; i < lcnt; i++){ //アイコン画像指定(リサイズ処理) var icon_opt = { url: points[i].icon, scaledSize:new google.maps.Size(32,32) }; marker = create_marker({ map: gmap_canvas, position: points[i].latlng, title:points[i].location, icon: icon_opt }); } } //ライン・ラインシンボルインターバル描画 function animateSymbol(func=null) { if(func != null){ pline.set('icons', null); //ラインマーカ初期化 window.clearInterval(intervalID); //初期化 } //ライン上シンボルオプション定義 var lineSymbol_FORWARD_OPEN_ARROW = { path: google.maps.SymbolPath.FORWARD_OPEN_ARROW, scale: 3, strokeColor: '#e65100', strokeWeight: 2 }; //ポリラインオプション定義 var polyopt = { map: gmap_canvas, path: [points[0].latlng, points[1].latlng], strokeColor: "#e65100", strokeOpacity: 1, strokeWeight: 2, zIndex: 1, icons: [ {icon: lineSymbol_FORWARD_OPEN_ARROW, offset: C_HOME_POS}, //描画停止後の描画位置 ] }; //ライン描画 pline = new google.maps.Polyline(polyopt); //値の取得と設定 options = getVal(); //インターバル実行 intervalID = window.setInterval(drawSymbol , options.refresh, pline, options); } //描画処理 function drawSymbol(line, options){ var icons = line.get('icons'); Intervalcount = (Intervalcount +1) % options.div_num +1; icons[0].offset = (Intervalcount / options.pos) + '%'; //Intervalcount = (Intervalcount + 1) % 200; //icons[0].offset = (Intervalcount / 2) + '%'; line.set('icons', icons); if(Intervalcount / 2 == 1){ //1%位置から描画開始(回数をカウント) interval_cnt = interval_cnt +1; } if(interval_cnt > options.loopcnt ){ //指定回数でインターバル停止 window.clearInterval(intervalID); icons[0].offset = C_HOME_POS; //描画停止位置 Intervalcount = 0; interval_cnt = 0; intervalID = null; } } //値の取得 function getVal(){ var def_refresh = 10; //◆設定◆更新頻度(ミリ秒)小さいと速くなるがCPU負荷が増す var def_divnum = 200; //◆設定◆100%の分割数(200⇒0.5%単位描画)大きいとコマ送りになる var def_loopcnt = 3; var o_refresh = document.getElementById("refresh").value; var o_divnum = document.getElementById("divnum").value; var o_loopcnt = document.getElementById("loopcnt").value; var n_refresh = chkNum(o_refresh); if(n_refresh == false){n_refresh = def_refresh;} var n_divnum = chkNum(o_divnum); if(n_divnum == false){n_divnum = def_divnum;} var n_loopcnt = chkNum(o_loopcnt); if(n_loopcnt == false){n_loopcnt = def_loopcnt;} var options = { refresh: n_refresh, div_num: n_divnum, //divnumに同じ pos: n_divnum /100, //分割数から計算した描画位置(%) loopcnt: n_loopcnt //描画回数 }; return options; } function chkNum(str){ if (str.match(/[^0-9]/g) || str == "" ){ return false; } return parseInt(str, 10); } google.maps.event.addDomListener(window,"load",init); $('#ver').text(google.maps.version); </script> |
別途、GoogleMapsAPIのライブラリを読み込む記述が必要です。 ご自分が取得されたAPIキーを以下のコードの(YourAPIkey)部分に置き換えて設定してください。
1 2 |
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=(YourAPIkey)&v=3"></script> |
参考
図形 | Google Maps JavaScript API | Google Developers
シンボル | Google Maps JavaScript API | Google Developers
window.setInterval – Web API インターフェイス | MDN
window.clearInterval – Web API インターフェイス | MDN
当サイトにお越しいただきありがとうございます。
当サイトは管理人アルゴリズンが個人で作成を行っているものです。
Google Inc.様とは一切関係はありません。
当サイト内のコンテンツの引用・出典の明記なきものは、
すべて管理人アルゴリズンが著作権を保持するオリジナルコンテンツです。
当サイトでご紹介しております写真等がある場合にも著作権の放棄は致しません。
申し訳ございませんが、無断転載、複製をお断りさせて頂いております。
尚、サイト内コンテンツを引用される際にはご連絡は不要です。
ただし、出典元として当サイト(個別URL)へのリンクをお願いいたします。
コンテンツを有益であると感じていただけましたら非常に光栄です。
ありがとうございます。
記事の作成依頼・更新依頼・削除要請などのご意見ご要望は、
まず、Twitter等よりメンションまたは、メッセージでご連絡を頂けますと幸いです。
@algorhythnn|Twitter
algorhythnn|Google+
algorhythnn|Facebook
運営者はSNS等で個人名等の公開は行わないポリシーで運営しております。
直接のご連絡・取材時などには個人名・屋号でご連絡を差し上げる場合もございますが、
個人名・屋号等をインターネット上で公開されることはご遠慮願います。
公開日: