Pour utiliser les formes vous devez rajouter l'unité uecNativeShape
Tous les éléments positionnés sur la carte sont accessibles au travers de la propriété Shapes de type TECShapes ou des autres groupes via Group['name'], ils descendent tous de la classe TECShape
Vous pouvez stockers dans vos éléments (marker, poi, line ou polygone) les données textuelles que souhaitez au travers de la propriété PropertyValue ses valeurs pourront être associées à un style
...
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';
Lorsque vous ajoutez plusieurs éléments à la suite encadrez-les par le couple BeginUpdate / EndUpdate
1Styles
Au lieu de décorer manuellement chaque élément vous pouvez définir des régles pour leur appliquer un style
Groupes ( TECShapes )
Un groupe gère un ensemble d'éléments, en fait la propriété Shapes est le groupe par défaut, vous accédez à un groupe par la propriété Group['name']
Vous pouvez aussi y accéder par un index au travers de la propriété Groups
1var
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;
Les propriétés Pois, markers, lines et Polygones disposent aussi d'une procedure fitBounds
2L'événement OnLoad est déclenché lorsque le contenu est totalement disponible
3Charge le groupe avec un stream contenant des données au format OSM XML ou olt
Charge le groupe avec une chaine contenant des données au format OSM XML ou olt
Chaine qui s'affiche comme info-bulle pour les éléments dont le Hint est vide
map['groupx'].Hint := 'value of [prop1] - value of [prop2]';
Active les support des Clusters, cela permet de regrouper des markers ou des pois proches pour une meilleure visibilité
property Pois: TECShapePOIList
Les listes d'éléments disposent d'un itérateur comme les groupes
2var
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;
Vous avez aussi des raccourcis pour créer vos éléments
3function 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;
...
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';
function AddPolygone(const dLatLngs: array of double): TECShapePolygone;
property MaxZoom: byte
L'opacité varie de 0 à 100, une valeur >100 indique que l'opacité du groupe n'est pas prise en compte et que seule celle des éléménts est utilisée.
Dans le cas d'une valeur > 100, l'opacité originelle des éléments n'est pas restaurée
1TECNativeMap.TopGroupZindex retourne le ZIndex le plus élevé de tous les groupes
4Les éléments ont eux aussi une propriété clickable
5Ne s'applique pas si l'on sauvegarde directement le groupe
6var
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;
Les listes d'éléments (Markers, Pois, Lines, Polygones) ont aussi une propriété Show que vous pouvez activer/désactiver individuellement.
7Retourne true si au moins un des éléments du groupe est sélectionné.
Les listes d'éléments ont aussi une propriété Selected
8...
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';
property Name: string
Markers et Pois HeatMap
Les listes de Markers et de Pois ont une propriétés HeatMap pour gèrer une carte thermique.
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;
CSV
Le gestionnaire de fichiers CSV est accessible au travers de la propriété CSV des groupes
function LoadFromFile(const filename: string):boolean;Lorsque les données sont chargées l'événement OnLoad de la carte est déclenché
9procedure SaveToFile(const filename: string;const ShapeList:TECShapeList);
Enregistre la liste d'éléments (markers ou Pois) dans un fichier csv
Utilisez la liste Fields pour sélectionner les PropertyValue a enregistrer.Fields contient les champs du dernier fichier CSV chargé donc au besoin videz la avant de la remplir avec votre sélection.
Pas besoin d'y rajouter les champs pour la Latitude et Longitude, FieldNameLatitude et FieldNameLongitude seront utilisées
...
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';
property FieldNameWKT: string;
// 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;
Si la position géographique est regroupée dans un seul champ, indiquez le dans FieldNameLatitude, laissez FieldNameLongitude vide, utilisez DelimiterLatLng pour définir le séparateur entre la latitude et la longitude.
4map.Shapes.CSV.FieldNameLongitude := '';
map.Shapes.CSV.DelimiterLatLng := ',';
property idxLatitude: integer
property idxLongitude: integer
// 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
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
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
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;
La géométrie doit être exprimée en degrès décimal, si besoin vous pouvez vous brancher sur OnConvertLatLng pour définir une procédure de conversion
1// 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;
Les autres champs du fichier CSV sont importés dans
les éléments au travers de leur propriété
PropertyValue[field_name] := field_value
Si le fichier CSV ne nomme pas ses champs, ils seront
dénommés en concatant le nom du fichier sans l'extension
+ l'index du champ
Labels
Les listes de Polygones, de Markers et de Pois permettent d'associer des labels à leurs éléments, vous y accédez au travers de la propriétés Labels
property Align: TLabelShapeAlignproperty BorderColor: TColor
property ColorType: TLabelShapeColorType
Fixation des propriétés graphiques
lcShape (défaut) la couleur et la fonte de l'item seront utiliséeslcColor la couleur et la Fonte seront fixées par les propriétés Color et FontXXX
lcProperty utilise des propriétés de l'élément (item['fontcolor'],item['fillcolor'],item[ 'bordercolor'],item['shadowcolor'],item[ 'shadowsize'])
property FontColor: TColor
property FontBold: boolean
property FontItalic: boolean
property FontSize: integer
property FontFamily: string
property LabelType: TLabelShapeType
nombre de décimales utilisées pour l'affichage des latitude et longitude, par défaut 3
Vous pouvez afficher plusieurs propriétés en les plaçant entre []
// [location] and [size] are replaced by the content of these properties
map.shapes.markers.Labels.LabelMask := '[location]'+#13#10+'[size]';
Mettre 0 (valeur par défaut) pour que tout le texte s'affiche
property ShowOnlyIf : TLabelShowOnly (default lsoAll)
Filtrer l'affichage des labels
Possibilités : lsoAll,lsoSelected,lsoPressed,lsoHover,lsoFocused
...
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';
sur mobile lsoHover est identique à lsoPressed
10Sous Firemonkey le texte est entouré d'un liseret de couleur ShadowColor et de taille ShadowTextOffset
11...
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';
Ajouter des Shapes
Vous pouvez utiliser les raccourcis suivant pour ajouter vos éléments
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;
...
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';
function TNativeMapControl.AddLine(const dLatLngs: array of double; const GroupName: string = ''): TECShapeLine;
...
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';
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;
Vous ne devez pas détruire manuellement les éléments ainsi créé si besoin utilisez remove, ils sont maintenu dans les listes de leur groupe respectif
2TECClusterManager
Les propriétés suivantes vous permettent de modifier l'affichage des clusters
property Color : TColorproperty Style : TClusterStyle (csEllipse, csStar, csRect, csTriangle, csHexagon, csDiamond)
property TextColor : TColor
property BorderColor : TColor
property BorderSize : integer
property FontSize : integer
property Opacity : byte
property WidthHeight : integer
property FillClusterList : boolean
Vous pourrez y avoir accès dans l'événement OnMouseOverCluster ( Cluster.shapes )
Les éléments qui sont à moins de MaxPixelDistance d'un cluster y sont regroupés, 60 pixels par défaut
Permet d'afficher les clusters pendant que l'on déplace la carte, par défaut true
Si le zoom est superieur à MaxZoom on ne regroupe pas les éléments, defaut 18
Déclenché lors de l'ajout d'un élément dans un cluster, vous pouvez refuser en basculant cancel à true, défaut false
var Color:TColor;var BorderColor:TColor;var TextColor:TColor,
var WidthHeight,FontSize:integer;var CStyle:TClusterStyle)
Déclenché avant l'affichage pour vous permettre d'ajuster les propriétés
Si vous vous branchez sur cet évenement vous prenez en charge intégralement le dessin du cluster
Déclenché par l'entrée de la souris sur le cluster
Déclenché par la sortie de la souris du cluster
property Cursor: TECShape ;
Curseur de dessin, par défaut un TECShapePOI en forme de croix
property Line: TECShapeLine;
La ligne qui représente votre dessin, vous pouvez ajuster ses propriétés soit directement soit par un style.
map.Styles.addRule('#TECNativeFreeHand.Line {color : green;penStyle:Dash;weight:2}') ;
property PolygoneSelection: TECShapePolygone ;
Accessible dans l'événenement OnSelection, il représente l'aire de votre sélection
property SelectionList: TECShapesList;
Accessible dans l'événement OnSelection, cette liste contient les éléments sélectionnés
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
Permet de définir un filtre pour la sélection
...
// select only cafe
procedure FilterCafe(const Shape: TECShape; var cancel: boolean);
begin
cancel := shape.PropertyValue['kind']<>'cafe' ;
end;
function AddLine(const GroupName:string=''):TECShapeLine;
function AddPolygone(const GroupName:string=''):TECShapePolygone;
SelectArea
Cette propriété permet de sélectionner une zone rectangulaire ou circulaire.
property AreaType: TECAreaType ;
property Area: double
property Width: double
property Height: double
property Color : TColor
procedure setPosition(const Lat,Lng:double)
procedure Boundary(const dNELat, dNELng, dSWLat, dSWLng: double)
procedure fitBounds
property Center : TLatLng
property NELat: double
property NELng: double
property SWLat: double
property SWLng: double
property Visible: boolean
property ShowMetrics : boolean
property OnChange: TNotifyEvent
property OnClick: TNotifyEvent
property OnDblClick: TNotifyEvent
property OnLongPress: TNotifyEvent
property OnRightClick: TNotifyEvent
property OnUpdateMetric : TOnUpdateMetric
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
Cette propriété gère des grilles que vous pouvez supperposer sur votre carte, les grilles peuvent être rectangulaire ou délimitée par un polygone.
function Add(const col, row: integer;const GridName: string = '') : TECGrid;
function Add(const Poly: TECShapePolygone;const CellSizeMeter: integer = 500; const GridName: string = ''): 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);
property Grid[index: integer]: TECGrid default;
property Grid[index: string]: TECGrid default;
grid := Map.Grids[1];
// get a grid by his name
grid := Map.Grids['grid 2'];
// grid = nil if not exists
property OnCellDblClick: TOnCellEvent
property OnCellRightClick: TOnCellEvent
property OnCellLongPress: TOnCellEvent
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
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
Cette classe gère une grille
procedure setPosition(const Lat, Lng: double);const aCellSizeMeter: integer);
property Name: string
property NELat: double
property NELng: double
property SWLat: double
property SWLng: double
ZIndex de la grille
property toTxt: string