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

Layers

Vous êtes ici :TECMap > Overlays

TECNativeLayer est la classe de base des layers qui vous permettent de réagir en fonction de la zone affichée et des actions de la souris.

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

FOnShapeRightClick,
FOnShapeClick : TOnShapeMouseEvent;

FOnMouseClick,
FOnMouseMove : TNotifyEvent;

function getMinZoom : byte;
function getMaxZoom : byte;

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

function getVisible : boolean;

protected

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;


public


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;

end;



Vous pouvez soit vous brancher sur OnMapHiResChange soit surcharger la procedure doOnMapHiResChange(sender : TObject) pour que votre layer s'adapte au changement de résolution

29

Panoramio

Google a fermé Panoramio le 4 novembre 2016, le service n'est plus fonctionnel

Un layer Panoramio est intégré dans TECNativeMap au travers de la propriété PanoramioLayer

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




L'évenement OnPanoramioClick(sender: TObject; const Item: TECShape; const ownerId, ownerName, PhotoId, PhotoDate, PhotoTitle, PhotoUrl, copyright: string) est déclenché lors d'un clic sur un élément Panoramio.

Fig. 125 Click sur un élément Panoramio

TECNativePlaceLayer

Vous permet d'afficher automatiquement le résultat d'une recherche

Pour utiliser ce layer vous devez incorporer l'unité uecNativePlaceLayer ou FMX.uecNativePlaceLayer selon que vous utilisiez la version VCL ou FireMonkey

99

Exemple : un layer qui affiche les 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 := 'http://www.helpandweb.com/cake_32.png';
// lat,lng on center of image
FPlacesLayer.XAnchor := 16;
FPlacesLayer.YAnchor := 16;
// hi-res image 64*64
FPlacesLayer.MarkerHiResFilename := 'http://www.helpandweb.com/cake_64.png';
// lat,lng on center of image
FPlacesLayer.HiResXAnchor := 32;
FPlacesLayer.HiResYAnchor := 32;
...

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

// 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
begin

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

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

end;


if FPlacesLayer.Shapes.InfoWindows.Count=0 then
begin
FPlacesLayer.Shapes.InfoWindows.add(0,0,'');
FPlacesLayer.Shapes.InfoWindows[0].zindex := 100;
end;

FPlacesLayer.Shapes.InfoWindows[0].content := Content;
FPlacesLayer.Shapes.InfoWindows[0].SetPosition(Shape.Latitude,shape.Longitude);
FPlacesLayer.Shapes.InfoWindows[0].Visible := true;


end;


end;

Fig. 126 Click sur un élément TECNativePlaceLayer

Par défaut les éléments du layer sont des TECShapeMarker mais vous pouvez changer le type de TECShape en redéfinissant TECNativePlaceLayer.doCreateShape(SearchResult : TECPlaceResult):TECShape;

XapiLayer

XapiLayer utilise TECNativePlaceLayer et est directement intégrer dans TECNativeMap pour une utilisation simplifié.

La recherche s'effectue dans la zone affichée par votre carte et est mise à jour à chaque déplacement

property Shapes:TECShapes

Le groupe qui contient les éléments affichés, il est nommé 'XAPI'

property Search : string


La recherche s'effectue en faisant une requête sur un serveur XAPI

Vous pouvez rechercher tous les tags OSM en utilisant une syntaxe du type 'node[key=value]'

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

Pour les nodes vous pouvez utiliser une syntaxe simplifiée.

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

Pour les clef amenity vous pouvez simplifier encore plus.

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

property Visible : boolean


Affiche / cache le layer

property MaxItem : integer


Nombre d'éléments maximum

property OnClick : TOnShape

Cet événement est déclenché lors d'un click sur un item du layer

property OnChange : TNotifyEvent

Déclenché après chaque requête
map.XapiLayer.OnClick := doOnXapiClick;
map.XapiLayer.OnChange := doOnXapiChange;
...
procedure TForm1.doOnXapiChange(sender : TObject);
begin
//
end;

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

Utilisez les styles pour habiller vos éléments

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

map.styles.addRule(Selector+':restaurant' +
'{graphic:base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAaBAMAAABI' +
'sxEJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABJQTFRFAAAA////AAAAAAA'
+ 'AAAAAAAAA/h6U3wAAAAV0Uk5TAAAQgL++EJOXAAAAOElEQVQY02MIFQ0MFWRUCXVigLBcQ0OgrNDQUH'
+ 'JYQIDOMg0NDYawBIFC2FgCSCxBerFMg0Es02AAP34wMx8/aIAAAAAASUVORK5CYII=;visible:true;');

