Nous allons voir comment incruster une mini carte synchronisée sur la carte principale
Placez un TPanel sur votre composant TECNativeMap, fixez les propriétés color à clWhite, BevelInner et BevelOuter à false et BorderWidth à 4
Déposez sur le TPanel un composant TECNativeMap avec ses propriétés Align à alClient, dblClickZoom et Draggable à false
La mini carte devra être centrée sur la carte principale avec un zoom 5 crans en dessous, et nous y dessinerons une zone rectangulaire correspondante à la vue de la carte principale.
procedure TForm1.UpdateMiniMap;
begin
// if the call comes from the direct change of the minimap, you must leave otherwise we go into an infinite loop
if minimap.tag = 1 then exit;
// indicates that map has initiated the movement
map.tag := 1;
if not assigned(FMiniPolygone) then
begin
minimap.ShowCopyrightTile := false;
minimap.shapes.Polygones.add(0,0) ;
FMinipolygone := minimap.shapes.Polygones[0];
FMinipolygone.ShowText := false;
FMinipolygone.fillColor := clBlue;
FMinipolygone.hoverColor := clBlue;
FMinipolygone.Opacity := 50;
minimap.OnChangeMapZoom := minimapChangeMapZoom;
minimap.OnMapMove := minimapMapMove;
end;
minimap.setCenter(Map.latitude,Map.longitude);
minimap.zoom := Map.zoom - 5;
FMinipolygone.SetPath([ Map.SouthWestLatitude, Map.SouthWestLongitude,
Map.SouthWestLatitude, Map.NorthEastLongitude,
Map.NorthEastLatitude, Map.NorthEastLongitude,
Map.NorthEastLatitude, Map.SouthWestLongitude,
Map.SouthWestLatitude, Map.SouthWestLongitude
]);
map.tag := 0;
end;
Vous devrez appeler UpdateMiniMap dans les événenemts OnMapMove et OnChangeMapBounds de la carte principale.
Vous devrez aussi répondre aux événements OnMapMove et OnChangeMapBounds pour ajuster la vue de la carte principale lorsque l'on actionne directement la mini carte, sans oublier d'ajuster la position de la minimap dans l'événement OnResize
unit UMainNativeMiniMap;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uecNativeMapControl, ExtCtrls, StdCtrls,uecNativeShape;
type
TForm1 = class(TForm)
Panel1: TPanel;
Map: TECNativeMap;
plus: TButton;
Button1: TButton;
pnMiniMap: TPanel;
minimap: TECNativeMap;
procedure FormCreate(Sender: TObject);
procedure MapMapMove(sender: TObject; const Lat, Lng: Double);
procedure MapResize(Sender: TObject);
procedure MapChangeMapBounds(Sender: TObject);
procedure minimapMapMove(sender: TObject; const Lat, Lng: Double);
procedure minimapChangeMapZoom(Sender: TObject);
private
{ Déclarations privées }
procedure UpdateMiniMap;
var FMiniPolygone : TECShapePolygone;
public
{ Déclarations publiques }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Map.LocalCache := ExtractFilePath(application.exename) + 'cache';
end;
procedure TForm1.MapChangeMapBounds(Sender: TObject);
begin
UpdateMiniMap;
end;
procedure TForm1.MapMapMove(sender: TObject; const Lat, Lng: Double);
begin
UpdateMiniMap;
end;
procedure TForm1.MapResize(Sender: TObject);
begin
pnMiniMap.Top := Map.Height - pnMiniMap.Height -16;
pnMiniMap.Left:= Map.width - pnMiniMap.width - 8;
end;
procedure TForm1.minimapChangeMapZoom(Sender: TObject);
begin
// it deals only with direct access to the minimap
if map.tag=1 then exit;
// indicates that minimap has initiated the movement
minimap.tag := 1;
Map.zoom := minimap.zoom + 5;
minimap.tag := 0;
end;
procedure TForm1.minimapMapMove(sender: TObject; const Lat, Lng: Double);
begin
// it deals only with direct access to the minimap
if map.tag=1 then exit;
// indicates that minimap has initiated the movement
minimap.tag := 1;
Map.setCenter(minimap.latitude,minimap.longitude);
minimap.tag := 0;
end;
procedure TForm1.UpdateMiniMap;
begin
// if the call comes from the direct change of the minimap, you must leave otherwise we go into an infinite loop
if minimap.tag = 1 then exit;
// indicates that map has initiated the movement
map.tag := 1;
// if the first call, creation of the polygon indicates the main view
if not assigned(FMiniPolygone) then
begin
minimap.ShowCopyrightTile := false;
minimap.shapes.Polygones.add(0,0) ;
FMinipolygone := minimap.shapes.Polygones[0];
FMinipolygone.ShowText := false;
FMinipolygone.fillColor := clBlue;
FMinipolygone.hoverColor := clBlue;
FMinipolygone.Opacity := 50;
end;
minimap.setCenter(map1.latitude,map1.longitude);
minimap.zoom := map1.zoom - 5;
// update polygon with boundingbox main map
FMinipolygone.SetPath([ map1.SouthWestLatitude, map1.SouthWestLongitude,
map1.SouthWestLatitude, map1.NorthEastLongitude,
map1.NorthEastLatitude, map1.NorthEastLongitude,
map1.NorthEastLatitude, map1.SouthWestLongitude,
map1.SouthWestLatitude, map1.SouthWestLongitude
]);
map.tag := 0;
end;
end.
Google Maps dispose déjà en natif d'un layer Panoramio nous allons voir comment porter cette fonctionnalité vers toutes les apis disponible dans notre composant Delphi TECMap.
Nous allons créer une classe sur le même modèle que celle qui gère la création interactive d'une route c'est pourquoi nous ne détaillerons pas le code commun.
Le principe est simple, chaque fois que la vue de la carte change nous récupérons les images panoramio disponible dans la zone visible, avant de les afficher on les place dans un groupe pour pouvoir les manipuler plus facilement.
On se branche sur l'évènement OnChangeMapBounds pour détecter le changement de vue.
Pour la recherche d'images on utilise PanoramioView.Search, elle est lancée dans un Thread séparé, nous devons nous brancher sur l'évènement OnPanoramioSearch pour récupèrer notre liste d'images.
On va transformer chaque image en marker et gérer le Click pour pouvoir afficher une InfoWindow contenant le titre et l'image en taille moyenne.
FPanoramioLayer := TPanoramioLayer.create;
...
// connect TECMap component for show Panoramio layer
FPanoramioLayer.Map := map;
// deconnect layer
FPanoramioLayer.Map := nil
unit UPanoramioLayer;
interface
uses Windows, SysUtils, Classes, Graphics, ECMaps, UECMapUtil;
type
TOnPanoramioLayerPhotoClick = procedure(sender: Tobject; const PhotoId : integer) of object;
TPanoramioLayer = class
private
FECMap : TECMap;
FOldOnPanoramioSearch : TOnPanoramioSearch;
FOldOnChangeMapBounds : TNotifyEvent;
FOnPanoramio : TNotifyEvent;
FOnClick : TOnPanoramioLayerPhotoClick;
FChangedBounds,
FInfowindow,
FShow : boolean;
FIdInfoWindow,
FMaxPhoto : integer;
procedure setMap(const ecMap:TECMap);
procedure setShow(const value:boolean);
procedure AssignEvents;
procedure RestoreEvents;
procedure doOnPanoramioSearch(sender: TObject; const First,Last: Integer);
procedure doOnChangeMapbounds(sender: TObject);
procedure doOnMarkerClick(sender: Tobject; const Index: integer;
const dLatitude, dLongitude: double);
public
constructor Create ;
destructor Destroy ; override;
procedure Clear;
property Map : TECMap read FECMap write setMap;
property MaxPhoto : integer read FMaxPhoto write FMaxPhoto;
property Show : boolean read FShow write setShow;
property Infowindow : boolean read FInfowindow write FInfowindow;
property OnPanoramio : TNotifyEvent read FOnPanoramio write FOnPanoramio;
property OnClick : TOnPanoramioLayerPhotoClick read FOnClick write FOnClick;
end;
implementation
constructor TPanoramioLayer.Create;
begin
FMaxPhoto := 300;
FInfowindow := true;
inherited;
end;
destructor TPanoramioLayer.Destroy ;
begin
Clear;
Map := nil;
inherited;
end;
procedure TPanoramioLayer.AssignEvents;
begin
if not assigned(Map) then exit;
// save the events of Origins
FOldOnPanoramioSearch := Map.OnPanoramioSearch;
FOldOnChangeMapBounds := Map.OnChangeMapBounds;
// connect to the events that interest us
Map.OnPanoramioSearch := doOnPanoramioSearch;
Map.OnChangeMapBounds := doOnChangeMapbounds;
end;
// Reassign the events of origins
procedure TPanoramioLayer.RestoreEvents;
begin
if not assigned(Map) then exit;
Map.InfoWindows.delete(FIdInfoWindow);
end;
procedure TPanoramioLayer.setMap(const ecMap:TECMap);
begin
Clear;
RestoreEvents;
FECMap := ecMap;
FIdInfoWindow := -1;
FChangedBounds := false;
AssignEvents;
if assigned(FECMap) then Show := true;
end;
procedure TPanoramioLayer.Clear;
begin
if not assigned(Map) then exit;
Map.Groups['panoramio'].Delete;
end;
procedure TPanoramioLayer.setShow (const value:boolean);
begin
// delete old images
Clear;
if value then
begin
Map.PanoramioView.LatSW := Map.SouthWestLatitude;
Map.PanoramioView.LatNE := Map.NorthEastLatitude;
Map.PanoramioView.LngSW := Map.SouthWestLongitude;
Map.PanoramioView.LngNE := Map.NorthEastLongitude;
// search for images, called doOnPanoramioSearch when they are found
Map.PanoramioView.Search;
end;
FShow := value;
end;
// triggered by Show := true
procedure TPanoramioLayer.doOnPanoramioSearch(sender: TObject; const First,Last: Integer);
var i,j:integer;
marker : TECMapMarker;
Lat,Lng : double;
url : string;
begin
for i := first to Last - 1 do
begin
Lat := Map.PanoramioView.photo_lat[i];
Lng := Map.PanoramioView.photo_lng[i];
url := remplace_str(Map.PanoramioView.photo_file_url[i],'/medium/', '/mini_square/');
j := Map.AddMarker(lat,lng);
marker := Map.Markers[j];
marker.Draggable := false;
marker.Icon := url;
marker.Group := Map.Groups['panoramio'];
marker.Tag := i;
marker.OnMarkerClick := doOnMarkerClick;
end;
Map.Groups['panoramio'].show;
if assigned(FOnPanoramio) then
FOnPanoramio(self);
if (Map.PanoramioView.HasMore) and (Map.Groups['panoramio'].count<MaxPhoto) then
begin
Map.PanoramioView.NextSearch;
exit;
end;
if assigned(FOldOnChangeMapBounds) and FChangedBounds then
FOldOnChangeMapBounds(self);
FChangedBounds := false;
end;
procedure TPanoramioLayer.doOnChangeMapbounds(sender: TObject);
begin
if FChangedBounds then exit;
FChangedBounds := true;
Show := true;
end;
procedure TPanoramioLayer.doOnMarkerClick(sender: Tobject; const Index: integer;
const dLatitude, dLongitude: double);
var i:integer;
s : string;
begin
if not assigned(Map.Markers[index]) then exit;
if Infowindow then
begin
i := Map.Markers[index].tag;
s := '<h3>'+Map.PanoramioView.photo_title[i]+'</h3>'+
Map.PanoramioView.HtmlPhoto(i,pimMedium)+
Map.PanoramioView.HtmlCopyright(i) ;
if FIdInfoWindow< 0 then
FIdInfoWindow := Map.InfoWindows.add(s)
else
Map.InfoWindows[FidInfoWindow].Content := s;
// for Bing maps
Map.InfoWindows[FidInfoWindow].SetOptions('width :550, height :450,zIndex:500');
Map.InfoWindows[FidInfoWindow].SetPosition(dLatitude, dLongitude);
Map.InfoWindows[FidInfoWindow].Open := true;
end;
if assigned(FOnClick) then
FOnClick(self,Map.Markers[index].tag);
end;
end.
Nous allons voir comment afficher StreetView dans une InfoWindow
StreetView n'est disponible qu'avec l'api Google Maps !
La première étape est de créer notre InfoWindow, nous stockons son index dans idStreetWindow
Son contenu sera un élément DIV qui devra avoir un nom unique ici "streetwindow"
Il faut aussi définir sa taille, 300 pixels en hauteur et largeur.
idStreetWindow := map.InfoWindows.Add('<div id="streetwindow" style="width:300px;height:300px"></div>');
Nous nous branchons sur les événements OnInfoWindowOpen et OnInfoWindowClose pour afficher/cacher StreetView lorsque l'InfoWindow sera ouverte ou fermée.
map.OnInfoWindowOpen := mapInfoWindowOpen;
map.OnInfoWindowClose := mapInfoWindowClose;
Dans ces événements nous utilisons javascript pour faire le travail désiré.
procedure TForm.mapInfoWindowOpen(sender: TObject;
const Index: Integer);
var js:string;
begin
if index=idStreetWindow then
begin
js :=
// get latitude and longitude of InfoWindow
'var LatLng = new google.maps.LatLng('+doubletostr(map.InfoWindows[index].Latitude)+','+doubletostr(map.InfoWindows[index].Longitude)+');'+
'var pano = new google.maps.StreetViewPanorama(document.getElementById("streetwindow"), {'+
'position:LatLng'+
'});'+
'pano.setVisible(true);';
// run javascript
map.Javascript(js);
end;
procedure TForm.mapInfoWindowClose(sender: TObject; const Index: Integer);
begin
if index=idStreetWindow then
begin
map.javascript('pano.setVisible(false);pano = null;');
end;
end;
Pour ouvrir l'InfoWindow vous pouvez soit réagir directement lors d'un clic sur la carte en vous branchant sur OnMapClick
procedure TForm.mapMapClick(sender: Tobject;const dLatitude, dLongitude: Double);
begin
map.InfoWindows[idStreetWindow].SetPosition(dlatitude,dlongitude);
map.InfoWindows[idStreetWindow].Open := true;
end;
Mais vous pouvez aussi l'associer à un marker et alors elle s'ouvrira lors d'un clic sur celui-ci
// anchor infowindow to marker number 0
map.InfoWindows[idStreetView].Anchor := 0;
Nous allons réaliser une classe qui manipulera un composant TECMap dans le but de créer une route en cliquant sur la carte le point de départ et d'arrivée, une fois la route créé nous devrons pouvoir la modifier à la souris
Un évenement sera déclenché à chaque modification de la route et nous pourront alors consulter les diverses informations de celle-ci (distance, durée, points de passages )
FInfoRoute := TInfoRoute.create;
// event fired when new route or route change
FInfoRoute.OnRoute := OnInfoRoute;
// route color
FInforoute.Color := clRed;
// Active InfoRoute
FInfoRoute.map := map;
// deactive InfoRoute
FInfoRoute.map := nil;
Lors de la connexion du composant TECMap nous sauvegardons les évenements sur lesquels nous nous branchons.
procedure TInfoRoute.setMap(const Map:TECMap);
begin
Clear;
RestoreEvents;
FECMap := Map;
AssignEvents;
end;
procedure TInfoRoute.AssignEvents;
begin
if not assigned(FECMap) then exit;
// save the events of Origins
FOldMapClick := FECMap.OnMapClick;
FOldAfterReload := FECMap.OnAfterReload ;
FOldBeforeReload := FECMap.OnBeforeReload ;
FOldRouteChange := FECMap.OnRouteChange;
// connect to the events that interest us
FECMap.OnMapClick := doOnMapClick;
FECMap.OnAfterReload := doOnAfterReload;
FECMap.OnBeforeReload := doOnBeforeReload;
FECMap.OnRouteChange := doOnRouteChange;
end;
// Reassign the events of origins
procedure TInfoRoute.RestoreEvents;
begin
if not assigned(FECMap) then exit;
FECMap.OnMapClick := FOldMapClick;
FECMap.OnAfterReload := FOldAfterReload;
FECMap.OnBeforeReload := FOldBeforeReload;
FECMap.OnRouteChange := FOldRouteChange;
end;
Le principal évenement est OnMapClick qui nous permet de réagir lors que l'utilisateur clique sur la carte.
Si la route n'est pas créé on teste si l'on doit créer le marker de début ou de fin, pour chaqu'un d'eux nous ajustons ses coordonnées avec AlignLatLngToRoute pour se positionner sur la route la plus proche du point cliqué.
procedure TInfoRoute.doOnMapClick(sender: Tobject; const dLatitude, dLongitude: double);
var id:integer;
lat,lng : double;
begin
if not assigned(FECMap) or
assigned(FPolyline) or
assigned(FRoute) then exit;
lat := dLatitude;
lng := dLongitude;
// Start Marker
if not assigned(FStartMarker) then
begin
FECMap.AlignLatLngToRoute(lat, lng);
FStartLat := lat;
FStartLng := lng;
id := FECMap.AddMarker(lat, lng);
FStartMarker := FECMap.Markers[id];
FStartMarker.Draggable := true;
FStartMarker.OnMarkerMove := doOnMoveMarker;
end
else // End Marker
if not assigned(FEndMarker) then
begin
FECMap.AlignLatLngToRoute(lat, lng);
id := FECMap.AddMarker(lat, lng);
FEndLat := lat;
FEndLng := lng;
FEndMarker := FECMap.Markers[id];
FEndMarker.Draggable := true;
FEndMarker.OnMarkerMove := doOnMoveMarker;
SetRoute;
end;
end;
On se branche sur l'événement OnMarkerMove des markers pour pouvoir modifier manuellement le début et la fin de notre route dans le cas des apis qui ne permettent pas de gérer les routes modifiables.
procedure TInfoRoute.doOnMoveMarker(sender: Tobject; const Index: integer;
var dLatitude, dLongitude: double);
begin
FECMap.AlignLatLngToRoute(dLatitude, dLongitude);
setRoute;
end;
Lors de la création du point d'arrivée on appelle setRoute pour créer notre route.
Seules les apis Google Maps et OpenMapQuest permettent de modifier la route à la souris, pour les autres nous allons émuler cette fonction en utilisant une Polyline et nos markers de début et de fin.procedure TInfoRoute.setRoute;
var id : integer;
begin
if assigned(FECMap) and
assigned(FStartMArker) and
assigned(FEndMarker) then
begin
if assigned(FPolyLine) then
begin
FECMap.Polylines.delete(FPolyLine.id);
FRoutePath.free;
FPolyline := nil;
end;
if assigned(FRoute) then
begin
FECMap.Routes.delete(FRoute.Id);
FRoute := nil;
end;
FRoutePath := nil;
// only Google and OpenMapQuest support dynamic route
if (FECMap.MapAPI=apiGoogle) or
(FECMap.MapAPI=apiOpenMapQuest) then
begin
id := FECMap.AddRoute('',FStartMarker.Latitude,FStartMarker.Longitude,FEndMarker.Latitude,FEndMarker.Longitude);
FRoute := FECMap.routes[id];
// the dynamic routes have their own markers
// so ours is deleted
if assigned(FStartMarker) then
begin
FECMap.Markers.delete(FStartMarker.id);
FStartMarker := nil;
end;
if assigned(FEndMarker) then
begin
FECMap.MArkers.delete(FEndMarker.id);
FEndMarker := nil;
end;
end
else
begin
FRoutePath := FECMap.getRoutePathFrom([FStartMarker.Latitude,FStartMarker.Longitude,FEndMarker.Latitude,FEndMarker.Longitude]);
if FRoutePath<>nil then
begin
id := map.polylines.addFromRoutePath(FRoutePath);
FPolyLine := FECMap.PolyLines[id];
FPolyLine.Color := FColor;
FPolyLine.Opacity := FOpacity;
FPolyLine.ReDraw;
if assigned(OnRoute) then
OnRoute(self);
end;
end;
end;
end;
Avec Google Maps ou OpenMapQuest lorsque la route est modifiée l'événement OnRouteChange est déclenché, si la route vient d'être créé nous la rendons modifiable et nous ajustons sa couleur.
procedure TInfoRoute.doOnRouteChange(sender: Tobject; const idRoute: integer;const NewRoute: boolean);
begin
if assigned(FRoute) and
(FRoute.id=idRoute) and
assigned(OnRoute) then
begin
if NewRoute then
begin
FRoute.Draggable := true;
FRoute.Color := FColor;
FRoute.Opacity := FOpacity;
// updateOptions fire OnRouteChange
FRoute.updateOptions;
end
else
if assigned(OnRoute) then
OnRoute(self) ;
end
else
if Assigned(FOldRouteChange) then
FOldRouteChange(sender,idRoute,NewRoute);
end;
Lorsque la route est créé/modifiée l'événement OnRoute de notre classe est déclenché, en vous y branchant vous pourrez récupérer les informations sur celle-ci au travers de la propriété RoutePath de type TECMapRoutePath.
RoutePath.Distance; // distance in meters
RoutePath.Duration; // duration in seconds
unit UInfoRoute;
interface
uses Windows, SysUtils, Classes, Graphics, ECMaps;
type
TInfoRoute = class
private
FECMap : TECMap;
FStartLat,FStartLng,
FEndLat,FEndLng : double;
FStartMarker,
FEndMarker : TECMapMarker;
FPolyLine : TECMapPolyline;
FRoutePath : TECMapRoutePath;
FRoute : TECMapRoute;
FOldMapClick : TOnMapClick;
FOldRouteChange : TOnRouteChange;
FOldAfterReload,
FOldBeforeReload,
FOnRoute : TNotifyEvent;
FColor : TColor;
FOpacity : double;
procedure setMap(const Map:TECMap);
procedure AssignEvents;
procedure RestoreEvents;
procedure setRoute;
function getRoutePath:TECMapRoutePath;
procedure doOnMapClick(sender: Tobject; const dLatitude, dLongitude: double);
procedure doOnMoveMarker(sender: Tobject; const Index: integer;
var dLatitude, dLongitude: double) ;
procedure doOnRouteChange(sender: Tobject; const idRoute: integer;const NewRoute: boolean);
procedure doOnBeforeReload(sender: Tobject);
procedure doOnAfterReload(sender: Tobject);
public
constructor Create ;
destructor Destroy ; override;
procedure Clear;
property Map : TECMap read FECMap write setMap;
property RoutePath : TECMapRoutePath read getRoutePath;
property Color : TColor read FColor write FColor;
property Opacity: double read FOpacity write FOpacity;
property OnRoute : TNotifyEvent read FOnRoute write FOnRoute;
end;
implementation
constructor TInfoRoute.Create;
begin
FColor := clBlue;
FOpacity := 0.5;
inherited;
end;
destructor TInfoRoute.Destroy ;
begin
Map := nil;
inherited;
end;
procedure TInfoRoute.AssignEvents;
begin
if not assigned(FECMap) then exit;
// save the events of Origins
FOldMapClick := FECMap.OnMapClick;
FOldAfterReload := FECMap.OnAfterReload ;
FOldBeforeReload := FECMap.OnBeforeReload ;
FOldRouteChange := FECMap.OnRouteChange;
// connect to the events that interest us
FECMap.OnMapClick := doOnMapClick;
FECMap.OnAfterReload := doOnAfterReload;
FECMap.OnBeforeReload := doOnBeforeReload;
FECMap.OnRouteChange := doOnRouteChange;
end;
// Reassign the events of origins
procedure TInfoRoute.RestoreEvents;
begin
if not assigned(FECMap) then exit;
FECMap.OnMapClick := FOldMapClick;
FECMap.OnAfterReload := FOldAfterReload;
FECMap.OnBeforeReload := FOldBeforeReload;
FECMap.OnRouteChange := FOldRouteChange;
end;
procedure TInfoRoute.setMap(const Map:TECMap);
begin
Clear;
RestoreEvents;
FECMap := Map;
AssignEvents;
end;
procedure TInfoRoute.doOnBeforeReload(sender: Tobject);
begin
Clear;
if assigned(FOldBeforeReload) then
FOldBeforeReload(FECMap);
end;
procedure TInfoRoute.doOnAfterReload(sender: Tobject);
var id:integer;
begin
if (FStartLat <> 0) and
(FStartLng <> 0) and
(FStartMarker = nil) then
begin
id := FECMap.AddMarker(FStartLat, FStartLng);
FStartMarker := FECMap.Markers[id];
FStartMarker.Draggable := true;
FStartMarker.OnMarkerMove := doOnMoveMarker;
if (FEndLat <> 0) and
(FEndLng <> 0) then
begin
id := FECMap.AddMarker(FEndLat, FEndLng);
FEndMarker := FECMap.Markers[id];
FEndMarker.Draggable := true;
FEndMarker.OnMarkerMove := doOnMoveMarker;
SetRoute;
end;
end;
if assigned(FOldAfterReload) then
FOldAfterReload(FECMap);
end;
procedure TInfoRoute.doOnMapClick(sender: Tobject; const dLatitude, dLongitude: double);
var id:integer;
lat,lng : double;
begin
if not assigned(FECMap) or
assigned(FPolyline) or
assigned(FRoute) then exit;
lat := dLatitude;
lng := dLongitude;
if not assigned(FStartMarker) then
begin
FECMap.AlignLatLngToRoute(lat, lng);
FStartLat := lat;
FStartLng := lng;
id := FECMap.AddMarker(lat, lng);
FStartMarker := FECMap.Markers[id];
FStartMarker.Draggable := true;
FStartMarker.OnMarkerMove := doOnMoveMarker;
end
else
if not assigned(FEndMarker) then
begin
FECMap.AlignLatLngToRoute(lat, lng);
id := FECMap.AddMarker(lat, lng);
FEndLat := lat;
FEndLng := lng;
FEndMarker := FECMap.Markers[id];
FEndMarker.Draggable := true;
FEndMarker.OnMarkerMove := doOnMoveMarker;
SetRoute;
end;
end;
procedure TInfoRoute.doOnMoveMarker(sender: Tobject; const Index: integer;
var dLatitude, dLongitude: double);
begin
FECMap.AlignLatLngToRoute(dLatitude, dLongitude);
setRoute;
end;
procedure TInfoRoute.setRoute;
var id : integer;
begin
if assigned(FECMap) and
assigned(FStartMArker) and
assigned(FEndMarker) then
begin
if assigned(FPolyLine) then
begin
FECMap.Polylines.delete(FPolyLine.id);
FRoutePath.free;
FPolyline := nil;
end;
if assigned(FRoute) then
begin
FECMap.Routes.delete(FRoute.Id);
FRoute := nil;
end;
FRoutePath := nil;
// only Google and OpenMapQuest support dynamic route
if (FECMap.MapAPI=apiGoogle) or
(FECMap.MapAPI=apiOpenMapQuest) then
begin
id := FECMap.AddRoute('',FStartMarker.Latitude,FStartMarker.Longitude,FEndMarker.Latitude,FEndMarker.Longitude);
FRoute := FECMap.routes[id];
// the dynamic routes have their own markers
// so ours is deleted
if assigned(FStartMarker) then
begin
FECMap.Markers.delete(FStartMarker.id);
FStartMarker := nil;
end;
if assigned(FEndMarker) then
begin
FECMap.MArkers.delete(FEndMarker.id);
FEndMarker := nil;
end;
end
else
begin
FRoutePath := FECMap.getRoutePathFrom([FStartMarker.Latitude,FStartMarker.Longitude,FEndMarker.Latitude,FEndMarker.Longitude]);
if FRoutePath<>nil then
begin
id := map.polylines.addFromRoutePath(FRoutePath);
FPolyLine := FECMap.PolyLines[id];
FPolyLine.Color := FColor;
FPolyLine.Opacity := FOpacity;
FPolyLine.ReDraw;
if assigned(OnRoute) then
OnRoute(self);
end;
end;
end;
end;
procedure TInfoRoute.doOnRouteChange(sender: Tobject; const idRoute: integer;const NewRoute: boolean);
begin
if assigned(FRoute) and
(FRoute.id=idRoute) and
assigned(OnRoute) then
begin
if NewRoute then
begin
FRoute.Draggable := true;
FRoute.Color := FColor;
FRoute.Opacity := FOpacity;
// updateOptions fire OnRouteChange
FRoute.updateOptions;
end
else if assigned(OnRoute) then
OnRoute(self) ;
end
else
if Assigned(FOldRouteChange) then
FOldRouteChange(sender,idRoute,NewRoute);
end;
function TInfoRoute.getRoutePath:TECMapRoutePath;
begin
if ASsigned(FRoute) then
result := FRoute.Path
else
if Assigned(FRoutePath) then
result := FRoutePath
else
result := nil;
end;
procedure TInfoRoute.Clear;
begin
if not assigned(FECMap) then exit;
if assigned(FStartMarker) then
begin
FECMap.MArkers.delete(FStartMarker.id);
FStartMarker := nil;
end;
if assigned(FEndMarker) then
begin
FECMap.MArkers.delete(FEndMarker.id);
FEndMarker := nil;
end;
if assigned(FPolyLine) then
begin
FECMap.Polylines.delete(FPolyLine.id);
FPolyLine := nil;
FRoutePath.free;
FRoutePath := nil;
end;
if assigned(FRoute) then
begin
FECMap.Routes.delete(FRoute.Id);
FRoute := nil;
end;
end;
end.