Detect IE 8 – 12 using simple JS

This is a simple JS to detect the version of IE from 8 – 11, which helped me write IE specific styles without any crazy IE Hacks or conditional statements.

This JS will add a class on the HTML tag(you can target any tag inside the HMTL) specific to that IE version.
Example you are on IE10 the html tag will be <html class=”ie ie10″>

Note: This JS needs to be placed before all you styles.

JSFiddle: https://jsfiddle.net/giri_jeedigunta/2ctoccs7/



(function(ua) {
     var browserData = ua,
         targetTag = document.getElementsByTagName("html")[0],
         ieInfo,
         className,
         versionNum;

     /* IE Check Starts */
     if (browserData.indexOf("MSIE ") > 0) {
         /* Check for IE 8, 9 */
         ieInfo = browserData.indexOf("MSIE ");
         versionNum = parseInt(browserData.substring(ieInfo + 5, browserData.indexOf(".", ieInfo)), 10);
     } else if (browserData.indexOf("Trident/") > 0) {
         /* Check for IE 10 */
         ieInfo = browserData.indexOf("rv:");
         versionNum = parseInt(browserData.substring(ieInfo + 3, browserData.indexOf(".", ieInfo)), 10);
     } else if (browserData.indexOf("Edge/")) {
         /* Check for IE 11 */
         ieInfo = browserData.indexOf("Edge/");
         versionNum = parseInt(browserData.substring(ieInfo + 5, browserData.indexOf(".", ieInfo)), 10);
     }
     /* IE Check Ends */

     // Adding the Class to the Targeted HTML Tag.
     className = "ie ie" + versionNum;
     if (isNaN(versionNum)) return !1;
     targetTag.setAttribute("class", className); // Example Output for IE 11: <html class="ie ie11">    

 }(window.navigator.userAgent));

Cross browser SVG Masking – Supports IE8, IE9, IE10, Firefox, Chrome

In one of my recent projects I  ran into performance issues with the usage of multiple  png images(each image up to 1mb). So I started to research on the masking and clipping concepts over the web but nothing was close to what I wanted to achieve.  I want the code to be simple, maintainable and mostly work on all commonly used browsers.

I’ve come up with a cross-browser solution which supports Firefox, chrome, safari, IE v9 and above. Thankfully  IE v9 and above have support for basic SVG, masking and clipping. Here are some examples from the microsoft site: http://msdn.microsoft.com/en-us/library/ie/bg124134(v=vs.85).aspx on simple masking and clipping.

For IE v8: You can use the chromakey filter technique found in this wonderful tutorial: thenittygritty.co/css-masking

Here is the code / some steps involved:

You don’t need to create complex vector code or .SVG files for this solution. I made made the required mask shape as mask.png and applied it on top of the sample.jpg using SVN Mask code as shown below:

    <div class="svgMask">
        <svg width="400" height="300" baseProfile="full" version="1.2">
            <defs>
                <mask id="svgmask2" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse" transform="scale(1)">
                    <image width="100%" height="100%" xlink:href="mask.png"/>
                </mask>
            </defs>
            <image mask="url(#svgmask2)" width="100%" height="100%" y="0" x="0" xlink:href="sample.jpg"/>
        </svg>
    </div>

Here is the demo on JSFiddle: http://jsfiddle.net/giri_jeedigunta/Z2J34/

The important thing with SVG is the height attribute. If you don’t mention proper height nothing will be visible.

DOM Manipulation: Please refer the createlementNS on MDN : https://developer.mozilla.org/en-US/docs/Web/API/document.createElementNS

Mobile Support: This worked perfectly fine on iPhone, iPad, Chrome on Android Phones but the native browser on the samsung s3 did not render this code.

Even though most of the online resources like http://caniuse.com/svg said that there is support for android, it failed to render on the native browser. You can use -webkit-mask as a fallback option for scenarios like this.

Google Maps: Driving Directions Using Query String Parameters

Passing few query string parameters can land the user on the Google Maps Page with Driving Directions.

Examples:
1) https://maps.google.com/maps?f=d&saddr=New%20Ringgold,%20PA,%20USA&daddr=Allentown,%20PA,%20USA
2) https://maps.google.com/maps?f=d&saddr=17960&daddr=17980

