Creating Dynamic Animated Tile Layers in Bing Maps 4

 

If you’ve been following this series of blog posts, you’ll know that I’ve been investigating methods to create an animated background tile layer to display weather maps using the Bing Maps v7 AJAX control.

For this final post, I’m going to wrap everything I’ve done so far into a reusable module.

Bing Maps Custom Modules and the “Ninja” update

The most recent update to the Bing Maps AJAX control, introduced in early May 2011, became slightly notorious as the “ninja” update. The reason being that, silent but deadly, the unannounced update accidentally broke many websites with no warning. Unfortunately, these breaking changes rather eclipsed some of the other nice new features introduced in the update – one of which was the introduction of a common framework through which Bing Maps could be extended by creating custom modules.

Now that the bugs introduced in the latest update have mostly been ironed out, I thought it time to investigate the new module functionality. It’s pretty easy to move your custom code into a module – the main requirement is that, at the end of your function, you place a call to the Microsoft.Maps.moduleLoaded() method. This lets Bing Maps know that your module had been loaded and ready to use.

So, I added the moduleLoaded() call, rolled my animatedTileLayer function into a file and uploaded it to http://www.a3uk.com/bm_modules/animatedtilelayer.js. Note that custom modules registered via the Bing Maps registerModule() method must be placed on a publicly-accessible website – you can’t register a custom module on a local URL. So, when you’re developing a module locally, I recommend that you get it working properly first using a regular embedded script, and then wrap it in a module at the last minute.

To use my new module, I registered and loaded it as follows:

// Register and load the animation module
Microsoft.Maps.registerModule('animatedTileLayerModule', 'http://www.a3uk.com/bm_modules/animatedtilelayer.js');
Microsoft.Maps.loadModule("animatedTileLayerModule", { callback: animationModuleLoaded });

The animationModuleLoaded callback would be fired after the module had loaded, and was responsible for creating a new instance of the animatedTileLayer class and adding it to the map, as follows:

function animationModuleLoaded() {

// Define the array of frame URLs. The URL for the tiles of each frame are
// stored in subdirectories corresponding to each timestamp, named by quadkey
var frames = [
  'http://www.a3uk.com/demos/aniamtedtilelayer/tiles/201105271015/{quadkey}.png',
  'http://www.a3uk.com/demos/aniamtedtilelayer/tiles/201105271030/{quadkey}.png',
  'http://www.a3uk.com/demos/aniamtedtilelayer/tiles/201105271045/{quadkey}.png',
  ...
];

// Create a new instance of the AnimatedTileLayer class
animatedTileLayer = new AnimatedTileLayer(
  map,     // Map instance to which tilelayer should be added
  frames,  // Array of frames of the animation
  {
     framerate: 1000,        // Delay between frame changes (ms)
     loopbehaviour: 'loop',  // Behaviour when last frame is met
     opacity: 1,             // Opacity of tile layer
     mode: 'dangerous',      // Method to use when switching layers
     frameChangeCallback: updateFrameCounter     // Callback on every frame change
   }
);

// Add the tilelayer to the map
map.entities.push(animatedTileLayer);
}

(The options passed to the AnimatedTileLayer constructor are explained in my previous posts). I also added a couple of basic HTML buttons to the page that would control starting, stopping, and resetting the animation, and a text input box that would display the timestamp of the currently displayed frame:

Animation Controls
 

The current frame counter would be updated by the function specified in the frameChangeCallback:

// Callback gets called every time frame changes
function updateFrameCounter(n) {

  // Display the frame counter
  document.getElementById('frameIndex').value = n;

  // Show the timestamp corresponding to this frame
  var t = String(timeStamps[n]);
  document.getElementById('frameTimeStamp').value = t.substr(0, 4) + '-' + t.substr(4, 2) + '-' + t.substr(6, 2) + ' ' + t.substr(8, 2) + ':' + t.substr(10,2);
}

Put it all together and what have you got?

So that’s it – my animatedtilelayer class wrapped into a custom module, registered and loaded from a page that creates a new animated tile layer and calls into a couple of the methods provided by the class.

You can play with (version 1.0) of the final product at http://www.a3uk.com/demos/animatedtilelayer/:

image

To Do:

