How to show values in json data - javascript

Wondered if somebody could help me with some JavaScript.
I have a json file which looks similar to the one below, although this is a cut down version of the original one which is considerably larger. I'm attempting to grab some coordinates from it and use them to outline specific areas on a google map to which I set myself up a fiddle to test with:
https://jsfiddle.net/pork1977/up8rnf6d/
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"LEVEL1_COD": 1,
"LEVEL1_NAM": "EUROPE"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
24.128105619999872,
34.858005329767494
],
[
24.128505619999856,
34.808905329767484
],
[
24.044605619999857,
34.850005329767484
],
[
24.074605619999858,
34.868605329767476
],
[
20.819105619999874,
80.719105329767487
]
]
]
]
}
},
{
"type": "Feature",
"properties": {
"LEVEL1_COD": 2,
"LEVEL1_NAM": "AFRICA"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
32.954405619999847,
-26.058594670232509
],
[
32.895205619999871,
-26.040794670232515
],
[
32.980505619999889,
-25.972794670232517
],
[
32.982705619999848,
-25.98359467023252
],
[
32.954405619999847,
-26.058594670232509
]
]
]
]
}
},
{
"type": "Feature",
"properties": {
"LEVEL1_COD": 3,
"LEVEL1_NAM": "AUSTRALASIA"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
169.185405619999841,
-52.576994670232516
],
[
169.028205619999852,
-52.559194670232515
],
[
169.000705619999877,
-52.507194670232515
],
[
169.205205619999873,
-52.441394670232512
]
]
]
]
}
},
{
"type": "Feature",
"properties": {
"LEVEL1_COD": 4,
"LEVEL1_NAM": "ASIA-TROPICAL"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
96.914105619999845,
-12.198094670232521
],
[
96.902405619999882,
-12.199994670232513
],
[
96.914705619999864,
-12.151994670232511
],
[
96.924405619999874,
-12.182794670232511
],
[
96.914105619999845,
-12.198094670232521
]
]
]
]
}
},
{
"type": "Feature",
"properties": {
"LEVEL1_COD": 5,
"LEVEL1_NAM": "SOUTHERN AMERICA"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
-67.212794380000133,
-55.893594670232517
],
[
-67.246994380000132,
-55.894994670232514
],
[
-67.41389438000013,
-55.832194670232518
],
[
-67.246994380000132,
-55.828094670232517
]
]
]
]
}
}
]
}
I'm attempting to filter some values on this. What I'm trying to do is get the "coordinates" when I specify a value for the LEVEL1_COD key in the filter.
I've managed to do this by running the below, and in this example it shows me the coordinates for EUROPE as this has it's LEVEL1_COD value set to 1. Note: the json variable here is using the full blown version of my snippet above.
var json = JSON.parse($.getJSON({'url': "https://raw.githubusercontent.com/tdwg/wgsrpd/master/geojson/level1.geojson", 'async': false}).responseText);
var coords = json.features.filter(function (el) {
return (el.properties.LEVEL1_COD == "1");
})[0].geometry.coordinates
console.log(coords);
Console.log shows me:
[ [ [ [ 24.128105619999872, 34.858005329767494 ], [
24.128505619999856, 34.808905329767484 ], [ 24.044605619999857, 34.850005329767484 ], [ 24.074605619999858, 34.868605329767476 ], [ 20.819105619999874, 80.719105329767487 ] ] ] ]
What I can't figure out, is how to change this from an 'equals' to a 'contains' type of filter.
For example, if I had a list of LEVEL1_COD values of say 1,2,5 and I wanted to filter on those values so I could see each set of coordinates, how would you go about doing that? I'd like to get the areas outlined on the map for each of these areas.
I'm sure the line which needs tweaking is:
return (el.properties.LEVEL1_COD == "1");
But after trying all sorts of things I can't get it to return more than one set. Do you need to loop through each item to do this? or is there a smarter way? Speed is somewhat important since the json files I'll be using are quite large.
Thanks
Paul

