Google Maps API - return error if Lat/Lng incorrect - google-maps-markers

I have a Goggle Map displaying markers based on a list being pulled from a database via php. It all works OK but will display a blank grey map page if one of the lng/lats are incorrect.
eg: "510.51356, -0.7015494" rather than "53.8741174, -0.7015494"
I've tried:
var myLatlng = new google.maps.LatLng(510.51356, -0.7015494);
console.log(myLatlng);
Thinking it would return an error but doesn't - it returns an object but no data - but this is the same whether the lng/lat is correct or not.
Is there a way I can stop GoogleMaps from trying to add markers with incorrect lng/lats?
Below is the full code I'm using:
var myLatlng = new google.maps.LatLng(510.51356,-0.7015494);
var markerOptions = {
map: map,
position: myLatlng,
title: “MY LOCATION TITLE”
};
marker_3744 = createMarker_map(markerOptions);
marker_3744.set("content", "<strong>MY LOCATION TITLE</strong><br /><strong>Full address in here”);
google.maps.event.addListener(marker_3744, "click", function(event) {
iw_map.setContent(this.get("content"));
iw_map.open(map, this);
});```

Related

amCharts: Map Recentering after JSON DataSource Despite Previous chart.homeGeoPoint

I'm mapping a series of points with amChart; after loading the data from an external JSON source, the map re-centers instead of staying at the point I'd set earlier with chart.homeGeoPoint.
I believe I need to use an event listener and set the homeGeoPoint after the map renders the points... but I'm at a bit of a loss; the only events I've found are from dataSource.events, and those appear to be related to fetching/parsing the JSON, as opposed to rendering the map.
// Create map instance
var chart = am4core.create("chartdiv", am4maps.MapChart);
// Set map definition
chart.geodata = am4geodata_region_world_northAmericaLow;
// Set projection
chart.projection = new am4maps.projections.Miller();
// Initial Position / Zoom
chart.homeZoomLevel = 2.6;
chart.homeGeoPoint = {
latitude: 39,
longitude: -96.2456
};
// Series for World map
var worldSeries = chart.series.push(new am4maps.MapPolygonSeries());
worldSeries.useGeodata = true;
// Markers
// Create image series
var imageSeries = chart.series.push(new am4maps.MapImageSeries());
// Create a circle image in image series template so it gets replicated to all new images
var imageSeriesTemplate = imageSeries.mapImages.template;
var circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 5;
circle.fill = am4core.color("#116ad6");
circle.stroke = am4core.color("#FFFFFF");
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = "{title}";
// Set property fields
imageSeriesTemplate.propertyFields.latitude = "latitude";
imageSeriesTemplate.propertyFields.longitude = "longitude";
imageSeriesTemplate.propertyFields.url = "url";
// Load data
imageSeries.dataSource.url = "/foo/map-points.php";
imageSeries.dataSource.parser = new am4core.JSONParser();
imageSeries.dataSource.parser.options.emptyAs = 0;
// Center after render
imageSeries.dataSource.events.on("done", function(ev) {
// This doesn't work - perhaps it is firing too early?
chart.homeGeoPoint = {
latitude: 39,
longitude: -96.2456
};
});
By request, here is a foo.json file for expirmenting with.
[{"title":"ISP","url":"\/airport\/kisp\/","latitude":40.7952,"longitude":-73.1002},{"title":"AEX","url":"\/airport\/kaex\/","latitude":31.3274,"longitude":-92.5486}]
What do I need to do to make sure the map stays centered on my desired location after the JSON data are loaded and rendered?
I've created an issue on GitHub in regards to why the map re-positions on the MapImageSeries' dataSource load and how to better work with that. (If you've a GitHub account, please subscribe to the issue.)
In the meantime, presuming the first time your dataSource gets its data that the user hasn't moved the map and we want to maintain homeGeoPoint as the current center, we can chain events to achieve that.
When the dataSource is "done" with its data, that doesn't necessarily imply anything has been done on the actual map level. The data still needs to propagate to the MapImageSeries, that still needs to create MapImages per data item, have the data validated/parsed there, and for whatever reason the map position shifts around. So the first time that happens (using events.once instead of events.on), we then listen for the MapImageSeries' "datavalidated" event also only one time (because "datavalidated" will have run before this, e.g. as soon as you create the MapImageSeries, if no data is supplied or it's taking some time, it will still run the event and the "inited" event, i.e. I guess you can say the series itself will successfully render nothing).
And to center the map we use chart.goHome(0);, this method will zoom to your homeGeoPoint and homeZoomLevel, the 0 is for how long the animation duration should run, i.e. just do the work, don't animate.
So all that together will look something like this:
// Center after render
imageSeries.dataSource.events.once("done", function(ev) {
imageSeries.events.once("datavalidated", function() {
chart.goHome(0);
});
});
Here's a demo:
https://codepen.io/team/amcharts/pen/239bfdc8689c65468df32d71b29759b8
Even though the map does re-position once the MapImageSeries loads, then it re-centers with the above code, I haven't actually seen the map shift at all anymore. So it looks to me the above code is doing the job of maintaining the homeGeoPoint. Let me know if that is still the case once implemented in your application.

Refresh Google Maps Markers (Change Icon) through Django & JSON

Hi there StackOverflow!
I have been building a web interface to display the communication states of the various elements on my network. I am down to the last bit that I have been putting off as I knew it was going to be a struggle.
For reasons of awesomeness I wanted to have a geographical layout of the various equipment with their current states and therefore decided to implement the googlemaps api to help me.
The Idea is that via ajax, the map updates the markers (their icon) every 4 seconds with their communication state (via django, ajax & JSON).
The script I have based this on is based on Beetroot-Beetroot's answer from this thread.
Where instead of icon, he updates the location of the markers.
I have adapted this so that the icons change from the first to the second state (e.g. On and Off). As seen in this JSFiddle
Now ,I realize that this is using the "Simulated Ajax" as Beetroot-Beetroot called it rather than the continually updating version that has been commented out (Pulls in a Json File).
I have been trying to use a view & template in Django to create a HTML file that contains the new information to be put into "var Locs" and tried importing it. This is not working, and even if it did would be incredibly messy / frowned upon.
So, my next plan of action was just to make a JSON file to update the "Loc" array within the script.
My Question finally, Through Django, how can I create JSON file that the script can pull in and updates the "var Loc" array, with the new information?
Here is the HTML equivalent of the JSON file, (Uses Django tags to decide what each value would be if/else, etc).
{% load staticfiles %}
var Locs = {
1: { info:'Updated', lat:40.538834, lng:-74.555049, icon: {% if element1.communication_state == 'CS_AVAILABLE' %}'http://i.imgur.com/DCU6Bzc.png'{% else %}'http://i.imgur.com/8bJFdFV.png'{% endif %} },
2: { info:'Updated', lat:40.543127, lng:-74.606598, icon: {% if element2.communication_state == 'CS_AVAILABLE' %}'http://i.imgur.com/DCU6Bzc.png'{% else %}'http://i.imgur.com/8bJFdFV.png'{% endif %} },
3: { info:'Updated', lat:40.544770, lng:-74.632273, icon: {% if element3.communication_state == 'CS_AVAILABLE' %}'http://i.imgur.com/DCU6Bzc.png'{% else %}'http://i.imgur.com/8bJFdFV.png'{% endif %} },
4: { info:'Updated', lat:40.489954, lng:-74.586175, icon: {% if element4.communication_state == 'CS_AVAILABLE' %}'http://i.imgur.com/DCU6Bzc.png'{% else %}'http://i.imgur.com/8bJFdFV.png'{% endif %} },
};
Once I can get a valid JSON file/url to the script it should work, the problem I'm having is that I have no idea how to generate a correctly formatted JSON file through Django.
This is what I assume will be the final script for the maps once I am able to generate the JSON file.
var locations = {};
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 11,
center: new google.maps.LatLng(40.5000, -74.6203),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infowindow = new google.maps.InfoWindow();
var auto_remove = true;//When true, markers for all unreported locs will be removed.
function setMarkers(locObj) {
if(auto_remove) {
//Remove markers for all unreported locs, and the corrsponding locations entry.
$.each(locations, function(key) {
if(!locObj[key]) {
if(locations[key].marker) {
locations[key].marker.setMap(null);
}
delete locations[key];
}
});
}
$.each(locObj, function(key, loc) {
if(!locations[key] && loc.lat!==undefined && loc.lng!==undefined) {
//Marker has not yet been made (and there's enough data to create one).
//Create marker
loc.marker = new google.maps.Marker({
position: new google.maps.LatLng(loc.lat, loc.lng),
icon: loc.icon,
map: map
});
//Attach click listener to marker
google.maps.event.addListener(loc.marker, 'click', (function(key) {
return function() {
if(locations[key]) {
infowindow.setContent(locations[key].info);
infowindow.open(map, locations[key].marker);
}
}
})(key));
//Remember loc in the `locations` so its info can be displayed and so its marker can be deleted.
locations[key] = loc;
}
else if(locations[key] && loc.remove) {
//Remove marker from map
if(locations[key].marker) {
locations[key].marker.setMap(null);
}
//Remove element from `locations`
delete locations[key];
}
else if(locations[key]) {
//Update the previous data object with the latest data.
$.extend(locations[key], loc);
locations[key].marker.setIcon(loc.icon);
if(loc.lat!==undefined && loc.lng!==undefined) {
//Update marker position (maybe not necessary but doesn't hurt).
locations[key].marker.setPosition(
new google.maps.LatLng(loc.lat, loc.lng)
);
}
//locations[key].info looks after itself.
}
});
}
var ajaxObj = {//Object to save cluttering the namespace.
options: {
url: MAPS_JSON,//The resource that delivers loc data.
dataType: "json"
},
delay: 4000,//(milliseconds) the interval between successive gets.
errorCount: 0,//running total of ajax errors.
errorThreshold: 5,//the number of ajax errors beyond which the get cycle should cease.
ticker: null,//setTimeout reference - allows the get cycle to be cancelled with clearTimeout(ajaxObj.ticker);
get: function() { //a function which initiates
if(ajaxObj.errorCount < ajaxObj.errorThreshold) {
ajaxObj.ticker = setTimeout(getMarkerData, ajaxObj.delay);
}
},
fail: function(jqXHR, textStatus, errorThrown) {
console.log(errorThrown);
ajaxObj.errorCount++;
}
};
//Ajax master routine
function getMarkerData() {
$.ajax(ajaxObj.options)
.done(setMarkers) //fires when ajax returns successfully
.fail(ajaxObj.fail) //fires when an ajax error occurs
.always(ajaxObj.get); //fires after ajax success or ajax error
}
setMarkers(locs);//Create markers from the initial dataset served with the document.
ajaxObj.get();//Start the get cycle.
Thanks for any help, I realize this is a long winded question.
I can Provide links to my models.py, views.py, urls.py, etc if that would help.
Didn't realize you could make a template .json file like you could a .html file. All working correctly now, and looking at this question again it made no sense...

fineuploader - Read file dimensions / Validate by resolution

I would like to validate by file dimensions (resolution).
on the documentation page there is only information regarding file name and size, nothing at all in the docs about dimensions, and I also had no luck on Google.
The purpose of this is that I don't want users to upload low-res photos to my server. Thanks.
As Ray Nicholus had suggested, using the getFile method to get the File object and then use that with the internal instance object qq.ImageValidation to run fineuploader's validation on the file. A promise must be return because this proccess is async.
function onSubmit(e, id, filename){
var promise = validateByDimensions(id, [1024, 600]);
return promise;
}
function validateByDimensions(id, dimensionsArr){
var deferred = new $.Deferred(),
file = uploaderElm.fineUploader('getFile', id),
imageValidator = new qq.ImageValidation(file, function(){}),
result = imageValidator.validate({
minWidth : dimensionsArr[0],
minHeight : dimensionsArr[1]
});
result.done(function(status){
if( status )
deferred.reject();
else
deferred.resolve();
});
return deferred.promise();
}
Remained question:
Now I wonder how to show the thumbnail of the image that was rejected, while not uploading it to the server, the UI could mark in a different color as an "invalid image", yet the user could see which images we valid and which weren't...
- Update - (regarding the question above)
While I do not see how I could have the default behavior of a thumbnail added to the uploader, but not being uploaded, but there is a way to generate thumbnail manually, like so:
var img = new Image();
uploaderElm.fineUploader("drawThumbnail", id, img, 200, false);
but then I'll to create an item to be inserted to qq-upload-list myself, and handle it all myself..but still it's not so hard.
Update (get even more control over dimensions validation)
You will have to edit (currently) the qq.ImageValidation function to expose outside the private function getWidthHeight. just change that function deceleration to:
this.getWidthHeight = function(){
Also, it would be even better to change the this.validate function to:
this.validate = function(limits) {
var validationEffort = new qq.Promise();
log("Attempting to validate image.");
if (hasNonZeroLimits(limits)) {
this.getWidthHeight().done(function(dimensions){
var failingLimit = getFailingLimit(limits, dimensions);
if (failingLimit) {
validationEffort.failure({ fail:failingLimit, dimensions:dimensions });
}
else {
validationEffort.success({ dimensions:dimensions });
}
}, validationEffort.success);
}
else {
validationEffort.success();
}
return validationEffort;
};
So you would get the fail reason, as well as the dimensions. always nice to have more control.
Now, we could write the custom validation like this:
function validateFileDimensions(dimensionsLimits){
var deferred = new $.Deferred(),
file = this.holderElm.fineUploader('getFile', id),
imageValidator = new qq.ImageValidation(file, function(){});
imageValidator.getWidthHeight().done(function(dimensions){
var minWidth = dimensions.width > dimensionsLimits.width,
minHeight = dimensions.height > dimensionsLimits.height;
// if min-width or min-height satisfied the limits, then approve the image
if( minWidth || minHeight )
deferred.resolve();
else
deferred.reject();
});
return deferred.promise();
}
This approach gives much more flexibility. For example, you would want to have different validation for portrait images than landscape ones, you could easily identify the image orientation and run your own custom code to do whatever.

Google Maps Places api, how do I get the standard infowindow content from a marker

New to Google Maps, and not a script expert either. Thanks in advance for any help you can provide.
I am putting a google map on a page of store locations. I have managed to get the map to display the marker I want for the store location using the search. Now I want the infoWindow to be populated to look like the standard google window. But using the code I was able to find on the places library, the results show up unformatted with no line breaks, and shows errors if a piece if information is missing, etc... I have searched and didn't find anything that helped - so please forgive me if this is already answered - and I have read through the google places library numerous times so either I am dense or they just don't address this specific question.
The user will click on a store location listed on the page and I want to show them the map with the one marker (through search I think I can get that to happen) and I want the store information show up in the infoWindow when they click on the marker (preferably I would like the infoWindow already opened but I couldn't find anything on that either). Since I am new to the site I can't post an image of the infoWindow so hopefully it's not needed. Like the google's map website, I want a nicely formatted name, the reputation stars, a formatted address, phone number and website, along with a picture of the business if it exists. The example I use below is for a business where all of this information exists within google. The code I currently have for the map is included.
Please don't reply simply to direct me back to the places library; if that's all you have then it is not helping. I need some clarification and ideally an example. Thanks.
<script type="text/javascript">
var map;
var service;
var infowindow;
function initialize() {
var mvale = new google.maps.LatLng(40.708572,-74.017385);
map = new google.maps.Map(document.getElementById('map_canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: mvale,
zoom: 16
});
var request = {
location: mvale,
radius: '500',
keyword: "Michelle Vale"
};
infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.search(request, callback);
}
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name + place.rating + place.vicinity +
place.formatted_address + place.website );
infowindow.open(map, this);
});
}
function openInfoWindow(id){return true;}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
I finally located some code for formatting the infoWindow in another post where they were answering a question about removing the border for the infoWindow.
Here is my example :
infowindow.setContent('<span style="padding: 0px; text-align:left" align="left"><h5>' + place.name + ' ' + place.rating
+ '</h5><p>' + place.formatted_address + '<br />' + place.formatted_phone_number + '<br />' +
'<a target="_blank" href=' + place.website + '>' + place.website + '</a></p>' ) ;
I also figured out how to use the getDetails function described in the Places Library
I still don't know how to get the rating information (I'm using the tag but it gives an error), how to retrieve the image for the location, nor how to eliminate the "undefined" error from appearing.
Last element is to have the infoWindow open when the map loads... I saw a post about it but couldn't get it to work.

How to delete markers from google map before painting new ones on idle event

I'm drawing markers on a google map after it's been panned or zoomed.
If the viewport has not totally changed than the markers that appeared before the move and should still appear after it are being painted on top of themselves again and again.
I know I have to delete all the markers from the map before the new markers are painted and I know I should be using marker.setMap(null);.
I just don't know how and where to fit it in my code.
google.maps.event.addListener(map, 'idle', showMarkers);
function showMarkers(){
// get viewport bounds
var southWestLat = map.getBounds().getSouthWest().lat();
var southWestLng = map.getBounds().getSouthWest().lng();
var northEastLat = map.getBounds().getNorthEast().lat();
var northEastLng = map.getBounds().getNorthEast().lng();
var marker;
$.ajax({
type: "POST",
url: "markers.php",
dataType: "json",
data: ({'southWestLat' : southWestLat , 'southWestLng' : southWestLng , 'northEastLat' : northEastLat , 'northEastLng' : northEastLng}),
success: function(coordinatesMap){
for (var id in coordinatesMap){
if (coordinatesMap.hasOwnProperty(id)){
marker = new google.maps.Marker({
position: new google.maps.LatLng(coordinatesMap[id].lat,coordinatesMap[id].lng),
map: map
});
}
}
}
});
}
For performance reasoning you don't want to clear all the markers; Only the ones no longer on the map. This can be accomplished by storing the marker in an array or object. On 'success' you want to check if a marker is already at the lat lng using your array/object. If so then don't add a new one, if not then add it. After you have finished processing the markers in the ajax request, remove the ones no longer visible on the map.

Resources