はじめに
Delphi にはモバイルプラットフォーム向けに TMapView
というコンポーネントがあるのですが 1、デスクトッププラットフォームあるいは VCL 用には用意されていません。
VCL アプリケーションでも Google Map を表示したい事があるのでどうにかしてみようと思いました。
Maps Embed API
Maps Embed API の仕様はこちらで確認できます。
API キーの取得方法についてはミガロさんの技術 Tips が詳しいです。
- Google Maps Platform API キー取得手順と使用回数制限設定 (Migaro. 技術Tips)
- Google Maps Platform コアサービスの料金リスト (Google Maps Platform)
ソースコード
Maps Embed API を使った HTML を生成するためのサポートユニットです。
{ ---------------------------------------------------------------------------- }
{ Google Maps Embed API Support unit }
{ ---------------------------------------------------------------------------- }
unit uGoogleMapEmbed;
interface
uses
System.SysUtils, System.Math, System.NetEncoding;
const
DEFAULT_LANG = 'ja';
DEFAULT_WIDTH = 640;
DEFAULT_HEIGHT = 480;
type
TMapMode = (mmPlace, mmView, mmDirections, mmStreetView, mmSearch);
TMapType = (mtRoadmap, mtSatellite);
TDirectionMode = (dmNone, dmDriving, dmWalking, dmBicycling, dmTransit, dmFlying);
TDirectionAvoid = (daTolls, daFerries, daHighways);
TDirectionUnits = (duNone, duMetric, duImperial);
TGMERec = record
API_KEY: string;
MapMode: TMapMode;
Q: string;
Origin: string;
Destination: string;
Waypoints: string;
Mode: TDirectionMode;
Avoid: set of TDirectionAvoid;
Units: TDirectionUnits;
Heading: Integer;
Pitch: Integer;
Fov: Integer;
Zoom: Byte;
Maptype: TMapType;
Language: string;
Region: string;
Center_latitude: Single;
Center_longitude: Single;
Width: Integer;
Height: Integer;
procedure Init;
function GenerateHtml: string;
end;
implementation
const
INVALID_VALUE = $BEEF;
HTML_TEMPLATE = '''
<html>
<body>
<iframe
width="@WIDTH@"
height="@HEIGHT@"
style="border:0"
loading="lazy"
allowfullscreen
referrerpolicy="no-referrer-when-downgrade"
src="https://www.google.com/maps/embed/v1/@MAPMODE@?key=@APIKEY@@PARAMS@">
</iframe>
</body>
</html>
''';
strMapMode: array [TMapMode] of string =
('place', 'view', 'directions', 'streetview', 'search');
strMapType: array [TMapType] of string =
('roadmap', 'satellite');
strDirectionMode: array [TDirectionMode] of string =
('', 'driving', 'walking', 'bicycling', 'transit', 'flying');
strDirectionAvoid: array [TDirectionAvoid] of string =
('tolls', 'ferries', 'highways');
strDirectionUnits: array [TDirectionUnits] of string =
('', 'metric', 'imperial');
{ TGMERec }
procedure TGMERec.Init;
begin
Self := Default(TGMERec);
with Self do
begin
Center_Latitude := NaN;
Center_Longitude := NaN;
Zoom := 15;
MapType := mtRoadmap;
Language := DEFAULT_LANG;
Width := DEFAULT_WIDTH;
Height := DEFAULT_HEIGHT;
Heading := INVALID_VALUE;
Pitch := INVALID_VALUE;
Fov := INVALID_VALUE;
end;
end;
function TGMERec.GenerateHtml: string;
begin
var Params: string := '';
case MapMode of
mmPlace, mmSearch:
begin
// q (Required)
Params := Params + Format('&q=%s', [TNetEncoding.URL.EncodeQuery(Q)]);
end;
mmView:
begin
end;
mmDirections:
begin
// origin (Required)
Params := Params + Format('&origin=%s', [TNetEncoding.URL.EncodeQuery(origin)]);
// destination (Required)
Params := Params + Format('&destination=%s', [TNetEncoding.URL.EncodeQuery(destination)]);
// waypoints
if Waypoints <> '' then
Params := Params + Format('&waypoints=%s', [Waypoints]);
// mode
if Mode <> dmNone then
Params := Params + Format('&mode=%s', [strDirectionMode[Mode]]);
// avoid
var sAvoid := '';
for var a in Avoid do
begin
if sAvoid <> '' then
sAvoid := sAvoid + '|';
sAvoid := sAvoid + strDirectionAvoid[a];
end;
if sAvoid <> '' then
Params := Params + Format('&avoid=%s', [sAvoid]);
// units
if Units <> duNone then
Params := Params + Format('&units=%s', [strDirectionUnits[Units]]);
end;
mmStreetView:
begin
// heading
if Heading <> INVALID_VALUE then
Params := Params + Format('&heading=%d', [Heading]);
// pitch
if Pitch <> INVALID_VALUE then
Params := Params + Format('&pitch=%d', [Pitch]);
// fov
if Fov <> INVALID_VALUE then
Params := Params + Format('&fov=%d', [Fov]);
end;
end;
// center
if (not IsNan(Center_Latitude)) and (not IsNan(Center_Longitude)) then
Params := Params + Format('¢er=%f,%f', [Center_Latitude, Center_Longitude]);
// zoom
if zoom in [0..21] then
Params := Params + Format('&zoom=%d', [Zoom]);
// maptype
if maptype <> mtRoadmap then
Params := Params + Format('&maptype=%s', [strMapType[MapType]]);
// language
if language <> '' then
Params := Params + Format('&language=%s', [Language]);
// region
if region <> '' then
Params := Params + Format('®ion=%s', [Region]);
var s := HTML_TEMPLATE;
s := StringReplace(s, '@WIDTH@' , Width.ToString , [rfIgnoreCase]);
s := StringReplace(s, '@HEIGHT@', Height.ToString, [rfIgnoreCase]);
s := StringReplace(s, '@MAPMODE@' , strMapMode[MapMode] , [rfIgnoreCase]);
s := StringReplace(s, '@APIKEY@' , API_KEY , [rfIgnoreCase]);
if Params <> '' then
s := StringReplace(s, '@PARAMS@' , Params , [rfIgnoreCase]);
result := s;
end;
end.
複数行文字列を使っているので、Delphi 12 Athens 以降でコンパイル可能ですが、より古い Delphi に対応させるのはそんなに難しくないと思います。
使い方
高度なレコード型である TGMERec
を初期化し、フィールドに値を格納して GenerateHtml()
を呼ぶだけです。
例えば TEdgeBrowser
2 に表示するには、次のようなコードになります。
uses
..., uGoogleMapEmbed;
procedure TForm1.FormCreate(Sender: TObject);
begin
EdgeBrowser1.CreateWebView;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
var GMERec: TGMERec;
with GMERec do
begin
Init;
API_KEY := '(あなたの取得したAPI キー)';
MapMode := mmPlace;
Q := '東京スカイツリー';
Width := EdgeBrowser1.Width - 16;
Height := EdgeBrowser1.Height - 16;
end;
EdgeBrowser1.NavigateToString(GMERec.GenerateHtml);
end;
実行するとこんな感じになります。
uGoogleMapEmbed.pas
は HTML を生成しているだけなので、従来の TWebBrowser
等に表示するのも難しくないと思います。
See also:
- TEdgeBrowser (DocWiki)
- TEdgeBrowser コンポーネントの利用と TWebBrowser コンポーネントへの変更点 (DocWiki)
- TEdgeBrowserを使用してスクリプトを実行する方法 (blogs.embarcadero.com)
おわりに
簡単なテストしかしていないのでバグがあるかもしれません。
不具合を見つけたらコメント欄で教えてください m(_ _)m
Maps Static API 版と Maps JavaScript API 版はこちらです:
- 【Delphi】Google Map を表示するための URL を生成する【Maps Static API】(Qiita)
- 【Delphi】Google Map を表示するための JavaScript を生成する【Maps JavaScript API】(Qiita)
See also: