pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/universalbit-dev/CityGenerator/commit/a61eb509778c033f0159fb5e13c5e4add5ae1587

crossorigen="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-94620c216484da1f.css" /> Add GeoJSON parsing functionality · universalbit-dev/CityGenerator@a61eb50 · GitHub
Skip to content

Commit a61eb50

Browse files
Add GeoJSON parsing functionality
1 parent a187d6d commit a61eb50

File tree

1 file changed

+382
-0
lines changed

1 file changed

+382
-0
lines changed

src/js/geojson.js

Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
(function(GeoJSON) {
2+
GeoJSON.version = '0.4.1';
3+
4+
// Allow user to specify default parameters
5+
GeoJSON.defaults = {
6+
doThrows: {
7+
invalidGeometry: false
8+
},
9+
removeInvalidGeometries: false
10+
};
11+
12+
function InvalidGeometryError() {
13+
var args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
14+
var item = args.shift();
15+
var params = args.shift();
16+
17+
Error.apply(this, args);
18+
this.message = this.message || "Invalid Geometry: " + 'item: ' + JSON.stringify(item) + ', params: ' + JSON.stringify(params);
19+
}
20+
21+
InvalidGeometryError.prototype = Error;
22+
23+
24+
GeoJSON.errors = {
25+
InvalidGeometryError: InvalidGeometryError
26+
};
27+
28+
//exposing so this can be overriden maybe by geojson-validation or the like
29+
GeoJSON.isGeometryValid = function(geometry){
30+
if(!geometry || !Object.keys(geometry).length)
31+
return false;
32+
33+
return !!geometry.type && !!geometry.coordinates && Array.isArray(geometry.coordinates) && !!geometry.coordinates.length;
34+
};
35+
36+
// The one and only public function.
37+
// Converts an array of objects into a GeoJSON feature collection
38+
GeoJSON.parse = function(objects, params, callback) {
39+
var geojson,
40+
settings = applyDefaults(params, this.defaults),
41+
propFunc;
42+
43+
geomAttrs.length = 0; // Reset the list of geometry fields
44+
setGeom(settings);
45+
propFunc = getPropFunction(settings);
46+
47+
if (Array.isArray(objects)) {
48+
geojson = {"type": "FeatureCollection", "features": []};
49+
objects.forEach(function(item){
50+
var feature = getFeature({item:item, params: settings, propFunc:propFunc});
51+
if (settings.removeInvalidGeometries !== true || GeoJSON.isGeometryValid(feature.geometry)) {
52+
geojson.features.push(feature);
53+
}
54+
});
55+
addOptionals(geojson, settings);
56+
} else {
57+
geojson = getFeature({item:objects, params: settings, propFunc:propFunc});
58+
addOptionals(geojson, settings);
59+
}
60+
61+
if (callback && typeof callback === 'function') {
62+
callback(geojson);
63+
} else {
64+
return geojson;
65+
}
66+
};
67+
68+
// Helper functions
69+
var geoms = ['Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon', 'GeoJSON'],
70+
geomAttrs = [];
71+
72+
// Adds default settings to user-specified params
73+
// Does not overwrite any settings--only adds defaults
74+
// the the user did not specify
75+
function applyDefaults(params, defaults) {
76+
var settings = params || {};
77+
78+
for(var setting in defaults) {
79+
if(defaults.hasOwnProperty(setting) && !settings[setting]) {
80+
settings[setting] = defaults[setting];
81+
}
82+
}
83+
84+
return settings;
85+
}
86+
87+
// Adds the optional GeoJSON properties crs and bbox
88+
// if they have been specified
89+
function addOptionals(geojson, settings){
90+
if(settings.crs && checkCRS(settings.crs)) {
91+
if(settings.isPostgres)
92+
geojson.geometry.crs = settings.crs;
93+
else
94+
geojson.crs = settings.crs;
95+
}
96+
if (settings.bbox) {
97+
geojson.bbox = settings.bbox;
98+
}
99+
if (settings.extraGlobal) {
100+
geojson.properties = {};
101+
for (var key in settings.extraGlobal) {
102+
geojson.properties[key] = settings.extraGlobal[key];
103+
}
104+
}
105+
}
106+
107+
// Verify that the structure of CRS object is valid
108+
function checkCRS(crs) {
109+
if (crs.type === 'name') {
110+
if (crs.properties && crs.properties.name) {
111+
return true;
112+
} else {
113+
throw new Error('Invalid CRS. Properties must contain "name" key');
114+
}
115+
} else if (crs.type === 'link') {
116+
if (crs.properties && crs.properties.href && crs.properties.type) {
117+
return true;
118+
} else {
119+
throw new Error('Invalid CRS. Properties must contain "href" and "type" key');
120+
}
121+
} else {
122+
throw new Error('Invald CRS. Type attribute must be "name" or "link"');
123+
}
124+
}
125+
126+
// Moves the user-specified geometry parameters
127+
// under the `geom` key in param for easier access
128+
function setGeom(params) {
129+
params.geom = {};
130+
131+
for(var param in params) {
132+
if(params.hasOwnProperty(param) && geoms.indexOf(param) !== -1){
133+
params.geom[param] = params[param];
134+
delete params[param];
135+
}
136+
}
137+
138+
setGeomAttrList(params.geom);
139+
}
140+
141+
// Adds fields which contain geometry data
142+
// to geomAttrs. This list is used when adding
143+
// properties to the features so that no geometry
144+
// fields are added the properties key
145+
function setGeomAttrList(params) {
146+
for(var param in params) {
147+
if(params.hasOwnProperty(param)) {
148+
if(typeof params[param] === 'string') {
149+
geomAttrs.push(params[param]);
150+
} else if (typeof params[param] === 'object') { // Array of coordinates for Point
151+
geomAttrs.push(params[param][0]);
152+
geomAttrs.push(params[param][1]);
153+
}
154+
}
155+
}
156+
157+
if(geomAttrs.length === 0) { throw new Error('No geometry attributes specified'); }
158+
}
159+
160+
// Creates a feature object to be added
161+
// to the GeoJSON features array
162+
function getFeature(args) {
163+
var item = args.item,
164+
params = args.params,
165+
propFunc = args.propFunc;
166+
167+
var feature = { "type": "Feature" };
168+
169+
feature.geometry = buildGeom(item, params);
170+
feature.properties = propFunc.call(item);
171+
172+
return feature;
173+
}
174+
175+
function isNested(val){
176+
return (/^.+\..+$/.test(val));
177+
}
178+
179+
// Assembles the `geometry` property
180+
// for the feature output
181+
function buildGeom(item, params) {
182+
var geom,
183+
attr;
184+
185+
for(var gtype in params.geom) {
186+
var val = params.geom[gtype];
187+
var coordinates = [];
188+
var itemClone;
189+
var paths;
190+
// If we've already found a matching geometry, stop the loop.
191+
if (geom !== undefined && geom !== false) {
192+
break;
193+
}
194+
195+
// Geometry parameter specified as: {Point: 'coords'}
196+
if(typeof val === 'string' && item.hasOwnProperty(val)) {
197+
if(gtype === 'GeoJSON') {
198+
geom = item[val];
199+
} else {
200+
geom = {
201+
type: gtype,
202+
coordinates: item[val]
203+
};
204+
}
205+
}
206+
207+
// Geometry parameter specified as: {Point: 'geo.coords'}
208+
else if(typeof val === 'string' && isNested(val)) {
209+
geom = undefined;
210+
paths = val.split('.');
211+
itemClone = item;
212+
for (var m = 0; m < paths.length; m++) {
213+
if (itemClone == undefined || !itemClone.hasOwnProperty(paths[m])) {
214+
m = paths.length;
215+
geom = false;
216+
} else {
217+
itemClone = itemClone[paths[m]]; // Iterate deeper into the object
218+
}
219+
}
220+
if (geom !== false) {
221+
geom = {
222+
type: gtype,
223+
coordinates: itemClone
224+
};
225+
}
226+
}
227+
228+
/* Handle things like:
229+
Polygon: {
230+
northeast: ['lat', 'lng'],
231+
southwest: ['lat', 'lng']
232+
}
233+
*/
234+
else if(typeof val === 'object' && !Array.isArray(val)) {
235+
/*jshint loopfunc: true */
236+
var points = Object.keys(val).map(function(key){
237+
var order = val[key];
238+
var newItem = item[key];
239+
return buildGeom(newItem, {geom:{ Point: order}});
240+
});
241+
geom = {
242+
type: gtype,
243+
/*jshint loopfunc: true */
244+
coordinates: [].concat(points.map(function(p){
245+
return p.coordinates;
246+
}))
247+
};
248+
}
249+
250+
// Geometry parameter specified as: {Point: ['lat', 'lng', 'alt']}
251+
else if(Array.isArray(val) && item.hasOwnProperty(val[0]) && item.hasOwnProperty(val[1]) && item.hasOwnProperty(val[2])){
252+
geom = {
253+
type: gtype,
254+
coordinates: [ Number(item[val[1]]), Number(item[val[0]]), Number(item[val[2]]) ]
255+
};
256+
}
257+
258+
// Geometry parameter specified as: {Point: ['lat', 'lng']}
259+
else if(Array.isArray(val) && item.hasOwnProperty(val[0]) && item.hasOwnProperty(val[1])){
260+
geom = {
261+
type: gtype,
262+
coordinates: [Number(item[val[1]]), Number(item[val[0]])]
263+
};
264+
}
265+
266+
// Geometry parameter specified as: {Point: ['container.lat', 'container.lng', 'container.alt']}
267+
else if(Array.isArray(val) && isNested(val[0]) && isNested(val[1]) && isNested(val[2])){
268+
geom = undefined;
269+
for (var i = 0; i < val.length; i++) { // i.e. 0 and 1
270+
paths = val[i].split('.');
271+
itemClone = item;
272+
for (var j = 0; j < paths.length; j++) {
273+
if (itemClone == undefined || !itemClone.hasOwnProperty(paths[j])) {
274+
i = val.length;
275+
j = paths.length;
276+
geom = false;
277+
} else {
278+
itemClone = itemClone[paths[j]]; // Iterate deeper into the object
279+
}
280+
}
281+
coordinates[i] = itemClone;
282+
}
283+
if (geom !== false) {
284+
geom = {
285+
type: gtype,
286+
coordinates: [Number(coordinates[1]), Number(coordinates[0]), Number(coordinates[2])]
287+
};
288+
}
289+
}
290+
291+
// Geometry parameter specified as: {Point: ['container.lat', 'container.lng']}
292+
else if(Array.isArray(val) && isNested(val[0]) && isNested(val[1])){
293+
for (var k = 0; k < val.length; k++) { // i.e. 0 and 1
294+
paths = val[k].split('.');
295+
itemClone = item;
296+
for (var l = 0; l < paths.length; l++) {
297+
if (itemClone == undefined || !itemClone.hasOwnProperty(paths[l])) {
298+
k = val.length;
299+
l = paths.length;
300+
geom = false;
301+
} else {
302+
itemClone = itemClone[paths[l]]; // Iterate deeper into the object
303+
}
304+
}
305+
coordinates[k] = itemClone;
306+
}
307+
if (geom !== false) {
308+
geom = {
309+
type: gtype,
310+
coordinates: [Number(coordinates[1]), Number(coordinates[0])]
311+
};
312+
}
313+
}
314+
315+
// Geometry parameter specified as: {Point: [{coordinates: [lat, lng]}]}
316+
else if (Array.isArray(val) && val[0].constructor.name === 'Object' && Object.keys(val[0])[0] === 'coordinates'){
317+
geom = {
318+
type: gtype,
319+
coordinates: [Number(item.coordinates[(val[0].coordinates).indexOf('lng')]), Number(item.coordinates[(val[0].coordinates).indexOf('lat')])]
320+
};
321+
}
322+
}
323+
324+
if(params.doThrows && params.doThrows.invalidGeometry && !GeoJSON.isGeometryValid(geom)){
325+
throw new InvalidGeometryError(item, params);
326+
}
327+
328+
return geom;
329+
}
330+
331+
// Returns the function to be used to
332+
// build the properties object for each feature
333+
function getPropFunction(params) {
334+
var func;
335+
336+
if(!params.exclude && !params.include) {
337+
func = function(properties) {
338+
for(var attr in this) {
339+
if(this.hasOwnProperty(attr) && (geomAttrs.indexOf(attr) === -1)) {
340+
properties[attr] = this[attr];
341+
}
342+
}
343+
};
344+
} else if(params.include) {
345+
func = function(properties) {
346+
params.include.forEach(function(attr){
347+
properties[attr] = this[attr];
348+
}, this);
349+
};
350+
} else if(params.exclude) {
351+
func = function(properties) {
352+
for(var attr in this) {
353+
if(this.hasOwnProperty(attr) && (geomAttrs.indexOf(attr) === -1) && (params.exclude.indexOf(attr) === -1)) {
354+
properties[attr] = this[attr];
355+
}
356+
}
357+
};
358+
}
359+
360+
return function() {
361+
var properties = {};
362+
363+
func.call(this, properties);
364+
365+
if(params.extra) { addExtra(properties, params.extra); }
366+
return properties;
367+
};
368+
}
369+
370+
// Adds data contained in the `extra`
371+
// parameter if it has been specified
372+
function addExtra(properties, extra) {
373+
for(var key in extra){
374+
if(extra.hasOwnProperty(key)) {
375+
properties[key] = extra[key];
376+
}
377+
}
378+
379+
return properties;
380+
}
381+
382+
}(typeof module == 'object' ? module.exports : window.GeoJSON = {}));

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy