Composant Delphi / Google Maps / OpenStreetMap / Leaflet  / Mappilary / Native Maps 100% Delphi 0% WebBrowser 0% Javascript


you are here :TECMap > Overlays

TECNativeLayer is the base class of the layers that allow you to react to the displayed area, and mouse actions.

TECNativeLayer = class
FObserver : TNativeMapObserver;
FShapes : TECShapes;
FMap : TNativeMapControl;

FOnShapeClick : TOnShapeMouseEvent;

FOnMouseMove : TNotifyEvent;

function getMinZoom : byte;
function getMaxZoom : byte;

procedure setMinZoom(value:byte);
procedure setMaxZoom(value:byte);

function getVisible : boolean;


procedure doOnMapEndMove(sender : TObject); virtual;
procedure doOnShapeClick(sender : TObject); virtual;
procedure doOnShapeRightClick(sender : TObject); virtual;
procedure doOnMapMouseMove(sender : TObject); virtual;
procedure doOnMapMouseClick(sender : TObject); virtual;
procedure doOnMapHiResChange(sender : TObject); virtual;


procedure setVisible(const value:boolean); virtual;

constructor Create(_FMap:TnativeMapControl;const Name:string); virtual;
destructor Destroy; override;

property OnShapeClick : TOnShapeMouseEvent read FOnShapeClick write FOnShapeClick;
property OnShapeRightClick : TOnShapeMouseEvent read FOnShaperightClick write FOnShapeRightClick;

property OnMouseMove : TNotifyEvent read FOnMouseMove write FOnMouseMove;
property OnMouseClick : TNotifyEvent read FOnMouseClick write FOnMouseClick;

property Map : TNativeMapControl read FMap;
property Shapes : TECShapes read FShapes;
property Visible : boolean read getVisible write setVisible;

property MaxZoom : byte read getMaxZoom write setMaxZoom;
property MinZoom : byte read getMinZoom write setMinZoom;


You can either plug into OnMapHiResChange or overload the doOnMapHiResChange(sender: TObject) procedure so that your layer adapts to change resolution



Google closed Panoramio November 4, 2016, the service is no longer functional


A Panoramio layer is integrated into TECNativeMap through the property PanoramioLayer

// show panoramio layer
map.PanoramioLayer := true;

The event OnPanoramioClick(sender: TObject; const Item: TECShape; const ownerId, ownerName, PhotoId, PhotoDate, PhotoTitle, PhotoUrl, copyright: string) is raised when clicking a Panoramio item.

Fig. 125 Click sur un élément Panoramio


Allows you to automatically display the result of a search

To use this layer you must embed unit uecNativePlaceLayer or FMX.uecNativePlaceLayer depending on whether you use the VCL version or FireMonkey


Example: a layer that displays restaurants

// search Layer

FPlacesLayer := TECNativePlaceLayer.create(map,'PLACES_LAYER');
FPlacesLayer.OnPLaceClick := doOnPlaceClick;

FPlacesLayer.Visible := true;
FPlacesLayer.Search := 'node[amenity=restaurant]';
// standard image 32x32
FPlacesLayer.MarkerFilename := '';
// lat,lng on center of image
FPlacesLayer.XAnchor := 16;
FPlacesLayer.YAnchor := 16;
// hi-res image 64*64
FPlacesLayer.MarkerHiResFilename := '';
// lat,lng on center of image
FPlacesLayer.HiResXAnchor := 32;
FPlacesLayer.HiResYAnchor := 32;

// event click on place shape
procedure TForm1.doOnPlaceClick(sender : TECShape);
pResult : TECPlaceResult;
Content : string;
i : integer;

// here Sender and Sender.Item are allway assigned, and Sender.Item is TECPlaceResult

pResult :=TECPlaceResult(Sender.item)

for i:=0 to pResult.CountResult-1 do

n := pResult.NameResult[i];
r := pResult.Result[n];
if length(n)< 9 then
n := n+'<tab="65">';

content := content+'<b>'+n+'</b>: '+r+'<br>';


if FPlacesLayer.Shapes.InfoWindows.Count=0 then
FPlacesLayer.Shapes.InfoWindows[0].zindex := 100;