If you are looking to get more than one matching elements from the data based on the provided input(multiple values i.e., an array) Array.some can be used.
Below I've simulated few examples, hope this is what you are looking for
let data = {type:'FeatureCollection',features:[{type:'Feature',properties:{LEVEL1_COD:1,LEVEL1_NAM:'EUROPE',},geometry:{type:'MultiPolygon',coordinates:[[[[24.128105619999872,34.858005329767494],[24.128505619999856,34.808905329767484],[24.044605619999857,34.850005329767484],[24.074605619999858,34.868605329767476],[20.819105619999874,80.719105329767487],],],],},},{type:'Feature',properties:{LEVEL1_COD:2,LEVEL1_NAM:'AFRICA',},geometry:{type:'MultiPolygon',coordinates:[[[[32.954405619999847,-26.058594670232509],[32.895205619999871,-26.040794670232515],[32.980505619999889,-25.972794670232517],[32.982705619999848,-25.98359467023252],[32.954405619999847,-26.058594670232509],],],],},},{type:'Feature',properties:{LEVEL1_COD:3,LEVEL1_NAM:'AUSTRALASIA',},geometry:{type:'MultiPolygon',coordinates:[[[[169.185405619999841,-52.576994670232516],[169.028205619999852,-52.559194670232515],[169.000705619999877,-52.507194670232515],[169.205205619999873,-52.441394670232512],],],],},},{type:'Feature',properties:{LEVEL1_COD:4,LEVEL1_NAM:'ASIA-TROPICAL',},geometry:{type:'MultiPolygon',coordinates:[[[[96.914105619999845,-12.198094670232521],[96.902405619999882,-12.199994670232513],[96.914705619999864,-12.151994670232511],[96.924405619999874,-12.182794670232511],[96.914105619999845,-12.198094670232521],],],],},},{type:'Feature',properties:{LEVEL1_COD:5,LEVEL1_NAM:'SOUTHERN AMERICA',},geometry:{type:'MultiPolygon',coordinates:[[[[-67.212794380000133,-55.893594670232517],[-67.246994380000132,-55.894994670232514],[-67.41389438000013,-55.832194670232518],[-67.246994380000132,-55.828094670232517]]]]}}]};
const getFilteredData = (data, input) =>
data.features.filter(feature => {
return input.some(i => i === feature.properties.LEVEL1_COD);
});
let input = [1];
let filterdData = getFilteredData(data, input);
console.log(filterdData);
input = [1, 2, 5];
filterdData = getFilteredData(data, input);
console.log(filterdData);
input = [1, 7];
filterdData = getFilteredData(data, input);
console.log(filterdData);
.as-console-wrapper {
max-height: 100% !important;
}

It seems like you are populating your mapbox. You could use the package's filter
this.map.setFilter('YOUR_LAYER', ['==', 'LEVEL1_COD', 'YOUR_VALUE']);

Related

How to access single polygon created by geoJSON Leaflet

I added a geoJSON object to a map using. It creates around 200 polygons.
const geoJson = L.geoJSON(polygonsJSON).addTo(map);
The geoJSON object has structure:
{
"type": "FeatureCollection",
"name": "polygonsJSON",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
"type": "Feature",
"properties": {
"id": "23",
"NameSurname": "Namex Surnamex",
"r/s": "1823-1975"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
0.000165649338392,
-0.000006827196159
],
[
0.00014822202188,
-0.00002712912158
],
[
0.000138250722226,
-0.000018774789438
],
[
0.000155857701795,
0.000001347472926
],
[
0.000165649338392,
-0.000006827196159
]
]
]
]
}
},
I would like to modify (lets say change color) only one of the polygons based on its ID. How can I access it?
Thank you.

Using bringToFront() to style leaflet layers that are NOT in a layer event with ngx-leaflet

