How to populate two drop-downs in JQuery with to/from dates

If you ever need to populate two sets of drop-downs with the from and to hours, use the following script in your head section:

"text/javascript">
        $(document).ready(function () {
            var i = 0;

            for (var i = 0; i var ampm = i % 24 'AM' : 'PM';

                var hours = i % 12;
                if ((hours === 0) && (i!=0)) {
                    hours = 12;
                }
                var valueString = ("0" + hours.toString()).slice(-2) + " " + ampm;

                $('#ddlFromHour').append($('')
                        .attr('value', i)
                        .text(valueString));
                $('#ddlToHour').append($('')
                        .attr('value', i)
                        .text(valueString));
            }
            for (var i = 0; i var valueString = ("0" + i.toString()).slice(-2);

                $('#ddlFromMinute').append($('')
                        .attr('value', i)
                        .text(valueString));
                $('#ddlToMinute').append($('')
                        .attr('value', i)
                        .text(valueString));
            }
        });
    

Output will be two sets of drop-downs with “From and To Times”
Capture

Advertisements

Koalas to the Max – Cool HTML5 Canvas Painter

This awesome website uses hovers over a circle area to split the circle into four other circles and then four more and four more – each time reducing the size of the circle and the colour of the circles and making sure none of the circles meet.

http://www.koalastothemax.com/

The JS Code:

 

"use strict"

/*
* Made with love by Vadim Ogievetsky for Annie Albagli (Valentine's Day 2011)
* Powered by Mike Bostock's D3
*
* For me on GitHub:  https://github.com/vogievetsky/KoalasToTheMax
* License: MIT  [ http://koalastothemax.com/LICENSE ]
*
* If you are reading this then I have an easter egg for you:
* You can use your own custom image as the source, simply type in:
* http://koalastothemax.com?
* e.g.
* http://koalastothemax.com?http://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Flag_of_the_United_Kingdom.svg/200px-Flag_of_the_United_Kingdom.svg.png
*
* also if you want to use a custom image and want people to guess what it is
* (without seeing the url) then you can type the url in base64 encoding like so:
* http://koalastothemax.com?
* e.g.
* http://koalastothemax.com?YXN0bGV5LmpwZw==
* (try to guess the image above)
*/

var koala = {
  version: '1.8.2'
};

(function() {
  function array2d(w, h) {
    var a = [];
    return function(x, y, v) {
      if (x < 0 || y < 0) return void 0;
      if (arguments.length === 3) {
        // set
        return a[w * x + y] = v;
      } else if (arguments.length === 2) {
        // get
        return a[w * x + y];
      } else {
        throw new TypeError("Bad number of arguments");
      }
    }
  }

  // Find the color average of 4 colors in the RGB colorspace
  function avgColor(x, y, z, w) {
    return [
      (x[0] + y[0] + z[0] + w[0]) / 4,
      (x[1] + y[1] + z[1] + w[1]) / 4,
      (x[2] + y[2] + z[2] + w[2]) / 4
    ];
  }

  koala.supportsCanvas = function() {
    var elem = document.createElement('canvas');
    return !!(elem.getContext && elem.getContext('2d'));
  };

  koala.supportsSVG = function() {
    return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', "svg").createSVGRect;
  };

  function Circle(vis, xi, yi, size, color, children, layer, onSplit) {
    this.vis = vis;
    this.x = size * (xi + 0.5);
    this.y = size * (yi + 0.5);
    this.size = size;
    this.color = color;
    this.rgb = d3.rgb(color[0], color[1], color[2]);
    this.children = children;
    this.layer = layer;
    this.onSplit = onSplit;
  }

  Circle.prototype.isSplitable = function() {
    return this.node && this.children
  }

  Circle.prototype.split = function() {
    if (!this.isSplitable()) return;
    d3.select(this.node).remove();
    delete this.node;
    Circle.addToVis(this.vis, this.children);
    this.onSplit(this);
  }

  Circle.prototype.checkIntersection = function(startPoint, endPoint) {
    var edx = this.x - endPoint[0],
        edy = this.y - endPoint[1],
        sdx = this.x - startPoint[0],
        sdy = this.y - startPoint[1],
        r2  = this.size / 2;

    r2 = r2 * r2; // Radius squared

    // End point is inside the circle and start point is outside
    return edx * edx + edy * edy <= r2 && sdx * sdx + sdy * sdy > r2;
  }

  Circle.addToVis = function(vis, circles, init) {
    var circle = vis.selectAll('.nope').data(circles)
      .enter().append('circle');

    if (init) {
      // Setup the initial state of the initial circle
      circle = circle
        .attr('cx',   function(d) { return d.x; })
        .attr('cy',   function(d) { return d.y; })
        .attr('r', 4)
        .attr('fill', '#ffffff')
          .transition()
          .duration(1000);
    } else {
      // Setup the initial state of the opened circles
      circle = circle
        .attr('cx',   function(d) { return d.parent.x; })
        .attr('cy',   function(d) { return d.parent.y; })
        .attr('r',    function(d) { return d.parent.size / 2; })
        .attr('fill', function(d) { return String(d.parent.rgb); })
        .attr('fill-opacity', 0.68)
          .transition()
          .duration(300);
    }

    // Transition the to the respective final state
    circle
      .attr('cx',   function(d) { return d.x; })
      .attr('cy',   function(d) { return d.y; })
      .attr('r',    function(d) { return d.size / 2; })
      .attr('fill', function(d) { return String(d.rgb); })
      .attr('fill-opacity', 1)
      .each('end',  function(d) { d.node = this; });
  }

  // Main code
  var vis,
      maxSize = 512,
      minSize = 4,
      dim = maxSize / minSize;

  koala.loadImage = function(imageData) {
    // Create a canvas for image data resizing and extraction
    var canvas = document.createElement('canvas').getContext('2d');
    // Draw the image into the corner, resizing it to dim x dim
    canvas.drawImage(imageData, 0, 0, dim, dim);
    // Extract the pixel data from the same area of canvas
    // Note: This call will throw a security exception if imageData
    // was loaded from a different domain than the script.
    return canvas.getImageData(0, 0, dim, dim).data;
  };

  koala.makeCircles = function(selector, colorData, onEvent) {
    onEvent = onEvent || function() {};

    var splitableByLayer = [],
        splitableTotal = 0,
        nextPercent = 0;

    function onSplit(circle) {
      // manage events
      var layer = circle.layer;
      splitableByLayer[layer]--;
      if (splitableByLayer[layer] === 0) {
        onEvent('LayerClear', layer);
      }

      var percent = 1 - d3.sum(splitableByLayer) / splitableTotal;
      if (percent >= nextPercent) {
        onEvent('PercentClear', Math.round(nextPercent * 100));
        nextPercent += 0.05;
      }
    }

    // Make sure that the SVG exists and is empty
    if (!vis) {
      // Create the SVG ellement
      vis = d3.select(selector)
        .append("svg")
          .attr("width", maxSize)
          .attr("height", maxSize);
    } else {
      vis.selectAll('circle')
        .remove();
    }

    // Got the data now build the tree
    var finestLayer = array2d(dim, dim);
    var size = minSize;

    // Start off by populating the base (leaf) layer
    var xi, yi, t = 0, color;
    for (yi = 0; yi < dim; yi++) {
      for (xi = 0; xi < dim; xi++) {
        color = [colorData[t], colorData[t+1], colorData[t+2]];
        finestLayer(xi, yi, new Circle(vis, xi, yi, size, color));
        t += 4;
      }
    }

    // Build up successive nodes by grouping
    var layer, prevLayer = finestLayer;
    var c1, c2, c3, c4, currentLayer = 0;
    while (size < maxSize) {
      dim /= 2;
      size = size * 2;
      layer = array2d(dim, dim);
      for (yi = 0; yi < dim; yi++) {
        for (xi = 0; xi < dim; xi++) {
          c1 = prevLayer(2 * xi    , 2 * yi    );
          c2 = prevLayer(2 * xi + 1, 2 * yi    );
          c3 = prevLayer(2 * xi    , 2 * yi + 1);
          c4 = prevLayer(2 * xi + 1, 2 * yi + 1);
          color = avgColor(c1.color, c2.color, c3.color, c4.color);
          c1.parent = c2.parent = c3.parent = c4.parent = layer(xi, yi,
            new Circle(vis, xi, yi, size, color, [c1, c2, c3, c4], currentLayer, onSplit)
          );
        }
      }
      splitableByLayer.push(dim * dim);
      splitableTotal += dim * dim;
      currentLayer++;
      prevLayer = layer;
    }

    // Create the initial circle
    Circle.addToVis(vis, [layer(0, 0)], true);

    // Interaction helper functions
    function splitableCircleAt(pos) {
      var xi = Math.floor(pos[0] / minSize),
          yi = Math.floor(pos[1] / minSize),
          circle = finestLayer(xi, yi);
      if (!circle) return null;
      while (circle && !circle.isSplitable()) circle = circle.parent;
      return circle || null;
    }

    function intervalLength(startPoint, endPoint) {
      var dx = endPoint[0] - startPoint[0],
          dy = endPoint[1] - startPoint[1];

      return Math.sqrt(dx * dx + dy * dy);
    }

    function breakInterval(startPoint, endPoint, maxLength) {
      var breaks = [],
          length = intervalLength(startPoint, endPoint),
          numSplits = Math.max(Math.ceil(length / maxLength), 1),
          dx = (endPoint[0] - startPoint[0]) / numSplits,
          dy = (endPoint[1] - startPoint[1]) / numSplits,
          startX = startPoint[0],
          startY = startPoint[1];

      for (var i = 0; i <= numSplits; i++) {
        breaks.push([startX + dx * i, startY + dy * i]);
      }
      return breaks;
    }

    function findAndSplit(startPoint, endPoint) {
      var breaks = breakInterval(startPoint, endPoint, 4);
      var circleToSplit = []

      for (var i = 0; i < breaks.length - 1; i++) {
        var sp = breaks[i],
            ep = breaks[i+1];

        var circle = splitableCircleAt(ep);
        if (circle && circle.isSplitable() && circle.checkIntersection(sp, ep)) {
          circle.split();
        }
      }
    }

    // Handle mouse events
    var prevMousePosition = null;
    function onMouseMove() {
      var mousePosition = d3.mouse(vis.node());

      // Do nothing if the mouse point is not valid
      if (isNaN(mousePosition[0])) {
        prevMousePosition = null;
        return;
      }

      if (prevMousePosition) {
        findAndSplit(prevMousePosition, mousePosition);
      }
      prevMousePosition = mousePosition;
      d3.event.preventDefault();
    }

    // Handle touch events
    var prevTouchPositions = {};
    function onTouchMove() {
      var touchPositions = d3.touches(vis.node());
      for (var touchIndex = 0; touchIndex < touchPositions.length; touchIndex++) {
        var touchPosition = touchPositions[touchIndex];
        var prevTouchPosition = prevTouchPositions[touchPosition.identifier]
        if (prevTouchPosition) {
          findAndSplit(prevTouchPosition, touchPosition);
        }
        prevTouchPositions[touchPosition.identifier] = touchPosition;
      }
      d3.event.preventDefault();
    }

    function onTouchEnd() {
      var touches = d3.event.changedTouches;
      for (var touchIndex = 0; touchIndex < touches.length; touchIndex++) {
        var touch = touches.item(touchIndex);
        prevTouchPositions[touch.identifier] = null;
      }
      d3.event.preventDefault();
    }

    // Initialize interaction
    d3.select(document.body)
      .on('mousemove.koala', onMouseMove)
      .on('touchmove.koala', onTouchMove)
      .on('touchend.koala', onTouchEnd)
      .on('touchcancel.koala', onTouchEnd);
  };
})();