f: stands for “form” and controls the style of query form to be displayed.
f=d: Displays the “directions” form (two input boxes: from, to).
saddr: “saddr” source address. Use this when asking for driving directions.
daddr: “daddr” Destination address(es). Use this when asking for driving directions.

More detailed article on the Google Maps Query Strings:
http://asnsblues.blogspot.in/2011/11/google-maps-query-string-parameters.html

Custom Directions Panel with Google Maps API v3

I’ve been working a lot on Google Maps API V3 these days and most recently worked on the get directions. So I thought I will put up a small tutorial which covers the below:

Final Map with Directions Panel
Prerequisites: Knowledge on XHTML / HTML5, CSS, Good understanding of JS / jQuery is required.

For Map Basics refer:  Google Maps API Integration

 Custom Directions Panel or Google Maps Like Direction Panel:

Directions Setup Basic:

DirectionsService() is an asynchronous service comes along with the Google Maps API V3 which will generate the directions results upon providing the appropriate direction requests(source and destination). This service will generate a JSON as output, to render this JSON we can use the default rendering option DirectionsRenderer() provided in the API or we can also use the routes object to manually render each and every detail. I’ve used the DirectionsRenderer() option in this example.

Here is a glance at the code for the above two services. These needs to be setup once the map is initialized.

directionsSetup = function() {
	directionsService = new google.maps.DirectionsService();
	directionsDisplay = new google.maps.DirectionsRenderer({
		suppressMarkers: true
	});                   

	directionsDisplay.setMap(map);
	directionsDisplay.setPanel($Selectors.dirSteps[0]);
}, // direstionsSetup Ends

Get Directions:

Also, in the above code I’ve passed the option "suppressMarkers: true" in the DirectionsRenderer service which will suppress the default map marker images provided by Google and allows us to use the custom marker images.

The below function helps to generate the directions by taking the source and destination values from the input fields in the HTML or geolocation and passes the values to directions service, on success it will generate a response.

The div where the response needs to be rendered should be defined using: directionsDisplay.setPanel($Selectors.dirSteps[0])

Along with the setPanel we also need setDiretions to display the response in the div.
directionsDisplay.setDirections(response)

The response contains route object which will contain all the direction details like start / end position coordinates, waypoints and lot of other details.

Tip: If you want to completely customize the look and feel of the direction steps you need to use the route object to extract the details like, position, distance, route text etc,. and style them accordingly. If you need more details on this just leave a comment I can help you with whatever I know.

directionsRender = function(source, destination) {
	var request = {
		origin: source,
		destination: destination,
		provideRouteAlternatives: false, 
		travelMode: google.maps.DirectionsTravelMode.DRIVING
	};		

	directionsService.route(request, function(response, status) {
		if (status == google.maps.DirectionsStatus.OK) {
			directionsDisplay.setDirections(response);
			var _route = response.routes[0].legs[0]; 
			pinA = new google.maps.Marker({
				position: _route.start_location,
				map: map,
				icon: markerA
			}),
			pinB = new google.maps.Marker({
				position: _route.end_location,
				map: map,
				icon: markerB
			});
		}
	});
}, // directionsRender Ends

A detailed documentation on the DirectionsService is available here.

 Custom Direction Markers

To customize the makers on the map we need to define them using the below code:

Defining Custom Marker Images:

var markerA = new google.maps.MarkerImage('m1.png',
		new google.maps.Size(24, 27),
		new google.maps.Point(0, 0),
		new google.maps.Point(12, 27));
var markerB = new google.maps.MarkerImage('m2.png',
		new google.maps.Size(24, 28),
		new google.maps.Point(0, 0),
		new google.maps.Point(12, 28))

Replacing the Markers on the Map:

Once the marker images are defined we can simple map then to the A and B markers on the map using the Marker object like shown below:

Here I have used the route object and manually setup the start and end markers.
Important: If you don’t use the below code you will not see any markers on the Map at all.

var _route = response.routes[0].legs[0];
pinA = new google.maps.Marker({
	position: _route.start_location,
	map: map,
	icon: markerA
});
pinB = new google.maps.Marker({
	position: _route.end_location,
	map: map,
	icon: markerB
});

 Autocomplete Integration (Google Places API):

_auto_complete

Autocomplete or the Google Places API is the most easiest to integrate. This is a really powerful feature and you can do a whole bunch of things with it.

Here is a glace at the code. It’s very simple and straight forward all you need to do is pass the input field.

autoCompleteSetup = function() {
	autoSrc = new google.maps.places.Autocomplete($Selectors.dirSrc[0]);
	autoDest = new google.maps.places.Autocomplete($Selectors.dirDst[0]);
}, // autoCompleteSetup Ends

 Traffic Layer Integration (Adding Custom Control To Map)

_traffic_layer

There is no straight forward parameter / code for traffic layer integration. You need to setup a custom map control and bind it with an event to enable and disable the traffic layer.

Good thing is it’s not that complicated at all. Have a look at the code below:

trafficSetup = function() {
  // Creating a Custom Control and appending it to the map
  var controlDiv = document.createElement('div'), 
	  controlUI = document.createElement('div'), 
	  trafficLayer = new google.maps.TrafficLayer();

  jQuery(controlDiv).addClass('gmap-control-container').addClass('gmnoprint');
  jQuery(controlUI).text('Traffic').addClass('gmap-control');
  jQuery(controlDiv).append(controlUI);

  // Traffic Btn Click Event
  google.maps.event.addDomListener(controlUI, 'click', function() {
	  if (typeof trafficLayer.getMap() == 'undefined' || trafficLayer.getMap() === null) {
		  jQuery(controlUI).addClass('gmap-control-active');
		  trafficLayer.setMap(map);
	  } else {
		  trafficLayer.setMap(null);
		  jQuery(controlUI).removeClass('gmap-control-active');
	  }
  });
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(controlDiv);
}, // trafficSetup Ends

Learn more about Custom Map Controls Here.


var trafficLayer = new google.maps.TrafficLayer();
trafficLayer.setMap(map);
 

The above code will setup the traffic layer on top of the map. But once the traffic layer is set up you don’t have any direct option to disable it. Hence I have a custom control in place which helps me to easily enable and disable the traffic layer.

I’ve learned all about traffic integration from this tutorial. Pieter Vogelaar the author of the tutorial also included the code to display details of the traffic legends.

 HTML 5 GeoLocation, The Google Geocoding API Integration

_geo_location

The geolocation API lets you share your location(latitude and longitude) once the user allows the api to track the location we can pass the coordinates to the Google Geocoding API and get a formatted address.

Invoking the HTML 5 Geolocation:

$Selectors.useGPSBtn.on('click', function(e) {
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(function(position) {
			fetchAddress(position);
		});
	}
});

Using the Google Geocoding API:

fetchAddress = function(p) {
	var Position = new google.maps.LatLng(p.coords.latitude, p.coords.longitude),
		Locater = new google.maps.Geocoder();

	Locater.geocode({'latLng': Position}, function (results, status) {
		if (status == google.maps.GeocoderStatus.OK) {
			var _r = results[0];
			$Selectors.dirSrc.val(_r.formatted_address);
		}
	});
} // fetchAddress Ends

 

This tutorial is still a work in progress. My intention is to just give a basic idea on how we can put things together. Any feedback is welcome. Please comment or email me for any questions.

Click Here to download the complete code.

Good Luck!

Custom infowindow with jQuery UI Tabs using infobox, Google Maps API v3

Recently, I started using Google Maps API v3 and one of the things I wanted to achieve is to customize the default infowindow, re-skin it and add some tabbed content into it.

After some R&D I found infobox JS which allows you to customize the default infowindow. You can add styles and any HTML content. In a way it actually replaces the default infowindow functionality.

So in this tutorial I’m going to explain how I’ve used Google Maps API v3, jQuery UI Tabs and Infobox JS to achieve the below:

Prerequisites: Knowledge on XHTML / HTML5, CSS, JSON, Good understanding of JS and jQuery is required.

More Tutorials on Google Maps API V3: I’ve recently put up a tutorial on Get Directions and Custom Directions Panel.

HTML5 Mark-up:

