We are using the toLatitudeLongitude method of the coordinateFormatter to get a string representation of a given point object.
Unfortunately, for the cases where the decimalPlaces are set to 0 it adds a leading zero infront of the minute-value leading to a three-digit-value. Thats obviously wrong since minutes only range til 60, so any leading hundet-zero is simply wrong here.
We were pointed on that by some technical experts which are working with coordinates every day.
I did some research and only can find samples and references without a leading hundred-zero.
Can anyone explain me, why esri is doing that? Is there may a function to correct the string?
Solved! Go to Solution.
Hi Sebastian, I raised this issue very recently! it was confirmed as a bug: BUG-000172707 - The ArcGIS Maps SDK for JavaScript coordinateFormatter function converts points incorrectly when the toLatitudeLongitude method has the decimalPlaces parameter set to zero
Hi Sebastian, I raised this issue very recently! it was confirmed as a bug: BUG-000172707 - The ArcGIS Maps SDK for JavaScript coordinateFormatter function converts points incorrectly when the toLatitudeLongitude method has the decimalPlaces parameter set to zero
good to know
the bug page doesnt bring much info about details
https://support.esri.com/de-de/bug/the-arcgis-maps-sdk-for-javascript-coordinateformatter-bug-000172...
one should also note, that the wrong output is also part of the documentation which means that the current implementation isnt just buggy but wrong by design.
@JonathanDawe_BAS : can we ensure, that the wrong hundred-zero is exactly what will be fixed by this bug? if so, we can await the fix. If this could not be ensured we would first go with a workaround.
I've actually steered away from using the coordinate.formatter for formatting from a point to a string. I personally only use it for converting the other way from a string to a point.
The rationale was that we wanted a bit more control over the formatting - For example presenting DDM as 54°16.544' S, 36°26.348' W instead of 54 16.544S 36 26.348W.
export type DisplayFormat = 'DD' | 'DMS' | 'DDM';
export const BLANK_COORDINATES = {
DD: '--.-° N, --.-° E',
DMS: '--°--\'--\" N, --°--\'--\" E',
DDM: "--°--.--' N, --°--.--' E",
} as const;
// Utility functions for coordinate conversions
export function decimalToDMS(degree: number, isLat: boolean) {
const absolute = Math.abs(degree);
const degrees = Math.floor(absolute);
const minutesNotTruncated = (absolute - degrees) * 60;
const minutes = Math.floor(minutesNotTruncated);
const seconds = ((minutesNotTruncated - minutes) * 60).toFixed(2);
const direction = isLat ? (degree >= 0 ? 'N' : 'S') : degree >= 0 ? 'E' : 'W';
return `${degrees}°${minutes}'${seconds}" ${direction}`;
}
export function decimalToDDM(degree: number, isLat: boolean) {
const absolute = Math.abs(degree);
const degrees = Math.floor(absolute);
const minutes = ((absolute - degrees) * 60).toFixed(3);
const direction = isLat ? (degree >= 0 ? 'N' : 'S') : degree >= 0 ? 'E' : 'W';
return `${degrees}°${minutes}' ${direction}`;
}
export function formatLatitude(latitude: number) {
const direction = latitude >= 0 ? 'N' : 'S';
const absoluteValue = Math.abs(latitude).toFixed(2);
return `${absoluteValue}° ${direction}`;
}
export function formatLongitude(longitude: number) {
const direction = longitude >= 0 ? 'E' : 'W';
const absoluteValue = Math.abs(longitude).toFixed(2);
return `${absoluteValue}° ${direction}`;
}
export function formatCoordinate(
lat: number | nullish,
lon: number | nullish,
format: DisplayFormat,
displayPlaceholder: boolean = false,
) {
if (!isDefined(lat) || !isDefined(lon))
return displayPlaceholder ? BLANK_COORDINATES[format] : null;
switch (format) {
case 'DD':
return `${formatLatitude(lat)}, ${formatLongitude(lon)}`;
case 'DMS':
return `${decimalToDMS(lat, true)}, ${decimalToDMS(lon, false)}`;
case 'DDM':
return `${decimalToDDM(lat, true)}, ${decimalToDDM(lon, false)}`;
default:
return null;
}
}
this is awesome. Grate you share your code here.
This is my workaround to cut out the zeros until the fix is released:
/**
* This is a Bugfix of Esri coordinateFormatter.toLatitudeLongitude
* The Bug is already tracked and in product plan.
* Which means it may be fixed in the next two releases of ArcGIS.
* Bug link:
* https://support.esri.com/en-us/bug/the-arcgis-maps-sdk-for-javascript-coordinateformatter-bug-000172707
*
* Nevertheless this method fixes the wrong output as workaround.
* The problem is, that the minutes are printed as three-digit with leading zeros
* although minutes only reach to max. 60.
* Within this methode the leading hundredth-zero is cut out while a possible tenth-zero is kept.
* The issue is known for formats 'ddm' and 'dms'.
* If the given format is anything else, the original coordinates are returned.
*
* For both ddm and dms the leading hunderdth-zeros can be found by the hemisphere characters.
* The fix applies for precision = 0.
* DDM sample: 55 057N 003 010W
* DMS sample: 55 56 039N 003 09 043W
*
* For latitude we determine the index of the N- or S-character.
* For longitude we determine the index of the O- or W-character.
* The leading hundredth-zero is located at index - 3 for both lat- and lon-index.
* coordinates to be fixed
* format of the coordinates
* @returns a fixed version of the coordinates if format is of ddm or dms, otherwise the original coordinates are returned.
*/
private fixBuggyMinuteCoordinateFormat(coordinates: string, format: string): string {
// only process for formats ddm and dms
if (format === 'ddm' || format === 'dms') {
const regex_lat = /[NS]/;
const regex_lon = /[EW]/;
const match_lat = regex_lat.exec(coordinates);
const match_lon = regex_lon.exec(coordinates);
// only process if string contains N or S
if (match_lat && match_lon) {
const lat_i = match_lat.index - 3;
const lon_i = match_lon.index - 3;
// only process if there is a 0 at both indices
if (coordinates.charAt(lat_i) === '0' && coordinates.charAt(lon_i) === '0') {
//remove the longitudes zero first
coordinates = coordinates.slice(0, lon_i) + coordinates.slice(lon_i + 1);
//remove the latitudes zero second
coordinates = coordinates.slice(0, lat_i) + coordinates.slice(lat_i + 1);
}
}
}
return coordinates;
}
}