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
exemple, changer la couleur en fonction du nombre d'éléments contenu par le cluster
// 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;
Voir aussi la démo VCL / Cluster aggregate average values
Élément TECShape
Tous les éléments affichable descendent de TECShape, ils partagent les propriétés suivantes
property Clusterable : booleanPermet d'exclure l'élement des clusters, par défaut true
Geolocalise l'élément, équivalent Address mais n'est pas bloquante
Déclenche OnShapeLocation(item:TECShape,GeoResult:TECGeoResult;const Valid:boolean);
Si le TECShape n'a pas d'événement OnShapeLocation c'est le OnShapeLocation de son groupe qui est déclenché.
Valid est a true si la position actuelle de l'élément est la même que celle lors du déclenchement de la recherche.
// you can
use Iterator
var shape:TECShape
for shape in map.Selected
do
begin
..
end;
function DistanceTo(Shape:TECShape)
Si TrackLine est définie la trace du déplacement de l'élément sera automatique gérée
Pour l'activer il suffit simplement d'y accéder, vous pouvez aussi directement assigner une ligne
// 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
Si vous testez directement TrackLine elle est automatiquement créé si elle n'existe pas !
12Force l'élément a s'afficher au premier plan sans tenir compte des zindex
Un seul élément à la fois peut-être au premier plan, BringToFront ne change pas l'ordre d'affichage qui reste dépendant du ZIndex
13En basculant la propriété TNativeMapControl.ShapeDragMode sur sdmMultiShapes (défaut sdmShape) et si l'élément pointé par la souris est sélectionné vous pourrez déplacer simultanément tous les éléments draggable sélectionnés, ils garderont les mêmes distances entre eux.
property AngleDisponible pour les TECShapeMarker et TECShapePOI
3Vous pouvez injecter les propriétés de l'élément comme cela
Le texte peut être enrichi avec certains balises html voir TECShapeInfoWindow
5Vous pouvez utilisez PropertyValue pour stocker vos propres données, cette propriété est aussi utilisée par les tuiles vectorielles, les données OpenStreetMap y sont sauvegardées.
14Sélectionne ou non un élément, un élément sélectionné s'affiche comme s'il était survolé
La propriété Selected de la carte contient tous les éléments sélectionnés// you can
use Iterator
var shape:TECShape
for shape in map.Selected
do
begin
..
end;
TECSelectedShapesList
Type de la liste des éléments sélectionnés, vous donne accès àfunction ByArea(const NEALat,NEALng,SWALat,SWALng :double):integer;
function count : integer;
procedure SaveToFile(const filename:string);
property Item[index: integer]: TECShapeproperty 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