How to get dragged point on the DirectionsRenderer - google-maps

I use google maps for drawing my route. I setup only 2 points (start and end). The problem is that I will have to send the route to the next page.
I know that I can catch event:
google.maps.event.addListener(directionsDisplay, 'directions_changed', function() {
$("#full-route-json").val(encode64(JSON.stringify(directionsDisplay.directions.routes[0])));
});
But it will return all steps.
How to get the data only for my start and end points and dragged point like this:

AFAIK there is no implemented method to access these points(markers).
But these markers are stored inside a property of the DirectionsRenderer-instance.
The following code will give you these detail(please note that this code works now, but it may fail when the API changes)
google.maps.event.addListener(directionsDisplay, 'directions_changed', function() {
var that=this;
setTimeout(function(){//we need a short delay
for(var k in that){//iterate over all properties
if(typeof that[k].markers!='undefined'){//find the desired property
var markers=that[k].markers,arr=[];
for(var i=0;i<markers.length;++i){//collect the data
arr.push(markers[i].position.toString());
}
alert(arr.join(',\n'));
}
}},100)
});

Related

Titanium Alloy - How to run procedure after screen created

I'm trying to update the current location on map view. I get the current location in controller:
var updateCurrentLocation = function updateCurrentLocation(e){
Ti.API.info("Update current location on map");
$.map.setLocation({
latitude: e.coords.latitude,
longitude: e.coords.longitude,
latitudeDelta: 1,
longitudeDelta: 1
});
}
But the problem is that at this time the code run, the map view has not been created yet, so it cannot update the current location.
Can any one suggest some technique to solve this problem?
Thank you!
Are you not creating the map in the same controller? If you are just place the code after the map code, but that is obvious so I will assume you have thought of that.
Why not set the coords to the current user coords when you create the Map?
Worst case scenario, you can use setTimer(, timer ms) to call a function after a set amount of time if you wanted to call the updateCurrentLocation function after 500 milliseconds. This is not ideal.
starting up the map controller
function showMap() {
// create the new controller and pass in the
// model object as an argument 'item'
var ctrl = Alloy.createController('MapView', {
'item' : args.item // <-- pass is information + coords for map
});
setTimeout(function() {
args.photoListTab.open(ctrl.mainWindow);
}, 200);
}
in map controller
// get the photo object from the parameters
var coords = args.item.custom_fields.coordinates[0];
var locationString = args.item.custom_fields.location_address;
// create annotation
var annotation = Alloy.Globals.Map.createAnnotation({
latitude : Number(coords[1]),
longitude : Number(coords[0]),
title : args.item.custom_fields.location_string,
myid : args.item.id
});
complete solution here https://github.com/aaronksaunders/testInClass
Eventually I found there is a event call "complete" on the Map View. So, to do anything that you want to happen after the map loaded, in Map controller, use:
$.map.addEventListener('complete', function(e) {
Ti.API.info("Map controller: on Map complete");
$.trigger('complete', e); // Trigger event for other controller can listen too.
// And you can do other logic here.
});
Reference from Titanium Doc

Can the default behavior of a Google Maps Event be overridden

I am trying create a restriction on the movement of an editable polygon. I want to prevent the inside path from being pulled outside of outer path. I am using Google Maps google.maps.geometry.poly.containsLocation function to check if the new point is within the outer bounds but I can't find a way to stop the action from happening if it is outside.
I have tried returning false but the polygon still goes to the new location
google.maps.event.addListener(poly.getPaths().getArray()[1], 'set_at', function() {
return keepInside(this, arguments[0], arguments[1]);
});
function keepInside(polygon, index, new_point)
{
outer_edge = new google.maps.Polygon({
paths: polygon.getArray(),
});
is_in = google.maps.geometry.poly.containsLocation(new_point,outer_edge);
if(!is_in)
{
return false;
}
return true;
}
You got pretty close with your original code. Instead of returning false, you could set the point back to it's original position. Also, the second argument passed to the set_at listener is not the new point but the old point. Try this:
google.maps.event.addListener(poly.getPaths().getArray()[1], 'set_at', function(index, oldPoint) {
return keepInside(this, index, this.getAt(index), oldPoint);
});
function keepInside(polygon, index, newPoint, oldPoint)
{
outer_edge = new google.maps.Polygon({
paths: polygon.getArray(),
});
if(!google.maps.geometry.poly.containsLocation(newPoint, outer_edge))
{
polygon.setAt(index, oldPoint);
}
}

Bring GoogleMaps InfoWindow to front

I have a GoogleMaps APIv3 application in which multiple InfoWindows can be open at any one time. I would like to be able to bring an obscured InfoWindow to the front of all other InfoWindows if any part of it is clicked - similar to the behaviour of windows in MS Windows OS.
I had thought to add an onclick event handler which increases the z-index of the InfoWindow, but the event handler does not appear to be firing.
ZIndex is a global variable that keeps increasing as InfoWindows are clicked - or thats the theory anyway.
Can anyone help ?
Here is my code:-
var ZIndex=1;
var iw = new google.maps.InfoWindow({ content:contentString });
google.maps.event.addListener(iw, 'click', handleInfoWindowClick(iw) );
function handleInfoWindowClick(infoWindow) {
return function() {
infoWindow.setZIndex(ZIndex++);
}
}
there is no click-event for an infoWindow, it's a little bit more difficult.
you'll need to use an element(not a string) as content for the infowindow, because you need a DOMListener instead a listener for the infowindow-object
when domready-fires, you must apply the click-DOMListener to the anchestor of this content-node that defines the infowindow
The following code will do this for you, add this to your page:
google.maps.InfoWindowZ=function(opts){
var GM = google.maps,
GE = GM.event,
iw = new GM.InfoWindow(),
ce;
if(!GM.InfoWindowZZ){
GM.InfoWindowZZ=Number(GM.Marker.MAX_ZINDEX);
}
GE.addListener(iw,'content_changed',function(){
if(typeof this.getContent()=='string'){
var n=document.createElement('div');
n.innerHTML=this.getContent();
this.setContent(n);
return;
}
GE.addListener(this,'domready',
function(){
var _this=this;
_this.setZIndex(++GM.InfoWindowZZ);
if(ce){
GM.event.removeListener(ce);
}
ce=GE.addDomListener(this.getContent().parentNode
.parentNode.parentNode,'click',
function(){
_this.setZIndex(++GM.InfoWindowZZ);
});
})
});
if(opts)iw.setOptions(opts);
return iw;
}
Instead of google.maps.InfoWindow() you must call now google.maps.InfoWindowZ()
It also returns a genuine InfoWindow, but with the mentioned listener applied to it. It also creates the node from the content when needed.
Demo: http://jsfiddle.net/doktormolle/tRwnE/
Updated version for visualRefresh(using mouseover instead of click) http://jsfiddle.net/doktormolle/uuLBb/

Do not fire 'zoom_changed' event when calling fitBounds function on map

