geo-coordinates-parser 1.2.8 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +29 -13
- package/bundle/geocoordsparser.js +1 -1
- package/converter.js +36 -28
- package/package.json +1 -1
- package/test.js +3 -3
- package/testFormatConverter.js +8 -0
- package/testIndividual.js +13 -2
- package/testformats.js +12 -0
- package/toCoordinateFormat.js +52 -0
package/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Geo Coordinates Parser
|
2
2
|
|
3
|
-
A Javascript function for reading a variety of coordinate formats and converting to decimal latitude and longitude. Builds on
|
3
|
+
A Javascript function for reading a variety of coordinate formats and converting to decimal latitude and longitude. Builds on previous efforts and returns the verbatim coordinates and the decimal coordinates together in one object for convenience. Can be used to extract coordinates from longer strings. Also includes a function to test existing decimal coordinates against those from the converter.
|
4
4
|
|
5
|
-
##If you like this
|
5
|
+
##If you like this tool please [star it on GitHub](https://github.com/ianengelbrecht/geo-coordinates-parser)
|
6
6
|
|
7
7
|
### Installation
|
8
8
|
```
|
@@ -15,18 +15,31 @@ const convert = require('geo-coordinates-parser');
|
|
15
15
|
```
|
16
16
|
OR
|
17
17
|
```js
|
18
|
-
import convert from 'geo-coordinates-parser' //ES6
|
18
|
+
import convert from 'geo-coordinates-parser' //ES6, if you're using a bundler
|
19
19
|
```
|
20
20
|
THEN
|
21
21
|
```js
|
22
|
-
let converted
|
22
|
+
let converted;
|
23
|
+
try {
|
24
|
+
converted = convert('40° 26.7717, -79° 56.93172');
|
25
|
+
}
|
26
|
+
catch {
|
27
|
+
/*we get here if the string is not valid coordinates or format is inconsistent between lat and long*/
|
28
|
+
}
|
29
|
+
|
23
30
|
```
|
24
31
|
OR add the number of decimal places you want (but be reasonable, [see Coordinate Precision here](https://en.wikipedia.org/wiki/Decimal_degrees)) -- default is 5
|
25
32
|
|
26
33
|
```js
|
27
|
-
|
34
|
+
try{
|
35
|
+
let converted = convert(coordinatesString, integerDecimalPlaces)
|
36
|
+
//do stuff with coordinates...
|
37
|
+
}
|
38
|
+
catch{
|
39
|
+
//coordinates not valid
|
40
|
+
}
|
28
41
|
```
|
29
|
-
|
42
|
+
ALSO
|
30
43
|
```js
|
31
44
|
converted.decimalLatitude; // 40.446195 ✓
|
32
45
|
converted.decimalLongitude; // -79.948862 ✓
|
@@ -35,14 +48,14 @@ converted.verbatimLongitude; // '-79° 56.93172' ✓
|
|
35
48
|
```
|
36
49
|
The returned object includes properties verbatimCoordinates, verbatimLatitude, verbatimLongitude, decimalLatitude, decimalLatitude, and decimalCoordinates.
|
37
50
|
|
38
|
-
|
51
|
+
### Validating other conversions
|
52
|
+
Sometimes we may want to validate existing decimal coordinates against those returned from the converter to find errors. Because we're working with decimal numbers we must settle for values that are close enough (in this case equal up to six decimal places).
|
39
53
|
|
40
54
|
```js
|
41
|
-
converted.closeEnough(
|
55
|
+
converted.closeEnough(yourDecimalCoordinatesToValidate) //must be a numbers separated by ,
|
42
56
|
```
|
43
57
|
|
44
58
|
### Supported formats
|
45
|
-
|
46
59
|
All formats (except the 'exotic formats') covered by [npm coordinate-parser](https://www.npmjs.com/package/coordinate-parser) and the [coordinate regex in this GitHub Gist](https://gist.github.com/moole/3707127/337bd31d813a10abcf55084381803e5bbb0b20dc), including the following:
|
47
60
|
- -23.3245° S / 28.2344° E
|
48
61
|
- 27deg 15min 45.2sec S 18deg 32min 53.7sec E
|
@@ -55,7 +68,7 @@ All formats (except the 'exotic formats') covered by [npm coordinate-parser](htt
|
|
55
68
|
Formats used for testing can be be accessed with:
|
56
69
|
|
57
70
|
```
|
58
|
-
|
71
|
+
convert.formats
|
59
72
|
```
|
60
73
|
|
61
74
|
**Please add coordinate formats that throw an error in the Github Issues.**
|
@@ -63,9 +76,12 @@ covert.formats
|
|
63
76
|
### Want to use it in the browser?
|
64
77
|
A ready bundled script is available in the source code, in the bundle directory, named geocoordsparser.js. [Download](https://stackoverflow.com/a/13593430/3210158), include it in a script tag in your html, and you'll have a function called `convert()` available in your environment.
|
65
78
|
|
66
|
-
###
|
67
|
-
|
68
|
-
|
79
|
+
### Convert back to standard formats
|
80
|
+
Sometimes we might want to convert back to more traditional formats for representing coordinates, such as DMS or DM. This can be useful for standardizing coordinates. The convert function has an enum to help.
|
81
|
+
|
82
|
+
```js
|
83
|
+
converted.toCoordinateFormat(convert.to.DMS) /// '40° 26.771" N, 79° 56.932" W' ✓
|
84
|
+
```
|
69
85
|
|
70
86
|
### License
|
71
87
|
MIT Licence
|
@@ -1 +1 @@
|
|
1
|
-
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).convert=t()}}(function(){function t(t){var e=t.
|
1
|
+
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).convert=t()}}(function(){function t(t,e,r){const i=Number(t);let a;a=r?i>=0?"N":"S":i>=0?"E":"W";const n=Math.abs(i),o=Math.floor(n),s=60*(n-o);if("DM"==e)return`${o}\xb0 ${s.toFixed(3).replace(/\.0+$/,"")}' ${a}`;const d=Math.floor(s);return`${o}\xb0 ${d}' ${(60*(s-d)).toFixed(1).replace(/\.0$/,"")}" ${a}`}var e=function(e){if(!["DMS","DM"].includes(e))throw new Error("invalid format specified");if(this.decimalCoordinates&&this.decimalCoordinates.trim()){const r=this.decimalCoordinates.split(",").map(t=>t.trim());return`${t(r[0],e,!0)}, ${t(r[1],e,!1)}`}throw new Error("no decimal coordinates to convert")};function r(t,r){r||(r=5),t=t.replace(/\s\s+/g," ").trim();var a=null,l=null,f="",c="",E=[],S=!1;if(o.test(t)){if(!(S=i(E=o.exec(t))))throw new Error("invalid decimal coordinate format");a=E[2],l=E[6],a.includes(",")&&a.replace(",","."),l.includes(",")&&l.replace(",","."),E[1]?(f=E[1],c=E[5]):E[4]&&(f=E[4],c=E[8])}else if(s.test(t)){if(!(S=i(E=s.exec(t))))throw new Error("invalid DMS coordinates format");a=Math.abs(parseInt(E[2])),E[4]&&(a+=E[4]/60),E[6]&&(a+=E[6]/3600),parseInt(E[2])<0&&(a*=-1),l=Math.abs(parseInt(E[9])),E[11]&&(l+=E[11]/60),E[13]&&(l+=E[13]/3600),parseInt(E[9])<0&&(l*=-1),E[1]?(f=E[1],c=E[8]):E[7]&&(f=E[7],c=E[14])}else if(d.test(t)){if(!(S=i(E=d.exec(t))))throw new Error("invalid DMS coordinates format");a=Math.abs(parseInt(E[2])),E[4]&&(a+=E[4]/60,E[3]||(E[3]=" ")),E[6]&&(a+=E[6]/3600,E[5]||(E[5]=" ")),parseInt(E[2])<0&&(a*=-1),l=Math.abs(parseInt(E[10])),E[12]&&(l+=E[12]/60,E[11]||(E[11]=" ")),E[14]&&(l+=E[14]/3600,E[13]||(E[13]=" ")),parseInt(E[10])<0&&(l*=-1),E[1]?(f=E[1],c=E[9]):E[8]&&(f=E[8],c=E[16])}else if(u.test(t)){if(!(S=i(E=u.exec(t))))throw new Error("invalid coordinates format");a=Math.abs(parseInt(E[2])),E[4]&&(a+=E[4]/60,E[3]||(E[3]=" ")),E[6]&&(a+=E[6]/3600,E[5]||(E[5]=" ")),parseInt(E[2])<0&&(a*=-1),l=Math.abs(parseInt(E[10])),E[12]&&(l+=E[12]/60,E[11]||(E[11]=" ")),E[14]&&(l+=E[14]/3600,E[13]||(E[13]=" ")),parseInt(E[10])<0&&(l*=-1),E[1]?(f=E[1],c=E[9]):E[8]&&(f=E[8],c=E[16])}if(Math.abs(l)>=180)throw new Error("invalid longitude value");if(S){var b=/S|SOUTH/i;b.test(f)&&a>0&&(a*=-1),(b=/W|WEST/i).test(c)&&l>0&&(l*=-1);var m,N,h=E[0].trim(),T=h.match(/[,/;\u0020]/g);if(null==T){var p=Math.floor(t.length/2);m=h.substring(0,p).trim(),N=h.substring(p).trim()}else{var x=0;if(0==(p=T.length%2==1?Math.floor(T.length/2):T.length/2-1))x=h.indexOf(T[0]),m=h.substring(0,x).trim(),N=h.substring(x+1).trim();else{for(var M=0,v=0;M<=p;)v=(x=h.indexOf(T[M],v))+1,M++;m=h.substring(0,x).trim(),N=h.substring(x+1).trim()}}return isNaN(a)&&a.includes(",")&&(a=a.replace(",",".")),a=Number(Number(a).toFixed(r)),isNaN(l)&&l.includes(",")&&(l=l.replace(",",".")),l=Number(Number(l).toFixed(r)),Object.freeze({verbatimCoordinates:h,verbatimLatitude:m,verbatimLongitude:N,decimalLatitude:a,decimalLongitude:l,decimalCoordinates:`${a},${l}`,closeEnough:n,toCoordinateFormat:e})}throw new Error("coordinates pattern match failed")}function i(t){if(!isNaN(t[0]))return!1;var e=t.filter(t=>t);if(e.shift(),e.length%2>0)return!1;for(var r=/^[-+]?(\d+|\d+\.\d*|\d*\.\d+)$/,i=/[A-Za-z]+/,a=e.length/2,n=!0,o=0;o<a;o++)if(r.test(e[o])!=r.test(e[o+a])||i.test(e[o])!=i.test(e[o+a])){n=!1;break}return n}function a(t,e){var r=Math.abs(t-e);return diff=Number(r.toFixed(6)),diff<=1e-5}function n(t){if(t.includes(",")){var e=t.split(",");if(NaN==Number(e[0])||NaN==Number(e[1]))throw new Error("coords are not valid decimals");return a(this.decimalLatitude,Number(e[0]))&&a(this.decimalLongitude,e[1])}throw new Error("coords being tested must be separated by a comma")}var o=/(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))([\u2022\xba\xb0]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[,/;]?[\s]*(EAST|WEST|[EW])?[\s]*([+-]?[0-1]?[0-9]?[0-9](?:[\.,]\d{3,}))([\u2022\xba\xb0]?)[\s]*(EAST|WEST|[EW])?/i,s=/(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*(\.)[\ \t]*([0-5]?[0-9])[\ \t]*(\.)?[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(NORTH|SOUTH|[NS])?(?:[\ \t]*[,/;][\ \t]*|[\ \t]*)(EAST|WEST|[EW])?[\ \t]*([+-]?[0-1]?[0-9]?[0-9])[\ \t]*(\.)[\ \t]*([0-5]?[0-9])[\ \t]*(\.)?[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(EAST|WEST|[EW])?/i,d=/(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*(D(?:EG)?(?:REES)?)[\ \t]*([0-5]?[0-9])[\ \t]*(M(?:IN)?(?:UTES)?)[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(S(?:EC)?(?:ONDS)?)?[\ \t]*(NORTH|SOUTH|[NS])?(?:[\ \t]*[,/;][\ \t]*|[\ \t]*)(EAST|WEST|[EW])?[\ \t]*([+-]?[0-1]?[0-9]?[0-9])[\ \t]*(D(?:EG)?(?:REES)?)[\ \t]*([0-5]?[0-9])[\ \t]*(M(?:IN)?(?:UTES)?)[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(S(?:EC)?(?:ONDS)?)[\ \t]*(EAST|WEST|[EW])?/i,u=/(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*([\u2022\xba\xb0\.:]|D(?:EG)?(?:REES)?)?[\ \t]*,?([0-5]?[0-9](?:\.\d{1,})?)?[\ \t]*(['\u2032\xb4\u2019\.:]|M(?:IN)?(?:UTES)?)?[\ \t]*,?((?:[0-5]?[0-9])(?:\.\d{1,3})?)?[\ \t]*(''|\u2032\u2032|\u2019\u2019|\xb4\xb4|["\u2033\u201d\.])?[\ \t]*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?[\ \t]*([+-]?[0-1]?[0-9]?[0-9])[\ \t]*([\u2022\xba\xb0\.:]|D(?:EG)?(?:REES)?)?[\ \t]*,?([0-5]?[0-9](?:\.\d{1,})?)?[\ \t]*(['\u2032\xb4\u2019\.:]|M(?:IN)?(?:UTES)?)?[\ \t]*,?((?:[0-5]?[0-9])(?:\.\d{1,3})?)?[\ \t]*(''|\u2032\u2032|\xb4\xb4|\u2019\u2019|["\u2033\u201d\.])?[\ \t]*(EAST|WEST|[EW])?/i;const l=Object.freeze({DMS:"DMS",DM:"DM"});return r.to=l,r});
|
package/converter.js
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
//function for converting coordinates from a string to decimal and verbatim
|
2
|
-
|
2
|
+
|
3
|
+
const toCoordinateFormat = require('./toCoordinateFormat.js')
|
4
|
+
|
5
|
+
|
3
6
|
function converter(coordsString, decimalPlaces) {
|
4
7
|
|
5
8
|
if(!decimalPlaces) {
|
@@ -189,17 +192,18 @@ function converter(coordsString, decimalPlaces) {
|
|
189
192
|
//we need to get the verbatim coords from the string
|
190
193
|
//we can't split down the middle because if there are decimals they may have different numbers on each side
|
191
194
|
//so we need to find the separating character, or if none, use the match values to split down the middle
|
195
|
+
var verbatimCoordinates = match[0].trim()
|
192
196
|
var verbatimLat
|
193
197
|
var verbatimLng
|
194
198
|
|
195
|
-
var sepChars = /[
|
196
|
-
var seps =
|
199
|
+
var sepChars = /[,/;\u0020]/g //comma, forward slash and spacebar
|
200
|
+
var seps = verbatimCoordinates.match(sepChars)
|
197
201
|
|
198
202
|
if (seps == null) {
|
199
203
|
//split down the middle
|
200
204
|
var middle = Math.floor(coordsString.length/2)
|
201
|
-
verbatimLat =
|
202
|
-
verbatimLng =
|
205
|
+
verbatimLat = verbatimCoordinates.substring(0, middle).trim()
|
206
|
+
verbatimLng = verbatimCoordinates.substring(middle).trim()
|
203
207
|
}
|
204
208
|
else { //if length is odd then find the index of the middle value
|
205
209
|
|
@@ -219,21 +223,21 @@ function converter(coordsString, decimalPlaces) {
|
|
219
223
|
|
220
224
|
//it might be only one value
|
221
225
|
if (middle == 0){
|
222
|
-
splitIndex =
|
223
|
-
verbatimLat =
|
224
|
-
verbatimLng =
|
226
|
+
splitIndex = verbatimCoordinates.indexOf(seps[0])
|
227
|
+
verbatimLat = verbatimCoordinates.substring(0, splitIndex).trim()
|
228
|
+
verbatimLng = verbatimCoordinates.substring(splitIndex + 1).trim()
|
225
229
|
}
|
226
230
|
else {
|
227
231
|
var currSepIndex = 0
|
228
232
|
var startSearchIndex = 0
|
229
233
|
while (currSepIndex <= middle){
|
230
|
-
splitIndex =
|
234
|
+
splitIndex = verbatimCoordinates.indexOf(seps[currSepIndex], startSearchIndex)
|
231
235
|
startSearchIndex = splitIndex + 1
|
232
236
|
currSepIndex++
|
233
237
|
}
|
234
238
|
|
235
|
-
verbatimLat =
|
236
|
-
verbatimLng =
|
239
|
+
verbatimLat = verbatimCoordinates.substring(0, splitIndex).trim()
|
240
|
+
verbatimLng = verbatimCoordinates.substring(splitIndex + 1).trim()
|
237
241
|
|
238
242
|
}
|
239
243
|
|
@@ -253,15 +257,16 @@ function converter(coordsString, decimalPlaces) {
|
|
253
257
|
|
254
258
|
ddLng = Number(Number(ddLng).toFixed(decimalPlaces))
|
255
259
|
|
256
|
-
return {
|
257
|
-
verbatimCoordinates
|
260
|
+
return Object.freeze({
|
261
|
+
verbatimCoordinates,
|
258
262
|
verbatimLatitude: verbatimLat,
|
259
263
|
verbatimLongitude: verbatimLng,
|
260
264
|
decimalLatitude: ddLat,
|
261
265
|
decimalLongitude: ddLng,
|
262
266
|
decimalCoordinates: `${ddLat},${ddLng}`,
|
263
|
-
closeEnough: coordsCloseEnough
|
264
|
-
|
267
|
+
closeEnough: coordsCloseEnough,
|
268
|
+
toCoordinateFormat
|
269
|
+
})
|
265
270
|
}
|
266
271
|
else {
|
267
272
|
throw new Error("coordinates pattern match failed")
|
@@ -270,16 +275,12 @@ function converter(coordsString, decimalPlaces) {
|
|
270
275
|
}
|
271
276
|
|
272
277
|
function checkMatch(match) { //test if the matched groups arrays are 'balanced'. match is the resulting array
|
273
|
-
|
278
|
+
|
279
|
+
if(!isNaN(match[0])){ //we've matched a number, not what we want....
|
280
|
+
return false
|
281
|
+
}
|
274
282
|
//first remove the empty values from the array
|
275
|
-
var filteredMatch = match.filter(
|
276
|
-
if (!item || item == ''){
|
277
|
-
return false;
|
278
|
-
}
|
279
|
-
else {
|
280
|
-
return true;
|
281
|
-
}
|
282
|
-
});
|
283
|
+
var filteredMatch = match.filter(x=>x);
|
283
284
|
|
284
285
|
//we need to shift the array because it contains the whole coordinates string in the first item
|
285
286
|
filteredMatch.shift();
|
@@ -343,12 +344,19 @@ function coordsCloseEnough(coordsToTest) {
|
|
343
344
|
}
|
344
345
|
|
345
346
|
//Coordinates pattern matching regex
|
346
|
-
var dd_re = /(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))([•º°]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[
|
347
|
+
var dd_re = /(NORTH|SOUTH|[NS])?[\s]*([+-]?[0-8]?[0-9](?:[\.,]\d{3,}))([•º°]?)[\s]*(NORTH|SOUTH|[NS])?[\s]*[,/;]?[\s]*(EAST|WEST|[EW])?[\s]*([+-]?[0-1]?[0-9]?[0-9](?:[\.,]\d{3,}))([•º°]?)[\s]*(EAST|WEST|[EW])?/i;
|
347
348
|
//degrees minutes seconds with '.' as separator - gives array with 15 values
|
348
|
-
var dms_periods = /(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*(\.)[\ \t]*([0-5]?[0-9])[\ \t]*(\.)?[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(NORTH|SOUTH|[NS])?(?:[\ \t]*[
|
349
|
+
var dms_periods = /(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*(\.)[\ \t]*([0-5]?[0-9])[\ \t]*(\.)?[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(NORTH|SOUTH|[NS])?(?:[\ \t]*[,/;][\ \t]*|[\ \t]*)(EAST|WEST|[EW])?[\ \t]*([+-]?[0-1]?[0-9]?[0-9])[\ \t]*(\.)[\ \t]*([0-5]?[0-9])[\ \t]*(\.)?[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(EAST|WEST|[EW])?/i;
|
349
350
|
//degrees minutes seconds with words 'degrees, minutes, seconds' as separators (needed because the s of seconds messes with the S of SOUTH) - gives array of 17 values
|
350
|
-
var dms_abbr = /(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*(D(?:EG)?(?:REES)?)[\ \t]*([0-5]?[0-9])[\ \t]*(M(?:IN)?(?:UTES)?)[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(S(?:EC)?(?:ONDS)?)?[\ \t]*(NORTH|SOUTH|[NS])?(?:[\ \t]*[
|
351
|
+
var dms_abbr = /(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*(D(?:EG)?(?:REES)?)[\ \t]*([0-5]?[0-9])[\ \t]*(M(?:IN)?(?:UTES)?)[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(S(?:EC)?(?:ONDS)?)?[\ \t]*(NORTH|SOUTH|[NS])?(?:[\ \t]*[,/;][\ \t]*|[\ \t]*)(EAST|WEST|[EW])?[\ \t]*([+-]?[0-1]?[0-9]?[0-9])[\ \t]*(D(?:EG)?(?:REES)?)[\ \t]*([0-5]?[0-9])[\ \t]*(M(?:IN)?(?:UTES)?)[\ \t]*((?:[0-5]?[0-9])(?:\.\d{1,3})?)?(S(?:EC)?(?:ONDS)?)[\ \t]*(EAST|WEST|[EW])?/i;
|
351
352
|
//everything else - gives array of 17 values
|
352
|
-
var coords_other = /(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*([•º°\.:]|D(?:EG)?(?:REES)?)?[\ \t]*,?([0-5]?[0-9](?:\.\d{1,})?)?[\ \t]*(['′´’\.:]|M(?:IN)?(?:UTES)?)?[\ \t]*,?((?:[0-5]?[0-9])(?:\.\d{1,3})?)?[\ \t]*(''|′′|’’|´´|["″”\.])?[\ \t]*(NORTH|SOUTH|[NS])?(
|
353
|
+
var coords_other = /(NORTH|SOUTH|[NS])?[\ \t]*([+-]?[0-8]?[0-9])[\ \t]*([•º°\.:]|D(?:EG)?(?:REES)?)?[\ \t]*,?([0-5]?[0-9](?:\.\d{1,})?)?[\ \t]*(['′´’\.:]|M(?:IN)?(?:UTES)?)?[\ \t]*,?((?:[0-5]?[0-9])(?:\.\d{1,3})?)?[\ \t]*(''|′′|’’|´´|["″”\.])?[\ \t]*(NORTH|SOUTH|[NS])?(?:\s*[,/;]\s*|\s*)(EAST|WEST|[EW])?[\ \t]*([+-]?[0-1]?[0-9]?[0-9])[\ \t]*([•º°\.:]|D(?:EG)?(?:REES)?)?[\ \t]*,?([0-5]?[0-9](?:\.\d{1,})?)?[\ \t]*(['′´’\.:]|M(?:IN)?(?:UTES)?)?[\ \t]*,?((?:[0-5]?[0-9])(?:\.\d{1,3})?)?[\ \t]*(''|′′|´´|’’|["″”\.])?[\ \t]*(EAST|WEST|[EW])?/i;
|
354
|
+
|
355
|
+
const to = Object.freeze({
|
356
|
+
DMS: 'DMS',
|
357
|
+
DM: 'DM'
|
358
|
+
})
|
359
|
+
|
360
|
+
converter.to = to
|
353
361
|
|
354
362
|
module.exports = converter
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "geo-coordinates-parser",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.4.0",
|
4
4
|
"description": "A Javascript function for reading a variety of coordinate formats and converting to decimal numbers. Builds on other efforts by returning the verbatim coordinates and the decimal coordinates all in one object.",
|
5
5
|
"main": "merge.js",
|
6
6
|
"scripts": {
|
package/test.js
CHANGED
@@ -25,9 +25,9 @@ testFormats.some(t => { //.some so we can break
|
|
25
25
|
//check the verbatim coords are correct
|
26
26
|
if(converted.verbatimLatitude != t.verbatimLatitude || converted.verbatimLongitude != t.verbatimLongitude) {
|
27
27
|
console.log("Error in verbatim extraction")
|
28
|
-
console.log(t.verbatimCoordinates)
|
29
|
-
console.log(t.verbatimLatitude)
|
30
|
-
console.log(t.verbatimLongitude)
|
28
|
+
console.log('For', t.verbatimCoordinates)
|
29
|
+
console.log('got', converted.verbatimLatitude, 'should be ', t.verbatimLatitude)
|
30
|
+
console.log('got', converted.verbatimLongitude, 'should be', t.verbatimLongitude)
|
31
31
|
allPassed = false;
|
32
32
|
return true
|
33
33
|
}
|
package/testIndividual.js
CHANGED
@@ -1,4 +1,15 @@
|
|
1
1
|
const convert = require('./converter')
|
2
|
-
const test = '
|
2
|
+
const test = '42:12:4S 27:17:18E'
|
3
3
|
|
4
|
-
|
4
|
+
try{
|
5
|
+
let converted = convert(test)
|
6
|
+
console.log(converted)
|
7
|
+
console.log(converted.toCoordinateFormat(convert.to.DM))
|
8
|
+
|
9
|
+
//and just to make sure it's frozen
|
10
|
+
converted.decimalLatitude = 24
|
11
|
+
console.log(converted)
|
12
|
+
}
|
13
|
+
catch(err){
|
14
|
+
console.log(err.message)
|
15
|
+
}
|
package/testformats.js
CHANGED
@@ -131,6 +131,11 @@ var coordsParserFormats = [
|
|
131
131
|
verbatimCoordinates: '40° 7.38, -74° 7.38',
|
132
132
|
verbatimLatitude: '40° 7.38',
|
133
133
|
verbatimLongitude: '-74° 7.38'
|
134
|
+
},
|
135
|
+
{
|
136
|
+
verbatimCoordinates: '40 7 22.8; -74 7 22.8', //semicolon separator
|
137
|
+
verbatimLatitude: '40 7 22.8',
|
138
|
+
verbatimLongitude: '-74 7 22.8'
|
134
139
|
}
|
135
140
|
]
|
136
141
|
|
@@ -213,6 +218,13 @@ var coordsRegexFormats = [
|
|
213
218
|
verbatimLongitude: '-79.948862',
|
214
219
|
decimalLatitude: 40.446195,
|
215
220
|
decimalLongitude: -79.948862
|
221
|
+
},
|
222
|
+
{
|
223
|
+
verbatimCoordinates: '40.123256; -74.123256', //testing semicolon
|
224
|
+
verbatimLatitude: '40.123256',
|
225
|
+
verbatimLongitude: '-74.123256',
|
226
|
+
decimalLatitude: 40.123256,
|
227
|
+
decimalLongitude: -74.123256
|
216
228
|
}
|
217
229
|
]
|
218
230
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
//borrowed from https://www.codegrepper.com/code-examples/javascript/javascript+converting+latitude+longitude+to+gps+coordinates
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Converts decimalCoordinates to other formats commonly used
|
6
|
+
* @param {*} format Either DMS or DM
|
7
|
+
*/
|
8
|
+
function toCoordinateFormat(format) {
|
9
|
+
|
10
|
+
if(!['DMS', 'DM'].includes(format)) throw new Error('invalid format specified')
|
11
|
+
|
12
|
+
if(this.decimalCoordinates && this.decimalCoordinates.trim()) {
|
13
|
+
const parts = this.decimalCoordinates.split(',').map(x => x.trim())
|
14
|
+
const convertedLat = convert(parts[0], format, true)
|
15
|
+
const convertedLong = convert(parts[1], format, false)
|
16
|
+
return `${convertedLat}, ${convertedLong}`
|
17
|
+
}
|
18
|
+
else {
|
19
|
+
throw new Error('no decimal coordinates to convert')
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
//assumes everything is valid...
|
24
|
+
function convert(coordString, format, isLatitude) {
|
25
|
+
|
26
|
+
const coord = Number(coordString)
|
27
|
+
|
28
|
+
let direction
|
29
|
+
if (isLatitude) {
|
30
|
+
direction = coord >= 0 ? "N" : "S";
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
direction = coord >= 0 ? "E" : "W";
|
34
|
+
}
|
35
|
+
|
36
|
+
const absolute = Math.abs(coord);
|
37
|
+
|
38
|
+
const degrees = Math.floor(absolute);
|
39
|
+
const minutesNotTruncated = (absolute - degrees) * 60;
|
40
|
+
|
41
|
+
if(format == 'DM') {
|
42
|
+
return `${degrees}° ${minutesNotTruncated.toFixed(3).replace(/\.0+$/, '')}' ${direction}`;
|
43
|
+
}
|
44
|
+
|
45
|
+
//else
|
46
|
+
const minutes = Math.floor(minutesNotTruncated);
|
47
|
+
const seconds = ((minutesNotTruncated - minutes) * 60).toFixed(1).replace(/\.0$/, '');
|
48
|
+
|
49
|
+
return `${degrees}° ${minutes}' ${seconds}" ${direction}`;
|
50
|
+
}
|
51
|
+
|
52
|
+
module.exports = toCoordinateFormat
|