There’s still a few bugs that I’m aware of that, at some point, I might try to fix:

  • Memory usage (especially in Firefox) seems to be an issue, and grows substantially if the animation is left running for a while – I’m not sure memory from the old tile layers is properly released following entitycollection.clear(), but I haven’t investigated this fully yet. (This problem is also reported by another user here). IE9 and Chrome appear to fare much better.
  • The tile layer vanishes while the map is scrolled (but then reappears when the map has finished scrolling) – this doesn’t seem to be unique to my animated tile layer, but is a behaviour of the way Bing Maps handles custom tile layers in general, so I’m not sure there is anything I can do about it.
  • By necessity of my attempt to pre-load the next tilelayer before displaying it on the map (to enable smoother transitions between frames), there is an initial delay after clicking “Play” before the first frame change. Again, I think this might end up being marked as “by design”!
  • I’m sure there’s more – I haven’t exactly comprehensively QA’d this module, but you’re free to make use of it as you see fit.

Google Earth: Plug-in running slow? Here’s a few tips

Ever since the Google Earth Plug-in was released almost three years ago we’ve been amazed by the great applications that have been built around it, including such things as an emergency response map, games and even a way to track Santa Claus.

It’s always worked well on Firefox 3.x, but it’s never performed as well when using Google Chrome because of the way that Chrome handles plugins. However, Firefox 4 was recently released and has the same issue that Chrome has, meaning both browsers perform very poorly when running the Google Earth Plug-in.

To help visualize the difference between various browsers, Paul van Dinther at PlanetInAction has created a slick Speed Test where you can check your relative frame rate on various browsers. Here’s how it works:

I build a simple test framework that animates 50 screen overlays. The animation addresses position, size and rotation. The animation is performed for each 3D frame drawn which means a total of 200 API calls are made per frame. At 60 fps that would be 12000 API calls per second. Not bad for a bit of Javascript.

speed-test.jpg

Fortunately, there is a workaround for Firefox 4 that helps quite a bit. If you type “about:config” into your address bar, you’ll get to a page with a lot of settings. Find the line for “dom.ipc.plugins.enabled = true” and toggle it to “false”. Restart your browser and things should run much better. Sadly, it’s set to “true” for new users by default, meaning that the performance of the Google Earth Plug-in for millions of users will be quite poor.

The Google Earth team is aware of the issue and they’re certainly looking for ways to resolve it. Because it’s a core browser issue, and not an issue specific to the Google Earth, it will likely be difficult to resolve, but just know that they’re working on it. You can track the issue using this page in the Chromium bug tracker. Be sure to “star” the bug to help this issue get the attention it deserves.

So what kind of numbers are you seeing with Paul’s speed test? Here are a few we’ve found:

Frank – MacBook Pro with 4GB of memory
Firefox 3: 40-45 FPS
Chrome 10: 4FPS

Me – Windows 7 Netbook with 2GB of memory
Chrome 11: 6 FPS
Firefox 4: 9 FPS
Firefox 4 with the about:config tweak: 28 FPS
Internet Explorer 8: 28 FPS

The difference in speed can be quite shocking. It’s not as bad for me on my desktop PC, which is more powerful, but the netbook really shows off the difference between various browsers.

How about you?

Protecting users from malicious downloads

For the past five years Google has been offering protection to users against websites that attempt to distribute malware via drive-by downloads — that is, infections that harm users’ computers when they simply visit a vulnerable site. The data produced by our systems and published via the Safe Browsing API is used by Google search and browsers such as Google Chrome, Firefox, and Safari to warn users who may attempt to visit these dangerous webpages.

Safe Browsing has done a lot of good for the web, yet the Internet remains rife with deceptive and harmful content. It’s easy to find sites hosting free downloads that promise one thing but actually behave quite differently. These downloads may even perform actions without the user’s consent, such as displaying spam ads, performing click fraud, or stealing other users’ passwords. Such sites usually don’t attempt to exploit vulnerabilities on the user’s computer system. Instead, they use social engineering to entice users to download and run the malicious content.

Today we’re pleased to announce a new feature that aims to protect users against these kinds of downloads, starting with malicious Windows executables. The new feature will be integrated with Google Chrome and will display a warning if a user attempts to download a suspected malicious executable file:

Download warning

This warning will be displayed for any download URL that matches the latest list of malicious websites published by the Safe Browsing API. The new feature follows the same privacy policy currently in use by the Safe Browsing feature. For example, this feature does not enable Google to determine the URLs you are visiting.

We’re starting with a small-scale experimental phase for a subset of our users who subscribe to the Chrome development release channel, and we hope to make this feature available to all users in the next stable release of Google Chrome. We hope that the feature will improve our users’ online experience and help make the Internet a safer place.

For webmasters, you can continue to use the same interface provided by Google Webmaster Tools to learn about malware issues with your sites. These tools include binaries that have been identified by this new feature, and the same review process will apply.