More advanced stuff

Google Maps API Tutorial

Custom direction details

GDirections.load() doesn’t give you much control over the layout of the directions information. If you want to have the directions displayed slightly differently, you have to read through the GRoutes and GSteps and build up the whole thing yourself.

Here’s a page where I’ve already done that to produce a display that looks almost exactly like that produced by GDirections, but since it’s all done in exposed Javascript, you can take a copy and customise the code to make it look the way that you want it to.

The parameters of my “customPanel()” function are:

  1. The map object.
  2. A string containing the name of the global variable that points to your map.
  3. The GDirections() object.
  4. The div into which the directions are to be placed.

Potential Pitfalls

  1. Don’t forget to use {getSteps:true} otherwise there won’t be any GRoute or GStep information to process
  2. The GDirections “load” event seems to happen just before it centres the map. If you are relying on GDirections to perform the initial centering of the map, then you have to set a short timeout after the “load” before the direction details are processed.

More advanced stuff

Google Maps API Tutorial

Get Directions on your own map

It is now possible to obtain directions on your own map.

Here’s an example.

There are initially two links: “To here” and “From here”. Clicking these links opens a corresponding form.

The initial version of the info window, one with the “To here” form and one with the “From here” form. When the “To here” or “From here” link is clicked, the corresponding html string is loaded into the info window.

When the “Get Directions” button is clicked, the form invokes the “getDirections()” function which makes a GDirections() call.

The details of using GDirections() is well described in the Official Documentation, so I’ll not repeat the information here.

From v2.124 you can specify walking directions and avoid highways by using the options {travelMode:G_TRAVEL_MODE_WALKING} and {avoidHighways:true}.

Potential Pitfalls

  1. GDirections() doesn’t currently support queries in the form “43.82589,-79.1004(My House)”.
    It does support the format “My House@43.82589,-79.1004”.
  2. For legal reasons, walking directions don’t work if you omit the second parameter when you create the GDirections() object. The API needs somewhere to put the disclaimer.

More advanced stuff

Google Maps API Tutorial

Marker Categories

If you have a map that shows several categories of markers, you may want to hide and show all the markers of one category at once, and remove the corresponding sidebar entries.

Here’s an example that does that.

The code makes use fo several of the techniques that have been described previously, which I’m not going to describe again.

The distinctive features of this code are:

Hiding and showing markers

The “hide(category)” and “show(category)” functions read through the array of markers and hide() or show() all the markers which match the specified category.

Dynamic sidebar

Rather than adding the sidebar entries as each marker is created, the “makeSidebar()” function is executed after all the markers already exist, by reading the gmarkers[] array. It omits entries for which gmarkers[i].isHidden().

The “makeSidebar()” function is called whenever the marker display changes.

Marker properties

Extra Properties are added to the marker Objects, to store the category and sidebar name information. This allows the “makeSidebar()”, “hide(category)” and “show(category)” functions to obtain all the information that they need from the marker Objects, rather than having to use some external list.

Checkbox settings

I can’t seen to get <input type=”checkbox” checked > to do exactly what I want, so I’ve added a line to the “hide()” and “show()” functions to ensure that the checkbox is checked and cleared.

In order for this to work, I’ve set the “id” of the checkbox that manages the “theatre” category to “theatrebox”, etc., so that the Javascript can easily obtain the name of the checkbox if it knows the category.

Associative array of GIcons

I’ve used an associative array to hold the GIcons, (as explained in the Associative arrays and Custom Icons tutorial). I’ve used the same names for the icons and categories.

More advanced stuff

Google Maps API Tutorial

“Did You Mean?”

The page will ask a “Did you mean?” question in response to an address search under certain circumstances. You might possibly want to offer the same functionality within the API.

Note: The API geocoder is quite different from the geocoder. Situations which cause the conditions which provoke a “Did you mean?” in one geocoder will not usually cause those conditions in the other geocoder.

Multiple Hits

One condition which provokes the question is when the geocoder returns more than one Placemark in response to the query.

To detect this situation with the API geocoder, simply test whether result.Placemark.length is greater than 1.
If it is greater than 1, then display a list of clickable options, using the Placemark.address values that are returned. Store the corresponding Placemark.coordinates so that they can be used to plot the marker when the user selects one of the alternatives.

Here’s an example

The API geocoder doesn’t often return multiple results. Bispham Road, Bispham, UK is one example address which currently produces three results in the API geocoder (because there really are three Bispham Roads in Bispham).

Potential Pitfalls

  1. Don’t store the Placemark.address and try to geocode that when the user selects it.
    Even though the geocoder returns that address, it doesn’t mean that it can geocode it if you pass it back.

Significantly Different Address

The geocoder may occasionally return an address which is sufficiently different from the requested address to be worth asking the “Did you mean?” question.

For example, if you search for Bespham Road, Cleveleys, FY2, the API geocoder will return a single result for Bispham Rd, Blackpool, FY2 0, United Kingdom, which you might consider to be sufficiently different to be worth querying.

This circumstance is much harder to test for. The returned address will often look very different from the query just because the geocoder converts the address into a standard format. In this case, the fact that “Gilford” has been replaced by the zip code “03249”; and the fact that “,USA” has been added; should not be considered to be “significant” differences in the address.

I reckon that it’s impractical to compare anything other than the house number and street. To go any further would require some fairly sophisticated AI to handle all the possible valid variations that might be used, and you’d almost need to write your own geocoder to check if “Gilford” actually is zip code “03249”.

My strategy for matching the street is to

  • Write a little function that converts words like “street”, “lane”, “north” etc. into standard versions “st”, “la”, “n” etc.
  • Split the reply at the first comma to obtain the part that specifies the street.
  • Convert the query and the reply to the same case, e.g. .toLowerCase().
  • Remove any apostrophes, so that “St Fred’s Rd” matches “St Freds Rd”.
  • Replace any other punctuation with spaces, since the geocoder ignores punctuation except that it separates words.
  • Replace multiple spaces with a single space, so that we now have a string of words separated by single spaces.
  • Split the strings into arrays of words.
  • Convert each word to the “standard” version.
  • Compare corresponding words from the query and the reply

Here’s an example

I’ve not done an awful lot of testing with this.

More advanced stuff

Google Maps API Tutorial

Custom Tooltips

It’s possible to add custom tooltips to your markers.

This technique was invented by “evilc”.

Here’s an example

The code is more complicated than using standard tooltips, but by creating our own tooltips we can:

  • Pop up the tooltip instantly when the mouse moves over the marker, instead of there being a delay.
  • Keep the tooltip visible until the mouse moves off the marker.
  • Pop up the marker tooltip when the mouse moves over the corresponding sidebar entry.
  • Use our own styles.

The technique involves creating a <div> that contains the tooltip which is initially hidden.

When the mouseover event occurs, the pixel position of the marker relative to the South West corner of the visible map is calculated, the tooltip <div> is positioned relative to that corner and made visible.

There’s no reason why the tooltip should only contain a simple text label. You can use images and tables etc. Don’t try using links or forms, because the tooltip disappears when the mouse moves over the tooltip, because it would no longer be over the marker.


  1. The tooltip appears in the wrong place when the International Date Line is within the visible map. This is caused by a problem with map.getBounds(). It returns the normalized values of the locations, but we really need the unnormalized values. I don’t believe that there’s anything that can be done about that until Google provide a mechanism for obtaining the unnormalized location of the map corners.
  2. The tooltip gets squashed up if it is created close to the East edge of the map. The behaviour is worse in Firefox than IE, particularly if overflow:hidden is not used. The behaviour at the other edges is OK.

Potential Pitfalls

  1. Make sure that you create the map before performing the appendChild(tooltip). If you append the tooltip div first, then the tooltip gets displayed underneath the map tiles and you can’t see it.
  2. Don’t put links or forms into the tooltip div. The user won’t be able to click on them because the tooltip disappears when the mouse moves off the marker.
  3. Do make sure that the tooltip has a defined CSS style, which should at least include a “background-color” setting. Without it, the tooltip background would be invisible.

More advanced stuff

Google Maps API Tutorial

Standard Tooltips

It’s possible to add tooltips to your markers.

Here’s an example

The preferred syntax for GMarker() allows a set of options to be specified. One of these options is “title”, which specifies the tooltip text.

E.g. new GMarker(point, {title:"My House"});