FPlacesLayer.Shapes.InfoWindows[0].content := Content;
FPlacesLayer.Shapes.InfoWindows[0].Visible := true;



Fig. 126 Click on an element TECNativePlaceLayer

By default the elements of layer are TECShapeMarker but you can change the type of TECShape by redefining TECNativePlaceLayer.doCreateShape(SearchResult : TECPlaceResult):TECShape;


XapiLayer uses TECNativePlaceLayer and is directly integrated with TECNativeMap.

The search is performed in the area displayed by your map, it is updated on each move

property Shapes:TECShapes

The group that contains the items, it's name is 'XAPI'

property Search : string

Research is done by doing a query on a server XAPI

You can find all the tags OSM using a syntax like 'node[key=value]'

// search bus stop
map.XapiLayer.Search := 'node[highway=bus_stop]';

For nodes you can use simplified syntax.

// search bus stop
map.XapiLayer.Search := 'highway=bus_stop';

For the key amenity you can simplify even more.

// search all restaurant, bar and café
map.XapiLayer.Search := 'restaurant|bar|cafe';

property Visible : boolean

show / hide layer

property MaxItem : integer

Maximum number of items

property OnClick : TOnShape

This event is raised when an item is clicked

property OnChange : TNotifyEvent

Raised after each request
map.XapiLayer.OnClick := doOnXapiClick;
map.XapiLayer.OnChange := doOnXapiChange;
procedure TForm1.doOnXapiChange(sender : TObject);

// event click on xapi shape
procedure TForm1.doOnXapiClick(sender : TECshape);

Use the styles to decorate your items

Selector := '#'+map.XapiLayer.Shapes.Name+ '.marker.amenity';

map.styles.addRule(Selector+':restaurant' +
+ 'JYQIDOMg0NDYawBIFC2FgCSCxBerFMg0Es02AAP34wMx8/aIAAAAAASUVORK5CYII=;visible:true;');

map.styles.addRule(Selector+':bar' +
+ 'iFmCxWaDLMaEAsoqDQBNGsGlDeHyexnbJPAHwpKuIe9zSwDFzFPR6egM4P9HMgX3YQgDSr67gQrsq51'
+ 'z8ZqqqSwHrOkhsZqguAo0iyS5weL1kD5qZUcjPNfXV1HPIThmaY9vr4QH8KknbPXbfMgtiqvSMA+1Zy'
+ 'lrNy9/SK8g0PVamc2NlTK98F1MyKB+QkmGEAAAAASUVORK5CYII=;visible:true;}');

map.styles.addRule(Selector+':cafe' +
+ 'JUBsgE2eEotQDIHyHXDJU2JRPyn8wQmgcfCfTPye1HghGw8/i4D4PBrbgVYWYcMGtLAoAakUmQ8VW0/'
+ 'RGS2+aW0SzGhYAB5lDXBZ7NtoAAAAASUVORK5CYII=;visible:true;}');

map.styles.addRule('#'+map.XapiLayer.Shapes.Name+ '.marker.highway:bus_stop {color:blue;styleicon:Flat;visible:true;}');
map.styles.addRule('#'+map.XapiLayer.Shapes.Name+ '.marker {scale:1;}');
map.styles.addRule('#'+map.XapiLayer.Shapes.Name+ '.marker:hover {scale:1.5;}');

Fig. 127 'restaurant|bar|cafe'

Fig. 128 'highway=bus_stop'


With way[key = value] you can retrieve paths.

// find roads
map.XapiLayer.Search := 'way[highway=motorway|primary|secondary|tertiary|residential]';
// styles routes
map.styles.addRule('#' + map.XapiLayer.Shapes.Name +
'.line.highway:primary {zindex:9;weight:4;color:gradient(Red,Yellow,0.3);visible:true;}');
map.styles.addRule('#' + map.XapiLayer.Shapes.Name +
'.line.highway:secondary {zindex:8;weight:3;color:gradient(Red,Yellow,0.4);visible:true;}');

Fig. 129 Xapi Way

You can also find the junctions between routes.

