I am building an app using javascript, google maps v2 and ESRI 10.1.
I have a DynamicMapServiceLayer and a single layer in my ESRI map service. I dynamically show or hide features on the layer using the ESRI setLayerDefinitions function based on filter values selected by the user at runtime.
When the user clicks on the map I use the ESRI IdentifyTask object to find what the user clicked on. I want to show an infowindow for the feature the user clicked on. My code is sort of working but it opens infowindows for features that are filtered out (not visible) on the layer.
How can I check to see if the user clicked on a visible feature and stop opening infowindows for hidden features? Or how can I get IdentifyTask to stop including hidden features in the response object it returns?
This is my identifyParameters task invoke set up
// set the identify parameters
var identifyParameters = new esri.arcgis.gmaps.IdentifyParameters();
identifyParameters.geometry = latLng; // where the user clicked on the map
identifyParameters.tolerance = 3;
identifyParameters.layerIds = [OUTAGES_LAYER];
identifyParameters.layerOption = 'all';
identifyParameters.bounds = map.getBounds();
var mapSize = map.getSize();
identifyParameters.width = mapSize.width;
identifyParameters.height = mapSize.height;
// execute the identify operation
identifyTask.execute(identifyParameters, function(response, error) {
if (hasErrorOccurred(error)) return;
addResultToMap(response, latLng);
});
UPDATE
I have upgraded to Google maps v3. Now the identify parameters support passing layerdef information as follows below. For example I can limit the identify operation to those features where FISCAL_YEAR = 2014. My problem is solved.
function identify(evt) {
dynamicMap.getMapService().identify({
'geometry': evt.latLng,
'tolerance': 3,
'layerIds': [12],
'layerOption': 'all',
'layerDefs': {12 : 'FISCAL_YEAR = 2014'},
'bounds': map.getBounds(),
'width': map.getDiv().offsetWidth,
'height': map.getDiv().offsetHeight
}, function(results, err) {
if (err) {
alert(err.message + err.details.join('\n'));
} else {
addResultToMap(results, evt.latLng);
}
});
}
Related
I’m using the Google Maps Geocode API to read an address and place a marker on the map. This is how I’m using it :
for(let marker of markers){
this.geocoder = new google.maps.Geocoder();
this.geocoder.geocode({
'address': marker["address"]
}, (results,status) => {
var position = new google.maps.LatLng(results[0].geometry.location.lat(),results[0].geometry.location.lng()); // error pointing to this line
this.personMarker = new google.maps.Marker({position: position, title: marker.name, markerInfo: marker, map : this.map , icon : marker.imageurl});
google.maps.event.addListener(this.personMarker, 'click', () => {
this.showCard = true;
this.org = marker.organization;
this.gig = marker.gig;
this.location = marker["address"];
this.image = marker.imageurl;
this.ngoData = marker;
this.ownerusername = marker.ownerusername;
});
});
}
I get this error: ‘Cannot read property ‘0’ of null’ pointing to the line I’ve shown with a comment in the code snippet.Just don’t know what’s causing that error because I’m accessing the ‘results’ parameter only inside the callback. console.log(results) sometimes returns 'null' for the first iteration of the loop, followed by proper results for the rest of the iterations, or proper results for all iterations. I don't understand this inconsistent behavior, but I do know that I get this error usually when the intervals between me clicking and loading the map again is short.
I know that all the addresses are valid because sometimes all my markers appear on the map and the error doesn't turn up
I write Xamarin UITest for Android app. In the app uses google map. Help me please, how to click on a marker on the map?
markers are not showing within the tree of views, my guess is that they're drawn on screen within the map framelayout.
given that the marker is at the center of the map, you could tap it using something like this :
(with a map fragment of id "map")
var map = app.Query("map")
var middleX = (map.First().Rect.Width + map.First().Rect.X) / 2
var middleY = (map.First().Rect.Height + map.First().Rect.Y) / 2
app.TapCoordinates(middleX, middleY)
but I think that's all you can do within the map itself.
If you're building the app yourself, I suggest checking out backdoor methods. These are methods that you can build into the app and then call from the test.
There are plenty of examples for Obj-C and Java apps. Here's an example for C# backdoor methods, which you'd put in either your MainActivity or AppDelegate classes: http://danatxamarin.com/2015/05/07/configuring-backdoor-methods-in-c-for-xamarin-test-cloud/
I'd create a backdoor to return whatever data you need about the map, and then use app.Invoke("myNewMethod"); which will return a string (which could be json). This string could contain screen coordinates, which you could then pass to app.TapCoordinates(x, y);.
The short answer is, Google Maps on Android doesn't really expose objects in an automatable way, so the second best option is backdoors.
If you have a custom renderer for android you can simulate a click inside, the main trick is to access markers inside the renderer:
var field = this.GetType().BaseType.GetField("_markers", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var markers = (List<Marker>)field.GetValue(this);
now for any element in markers as you cannot send a real click you can just simulate it. Pasting the code from my live project:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "ExternalClickedPin")
{
if (FormsControl.ExternalClickedPin != null)
{
var pin = Map.Pins.FirstOrDefault(x => x.MarkerId == FormsControl.ExternalClickedPin.MarkerId);
if (pin != null)
{
var field = this.GetType().BaseType.GetField("_markers", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var hiddenMarkers = (List<Marker>)field.GetValue(this);
var marker = hiddenMarkers.FirstOrDefault(x => x.Id == pin.MarkerId.ToString());
if (marker != null)
{
//simulating click
//1 invoke clicked event
// pin.SendMarkerClick(); // <- if needed for tests
//2 show info on map
marker.ShowInfoWindow(); //just what i was needing
//3 center pin on map
//Map.MoveToRegion(...); <- not here, im calling this from Forms subclassed control
}
}
FormsControl.ExternalClickedPin = null;
}
}
}
I'm creating a ASP.NET MVC3 website using a Google Maps API V3 with a lot of markers. Each marker has an InfoWindow with some information about this place.
I wish each marker have a direct link to access my website directly on this marker, like http://www.mywebsite/1589. So the user could access the website with the map centered on marker 1589 and its InfoWindows would be open.
The markers are already on the map and their InfoWindow are already displaying informations, but I have no idea how to create a direct link to the marker... Could anybody help me ?
Thanks in advance
The key pieces are:
parse the query string
// skip the first character, we are not interested in the "?"
var query = location.search.substring(1);
// split the rest at each "&" character to give a list of "argname=value" pairs
var pairs = query.split("&");
for (var i=0; i<pairs.length; i++) {
// break each pair at the first "=" to obtain the argname and value
var pos = pairs[i].indexOf("=");
var argname = pairs[i].substring(0,pos).toLowerCase();
var value = pairs[i].substring(pos+1).toLowerCase();
// process each possible argname - use unescape() if theres any chance of spaces
if (argname == "id") {id = unescape(value);}
if (argname == "marker") {index = parseFloat(value);}
}
open the infowindow after loading the markers, if a parameter is passed
// ========= If a parameter was passed, open the info window ==========
if (id) {
if (idmarkers[id]) {
google.maps.event.trigger(idmarkers[id],"click");
} else {
alert("id "+id+" does not match any marker");
}
}
if (index > -1) {
if (index < gmarkers.length) {
google.maps.event.trigger(gmarkers[index],"click");
} else {
alert("marker "+index+" does not exist");
}
}
you might also want the "link to" functionality in this example, which sets up the query string
I've been looking at the example on:
http://code.google.com/apis/maps/documentation/javascript/examples/places-autocomplete.html
and have decided to incorporate it into my site.
Is it possible to limit the addresses to UK addresses only?
Try this:
var input = document.getElementById('searchTextField');
var options = {
types: ['(cities)'],
componentRestrictions: {country: 'tr'}//Turkey only
};
var autocomplete = new google.maps.places.Autocomplete(input,options);
You can't strictly/hard limit the locations that it finds, although there is a feature request in the system to do so, but you can set a 'bias' on the results. It's passed in as an argument to the autocomplete method as a google maps bounds object. Autocomplete will then favor locations within those boundaries. Note, however, that since this isn't a hard boundary, if there are matches for the search outside the boundaries it will return those.
From my usage it seems a bit buggy and can use some improvement - especially considering that anything outside your boundary is not tagged by proximity at all, so something one block outside the boundary is just as likely to show as something 1000 miles outside, so make sure you play around with getting the boundaries working right.
You can intercept the JSONP results that are returned by the google.maps.places.Autocomplete functionality and use them as you see fit, such as to limit by country and display the results.
Basically you redefine the appendChild method on the head element, and then monitor the javascript elements that the Google autocomplete code inserts into the DOM for JSONP. As javascript elements are added, you override the JSONP callbacks that Google defines in order to get access to the raw autocomplete data.
It's a bit of a hack, here goes (I'm using jQuery but it's not necessary for this hack to work):
//The head element, where the Google Autocomplete code will insert a tag
//for a javascript file.
var head = $('head')[0];
//The name of the method the Autocomplete code uses to insert the tag.
var method = 'appendChild';
//The method we will be overriding.
var originalMethod = head[method];
head[method] = function () {
if (arguments[0] && arguments[0].src && arguments[0].src.match(/GetPredictions/)) { //Check that the element is a javascript tag being inserted by Google.
var callbackMatchObject = (/callback=([^&]+)&|$/).exec(arguments[0].src); //Regex to extract the name of the callback method that the JSONP will call.
var searchTermMatchObject = (/\?1s([^&]+)&/).exec(arguments[0].src); //Regex to extract the search term that was entered by the user.
var searchTerm = unescape(searchTermMatchObject[1]);
if (callbackMatchObject && searchTermMatchObject) {
var names = callbackMatchObject[1].split('.'); //The JSONP callback method is in the form "abc.def" and each time has a different random name.
var originalCallback = names[0] && names[1] && window[names[0]] && window[names[0]][names[1]]; //Store the original callback method.
if (originalCallback) {
var newCallback = function () { //Define your own JSONP callback
if (arguments[0] && arguments[0][3]) {
var data = arguments[0][4]; //Your autocomplete results
//SUCCESS! - Limit results here and do something with them, such as displaying them in an autocomplete dropdown.
}
}
//Add copy all the attributes of the old callback function to the new callback function. This prevents the autocomplete functionality from throwing an error.
for (name in originalCallback) {
newCallback[name] = originalCallback[name];
}
window[names[0]][names[1]] = newCallback; //Override the JSONP callback
}
}
//Insert the element into the dom, regardless of whether it was being inserted by Google.
return originalMethod.apply(this, arguments);
};
James Alday is correct:
http://code.google.com/apis/maps/documentation/javascript/places.html#places_autocomplete
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(49.00, -13.00),
new google.maps.LatLng(60.00, 3.00));
var acOptions = {
bounds: defaultBounds,
types: ['geocode']
};
it is somewhat annoying as searching for Durham gives Durham, North Carolina as the second result, regardless of how you try to persuade it to region bias - you can set it to viewport map bounds and it'll still try to suggest NC state... The jQuery solution can be found here, but doesn't seem to give as many results as the v3 API.
http://code.google.com/p/geo-autocomplete/
The best way you would go about doing this, is to query the places api yourself and appending the queried string with your country. Or, of course, use the geo-autocomplete jQuery plugin.
Just change the google domain for the maps to your country domain and it will automatically search within your country only:
So:
http://maps.google.com/maps/api/geocode/xml?address={0}&sensor=false&language=en
To:
http://maps.google.nl/maps/api/geocode/xml?address={0}&sensor=false&language=nl
Try something like this.
// Change Bangalore, India to your cities boundary.
var bangaloreBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(12.864162, 77.438610),
new google.maps.LatLng(13.139807, 77.711895));
var autocomplete = new google.maps.places.Autocomplete(this, {
bounds: bangaloreBounds,
strictBounds: true,
});
autocomplete.addListener('place_changed', function () {
});
I find that if you set the map to roughly where you want then set bounds to it, the search finds places in that area first. You do not to physically show the map.
It works better than giving random overseas addresses first, setting to country does not work.
The code for autocomplete to get latln is:
<div id="map_canvas"></div>
<input type="text" name="location" id="location" placeholder="Type location...">
<input type="text" name="loc_latitude" id="latitude">
<input type="text" name="loc_longitude" id="longitude">
and the JS is:
$(document).ready(function () {
var mapOptions = {
center: new google.maps.LatLng(52.41041560, -1.5752999),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
var autocomplete;
autocomplete = new google.maps.places.Autocomplete((document.getElementById(searchInput)), {
types: ['geocode'],
});
autocomplete.bindTo('bounds', map);
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var near_place = autocomplete.getPlace();
document.getElementById('latitude').value = near_place.geometry.location.lat();
document.getElementById('longitude').value = near_place.geometry.location.lng();
});
});
$(document).on('change', '#'+searchInput, function () {
document.getElementById('latitude').value = '';
document.getElementById('longitude').value = '';
});
Not exactly what you asked for but it works for me.
I want let user mark their position in our google maps application and then save it to our database, then it can be showed in our google maps application in the next time.
If you want to save the position where the user clicked you can use a "click" listener to get the latitude and longitude of the click with code like this then send it to your server using an Ajax style call where it can be stored in the database.
var clickListener = GEvent.addListener(map,"click",
function (overlay,latlng,overlaylatlng) {
alert(latlng);
});
This code is for v2 of the Google Maps API. Version 3 should have something similar.
An options is to try geolocation first and let the browser pinpoint them. If the browser doesn't support geolocation or an error occurs you can fall back onto them manually adding their position.
var geolocation = null; // holds the latlng object
navigator.geolocation.getCurrentPosition( geolocation_success_init, geolocation_error_init, {enableHighAccuracy: false, timeout: 10000} );
function geolocation_success_init( position ) {
geolocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
initialize_map();
}
function geolocation_error_init( error ){
initialize_map();
}
when you create your map check for geolocation
if ( geolocation ) {
marker = new google.maps.Marker({
position: geolocation,
map:.map,
title: "Your Location"
});
}