These types of tooltip are plain text. You can’t apply any formatting to them. If you want to change the style, position or duration you’ll need to use custom tooltips.

Potential Pitfalls

  1. Don’t try to mix this syntax with the old GMarker() syntaxThis won’t work: new GMarker(point, myIcon, {title:”My House”}). When you use the new syntax, the options must be the second parameter, like this new GMarker(point, {icon:myIcon, title:”My House”}).

More advanced stuff

Google Maps API Tutorial

Dual Maps

It’s possible to have a pair of maps that track each other’s movements by using “move” or “moveend” listeners one each other and updating the position of the other map to match the one that moved. For example, a small zoomed-out map can be used as a dynamic thumbnail to help you see what the main map is zoomed in on.

The only problem is that updating the position of the second map cases “move” and “moveend” events, and we don’t want to attempt to process those events, otherwise the code goes into a loop and gets stuck.

All we need to do is to add a pair of extra variables that remember whether the maps are being moved by our own code, and only update the other map when this is not the case, i.e. when the map is being moved by the user.

In this example there’s a crosshair on the small map. This is just a marker which gets recentred every time either map moves.

Credit Thanks to Esa Ojala for posing the original question which led me to develop this technique.

The Basics

Google Maps API Tutorial

Google Chrome Considerations



Currently unsupported
3D Map Type
Async behaviour
Maps in new tabs
Poor developer tools
Polygon winding rule
Polygon fill order

Chrome is an awful lot faster at client side processing. In particular, it compiles Javascript code rather than interpreting it.
[But it’s possible that you ain’t seen nothing yet. TraceMonkey is rumoured to run Javascript faster.]

This doesn’t mean that every map page will run faster. If the critical factor is the amount of time it takes to fetch resources from a server then there’s not a lot that Chrome can do to improve the speed.

What’s acceptable is very subjective, and depends on the hardware and Internet connection speed as well as the browser. On my computer, I reckon that the number of displayed markers and polylines that make the browser unacceptably sluggish are:
MSIE: 100 markers or 10 polylines.
Firefox: 300 markers or 100 polylines.
Chrome: 2000 markers or 1000 polylines
Currently Unsupported

Google Chrome is not included in the current list of supported browsers.
Most of the Google Maps API functionality works under Google Chrome, and GBrowserIsCompatible() accepts it, but if you happen to stumble upon something that doesn’t work under Chrome, then there may not be a fix for it.

3D Map Type

G_SATELLITE_3D_MAP currently doesn’t work under Chrome. The Google Earth plugin is not recognised.
Async Behaviour

Chrome has more asynchronous behaviour than other browsers. In other browsers, the display only gets refreshed when Javascript pauses, but Chrome is designed to run Javascript and refresh the display at the same time. This might possibly be a problem if you depend on things happening in a predictable order.
One particular problem that you might encounter is that it’s possible for the Javascript to start executing before CSS files have been read. If your map container has its size specified in an external CSS file, Chrome may well execute the “new GMAp2()” command before the map container size is known. A moment later, Chrome processes the CSS information and changes the size of the container, but the GMap2 object has been created with the wrong size.

Maps in new tabs

There’s an occasional problem that results in a page that’s launched into a new tab to be centred incorrectly.
It seems to occur intermittently with the API, but it occurs consistently with For example If you shift-click this link in Chrome and wait a few seconds for the page to be rendered in the closed tab, then the marker gets placed in the correct location but the map is centred on Moscow instead of Blackpool.

Poor developer tools

At present there are no useful extensions for Google Chrome equivalent to things like Firebug, Venkman, HTMLValidator and WebDeveloper in Firefox.
I recommend developing your code in Firefox and testing it in Chrome, MSIE, etc afterwards.

Polygon winding rule

When you create an encoded polygon with holes, the holes may not appear when your map is viewed with Chrome.
This is because the API uses the CANVAS graphics technology to render polylines and polygons, and CANVAS has a different winding rule.

In the other three graphics technologies, a region of a polygon is filled if its winding number is odd, and left empty if the winding number is even. You can consider the “winding number” to be the number of times that the path winds round the region in a clockwise direction. So, if you have a clockwise outer boundary and a clockwise inner boundary, the inner region has winding number 2, and is rendered as a hole.

In CANVAS, a region of a polygon is filled if its winding number is non-zero, and left empty only if the winding number is zero. So, if you have a clockwise outer boundary and a clockwise inner boundary, the inner region has winding number 2, and is not rendered as a hole. To create a hole you need to have one path be clockwise and the other path be anticlockwise for the centre to be renedered as a hole.

Here’s an example

Similarly, if you have a polygon with a path that crosses itself, the interior will appear different in Chrome.

Here’s an example

The different winding rule is a basic feature of the graphic technology, and there’s nothing that the API can do about it.

Polygon fill order

The fill of a polygon appears to be performed above the polyline that forms its boundary, whereas with the other graphics technologies the boundary is placed on top of the fill. This can make the result look quite different.
Consider this example and this one

From time to time, Chrome will decide to update itself. Without asking.
During the update process, the computer becomes so sluggish that it’s effectively useless for doing anything else until Chrome has finished its update.

Chrome also seems to occasionally perform extensive housekeeping tasks. At least I guess that’s what it’s doing. Every so often it will grab 100% of the CPU for about 10 minutes without any Internet I/O. The only way I’ve found to do any other work on the computer is to close Chrome, then, when I don’t want to use the computer for a while, restart Chrome and let it do its thing.

The Basics

Google Maps API Tutorial

Underlay message

One way to display a loading message is to place an image containing your message underneath the map tiles. The message is always there, but it’s not visible when the tiles have been loaded on top of it.

You have to place the image after the GMap2() object is created, because the API creates its own background for the map container when the GMap2() is created.


I suggest using low contrast, and allowing space at the side so that the message isn’t underneath the map controls.

A loading message placed underneath the tiles like this also becomes visible when the map changes zoom level or map type when new tiles need to be fetched

The Basics

Google Maps API Tutorial


The Marker Management system allows large numbers of markers to be managed efficiently, providing that only a modest number of markers are ever visible in the viewport at once.

You can create a marker manager like this:

       var mm = new GMarkerManager(map);

Then you can add individual markers like this:

       var marker=new GMarker(point);

Or add arrays of markers like this


The numbers represent the range of zoom levels for which the specified markers will be displayed.

You can perform several .addMarkers() calls for groups of markers that are to be displayed at different zoom levels, then use one .refresh() call to cause them to be displayed. By default, a GMarkerManager manages markers for zoom levels 0 to 17. If you switch to a map type that has more than 17 zoom levels, then zoom levels above 17 show the same markers as would be shown on zoon level 17.

You can change the maximum zoom range managed by a GMarkerManager like this

       var mm = new GMarkerManager(map, {maxZoom:19});

The .getMarkerCount(zoom) method returns the number of managed markers to be displayed on the specified zoom level.

In this example there are a total of 1576 markers being managed.

The 75 red markers are displayed on all zoom levels.
The 330 yellow markers are displayed on zoom level 11 and above.
The 474 green markers are displayed on zoom level 12 and above.
The 696 blue markers are displayed on zoom level 13 and above, but at that zoom level only a few are ever in the viewport at once.

There’s a GMarkerManager “changed” event returned when the GMarkerManager refreshes itself. The event returns two parameters. The first parameter is a GBounds() object which seems to return information about the region under consideration, but measured in units of 1024×1024 pixels. The second parameter is the number of active markers in the region under consideration.

Moving Markers

By default, the GMarkerManager doesn’t listen for changes in position of your markers. If you move a marker by performing marker.setPoint(), the manager will not notice the change.

With {trackMarkers:true} the GMarkerManager listens for any “changed” events on the markers, and performs a .refresh() whenever any of the managed markers moves. That’s fine if only one of your markers moves at once, but would be very inefficient if you move lots of markers at once because a refresh() would be performed for each marker.

If you move a lot of managed markers at once, then its better to perform one GMarkerManager.refresh() after moving all the markers.

Potential Pitfalls

  1. Don’t perform both map.addOverlay() and mm.addMarker() on the same marker.
  2. Don’t try to set the max zoom for a marker higher than the maxZoom setting of the GMarkerManager (default 17).
  3. If you’re using a custom map type, the max zoom value for a marker must be supported by the applied GProjection, even if you never zoom to that level.E.g. if you’re using the default max zoom of 17, like this manager.addmarker(marker,7), then your maptype could use new GMercatorProjection(18) but not new GMercatorProjection(17).
    If you have a marker that has a max zoom that’s not supported by the map type, then you might not get an error, but the marker will not be plotted correctly at any zoom level.