I have a multipolygon that I want to filter, put into unique layers, and set different styles to. I load the geoJson, apply general styles, and use onEachFeature to put the layers into featureGroups based on a condition. Still inside onEachFeature, I apply styles to each featureGroup. This works fine.
The problem is that the polygon strokes are overlapping, which is a common issue addressed in leaflet/svg. I know to use bringToFront to get around this issue, but I can't seem to get it to work in my ngx-leaflet angular app. When I test bringToFront inside a click event, it works. But I want the polygon styles themselves (with NO event) to be brought to the front.
Here's some example code (drawing from ngx-leaflet-tutorial-ngcli):
states.geojson (in /assets directory)
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "adm1_code": "Admin-1 scale rank", "diss_me": 2, "name": "USA-3520", "name_len": 3520 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -111.006268677999884, 31.327184550000098 ], [ -114.822108114999963, 32.500239563000022 ], [ -114.720794720599827, 32.7245646349499 ], [ -114.535858197098094, 32.738236510006914 ], [ -114.460736126870756, 32.854911313806042 ], [ -114.501727338146111, 33.019413268207757 ], [ -114.696746868872879, 33.089359557497573 ], [ -114.7235046809962, 33.32124432236759 ], [ -114.726898235864894, 33.411478697383984 ], [ -114.532611127401594, 33.568558775367194 ], [ -114.515936321603931, 33.963627135284071 ], [ -114.119061321722597, 34.293216978480757 ], [ -114.368963665640649, 34.471537291312927 ], [ -114.616961713112516, 34.879300963268804 ], [ -114.638861126739585, 35.123539243841037 ], [ -114.571942181186671, 35.212552915984247 ], [ -114.741278119289746, 36.013627134784429 ], [ -114.707147260337763, 36.108841977775057 ], [ -114.554779095678725, 36.16052654906099 ], [ -114.123895306323277, 36.045853697290283 ], [ -114.042010541153502, 36.219779478340229 ], [ -114.040203900289725, 37.003129088436651 ], [ -109.046624798995254, 36.999808775254735 ], [ -109.047430462999856, 31.327391256000041 ], [ -111.006268677999884, 31.327184550000098 ] ] ] } },
{ "type": "Feature", "properties": { "adm1_code": "Admin-1 scale rank", "diss_me": 2, "name": "USA-3524", "name_len": 3524 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -108.137503214999924, 31.777544657000064 ], [ -108.215121216999904, 31.777751364000025 ], [ -108.214811157999918, 31.327442932000068 ], [ -109.047430462999856, 31.327391256000041 ], [ -109.046624798995254, 36.999808775254735 ], [ -103.000799603418955, 36.999808775254735 ], [ -103.065594524767505, 32.00168865790522 ], [ -106.66217655600326, 32.000297056863644 ], [ -106.506052409999938, 31.770258281000068 ], [ -108.137503214999924, 31.777544657000064 ] ] ] } },
{ "type": "Feature", "properties": { "adm1_code": "Admin-1 scale rank", "diss_me": 2, "name": "USA-3526", "name_len": 3526 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -111.05023808032314, 41.999833189050435 ], [ -111.049920696982554, 40.999833189250239 ], [ -109.046331829550297, 40.999833189250239 ], [ -109.046624798995254, 36.999808775254735 ], [ -114.040203900289725, 37.003129088436651 ], [ -114.042547649554365, 42.000077329804924 ], [ -111.05023808032314, 41.999833189050435 ] ] ] } },
{ "type": "Feature", "properties": { "adm1_code": "Admin-1 scale rank", "diss_me": 2, "name": "USA-3522", "name_len": 3522 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -109.046331829550297, 40.999833189250239 ], [ -102.051800580432428, 40.99958904939507 ], [ -102.039569135107456, 36.999808775254735 ], [ -109.046624798995254, 36.999808775254735 ], [ -109.046331829550297, 40.999833189250239 ] ] ] } }
]
}
app.component.html
<div class="map"
leaflet
[leafletFitBounds]="fitBounds"
[leafletLayers]="layers">
</div>
app.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import * as L from 'leaflet';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
tiles = L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', {
maxZoom: 20,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
detectRetina: true
});
layers: L.Layer[];
redGroup = L.featureGroup();
blueGroup = L.featureGroup();
fitBounds = null;
constructor(
private http: HttpClient,
) { }
ngOnInit() {
this.http.get<any>('assets/states.geojson')
.subscribe(data => {
const tmp = L.geoJSON(data, {
style: () => ({
weight: 2,
fillOpacity: 1,
opacity: 1
}),
onEachFeature: this.onEachFeature.bind(this)
});
this.fitBounds = L.geoJSON(data).getBounds();
// this.redGroup.bringToFront();
this.layers = [ this.tiles, this.redGroup, this.blueGroup ];
// this.layers = [ this.tiles, this.redGroup.bringToFront(), this.blueGroup ];
// this.redGroup.bringToFront();
});
}
onEachFeature(feature, layer) {
if (feature.properties.name_len <= 3522) {
layer.addTo(this.redGroup);
// this.redGroup.bringToFront();
} else {
layer.addTo(this.blueGroup);
}
this.blueGroup.setStyle({fillColor: 'lightblue', color: 'blue'});
this.redGroup.setStyle({
fillColor: 'pink', color: 'red'
});
this.redGroup.bringToFront();
layer.on('click', (e) => {
e.target.setStyle({color: 'yellow'}).bringToFront();
});
}
}
I commented out all of my failed attempts to push redGroup to the front. As you can see, when you click on a polygon, the yellow stroke is pushed to the front with bringToFront. But on my initial load, I want the red stroke from redGroup to display on top of the blue stroke from blueGroup. How can I do this?
Per #reblace's guidance, I needed to call the code after a timeout at the bottom of onEachFeature, like so:
setTimeout(() => {
this.redGroup.bringToFront();
}, 0);