Fireworks for Bonfire Night Safety CSS Skills

With Bonfire Night approaching in the UK, Col Morley and Igor Krestov of Blue Claw decided to put their CSS skills to work creating this fire safety infographic aimed at school-age children.

http://visual.ly/bonfire-night-safety?view=true

When viewed in a suitable browser, some elements of the infographic will animate. Rather than aiming at supersmooth, in-your-face visual effects, the flickering of the flames and the sparkling of the sparklers is simple, subtle – and, we think, all the more effective for it.

Inspired by Firefox’s homepage Olympic flame over the summer of 2012, the infographic was created using layered graphics and CSS3 to aid in the process of transition of scale, movement and speed, explains Morley. “The bonfire is made up of several layered ‘fire’ shapes then playing around with key frames enabled stretching, opacity and by adding a warm glow renders a realistic flame effect.

Inspired by Firefox’s homepage Olympic flame over the summer of 2012, the infographic was created using layered graphics and CSS3 to aid in the process of transition of scale, movement and speed, explains Morley. “The bonfire is made up of several layered ‘fire’ shapes then playing around with key frames enabled stretching, opacity and by adding a warm glow renders a realistic flame effect.

“The spark that appears throughout the page was created using a similar technique. Three images were used to pulsate at different rates of scale, similar effect to how we animated the ‘fearful cat’. The movement of the eyes on the hot dog was produced by mouse tracking code adding further interest to those who spotted that.

“The styling of the traditional blackboard theme gives the piece the right level and tone for the audience and enabled us to experiment with textures and fonts.”

bomfirea2

Are photoshop-like blend modes possible in HTML5?

If you’re a user of our design applications such as Photoshop and Illustrator, you know how you can create very cool effects with blend modes. An Amazon search returns many books and a Google search on ‘photoshop blending tutorial’ returns more than 200,000 results. This points to a very widely known and used feature.

Adobe: http://blogs.adobe.com/webplatform/2012/04/04/bringing-blending-to-the-web/

Capture

To be able to blend to images together like Photoshop does, we will need to use the HTML5 canvas feature. The images are loaded dynamically using Javascript.

The easy way to blend two images together can be summarized into

// Might be an 'offscreen' canvas
var over  = someCanvas.getContext('2d');
var under = anotherCanvas.getContext('2d');

over.blendOnto( under, 'screen', {destX:30,destY:15} );

The full example is featured below:

The HTML

Blending mode
Opacity
</div> <canvas id="canvas2" width="300" height="300"></canvas> </section> <section class="result"> <canvas id="result" width="300" height="300"></canvas> </section> </div>

The Javascript Code

At first we define the blending modes:

var blendingModes = {
	normal: function(a, b) {
		return a;
	},

	lighten: function(a, b) {
		return (b > a) ? b : a;
	},

	darken: function(a, b) {
		return (b > a) ? a : b;
	},

	multiply: function(a, b) {
		return (a * b) / 255;
	},

	average: function(a, b) {
		return (a + b) / 2;
	},

	add: function(a, b) {
		return Math.min(255, a + b);
	},

	substract: function(a, b) {
		return (a + b < 255) ? 0 : a + b - 255; 	}, 	difference: function(a, b) { 		return Math.abs(a - b); 	}, 	negation: function(a, b) { 		return 255 - Math.abs(255 - a - b); 	}, 	screen: function(a, b) { 		return 255 - (((255 - a) * (255 - b)) >> 8);
	},

	exclusion: function(a, b) {
		return a + b - 2 * a * b / 255;
	},

	overlay: function(a, b) {
		return b < 128
			? (2 * a * b / 255)
			: (255 - 2 * (255 - a) * (255 - b) / 255);
	},

	softLight: function(a, b) {
		return b < 128 			? (2 * ((a >> 1) + 64)) * (b / 255)
			: 255 - (2 * (255 - (( a >> 1) + 64)) * (255 - b) / 255);
	},

	hardLight: function(a, b) {
		return blendingModes.overlay(b, a);
	},

	colorDodge: function(a, b) {
		return b == 255 ? b : Math.min(255, ((a << 8 ) / (255 - b)));
	},

	colorBurn: function(a, b) {
		return b == 0 ? b : Math.max(0, (255 - ((255 - a) << 8 ) / b));
	},

	linearDodge: function(a, b) {
		return blendingModes.add(a, b);
	},

	linearBurn: function(a, b) {
		return blendingModes.substract(a, b);
	},

	linearLight: function(a, b) {
		return b < 128
			? blendingModes.linearBurn(a, 2 * b)
			: blendingModes.linearDodge(a, (2 * (b - 128)));
	},

	vividLight: function(a, b) {
		return b < 128
			? blendingModes.colorBurn(a, 2 * b)
			: blendingModes.colorDodge(a, (2 * (b - 128)));
	},

	pinLight: function(a, b) {
		return b < 128
			? blendingModes.darken(a, 2 * b)
			: blendingModes.lighten(a, (2 * (b - 128)));
	},

	hardMix: function(a, b) {
		return blendingModes.vividLight(a, b) < 128 ? 0 : 255;
	},

	reflect: function(a, b) {
		return b == 255 ? b : Math.min(255, (a * a / (255 - b)));
	},

	glow: function(a, b) {
		return blendingModes.reflect(b, a);
	},

	phoenix: function(a, b) {
		return Math.min(a, b) - Math.max(a, b) + 255;
	}
};

The Blending Code

/** @type CanvasRenderingContext2D */
var ctx1 = null;

/** @type CanvasRenderingContext2D */
var ctx2 = null;

/** @type CanvasRenderingContext2D */
var ctx3 = null;

/** Current blending mode */
var mode = 'normal';

/** Current blending opacity */
var alpha = 1;

var totalImages = 2;
var img1 = new Image;
var img2 = new Image;

img1.onload = img2.onload = imageReady;

function imageReady() {
	if (--totalImages == 0) {
		setupScene();
	}
}

function setupScene() {
	ctx1 = document.getElementById('canvas1').getContext('2d');
	ctx2 = document.getElementById('canvas2').getContext('2d');
	ctx3 = document.getElementById('result').getContext('2d');

	drawImage(img1, ctx1);
	drawImage(img2, ctx2);
	drawImage(img1, ctx3);
}

/**
 * Draw image on specified canvas context
 * @param {Image} img
 * @param {CanvasRenderingContext2D} ctx
 */
function drawImage(img, ctx) {
	ctx.canvas.width = img.width;
	ctx.canvas.height = img.height;
	ctx.drawImage(img, 0, 0);
	updateScene();
}

function updateScene() {
	// create rect for smallest image
	var width =  Math.min(ctx1.canvas.width, ctx2.canvas.width);
	var height = Math.min(ctx1.canvas.height, ctx2.canvas.height);

	var imageData1 = ctx1.getImageData(0, 0, width, height);
	var imageData2 = ctx2.getImageData(0, 0, width, height);

	/** @type Array */
	var pixels1 = imageData1.data;
	/** @type Array */
	var pixels2 = imageData2.data;

	var r, g, b, oR, oG, oB, alpha1 = 1 - alpha;

	var blendingMode = blendingModes[mode];

	// blend images
	for (var i = 0, il = pixels1.length; i < il; i += 4) {
		oR = pixels1[i];
		oG = pixels1[i + 1];
		oB = pixels1[i + 2];

		// calculate blended color
		r = blendingMode(pixels2[i], oR);
		g = blendingMode(pixels2[i + 1], oG);
		b = blendingMode(pixels2[i + 2], oB);

		// alpha compositing
		pixels1[i] =     r * alpha + oR * alpha1;
		pixels1[i + 1] = g * alpha + oG * alpha1;
		pixels1[i + 2] = b * alpha + oB * alpha1;
	}

	ctx3.putImageData(imageData1, 0, 0);
}

/**
 * @param {String} name
 */
function humanizeName(name) {
	return name.charAt(0).toUpperCase() + name.substring(1).replace(/[A-Z]/g, function(s) {
		return ' ' + s.toLowerCase();
	});
}

$(function() {
	// setup page:

	// fill blending mode select box
	var options = [];
	for (var name in blendingModes) if (blendingModes.hasOwnProperty(name)) {
		options.push('' + humanizeName(name) + '');
	}

	$('select[name=blending]').html(options.join('')).change(function() {
		mode = $(this).val();
		if (!totalImages)
			updateScene();
	});

	$('input[name=opacity]').bind('change keyup keypress', function() {
		var value = parseInt($(this).val(), 10);
		if ($(this).data('prev-value') != value) {
			$(this).data('prev-value', value);
			alpha = Math.min(1, Math.max(0, value / 100));

			if (!totalImages)
				updateScene();
		}
	}).val(Math.floor(alpha * 100));

	// load images
	img1.src = 'image1.jpg';
	img2.src = 'image2.jpg';
});

The CSS

body {
			padding: 40px 10px;
			font-family: arial, sans-serif;
			font-size: 12px;
		}

		.blending-demo {
			margin-top: 5em;
			white-space: nowrap;
		}

		section {
			position: relative;
			display: inline-block;
		}

		section:after {
			font-weight: bold;
			font-size: 60px;
			position:absolute;
			top: 50%;
			margin-left: 0.15em;
			left: 100%;
			margin-top: -0.6em;
			line-height: 1.2;
		}

		.image1, .image2 {
			margin-right: 4em;
		}

		.image1:after {
			content: '+';
		}

		.image2:after {
			content: '=';
		}

		.controls {
			position: absolute;
			bottom: 100%;
			padding-bottom: 1em;
		}

		select[name=blending] {
			margin-bottom: 1em;
		}

		label {
			display: inline-block;
			line-height: 1.5;
			vertical-align: middle;
			margin-right: 1em;
			width: 7em;
		}

		input[name=opacity] {
			vertical-align: middle;
		}

