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

TECNativeMap

TECNativeMap is available in VCL and Firemonkey (Windows , Mac OS X, iOs and Android) for the same price !

you access an offline mode, not using the Google Maps service and other Bing Maps lets you keep control over your data.

Fig. 1 ECNativeMap on Mac OS X
Fig. 1 ECNativeMap on Mac OS X

TECNativeMap allows you to use OpenStreetMap maps, Google, MapBox, OpenCycleMap, OPNV, TomTom etc, and manage your own components to integrate into it.

To select a map provider use the property TileServer

map.TileServer := tsOsm;

Google

To use Google Tiles you need to enter your API key in GoogleKey, go to Google's platform to generate it.

map.Google.ApiKey := 'your api key';
map.TileServer := tsGoogle;

// 3 map types to choose from
map.TileServerInfo.MapStyle := 'satellite';
map.TileServerInfo.MapStyle := 'terrain';
map.TileServerInfo.MapStyle := 'roadmap';

// set language, default en-US
map.Google.Lang := 'fr-FR';
// set region, default US
map.Google.Region := 'FR';
// traffic is also supported
map.TrafficLayer := true;
// styles also
map.Google.Styles := '[{"featureType": "all","stylers": [{ "color": "#C0C0C0" }]'+
'},{"featureType": "road.arterial", "elementType": "geometry",'+
'"stylers": [ { "color": "#CCFFFF" } ]},{'+
'"featureType": "landscape","elementType": "labels", "stylers": [{ "visibility": "off" }'+
']}]';

Fig. 2 roadmap

Fig. 3 terrain

Fig. 4 satellite

Fig. 5 Demo Google Map

Bing

By filling in the BingKey property with your Bing key you can use Bing Maps tiles ( tsBingRoad, tsBingAerial and tsBingAerialLabels )


map.BingKey := YOUR_BING_KEY
map.TileServer := tsBingRoad;


Fig. 6 Bing Maps

Here

By filling the HereApiKey propertie You can use the Here tiles


map.TileServer := tsHere;
map.HereApiKey := := 'your_api_key' ;
// select style
map.TileServerInfo.MapStyle := 'explore.day';
map.TileServerInfo.MapStyle := 'lite.day';
map.TileServerInfo.MapStyle := 'explore.night';
map.TileServerInfo.MapStyle := 'satellite.day';
map.TileServerInfo.MapStyle := 'explore.satellite.day';

Fig. 7 Here style explore.day

MapBox

To use the tiles from MapBox ( tsMapBoxSatellite, tsMapBoxStreets,tsMapBoxStreetsSatellite,tsMapBoxStreetsBasic ) enter your token in MapBoxToken.

You must also specify a tile size of 512

1
// use your token
map.MapBoxToken := 'pk.xxx';

// The mapbox raster tiles are now 512 x 512 so you need to specify a tile size of 512

map.TileSize := 512;
map.TileServer := tsMapBoxStreets;

// To access all available raster tile styles use the tsMapBoxStreetsBasic server and specify a style

map.TileSize := 512;
map.TileServer := tsMapBoxStreetsBasic;
map.TileServerInfo.MapStyle := 'navigation-day-v1';
map.TileServerInfo.MapStyle := 'navigation-night-v1';
map.TileServerInfo.MapStyle := 'light-v10';
map.TileServerInfo.MapStyle := 'dark-v10';

Fig. 8 MapBoxStreets

TomTom

To use TomTom tiles ( tsTomTomBasic, tsTomTomHybrid, tsTomTomNight, tsTomTomIncident, tsTomTomFlow ) you must obtain a key and fill in the TomTomKey property of your map.

map.TomTomKey := your_tomtom_key
map.TileServer := tsTomTomBasic;

Fig. 9 TomTom Basic

map.TileServer := tsHereSatellite;

// add overlay tiles for TomTom Hybrid
map.AddOverlayTileServer(tsTomTomHybrid);

// mandatory, reset api key for overlay
map.TomTomKey := Your_TomTomKey;

Fig. 10 Here Satellite + TomTom Hybrid

For tsTomTomIncident and tsTomTomFlow you have the choice between 4 styles

var oc:TECOverlayTileLayer;
...
// add overlay tiles for incident
oc := map.AddOverlayTileServer(tsTomTomIncident);

oc.MapStyle := 's1'; // default style
oc.MapStyle := 's2';
oc.MapStyle := 's3';
oc.MapStyle := 'night';

// mandatory, reset api key for overlay
// use your key !
map.TomTomKey := map.TomTomKey;

oc := map.AddOverlayTileServer(tsTomTomflow);

oc.MapStyle := 'absolute'; // default style
oc.MapStyle := 'relative';
oc.MapStyle := 'relative-delay';
oc.MapStyle := 'reduced-sensitivity';

// mandatory, reset api key for overlay
// use your key !
map.TomTomKey := map.TomTomKey;

PTV Group

You must obtain your api key to use these maps.

You can use PTV tiles as a base map or as an overlay on top of any background map..

Fig. 11 PTV demo

property ApiKey: string

Your api key

property BaseMapLayer: TPTVBaseMapLayer

Choice of base map type (none, amber, blackmarble, classic, gravelpit, sandbox,silica, silkysand, satellite)

none to switch back to a TileServer-managed base map other than PTV

2

property ForegroundLayers: TPTVForegroundLayers

You can combine several layers on your PTV base map, as follows [background, transport, labels, trafficIncidents,trafficPatterns, restrictions, toll]

If you do not include background the base map will not be displayed.

3

If you use the satellite background map, you must use OverlayLayers to embed PTV layers.

2

property OverlayLayers: TPTVForegroundLayers

Use this property to overlay one or more PTV layers on a non-PTV map background, as desired. [transport, labels, trafficIncidents,trafficPatterns, restrictions, toll]

property PTV_COPYRIGHT: string

The copyright displayed with the PTV base map

property VehicleType: TPTVvehicleType

Allows you to choose specific maps for car or truck.
procedure TPTVForm.FormCreate(Sender: TObject);
begin
// see https://developer.myptv.com/en/documentation
Map.PTV.ApiKey := 'your api key';
end;
// select PTV base map
procedure TPTVForm.basemaplayerChange(Sender: TObject);
begin
case basemaplayer.ItemIndex of
0: Map.PTV.basemaplayer := TPTVBaseMapLayer.sandbox;
1: Map.PTV.basemaplayer := TPTVBaseMapLayer.classic;
2: Map.PTV.basemaplayer := TPTVBaseMapLayer.silkysand;
3: Map.PTV.basemaplayer := TPTVBaseMapLayer.amber;
4: Map.PTV.basemaplayer := TPTVBaseMapLayer.blackmarble;
5: Map.PTV.basemaplayer := TPTVBaseMapLayer.gravelpit;
6: Map.PTV.basemaplayer := TPTVBaseMapLayer.silica;
7: Map.PTV.basemaplayer := TPTVBaseMapLayer.satellite;
// cancel PTV base map
8: Map.PTV.basemaplayer := TPTVBaseMapLayer.none;
end;
end;

// add PTV layers on PTV base map
procedure TPTVForm.LabelsClick(Sender: TObject);
var
fl: TPTVForegroundLayers;
begin
fl := [];

if Labels.Checked then
fl := fl + [TPTVForegroundLayer.Labels];

if Background.Checked then
fl := fl + [TPTVForegroundLayer.Background];

if Transport.Checked then
fl := fl + [TPTVForegroundLayer.Transport];

if Trafficincidents.Checked then
fl := fl + [TPTVForegroundLayer.Trafficincidents];

if TrafficPatterns.Checked then
fl := fl + [TPTVForegroundLayer.TrafficPatterns];

if Restrictions.Checked then
fl := fl + [TPTVForegroundLayer.Restrictions];

if Toll.Checked then
fl := fl + [TPTVForegroundLayer.Toll];

Map.PTV.ForegroundLayers := fl;

end;

// add PTV layer on a non-PTV map base
procedure TPTVForm.OLabelsClick(Sender: TObject);
var
fl: TPTVForegroundLayers;
begin
fl := [];

if OLabels.Checked then
fl := fl + [TPTVForegroundLayer.Labels];

if OTransport.Checked then
fl := fl + [TPTVForegroundLayer.Transport];

if OTrafficIncidents.Checked then
fl := fl + [TPTVForegroundLayer.Trafficincidents];

if OTrafficPatterns.Checked then
fl := fl + [TPTVForegroundLayer.TrafficPatterns];

if ORestrictions.Checked then
fl := fl + [TPTVForegroundLayer.Restrictions];

if OToll.Checked then
fl := fl + [TPTVForegroundLayer.Toll];

Map.PTV.OverlayLayers := fl;
end;

You can display your map background in grayscale with map.Grayscale := true

1

List of predefined servers

tsOpenMapQuest, tsOpenMapQuestSat, tsCloudMade, tsOSM, tsOpenCycleMap, tsOPNV, tsArcGisWorldTopoMap, tsArcGisWorldStreetMap, tsArcGisWorldImagery, tsBingRoad, tsBingAerial, tsBingAerialLabels, tsOwnerDraw, tsCustom, tsHere, tsMapBoxSatellite, tsMapBoxStreets,tsMapBoxStreetsSatellite, tsMapBoxStreetsBasic, tsMapBoxOutdoors, tsYandexNormal, tsYandexSatellite, tsYandexHybrid, tsYandexPeople, tsDigitalGlobeRecent, tsDigitalGlobeTerrain, tsOsmFr, tsOpenTopoMap, tsMapillary, tsTomTomBasic, tsTomTomHybrid, tsTomTomNight, tsTomTomIncident, tsTomTomFlow, tsHyddaFull, tsOsmDe, tsTopPlusWebOpen, tsTopPlusWebOpenGrey, tsbingCanvasGray, tsbingCanvasDark, tsbingCanvasLight, tsBaseOpenSnowMap, tsPisteOpenSnowMap, tsHotOsm, tsIgn, tsCyclOSM, tsTomTomSat, tsOpenRailWayMap, tsGoogle

If you try to download tiles from the internet and there is no connection, the OnErrorConnection event in your map is triggered.


OnlyLocal is then set to true to prevent any connection attempt, when the connection comes back you will have to set OnlyLocal back to false, this will not be done automatically.

1

WMS tile server

You can use a WMS service to display your tiles.

// base map
map.TileServerWMS('https://ows.mundialis.de/services/service', 'TOPO-WMS');
// You can select a date in iso-8601 format
map.WMS_Time := '2023-10-19T09:00:00.000Z';
// show legend, Top Center, 85% opacity
map.WMS_Legend(true,lpTopCenter,85);

// overlay
var o : TECOverlayTileLayer;
o := map.AddOverlayTileServerWMS('https://ows.mundialis.de/services/service', 'OSM-Overlay-WMS');
// You can select a date in iso-8601 format
o.WMS_Time := '2023-10-19T09:00:00.000Z';
// show legend, Top Center, 85% opacity , Xmargin 4 , ymargin 4
o.WMS_Legend(true,lpTopCenter,85,4,4);

Use your own tile server

In addition to the previous maps you can use any other provider using the same format.

procedure TForm.FormCreate(Sender: TObject);
begin
Map.LocalCache := ExtractFilePath(application.exename) + 'cache';
Map.MaxZoom := 21;
// provider of custom tiles
Map.TileServerInfo.Name := 'OSM';
Map.TileServerInfo.GetTileFilename := GetOSMTile;
end;


procedure TForm.GetOSMTile(var TileFilename:string;const x,y,z:integer);
begin
TileFilename := 'https://tile.openstreetmap.org/' + inttostr(z) + '/' + inttostr(x) + '/' +
inttostr(y) + '.png' ;
end;


ColorFilter

This property allows you to modify/change certain colors of your tiles.

// shade of gray
map.ColorFilter.filter := fcGrey;
// color inversion
map.ColorFilter.filter := fcInvert;
// sepia color
map.ColorFilter.filter := fcSepia;
// use this non-filter to change only the light or dark setting
map.ColorFilter.filter := fcCustom;
// normal color
map.ColorFilter.filter := fcNone;
// Lightening and darkening are controlled by LightValue and DarkValue
// higher value is applied if filter <> fcNone and xValue>0

// change only the darkening
map.ColorFilter.filter := fcCustom;
map.ColorFilter.DarkValue := 64;
map.ColorFilter.LightValue := 0;

// invert color and change the Lightening
map.ColorFilter.filter := fcInvert;
map.ColorFilter.LightValue := 40;
map.ColorFilter.DarkValue := 0;

// You can also use the Dark and Light modes,
// which are shortcuts to Filter + LightValue.
map.Dark := true;
map.Light:= true;

Fig. 12 Filter fcInvert

With Firemonkey you can also define certain colors that will be kept or that you can replace without them being modified by the filter.

var c:TAlphaColor;
...
TAlphaColorRec(c).R := 247;
TAlphaColorRec(c).G := 250;
TAlphaColorRec(c).B := 191;
// 100% opacity
TAlphaColorRec(c).A := 255;

map.ColorFilter.Colors.Add(c);
map.ColorFilter.ActionColor := acKeep;
...
map.ColorFilter.Colors.Add(Old_color_1);
map.ColorFilter.Colors.Add(New_color_1);
map.ColorFilter.Colors.Add(Old_color_2);
map.ColorFilter.Colors.Add(New_color_2);
map.ColorFilter.Colors.ActionColor := acReplace;


// by default a tolerance of 1% is applied to the colors to keep or replace, you can pass to 10% in this way

map.ColorFilter.Tolerance := 0.1;

Fig. 13 Grey mode with one color kept.

Fig. 14 Gray mode with one color replacement

Fig. 15 Dark mode with color replacement

Overlay tiles

You can use several server of tiles to display above your base map.


var overlay:TECOverlayTileLayer;
...
// overlay clouds tiles
overlay := map.AddOverlayTiles(GetWeatherTile);
// set name for directory
overlay.Name := 'OpenWeatherMap_Clouds';
// you can also use this syntax
overlay := map.AddOverlayTiles(GetWeatherTile,'OpenWeatherMap_Clouds');

// remove overlay
map.RemoveOverlayTiles(overlay);

...

procedure TForm.GetWeatherTile(var TileFilename:string;const x,y,z:integer);
begin
TileFilename := format('http://%s.tile.openweathermap.org/map/clouds/%d/%d/%d.png',[Char(Ord( 'a') + random(3)),z,x,y]);
end;


Fig. 16 Overlay of clouds

You can still use a stream.

procedure TForm.getOverlayTileStream(var TileStream: TMemoryStream;const x, y, z: integer);
begin
// here fill the stream with your tile

end;

...
map.AddOverlayStreamTiles(getOverlayTileStream);

Or directly using a transparent predefined server as tsHereFlow or tsHereTruckTransparent

// mix Bing Aerial Labels and Here Flow
map.TileServer := tsBingAerialLabels;
map.AddOverlayTileServer(tsHereFlow);

As another example, use the services of OpenRailWayMap to display railroad facilities.

var o : TECOverlayTileLayer;
// standard style
o := map.AddOverlayTileServer(tsOpenRailWayMap);
// other styles
o.MapStyle := 'maxspeed';
o.MapStyle := 'signals';
o.MapStyle := 'electrification';
o.MapStyle := 'gauge';

Fig. 17 OpenRailWayMap standard style

With VCL your overlay should use pngs, under FMX you can use the opacity property.

4


var overlay:TECOverlayTileLayer;
...
// overlay clouds tiles
overlay := map.AddOverlayTiles(GetWeatherTile);

// set opacity 0..1
overlay.opacity := 0.5;

Use RemoveAllOverlayTiles to delete all overlays

You can also embed an image if it is to scale

2

Positioning on the map

You can determine the coordinates of the center of the map through the Latitude and Longitude properties, they are of type double and accessible in read/write

You can directly modify the coordinates through the procedure setCenter(const dlatitude,dlongitude:double)

PanTo(lat,lng) is equivalent but a scroll will be performed if the displacement is minimal otherwise we go directly to the new position as setCenter

Utilisez Move(direction,DistanceKM) to move in a direction varying from 0 to 359° and over a distance in KM

// Delphi map component ECNativeMap
var lat,lng:double;
begin
// get center of map
lat := map.Latitude;
lng := map.Longitude;
// move center of map
map.setCenter(lat+0.001,lng);
//
map.PanTo(lat+0.001,lng);

// move to south on 10.5km
map.Move(180,10.5);

end;

Mouse position

The latitude and longitude of the point under the mouse cursor are returned by the property MouseLatLng

You can connect on the event OnMapMouseMove to know in time real your position

Graticule

Displays a grid showing latitudes and longitudes.

Fig. 18 Graticule

map.Graticule.Visible := true;
map.Graticule.LineStyle := psDashDot; // psSolid, psDot, psDash
map.Graticule.LineColor := claBlack;
map.Graticule.LineSize := 1;
// default guDegrees;
// also guQTHLocator, guUTM and guLOC
map.Graticule.LabelUnit := guDecimalDegrees;
map.Graticule.LabelColor := claBlack;
map.Graticule.LabelFont.Style := [TFontStyle.fsBold];
map.Graticule.LabelPositions := [gpTop,gpRight,gpBottom,gpLeft];
// only firemonkey
map.Graticule.Opacity := 50; // 0..100

Reacting to the change in position

When the center of the map is moved, This either by code or the mouse directly, the event OnMapMove(sender: Tobject;const dLatitude,dLongitude:double) is raised

Sender represents the ECNativeMap component that has changed, dLatitude and dLongitude the new coordinates, who are also accessible through Latitude and Longitude

When the map starts to move the event OnMapDragStart is raised, then OnMapDrag while the move and OnMapDragEnd at the end of displacement.

Area displayed

You can determine the coordinates of North East point (top-right) and point South West (lower-left) of the displayed area by the component through the properties NorthEastLatitude, NorthEastLongitude, SouthWestLatitude and SouthWestLongitude, they are double and accessible read-only.

The procedure BoundingBox(maxLatitude,maxLongitude,minLatitude,minLatitude) limit the accessible area of your map, the event OnOutOfBounds is raised if you attempt to access a restricted area.

A call to BoundinBox without parameter throws limitations.

5

The procedure fitBounds(const dLatlo,dLnglo,dLathi,dLnghi:double) allows you to adjust the view to the coordinates passed.

You can also pass it an array containing groups and thus get a view on all elements.

6
map.fitBounds([map['G1'],map['G2']]);

the procedure boundingCoordinates(const lat, lng, radius: double; var latSW, lngSW,latNE, lngNE: double); Returns the coordinates of a rectangular area on the basis of the focal point and a distance in km.

The function ContainsLatLng(var dLatitude,dLongitude:double):boolean tells you if the dLatitude, dLongitude is in the visible portion of the map.

As soon as the view changes the event OnChangeMapBounds(sender: TObject) is raised.

The function ScreenShot Returns an integer containing the image of the map

Zoom

The Zoom property allows you to control the definition of your card, it is of type integer and is accessible in read/write

You have access also to the MaxZoom and property MinZoom that allow you to determine the limits of the zoom

7

Use the ZoomAround(const LatLngZoom:TLatLng; const NewZoom:Integer) procedure to zoom while remaining focused on a specific point (as in mouse)

The zoom change triggers the event OnChangeMapZoom(sender: TObject)

By setting the DragRect property on drZoom you can select an area with the mouse by holding the right button, when you release the button zoom is performed on the selected region.

ZoomScaleFactor

This property allows you to emulate the intermediate zooms

const Data_Uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg=='
;

map.Shapes.Markers[0].filename := Data_Uri;

Make right Click + scroll wheel to change ZoomScaleFactor

3

Fig. 19 ZoomScaleFactor

You can zoom in progressively from zoom 1 to beyond the maximum zoom provided by the tile server, simply by incrementing zoomScaleFactor, and vice versa to zoom out.

Fig. 20 Progressive zoom

ZoomScaleFactor can vary from -999 to 999, if the maximum zoom is not reached 100 corresponds to zoom+1 (and conversely)

8

Use the procedure ZoomScaleFactorAround (const LatLngZoom:TLatLng; const NewZoomScaleFactor:Integer) to zoom while remaining focused on a specific point (as with mouse)

The NumericalZoom property groups Zoom and ZoomScaleFactor

4
map.NumericalZoom := 15.6;

Keyboard map management

TECNativeMap has OnKeyUp and OnKeyDown events

Example of code to manage movement and zoom with the arrow keys, + and -.

procedure TForm.mapKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var kUp,kDown,kLeft,kRight,kCtrl : boolean;
PixelShift : integer;
begin
// KeyIsDown in uecMapUtil unit
kDown := KeyIsDown(VK_DOWN);
kLeft := KeyIsDown(VK_LEFT);
kUp := KeyIsDown(VK_UP);
kRight := KeyIsDown(VK_RIGHT);
kCtrl := KeyIsDown(VK_LCONTROL) or KeyIsDown(VK_RCONTROL);
// 40 pixels displacement
PixelShift := 40;

if kDown then
begin
if kLeft then
map.ScrollXY(PixelShift,-PixelShift)
else
if kRight then
map.ScrollXY(-PixelShift,-PixelShift)
else
map.ScrollXY(0,-PixelShift)
end
else
if kUp then
begin
if kLeft then
map.ScrollXY(PixelShift,PixelShift)
else
if kRight then
map.ScrollXY(-PixelShift,PixelShift)
else
map.ScrollXY(0,PixelShift)
end
else
if kRight then
map.ScrollXY(-PixelShift,0)
else
if kLeft then
map.ScrollXY(PixelShift,0);

// To make a move in Km you can use Move(direction,km)
// direction 0 to 359
// map.Move(90,0.1); move right 100 meters

// if CTRL we zoom in 1/10 of level
if KeyIsDown(VK_ADD) then
begin
if kCtrl then
map.ZoomScaleFactor := map.ZoomScaleFactor + 10
else
map.Zoom := map.Zoom + 1;
end
else
if KeyIsDown(VK_SUBTRACT) then
begin
if kCtrl then
map.ZoomScaleFactor := map.ZoomScaleFactor - 10
else
map.Zoom := map.Zoom - 1;
end;


end;

Adapt the markers to the Zoom

Use the ScaleMarkerToZoom property to resize markers depending of Zoom.

Fig. 21 ScaleMarkerToZoom

Selection

The Selected property allows you to select items.

// select items in area
nbr_item_selected := map.Selected.ByArea(NorthEastLat,NorthEastLng,SouthWestLat,SouthWestLng);

// select items <=Max_Distance_KM to CenterPointLat,CenterPointLng
nbr_item_selected := map.Selected.ByKMDistance(CenterPointLat,CenterPointLng,Max_Distance_KM);

// loop to all selected items

var shape:TECShape

for shape in map.Selected do
begin
..
end;

By setting DragRect to drSelect you can make a selection with the mouse by holding the right button and release once the area is delimited.

You can redefine the appearance of the selection rectangle using styles, example to have a line of 10 pixels width, green color, and a dotted line

map.styles.addRule('#_DRAGZOOM_.line {weight:10;color:green;penStyle:dash}');

Fig. 22 stylized selection

You can also use the freehand selection tool to simply surround your elements.

5

To deselect all your items use map.Selected.UnSelectedAll

The GroupFilter list allows to define a filter on the groups allowed

// only elements from these groups will be accepted
map.Selected.groupFilter.add('group1');
map.Selected.groupFilter.add('group2');
// clear list for accept all
map.Selected.groupFilter.clear;

You can define your own filter by connecting you on OnSelectShape.

map.Selected.OnSelectShape := doOnSelectShape;
...
procedure TForm.doOnSelectShape(Sender: TObject; const Shape: TECShape;
var cancel: Boolean);
begin

// accept only TECShapePOI
cancel := not(Shape is TECShapePOI);
end;

You can select / deselect any element by code through its selected property

// unselect
map.shapes.markers[0].selected := false;
// select
map['groupx'].pois[0].selected := true;

To move all selected elements at once with the mouse, assign sdmMultiShapes to your map's ShapeDragMode property.

6
// move all seleted shapes
map.ShapeDragMode := sdmMultiShapes;
// move only the element under the mouse (default)
map.ShapeDragMode := sdmShape;

Fig. 23 Move selected items

Selected items are drawn using the color HoverColor, you can add a distinguishing mark by connecting you on their OnAfterDraw event.

This example adds a red star in the upper right corner of selected items

// when you create item you must connect like this item.OnAfterDraw := doAfterDraw

procedure TForm1.doAfterDraw(const canvas: TECCanvas; var rect: TRect; item: TECShape) ;
var size_start : integer;
begin
if assigned(item) and (item.Selected) then
begin
size_start := (item.Width div 2);
if size_start< 10 then size_start := 10;

canvas.Pen.Color := claBlack;
canvas.PenWidth(1);
canvas.Brush.Color := GetHighlightColorBy(claRed,16);

rect.Left := rect.Left + (rect.Right-rect.Left) - size_start;
rect.Top := rect.Top - (size_start div 2);
rect.Bottom := rect.Top + size_start ;

canvas.DrawStar(rect);
end;
end;

Fig. 24 3 selected items

Or simply you can set a style.

// all shapes selected is red
map.styles.addRule(':selected {color:red}');
// enlarge the selected markers
map.styles.addRule('.marker:selected {scale:1.2}');

You can save the selection in a file with SaveToFile or in a string with toXXX

// Export of selected elements to geoJSON, GPX, KML and Text formats

map.Selected.SaveToFile('file.json');
map.Selected.SaveToFile('file.gpx');
map.Selected.SaveToFile('file.kml');
map.Selected.SaveToFile('file.txt');

json_string := map.Selected.toGeoJSON;
gpx_string := map.Selected.toGPX;
kml_string := map.Selected.toKML;
txt_string := map.Selected.toTxt;

Map rotation

Available only in the version Firemonkey

2
Put your component into a container (TPanel, TRectangle) which will be used to define the visible region and activate property OverSizeForRotation

map.OverSizeForRotation := true;

// To allow or not the rotation gesture use the property EnableTouchRotation

map.EnableTouchRotation := true;

EnableTouchRotation Enable rotation by gesture.

9

Fig. 25 Rotation map

Url

The Url property returns / accepts a string in the format '#zoom/Latitude/Longitude'


// zoom 18 latitude 48.856527 longitude 2.352104
// welcome to Paris !
map.Url := '#18/48.856527/2.352104';

Assigning a value to this property raises the event OnBeforeUrl(sender : TObject; var Url:string) that can allow you to change the url, and even to cancel the change by returning an empty string.

You can pass a such link in a InfoWindow



// welcome to Paris !
map.Shapes.InfoWindows[0].Content := 'Go to <a href="#18/48.856527/2.352104">Paris !</a>';

Fig. 26 Url Link

If you pass a 'classical' url it will open in your default browser.

1

Distance

The function DistanceFrom(const dLatitudeStart,dLongitudeStart,dLatitudeEnd,dLongitudeEnd:double):double to calculate the distance between 2 points, the result is in kilometers.

Angle to the North

The function Bearing(const dLatitudeStart,dLongitudeStart,dLatitudeEnd,dLongitudeEnd:double):integer gives you the angle, from 0 ° to 360 ° for direction from the point dLatitudeStart,dLongitudeStart to the point dLatitudeEnd,dLongitudeEnd

MiniMap

Fig. 27 MiniMap

To display a mini map in your main card simply add the uecNativeMiniMap unit to your listing and add the following lines.

// Delphi native map component TECNativeMap

var FMiniMap : TECNativeMiniMap;
...
// create and show minimap on Map
FMiniMap := TECNativeMiniMap.create(Map);

// for hide minimap
FMiniMap.Map := nil;

// for show
FMiniMap.Map := Map;





You do not have to release your minimap, It will be automatically during the destruction of the card to which it is attached.

3

You can change the corner of anchor with the property ancragePosition (apTopLeft, apTopRight, apBottomLeft, apBottomRight )

XMargin and YMargin allow you to adjust the position relative to the edges

BorderColor and BorderSize changes the color and size of the border surrounding the mini map.

Screenshot allows you to get an image of your miniMap, you will have to release it yourself!

Scale bar

The ScaleBar property of the map is used to manage the scale bar.

procedure TForm1.FormCreate(Sender: TObject);
begin
map.ScaleBar.Visible := true;
map.ScaleBar.Color := claWhite;
map.ScaleBar.SecondaryColor := claRed;
map.ScaleBar.Style := sbsBar;
map.ScaleBar.Division := sbdFour;
map.ScaleBar.Thickness := 8;
map.scalebar.opacity := 50;
end;


The following properties are available :

To use the AnchorPosition, Style and MeasureSystem properties, you must add the uecMapUtil unit.

4

property AnchorPosition: TAnchorPosition

Bar anchoring (apTopLeft, apTopRight, apBottomLeft, apBottomRight )


property Color: TColor

Main text and bar color


property SecondaryColor: TColor

Secondary bar color, also used for shadows


property Division : TECScaleBarDivision

Number of divisions (sbdNone, sbdOne, sbdFour)


property FontSize : integer

Text size


property MaxWidth: integer

Maximum bar length in pixels (default 80)


property Style : TScaleBarStyle

Line or bar (sbsLine, sbsBar)


property MeasureSystem: TMesureSystem

Measurement system (msMetric, msImperial, msNautical) ( default msMetric )


property Shadow: boolean

Shadow effect, use SecondaryColor


property Thickness : integer

Bar thickness (default 2)


property Visible: boolean

Displays or not the ScaleBar (default false)


property XMargin: integer

Margin from right or left edge of map


property YMargin: integer

Margin from top or bottom edge of map


property Opacity : byte

Bar transparency ( 0..100 )


Fig. 28 Demo Scalebar

Measurement tool

The component's MeasureTool property gives you access to a distance and area measurement tool.

procedure TForm1.FormCreate(Sender: TObject);
begin
map.MeasureTool.Visible := true;
// distance
map.MeasureTool.MeasureArea := false;
// area
map.MeasureTool.MeasureArea := true;
// react to changes in distance or area
map.MeasureTool.OnChange := doChange;
end;

// fired when distance or area change
procedure TFormMeasureTool.doChange(Sender : TObject);
begin
// you can also access the values
// map.MeasureTool.Distance
// map.MeasureTool.Area
if map.MeasureTool.MeasureArea then
begin
lbDistance.Caption := 'Perimeter : '+map.MeasureTool.DistanceText;
lbArea.Caption := 'Area : '+map.MeasureTool.AreaText;
end
else
begin
lbDistance.Caption := 'Distance : '+map.MeasureTool.DistanceText;
lbArea.Caption := '';
end;

end;



Fig. 29 Distance

Fig. 30 Area

Click on the map to add a point, long-press a point to delete it, drag and drop to move your tool.

10

Take a look at the MeasureTool demo to get started.

Observer

An observer allows you to be notified when events is fired in map or in shape.

This has the advantage of not to block the main events of the map and the shapes.


TNativeMapObserver = class(TObject)
public

property OnMapFree : TNotifyEvent ;
property OnMapHiResChange : TNotifyEvent ;
property OnMapActiveChange : TNotifyEvent
property OnMapAnimation : TNotifyEvent;
property OnMapResize : TNotifyEvent;
property OnMapRotation : TNotifyEvent;
property OnMapMove : TNotifyEvent;
property OnMapMouseMove : TNotifyEvent;
property OnMapMouseClick : TNotifyEvent;
property OnMapEndMove : TNotifyEvent;
property OnMapzoom : TNotifyEvent;
property OnMapLoad : TNotifyEvent;
property OnMapBounds : TNotifyEvent;
property OnMapChangeBounds : TNotifyEvent;
property OnMapTileServer : TNotifyEvent;
property OnMapAddRoute : TNotifyEvent;
property OnMapErrorRoute : TNotifyEvent;
property OnMapChangeRoute : TNotifyEvent;
property OnMapPaint : TNotifyEvent;
property OnShapesPaint : TNotifyEvent;
property OnMapShapeDescription : TNotifyEvent;
property OnMapShapeProperties : TNotifyEvent;
property OnMapShapeHint : TNotifyEvent;
property OnMapShapeClick : TNotifyEvent;
property OnMapShapeMove : TNotifyEvent;
property OnMapShapeDblClick : TNotifyEvent;
property OnMapShapeMouseOut : TNotifyEvent;
property OnMapShapeMouseOver : TNotifyEvent;
property OnMapShapeDrag : TNotifyEvent;
property OnMapShapeDragEnd : TNotifyEvent;
property OnMapShapePathChange : TNotifyEvent;
property OnMapShapeRightClick : TNotifyEvent;
property OnMapShapesChange : TNotifyEvent;

You can add as many observers as you want.

FObserver1 := TNativeMapObserver.Create;
FObserver1.OnMapResize := Map_Resize;
FObserver1.OnMapMove := Map_Move;

FObserver2 := TNativeMapObserver.Create;
FObserver2.OnMapBounds := Map_Bounds;
FObserver2.OnMapTileServer := Map_TileServer;
FObserver2.OnMapRotation := Map_Rotate;

// attach observer
map.attach(FObserver1);
map.attach(FObserver2);
...
// detach
map.detach(FObserver1);
map.detach(FObserver2);
...
FObserver1.free;
FObserver2.free;

The layers using observers to react to the change of position.

go to page
Réalisé avec la version gratuite pour les particuliers d'Help&Web