Merge JSON values into a variable or string - javascript

I JSON nodes with the same title, but different latitude and longitude values in each node. I need to check for the same title value, but then merge together the latitude and longitude values into a url for a map API. I need it to be in this order latitude, longitude, latitude, longitude, etc... I just don't know what to do at this point. Thanks for any help or suggestions.
JS VAR
<img class="detail_map" src="http://open.mapquestapi.com/staticmap/v4/getplacemap?size=320,240&zoom=15&location=' + data.nodes.Latitude + ',' + data.nodes.Longitude + '&imagetype=jpeg&showicon=blue-1">
JSON Object
var data = fl({
"nodes":[
{"node":{
"title":"180","Address":"555 Market St. San Francisco, CA United States See map: Google Maps","
Latitude":"37.789952","
Longitude":"-122.400158"}},
{"node":{
"title":"180","Address":"Epic Roasthouse (399 Embarcadero) San Francisco, CA United States See map: Google Maps","
Latitude":"37.797677","
Longitude":"-122.394339"}},
{"node":{
"title":"180","Address":"Mason & California Streets (Nob Hill) San Francisco, CA United States See map: Google Maps","
Latitude":"37.791556","
Longitude":"-122.410766"}},
{"node":{
"title":"180","Address":"Justin Herman Plaza San Francisco, CA United States See map: Google Maps","
Latitude":"37.774930","
Longitude":"-122.419416"}},
{"node":{
"title":"180","Address":"200 block Market Street San Francisco, CA United States See map: Google Maps","
Latitude":"37.793133","
Longitude":"-122.396560"}}
]});
});

You can use $.extend() function for merge two objects, the different properties will be replaced.
Example:
var newData = $.extend(data1, data2);
// Assuming data1, data2 are objects;
If you need convert string JSON to object, use $.parseJSON()

you can try to do something like this where var url_part is used to replace "data.nodes.Latitude + ',' + data.nodes.Longitude" from the img src:
var url_part = '';
$.each(data.nodes, function(key,val){
url_part += val.node.Latitude+","+val.node.Longitude+",";
});
but before useding url_part, you need to remove the last coma...

Use jQuery's $.map(). Compare the object's node.title value, and then from there return the string as you would expect. When you're done, join the array on ,.
var locs = $.map(fl.nodes, function(obj,i){
return obj.node.title == '180' ? 'latitude='+obj.node.Latitude+'&longitude='+obj.node.Longitude : '';
}).join(',');
would return lat1,long1,lat2,long2,lat3,long3,lat4,long4,lat5,long5
Working jsFiddle
Edit 1
Added support for dynamic titles.
function getNodesByTitle(title){
return $.map(fl.nodes, function(obj,i){
return obj.node.title == title ? 'latitude='+obj.node.Latitude+'&longitude='+obj.node.Longitude : '';
}).join(',');
}
In theoretical practice:
var locString = getNodesByTitle('your title here');

I had to create a function to merge addresses and latitude and longitude. Check out the jsFiddle to see it in action.
function fl(data){
//data = JSON.parse(data);
//Array to hold movie titles
var movieTitles = [];
//Assign Movies to to movies Array and ensure unique
for (var i=0; i < data.nodes.length; i++)
{
//Look for the current title in the movieTitles array
var movieIndex = movieTitles.indexOf(data.nodes[i].node.title);
if (movieIndex>-1) //If the title already exists
{
//Merge all the properties you want here
movies[movieIndex].Address += ", " + data.nodes[i].node.Address;
if(!movies[movieIndex].Coords) movies[movieIndex].Coords = [];
movies[movieIndex].Coords.push(
data.nodes[i].node.Latitude + "," + data.nodes[i].node.Longitude
);
}
else
{
//var address = movies[movieIndex].Address; movies[movieIndex].Address = address.replace(/^\s*/,'');
//Add movie to movies array
movies.push(data.nodes[i].node);
//Add movie title to movieTitles array
movieTitles.push(data.nodes[i].node.title);
}
}
displayLinks(); //Load all the links
//showCast(0); //Display details for first item
}
//});

Related

Prioritize city matches against province matches in Nominatim

I installed Nominatim in combination with the Maplibre geocoder, but I am having troubles getting the results in the correct order of relevance or getting the correct one at all. In Italy many provinces have the same name as the capital of the province, for example Cagliari is both the name of the Province and the name of a city. When I search for
Via Roma, Cagliari
I an expecting to see the result for the street "Via Roma" located in the city of Cagliari, but I get results for "Via Roma" in other cities located in the province of Cagliari instead. This happens frequently with street names that are fairly common across cities in the same area. How can I make Nominatim to give precedence to the street located in the city with the same name or to not take the province into account at all when elaborating the query?
This is how I am calling the geocoder api
var geocoder_api = {
forwardGeocode: async (config) => {
const features = [];
try {
geocoder_bbox = map.getBounds().toArray().flat()
let request =
'https://my.server/search?q=' +
config.query +
'&format=geojson&addressdetails=1&viewbox='+geocoder_bbox;
const response = await fetch(request);
const geojson = await response.json();
for (let feature of geojson.features) {
let center = [
feature.bbox[0] +
(feature.bbox[2] - feature.bbox[0]) / 2,
feature.bbox[1] +
(feature.bbox[3] - feature.bbox[1]) / 2
];
let point = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: center
},
place_name: feature.properties.display_name,
properties: feature.properties,
text: feature.properties.display_name,
place_type: ['place'],
center: center
};
features.push(point);
}
} catch (e) {
console.error(`Failed to forwardGeocode with error: ${e}`);
}
return {
features: features
};
}
};

Displaying Special Case Of Sorted Firebase Arrays (with AngularJS)

So basically I have a set of clubs, and a set of users. Each club and each user has a specific latitude and longitude. Showing all clubs to a user is easy with ng-repeat, but I'm trying to just show clubs within a certain distance of each user. So what I've come up with so far:
var arr = [];
$scope.clubs.$loaded().then(function() {
angular.forEach($scope.clubs, function(value, key) {
if($scope.getDistance(value.lng, value.lat) == true) {
console.log(value.name + " it's close enough!");
arr.push( {id: value.$id, description: value.description, name: value.name});
}
});
console.log(arr);
});
$scope.narr = arr;
Is there a more elegant way to do this? I'm basically singling out data from a firebase array, and then putting it into a smaller array (arr) and then ng-repeating through it. But now it's not a firebase array... Any ideas?
p.s. I don't think I can use any of the built in firebase sorting, because distance is unique for each user, and each location requires a latitude and longitude.
Why not evaluate $scope.getDistance() in your template?
You'll only need to create a $firebaseArray() on $scope.
$scope.cabyns = $firebaseArray(ref);
Then in your template you can call $scope.getDistance() with the item in ng-repeat. Using an ng-if direction, you can state whether it should be loaded.
<ul>
<li ng-repeat="item in cabyns">
<span ng-if="getDistance(item)">
{{ item.name }}
<span>
</li>
</ul>
Another thing you could try doing is using GeoFire if you're doing geofencing.
So i went with GeoFire. It's pretty much the same implementation as above, but should be much better for scaling. If anyone is interested, this is what your GeoFire function would look like:
var array = [];
$scope.publicArray = array;
$scope.geoFunc = function() {
geoQuery = geoFire.query({
center: [userData.Latitude, userData.Longitude],
radius: 25
});
geoQuery.on("key_entered", function(key, location, distance) {
console.log(key + " is located at [" + location + "] which is within the query (" + distance.toFixed(2) + " km from center)");
var newRef = new Firebase(furl + "/clubs/" + key);
$scope.thing = $firebaseObject(newRef);
array.push($scope.thing);
});
};
And then you could just ng-repeat through your publicArray.

Javascript Lookup Array, Return Corresponding Value

I have a script that fetches a part of a webpage. A small portion of it fetches the Team Name:
var teamName = tblRow.find ("td:eq(1)").text().trim().split(" vs")[0]
This will return something like Chicago Bears or San Francisco 49ers.
Is there a way for me to create an array like
Chicago Bears CHI
San Francisco 49ers SF
...
that will replace a team name with the abbrevated team name?
I know I can use $.inArray(value, array) to see if a value is in an array but I just want to return the corresponding column value. Error checking does not need to be performed to see if value exists in array.
Create a lookup object:
var teamNames = {
"Chicago Bears": "CHI",
...
}
And then do:
var teamName = tblRow.find ("td:eq(1)").text().trim().split(" vs")[0]
var abbv = teamNames[teamName];

Get definite City name in Google maps reverse geocoding

Using the Google Maps Geocoding API, i'm able to get the formatted address for a particular coordinate. To get the exact city name, I'm doing the following:
$.ajax({
url: 'http://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+long+'&sensor=false',
success: function(data){
var formatted = data.results;
var address_array = formatted[6].formatted_address.split(',');
var city = address_array[0];
}
});
where lat and long are derived using the browser coordinates. My problem is the following:
From coordinates 19.2100 and 72.1800, I get the city as Mumbai, but from a similar set of coordinates about 3Km away, I get city as Mumbai Suburban. How can I get Mumbai without changing the success function of my code? It seems to me that the result array doesn't always stick to the same format which creates problems in my displaying of the city name.
So I was trying to figure this out today and I came to this solution if it helps anyone. Google maps comes with the Geocoder built in now so you just create a geocoder object once the API has loaded.
You can easily wrap that in a function and just return an object with the city, state, and postal code. This site was helpful in allowing me to see what the different 'types' mean: Reverse Geocoding
var geocoder = new google.maps.Geocoder,
latitude = 28.54, //sub in your latitude
longitude = -81.39, //sub in your longitude
postal_code,
city,
state;
geocoder.geocode({'location': {lat:latitude, lng:longitude}}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
results.forEach(function(element){
element.address_components.forEach(function(element2){
element2.types.forEach(function(element3){
switch(element3){
case 'postal_code':
postal_code = element2.long_name;
break;
case 'administrative_area_level_1':
state = element2.long_name;
break;
case 'locality':
city = element2.long_name;
break;
}
})
});
});
}
});
You need to look at the type of the result, not the absolute index in the array of results. Iterate through the results array looking for the entry which has the appropriate type. Looks like that would be:
locality indicates an incorporated city or town political entity
But data may vary with region.
related question: Grabbing country from google geocode jquery
Looks like you want the entry with both the 'locality' and the 'political' types:
{
"long_name" : "Mumbai",
"short_name" : "Mumbai",
"types" : [ "locality", "political" ]
}
For what it's worth, I was looking for something similar and am trying https://plus.codes/
If you strip the encoded bit it yields a fairly consistent city, state, country name:
const extractCityName = latlng => {
googleMapsClient.reverseGeocode({ latlng }, (err, response) => {
if (!err) {
return response.json.plus_code.compound_code.split(' ').slice(1).join(' ');
}
});
};
// examples:
console.log(extractCityName(40.6599718,-73.9817292));
// New York, NY, USA
console.log(extractCityName(37.386052, -122.083851));
// Mountain View, CA, USA
console.log(extractCityName(51.507351, -0.127758));
// Westminster, London, UK
$.get({
url: locAPI,
success: function(data)
{
data.results[0].address_components.forEach(function(element){
// console.log(element.types);
if(element.types[0] == 'locality' && element.types[1] == 'political')
{
console.log('City:')
console.log(element.long_name);
}
if(element.types[0] == 'country' && element.types[1] == 'political')
{
console.log('Country:')
console.log(element.long_name);
}
});
}
})
In My Case, I had to find City and Country Name.. That's what I did.

Grouping javascript objects by a common value

I have a DB query which returns a bunch of location based data from my DB. I end up with a list of objects (which I put in to a single object and console.log() it to see whats inside).
Each object represents an entry from a user which contains notes on the location:
It contains: store name, address, userID, notes.
So many people can visit the location and write different notes. What I want to do is put the locations on a Google Map (JS API) and kind of group by location, so when a marker is clicked, it contains all notes for that location.
SO I thought about grouping the objects returned by address, then for each address, plot the marker and loop through.
for (var i = 0; i < rowCountVisits; i++) {
var storelatlng = new google.maps.LatLng(
parseFloat(result[2].latVisit[i]),
parseFloat(result[2].lngVisit[i]));
locationsObjVisits.push({
storelatlng: storelatlng,
vName: result[2].vName[i],
address: result[2].locationVisit[i],
date: result[2].dateVisit[i],
notes: result[2].notes[i],
usersName: result[2].user.thisName[i],
thisColour: result[2].user.thisColour[i]
});
}
So the locationsObjVisits... I am not sure what to do with this. Any ideas?
I would store the locationsObjVisits in an object with array properties, using the addresses as keys. So:
var locationsObjs = {};
for (var i = 0; i < rowCountVisits; i++) {
var storelatlng = new google.maps.LatLng(
parseFloat(result[2].latVisit[i]),
parseFloat(result[2].lngVisit[i]));
var address = result[2].locationVisit[i];
locationsObjs[address] = locationsObjs[address] || [];
locationObjs[address].push({
storelatlng: storelatlng,
vName: result[2].vName[i],
address: address,
date: result[2].dateVisit[i],
notes: result[2].notes[i],
usersName: result[2].user.thisName[i],
thisColour: result[2].user.thisColour[i]
});
}
Now you have all the objects grouped by address, and you can retrieve them from the object in an array using the address as the key. You can also loop through the keys of the locationsObjs object to get a unique list of addresses. So:
for(var address in locationsObjs)
if(locationsObjs.hasOwnProperty(address))
// Plot marker using the address.

Categories