The Result

http://media.chikuyonok.ru/canvas-blending/

JQuery Mobile – Stop Page Transition if Current Page does not validate.

<a> link button validation before transition to another Local, internal linked “pages”

[Question] I have two form pages and a next button to move from page 1 to page 2. When the next button is clicked, I wanted to validate all the required fields before moving to the second page. How do you make the page transition stop, when validation fail on page 1?

I ran into a problem when trying to validate a few radio button groups on a page before the page transition happened in JQuery Mobile.

I did not want the page to change before I managed to check if the user had managed to select an option from the screen.
I am using JQuery Mobile Events to trap the page change and cancel it if there is something wrong with the page I am trying to move from.
Because there were more than one radio button group on the page, I got the names of all the groups and then looped through them. If I found one unchecked, I would stop the transition with e.preventDefault().

I hope this helps someone.
 

 <script type="text/javascript">
        $(document).bind('pagebeforechange', function (e, data) {
            var to = data.toPage,
                from = data.options.fromPage;

            if (typeof to === 'string') {
                var u = $.mobile.path.parseUrl(to);
                to = u.hash || '#' + u.pathname.substring(1);
                if (from) from = '#' + from.attr('id');
                var blnchecked;
                blnchecked = true;
                //find all radio groups on a page
                var radio_groups = {}
                $(from + " input[type=radio]").each(function () {
                    radio_groups[this.name] = true;
                })

                for (group in radio_groups) {
                    if_checked = !!$(from + " input[name=" + group + "]:checked").length;
                  //  alert(group + (if_checked ? ' has checked radios' : ' does not have checked radios'));
                    if (!if_checked) {
                        blnchecked = false;
                    }
                }


                if (blnchecked==false) {
                    alert('Please select an option!');
                    e.preventDefault();

                    // remove active class on button
                    // otherwise button would remain highlighted
                    $.mobile.activePage
                        .find('.ui-btn-active')
                        .removeClass('ui-btn-active');
                }
            }
        });
    </script>

window.location.origin does not work in Internet Explorer

Internet Explorer does not have access to window.location.origin, which is a bummer because it is a pretty handy variable to have, but we can make it work with a fairly straight forward check because we access .origin;

if (!window.location.origin) {
  window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}

HTML5 Geolocation – Making your html location aware

Wherever you go, there you are. And sometimes knowing where you are makes all the difference (especially to a web app). In this chapter we’re going to show you how to create web pages that are location aware—sometimes you’ll be able to pinpoint your users down to the corner they’re standing on, and sometimes you’ll only be able to determine the area of town they’re in (but you’ll still know the town!). Heck, sometimes you won’t be able to determine anything about their location, which could be for technical reasons, or just because they don’t want you being so nosy. Go figure.

In any case, in this chapter we’re going to explore a JavaScript API: Geolocation. Grab the best location-aware device you have (even if it’s your desktop PC), and let’s get started.

Knowing where your users are can add a lot to a web experience: you can give them directions, make suggestions about where they might go, you can know it’s raining and suggest indoor activities, you can let your users know who else in their area might be interested in some activity. There’s really no end to the ways you can use location information.

With HTML5 (and the Geolocation JavaScript-based API) you can easily access location information in your pages. That’s said, there are a few things to know about location before we get started. Let’s check it out…

 

Q: I heard Geolocation isn’t a real API?
A: Geolocation is not considered a first-class member of the existing HTML5 standard, but that said, it is a standard of the W3C, widely supported and pretty much everyone includes Geolocation in the list of important HTML5 APIs. And it most certainly is a real JavaScript API!
Q: Is the Geolocation API the same as the Google Maps API?
A: No. They are completely different APIs. The Geolocation API is solely focused on getting you information about your position on
the Earth. The Google Maps API is a JavaScript library offered by Google that gives you access to all their Google Maps functionality.
So, if you need to display your users location in a map, Google’s API gives you a convenient way to implement that functionality.
Q: Isn’t it a privacy concern to have my device reveal my location?
A: The Geolocation specification specifies that any browser must have the express permission of the user to make use of their location. So, if your code makes use of the Geolocation API, the first thing the browser will do is make sure it is okay with the user to share her location.
Q: How well supported is Geolocation?
A: Very well supported; in fact, it’s available in almost every modern browser including desktop and mobile. You’ll want to be sure you’re using the latest version of your browser; if you are,  then you’re probably good to go.

 

