I want to get location name using latitude and longitude of user like any theater, restaurant, famous park, vacation place, shopping store. I am using Google map api but they only shows area name not any store name. How I get location name?
You can use Google Places API to get this information. Google Maps will not return store or place data based on latitude and longitude parameters.
I would enable your API key to work with Google Places API and then make a call to the getNearbyPlaces endpoint. The endpoint requires latitude, longitude, and radius (distance in meters in which the results must be found) parameters. Remember, this is still a query so your response will contain multiple results and by default, the results are ordered by popularity. I like to also specify a "type=establishment" as an optional parameter so I don't get abstract results like "route".
You can test this out in RapidAPI here. I've linked you directly to the getNearbyPlaces endpoint. Just fill in your apiKey, latitude, longitude, radius (I like to keep it around 20 meters for specificity), and any other optional parameters. Click "TEST function" to see a detailed JSON response. I'll show you a screenshot of what this looks like.
In this example, I looked up the latitude and longitude for Bob's Doughnuts. Boom! My first result was in fact, Bob's Doughnuts in San Francisco. RapidAPI also lets you generate a code snippet that you can copy and paste directly into your own code. You just have to click the "CODE" button above the response, sign in, and choose the language you're using. The code snippet provided from the above call looks like:
Hope this helps! One more thing.. Since the results are ordered by popularity, the first result might not always be the ideal result. The API provides a "rankBy" parameter, but I think Google is still working out some bugs with it. In the meantime, I would build a loop that finds the closest result item by distance. All you need to do is create a distance function using the Haversine formula. I'll build you a quick function! I used the haversine formula function from this post. Heres the code.
// Still using my Bob's Doughnuts example
const startLatitude = "37.7918904"; // your original query latitude
const startLongitude = "-122.4209966"; // your original query longitude
function closestResult(results) {
let closestResult = null;
let shortestDistance = null;
for (let i = 0; i < results.length; i++) {
let location = results[i].geometry.location;
let currentDistance =
getDistanceFromLatLonInKm(startLatitude, startLongitude, location.lat, location.lng);
if (shortestDistance === null) {
closestResult = results[i];
shortestDistance = currentDistance;
} else if (currentDistance < shortestDistance) {
closestResult = results[i];
shortestDistance = currentDistance;
}
}
return closestResult;
}
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2-lat1); // deg2rad below
var dLon = deg2rad(lon2-lon1);
var a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2)
;
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI/180);
}
Now your success callback can look like this:
Happy coding!
Related
I have a google form which is basically an assessment for students. Each question carries 1 point. When I connect my form to a specific spreadsheet, I get the total score of the student e.g 24/30
What I want to do:
Along with the total score, we want to get each question's score to go to the spreadsheet. Here is what we are trying to have:
I have no idea what to do. Please guide. Thanks
You can try with Apps Script. I tested the following script that can give you an idea on how to achieve this.
const TARGET_SPREADSHEET_ID = "spreadsheetID"; //Change according to your needs
const TARGET_SHEET_NAME = "sheetName"; //Change according to your needs
const SOURCE_FORM_ID = "formID"; //Change according to your needs
//Run this function only one time, this will create a trigger that will run function "onFormSubmitTrigger" whenever a student submits a response.
function installOnFormSubmitTrigger() {
const form = FormApp.openById(SOURCE_FORM_ID);
ScriptApp.newTrigger("onFormSubmitTrigger")
.forForm(form)
.onFormSubmit()
.create();
}
function onFormSubmitTrigger(e) {
const targetSpreadsheet = SpreadsheetApp.openById(TARGET_SPREADSHEET_ID);
const targetSheet = targetSpreadsheet.getSheetByName(TARGET_SHEET_NAME);
//GETTING RESPONSES
var itemResponses = e.response.getItemResponses();
var responses = itemResponses.map(itemResponse => itemResponse.getResponse()); //Get responses
var name = responses.splice(0,1); //extracting first element ("Full Name") of responses
//GETTING SCORES
var itemScores = e.response.getGradableItemResponses();
var scores = itemScores.map(itemScore => itemScore.getScore()); // Get response score
scores.splice(0,1); //removing score for the first element ("Full Name")
var newArr = name.concat(scores); //combining name and scores in one array
//newArr.splice (1,0,""); //you can add this line to insert blank between "Student Name" and "Q1"
targetSheet.appendRow(newArr); //Append scores to the sheet
}
Test the script by submitting a form and the target sheet should show students names and the score for each question they answered. If you have any questions let me know.
I would like to develop an API using HAPI JS and MYSQL using limit and offset parameters
Could anyone please suggest me resources on how to develop this.
Thanks.
Example: GET /schools?offset=10&limit=20
Paging depends on very basic principles.
First, you need to know in a particular query, which you'll show in the page you have, how many rows do you have?
For example, you listing blog post on your page, get total row
SELECT count(*) FROM blog_post_table; // cosnt numRows = Query....,
Let's say it's 168;
Now, you need to decide how many rows will be shown in a page. On your example, there is a query parameter "limit=20" which answers our question.
const perPage = request.query.limit || 20;
Based on the limit parameter in the query string or at least 20 items per page, validation is your homework, Joi.
Then, we should calculate how many pages will be there based on our perPage information.
const totalPages = Match.ceil(numRows / perPage);
It results in 9, we used Math.ceil, you get it I assume, you can't divide 168 with 20 because there are 8 remaining items. The result w 8.4, means we need one more page to show remaining 8 items.
So far so good, now we have to calculate our offset, where we start from reading data. In the first page, of course, it starts from 0, but what about second or fourth or ninth?
Now we need a current page parameter, and we should carry this information in query strings (I discarded your offset=10 definition on purpose), let's say there is parameter in query string named page
const currentPage = request.query.page || 1; // easy, yet harmful, it needs validation
Now we know our current page, now we can calculate our limit based on those figures.
const offset = perPage * (currentPage - 1);
To realize, put numbers on the places
const offset = 20 * (1-1); // page 1 offset = 0;
const offset = 20 * (2-1); // page 2 offset = 20;
.
.
.
const offset = 20 * (9-1); // page 9 offset = 160;
Now we can make our main query based on our calculations.
const sql = `SELECT * FROM blog_post_table LIMIT ${perPage} OFFSET ${offset}`;
Fetch rows and send to your page. Some additional information will be useful if you want to show a proper paging interface.
Let's say your response data is like this;
const response = {
'results': ['array of elements from db'],
'currentPage': currentPage, // learn object literals, it unnecessary,
'nextPage': currentPage + 1, // don't be that naive, validate this,
'lastPage': totalPages, // it is obvious
'previousPage': currentPage - 1, // what if we're in the very first page, then we can go to 0, validate!
}
BONUS:
Little code that generates previous and next pages, not a perfect solution just made it up quickly.
const getOtherPages = (totalPages, currentPage) => {
previousPage = null
nextPage = null
if currentPage > totalPages or currentPage < 1:
return previousPage, nextPage
if currentPage > 1:
previousPage = currentPage - 1
if (currentPage + 1) < totalPages:
nextPage = currentPage + 1
return [previousPage, nextPage]
}
// Usage
const [previousePage, nextPage] = getOtherPages(totalPages, currentPage);
I have a special case when I want to do something like
let predicate = NSPredicate(format:"
DISTANCE(\(UserLocation),photoLocation) <= visibleRadius AND
DISTANCE(\(UserLocation),photoLocation" <= 10)"
var query = PFQuery(className:"Photo", predicate:predicate)
Basically, I want to get all photos that are taken within 10km around my current location if my current location is also within the photo's visible radius
Also, photoLocation and visibleRadius are two columns in the database, I will supply UserLocation as a PFGeoPoint.
Is it possible to achieve this? In my opinion, I don't think that I may call, for example, photoLocation.latitude to get a specific coordinate value. May I?
I'll appreciate you a lot if this can be achieved!!
I found this at the pares.com docs here is the link
let swOfSF = PFGeoPoint(latitude:37.708813, longitude:-122.526398)
let neOfSF = PFGeoPoint(latitude:37.822802, longitude:-122.373962)
var query = PFQuery(className:"PizzaPlaceObject")
query.whereKey("location", withinGeoBoxFromSouthwest:swOfSF, toNortheast:neOfSF)
var pizzaPlacesInSF = query.findObjects()
This code fetch you all the objects that are in a rectangle area defined by the swOfSF & neOfSF objectc, where seOfSF is in the south-west corner and neOfSF is in the north-east corner.
You can make some alterations to the code and get all the objects in rectangle area that your object is in middle
i would recommend that you don't use a radius, because it will take a lot of calculations. Instead use a rectangle area (like in the code i gave you).
just calculate what is the max/min longitude & max/min latitude from your position and fetch all the objects that are in between. you can read about how to fine the min/max longitude & latitude here Link
I managed to solve it using Parse Cloud Code, here is the quick tutorial
Parse.Cloud.define("latestPosts", function(request, response) {
var limit = 20;
var query = new Parse.Query("Post");
var userLocation = request.params.userLocation;
var searchScope = request.params.searchScope;
var afterDate = request.params.afterDate;
var senderUserName = request.params.senderUserName;
query.withinKilometers("Location", userLocation, searchScope);
query.greaterThan("createdAt", afterDate);
query.notEqualTo("senderUserName",senderUserName);
query.ascending("createdAt");
query.find({
success: function(results) {
var finalResults = results.filter(function(el) {
var visibleRadius = el.get("VisibleRadius");
var postLocation = el.get("Location");
return postLocation.kilometersTo(userLocation) <= visibleRadius;
});
if (finalResults.length > limit) {
var slicedFinalResults = results.slice(0, 20);
response.success(slicedFinalResults);
} else {
response.success(finalResults);
}
},
error: function() {
response.error("no new post");
}
});
});
The code above illustrate a basic example of how to use Cloud Code. Except, I have to make sure that all the returned image are in the union of user's search scope and photo's visible circle. There are more techniques such as Promises. But for my purpose, the code above should just suffice.
I have a form that accepts currency from several fields and depending on what I enter into one, it calculates others. For this most part the code below works (example being the invoice amount field)
<xp:inputText value="#{FInvoiceDoc.InvoiceAmount}" id="InvoiceAmount">
<xp:this.converter>
<xp:convertNumber type="currency"></xp:convertNumber></xp:this.converter>
<xp:eventHandler event="onchange" submit="false" id="eventHandler5">
<xp:this.script><![CDATA[var rate = XSP.getElementById("#{id:ExchangeRate}").value;
var stAmount = XSP.getElementById("#{id:InvoiceAmount}").value;
var stTvat = XSP.getElementById("#{id:TVAT}").value;
var stTst = XSP.getElementById("#{id:TST}").value;
var stToop = XSP.getElementById("#{id:Toop}").value;
var tmp;
// get the dojo currency code
dojo.require("dojo.currency");
// get the numeric values using parse
amount = dojo.currency.parse(stAmount,{currency:"USD"});
total = rate * amount;
XSP.getElementById("#{id:EstUSAmount}").innerHTML = dojo.currency.format(total,{currency:"USD"});
XSP.getElementById("#{id:InvoiceAmount}").value = dojo.currency.format(amount,{currency:"USD"});
if (amount != 0) {
tvat = dojo.currency.parse(stTvat,{currency:"USD"});
tst = dojo.currency.parse(stTst,{currency:"USD"});
toop = dojo.currency.parse(stToop,{currency:"USD"});
tmp = (tvat / (amount-tvat-tst-toop)) * 100;
XSP.getElementById("#{id:VP}").innerHTML = tmp.toFixed(2);
tmp = (tst / (amount-tvat-tst-toop)) * 100;
XSP.getElementById("#{id:STP}").innerHTML = tmp.toFixed(2);
tmp = (toop / (amount-tvat-tst-toop)) * 100;
XSP.getElementById("#{id:OoPP}").innerHTML = tmp.toFixed(2);
}
]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
Like I said, for the most part this works, but if I enter only a partial number like
200.2
instead of
200.20
then it fails. Most data entry folks will want to not have to key in the last "0" just so it's legal.
btw, if I enter it in as just 200 with no cents, it's OK.
It's as if the statement;
amount = dojo.currency.parse(stAmount,{currency:"USD"});
requires a 2 digit penny amount or no pennys, but doesn't like just the leading cents digit.
Any way around this?
The currency format is very restrictive and needs the certain number of decimal places for a given currency. As you can see here there can be different number of decimal places depending on currency. For most currencies it needs two decimal places though. But, you can trick the parser. Just try it with standard number of decimal places and if it fails try it with one decimal place again. Your code would look like this then:
var amount = dojo.currency.parse(stAmount,{currency:"USD"});
if (!amount && amount!==0) {
amount = dojo.currency.parse(stAmount,{currency:"USD",places:"1"});
}
This accepts inputs like
12
12.3
12.34
$12
$12.3
$12.34
But it is still very picky. It doesn't accept spaces or more decimal places then currency allows.
If you want more flexibility for your users and need USD currency only I'd go for dojo.number or other number parsing instead and show the "$" outside the input field. Then, you'd be able to accept much more formats and could add functions like rounding.
Yeah, I've played with the converters. Thing is I want the converter to stay "Currency". The data I receive from the notes database is always correct and formats properly. Its the manipulation that I''m having a problem with. Since this is all on the client side, I've created a function that I can reuse throughout the page.
<script>
function isNumeric(n) {
n = parseFloat(n);
return !isNaN(n) || n != n;
}
// We call this if its a currency amount. If they only entered one number after
// the decimal, then we just append a 0. We're expecting a string and we send
// the string back.
function cMask(Amount)
{
if (Amount == "") { return "0.00" }
a = Amount.split(".");
if (a.length == 2)
{
if (a[1] != null)
{
if (a[1].length == 1)
{
Amount = Amount + "0";
}
}
}
// get the dojo currency code
dojo.require("dojo.currency");
b = dojo.currency.parse(Amount,{currency:"USD"});
if (isNumeric(b)) {return Amount} else {return "0.00"}
}
</script>
Then its a matter of just changing the initial variable load line.
var stAmount = cMask(XSP.getElementById("#{id:InvoiceAmount}").value);
Seems to work and I've just taught myself how to create reusable client-side javascript for my page.
I want to get all the airport near my location order by distance. I am using Nearby Search Requests with google places api using this url : https://maps.googleapis.com/maps/api/place/nearbysearch/xml?location=51.9143924,-0.1640153&sensor=true&key=api_key&radius=50000&types=airport The results that I am getting are sparse with no order what so ever. I tried rankby=distance but no result appear.
and as per https://developers.google.com/places/documentation/search#PlaceSearchRequests documentation " radius must not be included if rankby=distance".
Yes, you cannot use radius and rankBy in same request. But you can use rankBy=distance and then count distance youself based on geometry.location.lat and geometry.location.lng. For exmaple in groovy i've done like that:
GeoPosition and Placeclasses are implemented by me, so don't expect to find them at the core libs :)
TreeMap<Double, Place> nearbyPlaces = new TreeMap<Double, Place>()
if(isStatusOk(nearbySearchResponse))
nearbySearchResponse.results.each {
def location = it.geometry.location
String placeid = it.place_id
GeoPosition position = new GeoPosition(latitude: location.lat,
longitude: location.lng)
Place place = new Place(position)
double distance = distanceTo(place)
//If the place is actually in your radius (because Places API oftenly returns places far beyond your radius) then you add it to the TreeMap with distance to it as a key, and it will automatically sort it for you.
if((distance <= placeSearcher.Radius()))
nearbyPlaces.put(distance, place)
}
where distance is counted like that (Haversine formula):
public double distanceTo(GeoPosition anotherPos){
int EARTH_RADIUS_KM = 6371;
double lat1Rad = Math.toRadians(this.latitude);
double lat2Rad = Math.toRadians(anotherPos.latitude);
double deltaLonRad = Math.toRadians(anotherPos.longitude - this.longitude);
return 1000*Math.acos(
Math.sin(lat1Rad) * Math.sin(lat2Rad) +
Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLonRad)
) * EARTH_RADIUS_KM;
}
You can not use radius and rankby together that's the problem
As per October 2018, Google has added the initial location as part of the nearbySearch, as follows:
service.nearbySearch({
location: place.geometry.location, //Add initial lat/lon here
rankBy: google.maps.places.RankBy.DISTANCE,
type: ['museum']
}, callback);
The aforementioned code will return the museums close to the location specified ordered by distance asc.
Find more info here: https://developers.google.com/maps/documentation/javascript/examples/place-search