/** * ContentONE Maps Wrapper * * Wraps common mapping functionality. * * @version 1.1 * @date March 2, 2011 * @copyright (c) World Web Management Services (http://www.worldwebms.com/) */ (function($) { /** * Create C1 jQuery extension. */ if( !$.fn.c1 ) { $.fn.c1 = function( name, options ) { if( this.c1[name] ) return this.c1[name].call( this, options ); return this; } } /** * Create C1 Maps jQuery extension. */ $.fn.c1.maps = function( options ) { var t = this; // Ensure the map APIs have been loaded and we can use them if( !window.google.maps ) return this; // If a marker should be shown if( options.showMarker ) { var id = options.showMarker; var options = t.data( 'options' ); if( options && options._map && options.markers[id] ) { google.maps.event.trigger( options.markers[id]._marker, 'click' ); options._map.setCenter( options.markers[id]._marker.getPosition() ); options._map.setZoom( 13 ); if( $.fn.scrollIntoView ) t.scrollIntoView( { 'animation': 500, 'offsetTop': -20 } ); } return; // If an address should be geocoded } else if( options.geocode ) { // Create the geocoder if( $.fn.c1.maps._geocoder == null ) $.fn.c1.maps._geocoder = new google.maps.Geocoder(); // Geocode the address $.fn.c1.maps._geocoder.geocode( { 'address': options.address }, function( results, status ) { if( status == google.maps.GeocoderStatus.OK ) { options.geocode.call( options, { 'address': options.address, 'lat': results[0].geometry.location.lat(), 'lng': results[0].geometry.location.lng() } ); } else { alert( 'Unable to find the address due to the following reason: ' + status ); } } ); return false; } // Setup the default options options = $.extend( { // Initial view settings 'origin' : {'lat': -25.335448, 'lng': 135.745076, 'zoom': 4}, 'type' : 'roadmap', // Controls 'controls' : {'default': true}, // Markers 'markers' : [], // Layers 'layers' : { 'poi.business': 'off' }, // Info window settings 'directions': false, 'info': true }, options ); // Convert the directions to the jquery object if( options.directions == false ) options.directions = null; else if( options.directions == true ) options.directions = {'container': null}; else options.directions = {'container': $(options.directions).hide()}; // Initialize the map t.addClass( 'loaded' ).addClass( 'c1-maps' ); // Check for markers from other sources for backwards compatibilty if( options.markers.length == 0 ) { // Lat/lng coordinates provided as map arguments if( options.lat || options.lng ) { options.origin.lat = options.lat; options.origin.lng = options.lng; // Single marker provided } else if( options.marker ) { options.markers.push( options.marker ); } } // If the initial view settings need to be determined var lat = options.origin.lat; var lng = options.origin.lng; if( options.origin.zoom == 'auto' ) { options.zoom = 'auto'; options.origin.zoom = 4; } var zoom = options.zoom || options.origin.zoom; // If the origin has an icon then add another marker if( options.origin.icon ) { if( options.origin.icon == 'default' ) options.origin.icon = 'http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/blank.png'; options.markers.push( options.origin ); } // If there is only one marker then change the origin to the marker if( options.markers.length == 1 ) { lat = options.markers[0].lat; lng = options.markers[0].lng; if( options.markers[0].zoom ) zoom = options.markers[0].zoom; } // Handle zoom levels var markerBounds = false; var mapBounds = false; // Show all markers if( zoom === 'auto' ) { markerBounds = new google.maps.LatLngBounds(); mapBounds = new google.maps.LatLngBounds(); // Show full custom map } else if( zoom === 'fill' ) { mapBounds = new google.maps.LatLngBounds(); // Show all of Australia } else if( zoom === 'au' ) { mapBounds = new google.maps.LatLngBounds( new google.maps.LatLng(-11, 113), new google.maps.LatLng(-44, 154) ); } // Create the map var mapOptions = { zoom: mapBounds ? 15 : zoom }; if( markerBounds == false ) mapOptions.center = new google.maps.LatLng( lat, lng ); switch( options.type ) { case 'hybrid': mapOptions.mapTypeId = google.maps.MapTypeId.HYBRID; break; default: mapOptions.mapTypeId = google.maps.MapTypeId.ROADMAP; break; } // Change background if( options.background ) mapOptions.backgroundColor = options.background; // Specify a custom map if( options.type == 'custom' ) { // Custom maps are generated from a single image. // Markers and points within the map are pixel-based. // These points are converted to the relevant lat/lng coordinate // when displaying in the map. // Default values options.map = $.extend( { 'tileSize': 256, 'minZoom': 2, 'maxZoom': 4 }, options.map ); // Define a custom projection that can display the map starting // from (0,0) and show complete map in bottom right corner. function CustomMapProjection() { this.origin = new google.maps.Point(0, 0); this.perLonDegree = this.mapSize.width / 360; this.latRange = this.mapSize.height / 4; } CustomMapProjection.prototype.fromLatLngToPoint = function(latLng) { var origin = this.origin; var x = origin.x + this.perLonDegree * latLng.lng(); var latRadians = latLng.lat() * (Math.PI / 180); var y = origin.y - this.latRange * Math.sin(latRadians); return new google.maps.Point(x, y); } CustomMapProjection.prototype.fromPointToLatLng = function(point, noWrap) { var y = point.y; var x = point.x; if (y < 0) y = 0; if (y >= this.mapSize.height) y = this.mapSize.height; var origin = this.origin; var lng = (x - origin.x) / this.perLonDegree; var latRadians = Math.asin((origin.y - y) / this.latRange); var lat = latRadians / (Math.PI / 180); return new google.maps.LatLng(lat, lng, noWrap); } // Utility functions that can convert a pixel coordinate to // a lat/lng coordinate and vice versa. CustomMapProjection.prototype.fromLatLngToPixel = function(latLng) { var worldCoordinate = this.fromLatLngToPoint(latLng); var zoom = 1 << this.maxZoom; return new google.maps.Point(Math.round(worldCoordinate.x * zoom), Math.round(worldCoordinate.y * zoom)); } CustomMapProjection.prototype.fromPixelToLatLng = function(point) { var zoom = 1 << this.maxZoom; var worldCoordinate = new google.maps.Point(point.x / zoom, point.y / zoom); return this.fromPointToLatLng(worldCoordinate); } // Determine the dimensions of the map to display // Give some padding to the latitude height as generally lats finish around 85 degrees. CustomMapProjection.prototype.mapSize = new google.maps.Size(options.map.image.w, options.map.image.h * 1.1); CustomMapProjection.prototype.tileSize = new google.maps.Size(options.map.tileSize, options.map.tileSize); CustomMapProjection.prototype.maxZoom = options.map.maxZoom; // Create the custom map type function CustomMapType() { } CustomMapType.prototype.projection = options.map._projection = new CustomMapProjection(); CustomMapType.prototype.tileSize = CustomMapProjection.prototype.tileSize; CustomMapType.prototype.maxZoom = CustomMapProjection.prototype.maxZoom; if (options.map.minZoom) CustomMapType.prototype.minZoom = options.map.minZoom; CustomMapType.prototype.getTile = function(coord, zoom, ownerDocument) { // Determine how many tiles are required to display the image var rZoom = this.maxZoom - zoom; var factor = (rZoom > 0 ? Math.pow(2, rZoom) : 1) * this.tileSize.width; var numTilesX = Math.ceil(options.map.image.w / factor); var numTilesY = Math.ceil(options.map.image.h / factor); // If the tile is outside of the source image then display an empty div // as there is no need for an image to be created. if (coord.y < 0 || coord.y >= numTilesY || coord.x < 0 || coord.x >= numTilesX) { var div = ownerDocument.createElement('div'); div.style.width = this.tileSize.width + 'px'; div.style.height = this.tileSize.height + 'px'; div.style.backgroundColor = 'transparent'; return div; } // Determine the url to generate the tile from var image = ownerDocument.createElement('img'); image.src = options.map.image.src.replace( /(-tile-\d+x\d+)(.\w+)$/, '$1-x' + coord.x + 'y' + coord.y + 'z' + (options.map.maxZoom - zoom) + '$2' ); image.width = this.tileSize.width; image.height = this.tileSize.height; return image; } // Disable common controls in map interface mapOptions.streetViewControl = false; mapOptions.mapTypeControl = false; options.directions = false; } // Process layers var mapStyles = []; $.each( options.layers, function( name, layerConfig ) { if (layerConfig === 'off') { mapStyles.push( { featureType: name, stylers: [{ visibility: 'off'}] } ); } } ); if (mapStyles.length > 0) { mapOptions.styles = mapStyles; } // Create the map options._map = new google.maps.Map( this.get( 0 ), mapOptions ); // Start the custom map if( options.type == 'custom' ) { options._map.mapTypes.set('custom', new CustomMapType()); options._map.setMapTypeId('custom'); // Add grid overlay debugging tools if( options.map.debug ) { function CoordMapType(tileSize) { this.tileSize = tileSize; } CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) { // Determine pixel coordinate var projection = options._map.getProjection(); var numTiles = 1 << zoom; var rZoom = options.map.maxZoom - zoom; var factor = 1 << rZoom; var pixelCoordinate = new google.maps.Point( coord.x * this.tileSize.width * factor, coord.y * this.tileSize.height * factor ); var worldCoordinate = new google.maps.Point( coord.x * this.tileSize.width / numTiles, coord.y * this.tileSize.height / numTiles ); var latLng = projection.fromPointToLatLng(worldCoordinate); var div = ownerDocument.createElement('div'); div.innerHTML = 'tile: ' + coord + '
' + 'pixel: (' + pixelCoordinate.x + ',' + pixelCoordinate.y + ')
' + 'lat/lng: (' + latLng.lat().toFixed(3) + ',' + latLng.lng().toFixed(3) + ')'; div.style.width = this.tileSize.width + 'px'; div.style.height = this.tileSize.height + 'px'; div.style.borderStyle = 'solid'; div.style.borderWidth = '1px'; div.style.borderColor = '#aaa'; return div; } options._map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(options.map.tileSize, options.map.tileSize))); } // Adjust bounds if full map should be shown by extending the bounds // to north-west and south-east corners. if( zoom === 'fill' ) { mapBounds.extend(options.map._projection.fromPixelToLatLng(new google.maps.Point(0, 0))); mapBounds.extend(options.map._projection.fromPixelToLatLng(new google.maps.Point(options.map.image.w, options.map.image.h))); } } // Create delivery service wrapper if( options.directions ) { if( options.directions === true ) options.directions = {}; options.directions._service = new google.maps.DirectionsService(); options.directions._render = new google.maps.DirectionsRenderer(); options.directions._render.setMap( options._map ); } // Returns a lat lng object from a given set of coordinates function getLatLng( x, y ) { if( options.map && options.map.unit == 'px' ) return options.map._projection.fromPixelToLatLng(new google.maps.Point(x, y)); return new google.maps.LatLng(y, x); } // Add markers function createMarker( pos ) { var details = options.markers[pos]; // Setup the marker var config = { 'position': getLatLng(details.lng, details.lat), 'map': options._map, 'title': details.name ? details.name : '' }; // Create ordered icons if required if( !details.icon && options.icon ) { // Create ordered icons if required if( options.icon == 'count' ) { var a = 'A'; if( pos <= 25 ) details.icon = 'http://www.google.com/mapfiles/marker' + String.fromCharCode(a.charCodeAt(0) + pos) + '.png'; else details.icon = 'http://www.google.com/mapfiles/marker.png'; // URL based icon } else if( options.icon.indexOf( '/' ) >= 0 ) { details.icon = options.icon; } } // Add the icon if( details.icon ) { config.icon = details.icon; if( details.legend ) $(details.legend).html( '.' ); } // If draggable if( details.drop ) config.draggable = true; // Create the marker var marker = new google.maps.Marker(config); if( options.info ) google.maps.event.addListener(marker, 'click', function() { openInfoWindow( pos ); }); // Add drop event if( details.drop ) google.maps.event.addListener(marker, 'dragend', details.drop); // Adjust the bounds if( markerBounds ) markerBounds.extend( config.position ); // Add link from list to open window if( details.list ) $(details.list).click( function( event ) { openInfoWindow( pos, null, true ); } ).css( 'cursor', 'pointer' ); return marker; } $.each( options.markers, function( i ) { this._marker = createMarker( i ); } ); // If all markers should be displayed if( markerBounds ) mapBounds = markerBounds; // Show a specific area within the map if( mapBounds ) { var zoomChangeListener = google.maps.event.addListener( options._map, 'zoom_changed', function() { var zoomChangeBoundsListener = google.maps.event.addListener( options._map, 'bounds_changed', function( event ) { if( this.getZoom() > 16 ) this.setZoom( 16 ); google.maps.event.removeListener( zoomChangeBoundsListener ); } ); google.maps.event.removeListener( zoomChangeListener ); } ); options._map.fitBounds( mapBounds ); } // Creates the content for the window function getInfoWindowHtml( pos ) { var details = options.markers[pos]; // Build the HTML var html = details.html || details.info; if( html == null ) { html = ( details.name ? ( '' + details.name + '
' ) : '' ) + ( details.address ? ( details.address.replace( "\n", '
' ) ) : '' ); } // Start the container html = '
' + html; // Add direction options if( options.directions ) html += '
Directions to here
'; // End the container html += '
'; return html; } // Opens a window function onInfoWindowClose() { // if( options.directions.container ) // options.directions.container.fadeOut( 500 ); // if( options._directions ) // options._directions.clear(); } function openInfoWindow( pos, open, scroll ) { if( options.info == false ) return; if( options._infoWindow == null ) options._infoWindow = new google.maps.InfoWindow({'content': ''}); options._infoWindow.setContent( getInfoWindowHtml( pos ) ); options._infoWindow.open( options._map, options.markers[pos]._marker ); if( scroll && $.fn.scrollIntoView ) t.scrollIntoView( { 'animation': 'slow', 'offsetTop': -20 } ); } // Open info window if( options.info && options.markers.length == 1 && ( options.markers[0].name != '' || options.markers[0].info != '' ) ) openInfoWindow( 0, function() { if( options.from ) { var window = t.find( '.infoWindow' ); window.find( '.directions a').click(); window.find( 'input[name="from"]').val( options.from ); window.find( 'form' ).submit(); } } ); // Save options t.data( 'options', options ); return this; }; })(jQuery); var C1MapsAPI = { // Get directions to the destination toHere: function( source ) { var window = $(source).parents( '.infoWindow' ); var matches = source.className.match( /marker-(\d+)/ ); var pos = matches[1]; var options = window.parents( '.c1-maps' ).data( 'options' ); window.data( 'html', window.html() ); window.html( '
' + 'Directions to ' + ( options.markers[pos].name ? options.markers[pos].name : 'here' ) + '
' + 'Start address:
' + '
' + ' ' + '
' ); window.find( 'form' ).submit( function() { if( options.directions.container ) { options.directions.container.find( '.content' ).html( '' ); options.directions.container.fadeIn( 500 ); } var request = { origin: window.find( 'input[name="from"]' ).val(), destination: options.markers[pos].lat + ' ' + options.markers[pos].lng }; request.travelMode = google.maps.DirectionsTravelMode.DRIVING; options.directions._service.route(request, function( result, status ) { if( status == google.maps.DirectionsStatus.OK ) options.directions._render.setDirections( result ); }); return false; } ); window.find( 'input[type="button"]' ).click( function() { window.html( window.data( 'html' ) ); if( options.directions.container ) options.directions.container.fadeOut( 500 ); if( options._directions ) options._directions.clear(); } ); return false; } };