The Lat and Long of it…
latlongTo know where you are, you need a coordinate system, and you need one on the Earth’s surface. Luckily we have such a thing, and it uses latitude and longitude together as a coordinate system. Latitude specifies a north/sourth point on the Earth, and longitude, an east/west point. Latitude is measured from the equator, and longitude is measured from Greenwich, England. The job of the geolocation API is to give us the coordinates of where we are at any time, using these coordinates.

You’ve probably seen latitude and longitude specfied in both  degrees / minutes / seconds, such as (47˚38’34’’, 122˚32’32’’), and in decimal values, such as (47.64, -122.54). With the Geolocation API we always use decimal values. If you need to convert degrees/ minutes/seconds to decimal, you can use this function:

 

function degreesToDecimal(degrees, minutes, seconds) {
return degrees + (minutes / 60.0) + (seconds / 3600.0);
}

How the Geolocation API determines your location

You don’t have to have the newest smartphone to be location aware. Even desktop browsers are joining the game. You might ask, how would a desktop browser determine its location if it doesn’t have GPS or any other fancy location technologies?

Well, all browsers (in devices and on your desktop) are using a few different ways to determine where you are, some more accurate than others. Let’s take a look:

GPS
Global Positioning System, supported by many newer mobile devices, provides extremely accurate location information based on satellites. Location data may  include altitude, speed and heading information. To use it, though, your device has to be able to see the sky, and it can take a long time to get a location. GPS can also be hard on your batteries.

IP Address
Location information based on your IP address uses an external database to map the IP address to a physical location. The advantage of this approach is that it can work anywhere; however, often IP addresses are resolved to locations such as your ISP’s local office. Think of this method as being reliable to the city or sometimes neighborhood level.

Cell Phone
Cell phone triangulation figures out your location based on your distance from one or more cell phone towers (obviously the more towers, the more accurate your location will be). This method can be fairly accurate and works indoors (unlike GPS); it also can be much quicker than GPS. Then again, if you’re in the middle of nowhere with only one cell tower, your accuracy is going to suffer.

WiFi
WiFi positioning uses one or more WiFi access points to triangulate your location. This method can be very accurate, works indoors and is fast. Obviously it requires you are somewhat stationary (perhaps drinking a venti iced tea at a coffee house).

 

The browser implementation is going to determine how location is determined. But the good news is the browser can use any of these means to determine your location. In fact, a smart browser might first use cell phone triangulation, if it is available, to give you a rough idea of location, and then later give you a more accurate location with WiFi or GPS.
We’ll see that you don’t need to worry about how the location is being determined, and we’ll focus more on the accuracy of your location instead. Based on the accuracy, you can determine how useful the location is going to be for you.

 

The code:

window.onload = getMyLocation;
function getMyLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayLocation);
} else {
alert(“Oops, no geolocation support”);
}
}

function displayLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var div = document.getElementById(“location”);
div.innerHTML = “You are at Latitude: ” + latitude + “, Longitude: ” + longitude;
}

What we just did…
Let’s walk through the code in a little more detail:

if (navigator.geolocation) {

} else {
alert(“Oops, no geolocation support”);
}

 

The first thing you need to know if you’re going to write geolocation code is “does this browser support it?” To do that we make use of the fact that browsers have a geolocation property in their navigation object only if geolocation is supported. So we can test to see if the geolocation property exists, and if so make use of it; otherwise, we’ll let the user know.

If your browser supports the Geolocation API, you’ll find a geolocation property in the navigator object.

We can use a simple test to see if geolocation is there (if it’s not then navigator.geolocation evaluates to null and the condition will fail).

Now, if there is a navigator.geolocation property, we’re going to make some more use of it. In fact, the navigator.geolocation property is an  object that contains the entire geolocation API. The main method the API supports is getCurrentPosition, which does the work of getting the browser’s location. Let’s take a closer look at this method, which has three parameters, the second two of which are  optional:

getCurrentPosition(successHandler, errorHandler, options)

The successHandler is a function that is called if the browser is able to successfully determine your location.
These two parameters are optional, which is why we didn’t need them before.
The errorHandler is another function, that is called if something goes wrong and the browser can’t determine your location.
The options parameter allows you to customize the way geolocation works.

Remember, APIs are just objects with properties and methods!