Leaflet click on map and retrieve address - leaflet

I'm working on a Leaflet map based upon https://esri.github.io/esri-leaflet/examples/reverse-geocoding.html. Depending the place you click on the map you'll obtain the real address (street, city, area) or the commercial name: on the linked example, zoom max the map then click on any restaurant and you'll get "Royal Bangladesh Indian Restaurant" instead of address...
To avoid this I'm trying to detect first if the address is a real one or not:
map.on('click', function (e) {
geocodeService.reverse().latlng(e.latlng).run(function (error, result) {
if (error) { return; }
let address = result.address.Match_addr;
lat = parseFloat(e.latlng.lat);
lon = parseFloat(e.latlng.lng);
getAddress(address,lat,lon);
});
});
function getAddress(addr,lat,lon) {
let ad = addr.split(',');
if(typeof ad[1] == "string") { // OK -> real address
alert(ad[0]+', '+ad[2]+' '+ad[1]+'');
// street city zip code ----> works perfectly
}
else if(typeof ad[1] == "undefined") { // commercial name
// ...now what I'm tying to achieve: fire pseudo-click with new coords on map
morelat = lat+0.00005;
morelon = lon+0.00005;
map.fire('click',[morelat,morelon]) // <--- doesn't work but looking for something like
}
}
The idea is to increase/decrease lat+lon by mixing morelat, morelon (and later lesslat, lesslon), turning around the inital click place till I can find the closest real address.
I've tried to do this but it doesn't work
else if(typeof ad[1] == "undefined") { // commercial name
morelat = lat+0.00005;
morelon = lon+0.00005;
geocodeService.reverse().latlng([morelat,morelon]).run(function (error, result) {
if (error) { return; }
getAddress(addr,morelat,morelon)
});
}
Any idea of the best way to proceed?

OK, it seems to be easy:
result.address.LongLabel is the full address including commercial name in first position if provided.
result.address.Match_addr is the commercial name if provided, else the real address if not.
The LongLabel.length (in my tests) is 6 (real address) or 7 (with commercial)
map.on('click', function (e) {
geocodeService.reverse().latlng(e.latlng).run(function (error, result) {
if (error) { return; }
let elems = result.address.LongLabel.split(',')
if(elems.length==6) {
address = result.address.LongLabel;
}
if(elems.length==7) {
// remove commercial name
address = result.address.LongLabel.replace(result.address.Match_addr+',','');
}
let ad = address.split(',');
alert(ad[0]+', '+ad[2]+' '+ad[1]+'');
});
});

Related

Can an automated apps script email notification link back to specific sheet?

much to my surprise I've successfully made an apps scripts that sends me email notifications when a specific cell is changed to 'Submitted,' but I have no idea how to make this identify the sheet it came from - have linked a copy of the sheet below, there are going to be around 20 of these, each with 6 submission sheets, and I need to do a thing as soon as the sheet has been marked submitted, i.e. same day. I'd rather not hard code in separate messages for each sheet, can I do something around getting the URL and sheet with the get active sheet coding and insert it into the email message? I'm also aware currently I've hard coded in the sheet names and therefore need 6 different triggers, I'm working on that - tried loads of different coding pages and this is the only one that worked!
https://docs.google.com/spreadsheets/d/1b0LOr9vhmFu4WtYy_RbS-1cvXncNOI_x3YT0f30fZgY/edit#gid=1979912158
Cheers,
Meg
function emailSubmit() {
MailApp.sendEmail("Testemail", "Test", "Test message");
}
function onEdit(e) {
const specificSheet = "Sub1"
const specificCell = "C11"
let sheetCheck = (e.range.getSheet().getName() == specificSheet)
let cellCheck = (e.range.getA1Notation() == specificCell)
if (!(sheetCheck && cellCheck) || e.value !== "Submitted") {
return;
}
else {
emailSubmit()
}
}
function onEdit2(e) {
const specificSheet = "Sub2"
const specificCell = "C11"
let sheetCheck = (e.range.getSheet().getName() == specificSheet)
let cellCheck = (e.range.getA1Notation() == specificCell)
if (!(sheetCheck && cellCheck)) {
return
}
else {
emailSubmit()
}
}
To obtain the spreadsheet object bound to the fired onEdit trigger, use the event object source
Sample:
function emailSubmit(spreadsheet, sheet) {
console.log("spreadsheet: " + spreadsheet);
console.log("sheet: " + sheet);
MailApp.sendEmail("Testemail", "Test", "Spreadsheet " + spreadsheet + " and tab " + sheet + "have been submitted");
}
function onEdit(e) {
const allowedSheets = ["Sub1","Sub2"];
const specificCell = "C11";
const spreadsheetName = e.source.getName();
const sheetName = e.range.getSheet().getName();
let sheetCheck = (allowedSheets.indexOf(sheetName) != -1);
let cellCheck = (e.range.getA1Notation() == specificCell);
if (!(sheetCheck && cellCheck) || e.value !== "Submitted") {
return;
}
else {
emailSubmit(spreadsheetName, sheetName);
}
}
References:
Event Objects
getName()
indexOf()

problem while using local storage in ionic

What i am trying to do-
i am setting (again) some key (which are set at some other point in my application i.e, Login )value pairs in local storage when a function is called.
similar to reset password.
and it works fine just the problem is that when on the same page if i access those items after resetting them it shows undefined. but when i do login again those values are changed and shows the latest values.
i also tried running on android device and in ionic serve and ionic lab . it never worked.
constructor(public navCtrl: NavController,
public navParams: NavParams,
public apiConnect:ApiIntegrationProvider,
public loadingCtrl:LoadingController,
public toastCtrl:ToastController,
public storage: Storage) {
console.log(this.user_name)
this.fetchProfile();
}
fetchProfile(){
this.user_role=localStorage.getItem("userRole");
this.user_name=localStorage.getItem("userName");
this.user_Email=localStorage.getItem("userEmail");
this.user_Mobile=localStorage.getItem("userMobile");
this.user_Avatar=localStorage.getItem("userAvatar");
this.user_Language=localStorage.getItem("userLanguage");
this.company_name=localStorage.getItem("companyName");
this.company_email=localStorage.getItem("companyEmail");
this.company_punch=localStorage.getItem("companyPunch");
this.company_url=localStorage.getItem("companyUrl");
console.log("user data")
console.log("company name", this.company_name,"email",this.company_email,"punch",this.company_punch,"website", this.company_url,"language", this.user_Language);
if(this.user_Language=='pt'){
this.language="Portuguese"
}else{
this.language="English"
}
if(this.user_role=='25'){
this.role='Inspector';
}else if(this.user_role=='35'){
this.role='Team Lead';
}else if(this.user_role=='45'){
this.role='Moderator';
}else if(this.user_role=='55'){
this.role='Administrator';
}else if(this.user_role=='65'){
this.role='Super Administrator';
}
}
editProfile(){
console.log(this.decideEditProfile);
console.log("edit profile function")
this.decideEditProfile=true;
}
SaveProfile(){
console.log(this.decideEditProfile);
console.log("edit profile function")
this.decideEditProfile=false;
this.useredit();
}
ionViewDidLoad() {
console.log('ionViewDidLoad ProfilePage');
}
showToast(position: string) {
let toast = this.toastCtrl.create({
message: this.editStatus.message,
duration: 2000,
position: 'top'
});
toast.present(toast);
}
useredit() {
const loader = this.loadingCtrl.create({
content: "Please wait...",
duration: 3000
});
loader.present();
let passingValue = {
"user_id": '3',
"inputName": 'James Red',
"inputEmail":'moderator#gmail.com.in',
"inputPassword":'123456'
}
this.apiConnect.postEditProfile(
JSON.stringify(passingValue)).subscribe((data) => {
console.log("login api "+JSON.stringify(data));
this.editStatus = data;
if (this.editStatus.status == "success") {
localStorage.removeItem("userName");
localStorage.removeItem("userEmail");
localStorage.removeItem("userMobile");
localStorage.removeItem("userAvatar");
localStorage.removeItem("userLanguage");
localStorage.setItem("userName",this.editStatus.Profile.fullName);
localStorage.setItem("userEmail",this.editStatus.Profile.emailAddress);
localStorage.setItem("userMobile",this.editStatus.Profile.mobile);
localStorage.setItem("userAvatar",this.editStatus.Profile.avatar);
localStorage.setItem("userLanguage",this.editStatus.Profile.languagePreference);
this.showToast('top');
this.navCtrl.push("DashBoardPage");
}
else {
this.showToast('top');
}
loader.dismiss();
})
}
From your question you are trying to say that even after updating the localstorage you are getting the old value or undefined.
So it might be possible that the data which you are returning may be null or empty. You have to carefully debug your application because localstorage do not work this same way. Do a console test.
Also in this piece of code :
if (this.editStatus.status == "success") {
localStorage.removeItem("userName");
localStorage.removeItem("userEmail");
localStorage.removeItem("userMobile");
localStorage.removeItem("userAvatar");
localStorage.removeItem("userLanguage");
localStorage.setItem("userName",this.editStatus.Profile.fullName);
localStorage.setItem("userEmail",this.editStatus.Profile.emailAddress);
localStorage.setItem("userMobile",this.editStatus.Profile.mobile);
localStorage.setItem("userAvatar",this.editStatus.Profile.avatar);
localStorage.setItem("userLanguage",this.editStatus.Profile.languagePreference);
this.showToast('top');
this.navCtrl.push("DashBoardPage");
}
You do not have to remove the items unnecessarily you can just set the localstorage and the old values will be replaced by the new values.
I hope this helps you. Thanks!

How to detect when Mapbox/Leaflet enters or exits fullscreen mode

How can I detect when Mapbox or Leaflet enters or exits fullscreen mode?
I found this answer where someone said this:
Documentation says:
map.on('fullscreenchange', function () {
if (map.isFullscreen()) {
console.log('entered fullscreen');
} else {
console.log('exited fullscreen');
}
});
If doesnt work, use this instead:
map.on('enterFullscreen', function(){
});
map.on('exitFullscreen', function(){
});
I tried that, as well as a few variations of the event type parameter. No dice.
Also, the documentation doesn't mention an event for this.
Note that I am using Mapbox GL JS.
I know this is a late response but to anyone in the future this is how I approached it (for mapbox GL JS (without leaflet).
map.on("resize", () => {
if (document.fullscreenElement) // do something
});
You can give the map wrapper div a name and exclusively also check if the map is what triggered the fullscreen event
map.on("resize", () => {
if (document.fullscreenElement?.attributes.name.value === "mapWrapper") // do something
});
And if you are using React you can use a state to hold this information.
const [isFullScreen, setIsFullScreen] = useState();
...
map.on("resize", () => {
setIsFullScreen(
document.fullscreenElement?.attributes.name.value === "mapWrapper"
);
});
...
if (isFullScreen) //do something
This is actually really simple. You don't need anything from Leaflet or Mapbox. Just use an event listener on the document object.
let fullScreenChange;
if ('onfullscreenchange' in window.document) {
fullScreenChange = 'fullscreenchange';
} else if ('onmozfullscreenchange' in window.document) {
fullScreenChange = 'mozfullscreenchange';
} else if ('onwebkitfullscreenchange' in window.document) {
fullScreenChange = 'webkitfullscreenchange';
} else if ('onmsfullscreenchange' in window.document) {
fullScreenChange = 'MSFullscreenChange';
}
function onFullscreenChange() {
// Your stuff.
}
window.document.addEventListener(fullScreenChange, onFullscreenChange);

Having trouble attaching event listener to a kml layer's polygon

Using Google Earth I have a loaded kml layer that displays polygons of every county in the US. On click a balloon pop's up with some relevant info about the state (name, which state, area, etc) When a user clicks the polygon I want the information to also pop up on a DIV element somewhere else.
This is my code so far.
var ge;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
ge.getNavigationControl().setStreetViewEnabled(true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
//here is where im loading the kml file
google.earth.fetchKml(ge, href, function (kmlObject) {
if (kmlObject) {
// show it on Earth
ge.getFeatures().appendChild(kmlObject);
} else {
setTimeout(function () {
alert('Bad or null KML.');
}, 0);
}
});
function recordEvent(event) {
alert("click");
}
// Listen to the mousemove event on the globe.
google.earth.addEventListener(ge.getGlobe(), 'click', recordEvent);
}
function failureCB(errorCode) {}
google.setOnLoadCallback(init);
My problem is that when I change ge.getGlobe() to kmlObject or ge.getFeatures() it doesn't work.
My first question is what should I change ge.getGlobe() to to be able to get a click listener when a user clicks on a kml layer's polygon?
After that I was planning on using getDescription() or getBalloonHtml() to get the polygons balloons information. Am I even on the right track?
...what should I change ge.getGlobe() to...
You don't need to change the event object from GEGlobe. Indeed it is the best option as you can use it to capture all the events and then check the target object in the handler. This means you only have to set up a single event listener in the API.
The other option would be to somehow parse the KML and attach specific event handlers to specific objects. This means you have to create an event listener for each object.
Am I even on the right track?
So, yes you are on the right track. I would keep the generic GEGlobe event listener but extend your recordEvent method to check for the types of KML object you are interested in. You don't show your KML so it is hard to know how you have structured it (are your <Polygon>s nested in <Placemarks> or ` elements for example).
In the simple case if your Polygons are in Placemarks then you could just do the following. Essentially listening for clicks on all objects, then filtering for all Placmark's (either created via the API or loaded in via KML).
function recordEvent(event) {
var target = event.getTarget();
var type = target.getType();
if(type == "KmlPolygon") {
} else if(type == "KmlPlacemark") {
// get the data you want from the target.
var description = target.getDescription();
var balloon = target.getBalloonHtml();
} else if(type == "KmlLineString") {
//etc...
}
};
google.earth.addEventListener(ge.getGlobe(), 'click', recordEvent);
If you wanted to go for the other option you would iterate over the KML Dom once it has loaded and then add events to specific objects. You can do this using something like kmldomwalk.js. Although I wouldn't really recommend this approach here as you will create a large number of event listeners in the api (one for each Placemark in this case). The up side is that the events are attached to each specific object from the kml file, so if you have other Plaemarks, etc, that shouldn't have the same 'click' behaviour then it can be useful.
function placeMarkClick(event) {
var target = event.getTarget();
// get the data you want from the target.
var description = target.getDescription();
var balloon = target.getBalloonHtml();
}
google.earth.fetchKml(ge, href, function (kml) {
if (kml) {
parseKml(kml);
} else {
setTimeout(function () {
alert('Bad or null KML.');
}, 0);
}
});
function parseKml(kml) {
ge.getFeatures().appendChild(kml);
walkKmlDom(kml, function () {
var type = this.getType();
if (type == 'KmlPlacemark') {
// add event listener to `this`
google.earth.addEventListener(this, 'click', placeMarkClick);
}
});
};
Long time since i have worked with this.. but i can try to help you or to give you some tracks...
About your question on "google.earth.addEventListener(ge.getGlobe(), 'click', recordEvent);"
ge.getGlobe can not be replaced with ge.getFeatures() : if you look in the documentation ( https://developers.google.com/earth/documentation/reference/interface_g_e_feature_container-members) for GEFeatureContainer ( which is the output type of getFeatures() , the click Event is not defined!
ge.getGlobe replaced with kmlObject: waht is kmlObject here??
About using getDescription, can you have a look on the getTarget, getCurrentTarget ...
(https://developers.google.com/earth/documentation/reference/interface_kml_event)
As I told you, i haven't work with this since a long time.. so I'm not sure this can help you but at least, it's a first track on which you can look!
Please keep me informed! :-)

Update OpenLayers popup

I am trying to update some popups in my map but I am not able to do that.
Firstly I create some markers, and with the next code, I create a popup associated to them. One popup for each marker:
popFeature = new OpenLayers.Feature(markers, location);
popFeature.closeBox = true;
popFeature.popupClass = OpenLayers.Class(OpenLayers.Popup.FramedCloud, {
'autoSize': true
});
popFeature.data.popupContentHTML = "hello";
popFeature.data.overflow = (false) ? "auto" : "hidden";
var markerClick = function (evt) {
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;
OpenLayers.Event.stop(evt);
};
mark.events.register("mousedown", popFeature, markerClick);
After that, I add the new marker to my marker layer.
Everything is fine until here, but, I want to update the popupcontentHTML some time later and I don't know how I can access to that value.
I read OL API but I don't understand how to get it. I am lost about features, events, extensions...
I want to know if I can access to that property and write other word.
I answer myself, maybe it helps other people in future:
for(i = 0; i < map.popups.length; i++){
if(map.popups[i].lonlat.lon == marker.lonlat.lon){
map.popups[i].setContentHTML("new content");
}
}
Content will be refreshed at the moment.