はじめに
Delphi にはモバイルプラットフォーム向けに TMapView
というコンポーネントがあるのですが 1、デスクトッププラットフォームあるいは VCL 用には用意されていません。
VCL アプリケーションでも Google Map を表示したい事があるのでどうにかしてみようと思いました。
Maps JavaScript API
Maps JavaScript API の仕様はこちらで確認できます。
API キーの取得方法についてはミガロさんの技術 Tips が詳しいです。
- Google Maps Platform API キー取得手順と使用回数制限設定 (Migaro. 技術Tips)
- Google Maps Platform コアサービスの料金リスト (Google Maps Platform)
ソースコード
Maps JavaScript API を使った HTML を生成するためのサポートユニットです。
{ ---------------------------------------------------------------------------- }
{ Google Maps JavaScript API Support unit }
{ ---------------------------------------------------------------------------- }
unit uGoogleMapJS;
interface
uses
System.SysUtils;
type
TGMJSRec = record
API_KEY: string;
Script: string;
procedure Init;
function GenerateJS: string;
end;
implementation
const
HTML_TEMPLATE = '''
<!doctype html>
<html>
<head>
<style>
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https:\/\/maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })
({ key: "@APIKEY@", v: "weekly" });
</script>
<script>
@SCRIPT@
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>
''';
{ TGMJSRec }
procedure TGMJSRec.Init;
begin
Self := Default(TGMJSRec);
end;
function TGMJSRec.GenerateJS: string;
begin
var s := HTML_TEMPLATE;
s := StringReplace(s, '@APIKEY@' , API_KEY , [rfIgnoreCase]);
s := StringReplace(s, '@SCRIPT@' , Script , [rfIgnoreCase]);
result := s;
end;
end.
複数行文字列を使っているので、Delphi 12 Athens 以降でコンパイル可能ですが、より古い Delphi に対応させるのはそんなに難しくないと思います。
使い方
高度なレコード型である TGMJSRec
を初期化し、フィールドに値を格納して GenerateJS()
を呼ぶだけです。
例えば TEdgeBrowser
2 に表示するには、次のようなコードになります。
uses
..., uGoogleMapJS;
procedure TForm1.FormCreate(Sender: TObject);
begin
EdgeBrowser1.CreateWebView;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
var GMJSRec: TGMJSRec;
with GMJSRec do
begin
Init;
API_KEY := '(あなたの取得したAPI キー)';
Script := '''
let map;
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
map = new Map(document.getElementById("map"), {
center: { lat: 0, lng: 0 },
zoom: 15
});
const geocoder = new google.maps.Geocoder();
const buildingName = "東京スカイツリー";
geocoder.geocode({ address: buildingName }, (results, status) => {
if (status === "OK") {
map.setCenter(results[0].geometry.location);
new google.maps.Marker({
map: map,
position: results[0].geometry.location,
title: buildingName,
});
}
});
}
initMap();
''';
end;
EdgeBrowser1.NavigateToString(GMJSRec.GenerateJS);
end;
「JavaScript を生成する」と言いながら、スクリプト部分の生成をサポートする機能は一切ありません。JavaScript を実行するためのガワを作ってくれるだけです。
実行するとこんな感じになります。
uGoogleMapJS.pas
は HTML を生成しているだけなので、従来の TWebBrowser
等に表示するのも難しくないと思います。
See also:
- TEdgeBrowser (DocWiki)
- TEdgeBrowser コンポーネントの利用と TWebBrowser コンポーネントへの変更点 (DocWiki)
- TEdgeBrowserを使用してスクリプトを実行する方法 (blogs.embarcadero.com)
おわりに
簡単なテストしかしていないのでバグがあるかもしれません。
不具合を見つけたらコメント欄で教えてください m(_ _)m
Maps Embed API 版と Maps Static API 版はこちらです:
- 【Delphi】Google Map を表示するための HTML を生成する【Maps Embed API】(Qiita)
- 【Delphi】Google Map を表示するための URL を生成する【Maps Static API】(Qiita)
See also: