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

Shapes

you are here :TECNativeMap

To use the shapes you need to add the unit uecNativeShape

All the elements positioned on the map are accessible through the property Shapes type TECShapes or another group through map['group_name'], they descend all the class TECShape

You can store in your elements (marker, poi, line or polygon) the textual data you want through the PropertyValue property, its values will be able to be associated to a style

var M:TECShapeMarker;
...
M := Map.addMarker(map.latitude,map.Longitude);
M.PropertyValue['my_tag']:='value_tag';
// you can also use
M['my_tag']:='value_tag';
// groups can also have them
map.shapes['tag']:='value';
map['group']['tag']:='value';

when you add several items, use BeginUpdate / EndUpdate, otherwise the map is redrawn after each addition.

1

// for optimisation
map.shapes.BeginUpdate;

map.Shapes.Markers.add(lat1,lng1);
map.shapes.Markers.add(lat2,lng2);
...
map.shapes.EndUpdate;

var G:TECShapes;
...
G := map['group_name'];
G.BeginUpdate;

G.Markers.add(lat1,lng1);
G.Markers.add(lat2,lng2);
...
G.EndUpdate;

Styles

Instead of manually decorate each element you can define rules to apply a style

Groups ( TECShapes )

A group maintains a set of elements, the Shapes property is the default group, you go to a group by the Group ['name'] property

You can access groups with the syntax map['name'] instead of map.Group['name']

2

You can also be accessed by an index through the property Groups

1

var my_group:TECShapes;
// for optimisation
my_group := map.Group['group1'];
my_group.BeginUpdate;

my_group.Markers.add(lat1,lng1);
my_group.Markers.add(lat2,lng2);
...
my_group.EndUpdate;

property CSV: TecCSV
Manager for loading csv files
procedure Clear
empty group
procedure BeginUpdate
blocks the drawing of the map, ensures best performance
procedure EndUpdate
Authorizes a repaint of the map
procedure fitBounds
Displays the map so that all the elements of the group are visible in the best zoom

Pois, markers, lines and polygons properties also have a fitBounds procedure

2
procedure SaveToFile(const Filename: string)
Saves the group to a file, the format is determined by the extension .gpx, .kml or own to TECNativeMap text format
function LoadFromFile(const Filename: string): boolean
Charge the group with the contents of a file, the format is determined by the extension .osm, .olt, .gpx, .kml, .csv or own to TECNativeMap text format

The OnLoad event is raised when the content is fully available

3
function LoadFromOSMStream(const Stream: TStream): boolean;

Charge the group with a stream that contains data in the OSM XML format or olt

function LoadFromOSMString(const data: string): boolean;

Charge the group with a string containing data at the OSM XML format or olt

property Hint : string

String that is displayed as a tooltip for elements with empty Hint

// you can inject the element's properties using the syntax
map['groupx'].Hint := 'value of [prop1] - value of [prop2]';
property HintColor : TColor
Defines a specific background color for the group's tooltips
property Clusterable : boolean

Active support of Clusters, This allows you to group markers and pois who are near for better visibility

Fig. 1 Clustering

property ClusterManager : TECClusterManager
property Pois: TECShapePOIList
List of elements of type TECShapePOI
property Markers: TECShapeMarkerList
List of elements of type TECShapeMarker
property Lines: TECShapeLineList
List of elements of type TECShapeLine
property Polygones: TECShapePolygoneList
List of elements of type TECShapePolygone
Liste des éléments de type TECShapePolygone
property InfoWindows: TECShapeInfoWindowList
Liste des éléments de type TECShapeInfoWindow

The lists have an iterator as groups

3

// Iterator for all list of shapes (markers, pois, lines, polygones and infowindows )

var poly : TECShapePolygone;

for poly in map.shapes.polygones do
begin
poly.color := clRed;
end;

You also have shortcuts to create your elements

4

function addMarker(const Lat, Lng: double) : TECShapeMarker;

function AddPOI(const Lat, Lng: double) : TECShapePOI;

function AddLine: TECShapeLine;

function AddEncodedLine(const EncodedLine: string; const precision: byte = 5): TECShapeLine;

function AddLine(const dLatLngs: array of double): TECShapeLine;

function AddLine(const dLine: TECShapeLine) : TECShapeLine;

function AddPolygone : TECShapePolygone;

function AddPolygone(const dLine: TECShapeLine): TECShapePolygone;

function AddEncodedPolygone(const EncodedLine: string; const precision: byte = 5): TECShapePolygone;

function AddPolygone(const dLatLngs: array of double): TECShapePolygone;

var my_maker : TECShapeMarker;
my_line : TECShapeLine;
my_poly : TECShapePolygone;
my_group : TECShapes;
...

my_group := map['my_group'];
my_marker := my_group.addMarker(lat,lng);
my_line := my_group.addLine([lat1,lng1,...,latx,lngx]);
my_poly := my_group.addPolygone(my_line);

property MaxZoom: byte

Maximum zoom level for which the items are displayed, above the group is not displayed
property MinZoom: byte
Minimum zoom level for which the items are displayed below the group does not appear
property Opacity : byte;
Defines an opacity (opacity and FillOpacity) for all the elements of the group.
The opacity varies from 0 to 100, a value >100 indicates that the opacity of the group is not taken into account, only that of the elements is used.

In the case of a value > 100, the original opacity of the elements is not restored

1
property Zindex : integer
Groups are displayed in ascending their ZIndex
function TopZindex : longint;
Returns the highest ZIndex of all the elements in the Group

TECNativeMap.TopGroupZindex Returns the highest ZIndex of all groups

4
property Clickable : boolean
Indicates whether all the elements meet the click of the mouse

The elements also have a clickable property

5
property Serialize : boolean
Indicates whether the Group should be saved when you save the entire map

Does not apply if we directly backup group

6


map.Group['group1'].Serialize := true;
map.Group['group2'].Serialize := false;

map.SaveToFile(filename); // group2 not save

property Visible: boolean
Display/Hide group
property Show: boolean
Show/Hide group but unlike visible items remain accessible to the mouse

Lists of elements (Markers, Pois, Lines, Polygons) also have a Show property that you can activate/deactivate individually.

7

Fig. 2 TECShapes.Show

property ShowHint: boolean
Allows the display of the property Hint of the elements in the form of a bubble when hovering the mouse over
property Selected : boolean
Select / Unselect all the elements of the group
Returns true if at least one of the elements of the group is selected.

Lists of items also have a Selected property

8
// selects all markers of test group
map['test'].markers.Selected := true;
// selects all pois of test group
map['test'].pois.Selected := true;
// selects all lines of test group
map['test'].lines.Selected := true;
// selects all polygones of test group
map['test'].polygones.Selected := true;

property Name: string

name of the group read-only
property ToTxt: string;
Import/Export in native format
property ToGpx: string;
Import/Export to Gpx format
property ToKml: string;
Import/Export to KML

Markers and Pois HeatMap

Marker and Pois lists have HeatMap properties to manage a heat map.

// Optimization: no map refresh during additions
map.BeginUpdate;
// new group
G := map['GroupTest'];
G.markers.heatmap.MaxZoom := 15;
(*
Above MaxZoom markers are displayed,
below MaxZoom the HeatMap is displayed.

When HeatMap is displayed, elements continue to react
to the mouse (Hint, Click...) even if they are not visible.
*
)

// You can modify the palette
// G.markers.heatmap.Palette.Clear;
// G.markers.heatmap.Palette.addColor(Red,Green,Blue,Value)

// Radius of HeatMap points
G.markers.heatmap.Radius := 10;

dy := (map.NorthEastLatitude - map.SouthWestLatitude) / 2;
dx := (map.NorthEastLongitude - map.SouthWestlongitude) / 2;

// add 10000 markers
for y := 0 to 9999 do
begin
Lat := map.latitude - dy + (random(round(dy*2 * 1000)) / 1000);
Lng := map.longitude - dx + (random(round(dx*2 * 1000)) / 1000);
M := G.Markers.AddMarker(Lat,Lng);
// the 'weight' of each element is defined and used to create the HeatMap
weight := random(1000);
M['weight'] := inttostr(weight);
M.Hint := 'marker '+inttostr(y)+' : weight '+inttostr(weight);
end;
(*
HeatMap generation,
the 'Weight' property of the elements is used to calculate the HeatMap
If you leave empty they will all weigh 1
*
)
G.markers.heatmap.update('weight');
G.markers.heatmap.visible := true;
// Optimization: map refresh restored
map.EndUpdate;

Fig. 3 Demo Markers HeatMap

CSV

The CSV file manager is accessible through the CSV property groups

function LoadFromFile(const filename: string):boolean;
Loads the data from the CSV file into the group and returns true if it is ok.
function LoadFromStream(const stream: TStream):boolean;
Loads the CSV stream data into the group and returns true if it is ok.
function ASyncLoadFromFile(const filename: string):boolean;
Loads the data from the CSV file into the group asynchronously (in a thread) and returns true if it is ok.
function ASyncLoadFromStream(const stream: TStream):boolean;
Loads the data from the CSV stream into the group asynchronously (in a thread) and returns true if it is ok.

When the data is loaded the OnLoad event of the map is triggered

9

procedure SaveToFile(const filename: string;const ShapeList:TECShapeList);

Saves the list of elements (markers or Pois) in a csv file

Use the Fields list to select the PropertyValue to save.
Fields contains the fields from the last loaded CSV file so if necessary empty it before filling it with your selection.
No need to add fields for Latitude and Longitude, FieldNameLatitude and FieldNameLongitude will be used
map.Shapes.CSV.Fields.clear;
map.Shapes.CSV.Fields.add('street');
map.Shapes.CSV.Fields.add('zip');
map.Shapes.CSV.SaveToFile(filename,map.shapes.Markers);

property FieldNameWKT: string;

Allows you to import or export CSV files containing the geometry of elements in WKT format, essential for lines and polygons.
//save group in csv format
// save the geometry of elements in WKT format, essential for lines and polygons.
// for this you must fill in the field FieldNameWKT

map.shapes.csv.FieldNameWKT := 'WKT';
map['group'].csv.FieldNameWKT := 'WKT';

map.shapes.savetofile('filename.csv');
map['group'].savetofile('filename.csv');

property FieldNameLatitude: string;

Name of the field that contains the latitude, by default "latitude".
property FieldNameLongitude: string;
Name of the field that contains the longitude, by default "longitude".

If the geographic position is grouped in a single field, specify it in FieldNameLatitude, leave FieldNameLongitude blank, use DelimiterLatLng to define the separator between latitude and longitude.

5
map.Shapes.CSV.FieldNameLatitude := 'centroide';
map.Shapes.CSV.FieldNameLongitude := '';
map.Shapes.CSV.DelimiterLatLng := ',';

property idxLatitude: integer

if the first line of the csv file does not contain the field names, you will have to indicate the index of the latitude field
property idxLongitude: integer
if the first line of the csv file does not contain the field names, you will have to indicate the index of the longitude field
// if the first line of the csv file does not indicate the names of the fields,
// you can indicate directly the index of the fields containing the latitude and longitude
// You must also empty FieldNameLatitude and FieldNameLongitude

map.Shapes.CSV.FieldNameLatitude := '';
map.Shapes.CSV.FieldNameLongitude := '';
map.Shapes.CSV.idxLatitude := 10;
map.Shapes.CSV.idxLongitude := 11;

property Delimiter : char

Field delimiter, default ","
property OnFilterCSV : TOnFilterCSV
Allows you to reject a line in the CSV file based on specific criteria
// filter csv data
map.shapes.CSV.OnFilterCSV := doOnFilterCSV;
...
// valid csv data , default true
procedure TForm.doOnFilterCSV(const Data: TStringList;var validCSV:boolean);
begin
if (data.Count>2) and (pos('POLYGON',data[7])< 1) then
validCSV := (data[2]<>'relation');
end;

property OnCreateCSVPoint: TOnCreateCSVPoint

By default the elements are imported as Markers of siFlat style
By connecting to this event you will be able to define yourself the type of Marker or Poi element and its various characteristics.
// take over the creation of the points
map.shapes.CSV.OnCreateCSVPoint := doOnCreateCSVPoint;
...

// Manual creation of each point
// Data contains the CSV values for the point
procedure TForm.doOnCreateCSVPoint(const Group: TECShapes; var CSVPoint: TECShape; const Lat, Lng: double; const Data:TStringList) ;
var M:TECShapeMarker;
begin

// create new marker
M := Group.addMarker(lat,lng);;
CSVPoint := M ;

// marker design
M.Width := 12;
M.StyleIcon := siFlat;

// we calculate its color according to its index number
M.Color := GetHashColor(inttostr(M.IndexOf));

end;

property OnCreateWKTObject : TOnCreateWKTObject

By connecting to this event you will be able to modify the properties of the imported elements in WKT format
// react after creation wkt object
map.shapes.CSV.OnCreateWKTObject := doOnCreateWKTObject;
map['group'].CSV.OnCreateWKTObject := doOnCreateWKTObject;

// fired after creation wkt object
procedure TForm.doOnCreateWKTObject(const Group: TECShapes;
const WKTObject: TECShape; const Lat, Lng: double; const Data: TStringList);
begin
// we calculate its color according to its index number

if WKTObject is TECShapePolygone then
TECShapePolygone(WKTObject).FillColor := GetHashColor(inttostr(WKTObject.IndexOf))
else
WKTObject.Color := GetHashColor(inttostr(WKTObject.IndexOf));
end;

The geometry must be expressed in decimal degrees, if needed you can connect to OnConvertLatLng to define a conversion procedure

1
// The expected coordinates are in decimal degrees
// you can connect to OnConvertLatLng to convert

// sample
procedure ConvertLatLng(var lat,lng:double);
begin
Lat := Lat / 1000000;
Lng := Lng / 1000000;
end;

procedure TForm.FormCreate(Sender: TObject);
begin
map.shapes.CSV.OnConvertLatLng := ConvertLatLng;
end;

The other fields of the CSV file are imported into the elements through their property PropertyValue[field_name] := field_value
If the CSV file does not name its fields, they will be named by concatenating the file name without the extension + the field index

Fig. 4 DemoCSV

Labels

The Polygones, Markers and Pois lists allow you to associate labels to their elements, you can access them through the Labels properties.

property Align: TLabelShapeAlign
Choice of label position : laTop (default) , laBottom, laLeft, laRight or LaCenter
property BorderSize: integer

property BorderColor: TColor

property ColorType: TLabelShapeColorType
Fixing the color, by default lcShape the item color will be used, or lcColor the Color property will be used
property Color: TColor

property FontColor: TColor

When ColorType=lcShape the color of the font is either White or Black depending on the best contrast.

10

property FontBold: boolean

property FontItalic: boolean

property FontSize: integer

property FontFamily: string

property LabelType: TLabelShapeType
Choice of the field whose text will be used as label : ltHint, ltDescription (default) , ltPosition (display latitude and longitude) , ltProperty, or ltMask
property PositionPrecision:byte

number of decimals used for latitude and longitude display, default 3

map.shapes.labels.PositionPrecision := 2;
property LabelProperty: string
Definition of the property used if LabelType=ltProperty
property LabelMask: string
Definition of the text mask used if LabelType=ltMask

You can display several properties by placing them between []

map.shapes.markers.Labels.LabelType := ltMask;
// [location] and [size] are replaced by the content of these properties
map.shapes.markers.Labels.LabelMask := '[location]'+#13#10+'[size]';
property Condition : TLabelCondition
With lcNone all elements can display their label, with lcSelected only the label of those whose Selected property is set to true is displayed..
property MaxWidth : integer
Maximum width for single-line labels, beyond that the text is cut and replaced by "..."
Set 0 (default value) so that all the text is displayed
property Margin: integer
Margin between the element and its label (default 8 pixels)
property MaxShow: integer
Maximum number of labels displayed (default 1000)
property MaxZoom: byte
Maximum zoom level for which the labels are displayed (default 22)
property MinZoom: byte
Minimum zoom level for which the labels are displayed (default 10)
property Style: TLabelShapeStyle
Background style : lsRectangle (default), lsRoundRect or lsTransparent
property Visible: boolean

property ShowOnlyIf : TLabelShowOnly (default lsoAll)

Filter the display of labels

Possibilities : lsoAll,lsoSelected,lsoPressed,lsoHover,lsoFocused,lsoEdited

// display the label only when you press the marker
map.shapes.markers.labels.ShowOnlyIf := lsoPressed;

on mobile lsoHover is identical to lsoPressed

11
property Rotation: boolean
If True if the map is rotated the labels remain horizontal but no longer have a background.
property Transparent: boolean
If True, the labels have the same opacity as their associated element.
property Scale: boolean
If True, labels use the scale of their associated element.
map.Shapes.Markers.Labels.Visible := true;
map.group['groupX'].Pois.Labels.Visible := true;

map.Shapes.Markers.Labels.LabelType := ltHint;
// the text can be multi-line
map.Shapes.Markers[0].hint := 'Text label'+#13# 10+'line 2';

map.group['groupX'].Pois.Labels.LabelType := ltProperty;
map.group['groupX'].Pois.Labels.LabelProperty := 'lb_voie_ext';
map.group['groupX'].Pois[0].PropertyValue['lb_voie_ext'] := 'text label';

// By default the background color is the color of the element, use ColorType to set another color.

map.shapes.Markers.Labels.ColorType := lcColor; // default lcShape
map.shapes.Markers.Labels.Color := clRed;

Fig. 5 Label displays

Labels for lines

The points of the lines consist of markers or pois, so you can activate the display of labels.

By default they are markers, to use pois see OnCreateShapeLinePoint

12

Reminder the points are only displayed if you fill in their Text property which correspond to the Hint of the labels..

var line : TECShapeLine;
...
if map.shapes.lines.count>0 then
begin
line := map.shapes.lines[0];
for i:=0 to line.count-1 do
line.path[i].Text := 'Point '+inttostr(i);
end;

Fig. 6 Display labels on a line

Add Shapes

You can use the following shortcuts to add your items

function TNativeMapControl.AddPOI(const Lat, Lng: double; const GroupName: string = ''): TECShapePOI;

function TNativeMapControl.AddMarker(const Lat, Lng: double; const GroupName: string = ''): TECShapeMarker;

function TNativeMapControl.AddLine(const Lat, Lng: double; const GroupName: string = ''): TECShapeLine;

var line : TECShapeLine;
...
// create line
line := map.addLine(lat,lng);
// use this syntax for add line in group
// line := map.addLine(lat,lng,'your group');

// don't free ! or use remove
// line.remove

// to find your item in the list use indexof
// map.shapes.lines[line.indexof]
// map.group['your group'].lines[line.indexof]

// block repaint
line.beginupdate;
// add more points in line
line.add(lat2,lng2);
line.add(lat3,lng3);
// now of for repaint
line.endupdate;
function TNativeMapControl.AddLine(const dLatLngs: array of double; const GroupName: string = ''): TECShapeLine;

var line : TECShapeLine;
...
// create line
line := map.addLine([lat,lng,lat2,lng2,lat3,lng3]);
// use this syntax for add line in group
// line := map.addLine([lat,lng,lat2,lng2],'your group');

// block repaint, no need with addline but now yes
line.beginupdate;
// add more points in line
line.add(lat4,lng4);
line.add(lat5,lng5);
// now of for repaint
line.endupdate;
function TNativeMapControl.AddPolygone(const Lat, Lng: double; const GroupName: string = ''): TECShapePolygone;

function TNativeMapControl.AddPolygone(const dLatLngs: array of double; const GroupName: string = ''): TECShapePolygone;

function TNativeMapControl.AddInfoWindow(const Lat, Lng: double; const GroupName: string = ''): TECShapeInfoWindow;

Do not destroy this shapes, they are kept in their respective group lists

2

TECClusterManager

The following properties allow you to change the display of the clusters

Watch demoNativePOI to understand how to use clusters

13
property Color : TColor
property Style : TClusterStyle (csEllipse, csStar, csRect, csTriangle,csTriangleDown ,csHexagon, csDiamond,csCategories)

Fig. 7 Cluster style

csCategories allows you to count element types within the cluster

14
function AddCategorie(const Categorie: string; Color: TColor): integer;

Add a category and set its color

The last category will be used to integrate all items that do not correspond to the criteria of the other categories.

property CategorieSort: TECCategorieSort
Indicates whether categories should be sorted (ctsAscending, ctsDescending, ctsNone)
property CategorieKey: string
Defines the element property to be used as a filter for categories
// We're going to use the default shapes group.
// To use another group, replace map.shapes with map['group_name'].
FClusterGroup := map.shapes;
// Categories are determined by the value of the 'shape' property of the elements.
FClusterGroup.ClusterManager.CategorieKey := 'shape';

// Each type of POI is referenced as a category,
// The color is calculated according to the name to maintain consistency.
with FClusterGroup.ClusterManager do
begin
// for poi['shape']='Ellipse'
AddCategorie('Ellipse', GetHashColor('ellipse'));
AddCategorie('Star', GetHashColor('etar'));
AddCategorie('Triangle', GetHashColor('triangle'));
AddCategorie('Diamond', GetHashColor('diamond'));
AddCategorie('Hexagon', GetHashColor('hexagon'));
AddCategorie('Arrow', GetHashColor('arrow'));
AddCategorie('ArrowHead', GetHashColor('arrowhead'));
AddCategorie('Cross', GetHashColor('cross'));
AddCategorie('DiagCross', GetHashColor('diagcross'));
AddCategorie('DirectionSign', GetHashColor('directionsign'));
AddCategorie('Rect', GetHashColor('rect'));
AddCategorie('Text', GetHashColor('text'));

// The last category will be used to count non-referenced categories.
// Here it's useless, but it's for documentation purposes.
AddCategorie('Other', GetHashColor('Other'));
end;

Fig. 8 Cluster Categories

property TextColor : TColor
property BorderColor : TColor
property BorderSize : integer
property FontSize : integer
property Opacity : byte
property WidthHeight : integer
property FillClusterList : boolean
Keeps the list of items contained in the cluster, by default false
You can access it at the OnMouseOverCluster event ( Cluster.shapes )
property MaxPixelDistance : integer

Items that are less than MaxPixelDistance of a cluster are grouped, 60 pixels by default

property DrawWhenMoving : boolean

Displays the clusters while moving the map defaults to true

property MaxZoom : byte

If the zoom is greater than MaxZoom elements are not grouped, default 18

property OnAddShapeToCluster : TOnAddShapeToCluster (sender : TECCluster; const Shape:TECShape;var cancel:boolean)

Raised when an item is added in a cluster, you can refuse by toggling cancel to true, default false

property OnColorSizeCluster : TOnColorSizeCluster (const Cluster : TECCluster;
var Color:TColor;var BorderColor:TColor;var TextColor:TColor,
var WidthHeight,FontSize:integer)

Raised before the display to allow you to adjust properties

property OnDrawCluster : TOnDrawCluster (const Canvas : TECCanvas; var rect : TRect; Cluster : TECCluster)

If you connect on this event you are supporting fully the cluster design

property OnMouseOverCluster : TOnNotifyEventCluster (const Cluster : TECCluster)

Triggered by the entry of the mouse on the cluster

property OnMouseOutCluster : TOnNotifyEventCluster (const Cluster : TECCluster)

Triggered by the release of the mouse in the cluster

example, change color depending on the number of elements contained by the cluster


map.Shapes.Clusterable := true;
// if you need to manipulate the elements contained in the cluster set FillClusterList a true
map.Shapes.ClusterManager.FillClusterList := true;
map.Shapes.ClusterManager.OnColorSizeCluster := doOnColorSizeCluster;

procedure TForm.doOnColorSizeCluster(const Cluster : TECCluster;
var Color:TColor;var BorderColor:TColor;var TextColor:TColor;
var WidthHeight,FontSize:integer;
var CCluster : TClusterStyle
);
//var i, nbrSelected: integer;
begin
// sample code if you need to manipulate the elements contained in the cluster
(*
nbrSelected := 0;
for i := 0 to Cluster.shapes.count - 1 do
begin
if Cluster.shapes[i].selected then
inc(nbrSelected);
end;
*
)

if Cluster.Count< 10 then
begin
Color := clGreen;
end

else

if Cluster.Count< 100 then
begin
Color := clBlue;
end

else

Color := clRed;

end;

Element TECShape

All displayable elements are descended from TECShape, they share the following properties

property Clusterable

allows not group this elements, true by default

map.shapes.markers[10].Clusterable := false;

property Address: string

Returns the address of the element, research is blocking
procedure Location

Geolocated the element, equivalent to Address but is not blocking

Raises OnShapeLocation(item:TECShape,GeoResult:TECGeoResult;const Valid:boolean);

If the TECShape is not OnShapeLocation event is the OnShapeLocation of its Group that is raised.

Valid is true if the current position of the element is the same as that at the research.

map.shapes.OnShapeLocation := doShapeLocation;
// Asynchronous search address for Markers[0],
// when it is found map.shapes.OnShapeLocation is triggered
map.shapes.Markers[0].Location;
//
procedure TForm1.doShapeLocation(item:TECShape;const GeoResult:TECGeoResult;const Valid:boolean);
begin

if assigned(item) and Valid then
begin
// address
GeoResult.address;
end;

end;


function DistanceTo(Shape:TECShape)

Returns the distance in kilometres between the two elements

procedure InfoWindow(const content:string);

procedure InfoWindow(window:TECShapeInfoWindow);

Add an infoWindow to the element, it appears when you click on the element.

my_marker.InfoWindow('content for my marker');
// you can also use one infoWindow for many shapes
id := map.shapes.infoWindows.add(0,0,'the same for all');
my_marker1.InfoWindow(map.shapes.infoWindows[id]);
my_marker2.InfoWindow(map.shapes.infoWindows[id]);
// for delete use nil
my_marker3.InfoWindow(nil);

procedure Remove

You can directly delete element

procedure SetPosition(const dLat, dLng: double)

Moves the item to latitude and longitude
procedure SetDistanceBearing(const Kilometers, Bearing: double;const vincenty:boolean=false)

Moves the element x kilometres at an angle expressed in degrees

If you wish to use the Vincenty formula, pass true as the last parameter .

procedure SetDirection(const dLat, dLng: double)
Moves the item to latitude and longitude, changes its angle of rotation so that it rotates in the right direction
function SpeedKmH:integer;
Returns the element's travel speed in km per hour
function Time:TDateTime
Returns the date and time of the last trip
function MoveDirection:integer;
indicates the angle of the direction of the last movement
function MoveDistance:double;
indicates the distance in km of the last trip
procedure CenterOnMap
Move the map so that the element is at the centre

function IndexOf: integer

Index of the item in its list (Pois, Markers, Lines ou Polygones)

function ShowOnMap: boolean

Indicates whether the item is in the visible part of the map

property Animation : TECShapeAnimation

Lets animate shape see Animation
property Latitude: double
Latitude of the element

property Longitude: double

Longitude of the element

property Altitude: double

Altitude of the element, you must have plugged a TECGeolocalise for your TECNativeMap component

property Color: TColor

Color of the item

property HoverColor: TColor

procedure setFocus;
Gives focus to the item, the display is identical to the mouse flyover
procedure unfocus;
Cancels focus
Color on hover

property Tag: longint

You can use it freely

property Visible : boolean

Displays or hides the element
property TrackLine : TECShapeLine

If TrackLine is set the track of the movement of the element will be generated

To activate it, simply use the property, you can also directly assign a line

FTracker := map.AddMarker(Latitude,Longitude) ;
// To activate the trace just access TrackLine
// line is created in the same group as FTracker
FTracker.TrackLine.visible := true;

// You can also pass a line
FTracker.TrackLine := your_line;

// for stop tracking set to nil , the line is free
FTracker.TrackLine := nil

Fig. 9 Trackline

property isTrackLineActive : boolean
Lets you know if a TrackLine is enabled.

If you test directly TrackLine it is automatically created if it does not exist !

15

property Serialize : boolean

Specify whether the item can be saved to a file (default yes)

property Clickable

Makes the reactive element to the mouse

property ZIndex

The items are displayed in ascending their ZIndex
BringToFront

Show element in foreground regardless of ZIndex

A single item at a time may be in the foreground, BringToFront does not change the display order which remains dependent of the ZIndex

16
SendToBack
Return to the normal display order

property Draggable

Makes a draggable element with the mouse

By switching the TNativeMapControl.ShapeDragMode property to sdmMultiShapes (default sdmShape) and if the element pointed by the mouse is selected you will be able to move all the draggable selected elements simultaneously, they will keep the same distances between them.

Fig. 10 ShapeDragMode - sdmMultiShapes

property XAnchor and YAnchor
Allows you to set the exact point inside the area of the element representing the Latitude and Longitude
property Angle
Angle of rotation in degrees (0-360)

Available for TECShapeMarker and TECShapePOI

3

property Hint: string

The text displayed in the bubble when the mouse hovers over the element, the parent group ShowHint property must be tripped to true

You can inject the properties of the element like this

shape.hint := 'value of [prop1] - value of [prop2]';

The text may be enriched with some html tags see TECShapeInfoWindow

6
property EnabledHint
Enables / disables the display of the ToolTip information for the item
property MaxShowHint
indicates the number of times the information bubble will be displayed, you can reactivate it with EnabledHint or reloading MaxShowHint
property PropertyValue[Name]
allows you to access the value of the property Name

You can use PropertyValue to store your own data, this property is also used by vector tiles, the OpenStreetMap data is saved.

17
property Properties
List of Property/Value in the format "name: value", each pair is separated by a carriage return.

property Group:TECShapes

Group to which the item belongs
property Rotation: boolean
compensation of the map rotation, if true then the element remains fixed even if the map has rotated
property Selected

Selects item, selected item appears as if it was over

The Selected property of the map contains all selected items

// you can use Iterator

var shape:TECShape

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

TECSelectedShapesList

Type of the list of selected items, gives you access to

function ByArea(const NEALat,NEALng,SWALat,SWALng :double):integer;
Selects elements within the area bounded by NEALat, NEALng (top-right corner) and SWALat, SWALng (bottom-left corner)
function ByKMDistance(const FLat,FLng,FKMDistance :double):integer;
Selects elements within KMDistance (distance in km) to the point FLat,FLng
procedure UnSelectedAll
Cleared all elements without deleting
procedure Clear
Clears all selected items of the map

function count : integer;

procedure SaveToFile(const filename:string);

property Item[index: integer]: TECShape
Returns the element whose is the index
property ToTxt:string
Returns the selected items in the internal text format of TECNativeMap (read-only)
property GroupFilter : TStringList
Allows you to filter based on the groups of elements, leave empty to select items regardless of his group
property OnChange:TNotifyEvent ;
Triggered by adding/removing an item to the list of selected

Research

You have several functions to search in your items


function FindShapeByArea(const SWALat, SWALng, NEALat, NEALng: double;
                        const ShapeList: TList<TECShape>;
                        const FilterShapes : TNativeShapes = [];
                        Filter:TOnShapeFilter=nil): integer;

ShapeList filled with items in a rectangular area which indicates the Southwest corners and Northeast

FilterShapes allows you to filter the wanted elements, by default all, example [nsMarker,nsPoi] to search only for TECShapeMarker and TECShapePOI

Filter allows to add a procedure to filter the search

// find the cafes located less than 2km
map.FindShapeByKMDistance(map.Latitude,map.Longitude, 2.0,liste,[nsMarker,nsPoi],FilterCafe);
...

procedure FilterCafe(const Shape: TECShape; var cancel: boolean);
begin
cancel := shape.PropertyValue['kind']<>'cafe' ;
end;

function FindShapeByKMDistance(const FLat, FLng, FKMDistance: double;
                                const ShapeList: TList<TECShape>;
                                const FilterShapes : TNativeShapes = [];
                                Filter:TOnShapeFilter=nil): integer;
ShapeList filled with items that are less than FKMDistance km from the point FLat,FLng
function FindShapeByFilter(const ShapeList: TList<TECShape>;
                                const FilterShapes : TNativeShapes;
                                Filter:TOnShapeFilter): integer;

All these functions return the number of items found.

18

For Delphi versions that do not support generics ShapeList is a simple TList

19

Events

Forms trigger the following events :


property OnShapeMove : TOnShapeMove

property OnShapeDrag : TOnShapeMove

property OnShapeDragEnd : TNotifyEvent

property OnShapeMouseOver : TOnShapeMouseEvent

property OnShapeMouseOut : TOnShapeMouseEvent

property OnShapeMouseDown : TOnShapeMouseEvent

property OnShapeMouseup : TOnShapeMouseEvent

property OnShapeClick : TOnShapeMouseEvent

property OnShapeRightClick: TOnShapeMouseEvent

property OnShapeDblClick : TOnShapeMouseEvent

property OnShapeDblClick : TNotifyEvent

property OnShapeLocation : TOnShapeLocation

Events can be assigned individually to each element, in this case they are not passed to the level of TECNativeMap

7

Snap markers on a line or a polygon

You can set the TECShapeMarker and TECShapePOI which will automatically gravitate towards a TECShapeLine or a TECShapePolygone if the drop has some distance from these.

Fig. 11 SnapDrag

Manage you this through the SnapDrag of type TECSnapDrag of the mapping component TECNativeMap property.

procedure ClearMarker;
Removes all the snaping markers
function AddMarker(const Marker: TECShape): boolean;
Adds a TECShapeMarker or TECShapePOI in the list of the snaping markers.
Returns true if the element is added.
procedure RemoveMarker(const Marker: TECShape);
Deletes the marker from the list of the snaping markers
procedure ClearGuide;
Remove all the TECShapeLine and TECShapePolygone of the list of guides
function AddGuide(const Guide: TECShapeLine): boolean;
Adds a TECShapeLine or a TECShapePolygone in the list of guides.
Returns true if the element is added.
procedure RemoveGuide(const Guide: TECShapeLine);
Removes the element from the list of guides
procedure CancelSnap;
Cancel the move and puts the marker to its point of origin
property MeterDistance: boolean ;
Selects the unit for distance triggering the magnetization.
true to meters, false (default) to pixels.
property SnapDistance: integer ;
Distance of attraction of the markers to a guide
property SnapShape: TECShape ;
Returns the marker that comes to be attracted.
property SnapGuide: TECShape;
Returns the guide coming to snap a marker
property TargetLine:boolean;
If true draws a line between the marker and the point target on the guide
property OnSnap: TNotifyEvent;
The event is raised when the a marker is attracted by a guide.
property OnNoSnap: TNotifyEvent;
The event is raised when the a marker is drop outside the catchment area of a guide.
map.SnapDrag.addMarker(mrk);

map.SnapDrag.AddGuide(poly);
map.SnapDrag.AddGuide(red_line);

map.SnapDrag.MeterDistance := true;
map.SnapDrag.SnapDistance := 50; // 50 meters

map.SnapDrag.MeterDistance := false;
map.SnapDrag.SnapDistance := 50; // 50 pixels

The property _snap_ of the guides is set to true when it attracts a marker, you can use to define a style that will visually report the status.

8
// double the size of line when targeted
map.Styles.addRule('.line._snap_:true {scale:2}') ;
map.Styles.addRule('.polygone._snap_:true {scale:2}') ;
// default size
map.Styles.addRule('.line._snap_:false {scale:1}') ;
map.Styles.addRule('.polygone._snap_:false {scale:1}') ;
// doted target line
map.Styles.addRule('#TECSnapDrag.line{penStyle:Dot}');

If you want that markers are attracted to specific lines, you can create your own variable of type TECSnapeDrag

9
var MySnapDrag : TECSnapDrag;
...
MySnapDrag := TECSnapDrag.create;

MySnapDrag.addMarker(mrk);

MySnapDrag.AddGuide(poly);
MySnapDrag.AddGuide(red_line);
...
MySnapDrag.free

Drawing and free hand selection

FreeHand allows you to define lines, which can become polygons, to mouse, for it simply activate FreeHand.Draw

Fig. 12 Draw lines and polygons

// event triggered when the drawing is finished
map.FreeHand.OnDraw := doFreeHandDraw;
// activate the hands-free drawing
map.FreeHand.Draw := true;
...
procedure TForm.doFreeHandDraw(Sender: TObject);
begin
// save the line to your map
map.addLine(TECNativeFreeHand(sender).line)
// you can use also this syntax
map.FreeHand.addLine;
// convert the drawn line into a polygon and add it to the map
map.addPolygone(TECNativeFreeHand(sender).line);
// you can use also this syntax
map.freeHand.addPolygone;
end;

You can also activate the free hand selection tool, allows you to choose items simply by surrounding

Fig. 13 Hands-free selection

property AutomaticMapMovement : boolean ;

Allows the automatic card moving when the drawing cursor approaches an edge, default True

property Draw: boolean ;

The drawing mode.

property Selection: boolean ;

The mode Selection.

Do not disable Draw after enabling Selection, Selection also active Draw !

4

property MouseButton: TMouseButton ;

The mouse button used to draw, by default mbRight.

If you use the left button, it map may be moved by holding down the CTRL key.

10

property Cursor: TECShape ;

Drawing slider, by default a TECShapePOI in the shape of a cross.

property Line: TECShapeLine;

The line that represents your drawing, you can adjust its properties either directly or by style.

// style for draw line
map.Styles.addRule('#TECNativeFreeHand.Line {color : green;penStyle:Dash;weight:2}') ;

Fig. 14 Style FreeHand Line

property PolygoneSelection: TECShapePolygone ;

Accessible in the OnSelection event, it represents the area of your selection.

property SelectionList: TECShapesList;

Accessible in the OnSelection event, this list contains selected items.

property OnPermission : TOnFreeHandPermission
Control FreeHand authorization
map.FreeHand.Selection := True;
map.FreeHand.OnPermission := doOnFreeHandPermission;
...
// selection with freeHand is only allowed if CTRL or SHIFT is pressed
procedure TForm1.doOnFreeHandPermission(sender : TObject;var valid:boolean);
begin
valid := (((GetKeyState(VK_CONTROL) and $8000) = $8000) or
((GetKeyState(VK_SHIFT) and $8000) = $8000)
);
end;

property SelectionFilter: TOnShapeFilter

Can set a filter for selection.

map.FreeHand.SelectionFilter := FilterCafe;
...
// select only cafe
procedure FilterCafe(const Shape: TECShape; var cancel: boolean);
begin
cancel := shape.PropertyValue['kind']<>'cafe' ;
end;

function AddLine(const GroupName:string=''):TECShapeLine;

Add your trace permanently as a Line to your map

function AddPolygone(const GroupName:string=''):TECShapePolygone;

Add your trace permanently as a Polygone to your map

SelectArea

This property allows you to select a rectangular or circular area.

Fig. 15 Demo SelectArea

property AreaType: TECAreaType ;

Type of selection : atRectangle ou atCircle

property Area: double

Surface in Km² of the selection

property Width: double

Width in Km of the selection

property Height: double

Height in Km of the selection

property Color : TColor

Color of the selection

procedure setPosition(const Lat,Lng:double)

Position the center of the selection

procedure Boundary(const dNELat, dNELng, dSWLat, dSWLng: double)

Define the rectangle enclosing the selection area

procedure fitBounds

Zoom in on the selection

property Center : TLatLng

Selection Center

property NELat: double

Latitude of the top right corner of the selection area

property NELng: double

Longitude of the top right corner of the selection area

property SWLat: double

Latitude of the bottom left corner of the selection area

property SWLng: double

Longitude of the bottom left corner of the selection area

property Visible: boolean

Display the selection area

property ShowMetrics : boolean

Display or not the Width, Height and Area information in the center of the selection area

property OnChange: TNotifyEvent

Event triggered after a move and at the end of a resize of the selection area

property OnClick: TNotifyEvent

Event triggered after a click in the selection area

property OnDblClick: TNotifyEvent

Event triggered after a double click in the selection area

property OnLongPress: TNotifyEvent

Event triggered after a click in the selection area

property OnRightClick: TNotifyEvent

Event triggered after a right click in the selection area

property OnUpdateMetric : TOnUpdateMetric

Event triggered before the display of the metrics to be able to modify them
procedure TFSelectArea.FormCreate(Sender: TObject);
begin
map.SelectArea.OnChange := doOnChange;
map.SelectArea.OnUpdateMetric:= doUpdateMetric;
map.SelectArea.Visible := true;
end;

procedure TFSelectArea.doUpdateMetric(const sender: TECSelectArea; var Value: string);
begin
// display only area
value := 'Area : '+doubletostrdigit(map.SelectArea.Area, 3)+' Km²';
end;

procedure TFSelectArea.doOnChange(sender : TObject);
begin
case map.SelectArea.AreaType of
atRectangle: begin
info.Caption := 'NorthEst : '+ doubletostrdigit(map.SelectArea.NELat,3)+','+
doubletostrdigit(map.SelectArea.NELng,3)+' SouthWest : '+
doubletostrdigit(map.SelectArea.SWLat,3)+','+
doubletostrdigit(map.SelectArea.SWLng,3)+
' W : '+doubletostrdigit(map.SelectArea.Width, 2)+' Km '+
'H : '+doubletostrdigit(map.SelectArea.Height, 2)+' Km '+
'Area : '+doubletostrdigit(map.SelectArea.Area, 3)+' Km²';
end;
atCircle: begin
info.Caption := 'Lat : '+ doubletostrdigit(map.SelectArea.Center.lat,3)+','+
doubletostrdigit(map.SelectArea.Center.lng,3)+' Radius : '+
doubletostrdigit(map.SelectArea.Width / 2,2)+' Km Area : '+doubletostrdigit(map.SelectArea.Area, 3)+' Km²';
end;
end;
end;

Grids

This property manages grids that you can place on your map, the grids can be rectangular or delimited by a polygon.


Fig. 16 Demo Grids

function Add(const col, row: integer;const GridName: string = '') : TECGrid;

function Add(const Poly: TECShapePolygone;const CellSizeMeter: integer = 500; const GridName: string = ''): TECGrid;

var grid:TECGrid;
// add a 5x3 grid
grid := Map.Grids.Add(5,3,'grid 5x3');
// create a grid on a polygon with cells of 1Km by 1Km
grid := Map.Grids.Add(Map['groupx'].Polygones[1],1000);
procedure Clear;
Delete all grids
function Count: integer;
Returns the number of grids
function getList(const aList:TStrings):integer;
Fill aList with the names of the grids
property FocusedGrid: TECGrid
Gives focus to a particular grid

property Grid[index: integer]: TECGrid default;

property Grid[index: string]: TECGrid default;

// get a grid by index
grid := Map.Grids[1];
// get a grid by his name
grid := Map.Grids['grid 2'];
// grid = nil if not exists
property EditableGrid: TECGrid
Returns the grid that is in edit mode, nil if there is none
property toTxt: string
Export / import grids in text format
property OnFocusedGrid: TNotifyEvent
Triggered when a grid has focus
property OnCellClick: TOnCellEvent
property OnCellDblClick: TOnCellEvent
property OnCellRightClick: TOnCellEvent
property OnCellLongPress: TOnCellEvent
Triggered during interactions with a cell
property OnChange : TNotifyEvent
Triggered when a grid is added or deleted
property OnEditChange : TOnEditChange
Triggered when the grid is moved or modified in editable mode
property OnHeaderClick: TOnHeaderClick
Triggered by a click on a label referencing columns and rows
map.grids.OnFocusedGrid := doFocusedGrid;
map.grids.OnCellRightClick := doGridRightClick;
map.grids.OnHeaderClick := donOnHeaderClick ;
map.grids.OnCellClick := doCellClick;
map.grids.OnCelldblClick := doCellDblClick;
map.grids.OnCellLongPress := doCellLongPress;
map.Grids.OnEditChange := doOnEditChange;
map.Grids.OnChange := doChangeGrids;
...
procedure TForm8.doFocusedGrid(Sender: TObject);
begin
// here sender = map.grids.FocusedGrid
if assigned(map.grids.FocusedGrid) then
begin
col.Value := map.grids.FocusedGrid.col;
row.Value := map.grids.FocusedGrid.row;
end;
end;

procedure TForm8.doOnEditChange(const Grid:TECGrid);
begin
info.Caption := (
'NorthEst : '+ doubletostrdigit(Grid.NELat,3)+' , '+doubletostrdigit(Grid.NELng,3)+
' SouthWest : '+doubletostrdigit(Grid.SWLat,3)+' , '+doubletostrdigit(Grid.SWLng,3)+
' - Col : '+inttostr(Grid.col)+' Row : '+inttostr(Grid.row));
end;

// click on labels
procedure TForm8.donOnHeaderClick(const Grid:TECGrid;const Text:string;const index: integer; const Position : TECHeaderLabelPosition) ;
var PosText:string;
begin

case Position of
hlpTop : PosText := 'Top';
hlpBottom: PosText := 'Bottom';
hlpLeft : PosText := 'Left' ;
hlpRight : PosText := 'Right';
end;

info.Caption := (Text + ' - Index : '+inttostr(index)+' Pos : '+PosText);
end;

procedure TForm8.doCellClick(const Grid:TECGrid; const Item: TECShapePolygone);
begin
info.Caption := ('Click '+Item.Description+ ' - Col:'+ Item['cell-col']+' Row:'+Item['cell-row']);
end;

procedure TForm8.doCellDblClick(const Grid:TECGrid; const Item: TECShapePolygone);
begin
info.Caption := ('DblClick '+Item.Description+ ' - Col:'+ Item['cell-col']+' Row:'+Item['cell-row']);
end;


procedure TForm8.doCellLongPress(const Grid:TECGrid; const Item: TECShapePolygone);
begin
info.Caption := ('Press '+Item.Description+ ' - Col:'+ Item['cell-col']+' Row:'+Item['cell-row']);
Grid.editable := true;
end;

procedure TForm8.doGridRightClick(const Grid:TECGrid; const Item: TECShapePolygone);
begin
info.Caption := ('RightClick '+Item.Description+ ' - Col:'+ Item['cell-col']+' Row:'+Item['cell-row']);
end;

property OnHeaderColLabel: TOnHeaderLabel

property OnHeaderRowLabel: TOnHeaderLabel

Allows to take in charge the titles of the labels, by default the columns are an alphabetical sequence (A,B,..,AA,AB..) and the lines a numerical sequence
// swap labels col & row
map.Grids.OnHeaderColLabel := doOnHeaderColLabel;
map.Grids.OnHeaderRowLable := doOnHeaderRowLabel;
...
procedure TForm.doOnHeaderColLabel(const index:integer;var value:string) ;
begin
value := inttostr(index);
end;
//
procedure TForm.doOnHeaderRowLabel(const index:integer;var value:string) ;
begin
value := NumberToAlphabet(index); // unit uecMapUtil
end;

TECGrid

This class manages a grid

procedure setPosition(const Lat, Lng: double);
If the grid is in Editable mode and is not defined from a polygon, then it will be centered on the indicated point
procedure Boundary(const dNELat, dNELng, dSWLat, dSWLng: double);
Defines a rectangular grid whose top-right corner has coordinates dNELat, dNELng and whose bottom-left corner has coordinates dSWLat, dSWLng
procedure setSize(const icol, irow: integer);
Redefine the number of columns and rows
procedure PolygonToGrid(const P: TECShapePolygone;
const aCellSizeMeter: integer);
Set the grid to fill the polygon with cells whose height and width are specified in meters.
procedure fitBounds;
Zoom in on the grid
function getCellAt(const lat,lng:double):TECShapePolygone;
Returns the cell containing the point Lat,Lng

Nil is returned if there is no cell

2
property Name: string
Name of the grid
property GridType: TECGridType
Returns gtTable for a rectangular grid, gtPolygon if cell is defined from a polygon
property CellSizeMeter: integer
Indicates or defines the size of the cells in meters
property CellColor: TColor
Color of the cells
property HoverColor: TColor
Color when hovering over a cell
property CellWeight: byte
Cell thickness
property col: integer
Number of columns
property row: integer
Number of lines
property Cells[ColIndex, RowIndex: integer]: TECShapePolygone default;
Returns the polygon of the cell or nil
property Editable: boolean
Toggles a grid of type gtTable in edit mode

property NELat: double
property NELng: double
property SWLat: double
property SWLng: double
Coordinates of the top-right and bottom-left corners
property ShowHeaderLabel: boolean
Display or not the labels
property ZIndex: integer
ZIndex of the grid

property toTxt: string
Import and export a grid in text format
go to page
Réalisé avec la version gratuite pour les particuliers d'Help&Web