# Map Mixins
The underlying map object is based on Leaflet (opens new window) and some mixins also rely on Leaflet plugins (opens new window). The following set of mixins is to be used to construct a new map activity and underlying Leaflet objects.
# Base Map
WARNING
This mixin is a mandatory one to build a map activity
Make it possible to manage map layers and extend supported layer types:
- setupMap(domElement, options) creates the underlying Leaflet map object with given options
- addLayer(options)/removeLayer(name) registers/destroys a layer based on a catalog layer descriptor
- showLayer/hideLayer(name) (un)hides the given layer in map, on first show the layer will be lazily created
- hasLayer(name) check if a given layer is already registered
- isLayerVisible(name) check if a given layer is visible and underlying Leaflet object created
- zoomToLayer(name) fits the map view to visualize a given layer
- zoomToBounds(bounds) fits the map view to visualize a given extent as bounds [ [south, west], [north, east] ]
- getLayerByName(name) retrieve the catalog layer descriptor for a given layer
- renameLayer(previousName, newName) rename a given layer
- removeLayer(name) destroys a given layer
- getLeafletLayerByName(name) retrieve the underlying Leaflet object for a given layer
- createLeafletLayer(options) creates the underlying Leaflet object based on a catalog layer descriptor, will check all registered constructor for any one matching
- getLeafletPaneByName(name) retrieve the underlying Leaflet object for a given pane
- createLeafletPane(name) creates the underlying Leaflet object for a pane
- removeLeafletPane(name) destroys the underlying Leaflet object for a given pane
- registerLeafletConstructor(constructor) registers a Leaflet constructor function for a given type of layer
- center(longitude, latitude, zoomLevel) centers the map view to visualize a given point at a given zoom level
- getCenter() get the current map view center as longitude, latitude and zoom level
- getBounds() get the current map view bounds as
[ [south, west], [north, east] ]
- setCurrentTime(datetime) sets the current time to be used for time-based visualisation (e.g. weather forecast data or dynamic features)
This mixin also adds the following internal data properties:
- layers available layers as catalog layer descriptors
This mixin automatically includes some Leaflet plugins: leaflet-fa-markers (opens new window) to create markers using Font Awesome icons, Leaflet.fullscreen (opens new window) to manage fullscreen mode, Leaflet.markercluster (opens new window) to create marker clusters, Leaflet.VectorGrid (opens new window) to display vector tiles (opens new window).
# Managing panes
Although DOM-based layers like Markers (opens new window) could make use of a z-index
to possibly manage render order between them, SVG or canvas-based layers used to manage GeoJson features (opens new window) like Polylines (opens new window) provided no mean to do so. Similarly, there was no simple way to render some layers only at some specific zoom levels. This is the reason why Leaflet 1.0 introduced the concept of panes (opens new window).
If you add a zIndex
option to your layer descriptor we will create a dedicated pane for you under-the-hood so that the layer will be rendered at its right rank. Check the z-index
value of the default panes (opens new window) to select the appropriate one.
If you add a panes
option to your layer descriptor we will create the dedicated panes for you under-the-hood so that you can then set in the pane
option of any sublayer the pane it will belong to. Each pane must have a unique name and can be visible at specific zoom levels:
{
name: 'Layer',
...
panes: [{
name: 'waypoints',
minZoom: 7,
maxZoom: 14
}]
}
# Map Style
Make it possible to generate Leaflet map objects with style based on (Geo)Json (feature) properties:
- convertFromSimpleStyleSpec(style) helper function to convert from simple style spec options (opens new window) to Leaflet style options (opens new window)
- createMarkerFromStyle(latlng, style) helper function create a Leaflet marker (opens new window) from marker style options:
- icon icon style options
- type type name (ie constructor function) of the icon to be created for the marker, e.g.
icon
(opens new window) (defaults),divIcon
(opens new window) oricon.fontAwesome
(opens new window) - options icon constructor options
- type type name (ie constructor function) of the icon to be created for the marker, e.g.
- type type name (ie constructor function) of the marker to be created, e.g.
marker
(defaults) orcircleMarker
- options marker constructor options
- icon icon style options
Use register/unregisterStyle(type, generator) to (un)register a function generating a Leaflet object depending on the given type:
markerStyle
=> f(feature, latlng, options) returns a Leaflet marker (opens new window)featureStyle
=> f(feature, options) returns a Leaflet style object (opens new window)
TIP
The simple style spec options (opens new window) does not cover all Leaflet style options (opens new window). However you can use it simply by converting option names from camel case to kebab case.
Our mapping extends the simple style spec and can be used to create styles more easily:
weight
: mapped asweight
,radius
: mapped asradius
,line-cap
: mapped aslineCap
,line-join
: mapped aslineJoin
,dash-array
: mapped asdashArray
,dash-offset
: mapped asdashOffset
,marker-size
: mapped asicon.options.iconSize
,marker-symbol
: mapped asicon.options.iconUrl
,marker-type
: mapped astype
,icon-size
: mapped asicon.options.iconSize
,icon-anchor
: mapped asicon.options.iconAnchor
,icon-class
: mapped asicon.options.className
,icon-html
: mapped asicon.options.html
and automatically switch todivIcon
constructor function,icon-classes
: mapped asicon.options.iconClasses
and automatically switch toicon.fontAwesome
constructor function,marker-color
: mapped asicon.options.markerColor
foricon.fontAwesome
,icon-color
: mapped asicon.options.iconColor
foricon.fontAwesome
,icon-x-offset
: mapped asicon.options.iconXOffset
foricon.fontAwesome
,icon-y-offset
: mapped asicon.options.iconYOffset
foricon.fontAwesome
The mixin automatically registers defaults styling:
markerStyle
=> will create a marker based on the following options merged with the following order of precedence- simple style spec options (opens new window) set on feature.style or feature.properties
- simple style spec options (opens new window) set on layer descriptor
- Leaflet style options (opens new window) set on the pointStyle property in the component
featureStyle
=> will create a style based on the following options merged with the following order of precedence- simple style spec options (opens new window) set on feature.style or feature.properties
- simple style spec options (opens new window) set on layer descriptor
- Leaflet style options (opens new window) set on the featureStyle property in the component
# Map Popup
Make it possible to generate Leaflet popups (opens new window) based on GeoJson feature properties. Use register/unregisterStyle(popup
, generator) to (un)register a function f(feature, layer, options) returning a Leaflet popup (opens new window)
The mixin automatically registers a default generator that will create a popup displaying a property name/value table based on the following options with the following order of precedence
- popup: set on feature.properties or layer descriptor or in the popup property of component options
- pick: array of property names to appear in the popup
- omit: array of property names not to appear in the popup
- template: Lodash template (opens new window) to generate popup content with
feature
, itsproperties
and translation function$t
as context - text: text content of the popup, if provided will override default display
- options: Leaflet popup options (opens new window)
TIP
If you want to disable a default popup configuration like popup: { }
(i.e. display all properties) on a per-layer basis you have to explicitely unset it on your layer options using popup: null
or popup: false
.
# Map Tooltip
Make it possible to generate Leaflet tooltips (opens new window) based on GeoJson feature properties. Use register/unregisterStyle(tooltip
, generator) to (un)register a function f(feature, layer, options) returning a Leaflet tooltip (opens new window)
The mixin automatically registers a default generator that will create a tooltip based on the following options with the following order of precedence
- tooltip: set on feature.properties or layer descriptor or in the tooltip property of component options
- property: property name to appear in the tooltip
- template: Lodash template (opens new window) to generate tooltip content with
feature
, itsproperties
and translation function$t
as context - text: text content of the tooltip, if provided will override default display
- options: Leaflet tooltip options (opens new window)
TIP
If you want to disable a default tooltip configuration like tooltip: { property: 'name' }
(i.e. display all properties) on a per-layer basis you have to explicitely unset it on your layer options using tooltip: null
or tooltip: false
.
# GeoJson Layer
Make it possible to manage and style raw or time-based GeoJson map layers (Leaflet.Realtime plugin (opens new window) is used under-the-hood):
- createLeafletGeoJsonLayer(options) automatically registered GeoJson Leaflet layer constructor
- updateLayer(name, geoJson, remove) update underlying GeoJson data of a given layer, if
remove
istrue
it will remove given features from the layer, otherwise it will add new ones found and update matching ones based on thefeatureId
option
WARNING
The style mixin is mandatory when using this mixin. If you'd like to support popups/tooltips you should also use the popup mixin and/or tooltip mixin.
If your component has a onLeafletFeature(feature, layer, options) method it will be called each time a new GeoJson feature is created.
# Clustering
Marker clustering options (opens new window) are to be provided in the cluster property of the Leaflet layer options or in the cluster property of component options, with this order of precedence. The following configuration illustrates a GeoJson marker cluster layer using options set on the layer descriptor (see image below):
{
name: 'Layer',
description: 'My sites',
tags: [ 'business' ],
icon: 'star',
attribution: '(c) My company',
type: 'OverlayLayer',
leaflet: {
type: 'geoJson',
source: 'https://s3.eu-central-1.amazonaws.com/kargo/nuclear-sites.json',
cluster: {},
'marker-color': 'orange',
'icon-color': 'white',
'icon-classes': 'fa fa-star',
popup: {
pick: [ 'NAME' ]
},
tooltip: {
property: 'LABEL'
}
}
}
TIP
If you want to disable a default clustering configuration like cluster: { disableClusteringAtZoom: 18 }
on a per-layer basis you have to explicitely unset it on your layer options using cluster: null
or cluster: false
.
# Additional feature types
The following options can be set as feature properties
to manage more geometry types:
- geodesic boolean set to
true
on aLineString
will result in a geodesic line from the Leaflet.Geodesic (opens new window) plugin - geodesic boolean set to
true
on aPoint
will result in a great circle from the Leaflet.Geodesic (opens new window) plugin, which radius must be specified in meters
# Dynamic styling
Usually the same style is used for all features of a GeoJson layer, you might however require a more dynamic style base on each feature properties. To handle this use case you can either:
- provide styling options for each feature in their
properties
orstyle
field - use Lodash templating (opens new window) on layer styling options with feature and its properties as context
WARNING
Templating can only be efficient if compilers are created upfront, as a consequence you need to declare the list of templated options in your layer styling using the template
property.
For instance you can change the marker color or image based on a given features's property like this:
'marker-color': `<% if (properties.visibility < 75) { %>#000000<% }
else if (properties.visibility < 300) { %>#d20200<% }
else if (properties.visibility < 1500) { %>#f9b40f<% }
else if (properties.visibility < 3000) { %>#eef52f<% }
else { %>#33c137<% } %>`,
'marker-symbol': `<% if (properties.visibility < 75) { %>/statics/windyblack.png<% }
else if (properties.visibility < 300) { %>/statics/windyred.png<% }
else if (properties.visibility < 1500) { %>/statics/windyorange.png<% }
else if (properties.visibility < 3000) { %>/statics/windyyellow.png<% }
else { %>/statics/windygreen.png<% } %>`,
template: ['marker-color', 'marker-symbol']
You can also draw a path with a different styling on each part like this:
{
type: 'FeatureCollection',
features: [{
type: 'Feature',
properties: { stroke: '#000000', weight: 1 },
geometry: { type: 'LineString', coordinates: [...] }
}, {
type: 'Feature',
properties: { stroke: '#FF00FF', weight: 3 },
geometry: { type: 'LineString', coordinates: [...] }
}]
}
# Edit Layer
Make it possible to edit features of a GeoJson layer (geometry and properties):
- editLayer(name) start/stop layer edition on a given layer
- updateFeatureProperties(feature, layer, leafletLayer) update feature properties action handler that will open an editor to define feature properties
WARNING
It has to be used with the GeoJson layer mixin and will use the configured styling.
# File Layer
Make it possible to drag'n'drop GeoJson or KML file on the map (Leaflet.FileLayer plugin (opens new window) is used under-the-hood). It will automatically create a new GeoJson layer named after the filename on drop. As a consequence it has to be used with the GeoJson layer mixin and will use the configured styling.
# Forecast Layer
Make it possible to manage Weacast map layers (opens new window):
- createLeafletForecastLayer(options) automatically registered Weacast Leaflet layer constructor
WARNING
This mixin assumes that your component has initialized its Weacast client (opens new window) in the weacastApi
property by using e.g. the Weacast mixin
# Canvas Layer
Make it possible to draw custom graphic elements on top of other layers using HTML canvas elements. These custom graphic elements are defined by their draw function and are run in the client application, using a controlled draw context. It is not possible for these draw functions to access anything outside the specified context.
createLeafletCanvasLayer (options) is automatically registered to allow creation of such Leaflet layer. The following fields can be set on the options object:
- draw an array containing the same information as given to setCanvasLayerDrawCode drawCode parameter.
- userData an object containing user data that'll be usable in the draw code.
- autoRedraw boolean set to true if the canvas should automatically be redrawn every frame.
- pointerEventsEnabled boolean set to true to enable pointer events on the canvas layer (required if you use clickable elements).
- clickThroughEnabled boolean set to true to allow click events to go through the canvas layer when no clickable elements were clicked (requires pointerEventsEnabled to work).
setCanvasLayerDrawCode (layerName, drawCode, autoRedraw) define the draw code used by the layer named
layerName
.autoRedraw
is a boolean used to enable automatic refresh of the layer at each displayed frame (required eg. to animate elements).drawCode
is expected to be an array of objects where each object is of the following form :{ feature: 'LAYER_NAME?FEATURE_NAME', code: '... some javascript draw code ...' }
will run the given draw code only for the feature namedFEATURE_NAME
in the layer namedLAYER_NAME
.{ layer: 'LAYER_NAME', code: '... some javascript draw code ...' }
will run the given draw code for each feature of the layer namedLAYER_NAME
.
setCanvasLayerUserData (layerName, userData) is used to add some custom user data to the draw context. The
userData
object parameter will be merged into theuserData
object available on the draw context. This allows users to push partial updates, there's no need to push the whole user data every time a single member changes.setCanvasLayerAutoRedraw (layerName, autoRedraw) is used to enable or disable automatic redraw of the canvas layer named
layerName
. Automatic redraw may be required for example when animating objects. By default automatic redraw is off, which means that the canvas layer will only redraw when :- the user moves the map
setCanvasLayerDrawCode
is calledsetCanvasLayerUserData
is called
The following configuration illustrates a layer used to draw feature property name as text at the feature position for all features of the layer named Airports.
{
name: 'AirportNames',
type: 'OverlayLayer',
icon: 'local_airport',
leaflet: {
type: 'kanvasLayer',
isVisible: true,
draw: [
layer: 'Airports', code: `
const props = ctx.feature.properties
const coords = {
lat: ctx.feature.geometry.coordinates[1],
lon: ctx.feature.geometry.coordinates[0]
}
const pos = ctx.latLonToCanvas(coords)
ctx.canvas.font = '10px sans-serif'
ctx.canvas.fillStyle = '#ffb300'
ctx.canvas.fillText(ctx.feature.properties.name, pos.x, pos.y)
`
]
}
}
The ctx
object is the draw context and is the only object available from the draw code.
By default, the following fields are available on the draw context :
- canvas the canvas rendering interface by which the drawing will occur. Draw api is available here (opens new window).
- now the time of the draw function call, can be useful to animate things.
- zoom the current map zoom value.
- latLonToCanvas (coords) project from latitude/longitude to canvas coordinates (pixels).
- addClickableFeature (geojson, path, clickStyle) add a clickable path element (opens new window) associated with the
geojson
feature. When clicked, it will emit a 'clicked' event with the associated feature as event data. - clearClickableFeatures () clear all the clickable features that have been added so far.
- userData object where all the user data pushed through
setCanvasLayerUserData
has been merged. - vec2 (a, b) build a vec2 object from two points (where points and vec2 are objects with
x
andy
members ). - len2 (vec) compute length of a vec2 vector.
- scale2 (vec, value) scale a vec2 vector by
value
. - norm2 (vec) return the corresponding normalized vec2 vector.
TIP
It is possible to extend what's available in the draw context from the application using the CanvasDrawContext
singleton. In this case you should call CanvasDrawContext.merge(contextAdditionObject)
to merge the content of contextAdditionObject
with the draw context. This call must be done before the canvas layer mixin is created. This can be useful to build an application specific library of draw functions and make these available to the canvas layer instances.
# Map Activity
Make it easier to create 2D mapping activities:
- initializeMap() setup the mapping engine, should be called first before any other method
- finalizeMap() destroy the mapping engine
WARNING
It assumes that the DOM element used by the render engine has a ref named map
← Mixins Globe Mixins →