[{"data":1,"prerenderedAt":1652},["ShallowReactive",2],{"article-google-map-vuejs":3},{"id":4,"title":5,"body":6,"category":1639,"createdAt":1641,"description":5,"extension":1642,"index":1643,"meta":1644,"navigation":541,"path":1645,"publish":541,"seo":1646,"series":1643,"seriesTitle":1643,"stem":1647,"tag":1648,"thumbnail":1650,"updatedAt":1643,"__hash__":1651},"articles\u002Farticles\u002Fgoogle-map-vuejs.md","Google Maps APIとVue.js を使ってGoogle Map 上にルートを描画する",{"type":7,"value":8,"toc":1626},"minimark",[9,13,18,29,38,44,47,51,60,71,76,94,455,461,464,468,471,498,501,510,521,577,580,583,590,904,912,915,925,940,946,950,956,991,994,997,1191,1197,1200,1225,1228,1231,1234,1237,1244,1247,1366,1376,1379,1382,1386,1389,1393,1396,1399,1414,1421,1584,1603,1606,1609,1613,1616,1619,1622],[10,11,12],"p",{},"こんにちはjunです。自主開発で地図上に描画する機能を実装するときに「Vueを用いてGoogle Map上にラインを描画できないかな？」と思いその方法を調べた結果、なんとか実装できました。今回の記事ではGoogle Map APIを用いてVue（またはVanilla js）で地図の表示とラインの描画機能を実装したいと思います。Google Map APIの取得の仕方とVue.jsのインストールなどはある程度省きます。",[14,15,17],"h2",{"id":16},"google-map-apiを取得する","Google Map APIを取得する",[10,19,20,21,28],{},"詳細な取得方法は省略しますが、最低限必要なものだけ解説します。自前のGoogleアカウントを用いて、",[22,23,27],"a",{"href":24,"rel":25},"https:\u002F\u002Fcloud.google.com\u002Fmaps-platform?hl=ja",[26],"nofollow","Google Cloud Platform","でGoogle Map APIを取得します。",[10,30,31,32,37],{},"毎月$200分までのリクエストは無料なので開発環境には十分でしょう。そしてweb上にGoogleMapを表示するには",[22,33,36],{"href":34,"rel":35},"https:\u002F\u002Fconsole.cloud.google.com\u002Fapis\u002Flibrary\u002Fmaps-backend.googleapis.com?",[26],"Maps JavaScript API","が必要になります。",[39,40],"image-render",{":src":41,":width":42,":center":43},"'_mix\u002Fsch-2021-03-07-17.15.12.png'","'500px'","true",[10,45,46],{},"このAPIを有効にしてAPIキーを手に入れます。まずAPI側のセットアップは以上です。",[14,48,50],{"id":49},"vue側の準備","Vue側の準備",[10,52,53,54,59],{},"今回は",[22,55,58],{"href":56,"rel":57},"https:\u002F\u002Fcli.vuejs.org\u002F",[26],"Vue CLI","を用いて開発します。vue cliを用いて適当にプロジェクトを作成します。",[61,62,67],"pre",{"className":63,"code":65,"language":66},[64],"language-text","$ vue create vue_map\n","text",[68,69,65],"code",{"__ignoreMap":70},"",[72,73,75],"h3",{"id":74},"api-用のjsを読み込む","api 用のJSを読み込む",[10,77,78,81,82,85,86,89,90,93],{},[68,79,80],{},"\u002Fsrc"," 配下にある",[68,83,84],{},"main.js","と",[68,87,88],{},"\u002Fpublic","配下にある",[68,91,92],{},"index.html","に以下のコードを挿入します。",[61,95,100],{"className":96,"code":97,"filename":98,"language":99,"meta":70,"style":70},"language-html shiki shiki-themes material-theme-ocean","\u003C!DOCTYPE html>\n\u003Chtml lang=\"\">\n  \u003Chead>\n    \u003Cmeta charset=\"utf-8\">\n    \u003Cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    \u003Cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    \u003Clink rel=\"icon\" href=\"\u003C%= BASE_URL %>favicon.ico\">\n    \n　　\u003C!-- このスクリプトを挿入-->\n    \u003Cscript src=\"http:\u002F\u002Fmaps.google.com\u002Fmaps\u002Fapi\u002Fjs?key=YOUR_API_KEY&language=ja\">\u003C\u002Fscript>\n   \n　　 \u003Ctitle>\u003C%= htmlWebpackPlugin.options.title %>\u003C\u002Ftitle>\n  \u003C\u002Fhead>\n  \u003Cbody>\n    \u003Cnoscript>\n      \u003Cstrong>We're sorry but \u003C%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.\u003C\u002Fstrong>\n    \u003C\u002Fnoscript>\n    \u003Cdiv id=\"app\">\u003C\u002Fdiv>\n    \u003C!-- built files will be auto injected -->\n  \u003C\u002Fbody>\n\u003C\u002Fhtml>\n","public\u002Findex.html","html",[68,101,102,122,141,152,177,210,242,276,283,290,317,323,345,355,365,375,395,405,431,437,446],{"__ignoreMap":70},[103,104,107,111,115,119],"span",{"class":105,"line":106},"line",1,[103,108,110],{"class":109},"sAklC","\u003C!",[103,112,114],{"class":113},"s-wAU","DOCTYPE",[103,116,118],{"class":117},"sJ14y"," html",[103,120,121],{"class":109},">\n",[103,123,125,128,130,133,136,139],{"class":105,"line":124},2,[103,126,127],{"class":109},"\u003C",[103,129,99],{"class":113},[103,131,132],{"class":117}," lang",[103,134,135],{"class":109},"=",[103,137,138],{"class":109},"\"\"",[103,140,121],{"class":109},[103,142,144,147,150],{"class":105,"line":143},3,[103,145,146],{"class":109},"  \u003C",[103,148,149],{"class":113},"head",[103,151,121],{"class":109},[103,153,155,158,161,164,166,169,173,175],{"class":105,"line":154},4,[103,156,157],{"class":109},"    \u003C",[103,159,160],{"class":113},"meta",[103,162,163],{"class":117}," charset",[103,165,135],{"class":109},[103,167,168],{"class":109},"\"",[103,170,172],{"class":171},"sfyAc","utf-8",[103,174,168],{"class":109},[103,176,121],{"class":109},[103,178,180,182,184,187,189,191,194,196,199,201,203,206,208],{"class":105,"line":179},5,[103,181,157],{"class":109},[103,183,160],{"class":113},[103,185,186],{"class":117}," http-equiv",[103,188,135],{"class":109},[103,190,168],{"class":109},[103,192,193],{"class":171},"X-UA-Compatible",[103,195,168],{"class":109},[103,197,198],{"class":117}," content",[103,200,135],{"class":109},[103,202,168],{"class":109},[103,204,205],{"class":171},"IE=edge",[103,207,168],{"class":109},[103,209,121],{"class":109},[103,211,213,215,217,220,222,224,227,229,231,233,235,238,240],{"class":105,"line":212},6,[103,214,157],{"class":109},[103,216,160],{"class":113},[103,218,219],{"class":117}," name",[103,221,135],{"class":109},[103,223,168],{"class":109},[103,225,226],{"class":171},"viewport",[103,228,168],{"class":109},[103,230,198],{"class":117},[103,232,135],{"class":109},[103,234,168],{"class":109},[103,236,237],{"class":171},"width=device-width,initial-scale=1.0",[103,239,168],{"class":109},[103,241,121],{"class":109},[103,243,245,247,250,253,255,257,260,262,265,267,269,272,274],{"class":105,"line":244},7,[103,246,157],{"class":109},[103,248,249],{"class":113},"link",[103,251,252],{"class":117}," rel",[103,254,135],{"class":109},[103,256,168],{"class":109},[103,258,259],{"class":171},"icon",[103,261,168],{"class":109},[103,263,264],{"class":117}," href",[103,266,135],{"class":109},[103,268,168],{"class":109},[103,270,271],{"class":171},"\u003C%= BASE_URL %>favicon.ico",[103,273,168],{"class":109},[103,275,121],{"class":109},[103,277,279],{"class":105,"line":278},8,[103,280,282],{"class":281},"s0W1g","    \n",[103,284,286],{"class":105,"line":285},9,[103,287,289],{"class":288},"sC9rS","　　\u003C!-- このスクリプトを挿入-->\n",[103,291,293,295,298,301,303,305,308,310,313,315],{"class":105,"line":292},10,[103,294,157],{"class":109},[103,296,297],{"class":113},"script",[103,299,300],{"class":117}," src",[103,302,135],{"class":109},[103,304,168],{"class":109},[103,306,307],{"class":171},"http:\u002F\u002Fmaps.google.com\u002Fmaps\u002Fapi\u002Fjs?key=YOUR_API_KEY&language=ja",[103,309,168],{"class":109},[103,311,312],{"class":109},">\u003C\u002F",[103,314,297],{"class":113},[103,316,121],{"class":109},[103,318,320],{"class":105,"line":319},11,[103,321,322],{"class":281},"   \n",[103,324,326,329,332,335,338,341,343],{"class":105,"line":325},12,[103,327,328],{"class":109},"　　 \u003C",[103,330,331],{"class":113},"title",[103,333,334],{"class":109},">",[103,336,337],{"class":281},"\u003C%= htmlWebpackPlugin.options.title %>",[103,339,340],{"class":109},"\u003C\u002F",[103,342,331],{"class":113},[103,344,121],{"class":109},[103,346,348,351,353],{"class":105,"line":347},13,[103,349,350],{"class":109},"  \u003C\u002F",[103,352,149],{"class":113},[103,354,121],{"class":109},[103,356,358,360,363],{"class":105,"line":357},14,[103,359,146],{"class":109},[103,361,362],{"class":113},"body",[103,364,121],{"class":109},[103,366,368,370,373],{"class":105,"line":367},15,[103,369,157],{"class":109},[103,371,372],{"class":113},"noscript",[103,374,121],{"class":109},[103,376,378,381,384,386,389,391,393],{"class":105,"line":377},16,[103,379,380],{"class":109},"      \u003C",[103,382,383],{"class":113},"strong",[103,385,334],{"class":109},[103,387,388],{"class":281},"We're sorry but \u003C%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.",[103,390,340],{"class":109},[103,392,383],{"class":113},[103,394,121],{"class":109},[103,396,398,401,403],{"class":105,"line":397},17,[103,399,400],{"class":109},"    \u003C\u002F",[103,402,372],{"class":113},[103,404,121],{"class":109},[103,406,408,410,413,416,418,420,423,425,427,429],{"class":105,"line":407},18,[103,409,157],{"class":109},[103,411,412],{"class":113},"div",[103,414,415],{"class":117}," id",[103,417,135],{"class":109},[103,419,168],{"class":109},[103,421,422],{"class":171},"app",[103,424,168],{"class":109},[103,426,312],{"class":109},[103,428,412],{"class":113},[103,430,121],{"class":109},[103,432,434],{"class":105,"line":433},19,[103,435,436],{"class":288},"    \u003C!-- built files will be auto injected -->\n",[103,438,440,442,444],{"class":105,"line":439},20,[103,441,350],{"class":109},[103,443,362],{"class":113},[103,445,121],{"class":109},[103,447,449,451,453],{"class":105,"line":448},21,[103,450,340],{"class":109},[103,452,99],{"class":113},[103,454,121],{"class":109},[10,456,457,460],{},[68,458,459],{},"http:\u002F\u002Fmaps.google.com\u002Fmaps\u002Fapi\u002Fjs","からAPIのソースを手に入れます。できたらnpmあたりでローカルに予めインストールしたいなと思ったのですが、node.js専用だったりとひとまず開発したかったので、今回は外部ファイルとします。このときVue.jsより早く読み込まれるようにしましょう。",[10,462,463],{},"スクリプトのurlにはAPIキーを含めます。公開環境で使用する場合は必ずAPIキーが自サイトのみで使用される条件を設定しておきましょう。でないと第三者に好き勝手にキーを使われて、請求だけはあなたのクレジットカードにきます。",[72,465,467],{"id":466},"プラグインとしてvueに登録しておく","プラグインとしてVueに登録しておく",[10,469,470],{},"上記のソースを読み込めばwindow.googleを見ると、今回使用するAPIを操作できるクラスなりメソッドがあります。",[61,472,476],{"className":473,"code":474,"language":475,"meta":70,"style":70},"language-javascript shiki shiki-themes material-theme-ocean","console.lgo(window.google);\n\u002F**\n*{maps: {…}}\n*\u002F\n","javascript",[68,477,478,483,488,493],{"__ignoreMap":70},[103,479,480],{"class":105,"line":106},[103,481,482],{},"console.lgo(window.google);\n",[103,484,485],{"class":105,"line":124},[103,486,487],{},"\u002F**\n",[103,489,490],{"class":105,"line":143},[103,491,492],{},"*{maps: {…}}\n",[103,494,495],{"class":105,"line":154},[103,496,497],{},"*\u002F\n",[10,499,500],{},"例えば地図を特定のDOMにマウントするときは以下のように呼びます。",[61,502,504],{"className":473,"code":503,"language":475,"meta":70,"style":70},"window.google.maps.Map(document.getElementById('map'),{option});\n",[68,505,506],{"__ignoreMap":70},[103,507,508],{"class":105,"line":106},[103,509,503],{},[10,511,512,513,516,517,520],{},"毎回、",[68,514,515],{},"window.google.maps","とやるのは面倒なので",[68,518,519],{},"this.$gm","と呼び出せるようにプラグイン化しておきます。",[61,522,525],{"className":473,"code":523,"filename":524,"language":475,"meta":70,"style":70},"import Vue from 'vue'\nimport App from '.\u002FApp.vue'\n\n\u002F\u002Fこれ\nVue.prototype.$gm = window.google.maps;\n\nVue.config.productionTip = false\nnew Vue({\n  render: h => h(App),\n}).$mount('#app')\n","src\u002Fmain.js",[68,526,527,532,537,543,548,553,557,562,567,572],{"__ignoreMap":70},[103,528,529],{"class":105,"line":106},[103,530,531],{},"import Vue from 'vue'\n",[103,533,534],{"class":105,"line":124},[103,535,536],{},"import App from '.\u002FApp.vue'\n",[103,538,539],{"class":105,"line":143},[103,540,542],{"emptyLinePlaceholder":541},true,"\n",[103,544,545],{"class":105,"line":154},[103,546,547],{},"\u002F\u002Fこれ\n",[103,549,550],{"class":105,"line":179},[103,551,552],{},"Vue.prototype.$gm = window.google.maps;\n",[103,554,555],{"class":105,"line":212},[103,556,542],{"emptyLinePlaceholder":541},[103,558,559],{"class":105,"line":244},[103,560,561],{},"Vue.config.productionTip = false\n",[103,563,564],{"class":105,"line":278},[103,565,566],{},"new Vue({\n",[103,568,569],{"class":105,"line":285},[103,570,571],{},"  render: h => h(App),\n",[103,573,574],{"class":105,"line":292},[103,575,576],{},"}).$mount('#app')\n",[10,578,579],{},"これで前準備が完了しました。",[14,581,582],{"id":582},"とりあえず地図をマウントする",[10,584,585,586,589],{},"準備が整ったのでvueを用いてGoogle Mapをマウントしましょう。インストール直後にある",[68,587,588],{},"App.vue","を以下のように書きます。",[61,591,596],{"className":592,"code":593,"filename":594,"language":595,"meta":70,"style":70},"language-vue shiki shiki-themes material-theme-ocean","\u003Ctemplate>\n  \u003Cdiv id=\"app\" class=\"mt-4\">\n      \u003Cdiv id=\"map\">\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: 'App',\n  data(){\n    return{\n      map:undefined,\n    }\n  },\n  mounted(){\n   const map = new this.$gm.Map(document.getElementById('map'),{\n      center: { lat: 34.855273888888888, lng: 135.30649 }, \u002F\u002F自由な緯度・経度を入力\n      zoom: 10,\n    });\n　　this.map = map;\n  }\n}\n\u003C\u002Fscript>\n","src\u002FApp.vue","vue",[68,597,598,607,637,660,668,676,680,688,700,720,728,736,744,749,754,761,813,849,861,871,884,889,895],{"__ignoreMap":70},[103,599,600,602,605],{"class":105,"line":106},[103,601,127],{"class":109},[103,603,604],{"class":113},"template",[103,606,121],{"class":109},[103,608,609,611,613,615,617,619,621,623,626,628,630,633,635],{"class":105,"line":124},[103,610,146],{"class":109},[103,612,412],{"class":113},[103,614,415],{"class":117},[103,616,135],{"class":109},[103,618,168],{"class":109},[103,620,422],{"class":171},[103,622,168],{"class":109},[103,624,625],{"class":117}," class",[103,627,135],{"class":109},[103,629,168],{"class":109},[103,631,632],{"class":171},"mt-4",[103,634,168],{"class":109},[103,636,121],{"class":109},[103,638,639,641,643,645,647,649,652,654,656,658],{"class":105,"line":143},[103,640,380],{"class":109},[103,642,412],{"class":113},[103,644,415],{"class":117},[103,646,135],{"class":109},[103,648,168],{"class":109},[103,650,651],{"class":171},"map",[103,653,168],{"class":109},[103,655,312],{"class":109},[103,657,412],{"class":113},[103,659,121],{"class":109},[103,661,662,664,666],{"class":105,"line":154},[103,663,350],{"class":109},[103,665,412],{"class":113},[103,667,121],{"class":109},[103,669,670,672,674],{"class":105,"line":179},[103,671,340],{"class":109},[103,673,604],{"class":113},[103,675,121],{"class":109},[103,677,678],{"class":105,"line":212},[103,679,542],{"emptyLinePlaceholder":541},[103,681,682,684,686],{"class":105,"line":244},[103,683,127],{"class":109},[103,685,297],{"class":113},[103,687,121],{"class":109},[103,689,690,694,697],{"class":105,"line":278},[103,691,693],{"class":692},"s6cf3","export",[103,695,696],{"class":692}," default",[103,698,699],{"class":109}," {\n",[103,701,702,705,708,711,714,717],{"class":105,"line":285},[103,703,704],{"class":113},"  name",[103,706,707],{"class":109},":",[103,709,710],{"class":109}," '",[103,712,713],{"class":171},"App",[103,715,716],{"class":109},"'",[103,718,719],{"class":109},",\n",[103,721,722,725],{"class":105,"line":292},[103,723,724],{"class":113},"  data",[103,726,727],{"class":109},"(){\n",[103,729,730,733],{"class":105,"line":319},[103,731,732],{"class":692},"    return",[103,734,735],{"class":109},"{\n",[103,737,738,741],{"class":105,"line":325},[103,739,740],{"class":113},"      map",[103,742,743],{"class":109},":undefined,\n",[103,745,746],{"class":105,"line":347},[103,747,748],{"class":109},"    }\n",[103,750,751],{"class":105,"line":357},[103,752,753],{"class":109},"  },\n",[103,755,756,759],{"class":105,"line":367},[103,757,758],{"class":113},"  mounted",[103,760,727],{"class":109},[103,762,763,766,769,772,775,778,781,784,788,791,794,796,799,801,803,805,807,810],{"class":105,"line":377},[103,764,765],{"class":117},"   const",[103,767,768],{"class":281}," map",[103,770,771],{"class":109}," =",[103,773,774],{"class":109}," new",[103,776,777],{"class":109}," this.",[103,779,780],{"class":281},"$gm",[103,782,783],{"class":109},".",[103,785,787],{"class":786},"sdLwU","Map",[103,789,790],{"class":113},"(",[103,792,793],{"class":281},"document",[103,795,783],{"class":109},[103,797,798],{"class":786},"getElementById",[103,800,790],{"class":113},[103,802,716],{"class":109},[103,804,651],{"class":171},[103,806,716],{"class":109},[103,808,809],{"class":113},")",[103,811,812],{"class":109},",{\n",[103,814,815,818,820,823,826,828,832,835,838,840,843,846],{"class":105,"line":397},[103,816,817],{"class":113},"      center",[103,819,707],{"class":109},[103,821,822],{"class":109}," {",[103,824,825],{"class":113}," lat",[103,827,707],{"class":109},[103,829,831],{"class":830},"sx098"," 34.855273888888888",[103,833,834],{"class":109},",",[103,836,837],{"class":113}," lng",[103,839,707],{"class":109},[103,841,842],{"class":830}," 135.30649",[103,844,845],{"class":109}," },",[103,847,848],{"class":288}," \u002F\u002F自由な緯度・経度を入力\n",[103,850,851,854,856,859],{"class":105,"line":407},[103,852,853],{"class":113},"      zoom",[103,855,707],{"class":109},[103,857,858],{"class":830}," 10",[103,860,719],{"class":109},[103,862,863,866,868],{"class":105,"line":433},[103,864,865],{"class":109},"    }",[103,867,809],{"class":113},[103,869,870],{"class":109},";\n",[103,872,873,876,878,880,882],{"class":105,"line":439},[103,874,875],{"class":109},"　　this.",[103,877,651],{"class":281},[103,879,771],{"class":109},[103,881,768],{"class":281},[103,883,870],{"class":109},[103,885,886],{"class":105,"line":448},[103,887,888],{"class":109},"  }\n",[103,890,892],{"class":105,"line":891},22,[103,893,894],{"class":109},"}\n",[103,896,898,900,902],{"class":105,"line":897},23,[103,899,340],{"class":109},[103,901,297],{"class":113},[103,903,121],{"class":109},[10,905,906,911],{},[22,907,910],{"href":908,"rel":909},"https:\u002F\u002Fdevelopers.google.com\u002Fmaps\u002Fdocumentation\u002Fjavascript\u002Freference\u002Fmap?hl=ja",[26],"Mapsクラス","のレファランスの通り、第一引数にマウント対象のDOMを入れ、第二引数にはオプションを入れます。DOMが必要なのでmounted()で初期処理を行います。",[10,913,914],{},"オプションには",[916,917,918,922],"ul",{},[919,920,921],"li",{},"center：初期表示の地図の中央座標",[919,923,924],{},"zoom：拡大の縮尺（10ぐらいがちょうどいい）",[10,926,927,928,931,932,935,936,939],{},"を入れておきましょう。",[68,929,930],{},"lat","は緯度、",[68,933,934],{},"lng","は経度を示しています。このインスタンスは後で使い回すので",[68,937,938],{},"this.map = map"," としてインスタンスを入れておきましょう。ひとまずこの処理を実装してブラウザで見てみましょう。",[61,941,944],{"className":942,"code":943,"language":66},[64],"$ npm run serve\n",[68,945,943],{"__ignoreMap":70},[39,947],{":src":948,":width":949},"'_mix\u002Fsch-2021-03-07-17.39.26-768x352.png'","'100%'",[10,951,952,955],{},[68,953,954],{},"localhost","をみたとき、このようになっていれば問題ありません。ストリートビューや前面表示がない方がいい人はオプションを以下のようにしておきます。",[61,957,959],{"className":473,"code":958,"filename":524,"language":475,"meta":70,"style":70},"new this.$gm.Map(document.getElementById('map'),{\n      center: { lat: 34.855273888888888, lng: 135.30649 },\n      zoom: 10,\n      streetViewControl:false, \u002F\u002F ストリートビュー非表示\n      fullscreenControl:false  \u002F\u002F フルスクリーン非表示\n});\n",[68,960,961,966,971,976,981,986],{"__ignoreMap":70},[103,962,963],{"class":105,"line":106},[103,964,965],{},"new this.$gm.Map(document.getElementById('map'),{\n",[103,967,968],{"class":105,"line":124},[103,969,970],{},"      center: { lat: 34.855273888888888, lng: 135.30649 },\n",[103,972,973],{"class":105,"line":143},[103,974,975],{},"      zoom: 10,\n",[103,977,978],{"class":105,"line":154},[103,979,980],{},"      streetViewControl:false, \u002F\u002F ストリートビュー非表示\n",[103,982,983],{"class":105,"line":179},[103,984,985],{},"      fullscreenControl:false  \u002F\u002F フルスクリーン非表示\n",[103,987,988],{"class":105,"line":212},[103,989,990],{},"});\n",[14,992,993],{"id":993},"地図にクリックイベントを追加",[10,995,996],{},"Google Mapの地図にはクリックやドラッグなどのイベントリスナーを追加できます。特定の位置やマーカーをクリックしたら何やかんやするというのができます。まずは簡単にクリックした地図位置の緯度・経度を取得してみましょう。以下のようにします。",[61,998,1000],{"className":473,"code":999,"filename":524,"language":475,"meta":70,"style":70},"\u003Ctemplate>\n  \u003Cdiv id=\"app\" class=\"mt-4\">\n      \u003Cdiv id=\"map\">\u003C\u002Fdiv>\n      {{position}}\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n\nexport default {\n  name: 'App',\n  data(){\n      return{\n        map:undefined,\n        position:undefined\n      }\n  },\n  methods:{\n   clickOnMap(mapEvent){\n    console.log(mapEvent.latLng.toString())\n    this.position = mapEvent.latLng.toString();\n   }\n  },\n  mounted(){\n   const map = new this.$gm.Map(document.getElementById('map'),{\n      center: { lat: 34.855273888888888, lng: 135.30649 }, \u002F\u002F自由な緯度・経度を入力\n      zoom: 10,\n    });\n\n    \u002F\u002Fリスナーの登録\n    map.addListener('click',(mapsMouseEvent)=>{\n      return this.clickOnMap(mapsMouseEvent);\n    });\n\n　　this.map = map;\n  }\n}\n",[68,1001,1002,1007,1012,1017,1022,1027,1032,1036,1041,1045,1050,1055,1060,1065,1070,1075,1080,1084,1089,1094,1099,1104,1109,1113,1119,1125,1131,1136,1142,1147,1153,1159,1165,1170,1175,1181,1186],{"__ignoreMap":70},[103,1003,1004],{"class":105,"line":106},[103,1005,1006],{},"\u003Ctemplate>\n",[103,1008,1009],{"class":105,"line":124},[103,1010,1011],{},"  \u003Cdiv id=\"app\" class=\"mt-4\">\n",[103,1013,1014],{"class":105,"line":143},[103,1015,1016],{},"      \u003Cdiv id=\"map\">\u003C\u002Fdiv>\n",[103,1018,1019],{"class":105,"line":154},[103,1020,1021],{},"      {{position}}\n",[103,1023,1024],{"class":105,"line":179},[103,1025,1026],{},"  \u003C\u002Fdiv>\n",[103,1028,1029],{"class":105,"line":212},[103,1030,1031],{},"\u003C\u002Ftemplate>\n",[103,1033,1034],{"class":105,"line":244},[103,1035,542],{"emptyLinePlaceholder":541},[103,1037,1038],{"class":105,"line":278},[103,1039,1040],{},"\u003Cscript>\n",[103,1042,1043],{"class":105,"line":285},[103,1044,542],{"emptyLinePlaceholder":541},[103,1046,1047],{"class":105,"line":292},[103,1048,1049],{},"export default {\n",[103,1051,1052],{"class":105,"line":319},[103,1053,1054],{},"  name: 'App',\n",[103,1056,1057],{"class":105,"line":325},[103,1058,1059],{},"  data(){\n",[103,1061,1062],{"class":105,"line":347},[103,1063,1064],{},"      return{\n",[103,1066,1067],{"class":105,"line":357},[103,1068,1069],{},"        map:undefined,\n",[103,1071,1072],{"class":105,"line":367},[103,1073,1074],{},"        position:undefined\n",[103,1076,1077],{"class":105,"line":377},[103,1078,1079],{},"      }\n",[103,1081,1082],{"class":105,"line":397},[103,1083,753],{},[103,1085,1086],{"class":105,"line":407},[103,1087,1088],{},"  methods:{\n",[103,1090,1091],{"class":105,"line":433},[103,1092,1093],{},"   clickOnMap(mapEvent){\n",[103,1095,1096],{"class":105,"line":439},[103,1097,1098],{},"    console.log(mapEvent.latLng.toString())\n",[103,1100,1101],{"class":105,"line":448},[103,1102,1103],{},"    this.position = mapEvent.latLng.toString();\n",[103,1105,1106],{"class":105,"line":891},[103,1107,1108],{},"   }\n",[103,1110,1111],{"class":105,"line":897},[103,1112,753],{},[103,1114,1116],{"class":105,"line":1115},24,[103,1117,1118],{},"  mounted(){\n",[103,1120,1122],{"class":105,"line":1121},25,[103,1123,1124],{},"   const map = new this.$gm.Map(document.getElementById('map'),{\n",[103,1126,1128],{"class":105,"line":1127},26,[103,1129,1130],{},"      center: { lat: 34.855273888888888, lng: 135.30649 }, \u002F\u002F自由な緯度・経度を入力\n",[103,1132,1134],{"class":105,"line":1133},27,[103,1135,975],{},[103,1137,1139],{"class":105,"line":1138},28,[103,1140,1141],{},"    });\n",[103,1143,1145],{"class":105,"line":1144},29,[103,1146,542],{"emptyLinePlaceholder":541},[103,1148,1150],{"class":105,"line":1149},30,[103,1151,1152],{},"    \u002F\u002Fリスナーの登録\n",[103,1154,1156],{"class":105,"line":1155},31,[103,1157,1158],{},"    map.addListener('click',(mapsMouseEvent)=>{\n",[103,1160,1162],{"class":105,"line":1161},32,[103,1163,1164],{},"      return this.clickOnMap(mapsMouseEvent);\n",[103,1166,1168],{"class":105,"line":1167},33,[103,1169,1141],{},[103,1171,1173],{"class":105,"line":1172},34,[103,1174,542],{"emptyLinePlaceholder":541},[103,1176,1178],{"class":105,"line":1177},35,[103,1179,1180],{},"　　this.map = map;\n",[103,1182,1184],{"class":105,"line":1183},36,[103,1185,888],{},[103,1187,1189],{"class":105,"line":1188},37,[103,1190,894],{},[10,1192,1193,1196],{},[68,1194,1195],{},"map.addListener('click',(mapsMouseEvent)=>{...})","とDOMにイベントを追加する時と似ていますね。第二引数に実行するコールバックを入れます。ちなみにコールバックの引数には自動的に地図上の座標なり他の情報が入っています。",[10,1198,1199],{},"このイベントリスナーには以下のメソッドが実行されるようになっており、クリック位置の経度、緯度を取得します。",[61,1201,1203],{"className":473,"code":1202,"filename":524,"language":475,"meta":70,"style":70},"clickOnMap(mapEvent){\n        console.log(mapEvent.latLng.toString())\n        this.position = mapEvent.latLng.toString();\n},\n",[68,1204,1205,1210,1215,1220],{"__ignoreMap":70},[103,1206,1207],{"class":105,"line":106},[103,1208,1209],{},"clickOnMap(mapEvent){\n",[103,1211,1212],{"class":105,"line":124},[103,1213,1214],{},"        console.log(mapEvent.latLng.toString())\n",[103,1216,1217],{"class":105,"line":143},[103,1218,1219],{},"        this.position = mapEvent.latLng.toString();\n",[103,1221,1222],{"class":105,"line":154},[103,1223,1224],{},"},\n",[10,1226,1227],{},"クリックすると以下のようになります。（真ん中の赤いのは気にしないでください。）",[39,1229],{":src":1230,":width":949},"'_mix\u002Fsch-2021-03-07-18.02.03-768x326.png'",[10,1232,1233],{},"左下に座標が表示されました。ひとまずこれで地図に対するイベントリスナーの登録と情報の取得については理解できたと思います。",[14,1235,1236],{"id":1236},"ラインの描画",[10,1238,1239,1240,1243],{},"それでは今度はクリックした際にラインを描画できるようにします。ラインを描画するためには",[68,1241,1242],{},"google.maps.Polyline","クラスのインスタンスを作成し、先ほどのMapインスタンスにセットすることで描画ができます。",[10,1245,1246],{},"上記の通り地図上の情報を取得できたように、今度は緯度経度の情報を元に地図に何かセットします。まずはMapの初期表示と同時にラインを描画しましょう。",[61,1248,1250],{"className":473,"code":1249,"filename":524,"language":475,"meta":70,"style":70},"...  \nmounted(){\n  const map = new this.$gm.Map(document.getElementById('map'),{\n    center: { lat: 34.855273888888888, lng: 135.30649 },\n    zoom: 10,\n  });\n  map.addListener('click',(mapsMouseEvent)=>{\n    return this.clickOnMap(mapsMouseEvent);\n  });\n  const LINE = new this.$gm.Polyline({\n      path:[\n        { lat: 34.855273888888888, lng: 135.30649 },\n        { lat: 34.854465, lng: 135.8 },\n      ],\n      geodesic: true,\n      strokeColor: \"#FF0000\",\n      strokeOpacity: 1.0,\n      strokeWeight: 2,\n  })\n  LINE.setMap(map);\n  this.map = map;\n} \n...\n",[68,1251,1252,1257,1262,1267,1272,1277,1282,1287,1292,1296,1301,1306,1311,1316,1321,1326,1331,1336,1341,1346,1351,1356,1361],{"__ignoreMap":70},[103,1253,1254],{"class":105,"line":106},[103,1255,1256],{},"...  \n",[103,1258,1259],{"class":105,"line":124},[103,1260,1261],{},"mounted(){\n",[103,1263,1264],{"class":105,"line":143},[103,1265,1266],{},"  const map = new this.$gm.Map(document.getElementById('map'),{\n",[103,1268,1269],{"class":105,"line":154},[103,1270,1271],{},"    center: { lat: 34.855273888888888, lng: 135.30649 },\n",[103,1273,1274],{"class":105,"line":179},[103,1275,1276],{},"    zoom: 10,\n",[103,1278,1279],{"class":105,"line":212},[103,1280,1281],{},"  });\n",[103,1283,1284],{"class":105,"line":244},[103,1285,1286],{},"  map.addListener('click',(mapsMouseEvent)=>{\n",[103,1288,1289],{"class":105,"line":278},[103,1290,1291],{},"    return this.clickOnMap(mapsMouseEvent);\n",[103,1293,1294],{"class":105,"line":285},[103,1295,1281],{},[103,1297,1298],{"class":105,"line":292},[103,1299,1300],{},"  const LINE = new this.$gm.Polyline({\n",[103,1302,1303],{"class":105,"line":319},[103,1304,1305],{},"      path:[\n",[103,1307,1308],{"class":105,"line":325},[103,1309,1310],{},"        { lat: 34.855273888888888, lng: 135.30649 },\n",[103,1312,1313],{"class":105,"line":347},[103,1314,1315],{},"        { lat: 34.854465, lng: 135.8 },\n",[103,1317,1318],{"class":105,"line":357},[103,1319,1320],{},"      ],\n",[103,1322,1323],{"class":105,"line":367},[103,1324,1325],{},"      geodesic: true,\n",[103,1327,1328],{"class":105,"line":377},[103,1329,1330],{},"      strokeColor: \"#FF0000\",\n",[103,1332,1333],{"class":105,"line":397},[103,1334,1335],{},"      strokeOpacity: 1.0,\n",[103,1337,1338],{"class":105,"line":407},[103,1339,1340],{},"      strokeWeight: 2,\n",[103,1342,1343],{"class":105,"line":433},[103,1344,1345],{},"  })\n",[103,1347,1348],{"class":105,"line":439},[103,1349,1350],{},"  LINE.setMap(map);\n",[103,1352,1353],{"class":105,"line":448},[103,1354,1355],{},"  this.map = map;\n",[103,1357,1358],{"class":105,"line":891},[103,1359,1360],{},"} \n",[103,1362,1363],{"class":105,"line":897},[103,1364,1365],{},"...\n",[10,1367,1368,1371,1372,1375],{},[68,1369,1370],{},"this.$gm.Polyline","でラインインスタンスを作成し、オプションをオブジェクト形式で指定すればラインの色、パス（２点以上の座標）、太さなどを指定できます。最後に",[68,1373,1374],{},"LINE.setMap(map)","で地図にはめると、以下のように描画されます。",[39,1377],{":src":1378,":width":949},"'_mix\u002Fsch-2021-03-10-21.17.39-768x346.png'",[10,1380,1381],{},"地図に赤線が表示されました。今は２点の適当な座標間ですが細かくパスを設定すれば以下のようにも描画できます。",[39,1383],{":src":1384,":width":1385,":center":43},"'_mix\u002Fsch-2021-03-10-21.19.41.png'","'300px'",[10,1387,1388],{},"この座標情報は友人のGPSから引っ張ってきたもので、詳細な座標情報が配列であったのでこれほど細かく描画されます。",[14,1390,1392],{"id":1391},"クリックした任意の地点でラインを描画していく","クリックした任意の地点でラインを描画していく。",[10,1394,1395],{},"初期表示でラインを描画することができたので、次はユーザーが任意の地点をクリックしたらその地点に向かってラインが描画されるようにしましょう。",[10,1397,1398],{},"先ほどクリックイベントから座標情報をしたのを覚えていますか？それを応用します。",[1400,1401,1402,1405,1408,1411],"ol",{},[919,1403,1404],{},"クリック位置から緯度・経度を取得",[919,1406,1407],{},"Google Map用の座標インスタンスに変換",[919,1409,1410],{},"ラインインスタンスにその座標（パス）を追加する。",[919,1412,1413],{},"クリックされたら繰り返す。",[10,1415,1416,1417,1420],{},"クリックイベントに付与した",[68,1418,1419],{},"drawLine","メソッドこんな感じです。",[61,1422,1424],{"className":473,"code":1423,"filename":524,"language":475,"meta":70,"style":70},"data(){\n  return{\n    map:undefined,\n    bounds:undefined,\n    path:[],\n    line:undefined\n  }\n},\nmethods:{\n  drawLine(mapEvent){\n    let latLng = mapEvent.latLng;\n\n    \u002F\u002F １点目をクリック\n    if(this.line === undefined){\n      const newLine = new this.$gm.Polyline({\n        path:[latLng],\n        geodesic: true,\n        strokeColor: \"#FF0000\",\n        strokeOpacity: 1.0,\n        strokeWeight: 2,\n      })\n      newLine.setMap(this.map);\n      this.path.push(latLng);\n      this.line = newLine;\n      return;\n    }\n\n    \u002F\u002F ２点目以降\n    this.path.push(latLng);\n    this.line.setPath([...this.path]);\n    return;\n  },\n},\n",[68,1425,1426,1431,1436,1441,1446,1451,1456,1460,1464,1469,1474,1479,1483,1488,1493,1498,1503,1508,1513,1518,1523,1528,1533,1538,1543,1548,1552,1556,1561,1566,1571,1576,1580],{"__ignoreMap":70},[103,1427,1428],{"class":105,"line":106},[103,1429,1430],{},"data(){\n",[103,1432,1433],{"class":105,"line":124},[103,1434,1435],{},"  return{\n",[103,1437,1438],{"class":105,"line":143},[103,1439,1440],{},"    map:undefined,\n",[103,1442,1443],{"class":105,"line":154},[103,1444,1445],{},"    bounds:undefined,\n",[103,1447,1448],{"class":105,"line":179},[103,1449,1450],{},"    path:[],\n",[103,1452,1453],{"class":105,"line":212},[103,1454,1455],{},"    line:undefined\n",[103,1457,1458],{"class":105,"line":244},[103,1459,888],{},[103,1461,1462],{"class":105,"line":278},[103,1463,1224],{},[103,1465,1466],{"class":105,"line":285},[103,1467,1468],{},"methods:{\n",[103,1470,1471],{"class":105,"line":292},[103,1472,1473],{},"  drawLine(mapEvent){\n",[103,1475,1476],{"class":105,"line":319},[103,1477,1478],{},"    let latLng = mapEvent.latLng;\n",[103,1480,1481],{"class":105,"line":325},[103,1482,542],{"emptyLinePlaceholder":541},[103,1484,1485],{"class":105,"line":347},[103,1486,1487],{},"    \u002F\u002F １点目をクリック\n",[103,1489,1490],{"class":105,"line":357},[103,1491,1492],{},"    if(this.line === undefined){\n",[103,1494,1495],{"class":105,"line":367},[103,1496,1497],{},"      const newLine = new this.$gm.Polyline({\n",[103,1499,1500],{"class":105,"line":377},[103,1501,1502],{},"        path:[latLng],\n",[103,1504,1505],{"class":105,"line":397},[103,1506,1507],{},"        geodesic: true,\n",[103,1509,1510],{"class":105,"line":407},[103,1511,1512],{},"        strokeColor: \"#FF0000\",\n",[103,1514,1515],{"class":105,"line":433},[103,1516,1517],{},"        strokeOpacity: 1.0,\n",[103,1519,1520],{"class":105,"line":439},[103,1521,1522],{},"        strokeWeight: 2,\n",[103,1524,1525],{"class":105,"line":448},[103,1526,1527],{},"      })\n",[103,1529,1530],{"class":105,"line":891},[103,1531,1532],{},"      newLine.setMap(this.map);\n",[103,1534,1535],{"class":105,"line":897},[103,1536,1537],{},"      this.path.push(latLng);\n",[103,1539,1540],{"class":105,"line":1115},[103,1541,1542],{},"      this.line = newLine;\n",[103,1544,1545],{"class":105,"line":1121},[103,1546,1547],{},"      return;\n",[103,1549,1550],{"class":105,"line":1127},[103,1551,748],{},[103,1553,1554],{"class":105,"line":1133},[103,1555,542],{"emptyLinePlaceholder":541},[103,1557,1558],{"class":105,"line":1138},[103,1559,1560],{},"    \u002F\u002F ２点目以降\n",[103,1562,1563],{"class":105,"line":1144},[103,1564,1565],{},"    this.path.push(latLng);\n",[103,1567,1568],{"class":105,"line":1149},[103,1569,1570],{},"    this.line.setPath([...this.path]);\n",[103,1572,1573],{"class":105,"line":1155},[103,1574,1575],{},"    return;\n",[103,1577,1578],{"class":105,"line":1161},[103,1579,753],{},[103,1581,1582],{"class":105,"line":1167},[103,1583,1224],{},[10,1585,1586,1587,1590,1591,1594,1595,1598,1599,1602],{},"１点目の時はインスタンスを作成し",[68,1588,1589],{},"data()","に格納します。そしてクリックごとに",[68,1592,1593],{},"path","に挿入していき、",[68,1596,1597],{},"this.line.setPath([...this.path])","で更新したパスの配列を展開、インスタンスのパスも更新します。するとクリックするたびにその地点に向かって線画描画されます。静止画ですが",[383,1600,1601],{},"VUE","という文字を一筆でかいてみました笑",[39,1604],{":src":1605,":width":949},"'_mix\u002Fscp-2021-03-10-21.42.12-768x408.png'",[10,1607,1608],{},"末尾のパスを消して再セットすればやり直し機能ができますし、特定のパスの座標を変更すれば途中の変更もできます。今回は面倒なのでやりませんでした。パスのインスタンスを複数管理できれば、複数ライン・レイヤーなど高度なライン描画を実現できます。詳細な実装をしたらまた記事を書いてみます。",[14,1610,1612],{"id":1611},"vueじゃなくてもよくね","Vueじゃなくてもよくね？",[10,1614,1615],{},"はい。その通りです。ほとんどがGoogle map javascript apiから提供されたオブジェクトをいじっているだけです。なのでVanilla.jsな環境でも普通に描画機能は実装できます。今回はvue.jsを利用して自主開発していたのでvue.jsを使っただけです。",[14,1617,1618],{"id":1618},"いろいろ試してみる",[10,1620,1621],{},"Google Map APIには他にもマーカ・カスタムデザインマーカを入れたり、DOM要素を地図に入れ込むなんてこともできるそうです。これらの描画情報をJSONに格納して、DBに入れておけば地図共有アプリなんかもできそうですね。いろいろやってみます。閲覧ありがとうございました。",[1623,1624,1625],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}",{"title":70,"searchDepth":143,"depth":143,"links":1627},[1628,1629,1633,1634,1635,1636,1637,1638],{"id":16,"depth":124,"text":17},{"id":49,"depth":124,"text":50,"children":1630},[1631,1632],{"id":74,"depth":143,"text":75},{"id":466,"depth":143,"text":467},{"id":582,"depth":124,"text":582},{"id":993,"depth":124,"text":993},{"id":1236,"depth":124,"text":1236},{"id":1391,"depth":124,"text":1392},{"id":1611,"depth":124,"text":1612},{"id":1618,"depth":124,"text":1618},[1640],"devstack","2021-03-10","md",null,{},"\u002Farticles\u002Fgoogle-map-vuejs",{"title":5,"description":5},"articles\u002Fgoogle-map-vuejs",[1649,595],"js","_mix\u002Fscp-2021-03-10-21.42.12-768x408.png","oZOhHuAchOiO9qVocS-_1TA4WK0zOIDu_l3spKlDDsE",1780987144420]