map.styles.addRule(Selector+':bar' +
'{graphic:base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAzklEQVRIx+2WUQ3'
+ 'FIAxFK2ES8HANVMIkIGUOkICESUDCJCABCdtPSQgJC2UjeXlZk3402e1ZoRSIGgZgA3AqfSOtAYgDoK'
+ 'iFmCxWaDLMaEAsoqDQBNGsGlDeHyexnbJPAHwpKuIe9zSwDFzFPR6egM4P9HMgX3YQgDSr67gQrsq51'
+ 'z8ZqqqSwHrOkhsZqguAo0iyS5weL1kD5qZUcjPNfXV1HPIThmaY9vr4QH8KknbPXbfMgtiqvSMA+1Zy'
+ 'lrNy9/SK8g0PVamc2NlTK98F1MyKB+QkmGEAAAAASUVORK5CYII=;visible:true;}');

map.styles.addRule(Selector+':cafe' +
'{graphic:base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOA'
+ 'AAAuUlEQVRIx2NgIACMjY0F0PgN+OTJBkCD9iMbCsT/cclTYkkCzGCoJfuB+D02eUosKQAZAjIM5nKQ'
+ 'JUBsgE2eEotQDIHyHXDJU2JRPyn8wQmgcfCfTPye1HghGw8/i4D4PBrbgVYWYcMGtLAoAakUmQ8VW0/'
+ 'TOALyFXDGHZUtEqCXRbCy8DzNLAKlNqTMn0ATi0AVI5LYflol7/1I7Pk4a18q5Zv3BKsPKpUMCvQogh'
+ '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'

Way

Avec une syntaxe du type way[key=value] pour pouvez extraire des chemins.

// 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

Vous pouvez aussi trouver les jonctions entres les routes.

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

Fig. 130 Xapi Roads & Junction

Recherche manuelle

Lorsque le layer est visible la recherche est synchronisée avec la zone visible de votre carte.

Pour pouvoir effectuer une recherche sur n'importe quelle zone vous devez cacher le layer et utiliser Bound pour délimiter la zone de recherche.

// sample, copie data in another group

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

TECNativeUTFLayer

Ce layer vous apporte le support du format UTFGrid

Exemple : traduction en Delphi de Visible Map

// support UTFGrid Layer see http://www.mapbox.com/developers/utfgrid/

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

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


FUTFLayer.Shapes.InfoWindows.add(0,0,'');
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

// http://a.tiles.mapbox.com/v3/mapbox.geography-class/4/7/7.grid.json for see data tile

procedure TForm1.GetUTFTile(var TileFilename:string;const x,y,z:integer);
begin
TileFilename := format('http://%s.tiles.mapbox.com/v3/mapbox.geography-class/%d/%d/%d.grid.json',
[Char(Ord('a') + random(3)),z,x,y]);
end;


// OnOver country

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

procedure TForm1.doOnOverUTFData(sender : TObject);
begin

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

FUTFLayer.Shapes.InfoWindows[0].SetPosition(map.MouseLatLng.Lat,map.MouseLatLng.Lng);
FUTFLayer.Shapes.InfoWindows[0].Visible := true;

end;


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


Fig. 131 UTFGrid geography-class

TECNativeLabelLayer

Ce layer affiche une infoWindow au-dessus des TECShape, elle est mise à jour et déplacée automatiquement en fonction du Hint et de la position des TECShape

Fig. 132 Using labels to display positions

Pour utiliser ce layer vous devez incorporer l'unité uecNativeLabelLayer ou FMX.uecNativeLabelLayer selon que vous utilisiez la version VCL ou FireMonkey

100

LLayer : TECNativeLabelLayer;

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

LLayer.visible := true;

// add shapes to layer
LLayer.add(map.Shapes.Markers[0]);
LLayer.add(map.Shapes.Pois[0]);

Consultez les sources des démos Firemonkey et DemoNativeRoute pour un exemple d'utilisation

Mappilary

Mappilary est un service du même type que Google Street Map, il permet d'afficher des photos au niveau des rues, l'avantage est que vous pouvez vous-même l'enrichir en enregistrant vos parcours.

TECNativeMap se contente d'utiliser les informations en libre accès au près de Mappilary, vous devez obtenir une clef pour utiliser les service de Mappilary.

Pour cela allez sur le site www.mapillary.com, connectez-vous, dans la section Integrations ajoutez vos applications, vous obtiendrez alors un Client ID qui vous servira de clef.

Pour utiliser mappilary vous devez incorporer l'unité uecMappilary ou FMX.uecMappilary selon que vous utilisiez la version VCL ou FireMonkey

101

Utilisez TECMappilaryLayer pour incorporer un layer Mappilary.

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

FMappilaryLayer.Visible := true;

Fig. 133 Demo Mappilary

TECMappilaryLayer



procedure CancelSearchSequence;
Annule une recherche de sequences.
procedure CancelSearchImageClose;
Annule une recherche d'images
procedure SearchImageClose(const Lat, Lng: double; Distance: integer);

Lance une recherche d'images situées à une Distance maximale, exprimée en mètres, du point Lat,Lng

Vous pouvez vous connecter à l'évènement OnImages pour être averti d'une réponse.

La propriété Images contient la liste des images.

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

Trouver la photo la plus proche parmis celles affichées dans le layer, la recherche est en local.

Lat,Lng indique le point de départ de la recherche

Distance indique la distance maximale en mètres de la zone de recherche

Seq contiendra la séquence trouvée ou nil

PhotoIndex contiendra l'index de la photo dans seq ou -1

Retourne la distance en mètres entre le point de recherche et la photo, 0 si pas de photo

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

Obtient un bitmap contenant l'image dont on a passé la clef.

Attention vous ne devez pas libérer le bitmap obtenu, pour le conserver vous devez en faire une copie !

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

rempli un bitmap avec l'image dont on a passé la clef.

Attention vous êtes responsable de la création et de la libération du bitmap !

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

Obtient un bitmap contenant l'image dont on a passé la clef, cette fonction n'est pas bloquante, OnBitmap est appelé lorsque l'image est chargée.

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

Obtient les informations d'une image

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

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

finally
img.Free;
end;
function UrlImage(const key:string):string;
Obtient l'url d'une image dont on passe la clef.
function LocalPathImage(const Key:string):string;
Obtient le chemin d'une image dans le cache local

property CanceledSearchSequence : boolean ;
Permet de savoir si une recherche de séquences a été annulée.
property CanceledSearchImageClose : boolean ;
Permet de savoir si une recherche d'images a été annulée.
property ClientId: string ;
OBLIGATOIRE la clef pour utiliser les services de Mappilary
property Connexion : TMappilaryConnexion ;
Type de connexion

mcOnlyMappilaryServer : uniquement par internet
mcOnlyLocal : uniquement en local
mcLocalOrServer : local et si besoin internet (valeur par défaut)
property LocalCache: string ;
Répertoire du cache local
property Thumb: TMappilaryThumbSize ;

Taille des images ( Thumb320, Thumb640, Thumb1024, Thumb2048 )

par défaut Thumb320

property Sequences: TMappilarySequenceList ;

Liste des séquences trouvée dans la zone visible de la carte

La propriétée est mise à jour automatiquement à chaque déplacement de la carte

property Images : TMappilaryImageList;
Liste des images obtenue avec un appel à SearchImageClose
property MaxDayInCache : integer;
Durée de vie des données stockées dans le cache local, par défaut 30 jours

property OnClick: TOnMAppilaryClick ;

Déclenché lors d'un click sur un élément mappilary

property OnSequenceColor:TOnMappilaySequenceColor;

Permet d'attribuer une couleur à une séquence.

Par défaut une couleur unique est attribuée en fonction de la clef de la séquence, une séquence aura donc toujours la même couleur.

102
Layer.OnSequenceColor := doSequenceColor;

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

Déclenché lorsque des séquences on été trouvées.

La recherche de séquence est déclenchée lors du déplacement de la carte

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

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


sequences.Items.BeginUpdate;
sequences.Items.Clear;

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

sequences.Items.EndUpdate;

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

end;
property OnImages : TOnMappilartyImages;

Déclenché lors de la réception des images après un appel à SearchImagesClose

TMappilaryAPI

TMappilaryLayer utilise en interne la classe TMappilaryAPI, vous pouvez l'utiliser directement si vous ne souhaitez pas afficher le layer.

Le fonctionnement est identique, il vous suffira simplement d'indiquer la zone de recherche avec la fonction Bound(NELat, NELng, SWLat, SWLng: double) puis SearchSequence pour lancer la recherche.

Fig. 134 Demo Firemonkey MappilarySearchImages

Aller à la page
Composant Delphi / Google Maps / OpenStreetMap / Leaflet  / Mappilary© 2016 ESCOT-SEP Christophe - Réalisé avec Help&Web - RSS - RSS - Google+