<!DOCTYPE html>
<html>
  <head>

    <title>Google Maps API V3: Custom Infowindow using Infobox</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

    <link rel="stylesheet" href="jquery-ui-1.9.0.custom/css/ui-lightness/jquery-ui-1.9.0.custom.min.css" type="text/css" media="all" />

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>    
    <script type="text/javascript" src="jquery-ui-1.9.0.custom/js/jquery-ui-1.9.0.custom.min.js"></script>

    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=&sensor=false"></script>
    <script type="text/javascript" src="infobox.js"></script>

    <style type="text/css">
    	body {margin: 0; padding: 0; width:100%; height: 1000px; overflow: hidden}
    	#map_canvas {margin:0 auto; width: 100%; height: 90%}
		#tabs {font-size: x-small; width: 255px; height: 150px}
		#tabs .ui-tabs-nav {height: 25px}
		p {font-size: x-small; marign: 0; padding: 0}
    </style>

  </head>
  <body>
    <div id="map_canvas"> </div>
    <script type="text/javascript" src="sample.js"></script> 
  </body>
</html>

Google Maps API v3 Basics:

Reference Javascript script:

You need to add the below reference Javascript script to your page. There is no need of API key to use Google Maps API v3. Sensor parameter is false by default. If your device have a GPS sensor make the sensor parameter true(sensor=true).

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=&sensor=false"></script>

Creating a Map:

To initialize the Map, we need to call constructor of Map class. It takes 2 arguments one is reference of HTML element to insert map (<div id=”map_canvas”> </div>) and two is Map options object.

map = new google.maps.Map(mapCanvas, {
	zoom: 10,
	center: new google.maps.LatLng(-33.950198, 151.259302),
	mapTypeId: google.maps.MapTypeId.ROADMAP 
});

zoom: It is a number to set initial zoom level of the map
center: It sets center of the map by taking coordinates of latitude and longitude.
mapTypeId: It specifies initial type of map. It is an identifier of google.maps.MapTypeId class.

Before continuing further please go through the Google MAPS API v3 Tutorials and get familiarized with the default options and functionalities.

Customizing infowindow using infobox JS:

The objective of this JS is to access the JSON Data and setup the markers using the latitude and longitude on the Google Map and add the custom infobox with jQuery UI Tabs for each of the markers.

For this tutorial I’ve used a JSON file which contains the location data(latitude and longitude). I’ve used a Singleton JS pattern coding standard for the JS. You can read more about this pattern here: The Singleton Pattern – Addy Osmani

Below is the JS code:

var myCustomMaps = (function (jQuery) {
	var instance, 
		map,
		mapCanvas = jQuery('#map_canvas')[0], 
		init = function () {
			return {
				pageLoad: function () {
					this.invokeMyMaps();										
				},	
				invokeMyMaps: function() {	

					var	markers = [], infoBubbles = [], infoBubble, 
						contentString=['<div id="tabs">','<ul>','<li><a href="#tab-1"><span>Tab1</span></a></li>','<li><a href="#tab-2"><span>Tab2</span></a></li>','<li><a href="#tab-3"><span>Tab3</span></a></li>','</ul>','<div id="tab-1">','<p>Tab 1 content. You can customize it further and make this dynamic / JS Object</p>','</div>','<div id="tab-2">','<p>Tab 2 content</p>','</div>','<div id="tab-3">','<p>Tab 3 content</p>','</div>','</div>'].join('');

					map = new google.maps.Map(mapCanvas, {
						zoom: 10,
						center: new google.maps.LatLng(-33.950198, 151.259302),
						mapTypeId: google.maps.MapTypeId.ROADMAP
					});				

					jQuery.ajax({
						url: 'Beach.json', 
						type: 'GET',
						dataType: 'json', 
						success: function(D) {

							beachSpecs = D.beaches;
							jQuery.each(beachSpecs, function(k, v) {
								//console.log(v.beachName, v.latitude, v.longitude);

								// Creating / Initiating Markers:
								var marker = new google.maps.Marker({
									position: new google.maps.LatLng(v.latitude, v.longitude),
									map: map, 
									title: jQuery.trim(v.beachName)
								});								

								// Creating / Initiating Infobox					
								infoBubble = new InfoBox({
									 content: contentString, // Tab content gets appended here.
									 disableAutoPan: false, 
									 maxWidth: 0, 
									 pixelOffset: new google.maps.Size(-140, 0), 
									 zIndex: null, 
									 boxStyle: { 
										//background: "url('tipbox.gif') no-repeat", 
										opacity: 1, 
										width: "280px"
									 }, 
									 closeBoxMargin: "0px", 
									 closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif", 
									 infoBoxClearance: new google.maps.Size(1, 1), 
									 isHidden: false, 
									 pane: "floatPane", 
									 enableEventPropagation: true									
								});

								markers[k] = marker;
								infoBubbles[k] = infoBubble;							

								// Binding Tab Functionality to infowindow
								google.maps.event.addListener(infoBubble, 'domready', function() {
								  jQuery("#tabs").tabs();
								});	

								// Marker Mouse events
								google.maps.event.addListener(marker, 'mouseup', function() {
									$.each(infoBubbles, function(ix, vx) {
										if(ix >; 0) {
											infoBubbles[ix].close();											
										}
									});
									infoBubble.open(map, marker);
								});																						

							});

						}, // success
						error: function (xhr, textStatus, errorThrown) {
							alert("Error: " + (errorThrown ? errorThrown : xhr.status));
						} // error
					}); //ajax																

				} //invokeMyMaps
			};
		};		
	return {
		load: function () {
			if (!instance) {
				instance = init();
			}
			return instance;
		}
	};
})(jQuery);

(function (jQuery) {
	var myMaps = myCustomMaps.load();
	myMaps.pageLoad();
})(jQuery);

All the Map related functionality is wrapped in the invokeMyMaps function. The below code is required to initialize the Google Map API.

map = new google.maps.Map(mapCanvas, {
	zoom: 10,
	center: new google.maps.LatLng(-33.950198, 151.259302),
	mapTypeId: google.maps.MapTypeId.ROADMAP
});

My next steps are to access the JSON File using the jQuery Ajax Call. On Success I’m accessing the JSON data and doing the following:

Setting up the Markers:

The below JS code is for setting up the Markers on the map with the latitude and longitude data from the JSON Object.

// Creating / Initiating Markers:
var marker = new google.maps.Marker({
	position: new google.maps.LatLng(v.latitude, v.longitude),
	map: map, 
	title: jQuery.trim(v.beachName)
});

Read more about markers.

Creating the Infobox:

Infobox is basically an enhanced version of an Infowindow. The below code is for setting up the infobox with options.

// Creating / Initiating Infobox					
infoBubble = new InfoBox({
	content: contentString, // Tab content gets appended here.
	disableAutoPan: false, 
	maxWidth: 0, 
	pixelOffset: new google.maps.Size(-140, 0), 
	zIndex: null, 
	boxStyle: { 
		//background: "url('tipbox.gif') no-repeat", 
		opacity: 1, 
		width: "280px"
	}, 
	closeBoxMargin: "0px", 
	closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif", 
	infoBoxClearance: new google.maps.Size(1, 1), 
	isHidden: false, 
	pane: "floatPane", 
	enableEventPropagation: true									
});

The content option is where you need to pass your custom HTML Content. I’m passing the jQuery UI Tads code using contentString variable and Infobox gives you a lot of options to play around and do maximum customization.

Read the detailed documentation on Infobox.

Since I have more than one location data I’m storing the marker details and the infobox details in the arrays:

markers[k] = marker;
infoBubbles[k] = infoBubble;

The Below functions are required to put everything together. The jQuery Tab event needs to be attached to the infobox on domready and infobox .open function is responsible for opening up the infowindow.

// Binding Tab Functionality to infowindow
google.maps.event.addListener(infoBubble, 'domready', function() {
	jQuery("#tabs").tabs();
});	

// Marker Mouse events
google.maps.event.addListener(marker, 'mouseup', function() {
	$.each(infoBubbles, function(ix, vx) {
		if(ix >; 0) {
			infoBubbles[ix].close();											
		}
	});
	infoBubble.open(map, marker);
});

This tutorial is still a work in progress. My intention is to just give a basic idea on how we can put things together. Any feedback is welcome. Please comment or email me for any questions.

Click Here to download the complete code.

More Tutorials on Google Maps API V3: I’ve recently put up a tutorial on Get Directions and Custom Directions Panel.

Good Luck!