HTMLMapmlViewerElement
The HTMLMapmlViewerElement interface represents the <mapml-viewer>
element.
Properties
Property name | Description |
---|---|
controls | Turns native map controls on or off. Reflects the controls attribute. |
controlsList | Allows to change the set of native controls. Reflects the controlslist attribute. |
extent | Returns the extent of the current map view. Read only. |
lat | Get or set the map's latitude. Reflects to the lat content attribute. No effect on map dynamic state. |
lon | Get or set the map's longitude. Reflects to the lon content attribute. No effect on map dynamic state. |
projection | The map's projection. Reflects the projection attribute. |
zoom | Get or set the map's zoom level. Reflects to the zoom content attribute. No effect on map dynamic state. |
controls
To add controls to the map:
let map = document.querySelector('mapml-viewer');
map.controls = true; // or false to remove controls
To check whether the map has controls toggled on or off:
let map = document.querySelector('mapml-viewer');
let controlsAdded = map.controls;
controlsList
The controlsList
property returns a DOMTokenList
that helps the user select what controls to display on the mapml-viewer
element based on the possible values.
To set the controlslist attribute:
let map = document.querySelector('mapml-viewer');
map.controlsList.value = "noreload nozoom"; // values can be noreload | nofullscreen | nozoom | nolayer
map.controlsList.add("nofullscreen"); // can also add using the 'add' method
map.controlsList.toggle("nolayer"); // can also toggle using the 'toggle' method
// view all methods here - https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList
To get the value of the controlslist:
let map = document.querySelector('mapml-viewer');
let controlsList = map.controlsList.value;
extent
Read-only. To get the map's extent:
let map = document.querySelector('mapml-viewer');
let extent = map.extent;
View Sample Extent
/**
*extent =
* {
* {
* "topLeft": {
* "tcrs": [
* {
* "horizontal": 906.7586206896551,
* "vertical": 981.7241379310345
* },
* ...
* ],
* "tilematrix": [
* {
* "horizontal": 3.5420258620689653,
* "vertical": 3.8348599137931036
* },
* ...
* ],
* "gcrs": {
* "horizontal": -93.05456518322721,
* "vertical": 63.783997873304855
* },
* "pcrs": {
* "horizontal": 131686.24163915217,
* "vertical": 1646487.1729743406
* }
* },
* "bottomRight": {
* "tcrs": [
* {
* "horizontal": 914.9655172413793,
* "vertical": 1015.5172413793102
* },
* ...
* ],
* "tilematrix": [
* {
* "horizontal": 3.574084051724138,
* "vertical": 3.9668642241379306
* },
* ...
* ],
* "gcrs": {
* "horizontal": -85.62509797700041,
* "vertical": 52.14641630380798
* },
* "pcrs": {
* "horizontal": 446541.0380154103,
* "vertical": 350026.2467191592
* }
* },
* "projection": "CBMTILE",
* "zoom": {
* "minZoom": 0,
* "maxZoom": 25
* }
* }
* }
*/
lat
To set the latitude:
let map = document.querySelector('mapml-viewer');
map.lat = 21.4; // if it's an invalid value, nothing happens
Note that the value supplied does not affect the map viewer state, except at
document load, or when an instance of a <mapml-viewer>
element is constructed
and programmatically added to the DOM. To change the value, use zoomTo();
To get the latitude:
let map = document.querySelector('mapml-viewer');
let latitude = map.lat;
lon
To set the longitude:
let map = document.querySelector('mapml-viewer');
map.lon = 21.4; // if it's an invalid value, nothing happens
Note that the value supplied does not affect the map viewer state, except at
document load, or when an instance of a <mapml-viewer>
element is constructed
and programmatically added to the DOM. To change the value, use zoomTo();
To get the longitude:
let map = document.querySelector('mapml-viewer');
let longitude = map.lon;
projection
To set/update the projection:
let map = document.querySelector('mapml-viewer');
map.projection = "CBMTILE"; // if it's an invalid/undefined projection, nothing happens
To get the projection:
let map = document.querySelector('mapml-viewer');
let projection = map.projection;
zoom
To set the zoom:
let map = document.querySelector('mapml-viewer');
map.zoom = 3; // if it's an invalid value, will default to 0
Note that the value supplied does not affect the map viewer state, except at
document load, or when an instance of a <mapml-viewer>
element is constructed
and programmatically added to the DOM. To change the value, use zoomTo();
To get the longitude:
let map = document.querySelector('mapml-viewer');
let zoom = map.zoom;
Methods
Method | Description |
---|---|
back() | Navigates back one state in the map's movement history. |
forward() | Navigates forward in the map's panning history. |
reload() | Clear the map's panning history and return to the starting location. |
toggleDebug() | Toggle the debug functionality of the map. |
viewSource() | View the source of the map. |
defineCustomProjection(options) | Define a custom projection for use by the page. |
zoomTo(lat, lon, zoom) | Fly or pan the map to a (new) location and zoom level. |
geojson2mapml(json, options) | Add a GeoJSON Layer to the map. |
matchMedia(mediaQueryString) | Returns a MediaQueryList-like object. |
back()
To go back in the map's history:
let map = document.querySelector('mapml-viewer');
map.back();
forward()
To go forward in the map's history:
let map = document.querySelector('mapml-viewer');
map.forward();
reload()
To clear the map's history and return to the initial location:
let map = document.querySelector('mapml-viewer');
map.reload();
toggleDebug()
To toggle the map's debug mode:
let map = document.querySelector('mapml-viewer');
map.toggleDebug();
viewSource()
To view the map's view source:
let map = document.querySelector('mapml-viewer');
map.viewSource();
defineCustomProjection(options)
MapML defines a few built-in tiled CRS projections, including Web Mercator (OSMTILE), pseudo-plate carrée (WGS84), and Canada's base map tile grid (CBMTILE).
The <mapml-viewer>
custom element provides the custom projections API, which gives you the ability to create custom projections and use them in the <mapml-viewer>
element, defined using extended JSON-based "proj4" syntax, supported by the proj4js library.
We won't discuss the actual <mapml-viewer>
element here, except to say that the map projection
attribute should have the exact same value of the projection
member of the JSON object you pass to the custom projections API's defineCustomProjection
method, and every <map-layer>
element in the map must declare and be encoded in that coordinate system, in order to display correctly.
The custom projections API is provided by the <mapml-viewer>
element. In a browser implementation, the API might be defined on the window object, but because of the ES6 modules used by custom elements, it is convenient to locate it on the mapping element which uses it.
To successfully call the defineCustomProjection
method, you need to encode the projection method and parameters as members of a JSON string. The process of doing this is not always simple, but is helped by resources such as https://spatialreference.org, where you can obtain the proj4 version of virtually any CRS definition.
Remember to enclose member names in quotes followed by a colon: e.g. "projection": "MY_PROJECTION_NAME". String values are also enclosed in quotes, and numbers and arrays following normal JSON syntax.
There are several required members to a custom projection definition:
projection
- this is a string name you give to your projection. We recommend using UPPERCASE to make projection names stand out. Colon ":" characters in the name are not permitted, because these names should not be confused with EPSG: or ogc: URI code lists, because what is being defined here is a CRS that has Web mapping specific parameters, discussed below.proj4string
- This string is processed by proj4js, so needs to provide parameters of a projection method supported by that library, in the format that it supports.origin
- an array of two numbers representing the origin of the tile grid in coordinates of the projected coordinate system, typically meters. The origin is always at the upper left of the tile grid space, and the column and row numbers increase to the right and down, respectively, following the WMTS standard. If your tile source is configured according to the "TMS" community standard, youresolutions
- an array of numbers, sorted in descending order of size in meters, of the "real-world" dimensions of a square pixel. The resolution is calculated using a nominal pixel size of 0.28mm, defined by the WMTS standard. NOTE THIS IS NOT TYPICALLY THE SAME VALUE THAT IS USED BY ESRI TILE SERVICES, WHICH USE 96 DPI AS THE NOMINAL SIZE (settable). Because scale varies over the extent of any projected coordinate system, the pixel resolution is usually valid only in limited locations, for example in Web Mercator, along the equator. The locations where pixel resolution is valid depend on the projection method and parameters. The set of resolutions must match the set of resolutions of tiles in a cache, if you intend to use your custom projection with an existing tile service.bounds
- an array of two arrays of coordinate pairs, defining a bounding box around part of the projected coordinate system, in meters typically. Requests should be valid and latitude / longitude are defined within these bounds. Requests for maps, tiles and coordinate transformations that fall completely outside these bounds will not execute, preventing redundant traffic and errors.tilesize
- tiles are always square, and usually 256 pixels on a side. You can specify another size here as an integer value. Values of 256, 512, 1024, 2048 or 4096 should work.
zoomTo(lat, lon, zoom)
To change the map's center location and zoom level:
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
var crd = pos.coords;
let map = document.querySelector('mapml-viewer');
map.zoomTo(crd.latitude,crd.longitude, 17); // hard-coded zoom
// could calculate a zoom based on accuracy of position
console.log(`More or less ${crd.accuracy} meters.`);
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
navigator.geolocation.getCurrentPosition(success, error, options);
geojson2mapml(json, options)
Convert a GeoJSON feature or feature collection string or object to MapML <map-layer>
containing one or more <map-feature>
elements. Returns and adds the converted layer element to the map.
Check out this application using the geojson2mapml API!
Parameters
Parameter | Description |
---|---|
<String | Object> json | A GeoJSON string or object. |
<Object> options | Optional. A set of key/value pairs that customize the output MapML layer. All options are optional and described below. |
Options
<Object> A set of key/value pairs that customize the output MapML layer. All options are optional and detailed below.
Option | Type | Default | Description |
---|---|---|---|
label | <String> | json.name , json.title or "Layer" | Sets the output layer's label. |
projection | <String> | map .projection or OSMTILE | Sets the output layer's projection. Defined values include: OSMTILE , CBMTILE , WGS84 , and APSTILE . |
caption | <String | Function> | json.features[i].id or the label value | A function that accepts the feature JSON and returns a string, OR a string that is the name of a property to be mapped to the featurecaption. If a matching property is not found, the string provided will be used as the feature caption value. See basic options usage for an example. |
properties | <Function | String | HTMLElement> | Properties will be mapped to an HTML table. | Specifies how the properties are mapped. <Function> - A function that accepts one argument - the GeoJSON feature object - and which must return an HTMLElement that becomes the single child element of the <map-properties> element. <String> - A string that will be parsed and used as the single child element of the <map-properties> element for all features. <HTMLElement> - an element that will be used as the single child element of <map-properties> element for all features. See basic options usage for an example. |
geometryFunction | <Function> | MapML geometry will mirror the GeoJSON geometry value | <Function> A function to modify the generated descendants of <map-geometry> which can add classes, hyperlinks and span's to the instance. Plain <map-geometry> element will be created by default. The function accepts two arguments: The generated child element of <map-geometry> and the feature json object to return a modified child element of the <map-geometry> element. See basic options usage for an example. |
matchMedia(mediaQueryString)
While not strictly 'media' features, some dynamic map properties can be combined in queries with standard media features, for example the 'prefers-color-scheme' feature, to enable a map container / media-query-like interface.
matchMedia(mediaQueryString)
returns a MediaQueryList-like object.
The matches
boolean-valued property of the object can be used for an immediate determination of whether the map meets the queried feature conditions. To react to changes in
the map state / media conditions, use MediaQueryList.addEventListener('change', callbackFn) to add an event listener for change
events that are triggered by changes in the
state of the queried map properties (projection, zoom, extent); any change to the map that results in a change in state of the MediaQueryListEvent matches
boolean propertytriggers the change
event and calls the callbackFn.
Supported map 'media' query features
Feature name | Description |
---|---|
map-zoom | Range of integers Used to evaluate if map-zoom is of a certain value or within a range |
map-projection | Discrete string values - known values include OSMTILE , CBMTILE , WGS84 , APSTILE . Can be extended with custom projections. |
map-top-left-easting | Range of integers - Decimal values are not supported. |
map-top-left-northing | Range of integers - Decimal values are not supported. |
map-bottom-right-easting | Range of integers - Decimal values are not supported. |
map-bottom-right-northing | Range of integers - Decimal values are not supported. |
prefers-map-content | Discrete string values - supported values include: image , tile , feature , table . Preferences can be established via multi-select in the MapML browser extension |
prefers-color-scheme | Discrete string values - supported values are light and dark |
prefers-lang | 2-character language code returned by navigator.language , based on user's browser display language setting |
Events
Event name | Description |
---|---|
layerchange | Fired when a layer changes src, usually by the user following a link. |
load | Fired when all layers have finished loading content |
click | Fired when the map receives both mousedown and mouseup events |
dblclick | Fired when the user double clicks or taps the map |
mousemove | Fired repeatedly as the mouse cursor traverses the map |
mouseover | Fired once as the mouse cursor enters the map |
mouseout | Fired once as the mouse cursor exits the map |
mousedown | Fired when the mouse's primary key is pressed down with cursor over the map |
mouseup | Fired when the mouse's primary key is released with cursor over the map |
movestart | Fired before the map starts to move / viewport changes |
move | Fired repeatedly as the map moves. |
moveend | Fired after the map stops moving |
zoomstart | Fired before the map changes zoom level |
zoom | Fired repeatedly as the map changes zoom |
zoomend | Fired after the map has changed zoom level |
preclick | Fired before a click on the map is triggered. May not be a primitive. |
contextmenu | Fired when user right-clicks or long presses on map. May not be a primitive. |
Examples
geojson2mapml
Basic options usage
Showcasing how use each option.
- label
- projection
- caption
- properties
- geometryFunction
geojson2mapml(json, {label: "Downtown Ottawa"});
geojson2mapml(json, {projection: "CBMTILE"});
// caption function
geojson2mapml(json, {caption: function(feature) {
return feature.properties.desc + ", not a Polygon";
}
});
// caption option string value referencing a property name
geojson2mapml(json, {caption: "desc"});
// properties function
geojson2mapml(json, {properties: function(feature) {
let parser = new DOMParser();
return parser.parseFromString("<h1>" + feature.properties.desc + "'s property</h1>", "text/html").body.firstChild;
}
});
// properties option - string valued - make sure you sanitize user-supplied strings
geojson2mapml(json, {properties: "<p>This property was inserted using a properties string</p>"});
let options = {
geometryFunction: function (g, f) {
g.setAttribute("class", f.properties.class);
return g;}
};
geojson2mapml(json, options);
Options string
An example showcasing how strings can be used to set label
, projection
, caption
and properties
options.
let map = document.querySelector('mapml-viewer');
let json = {
"name": "Default Name",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-75.6916809,45.4186964]
},
"properties": {"desc": "This is a Point"}
};
// GeoJSON To MapML
let output = map.geojson2mapml(json, {label: "Example 1", projection: "CBMTILE", caption: "desc", properties: "<h3>This is a property heading</h3>"});
Click to view the output HTMLElement
<map-layer label="Example 1" checked="">
<map-meta name="projection" content="CBMTILE"></map-meta>
<map-meta name="cs" content="gcrs"></map-meta>
<map-feature>
<map-featurecaption>This is a Point</map-featurecaption>
<map-geometry>
<map-point>
<map-coordinates>-75.6916809 45.4186964</map-coordinates>
</map-point>
</map-geometry>
<map-properties>
<h3>This is a property heading</h3>
</map-properties>
</map-feature>
</map-layer>
Options function
An example showcasing how functions can be used to set caption
and properties
options.
let map = document.querySelector('mapml-viewer');
let json = {
"name": "Default Name",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-75.6916809,45.4186964]
},
"properties": {"desc": "This is a Point"}
};
// function to set caption
let cap = function c(j) {
let str = "This point is located at: (" + j.geometry.coordinates[0] + ", " + j.geometry.coordinates[1] + ").";
return str;
}
// function to set properties
let prop = function f(p) {
let parser = new DOMParser();
return parser.parseFromString("<h1>" + p.properties.desc + "'s property</h1>", "text/html").body.firstChild;
}
// GeoJSON To MapML
let output = map.geojson2mapml(json, {label: "Example 2", caption: cap, properties: prop});
Click to view the output HTMLElement
<map-layer label="Example 2" checked="">
<map-meta name="projection" content="OSMTILE"></map-meta>
<map-meta name="cs" content="gcrs"></map-meta>
<map-feature>
<map-featurecaption>This point is located at: (-75.6916809, 45.4186964).</map-featurecaption>
<map-geometry>
<map-point>
<map-coordinates>-75.6916809 45.4186964</map-coordinates>
</map-point>
</map-geometry>
<map-properties>
<h1>This is a Point's property</h1>
</map-properties>
</map-feature>
</map-layer>
Default options
An example showcasing default output when no options are provided.
let map = document.querySelector('mapml-viewer');
let json = {
"title": "Point Geometry",
"bbox": [-75.916809, 45.886964, -75.516809, 45.26964],
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-75.6916809, 45.4186964]
},
"properties": {
"prop0": "This is a Point"
}
}]
};
// GeoJSON To MapML
let output = map.geojson2mapml(json);
Click to view the output HTMLElement
<map-layer label="Point Geometry" checked="">
<map-meta name="extent" content="top-left-longitude=-75.916809, top-left-latitude=45.886964, bottom-right-longitude=-75.516809,bottom-right-latitude=45.26964"></map-meta>
<map-meta name="projection" content="OSMTILE"></map-meta>
<map-meta name="cs" content="gcrs"></map-meta>
<map-feature>
<map-featurecaption>Point Geometry</map-featurecaption>
<map-geometry>
<map-point>
<map-coordinates>-75.6916809 45.4186964</map-coordinates>
</map-point>
</map-geometry>
<map-properties>
<table>
<thead>
<tr>
<th role="columnheader" scope="col">Property name</th>
<th role="columnheader" scope="col">Property value</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">prop0</th>
<td itemprop="prop0">This is a Point</td>
</tr>
</tbody>
</table>
</map-properties>
</map-feature>
</map-layer>
defineCustomProjection
Basic options usage
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Example Custom Projection</title>
<script type="module" src="./mapml.js"></script>
<script type="module">
let customProjectionDefinition = `{
"projection": "ATLAS_POLAR_MAP",
"proj4string" : "+proj=aeqd +lat_0=90 +lon_0=-90 +x_0=0 +y_0=0 +ellps=sphere +units=m +no_defs +type=crs",
"origin" : [-20015200,20015200],
"resolutions" : [33073,16536.5,8268.246,4134.123,2067.061,1033.531,516.765],
"bounds" : [[4979939,-4846977],[-5139071,3980038]],
"tilesize" : 256
}`;
let map = document.querySelector("mapml-viewer");
let cProjection = map.defineCustomProjection(customProjectionDefinition);
map.projection = cProjection;
</script>
</head>
<body>
<mapml-viewer projection="ATLAS_POLAR_MAP" zoom="2" lat="83.48919" lon="-87.7687" controls>
<map-layer label="Atlas of Canada Polar Wall Map" checked>
<map-link rel="license" title="Canadian Federal Geospatial Platform" href="https://geoappext.nrcan.gc.ca/arcgis/rest/services/FGP/NCR_RCN/MapServer/"></map-link>
<map-extent units="ATLAS_POLAR_MAP" checked hidden>
<map-input type="zoom" name="z" min="0" max="6" value="6" ></map-input>
<map-input type="location" name="x" axis="column" units="tilematrix" min="116" max="186"></map-input>
<map-input type="location" name="y" axis="row" units="tilematrix" min="125" max="184"></map-input>
<map-link rel="tile" tref="https://geoappext.nrcan.gc.ca/arcgis/rest/services/FGP/NCR_RCN/MapServer/tile/{z}/{y}/{x}/"></map-link>
<map-link rel="tile" tref="https://geoappext.nrcan.gc.ca/arcgis/rest/services/FGP/NCR_RCN_A/MapServer/tile/{z}/{y}/{x}/"></map-link>
</map-extent>
</map-layer>
</mapml-viewer>
</body>
</html>
matchMedia
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example map media query</title>
// adjust the path to where you can find the distributed mapml.js artifact
<script type="module" src="./mapml.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const map = document.querySelector('mapml-viewer');
map.whenReady().then(() => {
const extent = map.extent;
const topLeftEasting = Math.trunc(extent.topLeft.pcrs.horizontal);
const topLeftNorthing = Math.trunc(extent.topLeft.pcrs.vertical);
const bottomRightEasting = Math.trunc(extent.bottomRight.pcrs.horizontal);
const bottomRightNorthing = Math.trunc(extent.bottomRight.pcrs.vertical);
// Format the media query string to detect overlap:
// (xminm < xmaxq) and (xmaxm > xminq) and (yminm < ymaxq) and (ymaxm > yminq)
const query = `(map-projection: OSMTILE) and (7 < map-zoom < 14) and (map-top-left-easting < ${bottomRightEasting}) and (map-bottom-right-easting > ${topLeftEasting}) and (map-bottom-right-northing < ${topLeftNorthing}) and (map-top-left-northing > ${bottomRightNorthing})`;
const matcher = map.matchMedia(query);
// create a layer to visually represent the query as the map moves
const f = `<map-layer checked label="test media query"><map-meta name="projection" content="OSMTILE"></map-meta>
<map-meta name="cs" content="pcrs"></map-meta><map-feature><map-properties>${query}</map-properties>
<map-geometry><map-polygon><map-coordinates>${topLeftEasting} ${topLeftNorthing}
${bottomRightEasting} ${topLeftNorthing} ${bottomRightEasting} ${bottomRightNorthing} ${topLeftEasting} ${bottomRightNorthing}
${topLeftEasting} ${topLeftNorthing}</map-coordinates</map-polygon></map-geometry></map-feature></map-layer>`;
const parser = new DOMParser();
const layer = parser
.parseFromString(f, 'text/html')
.querySelector('map-layer');
map.appendChild(layer);
const changeDisplayLayer = () => {
if (matcher.matches) {
layer.checked = true;
layer.hidden = false;
alert('Feature overlaps the map');
} else {
layer.checked = false;
layer.hidden = true;
alert('Feature does not overlap the map');
}
};
changeDisplayLayer();
matcher.addEventListener('change', changeDisplayLayer);
});
});
</script>
</head>
<body>
<mapml-viewer projection="OSMTILE" zoom="14" lat="45.406314" lon="-75.6883335" controls>
<map-layer label="OpenStreetMap" checked>
<map-link rel="license" title="© OpenStreetMap contributors CC BY-SA"
href="https://www.openstreetmap.org/copyright"></map-link>
<map-extent units="OSMTILE" checked hidden>
<map-input name="z" type="zoom" value="18" min="0" max="18"></map-input>
<map-input name="x" type="location" units="tilematrix" axis="column" min="0" max="262144"></map-input>
<map-input name="y" type="location" units="tilematrix" axis="row" min="0" max="262144"></map-input>
<map-link rel="tile" tref="https://tile.openstreetmap.org/{z}/{x}/{y}.png"></map-link>
</map-extent>
</map-layer>
</mapml-viewer>
</body>
</html>
Specifications
Specification |
---|
HTMLMapmlViewerElement |
Requirements
Report problems with these requirements on GitHub
requirement enhancement impractical undecided under discussion
Spec | Viewer | API | |
---|---|---|---|
Properties | full | full | full |
Methods | partial * | full | partial * |
Exceptions *
- No specification will be provided for toggleDebug() or viewSource() methods.
- The defineCustomProjection method is implemented, but not yet specified
- The custom projections API (defineCustomProjection) is under discussion, in particular, the options parameter's format.
- The geojson2mapml method's options parameter specification is not final.