esri-to-geojson
Advanced tools
Comparing version 1.0.1 to 1.0.2
341
index.js
@@ -8,205 +8,250 @@ 'use strict'; | ||
/** | ||
* Converts csv to geojson | ||
* | ||
* @param {array} csv - csv file parsed using https://www.npmjs.com/package/csv | ||
* @returns {object} geojson - geojson object | ||
* */ | ||
* Converts csv to geojson | ||
* | ||
* @param {array} csv - csv file parsed using https://www.npmjs.com/package/csv | ||
* @returns {object} geojson - geojson object | ||
* */ | ||
toGeoJSON.fromCSV = function (csv) { | ||
var geojson = { type: 'FeatureCollection', features: [] }; | ||
var latFieldIndex = null; | ||
var lonFieldIndex = null; | ||
var feature = void 0, | ||
headers = void 0; | ||
var geojson = { type: 'FeatureCollection' }; | ||
var fieldNames = csvFieldNames(csv[0]); | ||
var features = csv.slice(1); | ||
geojson.features = _.map(features, function (feat, key) { | ||
var feature = { type: 'Feature', id: key }; | ||
feature.properties = constructProps(fieldNames, feat); | ||
feature.properties.OBJECTID = key; | ||
feature.geometry = convertCSVGeom(fieldNames, feat); | ||
return feature; | ||
}); | ||
return geojson; | ||
}; | ||
csv.forEach(function (row, i) { | ||
if (i === 0) { | ||
headers = row; | ||
/** | ||
* Parse array of field names and sanitize them | ||
* | ||
* @param {array} inFields - array of field names | ||
* @returns {array} fieldNames - array of sanitized field Names | ||
*/ | ||
// Search a whitelist of lat/longs to try to build a geometry | ||
function csvFieldNames(inFields) { | ||
var fieldNames = _.map(inFields, function (field) { | ||
return convertFieldName(field); | ||
}); | ||
return fieldNames; | ||
} | ||
headers.forEach(function (h, i) { | ||
if (['lat', 'latitude', 'latitude_deg', 'y'].indexOf(h.trim().toLowerCase()) > -1) { | ||
latFieldIndex = i + ''; | ||
} else if (['lon', 'longitude', 'longitude_deg', 'x'].indexOf(h.trim().toLowerCase()) > -1) { | ||
lonFieldIndex = i + ''; | ||
} | ||
}); | ||
} else { | ||
feature = { type: 'Feature', id: i, properties: {}, geometry: null }; | ||
/** | ||
* Convert CSV geom to geojson | ||
* | ||
* @param {array} fieldNames - array of field names | ||
* @param {array} feature - individual feature | ||
* @returns {object} geometry - geometry object | ||
*/ | ||
row.forEach(function (col, j) { | ||
var colNum = col.replace(/,/g, ''); | ||
feature.properties[headers[j]] = !isNaN(colNum) ? parseFloat(colNum) : col; | ||
}); | ||
function convertCSVGeom(columns, row) { | ||
var geometry = _.reduce(columns, function (tempGeom, colName, i) { | ||
if (isLongitudeField(colName)) tempGeom.coordinates[0] = parseFloat(row[i]);else if (isLatitudeField(colName)) tempGeom.coordinates[1] = parseFloat(row[i]); | ||
return tempGeom; | ||
}, { type: 'Point', coordinates: [null, null] }); | ||
return validGeometry(geometry) ? geometry : null; | ||
} | ||
// add an object to csv data | ||
feature.properties.OBJECTID = i; | ||
/** | ||
* Check to see if lat is present | ||
* | ||
* @param {string} fieldName - fieldName to Check | ||
* @returns {boolean} present - whether or not lat / lon options are present | ||
*/ | ||
if (latFieldIndex && lonFieldIndex) { | ||
feature.geometry = { | ||
type: 'Point', | ||
coordinates: [parseFloat(row[parseInt(lonFieldIndex, 10)]), parseFloat(row[parseInt(latFieldIndex, 10)])] | ||
}; | ||
} | ||
geojson.features.push(feature); | ||
} | ||
}); | ||
function isLatitudeField(fieldName) { | ||
return _.includes(['lat', 'latitude', 'latitude_deg', 'y'], fieldName.trim().toLowerCase()); | ||
} | ||
return geojson ? geojson : null; | ||
}; | ||
/** | ||
* Check to see if lon is present | ||
* | ||
* @param {string} fieldName - fieldName to Check | ||
* @returns {boolean} present - whether or not lat / lon options are present | ||
*/ | ||
function isLongitudeField(fieldName) { | ||
return _.includes(['lon', 'longitude', 'longitude_deg', 'x'], fieldName.trim().toLowerCase()); | ||
} | ||
/** | ||
* Converts esri json to GeoJSON | ||
* | ||
* @param {object} esriJSON - The entire esri json response | ||
* @param {object} options - The fields object returned in esri json | ||
* @returns {object} geojson - geojson object | ||
* | ||
* */ | ||
* Check to see if geometry object is valid | ||
* | ||
* @param {object} geometry - built geometry object | ||
* @return {boolean} validGeom - whether or not geom is valid | ||
*/ | ||
function validGeometry(geometry) { | ||
return geometry.coordinates.length === 2 && geometry.coordinates[0] && geometry.coordinates[1] ? true : false; | ||
} | ||
/** | ||
* Covert fields into properties object | ||
* @param {array} fieldNames - array of field names | ||
* @param {array} feature - individual feature | ||
* @returns {object} properties - property object | ||
*/ | ||
function constructProps(fieldNames, feature) { | ||
var properties = _.reduce(fieldNames, function (tempProps, fieldName, key) { | ||
tempProps[fieldName] = !isNaN(feature[key]) ? parseFloat(feature[key]) : feature[key]; | ||
return tempProps; | ||
}, {}); | ||
return properties; | ||
} | ||
/** | ||
* Converts esri json to GeoJSON | ||
* | ||
* @param {object} esriJSON - The entire esri json response | ||
* @param {object} options - The fields object returned in esri json | ||
* @returns {object} geojson - geojson object | ||
* | ||
* */ | ||
toGeoJSON.fromEsri = function (esriJSON, options) { | ||
if (!options) options = {}; | ||
if (!options.fields) options.fields = esriJSON.fields; | ||
if (!options) options = {}; | ||
if (!options.fields) options.fields = esriJSON.fields; | ||
var geojson = { type: 'FeatureCollection' }; | ||
var fields = convertFields(options.fields); | ||
var geojson = { type: 'FeatureCollection' }; | ||
var fields = convertFields(options.fields); | ||
geojson.features = _.map(esriJSON.features, function (feature) { | ||
return transformFeature(feature, fields); | ||
}); | ||
geojson.features = _.map(esriJSON.features, function (feature) { | ||
return transformFeature(feature, fields); | ||
}); | ||
return geojson ? geojson : null; | ||
return geojson; | ||
}; | ||
/** | ||
* Converts a set of fields to have names that work well in JS | ||
* | ||
* @params {object} inFields - the original fields object from the esri json | ||
* @returns {object} fields - converted fields | ||
* @private | ||
* */ | ||
* Converts a set of fields to have names that work well in JS | ||
* | ||
* @params {object} inFields - the original fields object from the esri json | ||
* @returns {object} fields - converted fields | ||
* @private | ||
* */ | ||
function convertFields(infields) { | ||
var fields = {}; | ||
var fields = {}; | ||
_.each(infields, function (field) { | ||
field.outName = convertFieldName(field.name); | ||
fields[field.name] = field; | ||
}); | ||
return fields; | ||
_.each(infields, function (field) { | ||
field.outName = convertFieldName(field.name); | ||
fields[field.name] = field; | ||
}); | ||
return fields; | ||
} | ||
/** | ||
* Converts a single field name to a legal javascript object key | ||
* | ||
* @params {string} name - the original field name | ||
* @returns {string} outName - a cleansed field name | ||
* @private | ||
* */ | ||
* Converts a single field name to a legal javascript object key | ||
* | ||
* @params {string} name - the original field name | ||
* @returns {string} outName - a cleansed field name | ||
* @private | ||
* */ | ||
function convertFieldName(name) { | ||
var regex = new RegExp(/\.|\(|\)/g); | ||
return name.replace(regex, ''); | ||
var regex = new RegExp(/\.|\(|\)/g); | ||
return name.replace(regex, '').replace(/\s/g, '_'); | ||
} | ||
/** | ||
* Converts a single feature from esri json to geojson | ||
* | ||
* @param {object} feature - a single esri feature | ||
* @param {object} fields - the fields object from the service | ||
* @returns {object} feature - a geojson feature | ||
* @private | ||
* */ | ||
* Converts a single feature from esri json to geojson | ||
* | ||
* @param {object} feature - a single esri feature | ||
* @param {object} fields - the fields object from the service | ||
* @returns {object} feature - a geojson feature | ||
* @private | ||
* */ | ||
function transformFeature(feature, fields) { | ||
var attributes = {}; | ||
var attributes = {}; | ||
// first transform each of the features to the converted field name and transformed value | ||
if (feature.attributes && Object.keys(feature.attributes)) { | ||
_.each(Object.keys(feature.attributes), function (name) { | ||
var attr = {}; | ||
attr[name] = feature.attributes[name]; | ||
try { | ||
attributes[fields[name].outName] = convertAttribute(attr, fields[name]); | ||
} catch (e) { | ||
console.error('Field was missing from attribute'); | ||
} | ||
}); | ||
} | ||
// first transform each of the features to the converted field name and transformed value | ||
if (feature.attributes && Object.keys(feature.attributes)) { | ||
_.each(Object.keys(feature.attributes), function (name) { | ||
var attr = {}; | ||
attr[name] = feature.attributes[name]; | ||
try { | ||
attributes[fields[name].outName] = convertAttribute(attr, fields[name]); | ||
} catch (e) { | ||
console.error('Field was missing from attribute'); | ||
} | ||
}); | ||
} | ||
return { | ||
type: 'Feature', | ||
properties: attributes, | ||
geometry: parseGeometry(feature.geometry) | ||
}; | ||
return { | ||
type: 'Feature', | ||
properties: attributes, | ||
geometry: parseGeometry(feature.geometry) | ||
}; | ||
} | ||
/** | ||
* Decodes an attributes CVD and standardizes any date fields | ||
* | ||
* @params {object} attribute - a single esri feature attribute | ||
* @params {object} field - the field metadata describing that attribute | ||
* @returns {object} outAttribute - the converted attribute | ||
* @private | ||
* */ | ||
* Decodes an attributes CVD and standardizes any date fields | ||
* | ||
* @params {object} attribute - a single esri feature attribute | ||
* @params {object} field - the field metadata describing that attribute | ||
* @returns {object} outAttribute - the converted attribute | ||
* @private | ||
* */ | ||
function convertAttribute(attribute, field) { | ||
var inValue = attribute[field.name]; | ||
var value = void 0; | ||
var inValue = attribute[field.name]; | ||
var value = void 0; | ||
if (inValue === null) return inValue; | ||
if (inValue === null) return inValue; | ||
if (field.domain && field.domain.type === 'codedValue') { | ||
value = cvd(inValue, field); | ||
} else if (field.type === 'esriFieldTypeDate') { | ||
try { | ||
value = new Date(inValue).toISOString(); | ||
} catch (e) { | ||
value = inValue; | ||
} | ||
} else { | ||
value = inValue; | ||
if (field.domain && field.domain.type === 'codedValue') { | ||
value = cvd(inValue, field); | ||
} else if (field.type === 'esriFieldTypeDate') { | ||
try { | ||
value = new Date(inValue).toISOString(); | ||
} catch (e) { | ||
value = inValue; | ||
} | ||
return value; | ||
} else { | ||
value = inValue; | ||
} | ||
return value; | ||
} | ||
/** | ||
* Looks up a value from a coded domain | ||
* | ||
* @params {integer} value - The original field value | ||
* @params {object} field - metadata describing the attribute field | ||
* @returns {string/integerfloat} - The decoded field value | ||
* */ | ||
* Looks up a value from a coded domain | ||
* | ||
* @params {integer} value - The original field value | ||
* @params {object} field - metadata describing the attribute field | ||
* @returns {string/integerfloat} - The decoded field value | ||
* */ | ||
function cvd(value, field) { | ||
var domain = _.find(field.domain.codedValues, function (d) { | ||
return value === d.code; | ||
}); | ||
return domain ? domain.name : value; | ||
var domain = _.find(field.domain.codedValues, function (d) { | ||
return value === d.code; | ||
}); | ||
return domain ? domain.name : value; | ||
} | ||
/** | ||
* Convert an esri geometry to a geojson geometry | ||
* | ||
* @param {object} geometry - an esri geometry object | ||
* @return {object} geojson geometry | ||
* @private | ||
* */ | ||
* Convert an esri geometry to a geojson geometry | ||
* | ||
* @param {object} geometry - an esri geometry object | ||
* @return {object} geojson geometry | ||
* @private | ||
* */ | ||
function parseGeometry(geometry) { | ||
try { | ||
var parsed = geometry ? arcgisToGeoJSON(geometry) : null; | ||
if (parsed && parsed.type && parsed.coordinates) return parsed;else { | ||
return null; | ||
} | ||
return parsed; | ||
} catch (e) { | ||
console.error(e); | ||
return null; | ||
try { | ||
var parsed = geometry ? arcgisToGeoJSON(geometry) : null; | ||
if (parsed && parsed.type && parsed.coordinates) return parsed;else { | ||
return null; | ||
} | ||
} catch (e) { | ||
console.error(e); | ||
return null; | ||
} | ||
} | ||
module.exports = toGeoJSON; |
{ | ||
"name": "esri-to-geojson", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Convert Esri JSON/CSV to GeoJSON", | ||
"bugs": { | ||
"url": "https://github.com/koopjs/esri-to-geojson/issues" | ||
}, | ||
"main": "index.js", | ||
@@ -9,2 +12,6 @@ "directories": { | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/koopjs/esri-to-geojson.git" | ||
}, | ||
"scripts": { | ||
@@ -14,3 +21,10 @@ "test": "standard src/ && npm run compile && tape test/*.js | tap-spec", | ||
}, | ||
"keywords": [], | ||
"homepage": "https://github.com/koopjs/esri-to-geojson", | ||
"keywords": [ | ||
"koop", | ||
"geojson", | ||
"csv", | ||
"esri json", | ||
"conversion" | ||
], | ||
"author": "Ben Stoltz <bstoltz@esri.com>", | ||
@@ -17,0 +31,0 @@ "license": "Apache-2.0", |
@@ -1,14 +0,12 @@ | ||
[![Build Status](https://travis-ci.org/koopjs/EsriToGeojson.svg?branch=master)](https://travis-ci.org/koopjs/EsriToGeojson) | ||
[![Build Status](https://travis-ci.org/koopjs/esri-to-geojson.svg?branch=master)](https://travis-ci.org/koopjs/esri-to-geojson) | ||
# GeoJSON | ||
# esri-to-geojson | ||
*Converts Esri JSON and CSV to GeoJSON format* | ||
Outside of solely translating geometry this project does make changes to | ||
fields. | ||
* decoding domains | ||
* creating x & y fields from CSVs | ||
* Translate date fields to be human readable text | ||
## Install | ||
EsriToGeojson should be installed as a dependency in a Node.js project like so: | ||
``` | ||
npm install esri-to-geojson --save | ||
``` | ||
Example: Convert Esri JSON to GeoJSON | ||
@@ -61,1 +59,36 @@ ```js | ||
``` | ||
## Set up | ||
esri-to-geojson should be installed as a dependency in a Node.js project like so: | ||
- `npm install esri-to-geojson --save` | ||
## Development | ||
### Install dependencies | ||
- `npm install` | ||
### Transpile to ES5 | ||
- `npm compile` | ||
### Test | ||
- `npm test` | ||
## API | ||
### `GeoJSON.fromEsri(esriJSON, options)` | ||
Converts Esri JSON to GeoJSON | ||
- esriJSON: the entire Esri JSON object | ||
- Options: | ||
``` javascript | ||
{ | ||
fields: array // fields object returned from esri json | ||
} | ||
``` | ||
### `GeoJSON.fromCSV(csv)` | ||
Converts CSV to GeoJSON | ||
- csv: csv file parsed using https://www.npmjs.com/package/csv |
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
21873
217
1
0
94
0