diff --git a/.babelrc.js b/.babelrc.js index 69c3a2b..2a8e7e7 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -1,3 +1,11 @@ module.exports = { - presets: ['@babel/env', '@babel/typescript'], + presets: [ + [ + '@babel/env', + { + targets: '> 0.25%, not dead', + }, + ], + '@babel/typescript', + ], }; diff --git a/.lintstagedrc b/.lintstagedrc index 72cc64d..9084819 100644 --- a/.lintstagedrc +++ b/.lintstagedrc @@ -1,15 +1,14 @@ { "linters": { - "*.{js,jsx,ts,tsx,css}": [ + "*.{js,ts,md}": [ "prettier --write", "git add" ], - "*.{js,jsx,ts,tsx}": [ - "yarn lint:js --fix", - "git add" + "*.{js,ts}": [ + "yarn tsc" ], - "*.css": [ - "yarn lint:css --fix", + "*.{js,ts}": [ + "yarn lint:js --fix", "git add" ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 830dad8..b9d046d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,58 +1,65 @@ # Breaking Changes in 3.0.0 +In version 3.0.0 I'm trying to get a little bit _back to the roots_. Geolib was once started because I, myself, needed a handful of methods to perform very specific geo related tasks like getting the distance or the direction between two points. Since it was one of the very first libraries on npm back then to do these kind of things in a very simple way, it got a lot of popularity (300k downloads per month as of April 2019!) and as a consequence a lot of contributions over the years. Many of which I just merged as long as they had accompanying tests, without looking at consistency, conventions, complexity, coding style or even the overall quality of the functions that I sometimes didn't even fully understand. + +I now cleaned up the codebase completely, rebuilt the entire library "from scratch", unified all the parameters, removed a few functions where I wasn't sure if they should be in here (feel free to add them back of you're using them!) or if they were even used (did a few searches on GitHub for the function names, turned out there are zero results). + +Elevation support was dropped, as well as a few functions that unnecessarily made the library really large in size (e.g. isPointInsideRobust alone was over 700[!] lines of code). I removed Grunt from the build process, added "modern" tools like ESLint and Prettier. I switched from Travis CI to Circle CI and I am in the process of further automate the release process of new versions using `semantic-release` and `conventional-commits`. I also switched from pure JavaScript from TypeScript because I think it does have some benefits. + - All functions are pure function now. No input data is mutated anymore. You give the same input, you get the same output. No side effects or whatsoever. +- I changed the default `getDistance` function from being the slow, accurate one to being the fast, slightly inaccurate one. The old `getDistance` function is now named `getPreciseDistance` while the old `getDistanceSimple` function is now the default `getDistance` function. You can, however, pass `getPreciseDistance` as parameter to any function that uses distance calculation internally. - Artificial limitation to 8 decimal places in decimal coordinates was removed - - `getBoundsOfDistance()` now returns the _exact_ coordinates due to the removal of the artificial 8 decimal place limitation - `getCompassDirection()` does no longer return an object with an _exact_ and a _rough_ direction but only the exact direction as string - 3rd parameter to `getCompassDirection()` is no longer a string ("circle", "line") but a function to determine the bearing (you can pass `getRhumbLineBearing` or `getGreatCircleBearing`). The function receives the origin and the destination as 1st and 2nd parameter. If no 3rd parameter was given, `getRhumbLineBearing(origin, dest)` is used by default. - There is now a new helper function `roughCompassDirection(exact)` if you _really_ only need a very rough (and potentially inaccurate) direction. - `orderByDistance()` does no longer modify its input so does not add a `distance` and `key` property to the returned coordinates -- The result of `getSpeed()` is now always returned as meters per second. It can be converted using the new convenience function `convertSpeed(mps, targetUnit)` +- The result of `getSpeed()` is now always returned as **meters per second**. It can be converted using the new convenience function `convertSpeed(mps, targetUnit)` - The point (or distance) is no consistently the first parameter for each functions using either of them (it wasn't before, how confusing is that?) - `findNearest()` does not take `offset` and `limit` parameters. It's only a convenience method to get the single one nearest point from a set of coordinates. If you need more than one, have a look at the implementation and implement your own logic using `orderByDistance` - Whereever distances are involved, they are returned as meters or meters per second. No more defaulting to kilometers or kilometers per hour. - The method how sexagesimal is formatted differs a little bit. It may now potentially return ugly float point units like `52° 46' 21.0004"` in rare cases but it is also more accurate then it was before. +- Dropped support for Meteor (feel free to add it back if you like) -## Method status in 3.0.0 +## Method status in 3.0.0 compared to 2.x.x -- ❗ getKeys -> getCoordinateKeys -- ❗ validate -> isValidCoordinate -- ❗ getLat -> getLatitude (might be re-added for convenience) -- ❗ getLon -> getLongitude (might be re-added for convenience) -- ‼ latitude -> removed -- ‼ longitude -> removed -- ‼ getElev -> removed (might be re-added) -- ‼ elevation -> removed -- ‼ coords -> removed (might be re-added as getCoordinate or getNormalizedCoordinate) -- ‼ ll -> removed (bccause wtfsrsly?) -- ❗ getDistance -> getPreciseDistance -- ❗ getDistanceSimple -> getDistance -- ✅ getCenter -- ✅ getBounds -- ✅ getCenterOfBounds -- ✅ getBoundsOfDistance (missing tests) -- ❗ isPointInside -> isPointInPolygon -- ‼ preparePolygonForIsPointInsideOptimized -> still missing -- ‼ isPointInsideWithPreparedPolygon -> still missing -- ‼ isInside -> removed (too ambiguous) -- ❗ isPointInCircle -> isPointWithinRadius -- ‼ withinRadius -> removed -- ✅ getRhumbLineBearing -- ❗ getBearing -> getGreatCircleBearing -- ✅ getCompassDirection -- ‼ getDirection -> removed (might be added back) -- ✅ orderByDistance -- ✅ isPointInLine +- ❗ `getKeys` renamed to `getCoordinateKeys` +- ❗ `validate` renamed to `isValidCoordinate` +- ❗ `getLat` renamed to `getLatitude` +- ❗ `getLon` renamed to `getLongitude` +- 🗑 `latitude` -> removed +- 🗑 `longitude` -> removed +- 🗑 `getElev` -> removed +- 🗑 `elevation` -> removed +- 🗑 `coords` -> removed (might be re-added as getCoordinate or getNormalizedCoordinate) +- 🗑 `ll` -> removed (because wtfsrsly?) +- ❗ `getDistance` renamed to `getPreciseDistance` +- ❗ `getDistanceSimple` renamed to `getDistance` +- ✅ `getCenter` +- ✅ `getBounds` +- ✅ `getCenterOfBounds` +- ✅ `getBoundsOfDistance` +- ❗ `isPointInside` renamed to isPointInPolygon +- 🗑 `preparePolygonForIsPointInsideOptimized` -> removed due to missing documentation +- 🗑 `isPointInsideWithPreparedPolygon` -> removed due to missing documentation +- 🗑 `isInside` alias -> removed (too ambiguous) +- ❗ `isPointInCircle` renamed to isPointWithinRadius +- 🗑 `withinRadius` -> removed +- ✅ `getRhumbLineBearing` +- ❗ `getBearing` renamed to `getGreatCircleBearing` for more clarity +- ✅ `getCompassDirection` +- 🗑 `getDirection` alias -> removed (unnecessry clutter) +- ✅ `orderByDistance` +- ✅ `isPointInLine` - ❗ getDistanceFromLine -> untested - ‼ isPointNearLine -> still missing -- ✅ getPathLength -- ✅ getSpeed -- ✅ computeDestinationPoint +- ✅ `getPathLength` +- ✅ `getSpeed` +- ✅ `computeDestinationPoint` - ‼ convertUnit -> still missing (will be remamed to convertDistance because too ambiguous) -- ❗ useDecimal -> toDecimal -- ❗ decimal2sexagesimal -> decimalToSexagesimal -- ❗ sexagesimal2decimal -> sexagesimalToDecimal -- ✅ isDecimal -- ✅ isSexagesimal -- +- ❗ `useDecimal` renamed to `toDecimal` +- ❗ `decimal2sexagesimal` renamed to `decimalToSexagesimal` +- ❗ `sexagesimal2decimal` renamed to `sexagesimalToDecimal` +- ✅ `isDecimal` +- ✅ `isSexagesimal` +- 🆕 Added new method `getCoordinateKey` to get a property name (e.g. `lat` or `lng` of an object based on an array of possible names) diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..9b1a9a0 --- /dev/null +++ b/lib/index.js @@ -0,0 +1 @@ +!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.geolib=n():t.geolib=n()}("undefined"!=typeof self?self:this,function(){return function(t){var n={};function r(e){if(n[e])return n[e].exports;var a=n[e]={i:e,l:!1,exports:{}};return t[e].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=t,r.c=n,r.d=function(t,n,e){r.o(t,n)||Object.defineProperty(t,n,{enumerable:!0,get:e})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,n){if(1&n&&(t=r(t)),8&n)return t;if(4&n&&"object"==typeof t&&t&&t.__esModule)return t;var e=Object.create(null);if(r.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:t}),2&n&&"string"!=typeof t)for(var a in t)r.d(e,a,function(n){return t[n]}.bind(null,a));return e},r.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(n,"a",n),n},r.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},r.p="",r(r.s=0)}([function(t,n,r){"use strict";r.r(n);var e=/^([0-9]{1,3})°\s*([0-9]{1,3}(?:\.(?:[0-9]{1,}))?)['′]\s*(([0-9]{1,3}(\.([0-9]{1,}))?)["″]\s*)?([NEOSW]?)$/,a=["lng","lon","longitude",0],i=["lat","latitude",1],u=["alt","altitude","elevation","elev",2],o=.001,c=1/1609.344,f=3600,s=function(t,n){return n.reduce(function(n,r){return t.hasOwnProperty(r)&&void 0!==r&&void 0===n?(n=r,r):n},void 0)},l=function(t){var n=t.toString().trim();return!isNaN(parseFloat(n))&&parseFloat(n)===Number(n)},d=function(t){return e.test(t.toString().trim())},h=function(t){var n=new RegExp(e).exec(t);if(null==n)throw new Error("Given value is not in sexagesimal format");var r=Number(n[2])/60||0,a=Number(n[4])/3600||0,i=parseFloat(n[1])+r+a;return["S","W"].includes(n[7])?-i:i};function g(t,n,r){return n in t?Object.defineProperty(t,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[n]=r,t}var M=function(t){var n=s(t,a),r=s(t,i),e=s(t,u);return function(t){for(var n=1;n90||n<-90):!!d(n)&&t(h(n))},v=function t(n){return l(n)?!(parseFloat(n)>180||n<-180):!!d(n)&&t(h(n))},p=function(t){var n=M(t),r=n.latitude,e=n.longitude;if(Array.isArray(t)&&t.length>=2)return v(t[0])&&m(t[1]);if(void 0===r||void 0===e)return!1;var a=t[e],i=t[r];return void 0!==i&&void 0!==a&&!1!==m(i)&&!1!==v(a)};function y(t,n,r){return n in t?Object.defineProperty(t,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[n]=r,t}var b=function t(n){if(l(n))return Number(n);if(d(n))return h(n);if(p(n)){var r=M(n);return Array.isArray(n)?n.map(function(n,r){return[0,1].includes(r)?t(n):n}):function(t){for(var n=1;n3&&void 0!==arguments[3]?arguments[3]:6378137,a=S(t),i=N(t),u=n/e,o=P(r),c=P(a),f=P(i),s=Math.asin(Math.sin(c)*Math.cos(u)+Math.cos(c)*Math.sin(u)*Math.cos(o)),l=f+Math.atan2(Math.sin(o)*Math.sin(u)*Math.cos(c),Math.cos(u)-Math.sin(c)*Math.sin(s));return l=(l+3*Math.PI)%(2*Math.PI)-Math.PI,{latitude:x(s),longitude:x(l)}},O=function(t){switch(arguments.length>1&&void 0!==arguments[1]?arguments[1]:"kmh"){case"kmh":return t*f*o;case"mph":return t*f*c;default:return t}};function E(t,n){return function(t){if(Array.isArray(t))return t}(t)||function(t,n){var r=[],e=!0,a=!1,i=void 0;try{for(var u,o=t[Symbol.iterator]();!(e=(u=o.next()).done)&&(r.push(u.value),!n||r.length!==n);e=!0);}catch(t){a=!0,i=t}finally{try{e||null==o.return||o.return()}finally{if(a)throw i}}return r}(t,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}var j=function(t){var n=Math.pow(10,12);return Math.round(t*n)/n},w=function(t){var n=E(t.toString().split("."),2),r=n[0],e=n[1],a=Math.abs(Number(r)),i=j(60*Number("0."+(e||0))),u=Math.floor(i),o=j(60*(i%u||0));return a+"° "+Number(u.toFixed(6)).toString().split(".").map(function(t,n){return 0===n?t.padStart(2,"0"):t}).join(".")+"' "+Number(o.toFixed(4)).toString().split(".").map(function(t,n){return 0===n?t.padStart(2,"0"):t}).join(".")+'"'},W=function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;r=void 0===r||isNaN(r)?1:r;var e=S(t),a=N(t),i=S(n),u=N(n),o=6378137*Math.acos(Math.sin(P(i))*Math.sin(P(e))+Math.cos(P(i))*Math.cos(P(e))*Math.cos(P(a)-P(u)));return Math.round(o/r)*r},I=function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:W;return r="function"==typeof r?r:W,n.slice().sort(function(n,e){return r(t,n)-r(t,e)})},F=function(t,n){return I(t,n)[0]},D=function(t){return!1!==Array.isArray(t)&&0!==t.length&&t.reduce(function(t,n){return{maxLat:Math.max(S(n),t.maxLat),minLat:Math.min(S(n),t.minLat),maxLng:Math.max(N(n),t.maxLng),minLng:Math.min(N(n),t.minLng)}},{maxLat:-1/0,minLat:1/0,maxLng:-1/0,minLng:1/0})},A=function(t,n){var r,e,a=S(t),i=N(t),u=P(a),o=P(i),c=n/6378137,f=u-c,s=u+c,l=P(90),d=P(-90),h=P(180),g=P(-180);if(f>d&&sh&&(e-=2*Math.PI)}else f=Math.max(f,d),s=Math.min(s,l),r=g,e=h;return[{latitude:x(f),longitude:x(r)},{latitude:x(s),longitude:x(e)}]},C=function(t){if(!1===Array.isArray(t)||0===t.length)return!1;var n=t.length,r=t.reduce(function(t,n){var r=P(S(n)),e=P(N(n));return{X:t.X+Math.cos(r)*Math.cos(e),Y:t.Y+Math.cos(r)*Math.sin(e),Z:t.Z+Math.sin(r)}},{X:0,Y:0,Z:0}),e=r.X/n,a=r.Y/n,i=r.Z/n;return{longitude:x(Math.atan2(a,e)),latitude:x(Math.atan2(i,Math.sqrt(e*e+a*a)))}},B=function(t){var n=D(t),r=n.minLat+(n.maxLat-n.minLat)/2,e=n.minLng+(n.maxLng-n.minLng)/2;return{latitude:parseFloat(r.toFixed(6)),longitude:parseFloat(e.toFixed(6))}},_=function(t,n){var r=P(N(n))-P(N(t)),e=Math.log(Math.tan(P(S(n))/2+Math.PI/4)/Math.tan(P(S(t))/2+Math.PI/4));return Math.abs(r)>Math.PI&&(r=r>0?-1*(2*Math.PI-r):2*Math.PI+r),(x(Math.atan2(r,e))+360)%360},k=function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:_,e="function"==typeof r?r(t,n):_(t,n);if(isNaN(e))throw new Error("Could not calculate bearing for given points. Check your bearing function");switch(Math.round(e/22.5)){case 1:return"NNE";case 2:return"NE";case 3:return"ENE";case 4:return"E";case 5:return"ESE";case 6:return"SE";case 7:return"SSE";case 8:return"S";case 9:return"SSW";case 10:return"SW";case 11:return"WSW";case 12:return"W";case 13:return"WNW";case 14:return"NW";case 15:return"NNW";default:return"N"}},T=function(t,n,r){var e=W(n,t),a=W(t,r),i=W(n,r),u=Math.acos((e*e+i*i-a*a)/(2*e*i)),o=Math.acos((a*a+i*i-e*e)/(2*a*i));return u>Math.PI/2?e:o>Math.PI/2?a:Math.sin(u)*e},$=function(t,n){var r=S(n),e=N(n),a=S(t),i=N(t);return(x(Math.atan2(Math.sin(P(e)-P(i))*Math.cos(P(r)),Math.cos(P(a))*Math.sin(P(r))-Math.sin(P(a))*Math.cos(P(r))*Math.cos(P(e)-P(i))))+360)%360};function X(t){return(X="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var Y=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:W;return t.reduce(function(t,r){return"object"===X(t)&&null!==t.last&&(t.distance+=n(r,t.last)),t.last=r,t},{last:null,distance:0}).distance},Z=function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;r=void 0===r||isNaN(r)?1:r;var e,a,i,u,o,c,f,s=S(t),l=N(t),d=S(n),h=N(n),g=6356752.314245,M=P(h-l),m=Math.atan(.9966471893352525*Math.tan(P(parseFloat(s)))),v=Math.atan(.9966471893352525*Math.tan(P(parseFloat(d)))),p=Math.sin(m),y=Math.cos(m),b=Math.sin(v),x=Math.cos(v),L=M,O=100;do{var E=Math.sin(L),j=Math.cos(L);if(0===(c=Math.sqrt(x*E*(x*E)+(y*b-p*x*j)*(y*b-p*x*j))))return 0;e=p*b+y*x*j,a=Math.atan2(c,e),o=e-2*p*b/(u=1-(i=y*x*E/c)*i),isNaN(o)&&(o=0);var w=1/298.257223563/16*u*(4+1/298.257223563*(4-3*u));f=L,L=M+1/298.257223563*(1-w)*i*(a+w*c*(o+w*e*(2*o*o-1)))}while(Math.abs(L-f)>1e-12&&--O>0);if(0===O)return NaN;var W=272331606109.84375*u/(g*g),I=W/1024*(256+W*(W*(74-47*W)-128)),F=g*(1+W/16384*(4096+W*(W*(320-175*W)-768)))*(a-I*c*(o+I/4*(e*(2*o*o-1)-I/6*o*(4*c*c-3)*(4*o*o-3))));return Math.round(F/r)*r},R=function(t){return/^NNE|NE|NNW|N$/.test(t)?"N":/^ENE|E|ESE|SE$/.test(t)?"E":/^SSE|S|SSW|SW$/.test(t)?"S":/^WSW|W|WNW|NW$/.test(t)?"W":void 0},V=function(t,n){return(arguments.length>2&&void 0!==arguments[2]?arguments[2]:W)(t,n)/(Number(n.time)-Number(t.time))*1e3},q=function(t,n,r){return W(n,t)+W(t,r)===W(n,r)},G=function(t,n){for(var r=!1,e=n.length,a=-1,i=e-1;++a { + it('should get the correct key out of a list of keys', () => { + expect( + getCoordinateKey({ lat: 1, lng: 1 }, ['latitude', 'lat']) + ).toEqual('lat'); + }); + + it('should return the first match from the lookup array only', () => { + expect( + getCoordinateKey({ lat: 1, latitude: 1 }, ['latitude', 'lat']) + ).toEqual('latitude'); + }); + + it('should return an index of a GeoJSON array', () => { + expect(getCoordinateKey([1, 2], ['latitude', 'lat', 0])).toEqual(0); + }); +}); diff --git a/src/getCoordinateKey.ts b/src/getCoordinateKey.ts index 641dbfd..88acabb 100644 --- a/src/getCoordinateKey.ts +++ b/src/getCoordinateKey.ts @@ -4,15 +4,19 @@ const getCoordinateKey = ( point: GeolibInputCoordinates, keysToLookup: Keys[] ) => { - return keysToLookup.reduce((acc: Keys | undefined, key: any): + return keysToLookup.reduce((foundKey: Keys | undefined, key: any): | Keys | undefined => { - if (point.hasOwnProperty(key) && typeof key !== 'undefined') { - acc = key; + if ( + point.hasOwnProperty(key) && + typeof key !== 'undefined' && + typeof foundKey === 'undefined' + ) { + foundKey = key; return key; } - return acc; + return foundKey; }, undefined); }; diff --git a/src/getDistanceFromLine.test.js b/src/getDistanceFromLine.test.js new file mode 100644 index 0000000..a698186 --- /dev/null +++ b/src/getDistanceFromLine.test.js @@ -0,0 +1,13 @@ +import getDistanceFromLine from './getDistanceFromLine'; + +describe('getDistanceFromLine', () => { + it('should get the shortest distance from a point to a line of two points', () => { + expect( + getDistanceFromLine( + { latitude: 51.516, longitude: 7.456 }, + { latitude: 51.512, longitude: 7.456 }, + { latitude: 51.516, longitude: 7.459 } + ) + ).toEqual(188.5131192933101); + }); +}); diff --git a/src/getDistanceFromLine.ts b/src/getDistanceFromLine.ts index ff82c85..a2a03d0 100644 --- a/src/getDistanceFromLine.ts +++ b/src/getDistanceFromLine.ts @@ -2,7 +2,6 @@ import getDistance from './getDistance'; import { GeolibInputCoordinates } from './types'; // Returns the minimum distance from a point to a line -// TODO: this is untested. Add tests. const getDistanceFromLine = ( point: GeolibInputCoordinates, start: GeolibInputCoordinates, @@ -11,7 +10,6 @@ const getDistanceFromLine = ( const d1 = getDistance(start, point); const d2 = getDistance(point, end); const d3 = getDistance(start, end); - let distance = 0; // alpha is the angle between the line from start to point, and from start to end const alpha = Math.acos((d1 * d1 + d3 * d3 - d2 * d2) / (2 * d1 * d3)); @@ -22,17 +20,17 @@ const getDistanceFromLine = ( // if the angle is greater than 90 degrees, then the minimum distance is the // line from the start to the point if (alpha > Math.PI / 2) { - distance = d1; - } else if (beta > Math.PI / 2) { + return d1; + } + + if (beta > Math.PI / 2) { // same for the beta - distance = d2; - } else { - // otherwise the minimum distance is achieved through a line perpendular to the start-end line, - // which goes from the start-end line to the point - distance = Math.sin(alpha) * d1; + return d2; } - return distance; + // otherwise the minimum distance is achieved through a line perpendicular + // to the start-end line, which goes from the start-end line to the point + return Math.sin(alpha) * d1; }; export default getDistanceFromLine; diff --git a/src/roughCompassDirection.ts b/src/getRoughCompassDirection.ts similarity index 81% rename from src/roughCompassDirection.ts rename to src/getRoughCompassDirection.ts index e05f260..e195d4a 100644 --- a/src/roughCompassDirection.ts +++ b/src/getRoughCompassDirection.ts @@ -1,6 +1,6 @@ // Receives an exact compass direction (like WNW) and spits out a very rough // and overly simplified direction (N|E|S|W). Use with caution! -const roughCompassDirection = (exact: string) => { +const getRoughCompassDirection = (exact: string) => { if (/^NNE|NE|NNW|N$/.test(exact)) { return 'N'; } @@ -18,4 +18,4 @@ const roughCompassDirection = (exact: string) => { } }; -export default roughCompassDirection; +export default getRoughCompassDirection; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..98c849b --- /dev/null +++ b/src/index.ts @@ -0,0 +1,36 @@ +export { default as computeDestinationPoint } from './computeDestinationPoint'; +export { default as convertSpeed } from './convertSpeed'; +export { default as decimalToSexagesimal } from './decimalToSexagesimal'; +export { default as findNearest } from './findNearest'; +export { default as getBounds } from './getBounds'; +export { default as getBoundsOfDistance } from './getBoundsOfDistance'; +export { default as getCenter } from './getCenter'; +export { default as getCenterOfBounds } from './getCenterOfBounds'; +export { default as getCompassDirection } from './getCompassDirection'; +export { default as getCoordinateKey } from './getCoordinateKey'; +export { default as getCoordinateKeys } from './getCoordinateKeys'; +export { default as getDistance } from './getDistance'; +export { default as getDistanceFromLine } from './getDistanceFromLine'; +export { default as getGreatCircleBearing } from './getGreatCircleBearing'; +export { default as getLatitude } from './getLatitude'; +export { default as getLongitude } from './getLongitude'; +export { default as getPathLength } from './getPathLength'; +export { default as getPreciseDistance } from './getPreciseDistance'; +export { default as getRhumbLineBearing } from './getRhumbLineBearing'; +export { + default as getRoughCompassDirection, +} from './getRoughCompassDirection'; +export { default as getSpeed } from './getSpeed'; +export { default as isDecimal } from './isDecimal'; +export { default as isPointInLine } from './isPointInLine'; +export { default as IsPointInPolygon } from './IsPointInPolygon'; +export { default as isPointNearLine } from './isPointNearLine'; +export { default as isSexagesimal } from './isSexagesimal'; +export { default as isValidCoordinate } from './isValidCoordinate'; +export { default as isValidLatitude } from './isValidLatitude'; +export { default as isValidLongitude } from './isValidLongitude'; +export { default as orderByDistance } from './orderByDistance'; +export { default as sexagesimalToDecimal } from './sexagesimalToDecimal'; +export { default as toDecimal } from './toDecimal'; +export { default as toRad } from './toRad'; +export { default as toDeg } from './toDeg'; diff --git a/src/isPointNearLine.test.js b/src/isPointNearLine.test.js new file mode 100644 index 0000000..131bf3e --- /dev/null +++ b/src/isPointNearLine.test.js @@ -0,0 +1,14 @@ +import isPointNearLine from './isPointNearLine'; + +describe('isPointNearLine', () => { + it('should get the shortest distance from a point to a line of two points', () => { + expect( + isPointNearLine( + { latitude: 51.516, longitude: 7.456 }, + { latitude: 51.512, longitude: 7.456 }, + { latitude: 51.516, longitude: 7.459 }, + 200 + ) + ).toBe(true); + }); +}); diff --git a/src/isPointNearLine.ts b/src/isPointNearLine.ts new file mode 100644 index 0000000..9316afa --- /dev/null +++ b/src/isPointNearLine.ts @@ -0,0 +1,13 @@ +import getDistanceFromLine from './getDistanceFromLine'; +import { GeolibInputCoordinates } from './types'; + +// Check if a point lies within a given distance from a line created by two +// other points +const isPointNearLine = ( + point: GeolibInputCoordinates, + start: GeolibInputCoordinates, + end: GeolibInputCoordinates, + distance: number +) => getDistanceFromLine(point, start, end) < distance; + +export default isPointNearLine; diff --git a/webpack.config.js/index.js b/webpack.config.js/index.js new file mode 100644 index 0000000..a8c7bc0 --- /dev/null +++ b/webpack.config.js/index.js @@ -0,0 +1,24 @@ +module.exports = { + mode: 'production', // this will trigger some webpack default stuffs for dev + entry: `${__dirname}/../src/index.ts`, + output: { + filename: 'index.js', + path: `${__dirname}/../lib`, + libraryTarget: 'umd', + library: 'geolib', + // this is a weird hack to make the umd build work in node + // https://github.com/webpack/webpack/issues/6525#issuecomment-417580843 + globalObject: 'typeof self !== "undefined" ? self : this', + }, + resolve: { + extensions: ['.js', '.ts'], + }, + module: { + rules: [ + { + test: /\.(ts|js)$/, + loader: require.resolve('babel-loader'), + }, + ], + }, +}; diff --git a/yarn.lock b/yarn.lock index 407ec7c..9f875a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1326,6 +1326,16 @@ babel-jest@^24.8.0: chalk "^2.4.2" slash "^2.0.0" +babel-loader@^8.0.6: + version "8.0.6" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" + integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + pify "^4.0.1" + babel-plugin-istanbul@^5.1.0: version "5.1.4" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.4.tgz#841d16b9a58eeb407a0ddce622ba02fe87a752ba" @@ -3930,7 +3940,7 @@ loader-runner@^2.3.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@^1.1.0: +loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==