-
Notifications
You must be signed in to change notification settings - Fork 25
MAPP
MAPP is a library for web mapping applications based on Openlayers map component.
The mapp.dictionary is an object proxy. The get handler will use the mapp.language (default: en
) value to lookup the requested key in the mapp.dictionaries. The English value will be returned if mapp.language entry has not been specified.
new Proxy({}, {
get: function(target, key, receiver){
if (mapp.dictionaries[mapp.language][key]) {
return mapp.dictionaries[mapp.language][key]
}
return mapp.dictionaries.en[key]
}})
The mapp.dictionaries object can be extended in any of the javascript modules imported into the mapp library.
Mapview is a decorator method. Methods and properties are assigned to the mapview object provided as argument. The decorated mapview object is returned.
export default (mapview) => {
Object.assign(mapview, {
srid: mapview.locale.srid || '3857',
addLayer,
fitView,
geoJSON,
getBounds,
infotip,
locate,
popup,
layers: {},
locations: {},
interactions: {
highlight: _highlight.bind(mapview),
draw: _draw.bind(mapview),
modify: _modify.bind(mapview),
zoom: _zoom.bind(mapview),
}
})
Valid mapview keys and values are:
mapp.Mapview({
host: '/mapp', // REQUIRED; Can be relative
target: 'Map', // REQUIRED; Can be string or instanceOf HTMLElement
hooks: true,
locale: {
extent: {
north: 62, //lat
east: 11, //lng
south: 48, //lat
west: -19, //lng
mask: true,
},
view: {
lat: 54.3,
lng: -4,
z: 4,
},
minZoom: 4,
maxZoom: 18,
},
scrollWheelZoom: true,
scalebar: 'metric', //'imperial'
controls: [new ol.control.Zoom()], // Adds OL zoom control
attribution: {
target: document.getElementById('Attribution'),
links: {
[`XYZ v${mapp.version}`]: "https://geolytix.github.io/xyz",
Openlayers: "https://openlayers.org",
}
}
})
Setting hooks: true
will update the URL parameter when the viewport changes.
The mapview.Map control is an OL Map interface assigned by the Mapview decorator.
The mapview.Map pointermove event updates the mapview.position and mapview.pointerLocation properties when triggered.
The mapview.Map mouseout event sets the mapview.position and mapview.pointerLocation properties to null when triggered.
The mapview.Map changeEnd event updates the lat, lng, and z URL view hooks when triggered.
The mapview.Map moveend event debounces the changeEnd evnt.
mapview.layers is a key/value list of layers which have been added to a mapview with the mapview.addLayer method. The layer key can be used to lookup a layer in the list. With hooks enabled on the mapview a comma seperated list of layers with display: true
is maintained as the layers URL parameter value.
mapview.locations is a key/value list of selected locations. A location key is composed of the location's layer key and id (eg. stores|23
). The mapp.location.get method will add a location to the locations list. With hooks enabled on the mapview a comma seperated list of location keys is maintained as the locations URL parameter value.
A single layer, or an array of layers provided as argument to the mapview.addLayer method will be cloned and assigned to the mapview.layers list. The layer.display flag will be set according to the current mapp hooks if hooks are enabled for the mapview. The layer.show() method will be called if layer.display is truthy.
Fits view[port] of the mapview.Map control to the provided extent. The options argument is passed on to the OL view.fit() method as opt_options. The options argument allows to override defaults for the duration of the transition animation and viewport padding.
The mapview.geoJSON method reads a single geoJSON geometry provided as params.geometry. The geometry will be transformed to the mapview.srid projection if an SRID/EPSG code is provided as params.dataProjection. The zIndex for the layer can provided as param. A new OL vector source and layer will be created. The layer will be added to the mapview.Map and returned. The style for the vector layer must be provided as params.Style.
mapview.geoJSON({
zIndex: infinity,
geometry: {
type: 'Point',
coordinates: entry.value,
},
dataProjection: '4326' // EPSG|SRID
// The Style param must be provided as OL Style object.
Style: mapp.utils.style({
strokeColor: "#F00",
strokeWidth: 2,
})
})
mapview.getBounds returns the calculated extent from the mapview.Map view[port]. The extent is returned as a object with north, east, west, and south keys for the individual edge values. The values are transformed to a target projection if an srid argument is provided as EPSG/SRID code.
The infotip method will create an .infotip
element with the content provided as HTML element. The infotip element position will update when a mapview pointermove event is triggered. Only one infotip element per mapview is valid. The current infotip will be cleared before a new element is created. A falsy argument (eg. null) will simply clear the infotip without creating a new element. The pointermove event will be unset when the current infotip element is cleared.
mapview.locate will draw an icon on the browser navigator position retrieved from mapp.utils.getCurrentPosition. The icon will be removed from the mapview.Map if mapview.locate is called again.
The infotip method creates a .popup
element with params.content provided as HTML element. Unlike the infotip element, the popup element has a static position. The position can be provided as params.coords. Otherwise the element is on the current mapview.position. Only one popup element per mapview is valid. The current popup will be cleared before a new element is created. Providing null as argument will clear the popup element.
The Mapview() decorator method binds interactions as mapview.interactions:{}
. The current interaction is assigned as mapview.interaction:{}
. An interaction must first complete the current interaction by calling mapview.interaction?.finish()
before assigning itself as current. Any interaction pointer events must be unassigned in the execution of the finish() method.
The params argument passed to an interaction will be assigned to the interaction object itself before the interaction is set as current mapview.interaction:{}
.
The draw interaction provides an interface to OL drawing tools. A newly drawn simple geometry will be returned from a valid drawing input.
The highlight interaction monitors pointer move, touch, and click events on the mapview. The interaction will visually highlight a map feature at the pointer pixel location and get the associated location for the feature on the pointer click event.
mapview.Map.forEachFeatureAtPixel() will find a Set of candidate features within the hitTolerance that pass the layerFilter. If not specified in the params, the default layerFilter() will look at all mapview.layers:{}
which have a qID
. The pointerMove event will check whether the Set of features changes. The top most feature from a changed Set will be passed to interaction.highlight()
. A string noChange
will be provided if the Set of candidate features is unchanged during the pointerMove event.
The default highlight() method will assign the highlighted feature as interaction.current:{}
. The feature id is assigned as layer.highlight
. The default interaction.highlight method will return without further action if the original pointer event is 'touch'. If defined as a function layer.hover() will be called with the highlight feature as argument. A highlight flag and the style will be set on the feature if supported. Otherwise the changed() event will be called on the Openlayers layer.L:{}
forcing a re-render of the layer canvas. The render will check whether the highlight ID on the layer matches a feature ID to determine whether a highlight style should be applied to the feature.
The clear() method removes the interaction.current:{}
assignment and resets the styling of associated feature and layer.
The singleClick() event method will emulate a pointerMove() event to determine which feature should be highlighted. The getLocation() method is called from the singleClick event. The default getLocation() method which is called from the singleClick will call mapp.location.get() with properties from the current highlight feature. mapp.location.nnearest() will be called if the feature consists of multiple locations.
const interaction = Object.assign({
type: 'highlight',
finish, // finish highlight interaction
clear, // clears current highlight in map
highlight, // callback for highlight event
getLocation, // callback for getLocation event
hitTolerance: 5, // in pixel
candidateKeys: new Set(),
layerFilter: L => Object.values(mapview.layers).some(layer => layer.qID && layer.L === L)
}, params)
The modify interaction provides access to OL modify tools to modify a provided input geometry.
The zoom interaction will draw a temporary rectangular polygon. The mapview.Map view[port] will be set to fit the extent of the drawn zoombox.
A Mapp Layer is an interface for spatial data. Layer are defined as JSON objects in the layers array of a Workspace Locale. A valid layer must have a format and a data source connection (dbs) defined. The XYZ host will assign defaults to a layer object.
A mapview must be assigned to the layer object in order to decorate a layer.
The layer decorator passes the layer to a defined format method which assigns the Openlayers layer object (L).
Common interface methods such as layer.show, and hide are assigned to the layer object.
A blank layer.filter object will be set if the filter has not been defined in the JSON layer.
The first theme from the layer.style.themes array will be assigned as layer.style.theme if not already set.
Any plugins matching layer keys will be executed with the layer being passed as argument to the plugin method.
The layer object is returned from the decorator.
The layer's display property will be set to true.
The OL layer layer.L will be removed first and then add to the mapview.map control. This is to prevent that the layer.L is added more than once to the map control.
A displayTrue
event will be dispatched to the layer's view.
The layer's attribition will be added to the mapview.
An URL parameter hook is added if enabled for the mapview.
The layer's display property will be set to false.
The OL layer layer.L will be removed from the mapview.map control.
A displayFalse
event will be dispatched to the layer's view.
The layer's attribition will be removed from the mapview.
An URL parameter hook is removed if enabled for the mapview.
Return layer table value for the current zoom level. Will return the first or last table (maybe null) if the current zoom level exceeds the range defined in layer.tables.
Return the last table value from the layer.tables object which is not null.
Return the first table value from the layer.tables object which is not null.
The layer.style method has access to the layer object and receives an OL feature as only argument.
An array of features can be assigned to a layer as featureLookup. A feature will not be styled if the featureLookup is set but the feature is not found in the array. The lookup feature properties will be assigned to the current feature for subsequent styling.
The style.cluster is assigned to the style.default for features with a count of more than 1, indicating a cluster of multiple locations.
The style.label object is assign to the style object.
For point geometry features, the style.icon object is assigned from a clone of the style object if an icon style is not defined in the style object. The scale and clusterScale will be removed from the root of the style object.
The theme style associated with a cat property value is assigned to the feature style.
The clusterScale is applied to the style.icon. The clusterScale is the icon scale for the cluster with the largest size. The size is either the count of locations in a cluster or the aggregate sum of field.values for all locations grouped in a cluster. Scaling is either linear or logarithmic (logScale
) between the smallest (or single location) and largest cluster.
// The clusterScale will be added to the icon scale.
style.icon.clusterScale = layer.style.logScale ?
// A natural log will be applied to the cluster scaling.
Math.log(style.icon.clusterScale) / Math.log(layer.max_size) * Math.log(properties.size || properties.count) :
// A fraction of the icon clusterScale will be added to the items scale for all but the biggest cluster location.
1 + (style.icon.clusterScale / layer.max_size * (properties.size || properties.count))
zoomInScale and zoomOutScale are applied to icon styles based on the current zoom level.
The highlightStyle is applied for a feature whose ID is set as the layer.highlight value.
The style.label text value is assigned for feature labels.
An OL style is returned to the layer render method. The OL style is returned from utils.style which receives the JSON style and feature as arguments.
The layer.format.cluster assigns an OL vector layer and source in the mapp.layer.decorate method. The cluster loader method is triggered from the mapview.Map changeEnd event. The loader method sends an XHR to the mapview.host with parameters inferred from the current viewport and style configuration. The loader method will create OL features from projected coordinates in the cluster response. A new OL vector source with the features will be assigned to the vector layer, effectively removing the existing source and features. The current max value will be calculated from the cluster response and assigned to the layer in order to calculate the cluster icon scale. Setting the vector source on the existing vector layer will automatically trigger the assigned layer.style method.
GeoJSON format layer request data from the GeoJSON API. Data is not requested on viewport changes but only when the layer.reload() method is called. Setting type:"cluster"
on the layer will assign the vector source to a cluster source with the distance defined as layer.cluster_distance
.
Locations are functional mapp objects. Locations are not selected but need to have a layer assigned in order to get the location data from the location/get API. The schema for location data is configured as an array of entries layer.infoj[] in the workspace.
A location object with a layer and id value must be provided to the mapp.location.get() method. A request will be sent to the location/get API. The response from the request will populate the entry values in the location.infoj[] array.
The location.infoj[] array holds entry objects for the location as configured in the JSON layer.infoj[] in the workspace.
mapp.location.decorate() will assign location methods and callback arrays to the location object passed as argument.
The location.flyTo() method will fit the view of the location.layer.mapviev{} to the extent of all features in all OL layers in the location.Layers[] array.
The OL layer objects for geometries associated to a location are stored in the location.Layers[] array.
The location.remove() method will remove all location.Layers[] from the location.layer.mapview{} and set the highlight interaction on the mapview. This is to ensure that any interaction initiated from a location entry is finished. An instanceof HTMLElement assigned as layer.view will be removed from the document. The location.hook will be filtered from the URL locations parameter and the location.layer.mapview.locations{} list object. The location.layer will be redrawn after a location is removed. Finally each method from the location.removeCallbacks[] array will be called.
If confirmed the location will be removed from the datasource first by sending the location details to the location/delete API. Thereafter the location.remove() method will be called.
The location.update() method will send a post request to the location/update API. The request body contains a filtered location.infoj array with only the entries which have values as newValue assigned. After a successful update the method will query all dependent entry fields and call all methods from the location.updateCallbacks[] array.
Checks whether two Sets are equal.
(a, b) => a.size === b.size && [...a].every(value => b.has(value))
The loadPlugins util take a single or an array of resource locator and attempt to load each as a dynamic module import. The utility will await for all dynamic imports to resolve.
The merge util assigns values from source objects to the target object. Matching target key values will be overwritten. A deep merge is performed by recursive iteration through the object.
The promiseAll util takes an array of promises and resolves once all promises have been resolved.
The style utility method receives a JSON style object, and an OL feature as optional argument and returns an OL style object. The OL style is created from stroke, fill, image(icon), and text(label) OL style objects. Icon styles are memoized prior to being scaled. The scale applied to an icon is calculated from the base scale, clusterScale, zoomInScale, zoomOutScale, and highlightScale.
svgSymbols is a collection of methods which return encoded and serialized SVG from a parameterized request.
The methods are:
- dot
- target
- triangle
- square
- diamond
- semiCircle
- markerLetter
- markerColor
- circle
- template
The xhr util wrap an XMLHttpRequest in a promise. Requests can be provided as a params object. Supported parameter are:
- url: The request URL.
- responseType: The requests response type, defaults to
json
. - body: A post request will be made a body is provided.
- cache: The response will be cached in a Map collection.
- requestHeader: An object with key/values representing the requestHeader sent with the request.
Provided as a string the method argument will evaluated as the URL param.
URL parameter can be inspected and set with the hooks module. Upon initialisation of the mapp module, URL parameter are parsed and stored in the mapp.hooks.current object.