GMarkerManager with a Sidebar

There’s a problem with using GMarkerManager with a sidebar, because marker.openInfoWindow() doesn’t work for markers that are not currently attached to the map. GMarkerManager removes offscreen markers from the map in order to achieve the efficiency improvement.

One way round the problem is to use map.openInfoWindow() instead of marker.openInfoWindow(), calculating the map pixel offset from the infoWindowAnchor and the iconAnchor.

          var iwAnchor = marker.getIcon().infoWindowAnchor;
          var iconAnchor = marker.getIcon().iconAnchor;
          var offset = new GSize(iwAnchor.x-iconAnchor.x,iwAnchor.y-iconAnchor.y);
          map.openInfoWindow(marker.getLatLng(), html, {pixelOffset:offset});

The Basics

Google Maps API Tutorial

Using a percentage height for the map div

If you try to use style=”width:100%;height:100%” on your map div, you get a map div that has zero height. That’s because the div tries to be a percentage of the size of the <body>, but by default the <body> has an indeterminate height.

There are ways to determine the height of the screen and use that number of pixels as the height of the map div, but a simple alternative is to change the <body> so that its height is 100% of the page. We can do this by applying style=”height:100%” to both the <body> and the <html>. (We have to do it to both, otherwise the <body> tries to be 100% of the height of the document, and the default for that is an indeterminate height.)

The <body> also has a margin by default. If you want to switch that off, add “margin:0” to the <body> style, to push the body right out to the edge of the screen.

In this example I’ve set the map div height to 96% to leave room for the back link.

The Basics

Google Maps API Tutorial

Onload function and external controls

If you’ve been following this tutorial, adding external controls that affect the map is straight forward. If, however, you made an initial decision to put all the API Javascript code into an onload function you’ll need to make some of your variables and function declarations global.

Any variables and functions that are declared local to the onload function cannot be accessed from click or mouseover events that occur on html elements outside the map.

Here’s an example of using external controls to change the zoom level of the map.

