currently my webAPI method returns to me a long string for a GeoJSON layer that i need to parse through and separate out into mutliple variables that allows for me to create my necessary GeoJSON layer. Can i accomplish this easily through the str.split function or is a there another route that i need to take
The returned string from the webAPI looks like this:
{"type":"FeatureCollection","bbox":[1108864.9370570681,507099.9482870581,1109064.5346246646,507455.89728260477],"features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[1109035.4443840273,507308.60334444791],[1108893.4509952962,507307.23951566964],[1108893.1628068388,507337.23816090077],[1109035.1562700756,507338.60198967904],[1109035.4443840273,507308.60334444791]]]},"properties":{"twp":"01","map_num":"8.0","sec":"33.00","qtr_sec":"003","map_block":"007","parcel":"008.00","pid":"018.033.00003007008.00","gis_acres":"0.0977962","debbie_ac":"0.10c","misc":"","scan_deeds":"T:\\Images\\Hyperlinked_Deeds\\00203","latitude":"37.2227488237","longitude":"-89.5082666075","name":"O'RILEY PROPERTIES LLC","site_addre":"519 MADISON ST","shape_leng":"344.000009295","shape_area":"4260.00340015","card_ac":"0.00c 0.00d","date":"1/1/0001 12:00:00 AM","ParcelId":"203","ParcelNumber":"0180330000300700800","_hg_layer":"PARCELS"}}
The features section of the string has an array of features but for use in this example i only copied of one specific feature that. the format I'm looking to set this up in is as follows:
var geojsonObject = {
'type': 'FeatureCollection',
'crs': {
'type': 'name',
'properties': {
//'name': 'EPSG:3857'
}
},
'features': [
{
"type": "Feature", "geometry":
{
"type": "Polygon", "coordinates": [[[1109035.4443840273, 507308.60334444791],
[1108893.4509952962, 507307.23951566964],
[1108893.1628068388, 507337.23816090077],
[1109035.1562700756, 507338.60198967904],
[1109035.4443840273, 507308.60334444791]]]
, "properties": {
"twp": "01",
"map_num": "8.0",
"sec": "33.00",
"qtr_sec": "003",
"map_block": "007",
"parcel": "008.00",
"pid": "018.033.00003007008.00",
"gis_acres": "0.0977962",
"debbie_ac": "0.10c",
"misc": "",
"scan_deeds": "T:\\Images\\Hyperlinked_Deeds\\00203",
"latitude": "37.2227488237",
"longitude": "-89.5082666075",
"name": "O'RILEY PROPERTIES LLC",
"site_addre": "519 MADISON ST",
"shape_leng": "344.000009295",
"shape_area": "4260.00340015",
"card_ac": "0.00c 0.00d",
"date": "1/1/0001 12:00:00 AM",
"ParcelId": "203",
"ParcelNumber": "0180330000300700800",
"_hg_layer": "PARCELS"
}
}
}
Again the features section of this code in my example just shows one specific feature but i will actually have several features that i need to display.
is parsing through this long string the easiest route to go or do i need to restructure the string that my WebAPI actually sends back to me
Related
anybody knows how to store GEOJSON in sails js models?
i want to store features and points in sails js models.
var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Coors Field",
"amenity": "Baseball Stadium",
"popupContent": "This is where the Rockies play!"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
};
In Sails' Attributes documentation you can find that there are 5 types supported by Sail's Waterline (the underlying ORM within Sails)
string
number
boolean
json
ref
In your case, you have several objects embedded. Something like the following would probably work:
attributes: {
type: {
type: 'string',
enum: ['Feature','This','That','Other'], // not required...
},
properties: {
type: 'json'
},
geometry: {
type: 'json'
}
}
We're building a frontend project for a web app that communicates with a backend written by another team. Some of the developers work on both projects, and have better understanding of changes to the backend and response fields coming back.
Recently we had portions of frontend break as they made changes in parts of the app based on changes to the backend without updating the logic in all places. To mitigate this I want to put in place a concept of a mask/template that all response data would be curated through. That way the rest of the members on the team who're not as familiar with the backend can notice/address these bugs.
To do so, I'm considering using JSON Schema. Instead of simply validating, however, I want to parse the backend data through it (removing the fields not present in the schema). This way the developer making changes in the frontend in response to a backend change would also need to update this template, therefore triggering a test failure until all logic using this schema is updated (not just the logic he touched). I'm playing with https://www.npmjs.com/package/jsonschema, but it doesn't seem to have a way to remove excess fields, just test for them.
Within JSON Schema, I can also set additionalProperties flag. However, it has 2 problems with it:
It doesn't cause the validator to remove the fields, it simply dumps them to error array
It needs to be set individually at each nested level, therefore I need to traverse the entire JSON structure, at which point I basically end up writing my own parser/validator.
Perhaps validator is not the right tool for this, but that's all I'm finding when searching for JSON schema parsers. Can someone guide me in the right direction so that I don't reinvent the wheel? It sounds like this functionality is very similar to what a validator already does and I would rather do this processing in the same pass.
Found a validator that does what I want: https://github.com/acornejo/jjv. It has removalAdditional flag that I can set, here is a quick test I did:
var jjv = require('jjv')();
var addressSchema = {
"id": "address",
"type": "object",
"properties": {
"lines": {
"type": "array",
"items": {"type": "string"}
},
"zip": {"type": "string"},
"city": {"type": "string"},
"country": {"type": "string"}
},
"required": ["country"]
};
var schema = {
"id": "person",
"type": "object",
"properties": {
"name": {"type": "string"},
"address": {"$ref": "address"},
"votes": {"type": "integer", "minimum": 1}
}
};
var p = {
"name": "Barack Obama",
"address": {
"lines": [ "1600 Pennsylvania Avenue Northwest" ],
"zip": "DC 20500",
"city": "Washington",
"foobar": "baz",
"country": "USA"
},
"a": {
"b": 1,
"c": 2
},
"votes": "lots",
"stuff": "yes"
};
jjv.addSchema('address', addressSchema);
jjv.addSchema('schema', schema);
jjv.defaultOptions.checkRequired = true;
jjv.defaultOptions.removeAdditional = true;
console.log(jjv.validate('schema', p));
console.log(p);
And a response:
{ validation: { votes: { type: 'integer' } } }
{ name: 'Barack Obama',
address:
{ lines: [ '1600 Pennsylvania Avenue Northwest' ],
zip: 'DC 20500',
city: 'Washington',
country: 'USA' },
votes: 'lots' }
I'm trying to take a series of GeoJSON Line Strings and put them on a map. My jBuilder and Rails controller combination is not producing correctly formatted json for putting on a web map. Here's the relevant code.
overview_data.json.builder
json.type "FeatureCollection"
json.features #segments do |street|
if (street.extent_json) # only if item has a line drawn
json.type "Feature"
json.properties do
json.title "Was #{street.prevName} before #{street.dateEarliest} and now is #{street.currentName} #{street.dateLatest})"
end
json.geometry do
# json.type "LineString"
json.coordinates street.extent_json
end # json.geometry
end # if
end # json.features
overview_controller.rb
class OverviewController < ApplicationController
def index
end
def overview_data
#segments = Street.all
end
end
street.extent_json as it appears in a web form and in the database (Postgres via pgAdmin)
{"type":"LineString",
"coordinates":[[-118.25712423772116,34.01007010760971],
[-118.25649456380442,34.01016443793837],
[-118.25584971702219,34.01016443793837],
[-118.25427932544667,34.0102021700405],
[-118.25213995141625,34.010227324765935]]}
Output as seen in http://localhost:3000/overview/overview_data.json. At present there are about ten items that have extent_json. Below are the first few:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"title": "Was 10th St. before 1903 and now is part of E. 9th Place (21). 1908)"
},
"geometry": {
"coordinates": "{\"type\":\"LineString\",\"coordinates\":[[-118.24982816353442,34.035546195508864],[-118.25104052200915,34.03663976724366]]}"
}
},
{
"type": "Feature",
"properties": {
"title": "Was 37th St before 1903 and now is part of E. 40th Place 1928)"
},
"geometry": {
"coordinates": "{\"type\":\"LineString\",\"coordinates\":[[-118.25712423772116,34.01007010760971],[-118.25649456380442,34.01016443793837],[-118.25584971702219,34.01016443793837],[-118.25427932544667,34.0102021700405],[-118.25213995141625,34.010227324765935]]}"
}
},
{
"type": "Feature",
"properties": {
"title": "Was Brook before 1903 and now is part of S. Toluca St. (26). and second block south gone 1908)"
},
"geometry": {
"coordinates": "{\"type\":\"LineString\",\"coordinates\":[[-118.25862396508458,34.06087254304104],[-118.25933206826451,34.05994816216629]]}"
}
},
{
"type": "Feature",
"properties": {
"title": "Was Auto Pl before 1928 and now is Commonwealth Pl and a portion abandoned 1930)"
},
"geometry": {
"coordinates": "{\"type\":\"LineString\",\"coordinates\":[[-118.28558737412096,34.07543021182353],[-118.28369373455645,34.07646106299854]]}"
}
},
{
"type": "Feature",
"properties": {
"title": "Was 3rd St before 1921 and now is Miramar St. One block abandoned )"
},
"geometry": {
"coordinates": "{\"type\":\"LineString\",\"coordinates\":[[-118.26117539280003,34.05901974362122],[-118.2593849946753,34.05823410691563],[-118.25815599257271,34.05768101430694],[-118.25759459655055,34.05717191451128],[-118.25663111959356,34.05654339202722]]}"
}
},
{
"type": "Feature",
"properties": {
"title": "Was Gregory Way before and now is Gregory Way 2017)"
},
"geometry": {
"coordinates": "{\"type\":\"LineString\",\"coordinates\":[[-118.37295765057208,34.06188579510917],[-118.37272698059681,34.06172580874592],[-118.37264114990832,34.06161026285129],[-118.3725660480559,34.06146805230318],[-118.37253386154772,34.061414723286084],[-118.37249631062151,34.06118363049104]]}"
}
},
The problem is the added "{\"type\":\"LineString\",\"coordinates\" and closing }". Otherwise I think it's OK.
In the jBuilder I originally had json.type "LineString" in the json.geometry do loop and it's even worse adding: "geometry":{"type":"LineString","coordinates":"{\"type\":\"LineString\",\"coordinates\".
As Зелёный pointed out json.coordinates JSON.parse(street.extent_json) replacing similar line was needed. As he also pointed out I must have had some malformed json inputs which I did. Once that was cleaned up everything is working.
He also pointed out "in jbuilder template all things must be in plain Ruby, but you pass a json string(which comes from database) as result Rails tried to convert json string to json again."
But output still has an error, here's the first item:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"title": "Was 10th St. before 1903 and now is part of E. 9th Place (21). 1908)"
},
"geometry": {
"coordinates": {
"type": "LineString",
"coordinates": [
[
-118.24982816353442,
34.035546195508864
],
[
-118.25104052200915,
34.03663976724366
]
]
}
}
},
An extra {
"coordinates": after geometry.
The problem is in extent_json method, it returns an object as json string. To resolve your issue, avoid the double call to_json.
To restate the problem: take a series of GeoJSONs from a database and use jBuilder to compile all the items that meet a certain criteria into a GeoJSON (for use in a Mapbox/Leaflet web map). https://stackoverflow.com/users/2057388/Зелёный provided the answer offline, but I want to document it to make sure I understand it and help anyone else with a similar problem. It helps to consider the jsons as hashes and that jbuilder is making another hash.
The input has two keys: type and coordinates.
The output has keys of type, properties, and geometry.
The properties value is a key title;
the geometry values are two keys type and coordinates. So overview_data.json.builder becomes:
extent = JSON.parse(street.extent_json) # the GeoJSON
json.type "Feature"
json.properties do
json.title h("Was #{street.prevName} before #{street.dateEarliest} and now is #{street.currentName} #{street.dateLatest}.")
end
json.geometry do
json.type "LineString"
json.coordinates extent["coordinates"]
end
Looks straightforward once it's laid out. Except for other key points. One was parsing extent_json to convert the string to a hash object. Then coordinates are extracted from that hash to put into the output json.
I'm trying to display bicycle relations which I downloaded from geofabrik, converted with osmconvert, filtered with osmfilter and converted to geojson. At the moment Leaflet displays line strings and nodes correctly on the map. The problem is with data from relations that are included in the file. Here is a part of my GeoJson file (I won't include whole file because it's just too big):
var rower = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"id": "way/27149688",
"properties": {
"type": "way",
"id": "27149688",
"tags": {
"agricultural": "no",
"bicycle": "yes",
"highway": "residential",
"maxweightrating:hgv": "24",
"maxweightrating:hgv:condtitional": "none # marked",
"name": "Mikołaja Reja",
"source:maxweightrating:hgv": "PL:sign_B-5-note"
},
"relations": [{
"role": "",
"rel": "4046118",
"reltags": {
"colour": "blue",
"description": "Leśna trasa rowerowa, preferowany rower górski / Forest track, Mountain Bike preferred",
"lcn_ref": "niebieski",
"name": "Szlak Trójmiejski",
"network": "rcn",
"route": "bicycle",
"type": "route"
}
}],
"meta": {
"timestamp": "2014-04-17T11:58:45Z",
"version": "20",
"changeset": "21747999",
"user": "wojtas82",
"uid": "729745"
},
"tainted": true
},
"geometry": {
"type": "LineString",
"coordinates": [[
18.5024141,
54.4354139
],[
18.503622,
54.4353485
],[
18.5053714,
54.4352858
]]
}
}]
};
As you can see relations are in square brackets. I wish to display different colours of tracks depending on relations>reltags>colour tag. Here is my main html file (actually the party that doesn't work):
var rower2 = L.geoJson(rower, {
style: function (feature) {
switch (feature.properties.relations) {
case 'blue':
return {color: "#ff0000"};
case 'red':
return {color: "#0000ff"};
}
}
}).addTo(map);
I tried to modify this part (feature.properties.relations) to (feature.properties.relations.reltags.colour) but it doesn't work. Is there any way to fix this problem?
This isn't working because feature.properties.relations is an array (hence the surrounding brackets) containing objects. To access the objects stored in that array you can use array notation like this: feature.properties.relations[0] for the first object in the array, feature.properties.relations[1] for the second object in the array and so forth. So if you want to access the colour property of the reltags object in the first relation object in the array you should use feature.properties.relations[0].reltags.colour
var rower2 = L.geoJson(rower, {
style: function (feature) {
switch (feature.properties.relations[0].reltags.colour) {
case 'blue':
return {color: "#ff0000"};
case 'red':
return {color: "#0000ff"};
}
}
}).addTo(map);
But my guess is that you're gonna be running into trouble because OSM did use an array for relations with a purpose. My guess is that there can be multiple relations for a feature, and thus it could have multiple colors.
Here's a working example on Plunker: http://plnkr.co/edit/EjCCsb?p=preview
PS. I'm wondering why you're returning '#FF0000' when the case is blue, because that's the code for red, same thing with case red, you're returning '#0000FF' which is the code for blue. Other than that the code is working fine when you use feature.properties.relations[0].reltags.colour as you can see in the example i supplied.
Previously I was using a json file with the following format:
[{"lat":43.788458853157117,"lng":-79.282781549043008,"category":"volunteer","name":"Rita","url":"", "description":"xxx is a member of 13"},{"lat":43.7,"lng":-79.4,"category":"organization","name":"TCAN","url":"http://tcan.ca","description":"Lorem ipsum"}]
Now I am attempting to generate the json file from a Drupal site and am getting the following structure. How can I reference the lowest level fields. I have looked at examples using d3.net but have not found any that apply.
{
"organizations": [
{
"member": {
"field_category": "organization",
"body": "A network of organizations in Toronto devoted to climate change mitigation and adaptation.",
"URL": "xxx.ca",
"title": "Toronto Climate Action Network",
"field_lat": 43.7,
"field_long": -79.4
}
},
{
"member": {
"field_category": "abc",
"body": "xxx.",
"URL": "",
"title": "yyy",
"field_lat": 43.7,
"field_long": -79.28
}
}
]
}
Assuming that your data is stored in the variable data:
var bottom = data.organizations.map(function(d) { return d.member; });