Is there a way to prevent the zoom_change event from being triggered if it occurs due to fitBounds() ?
I am having an issue where I need to do a search on the server from client when there is a zoom change to map but every time I call fitBounds() it causes zoom_change to trigger which causes the client to do another search on the server. I am only interested in zoom_change done by users and not programmatically using fitBounds.
When you do a fitBounds in your program, set a global flag. When the zoom_changed event fires, if the flag is set, clear it, otherwise send your request off to the server.
After many frustrating hours, here is my solution:
var tiles_listener = google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
var zoom_listener = google.maps.event.addListener(map, 'zoom_changed', function() {
reloadMarkers();
});
});
Note that I am calling addListenerOnce for tilesloaded to ensure that the zoome_changed listener is only added once, after the first fitBounds completes.
It's an old question, but it may be useful to others. I had the same problem, zoom_changed been triggered every time I called fitBounds() when adding several markers to a map. What I did was to add the listener to the map_changed event after the map was completely loaded, like this:
google.maps.event.addListener(map, 'tilesloaded', function() {
google.maps.event.addListener(map, 'zoom_changed', function() {
There is another way to do that by removing that that event. I think it would be much easier and cleaner than adding a global variable.
vm.map.events.bounds_changed = function() {
google.map.event.removeListener(zoom_changed);
}
Another way (forgotten to add that):
vm.map.events.bounds_changed = function() {
google.map.event.addEventListener(zoom_changed,function(mapper,eventName,args){});
}
In my app, I may fire off zoom change events programmatically, either via setZoom(), fitBounds(), or setOptions().
MAN = {};
MAN.globalMap = google.maps.Map(document.getElementById('map'));
I then route all programmatic calls to set the zoom through wrapper functions that flip a flag to false before they go on to set the zoom.
MAN.savedZoom = MAN.globalMap.getZoom();
MAN.saveZoomFlag = true;
// we want it to always be true, unless zoom was
// changed programatically.
MAN.setZoom = function setZoom(zoomLevel) {
console.log("won't save that I'm setting zoomLevel to " + zoomLevel);
this.saveZoomFlag = false;
MAN.globalMap.setZoom(zoomLevel);
};
MAN.fitBounds = function fitBounds(bounds) {
console.log("setting bounds, won't save zoomlevel.");
this.saveZoomFlag = false;
MAN.globalMap.fitBounds(bounds);
};
MAN.setOptions = function setOptions(options) {
console.log("setting options, won't save zoomlevel.");
this.saveZoomFlag = false;
MAN.globalMap.setOptions(options);
};
I then declare a listeners. At first I was declaring only the first, and was puzzled that it wasn't working:
google.maps.event.addListener(
MAN.globalMap,
'zoom_changed',
function zoom_changed_listener() {
console.log(
"zoom changed to " +
MAN.globalMap.getZoom() + "; " +
(MAN.saveZoomFlag ? "saving." : "not saving.")
);
if (MAN.saveZoomFlag) {
console.trace("saving");
MAN.savedZoom = MAN.globalMap.getZoom();
}
MAN.saveZoomFlag = true;
}
);
you may also find the idle event helpful, however, if you're just trying to avoid the initial set. See more about the maps events here: https://developers.google.com/maps/documentation/javascript/events
I suppose this should be simple. Have a variable say
var z = map.getZoom(); //scope this variable appropriately(somewhere before you call the fitbounds()
and then after the map.fitbounds() immediately do
map.setZoom(z); //this automatically changes the zoom level back to the previous level

OpenLayers - clear 'map' div

I am using OpenLayers to display dynamically loaded images. The code I am using is:
var map;
function init(strURL) {
map = new OpenLayers.Map('map');
var options = { numZoomLevels: 3,
isBaseLayer: true, };
var graphic = new OpenLayers.Layer.Image(
'City Lights',
strURL + "?sc=page",
new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
new OpenLayers.Size(580, 288),
options
);
// graphic.events.on({
// loadstart: function () {
// OpenLayers.Console.log("loadstart");
// },
// loadend: function () {
// OpenLayers.Console.log("loadend");
// }
// });
var jpl_wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{ layers: "landsat7" }, options);
map.addLayers([graphic, jpl_wms]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToMaxExtent();
}
I am calling this function on a button click event and passing the strURL (sources of the images) at that time. The result is, with each click a different image is loaded and displayed on the web page but is not clearing the previous image. So I 5 different images on the webpage are shown with 5 clicks and so on.
My javascript knowledge is limited, so my apologies if this is a stupid question. How to stop this behavior? Thanks for any assistance.
Also, I didn't quite understand the lines:
var jpl_wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{ layers: "landsat7" }, options);
But I know these lines are needed since I'm getting js error if I remove them.
So currently you are calling init(strURL) with each button click? Divide that code into two parts:
On page load, create map and layer objects
On button click, just update URL of existing image layer. Image layer has setUrl(url) method for that: http://dev.openlayers.org/apidocs/files/OpenLayers/Layer/Image-js.html#OpenLayers.Layer.Image.setUrl
Here is sample, that should explain it: http://jsfiddle.net/mEHrN/6/
About var jpl_wms = ... - it creates WMS layer, that should display Landsat imagery (but that URL doesn't seem to work). If you remove it, remember also to remove it from map.addLayers:
map.addLayers([graphic]);
Probably this was reason, why you got JS error.