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

Offline mode

you are here :TECNativeMap

The tiles are first searched in the memory cache (the tiles displayed recently), the local cache, archive local then on the internet if need.

Local cache

By assigning a directory to LocalCache property internet downloaded tiles are saved locally and are available offline.

Under android you will have to ask permission to read and write your data.

1
uses
...
System.Permissions,
{$IFDEF ANDROID}
Androidapi.Jni.Os,
Androidapi.jni.javatypes,
Androidapi.Helpers,
{$ENDIF}
...
{$IFDEF ANDROID}
PermissionsService.RequestPermissions([JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)],
procedure(const APermissions: TArray< string >;
const AGrantResults: TArray<TPermissionStatus>)
begin
if (Length(AGrantResults) = 2) and
(AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted)
then map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache')
else
map.LocalCache := '';
end)
{$ELSE}
map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache');
{$ENDIF}

Fig. 1 My local tiles

Use the MaxDayInCache property to specify the duration of retention in the cache by default 30 days, 0 for an infinite cache.

map.MaxDayInCache := 7; // max 7 days

LocalTileCache

This property of type TCustomTileCache allows you to save and load local tiles, instead of placing them in a subdirectory, for example, you can store them in a database.

You must therefore create a class descended from TCustomTileCache and redefine certain methods.

See the unit TileCacheSQLite.FireDAC which contains TTileCacheSQLite, it stores your tiles in a SQLite database saved in your directory LocalCache.

uses ..., TileCacheSQLite.FireDac;
...
//Define a local directory in which to store the database
map.LocalCache := ExtractfilePath(ParamStr(0)) + 'cache' ;
// Create TTileCacheSQLite,
// which handles DB creation on server changeover,
// and tile saving and reading on demand
map.LocalTileCache := TTileCacheSQLite.create(map);


TTileCacheSQLite = class(TCustomTileCache)
private
...
protected
// overload to react to server changes,
// here we'll open a database with the server's name
procedure doChangeTileServer(sender: TObject); override;

// override to save the XYZ tile contained in Stream,
// AHandle must be True if registration is ok
procedure doSaveLocalStream(const sender: TObject; const x, y, z: Integer;
const stream: TMemoryStream; var AHandled: boolean); override;

// override to load the XYZ tile in Stream,
// AHandle must be True if is ok

procedure doLoadLocalStream(const sender: TObject; const x, y, z: Integer;
const stream: TMemoryStream; var AHandled: boolean); override;

LocalTileCache is automatically released when the map is destroyed or when you change it, set it to nil to return to classic directory storage.

MBTiles

A MBTiles file is a file format for storing map tiles in a single file, technically a SQLite database.

To use it, add the file uecMBTiles.FireDAC (FMX.uecMBTiles.FireDAC under Firemonkey) to your uses.

FireDAC is used to access the SQLite database, so it's only compatible with recent versions of Delphi.

1
uses
... System.Permissions,System.IOUtils,
FMX.uecNativeMapControl,FMX.uecMBTiles.FireDAC;
{$IFDEF ANDROID}
const
PermissionReadExternalStorage = 'android.permission.READ_EXTERNAL_STORAGE';
PermissionWriteExternalStorage = 'android.permission.WRITE_EXTERNAL_STORAGE';
{$ENDIF}

procedure TForm23.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID} // android permissions management
PermissionsService.RequestPermissions
([PermissionReadExternalStorage,
PermissionWriteExternalStorage],
nil);
{$ENDIF}

{$IF DEFINED(iOS) or DEFINED(ANDROID)}
FDataBase := TPath.Combine(TPath.GetSharedDocumentsPath, 'countries-raster.mbtiles');
{$ELSE}
FDataBase := 'H:\#DATA\MBTiles\countries-raster.mbtiles';
{$ENDIF}
// connect the component Map to the MBTiles server
FecMBTiles := TecMBTiles.Create(Map);
// open DataBase, true if ok
if not FecMBTiles.Connect(FDataBase) then
begin
ShowMessage(FecMBTiles.MessageError);
end;
// call FecMBTiles.Disconnect for disconnect
end;

procedure TForm23.FormDestroy(Sender: TObject);
begin
FecMBTiles.Free;
end;

Fig. 2 MBTiles Firemonkey

The demo uses the MBTiles raster file which can be found at //github.com/klokantech/vector-tiles-sample

1

Archive local

An MBTiles file is much more efficient than a simple zip.

2

An archive local is the local cache in a Zip, this simplifies deployment of the tiles and other files.

To improve the speed, the tiles are extracted from archive and placed in the local cache during the first request, you must set a local cache to use an archive.

Fig. 3 Archive ile de ré

map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache');
map.TileServer := tsOSM;
map.LocalArchive := ExtractfilePath(ParamStr(0))+'ile_de_re.zip';

If roads or geolocations of addresses are saved in archive recovery is completely transparent

2
map.Routing.engine(reMapBox);
// if an archive is connected and contains the route, no internet connection is made to return the way
map.Routing.Request('saint-martin de ré', 'la couarde sur mer');

You can store your images or data files (kml, geojson etc...), to load start the name of the file by /

// load data
map.Shapes.LoadFromFile('/DATA/tdf.kml');
map.LoadFromFile('/DATA/tarbes.txt');
// load image in marker
marker.filename := '/IMAGE/node.png';

Use MapArchive to directly manipulate your archive and retrieve other data.

m := TMemoryStream.Create;
try

map.MapArchive.ReadStream('DATA/mydata.txt',m);

memo1.Lines.LoadFromStream(m);

finally
m.Free;
end;

MapArchiveCreator

This small utility allows you to create your archives, you can download areas of tiles, save routes, add images and files.

Fig. 4 MapArchiveCreator

You can ban any internet connection for the tiles and geocoding using the property OnlyLocal

3
// tiles and geocoding only uses local cache and local archive
map.onlyLocal := true;

Download full a zone

The TECDownLoadTiles class allows you to download in the background one complete zone, the EcNativeMapFiremonkeyDemo shows you how to preload the viewable area on the screen.

FECDownLoadTiles:=TECDownLoadTiles.create;

FECDownLoadTiles.OnDownLoad := doDownLoadtiles;
FECDownLoadTiles.OnEndDownLoad := doEndDownLoadtiles;

// tiles are saved in DirectoryTiles
FECDownLoadTiles.DirectoryTiles := map.LocalCache;

FECDownLoadTiles.TileServer := map.TileServer;
FECDownLoadTiles.TileSize := map.TileSize;

// download visible area from zoom+1 to MaxZoom

FECDownLoadTiles.DownLoadTiles(map.Zoom+1,map.MaxZoom,
map.NorthEastLatitude,map.NorthEastLongitude,
map.SouthWestLatitude,map.SouthWestLongitude);

...


// for abort
FECDownLoadTiles.Cancel;

// for pause
FECDownLoadTiles.Pause := true;
// restart
FECDownLoadTiles.Pause := false;

// see ECNativeMapFiremokeyDemo for complete use

Make sure that your provider of tile allows it !

3

Resume downloading later

You must save the following properties to be able to resume downloading at a specific location.

property StartX : integer
property StartY : integer
property StartZoom : byte
property StartCountTiles : integer
property StartDownLoadTiles : integer
property FromZoom : integer
property ToZoom : Integer
property NorthEastLatitude : double
property NorthEastLongitude : double
property SouthWestLatitude : double
property SouthWestLongitude : double

For the restart you will need to call this version of DownLoadTiles

procedure TECDownLoadTiles.DownLoadTiles(const FromZoom, ToZoom: Integer;
const NorthEastLatitude, NorthEastLongitude,
SouthWestLatitude,SouthWestLongitude: double;
const StartX,StartY:integer;
const StartZoom:byte;
const StartCountTiles,
StartDownLoadtiles:integer);

Fill the Stream of tiles

You can also directly return a stream containing the jpeg or png of your tiles, useful if you have your tiles in a database.

// manual management tiles as stream
map.TileServerInfo.getTileStream := getTileStream;
// the name will be uses as subdirectory in cache
map.TileServerInfo.Name := 'MyMAP';
// important to specify a manual management tiles
map.TileServer := tsOwnerDraw;



// asks for a tile
procedure TForm2.getTileStream(const ThreadIndex:integer;var TileStream: TMemoryStream;
const x, y, z: integer);
begin
// here fill tileStream with tileXYZ
end;


Also allows to use a Server's remote tiles.

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