All the functions which are called from clicks and mouseovers on html elements need to be global. That just means that you need to place the function declarations outside the onload function, like this

    // This function zooms in or out
    function myzoom(a) {
      map.setZoom(map.getZoom() + a);

    function onLoad() {

Similarly, any variables which are used by those global functions need to be global. That just means making the initial declaration of the variables before any function declarations, and then populating those global variables in your onload function. In this particular example, the myzoom() function needs to use the “map” variable, and the myclick() function which handles the sidebar needs to access the gmarkers[ ] and htmls[ ] arrays.

   <script type="text/javascript">
    var gmarkers = [];
    var htmls = [];
    var map;

    function myclick(i) {
    . . .

Potential Pitfalls

  1. Remember that “onload()” in all lower case behaves like a reserved word in Firefox. Use a different name or change the capitalisation.
  2. Clicks and mouseovers in the html inside an info window are “external” events. Any functions or variables they use also need to be global.
  3. Don’t re-declare your variables inside the onload function. Make the onload function use the global variables rather than creating it’s own local variables with the same name. I.e. change the
            var map = new GMap(document.getElementById("map"));


            map = new GMap(document.getElementById("map"));
  4. Beware free webhosting services that make their money by adding adverts to your pages. Some of them set their own onload function, using “window.onload”, which overwrites the onload setting in <body onload>.You may need to reset “window.onload” after their header code has executed, and then might be contractually obligated to call their olnload function as well as your own. The details vary depending on the webhosting service. Some of them go to considerable lengths to make this sort of thing very difficult because they don’t want people to be able to remove the adverts.

Heart problems in babies

Heart Disease

Specialist care

There are a small number of specialist foetal medicine units where experts can help mothers and their unborn babies. In these units, the heart and circulation of the foetus can be examined by ultrasound, in a procedure known as foetal echocardiography.

The advantage of these units is that when a cardiac malformation is associated with additional structural or chromosomal problems (as they often are) there are several different specialists available on the team to work together to provide the best care.

If surgery is necessary, an appointment with the cardiac surgeon in the cardiology centre is helpful to prepare parents for the perinatal period (the time just before and after the birth) and to discuss surgical issues. Specialist liaison nurses provide additional support for parents at this time, and good communication with the local obstetric unit and local paediatricians is essential.

Further information

Greater recognition and understanding of cardiac disease in the early stages of life should mean safer management before and at the time of birth leading to better results for heart babies. For example, treatments to open valves safely before birth are in development and fast heart rates can be treated using drugs.

As our knowledge of the development of babies during pregnancy improves, doctors will be able to offer better care.

Tiny Tickers is a charity aimed at improving our understanding of foetal heart problems. Its objectives are to raise awareness, promote research and support those affected by these problems. For more information, go to

Other organisations that can provide help and support include:

British Heart Foundation

  • Heart HelpLine: 0300 330 3311
  • Website:

Little Hearts Matter

  • Tel: 0121 455 8982
  • Website:

Grown Up Congenital Heart Patients Association

  • Tel: 0800 854759
  • Website:

Congenital heart defects

Heart Disease

Treatment of congenital heart defects

In tetralogy of Fallot, surgery may be needed to increase blood flow to the lungs with a shunt, linking the aorta and the pulmonary artery. The child is able to develop and the defect can be corrected later.

An arterial switch operation may be necessary to reconnect the arteries correctly. With holes in the heart, oygenated, red blood from the lungs passes into the right side of the heart, where it mixes with bluish blood and is sent back to the lungs. The heart is put under extra strain, potentially causing it to enlarge and causing high blood pressure and blood vessel damage. Growth and nourishment are affected.

Holes in the heart are closed with one or two patches and the single valve is divided into two. Blood circulation should be returned to normal but the reconstructed valve may not work normally.

If the defect is too complex to repair in infancy, a pulmonary artery band may be surgically used to reduce blood flow and high pressure in the lungs (pulmonary hypertension). The band is later removed and surgery carried out.

Balloon valvuloplasty, which involves threading a balloon through a dilated heart valve, is usually used to correct pulmonary valvular stenosis, although open-heart surgery may be necessary.

Congenital heart defects

Heart Disease

Causes of congenital heart defects

Causes are thought to include:

Development problems during pregnancy, sometimes as a result of a viral infection such as rubella contracted by the mother
Alcohol, illegal drugs and over-the-counter medicines can also cause defects
Maternal diabetes
Genetic conditions, such as Down’s syndrome

Diagnosing congenital heart defects

Diagnosis can be made by scans taken during pregnancy, but is usually made in the first days or weeks after birth. In some cases, however, diagnosis may not be made until much later in life.

Cardiovascular disease

Heart Disease

Risk factors for CVD

Some risk factors for CVD are potentially reversible or can be modified. These include:

  • Cigarette smoking
  • Increased levels of LDL cholesterol
  • High triglycerides (caused by the build up of fats derived from foods eaten or made in the body from other energy sources)
  • Low HDL cholesterol
  • Being overweight
  • Large waist circumference (being ‘apple-shaped’)
  • High blood pressure
  • Inactivity
  • Diabetes

Diet and CVD

Making small changes to your diet is one of the simplest and most effective ways to reduce your risk of CVD. You can do this by:

  • Reducing fat in your diet, especially saturated and trans-fats
  • Eating more fruit and vegetables, wholegrain food and soluble fibre
  • Drinking alcohol in moderation
  • Reducing salt to maintain a lower blood pressure

Cardiovascular disease

Heart Disease

What is CVD?

Cardiovascular disease (CVD), is a group of conditions that includes stroke and heart disease. It kills one in three people in the UK.

CVD is caused by a build-up of fatty streaks and cholesterol in the blood vessels. While some contributing factors can’t be altered, we can change our lifestyle.

Natural wear and tear to blood vessels makes it easier for fatty cholesterol to leak in and get stuck to the artery walls. This build-up causes the arteries to narrow, reducing the heart’s ability to pump blood through them to the body. If they become completely blocked, it will cause a heart attack or a stroke if the blockage occurs in the brain’s blood vessels. Importantly, not all cholesterol is bad. There are two types of cholesterol in the bloodstream: LDLs and HDLs. LDLs create the build-up in arteries, while high HDL levels are a good sign that you’re not at risk of CVD.