User:SignpostMarv Martin/Webmap API Examples

From Second Life Wiki
Jump to: navigation, search
Note: see agni.sl.mapapi.net for a production example of the refactored JavaScript.


This article covers the refactored javascript for the SLURL Map API made by SignpostMarv Martin for Open Hack 2009.

Automated documentation is available, along with a minified version of the Pluggable SLurl Javascript.

Summary of modifications

  • All functions were moved into a SLURL object, e.g. SLMap becomes SLURL.map
  • Some functions became pluggable
  • Some functions were improved for ease of use

Base HTML

Live Example: http://dev.signpostmarv.name/pub/secondlife/slurl.html

<html4strict><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Hack Day '09: Pluggable SLurl!</title> <meta http-equiv="Content-Type" content="application/xhtml+xml;charset=UTF-8" /> <script src="http://maps.google.com/maps?file=api&v=2&key=[YOUR GOOGLE MAP API KEY HERE]" type="text/javascript"></script> <script src="http://www.google.com/jsapi?key=[YOUR GOOGLE SEARCH API KEY HERE]" type="text/javascript"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script> <script src="http://static.marvulous.co.uk/%C2%B5/js/slurl/mapapi.js" type="text/javascript"></script>

<link rel="stylesheet" type="text/css" href="http://slurl.com/_styles/MAIN.css" /> <script type="text/javascript"> /*<![CDATA[*/ $(function() { mapInstance = new SLURL.map(document.getElementById('map-container')); mapInstance.gotoRegion('Hippotropolis'); }); $(document).unload(function() { // Google script that helps prevent memory leaks // (we're looking at you when we say that IE!) GUnload(); /*]]>*/ }); </script> </head> <body>

</body> </html></html4strict>

Adding a Plugin

The key feature of the refactoring (aside from shifting everything into a SLURL object) was to make the SLURL JS "pluggable"- making it easier to extend a SLURL map without needing to create & edit a duplicate of the javascript (which would become difficult to maintain over time the more customisations were made).

Currently, two functions can have callbacks registered with them:

  1. gotoRegion
  2. gotoSLURL

The internals of a plugin can be coded however you want them to, but the callback function for the plugin must be structured along these lines:

gotoSLURL,gotoRegion

<javascript>function my_callBack(slRegionName,x,y,SLMap) { // do stuff here }</javascript>

Registering a callback

Callback functions are registered to a particular instance of a SLURL map, enabling multiple maps to be used on the same page with different plugins.

For example, to enable Marv's Flickr plugin, the following modifications are made to the base HTML;

1) The Flickr plugin is added below mapapi.js: <html4strict><script src="http://static.marvulous.co.uk/%C2%B5/js/slurl/plugins/flickr.js" type="text/javascript"></script></html4strict> 2) Some extra CSS is added below MAIN.css: <html4strict><link rel="stylesheet" type="text/css" href="http://dev.signpostmarv.name/pub/secondlife/slurl-hacks.css" /></html4strict> 3) The Flickr plugin is configured: <javascript>SLURL_flickr.apiKey = whatever_your_api_key_is; SLURL_flickr.groupId = '51035802764@N01'; // Second Life flickr group ID- the same one linked from the official blog. change to suit. SLURL_flickr.searchMode = 'group'; // the plugin defaults to 'global'- e.g. searching all flickr photos. SLURL_flickr.resultsPerPage = 32; // the number of thumbnails to display SLURL_flickr.prependResultsHTML = ; // Useful for adding a header in before the results.</javascript> 4) The callbacks are registered after the mapInstance has been declared: <javascript> SLURL.addCallBack.gotoSLURL(mapInstance,SLURL_flickr.searchRegion); SLURL.addCallBack.gotoRegion(mapInstance,SLURL_flickr.searchRegion);</javascript>

5) Finally, some extra HTML for containing the flickr results is added to the body:<html4strict>
</html4strict>

Ease-of-use Improvements

SLURL.map.panTo

A wrapper method has been added to map instances allowing you to safely use SLURL.XYPoint instances to specify co-ordinates. <javascript>mapInstance.panTo(new SLURL.XYPoint(x,y));</javascript>

Adding multiple scripts

  • SLURL.addScript has been modified to accept an array for the scriptURL argument. Doing so will call SLURL.addScript for each item.
  • The load handler function will be called for all scripts, though load order cannot of course be guaranteed.

Pluggable SLURL uses this ease-of-use modification when loading the information sources for the Events & Poly Info plugins: <javascript>SLURL.addScript([ 'http://svc.sl.marvulous.co.uk/sl-event-transposer.php', 'http://svc.sl.marvulous.co.uk/sl-mapapi-office-hours.php', 'http://svc.sl.marvulous.co.uk/old-grid-size.js', 'http://svc.sl.marvulous.co.uk/roads.js' ]);</javascript>

Adding GPolyline & GPolygon

Two new methods have been added to the SLURL namespace:

  1. SLURL.Polygon
  2. SLURL.Polyline

Both methods will have property GPoly when instantiated, allowing them to be added to & removed from a map with ease.

The first argument (used to specify the Poly points) should be an array of SLURL.XYPoint objects.

The Poly Info plugin uses these methods thusly:

SLURL.Polygon

<javascript>new SLURL.Polygon(info.points,info.stroke[zoom],info.fill,{},func);</javascript>

SLURL.Polyline

<javascript>new SLURL.Polyline(info.points,info.stroke[zoom],{},func);</javascript>


Adding a Marker

Key Namespace Alterations

  1. SLURL.map.addMarker (previously SLMap.addMarker)
  2. SLURL.Img (previously Img)
  3. SLURL.Icon (previously Icon)
  4. SLURL.Marker (previously Marker)
  5. SLURL.XYPoint (previously XYPoint)

SLURL.map.addMarker has been altered for ease of use- the previous syntax for adding a single image as a marker required superfluous variables: <javascript> var yellow_dot_image = new Img("b_map_yellow.gif",9,9);

 var yellow_icon = new Icon(yellow_dot_image);
 var all_images = [yellow_icon, yellow_icon, yellow_icon, yellow_icon, yellow_icon, yellow_icon];
 
 // creates the marker
 marker = new Marker(all_images, new XYPoint(997,1002));
 mapInstance.addMarker(marker);</javascript>

The function has been modified in two ways:

  1. A single string can be passed instead of an array
  2. Arrays with fewer than 6 items have the first item padded

These two minor alterations simplify things, making the previous example: <javascript> var yellow_dot_image = new SLURL.Img("b_map_yellow.gif",9,9);

 var yellow_icon = new SLURL.Icon(yellow_dot_image);
 marker = new Marker(yellow_icon,new SLURL.XYPoint(997,1002));
 mapInstance.addMarker(marker);</javascript>

Multi-Grid Support

Some significant modifications were made to allow one core Javascript file to service maps for multiple grids.

Currently the same type of tiles as the Agni map must be used (e.g. multiple regions shrunk and composited into a single image dependant upon zoom level).

A really under-powered demo of gridConfig is available on Marv's dev server- it only changes the background color and starting region (to highlight the background color change).

Structure of gridConfig

<javascript> // This is based on the gridConfig for Agni { oceanColor : '#1d475f', // background color of the "ocean" (only displayed when no image is available) defaultRegion : 'Ahern', // default region to direct the map to if none is specified defaultCoords : // default parcel co-ordinates for use when none are specified or some are missing. { x : 128, y : 128, z : 20 }, init : function(SLMap) // Called during the instantiation of a map object { // do stuff here }, getTileURL : function(pos, zoom) // function for returning the grid map images { // should return an appropriate URL for the specified position & zoom level }, gotoRegion : function(SLMap,regionName,onLoadHandler) // Should poke external web-service or hard-coded array { // do stuff here }, gotoCoords : function(SLMap,x,y,z) // Should poke external web-service or hard-coded array { // do stuff here } }</javascript>

Specifying a gridConfig

The gridConfig object is passed as the third argument when instantiating a map object:

<javascript> m = new SLURL.map( document.getElementById('map-container'), {}, gridConfig );</javascript>

If no gridConfig is specified, the map instance will default to the gridConfig for Agni: <javascript>//partial snippet from Pluggable SLurl SLURL.map = function(map_element, map_options,gridConfig) { if(gridConfig == undefined) { this.gridConfig = SLURL.gridConfig['com.lindenlab.agni']; } else { this.gridConfig = gridConfig; }</javascript>

Note: because Agni's grid config is stored in the SLURL object, plugins could be used to replace variables or methods, removing the need to modify the core Javascript when working on new features.