map.XapiLayer.Junction := true;
map.XapiLayer.Search := 'way[highway=unclassified|road|motorway|trunk|primary|secondary|tertiary|residential]';

Fig. 130 Xapi Roads & Junction

Manual search

When layer is visible the search is synchronized with the visible area of your map.

To perform a search on any area you need to hide layer and use Bound to delimit the search box.

// sample, copie data in another group

map.XapiLayer.OnChange := XapiChange;
map.XapiLayer.visible := false; := 'highway=bus_stop';
// ! call bound after set search !
TForm.XapiChange(sender : TObject);
// here xapilayer contain openstreetmap data
// copie in another group[copy_xapi'].ToTxt := map.XapiLayer.shapes.ToTxt;


This layer gives you support for the format UTFGrid

Example: Delphi translation of Visible Map

// support UTFGrid Layer see

FUTFLayer := TECNativeUTFLayer.create(map,'mapbox.geography',GetUTFTile);

FUTFLayer.OnMouseOver := doOnOverUTFData;
FUTFLayer.OnMouseOut := doOnOutUTFData;

FUTFLayer.Shapes.InfoWindows[0].zindex := 100;
FUTFLayer.Shapes.InfoWindows[0].color := claBeige;
FUTFLayer.Shapes.InfoWindows[0].Width := 110;
FUTFLayer.Shapes.InfoWindows[0].ContentCenter := true;

FUTFLayer.Visible := true;


// connexion utf geography tiles

// for see data tile

procedure TForm1.GetUTFTile(var TileFilename:string;const x,y,z:integer);
TileFilename := format('',
[Char(Ord('a') + random(3)),z,x,y]);

// OnOver country

// FUTFLayer.Data['admin'] country name
// FUTFLayer.Data['flag_png'] country flag png base64 encoded

procedure TForm1.doOnOverUTFData(sender : TObject);

FUTFLayer.Shapes.InfoWindows[0].Content :='<img src="data:image/png;base64,'[ 'flag_png']+'" width="80" height="40">'+

FUTFLayer.Shapes.InfoWindows[0].Visible := true;


procedure TForm1.doOnOutUTFData(sender : TObject);
FUTFLayer.Shapes.InfoWindows[0].Visible := false;

Fig. 131 UTFGrid geography-class


This layer displays an infoWindow above the TECShape, It is updated and moved automatically depending on the Hint and the position of the TECShape

Fig. 132 Using labels to display positions

To use this layer you must embed the unit uecNativeLabelLayer or FMX.uecNativeLabelLayer Depending on whether you use the version VCL or FireMonkey


LLayer : TECNativeLabelLayer;

LLayer := TECNativeLabelLayer.Create(Map,'my layer');

LLayer.visible := true;

// add shapes to layer

See sources of demos Firemonkey and DemoNativeRoute for an example of using


Mappilary is a service of the same type as Google Street Map, it will display photos at street level, the advantage is that you can enrich it by registering your routes.

TECNativeMap just use the information in public access, you must obtain a key to use the service of Mappilary.

To do this go to the website, log in, in the Integrations section add your applications, you will then get a Client ID, this is your key.

To use mappilary you must incorporate the unit uecMappilary or FMX.uecMappilary depending on whether you use the VCL or FireMonkey version


Use TECMappilaryLayer to embed a layer Mappilary.

FMappilaryLayer := TECMappilaryLayer.Create(map);
FMappilaryLayer.ClientId := 'HERE-YOUR-CLIENT-ID';

FMappilaryLayer.Visible := true;

Fig. 133 Demo Mappilary


procedure CancelSearchSequence;
Cancels a search for sequences.
procedure CancelSearchImageClose;
Cancels a search for images
procedure SearchImageClose(const Lat, Lng: double; Distance: integer);

Initiates a search of images at a maximum Distance, in metres, of the point Lat,Lng

You can connect to the OnImages event to be notified of a response.

The Images property contains the list of images.

function FindImageClose(const Lat, Lng: double; Distance: integer; var seq : TMappilarySequence; var PhotoIndex : integer ) : integer;

Find the nearest photo amongst those displayed in the layer, the research is local.

Lat, Lng indicates the starting point of the research

Distance indicates the maximum distance in metres from the search point

Seq will contain the found sequence or nil

PhotoIndex will contain the index of the photo in seq or - 1

Returns the distance in metres between the point of research and the photo, 0 if no photo

function LoadImage(const Key: string): TBitmap; overload;

Gets a bitmap that contains the image we had the key.

Caution you must not release the resulting bitmap, to keep it you must make a copy !

function LoadImage(const Key: string; Bitmap:TBitmap):boolean;

Load a bitmap with the image .

Please note you are responsible for the creation and release of the bitmap !

var bmp:TBitmap;
bmp := TBitmap.create;
if LoadImage(key,bmp) then
// image ok
procedure LoadImage(const Key: string; OnBitmap: TOnGetMappyImage); overload;

Gets a bitmap containing the image associated with the key, This function is not blocking, OnBitmap est appelé lorsque l'image est chargée.

layer.onImages := doOnImage;
procedure TForm2.doOnImage(sender:TMappilaryImageList);
// you can test sender.More to see if there are other images waiting
function LoadImage(img:TMappilaryImage):boolean; overload;

Gets the information of an image

// get data image
img := TMappilaryImage.create;
// ! mandatory set key !
img.Key := PhotoKey;

if FECMappilaryLayer.LoadImage(img) then
user.Text := img.User;
date.Text := DateTimeToStr(img.CapturedDateTime);
location.Text := img.Location;
// = angle of image
// = latitude
// img.lng = longitude

function UrlImage(const key:string):string;
Gets the url of image associated with the key.
function LocalPathImage(const Key:string):string;
Gets the path to an image in the local cache

property CanceledSearchSequence : boolean ;
Lets you know if a search of sequences has been cancelled.
property CanceledSearchImageClose : boolean ;
Lets you know if a search has been cancelled.
property ClientId: string ;
Mandatory key to use the services of Mappilary
property Connexion : TMappilaryConnexion ;
Type of connection

mcOnlyMappilaryServer : only by internet
mcOnlyLocal : only in local
mcLocalOrServer : local and if need internet (default value)
property LocalCache: string ;
The local cache directory
property Thumb: TMappilaryThumbSize ;

Size of images ( Thumb320, Thumb640, Thumb1024, Thumb2048 )

by default Thumb320

property Sequences: TMappilarySequenceList ;

List of sequences found in the visible area of the map

The property is updated automatically to each movement of the map

property Images : TMappilaryImageList;
List of images obtained with a call to SearchImageClose
property MaxDayInCache : integer;
Lifetime of the data stored in the local cache, by default 30 days

property OnClick: TOnMAppilaryClick ;

Raised when click on an element mappilary

property OnSequenceColor:TOnMappilaySequenceColor;

To assign a color to a sequence.

By default a single color is assigned based on the key of the sequence, a sequence will have therefore always the same color.

Layer.OnSequenceColor := doSequenceColor;

procedure TForm2.doSequenceColor(Layer : TECMappilaryLayer;
MappilarySequence: TMappilarySequence;
var SequenceColor:TColor);
SequenceColor := your_color;
property OnSequences: TOnMappilartySequences ;

Raised when the sequences are found.

The research of sequence is triggered when moving the map

procedure TForm2.doOnSequences(sender:TMappilarySequenceList);
var i,n:integer;

n := sender.Count;
TotalSequences.Text := inttostr(n)+' sequences';


for i := 0 to n-1 do
sequences.Items.Add(sender.Sequences[i].Key) ;


// test sender.More to see if there are other sequences in the area

property OnImages : TOnMappilartyImages;

Raised when the images are received after a call to SearchImagesClose


Internally, TMappilaryLayer uses the TMappilaryAPI class, you can use it directly if you do not want to display layer.

The operation is the same, it is necessary to indicate the search area with the function box Bound(NELat, NELng, SWLat, SWLng: double) then call SearchSequence to start the search.

Fig. 134 Demo Firemonkey MappilarySearchImages

go to page
© 2016 ESCOT-SEP Christophe - Made width Help&Web - RSS - Google+