Sign in Join
Wiki copytemporary

LazMapViewer: what changed

Revision 3 to 4. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-[Template:LazMapViewer](</index.php?title=Template:LazMapViewer&action=edit&redlink=1> "Template:LazMapViewer \(page does not exist\)")
1+[[Template:LazMapViewer]]
22
33[![lazmapviewer.png](/wiki-images/1/12/lazmapviewer.png)](</File:lazmapviewer.png>)
44
55Map provider: [OpenStreatMap Mapnik](<https://www.openstreetmap.org>), [Open Data Commons Open Database License](<https://opendatacommons.org/licenses/odbl/>)
66
77## About
88
99**LazMapViewer** is a component for embedding maps obtained from the internet, such as Google maps or OpenStreetView, into a Lazarus form.
1010
1111The initial version of the package was written by Maciej Kaczkowski and later improved by members of the Lazarus forum. The package is currently maintained by Werner Pamler (wp_xxyyzzz-at-gmx-dot-net).
1212
1313License: Modified LGPL (with linking exception, like Lazarus LCL).
1414
1515## Download and Installation
1616
1717### Development version
1818
1919**Download**
2020
2121Use an SVN client to download the current trunk version from <svn://svn.code.sf.net/p/lazarus-ccr/svn/components/lazmapviewer>.
2222
2323Alternatively download the zipped snapshot from <https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/lazmapviewer/> and unpack it to some folder.
2424
2525**Installation**
2626
2727In Lazarus, go to "Package" > "Open Package File .lpk". Navigate to the folder with the LazMapViewer sources, and select `lazmapviewerpkg.lkp`. Click "Compile", then "Use" > "Install". This will rebuild the IDE (it may take some time). When the process is finished the IDE will restart, and you'll find the new components on the palette **MapViewer**.
2828
2929There are optional, supporting packages to extend the basic functionality. They must be installed in the same way, after `lazmapviewerpkg.lpk`.
3030
3131Package file name | Contained components | Purpose
3232---|---|---
3333lazmapviewerpkg.lpk | TMapView | Main component to display maps
3434| TMvDEFpc | Default download engine using the internal fpc routines (fphttpclient).
3535| TMvDECache | Offline-only access to map tiles
3636| TMvPluginManager | Extends the functionality of TMapView by plugins
3737| TMvGeoNames | Access to geo coordinates of cities
3838lazmapviewer_synapse.lpk | TMvDESynapse | Alternative download engine based on the [[Synapse]] library which must be installed first.
3939lazmapviewer_rgbgraphics.lpk | TMvRGBGraphicsDrawingEngine | Alternative drawing engine utilizing the [[LazRGBGraphics]] package which must be installed first.
4040lazmapviewer_bgra.lpk | TMvBGRADrawingEngine | Alternative drawing engine based on the [[BGRABitmap]] package which must be installed first.
4141
4242### Release version
4343
4444Occasionally, release versions are made available via the [[Online Package Manager]] for easy one-click-installation directly from Lazarus: Just check the package (and the sub-packages needed) in the OPM window and click on the "Install" button.
4545
4646### Requirements
4747
4848Release v1.0.2 was tested successfully on Windows, Linux gtk2/gtk3/qt5/qt6, macOS Cocoa with Lazarus/FPC combinations from current Laz 4.99/FPC 3.3.1 back to Laz 2.0.10/FPC 3.2.0.
4949
5050### Version changes
5151
5252 * **Version 1.1**
5353 * Translation (i18n) enabled
5454 * **Version 1.0**
5555 * Signficantly improved graphics engine
5656 * Overlay layers
5757 * Adding layers, points of interest, tracks and areas at designtime
5858 * Plugin architecture
5959 * **Version 0.x**
6060 * Initial commits
6161 * Several drawing and download engines
6262
6363## The Main Map Viewer: TMapView
6464
6565### Getting Started
6666
6767Here is a short tutorial to create your first map.
6868
6969#### Preparation
7070
7171 * Drop a `TMapView` component on the form and size it as needed. The component is on the _MapViewer_ tab of the Lazarus component palette.
7272 * With the `MapView` selected in the object inspector, pick one of the items from the `MapProvider` combobox, and set the `Active` property to `true` \- after a short time of loading you'll see your first map!
7373 * In the background the `MapView` component has established an internet connection to the specified map provider and downloaded the default map. The maps are delivered as a series of **tiled images** at given size, usually 256x256 pixels in png or jpeg format.
7474 * When property `CacheOnDisk` is set to `true` the tile images are stored in a cache directory and used primarily to reduce internet traffic; only when an image is not found another download from the internet is triggered again. Depending on the `CacheLocation` property the cache can be set up to be in the user profile (`clProfile`), the temp (`clTemp`) or a custom directory (`clCustom`, path `CachePath`).
7575 * It is recommended to turn off the `Active` property during normal work because the time to load the form with the `MapView` sometimes can be annoyingly long. In order to see the map at run time, you should add the following handler for the form's `OnShow` or `OnActivate` event and set the `Active` there:
7676
7777```
7878procedure TForm1.FormActivate(Sender: TObject);
7979 begin
8080 MapView1.Active := true;
8181 end;
8282```
8383
8484 * Another important optimization is to make sure that the `UseThreads` property is `true`. This delegates downloading and drawing to several tasks and considerably speeds up viewing of the maps.
8585 * That's all. Compile, run and see your fist map! Use the left mouse button to drag the map to another location, and rotate the mouse wheel to change the magnfication.
8686
8787#### Magnification
8888
8989 * The map images are provided in different magnifications depending on the `Zoom` level of the `MapView`. Each step in `Zoom` level corresponds to doubling the magnification. The lowest zoom level (`0`) displays the entire world in a single tile, level `1` holds a quarter in each tile, etc. The maximum `Zoom` level for most map providers is 18 -- this means that the most detailed maps cover a fraction of `1/2^18` of the earth circumference, about 150 m (at the equator).
9090 * So, if you want to see **more details** you must increase the `Zoom` value of the `MapView`. You can enter the requested value in the Object Inspector at **designtime** , or add a `TScrollbar` or `TTrackbar` to the form to change the magnfication interactively by using the following simple `OnChange` event handler (set the `Max` of the bar to, say, 18:
9191
9292```
9393procedure TForm1.TrackBar1Change(Sender: TObject);
9494 begin
9595 MapView1.Zoom := TrackBar1.Position;
9696 end;
9797```
9898
9999 * Alternatively, zooming can also be achieved by rotating the **mouse wheel** provided that `mvoMouseZooming` is set in the `Options`. When `ZoomToCursor` is `true` the zoom operation is relative to the mouse cursor, otherwise to the map center.
100100
101101#### Location
102102
103103 * By default the **center of the map** is the intersection of the 0-degree meridian with the equator - which is a bit off of the coast of western Africa. In order to focus onto a different location you must specify its longitude and latitude in the `Center` property of the `MapView`. This is a `TRealPoint` record having the longitude and latitude in the `Lon` and `Lat` record elements. Alternatively you can also use the `MapCenter` propery which is accessible directly in the object inspector at designtime.
104104 * Suppose we want to zoom into Manhattan. Use your favorite search engine to determine the geo coordinates of Manhattan: Longitude = -73.985130°, Latitude = 40.758896°. Alternatively you can also use the `TGeoNames` component which comes with the LazMapViewer package and provides access to a database of the geo coordinates of a huge number of locations via internet.
105105
106106```
107107uses
108108 mvTypes;
109109 procedure TForm1.FormActivate(Sender: TObject);
110110 var
111111 P: TRealPoint;
112112 begin
113113 MapView1.Active := true;
114114 MapView1.Zoom := 13; // for the magnification used in the introductory screenshot
115115
116116 // Geo-coordinates of the map center:
117117 P.Lat := 40.758896;
118118 P.Lon := -73.985130;
119119 MapView1.Center := P;
120120
121121 // or:
122122 // MapView1.MapCenter.Latitude := 40.758896;
123123 // MapView1.Mapcenter.Longitude := -73.985130;
124124
125125 // or:
126126 // MapView1.MapCenter.RealPt := RealPoint(40.758896, -73.985130);
127127 end;
128128```
129129
130130 * In addition to specifying the location numerically you can also change the location by **dragging the map with the mouse** (with `mvoMouseDragging` set in the `Options`): Just press the left mouse button and slowly move the mouse in the direction where you want to see more details - the map will follow. But you should be aware that usually neighboring maps will have to be loaded from the internet, and, depending on the speed of your internet connection, this may make the entire action a bit sluggish.
131131 * At **designtime** , you can enter the coordinates in the `MapCenter` property of the object inspector, and when `Active` is `true` you'll get immediate feedback in the map.
132132
133133### Basic Documentation
134134
135135[![tmapview 200.png](/wiki-images/d/dd/tmapview_200.png)](</File:tmapview_200.png>)
136136
137137#### Properties
138138
139139These are the main properties of the `TMapView` component:
140140
141141 * `Active (boolean)`:
142142
143-
144-
145- Must be set to `true` before the `MapView` component can display maps.
143+Must be set to `true` before the `MapView` component can display maps.
146144
147145 * `CacheLocation` (enumeration `clProfile`, `clTemp`, `clCustom`):
148146
149-
150-
151- Determines whether the directory for the tile image cache is the user profile, the temp directory or a custom directory specified by `CachePath`
147+Determines whether the directory for the tile image cache is the user profile, the temp directory or a custom directory specified by `CachePath`
152148
153149 * `CacheMaxAge`:
154150
155-
156-
157- Is the maximum number of days after which files are reloaded from the provider. Default: quasi-infinite.
151+Is the maximum number of days after which files are reloaded from the provider. Default: quasi-infinite.
158152
159153 * `CacheOnDisk (boolean)`:
160154
161-
162-
163- When set to `true` (default) dowloaded map tiles are stored in a directory to reduce internet traffic and for faster access. It is not recommended to turn this property off. If you want to delete the cache files and directories call the method `TMapView.DeleteCacheFiles` which deletes the cache directory of the currently used map provider.
155+When set to `true` (default) dowloaded map tiles are stored in a directory to reduce internet traffic and for faster access. It is not recommended to turn this property off. If you want to delete the cache files and directories call the method `TMapView.DeleteCacheFiles` which deletes the cache directory of the currently used map provider.
164156
165157 * `CachePath (string)`:
166158
167-
168-
169- Name of the directory in which downloaded map images are buffered when `CacheLocation` is set to `clCustom`.
159+Name of the directory in which downloaded map images are buffered when `CacheLocation` is set to `clCustom`.
170160
171161 * `Cyclic (boolean)`:
172162
173-
174-
175- When switched to `true` the map is repeated at the date boundary to completely fill the width of the mapviewer.
163+When switched to `true` the map is repeated at the date boundary to completely fill the width of the mapviewer.
176164
177165 * `DownloadEngine (TMvCustomDownloadEngine)`:
178166
179-
180-
181- Determines the control which downloads the tile images from the map servers. In Windows, this is by default the `TMvDEWin` engine based on the _WinInet_ library. Linux and macOS, by default, use the `TMvDEFPC` engine which takes advantage of the `TFPHttpClient` class coming with FPC. If a different download engine is required the corresponding component can be hooked to this property. The alternative `TMvDESynapse` engine based on the _Synapse_ library can be installed as a separate component. Note that there is also a "download" engine `TMvDECache` which only loads images from the cache but does not actually access the internet - this is interesting of off-line applications. It is required that you already have pre-loaded tile images and your application covers only a small region at the highest magnification.
167+Determines the control which downloads the tile images from the map servers. In Windows, this is by default the `TMvDEWin` engine based on the _WinInet_ library. Linux and macOS, by default, use the `TMvDEFPC` engine which takes advantage of the `TFPHttpClient` class coming with FPC. If a different download engine is required the corresponding component can be hooked to this property. The alternative `TMvDESynapse` engine based on the _Synapse_ library can be installed as a separate component. Note that there is also a "download" engine `TMvDECache` which only loads images from the cache but does not actually access the internet - this is interesting of off-line applications. It is required that you already have pre-loaded tile images and your application covers only a small region at the highest magnification.
182168
183169 * `DrawingEngine (TMvCustomDrawingEngine)`:
184170
185-
186-
187- Painting of the tiled images is a speed-critical task. By default, this is done using routines from the _IntfGraphics_ unit; the corresponding drawing engine is in the `TMvInfGraphicsDrawingEngine` class. However, it is possible to provide a different drawing engine here. The standard installation of _LazMapViewer_ comes with the alternative `TMvRGBGraphicsDrawingEngine` which is based on the _RGBGraphics_ package, and with the `TMvBGRADrawingEngine` utilizing the _BGRABitmap_ package. The external libraries required must be installed from separate packages.
171+Painting of the tiled images is a speed-critical task. By default, this is done using routines from the _IntfGraphics_ unit; the corresponding drawing engine is in the `TMvInfGraphicsDrawingEngine` class. However, it is possible to provide a different drawing engine here. The standard installation of _LazMapViewer_ comes with the alternative `TMvRGBGraphicsDrawingEngine` which is based on the _RGBGraphics_ package, and with the `TMvBGRADrawingEngine` utilizing the _BGRABitmap_ package. The external libraries required must be installed from separate packages.
188172
189173 * `DrawPreviewTiles (boolean)`:
190174
191-
192-
193- When a tile currently is not available an existing tile is stretched to fit into the tile's place in the map. Otherwise, when `DrawPreviewTiles = false`, the missing tile's area is filled by the uniform background color of the `MapView`.
175+When a tile currently is not available an existing tile is stretched to fit into the tile's place in the map. Otherwise, when `DrawPreviewTiles = false`, the missing tile's area is filled by the uniform background color of the `MapView`.
194176
195177 * `Layers`:
196178
197-
198-
199- A collection of `TMapLayer` instances which can be drawn independently over the base map - see below.
179+A collection of `TMapLayer` instances which can be drawn independently over the base map - see below.
200180
201181 * `MapCenter`:
202182
203-
204-
205- A helper class needed for entering the geo coordinates of the map's center point (`MapCenter.Latitude` and `MapCenter.Longitude`) in the object inspector. When the option `mvoLatOnInDMS` is set the values can be entered in the degree-minute-second format, otherwise as standard fractional floating point numbers.
183+A helper class needed for entering the geo coordinates of the map's center point (`MapCenter.Latitude` and `MapCenter.Longitude`) in the object inspector. When the option `mvoLatOnInDMS` is set the values can be entered in the degree-minute-second format, otherwise as standard fractional floating point numbers.
206184
207185 * `MapProvider (string)`:
208186
209-
210-
211- This string identifies the provider from which the maps are downloaded. Built-in providers allow to choose between _OpenStreetMaps_ , _GoogleMaps_ , _Virtual Earth_ , _Yandex_ etc. Details are given in section Map Providers.
187+This string identifies the provider from which the maps are downloaded. Built-in providers allow to choose between _OpenStreetMaps_ , _GoogleMaps_ , _Virtual Earth_ , _Yandex_ etc. Details are given in section Map Providers.
212188
213189 * `Options`:
214190
215-
191+A set with the following elements
216192
217- A set with the following elements
218- \- `mvoMouseDragging`: Allows to enable/disable dragging of the map by the mouse. Default: on
219- \- `mvoMouseZooming`: Allows to enable/disable zooming by rotating the mouse wheel. Default: on
220- \- `mvoEditorEnabled`: Allows to edit the position of points and tracks with the mouse. Default: off
221- \- `mvoLatLonInDMS`: When set, geo coordinates can be displayed/entered in the degree-minute-seconds format, otherwise as standard float number of the degrees. Default: off
193+\- `mvoMouseDragging`: Allows to enable/disable dragging of the map by the mouse. Default: on
222194
223- * `UseThreads (boolean)`:
195+\- `mvoMouseZooming`: Allows to enable/disable zooming by rotating the mouse wheel. Default: on
224196
225-
197+\- `mvoEditorEnabled`: Allows to edit the position of points and tracks with the mouse. Default: off
226198
227- When set to `true` downloading and drawing of maps is delegated to multiple threads in order to achieve a smoother response. It is not recommended to turn this property off.
199+\- `mvoLatLonInDMS`: When set, geo coordinates can be displayed/entered in the degree-minute-seconds format, otherwise as standard float number of the degrees. Default: off
228200
229- * `Zoom (integer)`:
201+ * `UseThreads (boolean)`:
230202
231-
203+When set to `true` downloading and drawing of maps is delegated to multiple threads in order to achieve a smoother response. It is not recommended to turn this property off.
232204
233- Magnfication of the map: 0 = coarsest magnification, earth view, 17 or 18 = highest magnification. Each zoom step results in doubling of the magnfication factor.
205+ * `Zoom (integer)`:
234206
235- * `ZoomMax (integer)` and `ZoomMin`:
207+Magnfication of the map: 0 = coarsest magnification, earth view, 17 or 18 = highest magnification. Each zoom step results in doubling of the magnfication factor.
236208
237-
209+ * `ZoomMax (integer)` and `ZoomMin`:
238210
239- Specify the range in which the zoom can be varied.
211+Specify the range in which the zoom can be varied.
240212
241213 * `ZoomToCursor (boolean)`:
242214
243-
244-
245- When this is `true` zooming is relative to the mouse position, otherwise to the center of the map. This feature is interesting for zooming with the mouse wheel.
215+When this is `true` zooming is relative to the mouse position, otherwise to the center of the map. This feature is interesting for zooming with the mouse wheel.
246216
247217Here are properties related to overlayed GPS objects (points of interest, tracks):
248218
249219 * `GPSItems: TGPSObjectList`:
250220
251-
252-
253- List of GPS objects assigned to the MapView. See below for details.
221+List of GPS objects assigned to the MapView. See below for details.
254222
255223 * `DefaultTrackColor: TColor`, `DefaultTrackWidth: Integer`:
256224
257-
258-
259- The default color and line width, respectively, of overlayed tracks. See below for details.
225+The default color and line width, respectively, of overlayed tracks. See below for details.
260226
261227 * `POIImage: TBitmap`:
262228
263-
264-
265- Bitmap which will be overlayed to mark a "point of interest" (POI).
229+Bitmap which will be overlayed to mark a "point of interest" (POI).
266230
267231 * `POImages: TCustomImageList`:
268232
269-
270-
271- Image list from which images can be selected as markers for points-of-interest. Note that the _LazMapViewer_ installation comes with a large selection of POI icons in the folder _marker-images_.
233+Image list from which images can be selected as markers for points-of-interest. Note that the _LazMapViewer_ installation comes with a large selection of POI icons in the folder _marker-images_.
272234
273235 * `POITextBgColor: TColor`:
274236
275-
276-
277- Background color of the overlayed text describing a point of interest. The transparency of the background is determined by `POITextBgOpacity`. Turn off the text background by selecting `clNone` or `POITextBgOpacity = 0.0`.
237+Background color of the overlayed text describing a point of interest. The transparency of the background is determined by `POITextBgOpacity`. Turn off the text background by selecting `clNone` or `POITextBgOpacity = 0.0`.
278238
279239 * `POITextBgOpacity: Single`:
280240
281-
282-
283- Opacity of the overlayed text background of a point of interest for better readability. The floating point value is expected to be between 0.0 (fully transparent) and 1.0 (fully opacque). Default: 0.55
241+Opacity of the overlayed text background of a point of interest for better readability. The floating point value is expected to be between 0.0 (fully transparent) and 1.0 (fully opacque). Default: 0.55
284242
285243#### Events
286244
287245 * `OnAfterDrawObjects, OnBeforeDrawObjects`:
288246
289-
290-
291- Events which are executed after/before overlay objects of the map (points of interest, tracks) are drawn.
247+Events which are executed after/before overlay objects of the map (points of interest, tracks) are drawn.
292248
293249 * `OnAfterDrawTile`:
294250
295-
296-
297- Comes after a tile has been painted. Helpful for custom-drawing information about this specific tile since the event has the tile's x and y indices, as well as the zoom level as a parameter in the `TileID` record.
251+Comes after a tile has been painted. Helpful for custom-drawing information about this specific tile since the event has the tile's x and y indices, as well as the zoom level as a parameter in the `TileID` record.
298252
299253 * `OnAfterPaint`:
300254
301-
302-
303- Is triggered after the map has been drawn completely.
255+Is triggered after the map has been drawn completely.
304256
305257 * `OnCenterMove`:
306258
307-
308-
309- Fires whenever the `Center` of the `MapView` have been changed.
259+Fires whenever the `Center` of the `MapView` have been changed.
310260
311261 * `OnCenterMoving`:
312262
313-
314-
315- Is executed before a request to move the map center is handled. It has parameters `NewCenter` and `Allow` which can be used to restrict panning to a given region only (useful for off-line mode).
263+Is executed before a request to move the map center is handled. It has parameters `NewCenter` and `Allow` which can be used to restrict panning to a given region only (useful for off-line mode).
316264
317265 * `OnChange`:
318266
319-
320-
321- Fires whenever the `Center`, size or `Zoom` factor of the `MapView` change.
267+Fires whenever the `Center`, size or `Zoom` factor of the `MapView` change.
322268
323269 * `OnDrawEditMark`:
324270
325-
326-
327- Can be used to override painting of the mark which is currently edited. By default, the edited mark is a red square with green background.
271+Can be used to override painting of the mark which is currently edited. By default, the edited mark is a red square with green background.
328272
329273 * `OnDrawGpsPoint`:
330274
331-
332-
333- See below.
275+See below.
334276
335277 * `OnDrawMissingTile`:
336278
337-
338-
339- Can be used primarily to custom-paint the background of missing tiles when `DrawPreviewTiles` is `false`. It is also helpful when the tiles contain (semi-) transparent areas where the background is supposed to shine through.
279+Can be used primarily to custom-paint the background of missing tiles when `DrawPreviewTiles` is `false`. It is also helpful when the tiles contain (semi-) transparent areas where the background is supposed to shine through.
340280
341281 * `OnEditStartDrag`, `OnEditEndDrag`, `OnEditDrag`, `OnEditSelectionCompleted`, `OnEditIsDirty`:
342282
343-
344-
345- Are mainly used for internal communication between mapview and editmark during editing.
283+Are mainly used for internal communication between mapview and editmark during editing.
346284
347285 * `OnKeyDown`, `OnKeyPress`, `OnKeyUp`: standard keyboard events inherited from `TControl`. Useful, for example, if you want to move the map center by the keyboard.
348286 * `OnMouseDown`, `OnMouseUp`:
349287
350-
351-
352- Standard mouse events inherited from `TControl` fired when a mouse button is clicked.
288+Standard mouse events inherited from `TControl` fired when a mouse button is clicked.
353289
354290 * `OnMouseEnter`, `OnMouseLeave`:
355291
356-
357-
358- standard mouse events inherited from `TControl` fired when the mouse is moved into/out of the map
292+standard mouse events inherited from `TControl` fired when the mouse is moved into/out of the map
359293
360294 * `OnResize`:
361295
362-
363-
364- Becomes active after the size of the map window has changed.
296+Becomes active after the size of the map window has changed.
365297
366298 * `OnZoomChange`:
367299
368-
369-
370- Fires whenever the `Zoom` factor of the `MapView` changes.
300+Fires whenever the `Zoom` factor of the `MapView` changes.
371301
372302 * `OnZoomChanging`:
373303
374-
375-
376- Is executed before a request to change to magnification is handled. It has parameters `ANewZoom` and `Allow` which can be used to restrict zooming only to specific ranges.
304+Is executed before a request to change to magnification is handled. It has parameters `ANewZoom` and `Allow` which can be used to restrict zooming only to specific ranges.
377305
378306#### Main methods
379307
380308 * `procedure GetMapProviders(lstProviders: TStrings)`:
381309
382-
383-
384- Returns in `lstProviders` the names of all registered map providers. When one of these strings is assigned to the `MapProvider` property of the `MapVieew` the servers of the corresponding provider will become the source of the displayed maps.
310+Returns in `lstProviders` the names of all registered map providers. When one of these strings is assigned to the `MapProvider` property of the `MapVieew` the servers of the corresponding provider will become the source of the displayed maps.
385311
386312 * `function GetVisibleArea: TRealArea`:
387313
388-
389-
390- Returns the top/left and bottom/right corner points of the displayed rectangle in geo coordinates. `TRealArea` is a record consisting of the `TRealPoint` records `TopLeft` and `BottomRight` (`TRealPoint = record Lon, Lat: Double`).
314+Returns the top/left and bottom/right corner points of the displayed rectangle in geo coordinates. `TRealArea` is a record consisting of the `TRealPoint` records `TopLeft` and `BottomRight` (`TRealPoint = record Lon, Lat: Double`).
391315
392316 * `function LatLonToScreen(aPt: TRealPoint): TPoint`:
393317
394-
395-
396- Maps a geo point (latitude, longititude) to screen pixels (relative to the `TMapView` instance).
318+Maps a geo point (latitude, longititude) to screen pixels (relative to the `TMapView` instance).
397319
398320 * `function ScreenToLatLon(aPt: TPoint): TRealPoint`:
399321
400-
401-
402- Maps the coordinates of a screen pixel (relative to the `MapView` instance) to geo coordinates (latitude, longitude). Here is an example how the geo coordinates of the mouse cursor can be updated in two labels by means of the `OnMouseMove` event of the `MapView`:
322+Maps the coordinates of a screen pixel (relative to the `MapView` instance) to geo coordinates (latitude, longitude). Here is an example how the geo coordinates of the mouse cursor can be updated in two labels by means of the `OnMouseMove` event of the `MapView`:
403323```
404324uses
405325 mvTypes, // for TRealPoint
406326 mvEngine; // for LonToStr() and LatToStr() funtions
407327
408328 procedure TForm1.MapView1MouseMove(Sender: TObject; Shift: TShiftState;
409329 X, Y: Integer);
410330 var
411331 P: TRealPoint;
412332 begin
413333 P := MapView1.ScreenToLatLon(Point(X, Y));
414334 Label1.Caption := 'Longitude: ' + LonToStr(P.Lon, true);
415335 Label2.Caption := 'Latitude: ' + LatToStr(P.Lat, true);
416336 end;
417337```
418338
419339 * `procedure SaveToFile(AClass: TRasterImageClass; const AFileName: String)`:
420340
421-
422-
423- Save the currently displayed map as bitmap of the given class to a file. Example for saving to a jpg image:
341+Save the currently displayed map as bitmap of the given class to a file. Example for saving to a jpg image:
424342```
425343procedure TForm1.Button1Click(Sender: TObject);
426344 begin
427345 MapView1.SaveToFile(TJpegImage, 'mapview.jpg');
428346 end;
429347```
430348
431349 * `procedure SaveToStream(AClass: TRasterImageClass; AStream: TStream)`:
432350
433-
434-
435- Similar to `SaveToFile`, but output is not in a file, but in the stream provided.
351+Similar to `SaveToFile`, but output is not in a file, but in the stream provided.
436352
437353 * `function SaveToImage(AClass: TRasterImageClass): TRasterImage`:
438354
439-
440-
441- Creates an instance of the given image class and writes the currently visible view port image to it.
355+Creates an instance of the given image class and writes the currently visible view port image to it.
442356
443357 * `procedure CenterOnObj(obj: TGPSObj)`:
444358
445-
446-
447- Centers the map on the provided GPS object. More on GPS objects below.
359+Centers the map on the provided GPS object. More on GPS objects below.
448360
449361 * `function CyclicPointsOf(APoint: TPoint): TPointArray`:
450362
451-
452-
453- Calculates the positions of specified screen point which appear on the reapeted maps in "cyclic" mode.
363+Calculates the positions of specified screen point which appear on the reapeted maps in "cyclic" mode.
454364
455365 * `procedure ZoomOnArea(const aArea: TRealArea)`:
456366
457-
458-
459- Adjusts the `Zoom` level such that the given area is completely shown and fills the component bounds as much as possible.
367+Adjusts the `Zoom` level such that the given area is completely shown and fills the component bounds as much as possible.
460368
461369 * `procedure ZoomOnObj(obj: TGPSObj)`:
462370
463-
464-
465- Adjusts the `Zoom` level such that the given GPS object is completely seen at highest magnification. More about GPS objects below.
371+Adjusts the `Zoom` level such that the given GPS object is completely seen at highest magnification. More about GPS objects below.
466372
467373 * `function ObjsAtScreenPt(X, Y: Integer; ATolerance: Integer = -1; AClass: TGPSObjClass = nil): TGPSObjArray`:
468374
469-
470-
471- Returns an array of all GPS objects found within the given tolerance (in pixels) at the screen point X, Y. The search can be restricted to a specified class of GPS objects (e.g. `TGPSPointOfInterest` only).
375+Returns an array of all GPS objects found within the given tolerance (in pixels) at the screen point X, Y. The search can be restricted to a specified class of GPS objects (e.g. `TGPSPointOfInterest` only).
472376
473377 * `function VisibleObjsAtScreenPt(X, Y: Integer; ATolerance: Integer = -1; AClass: TGPSObjClass = nil): TGPSObjArray`:
474378
475-
476-
477- Similar to `ObjsAtScreenPt`, but only visible objects are considered.
379+Similar to `ObjsAtScreenPt`, but only visible objects are considered.
478380
479381 * `function VisiblePointsAtScreenPt(X, Y: Integer; ATolerance: Integer = -1; APointTypes: TMvPointTypes = ptAll): TGPSObjArray`:
480382
481-
482-
483- Similar to `VisibleObjsAtScreenPt`, but now both GPS-type and map-type of points are found (`TMvPointType = (ptGPSPointOfInterest, ptGPSTrackPoint, ptGPSAreaPoint, ptMapPointOfInterest, ptMapTrackPoint, ptMapAreaPoint)`, see below).
383+Similar to `VisibleObjsAtScreenPt`, but now both GPS-type and map-type of points are found (`TMvPointType = (ptGPSPointOfInterest, ptGPSTrackPoint, ptGPSAreaPoint, ptMapPointOfInterest, ptMapTrackPoint, ptMapAreaPoint)`, see below).
484384
485385 * `function VisiblePointsInArea(Area: TRealArea; APointTypes: TMvPointTypes = ptAll): TGPSObjArray`:
486386
487-
488-
489- Similar to `VisiblePointsAtScreenPt`, but now an area in geo coordinates is search for the points rather than the vicinity of a screen point.
387+Similar to `VisiblePointsAtScreenPt`, but now an area in geo coordinates is search for the points rather than the vicinity of a screen point.
490388
491389### Map Providers
492390
493391The `MapView` component can display maps from various providers. To activate a given provider its name must be specified in the `MapProvider` property of the component.
494392
495393Here is a list of the names of the built-in map providers:
496394
497395 * OpenStreetMap Mapnik ([Open Data Commons Open Database License](<https://opendatacommons.org/licenses/odbl/>), copyright <https://www.openstreetmap.org/copyright/en>; the introductory screenshot uses a map of this provider)
498396 * OpenStreetMap Wikipedia
499397 * OpenStreetMap Sputnik
500398 * OpenStreetMap.fr Hot
501399 * OpenStreetMap.fr Cycle Map
502400 * Open Topo Map
503401 * Google Maps (Terms and conditions: <https://www.google.com/intl/en_en/help/terms_maps/>)
504402 * Google Satellite
505403 * Yandex.Maps (Terms and conditions: <https://yandex.ru/legal/maps_termsofuse/index.html>)
506404 * Yandex.Maps Satellite
507405 * Virtual Earth Bing
508406 * Virtual Earth Aerial
509407 * Virtual Earth Hybrid
510408
511409The following providers require an API key to access their service. The API key can be obtained by registering at the provider sites. Usually the API keys are free, however, a charge may be required for commercial usage - please see the details on the provider sites. The strings received as API keys must be stored in global variables of your application.
512410
513411 * **Thunderforest maps** : Registration at <https://www.thunderforest.com/docs/apikeys/>, store API key in the variable `ThunderForest_ApiKey` (Terms and conditions: <https://www.thunderforest.com/terms/>)
514412 * ThunderForest Open Cycle Map
515413 * ThunderForest OpenStreetMap Transport
516414 * ThunderForest Neighbourhood
517415 * ThunderForest Atlas
518416 * ThunderForest Pioneer
519417 * ThunderForest Outdoors
520418 * ThunderForest Landscape
521419 * ThunderForest Mobile-Atlas
522420 * ThunderForest Transport-Dark
523421 * ThunderForest Spinal-Map
524422 * **Stadia maps** : Registration at <https://client.stadiamaps.com>, store the API key in the variable `StadiaMaps_ApiKey` (Terms and coditions: <https://stadiamaps.com/terms-of-service/>)
525423 * Stadia Alidate Smooth
526424 * Stadia Alidate Smooth Dark
527425 * Stadia Alidate Satellite
528426 * Stadia Outdoors
529427 * Stadia Stamen Toner
530428 * Stadia Stamen Terrain
531429 * Stadia OSM Bright
532430 * **Here WeGo maps** : Registration at [https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account](<https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account>), store the received APP ID and APP CODE in the variables `HERE_AppID` and `HERE_AppCode`, respectively. Terms and conditions: <https://legal.here.com/us-en/terms/here-end-user-terms>
533431 * Here WeGo Map
534432 * Here WeGo Grey Map
535433 * Here WeGo Reduced Map
536434 * Here WeGo Transit Map
537435 * Here WeGo POI Map
538436 * Here WeGo Pedestrian Map
539437 * Here WeGo DreamWorks Map
540438 * **OpenWeatherMap** : Registration at <https://home.openweathermap.org/users/sign_up>, store the API Key in variable `OpenWeatherMap_ApiKey`:
541439 * OpenWeatherMap Clouds
542440 * OpenWeatherMap Precipitation
543441 * OpenWeatherMap Pressure
544442 * OpenWeatherMap Temperature
545443 * OpenWeatherMap Wind
546444
547445More providers can be found in the include file _mvengine_mapreg.inc_.
548446
549447Please respect the license requirements of the map providers.
550448
551449### The Drawing Engine
552450
553451For flexible output, all the drawing operations are handled by a dedicated class, the "drawing engine". The basic ancestor is `TMvCustomDrawingEngine` which provides methods for the elemental drawing operations, such as drawing (scaled) bitmaps, writing text, drawing graphics primitives (line, polygon, rectangle, ellipse). This is similar to what `TCanvas` does in the LCL, but it is more general because basically any graphics library can be interfaced to the mapviewer.
554452```
555453type
556454 TMvCustomDrawingEngine = class(TComponent)
557455 public
558456 function GetCacheItemClass: TPictureCacheItemClass; virtual; abstract;
559457 procedure CreateBuffer(AWidth, AHeight: Integer); virtual; abstract;
560458 procedure DrawBitmap(X, Y: Integer; ABitmap: TCustomBitmap; UseAlphaChannel: Boolean); virtual; abstract;
561459 procedure DrawCacheItem(X, Y: Integer; AImg: TPictureCacheItem; ADrawMode: TItemDrawMode = idmDraw; AOpacity: Single = 1.0); virtual; abstract;
562460 procedure DrawScaledCacheItem(DestRect, SrcRect: TRect; AImg: TPictureCacheItem); virtual; abstract;
563461 procedure Ellipse(X1, Y1, X2, Y2: Integer); virtual; abstract;
564462 procedure FillPixels(X1, Y1, X2, Y2: Integer; AColor: TColor); virtual; abstract;
565463 procedure FillRect(X1, Y1, X2, Y2: Integer); virtual; abstract;
566464 function GetFont: TMvFont;
567465 function GetPen: TMvPen;
568466 procedure Line(X1, Y1, X2, Y2: Integer); virtual; abstract;
569467 procedure Polyline(const Points: array of TPoint); virtual; abstract;
570468 procedure Polygon(const Points: array of TPoint); virtual; abstract;
571469 procedure PolyBezier(const Points: array of TPoint; Filled: Boolean = False; Continuous: Boolean = True); virtual; abstract;
572470 procedure PaintToCanvas(ACanvas: TCanvas); overload;
573471 procedure PaintToCanvas(ACanvas: TCanvas; Origin: TPoint); overload; virtual; abstract;
574472 procedure Rectangle(X1, Y1, X2, Y2: Integer); virtual; abstract;
575473 function SaveToImage(AClass: TRasterImageClass): TRasterImage; virtual; abstract;
576474 procedure SetFont(AFont: TMvFont);
577475 procedure SetFont(AFontName: String; AFontSize: Integer; AFontStyle: TFontStyles; AFontColor: TColor);
578476 procedure SetPen(APen: TMvPen);
579477 procedure SetPen(APenStyle: TPenStyle; APenWidth: Integer; APenColor: TColor);
580478 function TextExtent(const AText: String): TSize; virtual; abstract;
581479 function TextHeight(const AText: String): Integer;
582480 procedure TextOut(X, Y: Integer; const AText: String); virtual; abstract;
583481 function TextWidth(const AText: String): Integer;
584482
585483 property BrushColor: TColor read GetBrushColor write SetBrushColor;
586484 property BrushStyle: TBrushStyle read GetBrushStyle write SetBrushStyle;
587485 property FontColor: TColor read GetFontColor write SetFontColor;
588486 property FontName: String read GetFontName write SetFontName;
589487 property FontSize: Integer read GetFontSize write SetFontSize;
590488 property FontStyle: TFontStyles read GetFontStyle write SetFontStyle;
591489 property PenColor: TColor read GetPenColor write SetPenColor;
592490 property PenStyle: TPenStyle read GetPenStyle write SetPenStyle;
593491 property PenWidth: Integer read GetPenWidth write SetPenWidth;
594492 property Opacity: Single read GetOpacity write SetOpacity;
595493 end;
596494```
597495
598496Since an arbitrary graphics engine does not store images in the LCL classes (TBitmap etc) a more general `TPictureCacheItem` class was introduced which must be implemented by each drawing engine class.
599497
600498The default drawing engine is `TMvIntfImageDrawingEngine` which is based on the routines of `FCL-Image` and `TLazIntfImage`. It does not require installation of any third-party packages because everything comes with Lazarus and FPC. However, drawing may be a bit sluggish from time to time. Better performance can be achieved with the `TMvRGBGraphicsDrawingEngine` or with the `TMvBGRADrawingEngine`; they require installation of the _RGBGraphics_ or _BGRABitmap_ packages, respectively. They are external, but can be installed from the Online-Package-Manager. Note that the `TMvRGBGraphicsDrawingEngine` currently (Sept 2025) has rendering issues (false colors, image upside-down) for the cocoa widgetset (mac OS).
601499
602500### Map Overlays
603501
604502`TMapView` is able to overlay various objects on the basic map discussed so far: Points of interest, tracks, areas, even other tile maps. For historical reasons, this can be achieved at two levels of access: \- a RAD-like approach at designtime in the Object Inspector (`TMapXXX` classes) \- a more direct approach requiring some code (`TGPSXXX` classes)
605503
606504#### Basic overlay architecture
607505
608506##### Classes
609507
610508The public `TMapView` property `GPSItems` collects data on points of interest and tracks to be overlayed on the map. The common ancestor type of these overlay items is **`TGPSObj`** :
611509```
612510type
613511 TGPSObj = class
614512 ...
615513 public
616514 destructor Destroy; override;
617515 property Name: String read FName write FName;
618516 property ExtraData: TObject read FExtraData write SetExtraData;
619517 property IdOwner: Integer read FIdOwner;
620518 property BoundingBox: TRealArea read GetBoundingBox write SetBoundingBox;
621519 property Visible: Boolean read FVisible write FVisible;
622520 property ZOrder: Integer read FZOrder;
623521
624522 end;
625523```
626524
627525 * The `Name` can be displayed near the item in the map.
628526 * `ExtraData` can be used freely, for example to define the color of a track. An example how this could be done is found in unit `mvExtraData`, classes `TDrawingExtraData` and `TTrackExtraData`.
629527 * `IdOwner` is the ID of the owner TGPSObj instance to which the current item belongs.
630528 * `BoundingBox` gives the geo coordinates of the top/left and bottom/right corner points of the rectangle over which the object extends.
631529 * `Visible` allows to show/hide a `TGPSObj` instance.
632530 * `ZOrder` determines the order in which various `TGPSObj` instances are drawn.
633531
634532A specialized `TGPSObj` class is a **`TGPSPoint`** , for example a scenic "Point-of-Interest" (POI), a way point along a hiking path etc.
635533```
636534TGPSPoint = class(TGPSObj)
637535 public
638536 constructor Create(ALon,ALat: double; AEle: double=NO_ELE; ADateTime: TDateTime=NO_DATE);
639537 class function CreateFrom(aPt: TRealPoint): TGPSPoint;
640538
641539 function HasEle: boolean;
642540 function HasDateTime: Boolean;
643541 function DistanceInKmFrom(OtherPt: TGPSPoint; UseEle: boolean=true): double;
644542
645543 property Lon: Double read GetLon;
646544 property Lat: Double read GetLat;
647545 property Ele: double read FEle;
648546 property DateTime: TDateTime read FDateTime;
649547 property RealPoint: TRealPoint read FRealPt;
650548 end;
651549```
652550
653551In its constructor, the geo coordinates longitude and latitude must be specified. They are also available as read-only properties `Lon` and `Lat`, as well as a record `RealPoint`. Optional parameters are the elevation of the point (property `Ele` as well as some date/time information (property `DateTime`), for example the date and time when this point was visited. A special function, `DistanceInKmFrom`, is available to calculate the on-earth distance from another GPS point.
654552
655553**`TGPSPointOfInterest`** is a further specialization of `TGPSPoint`. It provides an `ImageIndex` property to select a marker image from the `TMapView`'s `POIImages`:
656554```
657555type
658556 TGPSPointOfInterest = class(TGPSPoint)
659557 public
660558 property ImageIndex: Integer read FImageIndex write FImageIndex default -1;
661559 end;
662560```
663561
664562A sequence of `TGPSPoint` instances sets up a **`TGPSPolyLine`** , like a polygon. The individual vertices are collected in the list `Points`. The `TGPSPolyLine` provides the method `GetArea` to determine the enclosing rectangle `Area` (`TRealArea` is a record with the top/left and bottom/right corner points in geo coordinates).
665563```
666564type
667565 TGPSPolyLine = class(TGPSObj)
668566 private
669567 FPoints: TGPSPointList;
670568 function GetAllObjs: TGPSObjEnumerator; override;
671569 public
672570 constructor Create;
673571 destructor Destroy; override;
674572 procedure GetArea(out Area: TRealArea); override;
675573 property Points: TGPSPointList read FPoints;
676574 end;
677575```
678576
679577The descendant class **`TGPSTrack`** inherits the `Points` property which is to be understood as the points along a path, for example points of a hike. There is also a `DateTime` property usable for example to hold the date of the hike; by default it is taken from the `DateTime` value of the first track point. The function `TrackLengthInKm` calculates the length of the entire path with the points being connected by straight line segments. There are also properties to determine the order the track is painted on the map:
680578```
681579type
682580 TGPSTrack = class(TGPSPolyLine)
683581 public
684582 function TrackLengthInKm(UseEle: Boolean=true): double;
685583 property DateTime: TDateTime read GetDateTime write FDateTime;
686584 property LineColor: TColor read FLineColor write FLineColor;
687585 property LineWidth: Double read FLineWidth write FLineWidth;
688586 property ConnectColor: TColor read FConnectColor write FConnectColor;
689587 property ConnectWidth: Double read FConnectWidth write FConnectWidth;
690588 property Opacity: Single read FOpacity write FOpacity;
691589 end;
692590```
693591
694592There is also a **`TGPSArea`** which is a closed polygon (`TGPSLine`) and can be filled by a specified color. Note the parameter `Opacity` for semitransparent rendering so that the underlying map shines through. The user can take advantage of this feature to highlight some areas in the original map.
695593```
696594type
697595 TGPSArea = class(TGPSPolyLine)
698596 public
699597 property FillColor: TColor read FFillColor write FFillColor;
700598 property LineColor: TColor read FLineColor write FLineColor;
701599 property LineWidth: Double read FLineWidth write FLineWidth;
702600 property Opacity: Single read FOpacity write FOpacity;
703601 end;
704602```
705603
706604The **`TGPSTileLayer`** , finally, which also descends from `TGPSObj`, is able to display an entire map of tiles, just like the `TMapView`. It can have its own setting for the `MapProvider` and the `UseThreads` property. The enumerated property `DrawMode` determines the way how the layer is drawn over the background:
707605
708606 * `idmDraw` \- fully overwrites the background
709607 * `idmUseOpacity` \- uses the `Opacity` value (a `single` between `0`=transparent) and `1`=opaque) for semi-transparent rendering
710608 * `idmUseSourceAlpha` \- some map providers deliver tile images with alpha channel, e.g. _OpenRailwayMap_ which only contains the tracks of railway lines on a transparent background. In this setting the overlay map is perfectly mixed with the background map.
711609
712610```
713611type
714612 TGPSTileLayer = class(TGPSTileLayerBase) // TGPSTileLayerBase inherits from TGPSObj
715613 public
716614 // all the following properties are inherited from the ancestor, TGPSTileLayerBase
717615 property MapProvider; // String
718616 property DrawMode; // TItemDrawMode = (idmDraw, idmUseOpacity, idmUseSourceAlpha)
719617 property Opacity; // Single
720618 property UseThreads; // boolean
721619```
722620
723621All these GPS objects are be stored in a **`TGPSObjectList`** :
724622```
725623type
726624 TGPSObjectList = class(TGPSObj)
727625 ...
728626 constructor Create;
729627 destructor Destroy; override;
730628 Procedure ClearAll;
731629 Procedure Clear(OwnedBy: integer);
732630 procedure ClearExcept(OwnedBy: integer; const ExceptLst: TIdArray; out Notfound: TIdArray);
733631 procedure GetArea(out Area: TRealArea); override;
734632 function GetObjectsInArea(const Area: TRealArea): TGPSObjList;
735633 function GetIdsArea(const Ids: TIdArray; AIdOwner: integer): TRealArea;
736634
737635 function Add(aItem: TGpsObj; AIdOwner: integer; AZOrder: integer = 0): integer;
738636 function ChangeZOrder(AItem: TGPSObj; ANewZOrder: Integer): Integer;
739637 procedure Delete(AObj: TGPSObj);
740638 procedure DeleteById(const Ids: Array of integer);
741639 function FindTrackById(const ID: Integer): TGPSTrack;
742640
743641 procedure BeginUpdate;
744642 procedure EndUpdate;
745643
746644 property Count: integer read GetCount;
747645 property Items[AIndex: Integer]: TGpsObj read GetItem; default;
748646
749647 property OnModified: TModifiedEvent read FOnModified write FOnModified;
750648 end;
751649```
752650
753651Objects can be added to the list by calling the `Add` method. Since each addition is accompanied by a repaint of the `MapView` you should call `BeginUpdate` before and `EndUpdate` after adding the objects. Every added object must be accompanied by an arbitrary numeric ID which is used to group similar objects.
754652
755653Method `DeleteByID` deletes all objects sharing the same ID. `Clear`, on the other hand, clears all the objects which are owned by object having the specified ID. An extension is `ClearExcept` which does the same but skips IDs listed in the `ExceptLst` array. Clearing a list with many objects, may take a painful long time, caused by the internal notification handling. The methode `ClearAll` will shorten this time to a minimum, by the price of lacking the notification, which may, if used, cause exception on accessing deleted items. So if using this method, make sure all other instances (e.g. marker-related plugins) which access the list are treated subsequently.
756654
757655`GetObjectsInArea` creates a TFPObjectlist (of type `TGpsObjList` here) with all the objects enclosed by the given rectangle (`Area`). `GetIDsArea`, conversely, returns the rectangle enclosing all the objects with the IDs listed in parameter `IDs` (which is a simple array here).
758656
759657The `TMapView` component provides 10 pre-allocated `TGPSObjectList` instances which are accessible via the array property `GPSLayer[L: Integer]`. They serve like a stack of layers drawn the in order of their Z value (see `TGPSObj`). For historic reasons, the center layer `GPSLayer[5]` is also made available as property `GPSItems`.
760658
761659##### Examples
762660
763661###### Adding a point-of-interest
764662
765663Suppose you want to mark a special point in the map by a mouse click and identify it with some descriptive text. Write a handler for the OnMouseUp event in which you query the description and then take the pixel coordinates of the clicked point, convert it to geo coordinates and create a `TGpsPoint` from it which you add to the `GpsItems` of the `MapView`:
766664```
767665uses
768666 mvTypes, mvGPSObj;
769667
770668 const
771669 _POI_ = 10;
772670
773671 procedure TForm1.MapView1MouseUp(Sender: TObject; Button: TMouseButton;
774672 Shift: TShiftState; X, Y: Integer);
775673 var
776674 pt: TRealPoint;
777675 gpsPt: TGpsPoint;
778676 ptName: String;
779677 begin
780678 ptName := '';
781679 if InputQuery('Point of Interest', 'Enter name:', ptName) then
782680 begin
783681 pt := MapView1.ScreenToLatLon(Point(Y, X));
784682 gpsPt := TGpsPoint.CreateFrom(pt, NO_ELE, Now() );
785683 gpsPt.Name := ptName;
786684 Mapview1.GPSItems.Add(gpsPt, _POI_);
787685 end;
788686 end;
789687```
790688
791689In this example the constant `_POI_` is used as ID of the added point. By default, the point is drawn as a red cross, the name is drawn underneath it. You can highlight the text by changing its background color in property `POITextBgColor` of the `MapView`; for semi-transparent text background adjust the `POITextBgOpacity` property. You can also replace the default red cross by an arbitrary bitmap which must be loaded into the `POIImage` property (the folder _marker-images_ of the LazMapViewer installation contains a larger number of ready-to-use pin-cushion-like icons). And when the point is created as an instance of `TGPSPointOfInterest` rather than `TGPSPoint` you can select for it an image from the `MapView.POIImages` image list.
792690
793691There is also an event, `OnDrawGpsPoint`, which can be used to replace the entire drawing process by custom routines. The event has the `GpsPoint` as parameter. The other event parameter is the `DrawingEngine` which provides methods for drawing as explained above. Here is an example in which at first the screen coordinates of the point are calculated; and then a blue circle is drawn at this position as a marker and labeled by a large bold font:
794692```
795693procedure TForm1.MapView1DrawGpsPoint(Sender: TObject;
796694 ADrawer: TMvCustomDrawingEngine; APoint: TGpsPoint);
797695 const
798696 R = 8; // Circle radius, in pixels
799697 var
800698 p: TPoint;
801699 begin
802700 // Screen coordinates of the GPS point
803701 p := MapView1.LatLonToScreen(APoint.RealPoint);
804702
805703 // Draw a blue circle
806704 ADrawer.PenColor := clBlack;
807705 ADrawer.BrushColor := clBlue;
808706 ADrawer.BrushStyle := bsSolid;
809707 ADrawer.Ellipse(p.X-R, p.Y-R, P.X+R, p.Y+R);
810708
811709 // Draw the point label
812710 ADrawer.BrushStyle := bsClear;
813711 ADrawer.FontName := 'SegoeUI';
814712 ADrawer.FontSize := 16;
815713 ADrawer.FontStyle := [fsBold];
816714 ADrawer.TextOut(
817715 p.X - ADrawer.TextWidth(APoint.Name) div 2,
818716 p.Y + R + 4,
819717 APoint.Name
820718 );
821719 end;
822720```
823721
824722###### Overlaying another tile layer
825723
826724The following code displays central Europe and overlays the railway lines from the _OpenRailwayMap Standard_ provider. The usual steps are:
827725
828726 * Create a instance of `TGPSTileLayer`.
829727 * Set its `MapProvider` and `DrawMode` as needed; the `DrawMode` `idmUseSourceAlpha` respects the alpha channel of the layer tile images (if available) and makes the bottom layer shine through.
830728 * Add it to one of the `MapView`'s `GPSLayer`s. Provide an appropriate ID to identify the layer.
831729
832730```
833731uses
834732 mvGPSObj, mvDrawingEngine;
835733
836734 const
837735 _TILELAYERS_ID_ = 42;
838736
839737 procedure TForm1.FormCreate(Sender: TObject);
840738 var
841739 layer: TGPSTileLayer;
842740 begin
843741 MapView1.MapProvider := 'OpenStreetMap Standard';
844742 MapView1.Zoom := 5;
845743 MapView1.MapCenter.Longitude := 10;
846744 MapView1.MapCenter.Latitude := 49;
847745 layer := TGPSTilelayer.Create;
848746 layer.MapProvider := 'OpenRailwayMap Standard';
849747 layer.DrawMode := idmUseSourceAlpha;
850748 MapView1.GPSLayer[0].Add(layer, _TILELAYERS_ID_);
851749 MapView1.Active := true;
852750 end;
853751```
854752
855753###### Creating a custom track
856754
857755The following code creates a track and defines its points by adding instances of `TGPSPoint` to it. Then the track is added to the `GPSItems` of the `MapView`. For identification it is given a unique ID value (`TRACK_ID`). Finally the smallest area enclosing all track points is calculated so that the `MapView` can zoom to it:
858756```
859757uses
860758 ..., mvMapViewer, mvGpsObj, mvTypes;
861759 const
862760 TRACK_ID = 293; // unique number
863761
864762 procedure CreateGPSTrack;
865763 var
866764 track: TGPSTrack;
867765 area: TRealArea;
868766 begin
869767 track := TGPSTrack.Create;
870768 track.Points.Add(TGPSPoint.Create(-16.123, 65.491)); // Latitude, Longitude pairs
871769 track.Points.Add(TGPSPoint.Create(-18.34, 64.374));
872770 track.Points.Add(TGPSPoint.Create(-19.979, 63.895));
873771
874772 MapView.GPSItems.Add(track, TRACK_ID);
875773 track.GetArea(area);
876774 MapView.ZoomOnArea(area);
877775 end;
878776```
879777
880778###### Reading and displaying a track from a gpx file
881779
882780Suppose you recorded your nice mountain hike by means of a gps tracker, and now you want to use the MapView to display the path in a map. In unit _mvGPX_ , you find a reader class for gpx files which directly loads the track into the `GPSItems` of the `MapView` component:
883781```
884782uses
885783 ..., mvMapViewer, mvTypes, mvGPX;
886784
887785 procedure TMainForm.BtnLoadGPXFileClick(Sender: TObject);
888786 var
889787 reader: TGpxReader;
890788 b: TRealArea;
891789 begin
892790 if OpenDialog.Execute then begin
893791 reader := TGpxReader.Create;
894792 try
895793 reader.LoadFromFile(OpenDialog.FileName, MapView.GPSItems, b);
896794 MapView.Engine.ZoomOnArea(b);
897795 finally
898796 reader.Free;
899797 end;
900798 end;
901799 end;
902800```
903801
904802#### Creating overlays at designtime
905803
906804##### Classes
907805
908806In order to facilitate using overlay objects several collections were added to the `TMapView` so that objects can be added, edited and deleted at designtime. For this reason, the basic list elements descend from `TCollection` and the elements themselves descend from `TCollectionItem`. The most fundamental collection here is `TMapCollectionBase` and its descendant `TMapCollection`. The most fundamental collection item classes are `TMapItem` and the derived `TMapPoint` (corresponding to `TGPSPoint`) with these most important properties:
909807```
910808type
911809 TMapItem = class(TCollectionItem)
912810 ...
913811 public
914812 property View: TMapView read GetView;
915813 property Layer: TMapLayer read GetLayer;
916814 property GPSObj: TGPSObj read GetGPSObj;
917815 published
918816 property Caption: TCaption read FCaption write SetCaption;
919817 property Visible: Boolean read FVisible write SetVisible default True;
920818 end;
921819
922820 TMapPoint = class(TMapItem)
923821 ...
924822 public
925823 property LatLonInDMS: Boolean read GetLatLonInDMS;
926824 property RealPoint: TRealPoint read GetRealPoint write SetRealPoint;
927825 property ToScreen: TPoint read GetToScreen;
928826 published
929827 property Longitude: Double read FLongitude write SetLongitude;
930828 property Latitude: Double read FLatitude write SetLatitude;
931829 property Elevation: Double read FElevation write SetElevation stored IsElevationStored;
932830 property DateTime: TDateTime read FDateTime write SetDateTime stored IsDateTimeStored;
933831 end;
934832```
935833
936834More specialized classes are `TMapPointOfInterest`, `TMapTrackPoint` and `TMapAreaPoint`
937835
938836 * `TMapPointOfInterest` is equivalent to `TGPSPointOfInterest` and introduces the `ImageIndex` property.
939837 * `TMapTrackPoint` publishes a new property `Mark` which determines whether this point is at the begin, end, somewhere in the middle, or between track segments (`smStart`, `smEnd`, `smMid`, `smNone`, respectively).
940838 * `TMapAreaPoint` is a vertex of a polygon (`TMapArea`); it has no additional properties.
941839
942840Another imporant descendant of `TMapItem` is `TMapLayer`. Similarly to `TGPSTileLayer` it refers to each one of the layer stacks in the map. Like `TGPSTileLayer` it can contain a complete tile map (based on its `MapProvider` setting). But it can also consist of points-of-interest, tracks or areas (or a combination of them). The points-of-interest are administrated by the `PointsOfInterest` collection (type `TMapPointsOfInterest`), the tracks in the `Tracks` collection (type TMapTracks), and the areas in the `Areas` collection (type `TMapAreas`). The link between the `TMapLayer` and the GPS-type of objects is established by the class `TGPSComboLayer` which consists of a `TGPSTileLayer` for its background and a collection of other objects to draw on top. Actually, the `Draw` method is overridden to draw first the background and then - the rest of the objects contained into.
943841
944842The layers themselves are collected in a `TMapLayers` collection which descends from `TMapCollection`. The instance `Layers` is a direct member of `TMapView`.
945843```
946844type
947845 TMapLayer = class(TMapItem)
948846 ...
949847 public
950848 function HitTest(constref Area: TRealArea): TMapObjectList; override;
951849 function AddPointOfInterest(APoint: TRealPoint; ACaption: String = ''): TMapPointOfInterest;
952850 procedure AssignFromGPSList(AList: TGPSObjectList);
953851 property ComboLayer: TGPSComboLayer read FComboLayer;
954852 published
955853 property MapProvider: String read GetMapProvider write SetMapProvider;
956854 property UseThreads: Boolean read GetUseThreads write SetUseThreads default True;
957855 property DrawMode: TItemDrawMode read FDrawMode write SetDrawMode default idmUseOpacity;
958856 property Opacity: Single read FOpacity write SetOpacity default 0.25;
959857 property PointsOfInterest: TMapPointsOfInterest read GetPointsOfInterest write SetPointsOfInterest;
960858 property Areas: TMapAreas read GetAreas write SetAreas;
961859 property Tracks: TMapTracks read GetTracks write SetTracks;
962860 end;
963861```
964862
965863##### Examples
966864
967865###### Overlaying a second map as a layer
968866
969867 * Click on the '...' button next to the `Layers` property (or double-click on the map, or right-click on the map and select "Layer Editor...") to open the layer editor.
970868 * Click on '+ Add' to create a new layer and to add it.
971869 * Specify the map provider in the `MapProvider` property.
972870 * Moreover, select the `DrawMode`: If the images received from the map server have their own transparency in an alpha channel the option `idmUseSourceAlpha` is the correct one. Otherwise, maybe you want the original map base layer to shine through the overlay layer - select `idmUseOpacity` and adjust the `Opacity` property as needed.
973871
974872If you want to overlay a TMapLayer by code you can do it this way:
975873```
976874function AddMapLayer(AMapView: TMapView): TMapLayer;
977875 begin
978876 Result := AMapView.Layers.Add as TMapLayer;
979877 end;
980878```
981879
982880###### Overlaying a layer with points-of-interest
983881
984882 * Open the layer editor and add a new layer. Or, if you want to add the points to an existing layer, select this layer in the layer editor.
985883 * Click on the '...' button next to the `PointsOfInterest` item among the layer's properties in the object inspector.
986884 * This opens the points editor where you can enter the point properties, in particular the `Latitude` and `Longitude`. `Caption` specifies the text to be displayed below the point symbol. If an imagelist is attached to the `MapView`'s `POIImages` property you can also pick one of these icons by means of the `ItemIndex` property.
987885 * Repeat with all other points that you want to add.
988886
989887The following code shows how a point-of-interest can be added to an existing MapLayer at runtime:
990888```
991889function AddMapPointOfInterest(AMapView: TMapView; ALayerIndex: Integer; ALatitude, ALongitude: Double; ACaption: String; AImageIndex: Integer): TMapPointOfInterest;
992890 var
993891 layer: TMapLayer;
994892 begin
995893 layer := AMapView.Layers[ALayerIndex];
996894 Result := layer.PointsOfInterest.Add as TMapPointOfInterest; // or := TMapPointOfInterest.Create(layer.PointsOfInterest);
997895 Result.RealPoint := RealPoint(ALatitude, ALongitude);
998896 Result.Caption := ACaption;
999897 Result.ImageIndex := AImageIndex;
1000898 end;
1001899```
1002900
1003901###### Displaying a track in a layer
1004902
1005903Suppose you have an array of GPS coordinates (type `TRealPointArray = array of TRealPoint`) which you want to display in the map as a track. As before, create or select a layer for the track. Then the track points can be added like in the following function:
1006904```
1007905funtion AddTrackToLayer(AMapView: TMapView; ALayerIndex: Integer; const APoints: TRealPointArray): TMapTrack;
1008906 var
1009907 layer: TMapLayer;
1010908 i: Integer;
1011909 trackPt: TMapTrackPoint;
1012910 begin
1013911 layer := AMapView.Layers[ALayerIndex];
1014912 Result := layer.Tracks.Add as TMapLayer; // or: TMapLayer.Create(layer.Tracks);
1015913 for i := Low(APoints) to High(APoints) do
1016914 begin
1017915 for realPt in APoints do begin
1018916 trackPt := Result.Points.Add as TMapTrackPoint;
1019917 trackPt.Point := APoints[i];
1020918 end;
1021919 end;
1022920```
1023921
1024922In an analogous way you can also define the vertex points of an area.
1025923
1026924###### Reading and displaying a track from a gpx file
1027925
1028926 * Again open the layer editor
1029927 * Select the layer to which you want to add the track, or add a new layer.
1030928 * In the toolbar of the layer editor, there is a "Load GPX" button to select the gpx file to be loaded. There is a dropdown menu with two options:
1031929 * Load... -- this simply loads the gpx file, the viewport does not change.
1032930 * Load and zoom ... -- does the same, but also adjusts the zoom and center of the viewport to fully see the loaded gpx objects.
1033931
1034932If you want to load a gpx file into a MapLayer by code you can do it this way:
1035933```
1036934uses
1037935 mvMapViewer, mvTypes, mvGPSObj, mvGPX;
1038936
1039937 procedure TMainForm.LoadGPXFileInMapLayer(AFileName: string; AMapView: TMapView; ALayerIndex: Integer);
1040938 var
1041939 reader: TGpxReader;
1042940 b: TRealArea;
1043941 begin
1044942 list := TGPSObjectList.Create;
1045943 try
1046944 reader := TGpxReader.Create;
1047945 try
1048946 reader.LoadFromFile(AFileName, list, b);
1049947 AMapView.Engine.ZoomOnArea(b);
1050948 AMapView.MapCenter.Longitude := (b.TopLeft.Lon - b.BottomRight.Lon) / 2;
1051949 AMapView.MapCenter.Latitude := (b.TopLeft.Lat - b.BottomRight.Lat) / 2;
1052950 AMapView.Layers[ALayerIndex].AssignFromGPSList(list);
1053951 finally
1054952 reader.Free;
1055953 end;
1056954 finally
1057955 list.Free;
1058956 end;
1059957 end;
1060958```
1061959
1062960###### Editing points by using the built-in points editor
1063961
1064962A points editor has been incorporated into the mapviewer to give the user the opportunity to edit map points at design-time. In order to activate the editor add the element `mvoEditorEnabled` to the `MapView.Options`. When now the mouse is moved over map points (points of interest, area points, track points) the point is highlighted by a green square with red border which can be dragged to the new location. The points editor is available also at run-time (see _points_of_interest_demo_ in the _examples_ folder of the MapViewer installation).
1065963
1066964Additionally, the window of the points editor can be opened by selecting the option "Edit MapView Points" from the context menu of the `MapView` component at design-time. At run-time, you must invoke the following code:
1067965```
1068966uses
1069967 mvMapViewerPathEditForm;
1070968
1071969 procedure TMainForm.FormCreate(Sender: TObject);
1072970 begin
1073971 with TMapViewerPathEditForm.Create(Self) do
1074972 begin
1075973 MapView := Self.MapView;
1076974 Show;
1077975 end;
1078976 end;
1079977```
1080978
1081979[![mapviewer pointseditor.png](/wiki-images/b/b1/mapviewer_pointseditor.png)](</File:mapviewer_pointseditor.png>)
1082980
1083981 * When the editor opens, it is in **Select/drag mode** (the first toolbar button displaying the arrow icon is pressed):
1084982 * You can **select** an individual point (from a track, area or POIs) by clicking on it. Click and pull a rubber-band to select multiple points. Ctrl+Click adds to the selection.
1085983 * You can click and **drag** selected points with the mouse (Ctrl+Click to drag multiple selected points).
1086984 * When you have points on top of each other then you can use Alt+Click to select the next one.
1087985 * For adding new points you have several options:
1088986 * Selecting the "orange marker" icon (2nd toolbutton from the left) brings you into **POI mode**. Now a click into the map adds a new point-of-interest. The caption of the POI can be specified in the "Caption" box the points of the editor. If you need exact locations of the point you can enter its GPS coordinates numerically.
1089987 * The third icon ("curve with end-points") enters **Track mode** for adding a new track of points. Each subsequent click into the map adds a point to the track. Add the last point of the track by holding the CTRL key down during clicking. Or click on the "arrow" icon (1st toolbutton) to return to selection mode. At least two points are required for a track.
1090988 * In the same way, the corner points of an area can be specified after selecting the fourth button with the "area" symbol (**Area mode**). Note that at least three points are required to define an area.
1091989 * The next two icons ("curve icon" with "+"/"x" overlay) are for editing existing points: In order to **add a point** to a track or area you must select two points of the shape and then click on the "curve +" icon. In order to **delete a point** you first select the point to be deleted and then click on the "curve x" symbol (in case of multiple selections, only the last selected point is deleted).
1092990 * The final two buttons with the magnifier icons are **zoom** buttons.
1093991
1094992![Light bulb](https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png) **Note:** This kind of editing is possible only for points descending from `TMapPoint`, but not for points descending from `TGPSPoint`.
1095993
1096994## Plugins
1097995
1098996Plugins are an easy way to extend the functionality of the MapViewer, without the need to change the source of the component itself. Together with the PluginManager which is the glue between the MapView and the plugins, and the RAD-method of connecting existing parts within the IDE, the system becomes a powerful and user friendly tool. For a more detailed explanation see the [[LazMapViewer-Plugins]] page.
1099997
1100998### What is a plugin and what can I do with it?
1101999
11021000The question could be answered by describing an example.
11031001
11041002Let's assume that your application needs the capability to measure the linear distance between two points on the map. The user will click on the map with the mouse to define the anchor-point and then hover the mouse around to see the distance between the anchor and the place indicated by the mouse cursor. If the user clicks again, the measurement mode is left.
11051003
11061004Without the use of a plugin you would need to implement three event methods for the MapView: `OnMouseUp`, `OnMouseMove` and `OnAfterPaint`.
11071005
11081006 * In the `OnMouseUp`-event, you would toggle the measurement mode and if entered you store the current position as the anchor-position.
11091007 * In the `OnMouseMove`-event, you have to store the actual position and calculate distance. And you will invalidate the MapView to initiate a redraw of the map.
11101008 * In the `OnAfterPaint`-event, you would paint two circles as markers, one on the anchor-position and one on the current position and draw a text with the distance.
11111009
11121010In total you have four additional form fields and three additional event methods in your form. For this simple example this may be a simple and suitable way, but if you think about other extensions, you will bloat the form's source file with code which could be better encapsulated somewhere else. And if another project needs the same functionality you will have to write the code again.
11131011
11141012The plugin approach provides handlers for these three events in a re-usable way. There is no need to write any code to get the wanted behaviour.
11151013
11161014### Using existing plugins
11171015
11181016[![tmvpluginmanager 200.png](/wiki-images/c/c4/tmvpluginmanager_200.png)](</File:tmvpluginmanager_200.png>)
11191017
11201018The key component for the MapViewer's plugin technology is the `TMvPluginManager`. It contains a list of all registered plugins from which the user can select the needed one at design-time.
11211019
11221020#### Creating plugins at design-time
11231021
11241022Follow these steps to activate plugins in your map application:
11251023
11261024 * Drop a `TMvPluginManager` component on the form.
11271025 * Link it to the MapView requiring a plugin. This is done in the Object Inspector by assigning it to the `PluginManager` property of the MapView.
11281026 * Double-click on the PluginManager component (or click on the '...' next to the `PluginManger` property) to open the plugin editor.
11291027 * Click on the '+ Add' button to see the list of the available plugins.
11301028 * Select the plugin needed.
11311029 * It is possible to have multiple plugins in the PluginManager. They are processed from top to bottom. You may adjust their order by means of the arrow buttons.
11321030 * Every plugin type has its own set of properties. They can be altered in the object inspector after selecting the plugin in the plugin editor's list (or in the object tree of the object inspector).
11331031
11341032The same PluginManager can be shared between several maps. All plugins and their properties are applied to each of these maps in the same way. While this is a useful feature for some plugin types (e.g. the `TMapGridPlugin`, `TLinkedMapsPlugin` or `TCenterMarkerPlugin`, see below), it can result in undesired behaviour in other cases. To avoid this, it may be required to duplicate plugins in the PluginManager for each map, set properties accordingly and specify in the plugin's `MapView` property the map on which it will be active (with each own set of properties). But there are also plugin types which can handle multiple maps automatically (`TDraggableMarkerPlugin, TSpreadMarkerPlugin`, see below).
11351033
11361034#### Creating plugins at run-time
11371035
11381036Of course plugins can be used also at run-time:
11391037
11401038 * Since plugins work only in compbination with the plugin manager you must create a `TMvPluginManager` instance first - either use the one dropped from the component palette, or create a new one by code (see below),
11411039 * Create the plugin by calling its constructor and add it to the plugin manager. There are several ways to do this:
11421040 * Specify the plugin manager as Owner in the plugin constructor.
11431041 * Or, if you prefer to specify another owner, call `PluginManager.AddPlugin(plugin)`, or `PluginManager.Plugins.Add(plugin)` after creation
11441042
11451043The following code creates a `TLegalNoticePlugin` (see below).
11461044```
11471045uses
11481046 mvPluginCommon;
11491047
11501048 procedure TForm1.FormCreate(Sender: TObject);
11511049 var
11521050 PluginManager: TMvPluginManager;
11531051 plugin: TLegalNoticePlugin;
11541052 begin
11551053 // Create the plugin manager
11561054 PluginManager := TMvPluginManager.Create(Self);
11571055
11581056 // Link the plugin manager to the MapView which is assumed to exist already.
11591057 MapView.PluginManager := PluginManager;
11601058
11611059 // Create the plugin and add it to the plugin manager
11621060 plugin := TLegalNoticePlugin.Create(PluginManager);
11631061
11641062 // Set plugin properties
11651063 plugin.LegalNotice := 'Map data from [https://www.openstreetmap.org/copyright OpenStreetMap and contributors]';
11661064 end;
11671065```
11681066
11691067### Available plugins
11701068
11711069Here is a list of the built-in plugins:
11721070
11731071 * `**TCenterMarkerPlugin**`
11741072
1175-
1176-
1177- It simply draws a cross in the center of the map. The size and color of the cross can be controlled by properties.
1073+It simply draws a cross in the center of the map. The size and color of the cross can be controlled by properties.
11781074
11791075 * `**TTileInfoPlugin**`
11801076
1181-
1182-
1183- Draws a border around the picture tiles from which the total map is composed. The zoom level as well as the x/y indices are indicated for each tile. The displayed info text can be modified by the `InfoMask` property which is a mask string for the `Format()` function accepting the `x`/`y`/`zoom` parameters as argument indices 0..2, respectively. Example: `InfoMark := 'x=%0:d, y=%1:d, zoom=%2:d'`
1077+Draws a border around the picture tiles from which the total map is composed. The zoom level as well as the x/y indices are indicated for each tile. The displayed info text can be modified by the `InfoMask` property which is a mask string for the `Format()` function accepting the `x`/`y`/`zoom` parameters as argument indices 0..2, respectively. Example: `InfoMark := 'x=%0:d, y=%1:d, zoom=%2:d'`
11841078
11851079 * `**TLegalNoticePlugin**`
11861080
1187-
1081+Draws a copyright text in a corner of the map. The text can be specified in the property `LegalNotice`. Using square brackets the clickable URL of the map provider's copyright page can be inserted by means of a wiki-like syntax:
11881082
1189- Draws a copyright text in a corner of the map. The text can be specified in the property `LegalNotice`. Using square brackets the clickable URL of the map provider's copyright page can be inserted by means of a wiki-like syntax:
1083+`Map data from [https://www.openstreetmap.org/copyright OpenStreetMap and contributors]`
11901084
1191- `Map data from [https://www.openstreetmap.org/copyright OpenStreetMap and contributors]`
1192- displays the text _"Map data from OpenStreetMap and contributors"_. The text in brackets consists of two parts separated by the first space character: The first part (_"https://www.openstreetmap.org/copyright"_) denotes the URL of the link, and the second part (_"OpenStreetMap and contributors"_) is shown instead of the URL for better readability and formatted like a html link (property `URLFontColor`). When the user clicks on this text, the URL is opened in the web browser of the system.
1085+displays the text _"Map data from OpenStreetMap and contributors"_. The text in brackets consists of two parts separated by the first space character: The first part (_"https://www.openstreetmap.org/copyright"_) denotes the URL of the link, and the second part (_"OpenStreetMap and contributors"_) is shown instead of the URL for better readability and formatted like a html link (property `URLFontColor`). When the user clicks on this text, the URL is opened in the web browser of the system.
11931086
11941087 * `**TLinkedMapsPlugin**`
11951088
1196-
1197-
1198- When a form contains two (or more) maps and the user changes the viewport by zooming or panning in one map the same changes are applied to the other maps sharing this plugin.
1089+When a form contains two (or more) maps and the user changes the viewport by zooming or panning in one map the same changes are applied to the other maps sharing this plugin.
11991090
12001091 * `**TMarkerHintPlugin**`
12011092
1202-
1203-
1204- Displays a hint popup window when the mouse pointer hovers above a point-of-interest. Both GPS type and Map-type points are supported. By default, the hint text is composed of the POI's caption and geo-coordiates, but there is also an `OnHint` event in which any text can be prepared.
1093+Displays a hint popup window when the mouse pointer hovers above a point-of-interest. Both GPS type and Map-type points are supported. By default, the hint text is composed of the POI's caption and geo-coordiates, but there is also an `OnHint` event in which any text can be prepared.
12051094
12061095 * `**TMarkerClickPlugin**`
12071096
1208-
1209-
1210- Fires an `OnMarkerClick` event when the user click on a point-of-interest of both GPS type and Map-type. When markers are very close together or even overlapping you can activate the `ExtendedClicks` options of this plugin which allows to click on the marker's caption or icon. Or you can use a `TSpreadMarkerPlugin` instead which temporarily separates the overlapping markers when the mouse comes close enough - see below.
1097+Fires an `OnMarkerClick` event when the user click on a point-of-interest of both GPS type and Map-type. When markers are very close together or even overlapping you can activate the `ExtendedClicks` options of this plugin which allows to click on the marker's caption or icon. Or you can use a `TSpreadMarkerPlugin` instead which temporarily separates the overlapping markers when the mouse comes close enough - see below.
12111098
12121099 * `**TMarkerEditorPlugin**`
12131100
1214-
1215-
1216- The user can add new points-of-interest to the map. Existing POIs can be selected by several methods and dragged to different locations. Again both GPS type and Map-type points are supported.
1101+The user can add new points-of-interest to the map. Existing POIs can be selected by several methods and dragged to different locations. Again both GPS type and Map-type points are supported.
12171102
12181103 * `**TDraggableMarkerPlugin**`
12191104
1220-
1221-
1222- Allows the user to drag points of the GPS type to another location. The mouse button to be used for dragging is specified in the `DragMouseButton` property, and the accuracy required to hit the point by clicking is determined by the `Tolerance` property. The main difference to the `TMarkerEditorPlugin` is that it can handle multiple maps without further measures.
1105+Allows the user to drag points of the GPS type to another location. The mouse button to be used for dragging is specified in the `DragMouseButton` property, and the accuracy required to hit the point by clicking is determined by the `Tolerance` property. The main difference to the `TMarkerEditorPlugin` is that it can handle multiple maps without further measures.
12231106
12241107 * `**TSpreadMarkerPlugin**`
12251108
1226-
1227-
1228- This is a very complex plugin which is useful when several GPS points are on the same location. When the mouse is moved over this stack of points and remains there for longer than `MarkerSpreadDelayMS` milliseconds the individual points are "exploded" so that every point is visible and, for example, can be dragged by a `TDraggableMarkerPlugin` if present. After `MarkerCollapseDelayMS` milliseconds, the point cloud collapses to a single point again.
1109+This is a very complex plugin which is useful when several GPS points are on the same location. When the mouse is moved over this stack of points and remains there for longer than `MarkerSpreadDelayMS` milliseconds the individual points are "exploded" so that every point is visible and, for example, can be dragged by a `TDraggableMarkerPlugin` if present. After `MarkerCollapseDelayMS` milliseconds, the point cloud collapses to a single point again.
12291110
12301111 * `**TMapGridPlugin**`
12311112
1232-
1233-
1234- Draws a grid of constant longitude/latitude lines over the map
1113+Draws a grid of constant longitude/latitude lines over the map
12351114
12361115 * `**TMapScalePlugin**`
12371116
1238-
1239-
1240- Draws a horizontal scale bar over the map. The units of the scale bar labels are kilometers/meters, or, when `Imperial` is true, miles/feet. The position of the bar depends of the elements in the `AlignSet` (`alTop, alBottom, alLeft, alRight`). The maximum length of the bar (in pixels) is given by `WidthMax`. Note that due to the projection of the earth onto a plane the length scale may be different across the latitudes of viewport; the length of the displayed bar always refers to the center of the map. The property `ZoomMin` is used to turn off the scale bar for smaller zoom levels so that confusion due to a noticeable difference in scaling over the viewport latitudes can be avoided.
1117+Draws a horizontal scale bar over the map. The units of the scale bar labels are kilometers/meters, or, when `Imperial` is true, miles/feet. The position of the bar depends of the elements in the `AlignSet` (`alTop, alBottom, alLeft, alRight`). The maximum length of the bar (in pixels) is given by `WidthMax`. Note that due to the projection of the earth onto a plane the length scale may be different across the latitudes of viewport; the length of the displayed bar always refers to the center of the map. The property `ZoomMin` is used to turn off the scale bar for smaller zoom levels so that confusion due to a noticeable difference in scaling over the viewport latitudes can be avoided.
12411118
12421119 * `**TAreaSelectionPlugin**`
12431120
1244-
1245-
1246- Allows the user to select an area (rectangular in terms of latitude and longitude) on the map.
1121+Allows the user to select an area (rectangular in terms of latitude and longitude) on the map.
12471122
12481123 * `**TGreatCirclePainterPlugin**`
12491124
1250-
1251-
1252- Draws a great circle and/or the orthodrome (=shortest line) between two points on the map.
1125+Draws a great circle and/or the orthodrome (=shortest line) between two points on the map.
12531126
12541127 * `**TUserDefinedPlugin**`
12551128
1256-
1257-
1258- This plugin does not have a predefined behaviour, but provides all events handled for specific code.
1129+This plugin does not have a predefined behaviour, but provides all events handled for specific code.
12591130
12601131The folder _examples/plugin_demos_ contains sample projects for these built-in plugins, as well as additional plugin samples.
12611132
12621133### Creating a new plugin class
12631134
12641135All plugins must be derived from the `TMvCustomPlugin` class (`unit mvPluginCore`) or from one of it's descendands.
12651136
12661137These classes could be added to an instance of a `TMvPluginManager`.
12671138
12681139In the derived class you override all needed methods. According to the example above this would be
12691140```
12701141TMyFirstPlugin = class(TMvPlugin)
12711142 ...
12721143 protected
12731144 procedure AfterPaint(AMapView: TMapView; var Handled: Boolean); override;
12741145 procedure MouseMove(AMapView: TMapView; AShift: TShiftState; X,Y: Integer;
12751146 var Handled: Boolean); override;
12761147 procedure MouseUp(AMapView: TMapView; Button: TMouseButton; Shift: TShiftState;
12771148 X,Y: Integer; var Handled: Boolean); override;
12781149```
12791150
12801151As you see, the methods are very similar to the events in the example. The parameter `Sender` is replaced by `AMapView` and additionally you will find a boolean var parameter `Handled`. This parameter could be used to control the interaction between plugins, since the system allows more than one plugin to be attached. For example, if our plugin has found a marker (either in `MouseMove` or `MouseDown`) and change some state(s) it may set the `Handled`-parameter to True and signalize the following plugins that the event is already processed. And also the plugin itself should check the parameter to keep hands of actions consumed by previous plugins.
12811152
12821153In the Form with the `MapView` you have to attach a `PluginManager` to the `MapView`.
12831154
12841155 * The `TMvPluginManager` is found in the component gallery (tab "Misc"), drop him to the form.
12851156 * In the ObjectEditor of the `MapView` select the PluginManager in the corresponding field
12861157 * Create a `FormCreate`-method of the form and create an instance of your plugin and add it to the plugin manager.
12871158
12881159```
12891160procedure TForm1.FormCreate(Sender: TObject);
12901161 begin
12911162 FMyFirstPlugin := TMyFirstPlugin.Create(Self);
12921163 FMyFirstPlugin.MapView := MapView1;
12931164 MvPluginManager1.PluginList.Add(FMyFirstPlugin);
12941165 end;
12951166```
12961167
12971168As soon as the mouse is interacting with the MapView, the overridden methods are called.
12981169
12991170You can include your own plugins into the IDE by using the
13001171```
13011172RegisterPluginClass(FMyFirstPlugin, 'My fiorst plugin');
13021173```
13031174
13041175method. You have to create your own package and install it. (The details will be added a a later time).
13051176
13061177## Finding Geo Locations: TMvGeoNames
13071178
13081179[![tmvgeonames 200.png](/wiki-images/c/c5/tmvgeonames_200.png)](</File:tmvgeonames_200.png>)
13091180
13101181`TMvGeoNames` is a component which searches the geo coordinates (longitude, latitude) of many cities or other locations in the world. Using the download engine of the `MapView` component it sends a query to the site <http://geonames.org/search.html> and analyzes the returned html string.
13111182
13121183### Getting Started
13131184
13141185 * Assuming that you already have set up an application for the `TMapView` component as described above, you simply drop a `TMvGeoNames` component on the form; it is located next to the `TMapView` icon in the _Misc_ component palette.
13151186 * Add a button which is supposed to trigger the search.
13161187 * Write an `OnClick` handler for the button which calls the `TMvGeoNames` method `Search`. Enter the search destination as first parameter, and the download engine to be used as second parameter. The function returns the found longitude and latitude as a `TRealPoint` record which can be passed immediately to the `Center` property of the `MapView` component. This way, the viewer can immediately jump to the found location:
13171188
13181189```
13191190procedure TForm1.Button1Click(Sender: TObject);
13201191 begin
13211192 MapView1.Center := MvGeoNames1.Search('Grand Canyon National Park', MapView1.DownloadEngine);
13221193 end;
13231194```
13241195
13251196### Documentation
13261197
13271198#### Methods
13281199
13291200 * `function Search(ALocationName: String; ADownloadEngine: TMvCustomDownloadEngine): TRealPoint`:
13301201
1331-
1332-
1333- Searches the requested location using the specified download engine. Return value is a `TRealPoint` with the geo coordinates of the location. The search returns also locations with similar names, however, they must be extracted by handling the `OnNameFound` event.
1202+Searches the requested location using the specified download engine. Return value is a `TRealPoint` with the geo coordinates of the location. The search returns also locations with similar names, however, they must be extracted by handling the `OnNameFound` event.
13341203
13351204#### Properties
13361205
13371206 * `LocationName: string`:
13381207
1339-
1340-
1341- Is the name of the (first) found location as listed by the _geonames_ site.
1208+Is the name of the (first) found location as listed by the _geonames_ site.
13421209
13431210#### Events
13441211
13451212 * `OnNameFound`:
13461213
1347-
1348-
1349- This event is triggered while the received response of the _geonames_ server is being analyzed. The html string usually contains a variety of locations. Whenver a location has been extracted from the received string the event is fired and tells the name, a description, and the longitude/latitude `TRealPoint` record for this location. Handling this event makes it possible to list all the found locations for example in a combobox or listbox to give the user the opportunity to select any one of them:
1214+This event is triggered while the received response of the _geonames_ server is being analyzed. The html string usually contains a variety of locations. Whenver a location has been extracted from the received string the event is fired and tells the name, a description, and the longitude/latitude `TRealPoint` record for this location. Handling this event makes it possible to list all the found locations for example in a combobox or listbox to give the user the opportunity to select any one of them:
13501215```
13511216type
13521217 TGeoLocation = class
13531218 Name: String;
13541219 Descr: String;
13551220 Coords: TRealPoint;
13561221 end;
13571222
13581223 procedure TForm1.MVGeoNames1NameFound(const AName: string;
13591224 const ADescr: String; const ALoc: TRealPoint);
13601225 var
13611226 loc: TGeoLocation;
13621227 begin
13631228 loc := TGeoLocation.Create;
13641229 loc.Name := AName;
13651230 loc.Descr := ADescr;
13661231 loc.Coords := ALoc;
13671232 ComboBox1.Items.AddObject(AName, loc);
13681233 end;
13691234```
13701235
13711236---
13721237*From the Free Pascal wiki, page "LazMapViewer", as the Internet Archive kept it on 2026-01-12, last changed on 2025-10-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history