Bing Map Drawing Tool Module - events - javascript

I'm using Bing Map Ajax Control V7 for test / learning.
I created a few pushpins with infobox, and added events:
function InsertEvent(mark, infoBox)
{
var obj = {marker : {}, infoWind : {}};
obj.marker.entity = mark;
obj.marker.eID = Microsoft.Maps.Events.addHandler(mark, "click", function(e) {toggleInfo(e, infoBox, true)});
obj.infoWind.entity = infoBox;
obj.infoWind.eID = Microsoft.Maps.Events.addHandler(infoBox, "mouseleave", function(e) {toggleInfo(e, infoBox, false)});
eventsID.push(obj);
}
So, these events work well, until I add DrawningToolModule to map.
function GetMap()
{
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
{credentials: "My extra top secret Bing Map Key",
center: new Microsoft.Maps.Location(51.201547622680664, 16.16974449157715), zoom: 15 });
Microsoft.Maps.loadModule('Microsoft.Maps.Search', { callback: searchModuleLoaded });
Microsoft.Maps.registerModule("DrawingToolsModule", "DrawingToolsModule/DrawingToolsModule.js");
Microsoft.Maps.loadModule("DrawingToolsModule", { callback: function () {
drawTools = new DrawingTools.DrawingManager(map, {toolbarContainer : document.getElementById("toolbarContainer")});
}
});
}
After loading data, pushpins reaction on click is fine.
After adding custom pushpins by DrawingTool - events are fine.
After drawing any shape (polygon, polyfil, circle) - my events for pushpins aren't invoking.
I added a function helper to check if event is still available:
function showEventsCount()
{
alert("Registered events: " + eventsID.length + "\nFirst entity has click event: " +
Microsoft.Maps.Events.hasHandler(eventsID[0].marker.entity, "click") /*map.entities.getLength()*/);
}
And in result I get true.
Is this a bug with blocking events, or am I missing something?

The likely issue is that your polygon is above your pushpins thus blocking the click event or there is an issue. Alternatively there is an EntityCollection above the pushpins that has the polygons in them. This is a known issue with Bing Maps v7. Try flatting the way the map renders polygons with the following code:
map.getMode().setOptions({drawShapesInSingleLayer: true });

Related

Bing Maps v8 - Invoke Click Event on PushPin

Once i load the Bing map with multiple pushpin with infobox. I have added click Here anchor tag on HTML with specific pushpin index to display infobox on javascript click event. Somehow it's not working for me.
I do see Invoke event is being supported in v8
Here is the fiddle https://jsfiddle.net/pakpatel/9dc4oxfk/2/
var map, infobox;
map = new Microsoft.Maps.Map('#myMap', {
credentials: ''
});
//Create an infobox at the center of the map but don't show it.
infobox = new Microsoft.Maps.Infobox(map.getCenter(), {
visible: false
});
//Assign the infobox to a map instance.
infobox.setMap(map);
//Create random locations in the map bounds.
var randomLocations = Microsoft.Maps.TestDataGenerator.getLocations(5, map.getBounds());
for (var i = 0; i < randomLocations.length; i++) {
var pin = new Microsoft.Maps.Pushpin(randomLocations[i]);
//Store some metadata with the pushpin.
pin.metadata = {
title: 'Pin ' + i,
description: 'Discription for pin' + i
};
//Add a click event handler to the pushpin.
Microsoft.Maps.Events.addHandler(pin, 'click', pushpinClicked);
//Add pushpin to the map.
map.entities.push(pin);
}
function pushpinClicked(e) {
//Make sure the infobox has metadata to display.
if (e.target.metadata) {
//Set the infobox options with the metadata of the pushpin.
infobox.setOptions({
location: e.target.getLocation(),
title: e.target.metadata.title,
description: e.target.metadata.description,
visible: true
});
}
}
function showInfoboxByKey(Key) {
//Look up the pushpin by gridKey.
var selectedPin = map.entities.get(gridKey);
//Show an infobox for the cluster or pushpin.
Microsoft.Maps.Events.invoke(selectedPin, "click");
}
<script type='text/javascript'
src='http://www.bing.com/api/maps/mapcontrol?callback=GetMap'
async defer></script>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
<a href='javascript:void(0);' onclick='showInfoboxByKey(3);'> Click Here </a>
The issue is you haven't passed in any event arguments when you invoked the event. As such the event handler doesn't get past your if statement and thus doesn't do anything. See the documentation here and you will notice that you need to provide the event arguments: https://msdn.microsoft.com/en-us/library/mt750279.aspx
That said, I'm not a fan of the approach being taken in your app here. If you simply want to get this working quick an easy, replace your invoke line of code with this:
pushpinClicked({e:{target: selectedPin }});
I highly recommend adding your pushpins to a layer and adding your click event to the layer. This greatly reduces the complexity of the event system and has a small performance boast.

Google Maps API v3 binding events to multiple maps

I've got a page with two Google maps on, using the v3 API. Currently they have one pin each, with the same lat & long set for each pin, although one of the maps will have other pins added at a later date (when I can get this to work!) The maps are generated by looping through an object, so further maps can be added simply if needed.
What I am trying to do is bind the bounds_changed event once to both maps, to run map.setZoom() after map.fitBounds() has been run. The event, however, only binds to the last map to be set up, so does not reset the zoom on the first map.
Link to JSFiddle replicating the issue: http://jsfiddle.net/pkhb8mvz/7/
(For a more clear example of what the event is being bound to, change the event to listen on click rather than bounds_changed then try clicking on the first map and watch the zoom level change on the second map)
Any help greatly appreciated!
The problem is that the map variable is being redefined on each iteration of your loop, so by the time your event listener callback runs it will operate on the second google.maps.Map object. The simplest solution is to capture the value of the map variable on each iteration using a closure, like so:
(function (map) {
var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function () {
if (!opts.center) {
map.setZoom(opts.zoom);
};
});
}) (map);
I forked your JSFiddle to demonstrate the idea: https://jsfiddle.net/e8qbr8qL/
Created this fiddle that works based on this answer https://stackoverflow.com/a/5839041/2321666.
Apart from the function you need to add, your map variable should be an array so that there is one instance of each map.
map[i] = new google.maps.Map($(maps[i].mapElement)[0], opts);
If you need any explanation of the code please ask, but i think there is enough info about javascript closures in the post added.
You can't add a listener to multiple maps unless you keep references to all of them, currently you are only keeping a reference to the last map created.
// use function closure to associate the map with its bounds listener
addBoundsListener(map, opts, bounds);
map.fitBounds(bounds);
}
function addBoundsListener(map, opts, bounds) {
// If no center option has been specified, center the map to
// contain all pins and reset the zoom
var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function () {
if (!opts.center) {
map.setZoom(opts.zoom);
}
});
}
updated fiddle
code snippet:
var maps = {
"propertyLocation": {
"mapElement": "#map1",
"options": {
"zoom": 10,
"streetViewControl": false
},
"pins": [{
"title": "Test 1",
"lat": "52.1975331616",
"long": "0.9771180153"
}]
},
"localArea": {
"mapElement": "#map2",
"options": {
"zoom": 14,
"streetViewControl": false
},
"pins": [{
"title": "Test 2",
"lat": "52.1975331616",
"long": "0.9771180153"
}]
}
};
// Sensible defaults
var defaults = {
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP,
draggable: true
};
for (var i in maps) {
// Extend the options
var opts = $.extend(true, defaults, maps[i].options),
marker,
map,
bounds = new google.maps.LatLngBounds();
// Create the map
map = new google.maps.Map($(maps[i].mapElement)[0], opts);
// Create all pins
for (var p = 0; p < maps[i].pins.length; p++) {
var pin = maps[i].pins[p];
marker = new google.maps.Marker({
position: new google.maps.LatLng(pin.lat, pin.long),
map: map,
title: pin.title,
icon: pin.icon
});
// Extend the bounds of the map to contain the marker
bounds.extend(marker.position);
}
// use function closure to associate the map with its bounds listener
addBoundsListener(map, opts, bounds);
map.fitBounds(bounds);
}
function addBoundsListener(map, opts, bounds) {
// If no center option has been specified, center the map to
// contain all pins and reset the zoom
var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function() {
if (!opts.center) {
map.setZoom(opts.zoom);
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div style="width: 500px; height: 500px;" id="map1"></div>
<div style="width: 500px; height: 500px;" id="map2"></div>

Google Maps geoXML3: passing a placemark into it's own event listener?

I'm working on an intranet project, so my KML files can't be externally available. This means I'm dependent on the geoXML3 library to parse my XML on to my Google map. However the lack of documentation around event listeners is frustrating. I want to call a click listener and have the geoXML3 placemark passed in. I'm trying to do the following, however clickListener always receives the last polygon processed in the afterParse loop as p.
kml = new geoXML3.parser({
suppressInfoWindows: true,
map: map,
afterParse: function (doc) {
for (var i = 0; i < doc[0].placemarks.length; i++) {
var p = doc[0].placemarks[i];
google.maps.event.addListener(
p.polygon,
"click",
function () { clickListener(p); }
);
}
}
});
kml.parse(mapSettings.kmlLocation);
If I was using the Google Maps API's KML support, I could do this and have the polygon passed in to the listener.
kml = new google.maps.KmlLayer(mapSettings.kmlLocation, {
suppressInfoWindows: true,
preserveViewport: false,
map: map
});
google.maps.event.addListener(
kml,
"click",
clickListener
};
Is there any way to either (more preferable) pass the correct geoXML3 placemark reliably in to clickListener, or (less preferable) a property in the geoXML3.parser I can bind a click event to and receive a kmlMouseEvent the way I would using the Google Maps API kml parser? Ultimately I need to be able to change the style of the polygon and track that in an array it's been selected/deselected.
Use function closure to associate the placemark with the event listener. One way (you can also use an anonymous function):
kml = new geoXML3.parser({
suppressInfoWindows: true,
map: map,
afterParse: function (doc) {
for (var i = 0; i < doc[0].placemarks.length; i++) {
var p = doc[0].placemarks[i];
clickablePolygon(p);
}
}
});
kml.parse(mapSettings.kmlLocation);
function clickablePolygon(p) {
google.maps.event.addListener(
p.polygon,
"click",
function () { clickListener(p); }
);
}

Add a bootstrap 3 tooltip to google maps API v3 marker

I want to add a bootstrap tooltip to google map marker.
I cannot add HTML 5 atributes to it. So i tried to find the ID or class of the marker and adding the tooltip via javascript.
But, when I try to inspect the marker element using chrome tools the right click does not work inside the map canvas.
How should I go forward with it? Can I assign a custom ID to my google map marker.?? Or any other possible way?
My Code:
google.maps.event.addListener(map, 'click', function (event) {
if (POIMarker) {
POIMarker.setMap(null);
}
POIMarker = new google.maps.Marker({
position: event.latLng,
title: 'Double-Click me to feed information about this place',
icon: 'Images/POIMarker.png'
});
POIMarker.setMap(map);
google.maps.event.clearListeners(POIMarker, 'dblclick');
google.maps.event.addListener(POIMarker, 'dblclick', function (event) {
$('#POIModal').modal('show');
});
});
Here's a really hacked way of doing it, which tracks the mouse position and then positions a Bootstrap tooltip where the mouse is when the google map event is triggered. You could modify it to show the modal instead of a tooltip or use the click event instead of mouseover/out, as needed.
See http://jsfiddle.net/6o33fx6L/
var mouse = {
x: 0,
y: 0
};
document.addEventListener('mousemove', function (e) {
mouse.x = e.clientX || e.pageX;
mouse.y = e.clientY || e.pageY
}, false);
google.maps.event.addListener(marker, 'mouseover', function (event) {
$("#tt").css("left", mouse.x + "px").css("top", (mouse.y - 20) + "px").tooltip('show');
});
google.maps.event.addListener(marker, 'mouseout', function (event) {
$("#tt").tooltip('hide');
});
This version swaps in the marker's title for the tooltip:
http://jsfiddle.net/6o33fx6L/1/
You can asign more fields to the marker with this little snippet
marker.set("id", YOURVALUE);
I'd place this code in your function where you create your markers, because it will be called most likely within a for loop. So maybe you could just do something like
for(i = 0; i < markers.length; ++i)
{
// create marker
marker.set("id", i);
//set marker to map
}
Access is easy, just do
marker.get('id');
This should do what you need do clearly identify certain markers

Google Maps V3 JavaScript works only in Chrome?

I wrote a script that first geocodes an address and then displays a map of that address.
The trouble is, it only works in Chrome / Chromium. Other browsers (Firefox 10 & IE9) display a grey box. A problem that could be related, if I add a marker to the map, the marker does not show in Chrome.
I know that :
I connect with the API successfully with my API key.
The address is properly geocoded.
I use jQuery UI dialog to display the map. This, however, does not seem to be a problem. Removing the dialog and using a static div creates the same "grey box" result.
Below is my script, how I invoke it, and the website that I am using this on.
Here's the script:
function Map(properties)
{
var that = this;
// the HTML div
this.element = properties.element;
// address string to geocode
this.address = properties.address;
// title to use on the map and on the jQuery dialog
this.title = properties.title;
this.latlng = null;
this.map = null;
this.markers = [];
// geocode address and callback
new google.maps.Geocoder().geocode({'address': this.address}, function(data)
{
// geocoded latitude / longitude object
that.latlng = data[0].geometry.location;
// map options
var options =
{
zoom: 16,
center: that.latlng,
zoomControl: false,
streetViewControl: false,
mapTypeControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create a map
that.map = new google.maps.Map(that.element, options);
// add a marker
that.markers.push(new google.maps.Marker({map: that.map,
position: that.latlng,
title: that.title + "\n" +
that.address}));
});
this.get_google_map = function()
{
return that.map;
}
// creates a jQuery UI dialog with a map
this.show_in_dialog = function()
{
// because the dialog can resize, we need to inform the map about this
$(that.element).dialog({ width: 400, height: 300, title: that.title,
resizeStop: function(event)
{
google.maps.event.trigger(that.map, 'resize');
},
open: function(event)
{
google.maps.event.trigger(that.map, 'resize');
}});
}
this.center = function()
{
that.map.setCenter(that.latlng);
}
}
Here's how I invoke it :
// grab the address via HTML5 attribute
var address = $("#address").attr("data-address");
// ... and the title
var title = $("#address").attr("data-title") + " Map";
var map_element = document.createElement('div');
// append the newly created element to the body
$("body").append(map_element);
// create my own map object
var map = new Map({ element : map_element,
address : address,
title : title });
// bind a link to show the map
$("#map_link").click(function()
{
map.center();
map.show_in_dialog();
return false;
});
And here's the URL of the problem (click on map):
http://testing.fordservicecoupons.com/dealer/30000/premium_coupon_page
Last but not least, I combine and obfuscate my JavaScripts, so what you see above is not exactly the same as in the source on the website.
This doesn't look good:
resizeStop: function(event) { google.maps.event.trigger(that.element, 'resize'); },
open: function(event) { google.maps.event.trigger(that.element, 'resize'); }
you trigger the resize-event on the element that contains the map(that.element), but you must trigger resize on the google.maps.Map-object (what should be that.map in this case)
Wow... Here was the issue.
The layout that I built was a fluid layout. So, one of the first CSS rules that I have written was:
img, div { max-width: 100%; }
So that divs and images can scale. Well, for whatever reason, Google maps DOES NOT like this rule with the end result being a grey box.
And so I added another rule - an exception for Google maps:
img.no_fluid, div.no_fluid { max-width: none; }
And then, in javascript:
// AFTER DIALOG CREATION
$(dialog).find('*').addClass("no_fluid");
The find('*') will get us all the descendants.
Viola!

Categories