Feel free to [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/dceejay) this project.
Either use the Manage Palette option in the Node-RED Editor menu, or run the following command in your Node-RED user directory - typically `~/.node-red`
- **track | hdg | heading | COG | bearing** : when combined with speed, draws a vector. (only first will be used)
- **speed** : when combined with track, hdg, heading, or bearing, draws a leader line vector - should be in m/s. Can also be specified as "20 kph", or "20 mph", or "20 kt". i.e a string with units.
- **SOG** : speed over ground - speed in knots.
- **alt | altitude | altft | altm** : Altitude in meters, but can use *altft* to specify feet instead.
- **weblink** : adds a link to an external page. Either set a url as a *string*, or an *object* like `{"name":"BBC News", "url":"https://news.bbc.co.uk", "target":"_new"}`, or multiple links with an *array of objects*`[{"name":"BBC News", "url":"https://news.bbc.co.uk", "target":"_new"},{"name":"node-red", "url":"https://nodered.org", "target":"_new"}]`
- **popup** : html to fill the popup if you don't want the automatic default of the properties list. Using this overrides photourl, videourl and weblink options.
- **contextmenu** : an html fragment to display on right click of marker - defaults to delete marker. You can specify `${name}` to substitute in the name of the marker. Set to `""` to disable just this instance.
If you use the name without the fa- prefix (eg `male`) you will get the icon inside a generic marker shape. If you use the fa- prefix (eg `fa-male`) you will get the icon on its own. Likewise you can use any of the [Weather-lite](https://github.com/Paul-Reed/weather-icons-lite) icons by using the wi- prefix. These map to icons returned by common weather API such as DarkSky and OpenWeatherMap - for example `"wi-owm-"+msg.payload.weather[0].icon` will pickup the icon returned from the OpenWeatherMap API.
You can also specify an emoji as the icon by using the :emoji name: syntax - for example `:smile:`. Here is a **[list of emojis](https://github.com/dceejay/RedMap/blob/master/emojilist.md)**.
Or you can specify an image to load as an icon by setting the icon to `http(s)://...` By default it will be scaled to 32x32 pixels. You can change the size by setting **iconSize** to a number - eg 64. Example icon - `"https://img.icons8.com/windows/32/000000/bird.png"` or you can use an inline image of the form `data:image/...` which uses a base64 encoded image.
There are lots of extra options you can specify as `msg.payload.options` - see the <ahref="https://spatialillusions.com/milsymbol/documentation.html"target="mapinfo">milsymbol docs here</a>.
Users of [TAK](https://tak.gov) can use the [TAK ingest node](https://flows.nodered.org/node/node-red-contrib-tak-registration) to create a JSON formatted TAK event object, received from a TAK server. This can be fed directly into the worldmap node.
If the payload also includes a property `fit:true` the map will zoom to fit the line or area. Alternatively you can use `fly:true` instead of fit for a more animated look.
Shapes can also have a **popup** property containing html, but you MUST also set a property `clickable:true` in order to allow it to be seen. You can also set **tooltip** to create a label that appears when you hover the mouse over the shape.
Often geojson may not have a `properties` or `style` property in which case you can specify some global optional properties (see below) in order to set some defaults for the geojson object.
3) You can also add the geojson as a specific overlay, in which case you can also have more control of styles, and per feature customisations. See the section on overlays [below](#to-add-a-new-geojson-overlay). This is the most complex but also the most customisable.
**Note**: the object you supply will replace the whole buildings layer. To delete the building send a msg with a name and the building property set to "" (blank string).
A 3D map view has now been added as **worldmap/index3d.html** using the mapbox api - the msg can support `msg.command.pitch` and `msg.command.bearing` to angle the view, for example:
The `icon` can be specified as a person, block, bar, or "anything else" - they will render slightly differently - all units are approximate. They will be positioned at the `lat`, `lon` as normal but also at the `msg.payload.height` - where height is in meters above the surface of the map (which may or may not relate to altitude...)
You can also control the map via the node, by sending in a msg.payload containing a **command** object. Multiple parameters can be specified in one command.
- **layer** - set map to specified base layer name - `{"command":{"layer":"Esri"}}`
- **search** - search markers on map for name containing `string`. If not found in existing markers, will then try geocoding looking using Nominatim. An empty string `""` clears the search results. - `{"command":{"search":"Winchester"}}`
- **showlayer** - show the named overlay(s) - `{"command":{"showlayer":"foo"}}` or `{"command":{"showlayer":["foo","bar"]}}`
- **side** - add a second map alongside with slide between them. Use the name of a *baselayer* to add - or "none" to remove the control. - `{"command":{"side":"Esri Satellite"}}`
- **split** - once you have split the screen with the *side* command - the split value is then the % across the screen of the split line. - `{"command":{"split":50}}`
- **coords** - turns on and off a display of the current mouse co-ordinates. Values can be "deg", "dms", or "none" (default). - `{"command":{"coords":"deg"}}`
a msg `{"action":"button", "name":"the_button_name"}` to the worldmap in node. If supplied with a `name` property only, it will remove the button. Optional `position` property can be 'bottomright', 'bottomleft', 'topleft' or 'topright' (default). button can also be an array of button objects.
- **contextmenu** - html string to define the right click menu when not on a marker. Defaults to the simple add marker input. Empty string `""` disables this right click.
- **trackme** - Turns on/off the browser self locating. Boolean false = off, true = cyan circle showing accuracy error, or an object like `{"command":{"trackme":{"name":"Dave","icon":"car","iconColor":"blue","layer":"mytrack","accuracy":false}}}`. Usual marker options can be applied.
- **showmenu** - Show or hide the display of the hamberger menu control in the top right . Values can be "show" or "hide". - `{"command":{"showmenu": "hide"}}`
- **showlayers** - Show or hide the display of selectable layers. Does not control the display of an individual layer, rather a users ability to interact with them. Values can be "show" or "hide". - `{"command":{"showlayers": "hide"}}`
The geojson features may contain a `properties` property. That may also include a `style` with properties - stroke, stroke-width, stroke-opacity, fill, fill-opacity. Any other properties will be listed in the popup.
The `opt` property is optional. See the <ahref="https://leafletjs.com/examples/geojson/">Leaflet geojson docs</a> for more info on possible options.
NOTE: In order to pass over **style**, **pointToLayer**, **onEachFeature**, or **filter** functions they need to be serialised as follows... for example
This may cause the function node setting them to be in error, for example if it references L (the leaflet map), which is unknown on the server side. The flow should still deploy and run ok.
The `fit` property is optional, and you can also use `fly` if you wish. If boolean true the map will automatically zoom to fit the area relevant to the geojson, or use 'fly' to set the animated style. You can also set `clickable` true to return the properties of the clicked feature to the worldmap-in node.
As with the geojson overlay, you can also inject a KML layer, GPX layer or TOPOJSON layer. The syntax is the same but with either a `kml` property containing the KML string - a `gpx` property containing a GPX string - or a `topojson` property containing the topojson.
Again the boolean `fit` or `fly` properties can be added to make the map zoom to the relevant area, and the `visible` property can be set false to not immediately show the layer.
As per the geojson overlay you can also inject an ESRI ArcGIS FeatureLayer layer. The syntax is the same but with an `esri` property containing the url of the desired feature layer.
This may cause the function node setting them to be in error, for example if it references L.marker, which is unknown on the server side. The flow should still deploy and run ok.
When clicked the button will send an event to the `worldmap in` node containing `{"action":"button", "name","My Fancy Button"}` - this can then be used to trigger other map commands or flows.
{ "action": "layer", "name": "myLayer" } // when a map layer is changed
{ "action": "addlayer", "name": "myLayer" } // when a new map layer is added
{ "action": "dellayer", "name": "myLayer" } // when a new map layer is deleted
{ "action": "file", "name": "myfilename", "type":"image/jpeg", "lat":51, "lon":-1, "content":"....."} // when a file is dropped on the map - see below.
{ "action": "button", "name": "My Fancy Button" } // when a user defined button is clicked
{ "action": "feedback", "name": "some name", "value": "some value", "lat":51, "lon":0, "layer":"unknown" } // when a user calls the feedback function - see below
If File Drop is enabled - then the map can accept files of type gpx, kml, nvg, jpeg, png and geojson. The file content property will always be a binary buffer. The lat, lon of the cursor drop point will be included. Tracks will be locally rendered on the map. The `node-red-node-exif` node can be used to extract location information from a jpeg image and then geolocate it back on the map. Png images will be located where they are dropped but can then be dragged if required.
All actions also include a:
`msg._sessionid` property that indicates which client session they came from. Any msg sent out that includes this property will ONLY be sent to that session - so you can target map updates to specific sessions if required.
`msg._sessionip` property that shows the ip of the client that is connected to the session.
The "connected" action additionally includes a:
`msg.payload.parameters` property object that lists the parameters sent in the url.
`msg.payload.clientTimezone` property string showing the clients local Timezone. Returns bool of `false` if unable to retrive clients local Timezone.
`msg._clientheaders` property that shows the headers sent by the client to make a connection to the session.
### Utility functions
There are some internal functions available to make interacting with Node-RED easier (e.g. from inside a user defined popup., these include:
- **feedback()** : it takes 2, 3, or 4 parameters, name, value, and optionally an action name (defaults to "feedback"), and optional boolean to close the popup on calling this function, and can be used inside something like an input tag - `onchange='feedback(this.name,this.value,null,true)'`. Value can be a more complex object if required as long as it is serialisable. If used with a marker the name should be that of the marker - you can use `${name}` to let it be substituted automatically.
- **addToForm()** : takes a property name value pair to add to a variable called `form`. When used with contextmenu feedback (above) you can set the feedback value to `"_form"` to substitute this accumulated value. This allows you to do things like `onBlur='addToForm(this.name,this.value)'` over several different fields in the menu and then use `feedback(this.name,"_form")` to submit them all at once. For example a simple multiple line form could be as per the example below:
Also if you wish to retain the values between separate openings of this form you can assign property names to the value field in the form `value="${foo}`, etc. These will then appear as part of an **value** property on the worldmap-in node message.
```
var menu = 'Add some data <inputname="foo"value="${foo}"onchange=\'addToForm(this.name,this.value)\'></input><br/>'
menu += 'Add more data <inputname="bar"value="${bar}"onchange=\'addToForm(this.name,this.value)\'></input><br/>'
menu += '<buttonname="my_form"onclick=\'feedback(this.name,"_form",null,true)\'>Submit</button>'
msg.payload = { command: { "contextmenu":menu } }
```
- **delMarker()** : takes the name of the marker as a parameter. In a popup this can be specified as `${name}` for dynamic substitution.
- **editPoly()** : takes the name of the shape or line as a parameter. In a popup this can be specified as `${name}` for dynamic substitution.
## Serving maps
By default this node expects users to have access to the internet in order to access the map servers that provide all the built in mapping. As per above you are able to add your own sources of mapping and sometimes this includes the requirement for offline access, in which case maps must be served up locally. There are several ways to do this outlined below. My personal favourite is the Tileserver-gl docker option, but of course this does require Docker.
### Using PMtiles files
You can use a PMtiles format map archive file from [Protomaps](https://docs.protomaps.com/basemaps/downloads) as a base layer map.
**Note**: the whole planet file is over 100GB so be warned both for local storage and your download speed. You can download or extract just a portion of it if you use the **pmtiles** command line with the extract option. Use `pmtiles extract --help` to see the options.
Copy, or create an alias to, your .pmtiles file(s) into your `~/.node-red/node_modules/node-red-contrib-web-worldmap/worldmap/` directory. On re-starting Node-RED the node will detect the file(s) and add them to the base map layer menu, using the file name as the layer name.
### Using a Docker Map Server
I have found the easiest to use mapserver for decent generic map to be Tileserver-gl. It uses mbtiles format maps - for example from [MapTiler Data](https://data.maptiler.com/downloads/planet/). You can download your mbtiles file into a directory and then from that directory run
and use a url like `"url": "http://localhost:1884/styles/basic-preview/{z}/{x}/{y}.png"`
Other more traditional map servers include containers like https://hub.docker.com/r/camptocamp/mapserver, then assuming you have the mapfile 'my-app.map' in the current working directory, you could mount it as:
```
docker run -d --name camptocamp -v $(pwd):/etc/mapserver/:ro -p 1881:80 camptocamp/mapserver
```
then the url should be of the form `"url": "http://localhost:1881/?map=/etc/mapserver/my-app.map"` where *my-app.map* is the name of your map file. A quick test of the server would be to browse to http://localhost:1881/?map=/etc/mapserver/my-app.map&mode=map
Or you can use a docker container like https://hub.docker.com/r/geodata/mapserver/ then assuming you have the mapfile 'my-app.map' in the current working directory, you could mount it as:
```
docker run -d --name mapserver -v $(pwd):/maps:ro -p 1882:80 geodata/mapserver
```
and use a url like `"url": "http://localhost:1882/?map=/maps/my-app.map",`
Other useful map servers include Geoserver, a somewhat larger image but fully featured.
```
docker run --name geoserver -d -v ${PWD}:/var/local/geoserver -p 1885:8080 oscarfonts/geoserver
IMHO the easiest WMS map server to make work is the <ahref="http://www.mapserver.org/"target="mapinfo">mapserver</a> package in Ubuntu / Debian. Usually you will start with
Configuring that, setting up your tiles, and creating a **.map** file is way beyond the scope of this README so I will leave that as an exercise for the reader. Once set up you should have a cgi process you can run called `mapserv`, and a `.map` file that describes the layers available from the server.
Car, Bus and Helicopter icons originally made by <ahref="http://www.freepik.com"title="Freepik">Freepik</a> from <ahref="http://www.flaticon.com"title="Flaticon">www.flaticon.com</a> are licensed by <ahref="http://creativecommons.org/licenses/by/3.0/"title="Creative Commons BY 3.0"target="mapinfo">CC 3.0 BY</a>.