coordinateconversion
This bundle provides a tool that allows converting coordinates on the fly as well as searching for coordinates and picking them from the map.
Usage
To make the coordinate conversion available to the user, add the tool ID coordinateconversionToggleTool to a tool set.
The widget is registered at the component system with the widget role coordinateconversion.
The bundles provides an API documentation.
Configuration reference
The following code sample shows the configurable properties and its default values:
"coordinateconversion": {
"Config": {
"defaultFormat": "wgs84-lat-lon",
"availableFormats": [
"wgs84-decimal-degrees",
"wgs84-degrees-decimal-minutes",
"wgs84-lat-lon",
"wgs84-pseudo-mercator",
"utm-32"
],
"locationSymbol": {
"type": "picture-marker",
"url": "resource('images/search-symbol-32.png')",
"height": 24,
"width": 24,
"xoffset": 0,
"yoffset": 0
},
"hideConversions": false
}
}
| Property | Type | Description |
|---|---|---|
defaultFormat |
String | ID of the format initially selected. A list of possible values is shown in the following table. |
availableFormats |
Array of Strings | A list of format IDs that can be selected for coordinate transformation (use IDs from the following table). If the list of available formats is empty, all formats listed in the following table are available. |
locationSymbol |
SimpleMarkerSymbol or PictureMarkerSymbol | The property locationSymbol allows to change the default symbol used to visualize the current location. See CoordinateConversion for details. |
hideConversions |
Boolean | Disables the part of the user interface that allows the user to activate additional conversions. Only the input form remains visible. |
Well-known conversion formats
| Name | ID | Description |
|---|---|---|
| WGS 84 (Decimal Degrees) | wgs84-decimal-degrees | WGS84-based coordinates in decimal degrees format |
| WGS 84 (Degrees Minutes) | wgs84-degrees-decimal-minutes | WGS84-based coordinates in degrees, decimal minutes format |
| WGS 84 (Degrees Minutes Seconds) | wgs84-lat-lon | WGS84-based coordinates in degrees, minutes and seconds format |
| WGS 84 (Web Mercator) | wgs84-pseudo-mercator | WGS84 with web mercator (pseudo mercator) base coordinates |
| ETRS89 / UTM zone 32N | utm-32 | Universal Transverse Mercator zone 32N |
| ETRS89 / UTM zone 33N | utm-33 | Universal Transverse Mercator zone 33N |
| ETRS89/DREF91/2016 / UTM zone 32N | utm-32-2016 | Universal Transverse Mercator zone 32N using german national realization of ETRS89 (DHHN2016) |
| ETRS89/DREF91/2016 / UTM zone 32N | utm-33-2016 | Universal Transverse Mercator zone 33N using german national realization of ETRS89 (DHHN2016) |
| DHDN Gauss-Krueger | gauss-krueger | The German Gauss Krueger format. The format switches between the different strips 2, 3, 4, and 5 automatically. |
| DHDN Gauss Krueger (Zone) | gauss-krueger-[2|3|4|5] | The German Gauss Krueger format for a specific zone (such as gauss-krueger-2). |
| LUREF / Luxembourg TM | luref | Luxembourg official reference system |
| SwissGrid LV95 | swissgrid-lv95 | Official reference system of Switzerland based on reference frame LV95 system |
| XY | xy | Longitude, latitude (WGS84) |
| MGRS | mgrs | Military Grid Reference System |
| UTM | utm | Universal Transverse Mercator |
| DD | dd | Decimal Degrees |
| DDM | ddm | Degrees decimal minutes |
| DMS | dms | Degrees minutes seconds |
Use Cases
Changing the label of a format
The label of a format can be changed by overriding the I18N keys used by this bundle.
To change the label of a format with a certain id, override the I18N key at coordinateconversion.formats[id].
For example:
// <app>/nls/bundle.js
export default {
root: {
coordinateconversion: {
formats: {
"wgs84-lat-lon": "WGS 84 DMS [CUSTOM]",
"dd": "DD Format [CUSTOM]"
}
}
},
de: true
};
NOTE: Overriding I18N keys requires updating the
app.jsonas well. You may also need to configure strings for additional languages used by your app. More details are available in the map.apps documentation.
Change the precision of the formats
You can adjust the precision of the formats provided via this bundle via the properties of the CustomConversionsRegistration service.
The example JSON below show the service configuration with the default values:
"coordinateconversion": {
"CustomConversionsRegistration": {
"decimalPlaces": 2,
"ddDecimalPlaces": 5,
"dsDecimalPlaces": 3
},
"Config": {
...
}
}
The following table shows the effect of changing these configuration properties on the individual formats.
| Format ID | Property | Description |
|---|---|---|
| wgs84-lat-lon | dsDecimalPlaces |
Sets the number of decimal places for seconds in the format. Example: 51° 57' 44.<999>"N. |
| wgs84-decimal-degrees | ddDecimalPlaces |
Sets the number of decimal places for degrees in the format. Example: 51.<999>°N. |
| wgs84-degrees-decimal-minutes | ddDecimalPlaces |
Sets the number of decimal places for decimal minutes. Example: 51° 57.<999>'N. |
| wgs84-pseudo-mercator | decimalPlaces |
Sets the number of decimal places for numeric values. Example: 848,885.<99>. |
| utm-32 | decimalPlaces |
Sets the number of decimal places for numeric values. Example: 405,574.<99>. |
| utm-33 | decimalPlaces |
Sets the number of decimal places for numeric values. Example: -6,335.<99>. |
| gauss-krueger | decimalPlaces |
Sets the number of decimal places for numeric values. Example: 2,611,778.<99>. |
| gauss-krueger-[2|3|4|5] | decimalPlaces |
Sets the number of decimal places for numeric values. Example: 2,611,778.<99>. |
| luref | decimalPlaces |
Sets the number of decimal places for numeric values. Example: 77,405.<99>. |
| swissgrid-lv95 | decimalPlaces |
Sets the number of decimal places for numeric values. Example: 2,600,572.<99>. |
Accessing the state of the widget
This bundle exposes some parts of the widget's state via an API.
To access the widget's state, inject the service "coordinateconversion.Model":
{
// ...
"components": [
{
"name": "YourService",
"references": [
{
"name": "coordinatesModel",
"providing": "coordinateconversion.Model"
}
]
}
]
}
The model exposes the current marker location as a reactive property:
import { watchValue } from "apprt-core/reactivity";
const model = this.coordinatesModel!; // injected
// Access current value
// model.currentLocation is the current position of the marker (includes movements with the mouse)
// model.confirmedLocation only includes "fixed" markers (via form input or click in the map).
console.log(model.currentLocation);
// Watch value updates using the reactivity API.
this.cleanupWatch = watchValue(
() => model.currentLocation,
(location) => {
if (location) {
console.info(`Current location is ${location.x} ${location.y}`);
}
}
);
How to register custom formats
Adding a new coordinate format requires an implementation of the SegmentedFormat interface,
registered using the interface name "coordinateconversion.SegmentedFormat".
The SegmentedFormat interface allows you to configure the new format's id, label and segments:
idshould be unique. It can be used from the bundle's configuration, for example inallowedFormats.labelwill be shown to the user, and should be translated into the current language.segmentsallow configuration of the number of coordinate input fields, their labels and custom validation logic.
Additionally, a SegmentedFormat must provide methods to transform between various representations of coordinates on a map:
Point (ESRI Geometry) <---> Segments values (multiple Strings) <---> String
The following example implements a simple XY format with two input fields.
To keep it simple, the example does not make use of I18N or advanced validation.
export class CustomXYFormat implements SegmentedFormat {
readonly id = "xy-custom";
readonly label = "XY (Custom)";
readonly segments: CoordinateSegment[] = [
{
id: "x",
label: "Longitude",
example: "7.62",
suffix: "° E",
validate: validateNumber
},
{
id: "y",
label: "Latitude",
example: "51.97",
suffix: "° N",
validate: validateNumber
}
];
readonly spatialReference = SpatialReference.WGS84;
async pointToSegments(point: Point): Promise<Record<string, string>> {
const amountOfDecimals = 4;
const x = point.x.toFixed(amountOfDecimals);
const y = point.y.toFixed(amountOfDecimals);
return { x, y };
}
segmentsToString({ x, y }: Record<string, string>): string {
return `${x}, ${y}`;
}
stringToSegments(input: string): ParseResult<Record<string, string>> {
const match = input.match(/^([^,]+),(.*)$/);
if (!match) {
return {
kind: "error",
message: "Expected format: x, y"
};
}
const x = (match[1] || "").trim();
const y = (match[2] || "").trim();
return {
kind: "success",
value: { x, y }
};
}
async segmentsToPoint(segments: Record<string, string>): Promise<ParseResult<Point>> {
return {
kind: "success",
value: new Point({
x: parseFloat(segments["x"]!),
y: parseFloat(segments["y"]!),
spatialReference: { wkid: 4326 }
})
};
}
}
const numberPattern = /^-?\d+[.]?\d*$/;
function validateNumber(input: string): boolean {
return numberPattern.test(input);
}
How to register custom ESRI formats (LEGACY)
NOTE: This is the old way to register custom formats. It still works, but formats using this API will not be able to take full advantage of the widget's capabilities. For example, there will only be a single input text field for coordinates.
To register custom formats for coordinate conversion, you need to implement the interface @arcgis/core/widgets/CoordinateConversion/support/Format from the ArcGIS Maps SDK for JavaScript.
Note: This interface might be changed by Esri in future versions of the API. Therefore, we cannot guarantee, that it is stable and backward compatible.
The following code sample shows how to add a custom lat/lon format:
import Format from "@arcgis/core/widgets/CoordinateConversion/support/Format";
import Point from "@arcgis/core/geometry/Point";
import { webMercatorToGeographic } from "@arcgis/core/geometry/support/webMercatorUtils";
export class XYFormatFactory {
/**
* @see https://developers.arcgis.com/javascript/latest/sample-code/widgets-coordinateconversion-custom/index.html
*/
createInstance(): Format {
// Regular expression to find a number
const numberSearchPattern = /-?\d+[\\.]?\d*/;
const formatProperties = {
// used to identify the format. This key is used in the defaultFormat option of the widget.
// it is only required if the name is localized and has no stable value.
id: "xy-custom",
// The format's name should be unique with respect to other formats used by the widget
name: "XY (Custom)",
conversionInfo: {
// Define a convert function
// Point -> Position
convert(point: Point) {
const returnPoint = point.spatialReference.isWGS84 ? point : (webMercatorToGeographic(point) as Point);
const x = returnPoint.x.toFixed(4);
const y = returnPoint.y.toFixed(4);
return {
location: returnPoint,
coordinate: `${x}, ${y}`
};
},
// Define a reverse convert function
// String -> Point
reverseConvert(coordinate: string) {
try {
const parts = coordinate.split(",");
return new Point({
x: parseFloat(parts[0]!),
y: parseFloat(parts[1]!),
spatialReference: { wkid: 4326 }
});
} catch (e) {
// Esri widget to display error message
console.error(e);
throw e;
}
}
},
// Define each segment of the coordinate
coordinateSegments: [
{
alias: "X",
description: "Longitude",
searchPattern: numberSearchPattern
},
{
alias: "Y",
description: "Latitude",
searchPattern: numberSearchPattern
}
],
defaultPattern: "X\u00B0, Y\u00B0"
};
return new Format(formatProperties);
}
}
Finally, register the format component as service coordinateconversion.Format in a manifest.json file as in the following code sample:
{
"name": "XYFormatFactory",
"provides": ["coordinateconversion.Format"],
"instanceFactory": true
}