Math.max.apply gives an error CreateListFromArrayLike called on non-object

I am working on something for checking what is the max value and whats is the min value. For this I am using Math.max.apply() and Math.min.apply().
Before I check that I convert an Object out of GeoJson code called from and to.
That looks like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
6.338356,
52.790868
],
[
6.378572,
52.648089
],
[
6.10522,
52.663572
],
[
6.089325,
52.798539
],
[
6.338356,
52.790868
]
]
]
},
"properties": {
"name": "DiggitTwoOne",
"regioFacetId": "tcm:106-353682-1024",
"level": 3,
"from": "10",
"to": "12"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
6.105498,
52.663816
],
[
6.378605,
52.648187
],
[
6.417051,
52.520692
],
[
6.173867,
52.509454
],
[
6.105498,
52.663816
]
]
]
},
"properties": {
"name": "DiggitTwoTwo",
"regioFacetId": "tcm:106-353682-1024",
"level": 3,
"from": "13",
"to": "15"
}
}
]
}
For now the javascript code looks like this:
var from = event.feature.getProperty("from");
var to = event.feature.getProperty("to");
var mergeObjects = JSON.parse(from,to);
console.log(Math.max.apply(Math,mergeObjects));
console.log(Math.min.apply(Math, mergeObjects));
When I run the javascript code it gives an error like this:
CreateListFromArrayLike called on non-object.
I am using the Objects from and to.
Is there something I did wrong or am I getting it wrong of using it like this.
Your problem is that apply accepts an array and you're not passing it that:
var from = event.feature.getProperty("from"),
to = event.feature.getProperty("to"),
numArr = [from, to];
Math.max.apply(Math, numArr);
Math.min.apply(Math, numArr);
Is this what you're looking for?

Howto get any item (Point, LineString, Polygon) within a bounding box in mongodb

I've a problem with a query matching items inside a BoundingBox.
How it's possible to match all items of type 2dsphere (GEO JSON)?
In this case I only got the data of type Point but the items of type LineString won't appear inside the result.
The schema definition looks like the following example:
/**
* Media location values (Point, LineString, Polygon)
* #property location
* #type {Object}
*/
location:{
"type":Object,
"index":"2dsphere"
},
I've e.g. this items in it:
[
{
"_account": "52796da308d618090b000001",
"_id": "5284e5798a1c039735000001",
"location": {
"coordinates": [
8.663705555555556,
50.10165277777778
],
"type": "Point"
},
"name": "Foto.JPG",
"preview": "/img/thumbs/13719-3zavxm.JPG",
"type": "image/jpeg",
"added": "2013-11-14T15:00:09.113Z",
"latlng": [ ],
"shares": [ ],
"shared": false,
"tags": [ ]
},
{
"_account": "52796da308d618090b000001",
"name": "Filtererd_Track.kml",
"type": "application/vnd.google-earth.kml+xml",
"_id": "5284e5c48a1c039735000002",
"added": "2013-11-14T15:01:24.280Z",
"latlng": [ ],
"shares": [ ],
"shared": false,
"tags": [ ]
},
{
"_account": "52796da308d618090b000001",
"_id": "5284e5c48a1c039735000003",
"location": {
"coordinates": [
[
9.49653,
50.94791
],
[
9.49731,
50.94811
],
[
9.49744,
50.94812
],
[
9.49755,
50.94808
],
[
9.4991,
50.94579
],
[
9.49969,
50.94545
],
[
9.50037,
50.94525
],
[
9.50136,
50.9452
],
[
9.50851,
50.98557
]
],
"type": "LineString"
},
"name": "test 2.gpx",
"preview": "/img/thumbs/13719-14rvt8w.png",
"type": "application/gpx+xml",
"added": "2013-11-14T15:01:24.529Z",
"latlng": [ ],
"shares": [ ],
"shared": false,
"tags": [ ]
}
]
The query to fetch the items looks like the following example but it does not match LineStrings / Polygons....
Think it's because of the subarrays but don't know how to include this in the query.
{
{
"location": {
"$geoWithin": {
"$box": [
[
-39.375,
36.73888412439431
],
[
76.640625,
56.897003921272606
]
]
}
}
}
}
I found a way to get everything in a bounding box by using $geoIntersects and create a Polygon from Bounding Box.
Like example below.
{
"location": {
"$geoIntersects": {
"$geometry": {
"type": "Polygon",
"coordinates": [
[
[
5.372314453125,
52.288322586002984
],
[
12.623291015625,
52.288322586002984
],
[
12.623291015625,
49.67829251994456
],
[
5.372314453125,
49.67829251994456
],
[
5.372314453125,
52.288322586002984
]
]
]
}
}
}
]
}

How to extract values from geojson efficiently?

I have a geojson file of the following structure:
var areas = {
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "id": 0, "properties": { "name": "a", "count": "854" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 13.271687552328165, 29.359549285088008 ], [ 13.272222904657671, 29.357697459147403 ], [ 13.272586765837973, 29.35566049412985 ], [ 13.273062097784726, 29.354438105832578 ], [ 13.272652418199639, 29.360795108476978 ], [ 13.271320041078822, 29.360700647951568 ], [ 13.271687552328165, 29.359549285088008 ] ] ] } }
,
{ "type": "Feature", "id": 1, "properties": { "name": "b", "count": "254"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 13.277038163109875, 29.358442424220023 ], [ 13.276782949188294, 29.358122923383512 ], [ 13.275290999273452, 29.358508600578681 ], [ 13.274634727185679, 29.358485484466968 ], [ 13.282581930993208, 29.358635779719847 ], [ 13.278334024184868, 29.359814295404375 ], [ 13.277038163109875, 29.358442424220023 ] ] ] } }
,
{ "type": "Feature", "id": 2, "properties": {"name": "c", "count": "385"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 13.279484097462499, 29.349831113628788 ], [ 13.27792879702741, 29.349728966688758 ], [ 13.276089401418951, 29.349901260351807 ], [ 13.275677565886326, 29.349951087700632 ], [ 13.279484097462499, 29.349831113628788 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "name": "d", "count": "243"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 13.290520299215724, 29.352306689134622 ], [ 13.289722088408338, 29.351802774685929 ], [ 13.289065241087885, 29.352101541350635 ], [ 13.28785814146197, 29.351114667998772 ], [ 13.290520299215724, 29.352306689134622 ] ] ] } }
]
}
Normally, to convert this data into an array I would create a loop to run through the appropriate variable storing this value in an array. However, I don't know if this is the best approach. Is there a way of pulling out all of the values for id into an array so that I would end up with:
[0,1,2,3]
I'm happy to use any external library to do this either - I'm mainly curious if there is a more efficient way than my current approach.
Not my code but there is a post on here regarding getting values from json quite efficiently.
refer to post
use jQuery's find() on JSON object
Answer from User Box9 is probably the best way
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else if (i == key && obj[key] == val) {
objects.push(obj);
}
}
return objects;
}
Upvoted this answer in regards to this code block as well because it's about the best way I've found to pull out values
Something like this should work:
var arr = new Array();
for(var i = 0; i < areas.features.length; i++){
arr.push(areas.features[i].id)
}
To get a certain id value directly you can do something like this:
areas.features[0].id
which in this case would be 0.
EXAMPLE
If you're absolutely desperate to give something else a go, you could try underscore's map. The code would look something like this:
_.map(areas.features, function (item) { return item.id });
This will call the inner function on each item in features, and return an array containing each result.
I don't think there's anything too radical you can do here - ultimately, pulling values out of nested objects and arrays can't be dumbed down all too much.

Categories