New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

geojson-tools

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

geojson-tools - npm Package Compare versions

Comparing version 0.1.7 to 0.2.0-pre

7

HISTORY.md

@@ -0,1 +1,8 @@

0.2.0 / 2015-06-02
==================
* Add `isGeoJSON()` check
* Add support for all GeoJSON types
* Add unit tests (coverage incomplete)
0.1.7 / 2014-06-13

@@ -2,0 +9,0 @@ ==================

10

package.json
{
"name": "geojson-tools",
"version": "0.1.7",
"version": "0.2.0-pre",
"description": "Tools for working with location data, using the GeoJSON specification",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "mocha"
},

@@ -26,8 +26,8 @@ "repository": {

"dependencies": {
"underscore": "^1.6.0"
"underscore": "^1.8.3"
},
"devDependencies": {
"mocha": "1.18.*",
"chai": "~1.9.1"
"mocha": "2.2.*",
"chai": "2.1.*"
}
}

@@ -29,2 +29,6 @@ # geojson-tools.js

### Validations
* [isGeoJSON](#isGeoJSON)
## Calculations

@@ -61,3 +65,3 @@

__Argumenta""
__Arguments__

@@ -250,7 +254,7 @@ * linestring - a valid GeoJSON `LineString`, or an array of locations, in the format `[lat, lng]`.

* array - an array of locations, in the format `[lat, lng]`.
* type - the type of `GeoJSON` object to return (note that this is not case-sensitive.
* type - the type of `GeoJSON` object to return (note that this is not case-sensitive).
The default type is 'Point', which is returned when pushing an array of a single set of coordinates.
Other types are `LineString` and `Polygon`.
<b>Note:</b> Other `GeoJSON` types will be supported in future versions.
<b>Note:</b> Other `GeoJSON` types will be supported in future versions.

@@ -303,6 +307,10 @@ __Examples__

* geoobj - a valid `GeoJSON` object of the following types: `Point`, `LineString` or `Polygon`.
* geoobj - a valid `GeoJSON` object of the following types: `Point`, `LineString`, `Polygon`, `MultiPoint`, `MultiLineString` or `MultiPolygon`.
**Note:** Other `GeoJSON` types will be supported in future versions.
**Note:** The `Feature`, `FeatureCollection` and `GeometryCollection` objects are unsupported.
The logic being that it would make it difficult to work with such deeply nested arrays, and that the primary `GeoJSON` objects
would be mixed.
To convert the above to arrays, rather convert the individual geometries in the feature etc.
__Examples__

@@ -337,1 +345,53 @@

```
## Validations
<a name="isGeoJSON" />
### isGeoJSON(obj[, returnError])
Takes an input of an object, and returns a `true` or `false`. Include a `Boolean` to return a validation message for invalid objects.
__Arguments__
* obj - an object, either valid or invalid `GeoJSON`.
* returnError - a `Boolean` indicating whether to return a validation message if obj is invalid.
The default `returnError` is `true`.
**Note:** All `GeoJSON` types are supported in the `isGeoJSON` check. They are:
* `Point`
* `MultiPoint`
* `LineString`
* `MultiLineString`
* `Polygon`
* `MultiPolygon`
* `Feature`
* `FeatureCollection`
* `GeometryCollection`
Nested GeoJSON objects are validated as part of the supplied object.
#### Caveats
1. We currently do not check the order of `LinearRings` inside a `Polygon`
2. All `coordinates` supplied are expected to be numbers, we do not `parseFloat`s
3. Though the library expects users to be using WGS84, we do not check bounds of lat and lng
__Examples__
To validate a valid `GeoJSON::Point`
```js
var geoobj = {"type":"Point","coordinates":[30,20]};
isGeoJSON(geoobj, true);
// true
```
To validate an invalid `GeoJSON::LineString`
```js
var geoobj = {"type":"LineString","coordinate":[[30,20],[29.5,20.5]]};
// note the 'coordinate', expecting 'coordinates'
isGeoJSON(geoobj, true);
// {result: false, message: "invalid GeoJSON type supplied"}
```

@@ -49,3 +49,3 @@ /**

type = 'LineString';
} else if (type === 'MultiPoint') {
} else if (type === 'multipoint') {
type = 'MultiPoint';

@@ -90,3 +90,3 @@ }

if (a.length < 2 && !error) {
error = new Error("Expecting each LineString in MultiiLineString to have at least 2 points.");
error = new Error("Expecting each LineString in MultiLineString to have at least 2 points.");
return true;

@@ -138,3 +138,3 @@ }

default:
error = new Error("type not recognised. Should be 'point', 'linestring', or 'polygon'");
error = new Error("type not recognised or supported");
}

@@ -205,4 +205,55 @@ if (error) {

});
break;
case 'multipoint':
var mpoint;
array = [];
// REVIEW should we check if valid object? Or can we do it at the top?
_.each(geoobj.coordinates, function (pt) {
array.push([parseFloat(pt[1]), parseFloat(pt[0])]);
});
break;
case 'multilinestring':
var multiline;
array = [];
// check if valid object
_.find(geoobj.coordinates, function (a) {
if (!a.length) {
error = new Error("the object specified is not a valid GeoJSON MultiLineString");
return true;
}
multiline = [];
_.each(a, function (pl) {
multiline.push([parseFloat(pl[1]), parseFloat(pl[0])]);
});
array.push(multiline);
return false;
});
break;
case 'multipolygon':
var poly;
array = [];
_.each(geoobj.coordinates, function (coord) {
_.find(coord, function (a) {
if (!a.length) {
error = new Error("the object specified is not a valid GeoJSON Polygon");
return true;
}
poly = [];
if (a[0].toString() !== _.last(a).toString()) {
error = new Error("The first and last coordinates of the Polygon are not the same");
return true;
}
if (a.length < 4) {
error = new Error("A valid Polygon should have a minimum set of 4 points");
return true;
}
_.each(_.initial(a), function (pl) {
poly.push([parseFloat(pl[1]), parseFloat(pl[0])]);
});
array.push(poly);
return false;
});
// return?
});
break;
default:

@@ -224,7 +275,2 @@ error = new Error("unknown GeoJSON type specified");

var getDistance = function (array, decimals) {
if (Number.prototype.toRad === undefined) {
Number.prototype.toRad = function () {
return this * Math.PI / 180;
};
}

@@ -256,6 +302,6 @@ decimals = decimals || 3;

dLat = (lat2 - lat1).toRad();
dLon = (lon2 - lon1).toRad();
lat1 = lat1.toRad();
lat2 = lat2.toRad();
dLat = _toRadian(lat2 - lat1);
dLon = _toRadian(lon2 - lon1);
lat1 = _toRadian(lat1);
lat2 = _toRadian(lat2);

@@ -340,3 +386,2 @@ a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +

c = [(b[0] - a[0]) * ratio * bearing[0], (b[1] - a[1]) * ratio * bearing[1]];
// console.log(c);
if (bearing[0] > 0) {

@@ -376,2 +421,192 @@ c[0] = c[0] + a[0];

/**
* takes an input of an object, and returns a `true` or `false`. Include a `Boolean`
+ to return a validation message for invalid objects.
*
* @param {Object} either a valid LineString, or an array of coordinates
* @param {Boolean} Optional true/false to return error message on invalid object
* @returns {Boolean} either true, false, or an object if `returnError` is not falsy
*/
var isGeoJSON = function (obj, returnError) {
var validTypes = [
"Point",
"MultiPoint",
"LineString",
"MultiLineString",
"Polygon",
"MultiPolygon",
"Feature",
"FeatureCollection",
"GeometryCollection"
];
var invalid;
var index = _.indexOf(validTypes, obj.type);
if (!obj.type || index < 0) {
return _returnError(false, returnError, {message: 'invalid GeoJSON type supplied'});
}
if (index < 6) {
if (!obj.coordinates || !_.isArray(obj.coordinates)) {
return _returnError(false, returnError, {message: 'invalid GeoJSON type supplied'});
}
if (obj.type === 'Point') {
// expect a single set of coordinates, or an array where the first 2 elements are numbers
return _isPosition(obj.coordinates, returnError);
}
if (obj.type === 'MultiPoint') {
if (obj.coordinates.length < 2) {
return _returnError(false, returnError, {message: 'expecting array with at least 2 elements for GeoJSON MultiPoint'});
}
invalid = _.find(obj.coordinates, function (xy) {
return !_isPosition(xy);
});
if (invalid) {
return _returnError(false, returnError, {message: 'one of the coordinates of the GeoJSON MultiPoint are invalid'});
}
// GeoJSON MultiPoint is valid
return true;
}
if (obj.type === 'LineString') {
if (obj.coordinates.length < 2) {
return _returnError(false, returnError, {message: 'expecting array with at least 2 elements for GeoJSON LineString'});
}
return _isLineString(obj.coordinates, returnError);
}
if (obj.type === 'MultiLineString') {
if (obj.coordinates.length < 2) {
return _returnError(false, returnError, {message: 'expecting array of multiple set of coordinates for GeoJSON MultiLineString'});
}
invalid = _.find(obj.coordinates, function (coordinates) {
return !_isLineString(coordinates, returnError);
});
if (invalid) {
return _returnError(false, returnError, {message: 'one of the coordinates of the GeoJSON MultiLineString are invalid'});
}
// GeoJSON MultiLineString is valid
return true;
}
if (obj.type === 'Polygon') {
return _isLinearRing(obj.coordinates, returnError);
}
if (obj.type === 'MultiPolygon') {
invalid = _.find(obj.coordinates, function (coordinates) {
return !_isLinearRing(coordinates, returnError);
});
if (invalid) {
return _returnError(false, returnError, {message: 'one of the coordinateof the GeoJSON MultiPolygon are invalid'});
}
// GeoJSON MultiPolygon is valid
return true;
}
}
if (index === 6) {
if (!obj.geometry) {
return _returnError(false, returnError, {message: 'expected GeoJSON Feature to have a geometry'});
}
if (!obj.properties) {
return _returnError(false, returnError, {message: 'expected GeoJSON Feature to have properties'});
}
// NOTE that we use recursion here, don't like the practise but we had to do it
// a feature can have an `id` but it is optional, we do not check it.
return isGeoJSON(obj.geometry, returnError);
}
if (index === 7) {
if (!obj.features) {
return _returnError(false, returnError, {message: "expected GeoJSON FeatureCollection to have features"});
}
if (!_.isArray(obj.features)) {
return _returnError(false, returnError, {message: "expected GeoJSON FeatureCollection's features to be an array"});
}
invalid = _.find(obj.features, function (feature) {
return !isGeoJSON(feature);
});
if (invalid) {
return _returnError(false, returnError, {message: "one of the GeoJSON FeatureCollection's features is invalid"});
}
return true;
}
if (index === 8) {
if (!obj.geometries) {
return _returnError(false, returnError, {message: "expected GeoJSON GeometryCollection to have geometries"});
}
if (!_.isArray(obj.geometries)) {
return _returnError(false, returnError, {message: 'expected GeoJSON GeometryCollection\'s geometries to be an array'});
}
var invalid = _.find(obj.geometries, function (geometry) {
return !isGeoJSON(geometry);
});
if (invalid) {
return _returnError(false, returnError, {message: 'one of the GeoJSON GeometryCollection\'s geometries is invalid'});
}
// GeoJSON GeometryCollection is valid
return true;
}
};
var _isLinearRing = function (arr, returnError) {
var invalid = _.find(arr, function (coordinates) {
if (coordinates.length < 4) {
return _returnError(false, returnError, {message: 'expecting coordinates of GeoJSON object to have at least 4 positions'});
}
if (!_.isEqual(_.last(coordinates), coordinates[0])) {
return _returnError(false, returnError, {message: 'the first and last positions of GeoJSON LinearRing are not the same'});
}
return _isPosition(coordinates);
});
if (invalid) {
return _returnError(false, returnError, {message: ''})
}
return true;
};
var _isPosition = function (coordinates, returnError) {
if (coordinates.length < 2 || !_.isNumber(coordinates[0]) || !_.isNumber(coordinates[1])) {
return _returnError(false, returnError, {message: 'invalid coordinates for GeoJSON Point'});
}
// Position is valid
return true;
};
var _isLineString = function (coordinates, returnError) {
var invalid = _.find(coordinates, function (xy) {
return !_isPosition(xy);
});
if (invalid) {
return _returnError(false, returnError, {message: 'one of the coordinates of the LineString are invalid'});
}
// GeoJSON LineString coordinates are valid
return true;
};
/**
* converts degrees to radians
*
* @param {Number} coordinates in degrees
* @returns {Number} coordinates in radians
*/
var _toRadian = function (degree) {
return decimal * Math.PI / 180;
}
/**
* returns an object with result, and error message if provided
*
* @param {Boolean} error, can also take any JavaScript object
* @param {Boolean} indicator of whether to return error message
* @param {Object} object containing error message
* @returns {Object} result and error message
*/
var _returnError = function (err, returnError, options) {
if (!returnError) {
return err;
}
if (!options) {
options = {};
}
if (options.message) {
return {result: err, message: options.message};
}
return {result: err};
};
/*

@@ -383,2 +618,3 @@ * Export functions

exports.getDistance = getDistance;
exports.complexify = complexify;
exports.complexify = complexify;
exports.isGeoJSON = isGeoJSON;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc