Google Maps API and DynamicMapsEngineLayer: Loop Over Features in the Map - javascript

[Edit APRIL 2, 2014]
I want to emphasize something. My scenario does not have a user event driving it to trigger an event listener. I know the Maps API documentation shows how to get a feature's featureId property from a MapsEngineMouseEvent. But my scenario needs to get the feature's featureId programmatically.
I've also tried programmatically "faking" a click, but that doesn't work either. (It seems the event object can't be instantiated??)
My hunch is, the solution to this either 1) doesn't exist, 2) is deceptively simple, or 3) will only be discovered if a minimum level 8 mage rolls a natural 20 wisdom check..
[Original Problem Statement]
I have few scenarios in a customized Google Maps client where I need to loop over features in a DynamicMapsEngineLayer and modify their style traits. The DynamicMapsEngineLayer works by performing..
..client-side rendering of vector data, allowing the developer to
dynamically restyle the vector layer in response to user interactions
like hover and click.
The Maps API documentation describes how to restyle individual features using event listeners, which expose a special featureId value assigned by Google servers. But my scenario doesn't have user-driven events. For example, consider this hypothetical link:
http://www.acme-map.com/index.php?ZoomToAndHighlightFeatureWithId=12345
FeatureWithId is our own unique id, not Google's special
featureId, which we don't have at this point in the runtime.
I need the map to load right above a feature and highlight it by changing its style trait. It needs to do this programmatically when the map first loads, without any user interaction. If these vector features are truly rendered in the DOM, then surely there's a way, no matter how cryptic, to reach into the map's guts and access these objects?
Is there a way to loop over individual features in a DynamicMapsEngineLayer or get the featureId property without an event listener?

I may be missing something here, but if you already know the feature ID, you can restyle it directly without an event. Just call getFeatureStyle() directly and set the style as you wish:
var style = dynamicLayer.getFeatureStyle('1234');
style.strokeColor = '#FF0000';
style.iconImage = 'url(images/myIcon.png)';
And if you don't know the feature ID, but you do have some other attribute to query against, you can make a call out to the Maps Engine API to fetch it.

Related

Adding hotkey functionality in Openlayer

In my Openlayer based map application, I want to enable user to perform an action using a custom key combination.
How can this be done? Do I need to make use of ol.interaction.Interaction?
Not sure of what you exactly expect but you will find below an answer according to my understanding.
Some interactions like ol.interaction.Draw already support default key combinations e.g http://openlayers.org/en/master/apidoc/ol.events.condition.html.
If you need custom combination of keys on existing interactions, these conditions functions act as a tiny wrapper on top of native JavaScript keyboard keys of your browser.
You need to create a new function that look more or less like this excerpt function example from the OpenLayers code and adapt it to manage your own custom key combination.

How can I get information about a clicked marker which was not added via overlay?

I have a question regarding the markers on the primefaces gmap element.
By now I have read up a lot about what is possible, and I found out that one can add custom markers to the map, as well as listen for their clicks and so on.
However, I want to be able to listen to clicks on one of the default markers google maps already provides.
For example:
I, as a user, would move around the map, looking for a restaurant to dine tonight. I find a marker for a restaurant I am interested in and which I want to know more about. As soon as I click it, the application - in this case my Java bean - should get information about the clicked marker.
It might not have to be all the information possible, but at least the position, name etc. so I can get information about the place with another google API.
Is there a possiblity to achieve this?
Some objects within the Maps API are designed to respond to user events such as your concern with clicking a marker and getting information about the clicked marker. To achieve it, you have to integrate JavaScript which is active in the browser side with your JavaBeans which is active at server side to get the possible information for the clicked marker.
Using JavaScript, you can add interactions by generating events and add event listeners to execute code when those specified events occur.
A very good example showing how your concern can be properly achieved by adding a marker and keeping client side representation in sync with the server side model can be found in GMap - Adding Markers.

Polygon mouseover event position

There is a problem on my website. I need to capture "mousemove" event and after that change the position of hint window according to the position of cursor at the moment of event. Here is the code:
google.maps.event.addListener(country, 'mousemove', function(e) {
this.setOptions({fillOpacity: 1});
$('div.info-win').css('top', e.kb.clientY + 20 + 'px');
$('div.info-win').css('left', e.kb.clientX -50 + 'px');
$('div.info-win').show()
});
At first everything was ok, but soon browser started to show the error, that e.kb is not defined. I checked the event via console and realized that "e.kb" really does not exist. Instead there was "e.lb" so I changed it in my code. But now the problem is the same, and console shows me that "e.lb" does not exist. I cant explain it, but now the captured event has ".gb" property instead of ".lb". can someone help me and explain why this happens every week again , so I need always to check the name of event property?? this is the first time I see problem like that but at the same time I cannot find any solution!
The Google Maps MouseEvent doesn't give the screen X and Y values.
Instead, it seems to give only Latitude/Longitude of the mouse position.
Reference:
https://developers.google.com/maps/documentation/javascript/reference#MouseEvent
https://developers.google.com/maps/documentation/javascript/reference#PolyMouseEvent
You need to convert the Latitude/Longitude value to the screen mouse X/Y position which is explained here (similar question):
Get Position of Mouse Cursor on Mouseover of Google Maps V3 API Marker
The reason your map worked for a while and later started failing is that you are using undocumented properties of the MouseEvent object. As you discovered, these may change at any time.
Think about it: do kb and lb and gb sound like names you would use in your code to describe a mouse position? And would you change them willy-nilly like that? :-)
So why does Google use gibberish names like these, and why do they change them all the time?
In the original source code that their developers work on, of course they use readable and consistent names. But then they compile the code with a "minifier" that shortens the private variable/property/method names for faster loading. When they revise the source and recompile it, those short names get reassigned arbitrarily.
The three different property names you found over the weeks clearly all refer to the same object in the original source, but the minifier changed the name you see in the browser.
Never assume you can use a property or method you discover in your browser's developer tools - especially if it has a name that makes no sense. Check it first in the Maps API documentation, and if it's not there, don't use it.
See Seyong's answer for the details of how to change your code to use the documented methods.

What is the Proper Way to Destroy a Map Instance?

I recently developed an html5 mobile application. The application was a single page where navigation hash change events replaced the entire DOM. One section of the application was a Google Map using API v3. Before the map div is removed from the DOM, I want to remove any event handlers/listeners and free up as much memory as possible as the user may not return to that section again.
What is the best way to destroy a map instance?
I'm adding a second answer on this question, because I don't want to remove the back and forth we had via follow-up comments on my previous answer.
But I recently came across some information that directly addresses your question and so I wanted to share. I don't know if you are aware of this, but during the Google Maps API Office Hours May 9 2012 Video, Chris Broadfoot and Luke Mahe from Google discussed this very question from stackoverflow. If you set the video playback to 12:50, that is the section where they discuss your question.
Essentially, they admit that it is a bug, but also add that they don't really support use cases that involve creating/destroying successive map instances. They strongly recommend creating a single instance of the map and reusing it in any scenario of this kind. They also talk about setting the map to null, and explicitly removing event listeners. You expressed concerns about the event listeners, I thought just setting the map to null would suffice, but it looks like your concerns are valid, because they mention event listeners specifically. They also recommended completely removing the DIV that holds the map as well.
At any rate, just wanted to pass this along and make sure it is included in the stackoverflow discussion and hope it helps you and others-
The official answer is you don't. Map instances in a single page application should be reused and not destroyed then recreated.
For some single page applications, this may mean re-architecting the solution such that once a map is created it may be hidden or disconnected from the DOM, but it is never destroyed/recreated.
Since apparently you cannot really destroy map instances, a way to reduce this problem if
you need to show several maps at once on a website
the number of maps may change with user interaction
the maps need to be hidden and re-shown together with other components (ie they do not appear in a fixed position in the DOM)
is keeping a pool of map instances.
The pool keeps tracks of instances being used, and when it is requested a new instance, it checks if any of the available map instances is free: if it is, it will return an existing one, if it is not, it will create a new map instance and return it, adding it to the pool. This way you will only have a maximum number of instances equal to the maximum number of maps you ever show simultaneously on screen.
I'm using this code (it requires jQuery):
var mapInstancesPool = {
pool: [],
used: 0,
getInstance: function(options){
if(mapInstancesPool.used >= mapInstancesPool.pool.length){
mapInstancesPool.used++;
mapInstancesPool.pool.push (mapInstancesPool.createNewInstance(options));
} else {
mapInstancesPool.used++;
}
return mapInstancesPool.pool[mapInstancesPool.used-1];
},
reset: function(){
mapInstancesPool.used = 0;
},
createNewInstance: function(options){
var div = $("<div></div>").addClass("myDivClassHereForStyling");
var map = new google.maps.Map(div[0], options);
return {
map: map,
div: div
}
}
}
You pass it the starting map options (as per the second argument of google.maps.Map's constructor), and it returns both the map instance (on which you can call functions pertaining to google.maps.Map), and the container , which you can style using the class "myDivClassHereForStyling", and you can dinamically append to the DOM.
If you need to reset the system, you can use mapInstancesPool.reset(). It will reset the counter to 0, while keeping all existing instances in the pool for reuse.
In my application I needed to remove all maps at once and create a new set of maps, so there's no function to recycle a specific map instance: your mileage may vary.
To remove the maps from the screen, I use jQuery's detach, which doesn't destroy the map's container .
By using this system, and using
google.maps.event.clearInstanceListeners(window);
google.maps.event.clearInstanceListeners(document);
and running
google.maps.event.clearInstanceListeners(divReference[0]);
divReference.detach()
(where divReference is the div's jQuery object returned from the Instance Pool)
on every div I'm removing, I managed to keep Chrome's memory usage more or less stable, as opposed to it increasing every time I delete maps and add new ones.
I would have suggested removing the content of the map div and using delete on the variable holding the reference to the map, and probably explicitly deleteing any event listeners.
There is an acknowledged bug, though, and this may not work.
As google doesnt provide gunload() for api v3 better use iframe in html and assign map.html as a source to this iframe. after use make src as null. That will definitely free the memory consumed by map.
When you remove the div, that removes the display panel and the map will disappear. To remove the map instance, just make sure that your reference to the map is set to null and that any references to other parts of the map are set to null. At that point, JavaScript garbage collection will take care of cleaning up, as described in: How does garbage collection work in JavaScript?.
I guess you're talking about addEventListener. When you remove the DOM elements, some browsers leak these events and doesn't remove them. This is why jQuery does several things when removing an element:
It removes the events when it can using removeEventListener. That means it's keeping an array with the event listeners it added on this element.
It deletes the attributes about events (onclick, onblur, etc) using delete on the DOM element when addEventListener is not available (still, it has an array where it stores the events added).
It sets the element to null to avoid IE 6/7/8 memory leaks.
It then removes the element.

Making Google Maps driving directions behave more like actual Google Maps

I've been doing driving directions in my map app using the directionsRenderer, so it renders both the path (on the map) and the html list of directions. My app works basically like this example: http://code.google.com/apis/maps/documentation/javascript/examples/directions-draggable.html
However, now I've been asked to make it a little more like the directions on Google Maps proper, for instance here
My client would like the little popups when you hover over the html items, as well as the little icons showing right turn, bear left, merge, etc.
I've managed to render my own html from the DirectionsService response, and hook up events for hovering and associate them with points on the map, but where I could use help is:
Getting the turn by turn icons. I imagine this isn't easy because I get each step as html text ("Take exit 433 on the left to merge onto I-80 E toward Bay Bridge/Oakland"), and I imagine that could be challenging to parse reasonably to determine which icon to show
Making the little mini-popups over the map. Although I can make the popups themselves, it's probably challenging or impossible to do it the exact same way because I don't have a short version of the instructions.
In any case, I thought I'd check if anyone knows a way to do this sort of thing -- not necessarily exactly, but just closer to it -- or if I'm just out of luck because google hasn't made any of that sort of functionality available via their api.
You are correct that you will have to examine strings to get turn icons. You can parse the DirectionsResult object yourself (it is "JSON-like" according to Google's documentation) rather than using the DirectionsRenderer if you wish, but I don't think it will get you anything much. Here's how it would go:
The DirectionsResult.route property will be an array of DirectionsRoute objects. If you didn't set provideRouteAlternatives to true, then there will only be one DirectionsRoute object in the array.
The DirectionsRoute object, in turn, has a property called legs. That property is an array of DirectionsLeg objects. If you have specified no waypoints (i.e., an intermediary destination), just a start and end point, then this array will also only have one object in it.
The DirectionsLeg object, in turn, has a property called steps. It will be an array where each element will be a DirectionsStep object.
The DirectionsStep object has a property called instructions. That is a string and is what you will have to examine using a regexp or whatever to figure out what turn icon to use. (It's possible that this may be easier to work with than the HTML you mention that I imagine is coming from the DirectionsRenderer. Or it may be possible that it isn't any easier whatsoever. I'm not sure. I've never actually done it.)

Categories

Resources