Archive for the 'Javascript' Category

HTML5 Inside – Geolocation

August 14th, 2010 by pyrat

Gps in orienteering
GPS tracking used in World Champs Orienteering

In this series I am going to write about the new whizz bang things which fall under the HTML5 umbrella. I am going to attempt to find out whether it is ‘hype or hardcore’.

Geolocation

Geolocation is the art of finding out where a user is. This can be as rough as country, or as fine grained as an exact latitude / longitude coordinate set.

Traditionally geolocation in the browser consisted of querying the user’s IP again a database. Usually this allowed you to find out what city a user was in. Nowadays, there is a geolocation API which is targetted specifically toward Mobile devices.

The W3C has an api for geolocation which is in draft stage at the time of writing.

Modern versions of Firefox, Chrome, Safari and Opera offer geolocation support. As far as I am aware all of these browsers actually implement the geolocation by querying a service provided by google. The google gears (deprecated) geolocation api has been natively implemented by the major browsers.

How does the actual geolocation work?

Note: The API Described is the old gears API but as HTML Geolocation currently uses this it should be seen to be relatively similar.

An HTTP POST is made containing JSON data which looks like the following.

  {
    "version": "1.1.0",
    "host": "maps.google.com",
    "home_mobile_country_code": 310,
    "home_mobile_network_code": 410,
    "radio_type": "gsm",
    "carrier": "Vodafone",
    "request_address": true,
    "address_language": "en_GB",
    "location": {
      "latitude": 51.0,
      "longitude": -0.1
    },
    "cell_towers": [
      {
        "cell_id": "42",
        "location_area_code": 415,
        "mobile_country_code": 310,
        "mobile_network_code": 410,
        "age": 0,
        "signal_strength": -60,
        "timing_advance": 5555
      },
      {
        "cell_id": "88",
        "location_area_code": 415,
        "mobile_country_code": 310,
        "mobile_network_code": 580,
        "age": 0,
        "signal_strength": -70,
        "timing_advance": 7777
      }
    ],
    "wifi_towers": [
      {
        "mac_address": "01-23-45-67-89-ab",
        "signal_strength": 8,
        "age": 0
      },
      {
        "mac_address": "01-23-45-67-89-ac",
        "signal_strength": 4,
        "age": 0
      }
    ]
  }

It has been designed to work with both mobile and wifi_enabled devices. The browser implementations map to native APIs on the device. So either a simple Lat/Lng is submitted potentially obtained from GPS (easy for google) or wifi_tower mac_addresses, or cell_tower information. Google can use this information to try to geocode a location.

The response is also in JSON. We love JSON here at simplyexcited, XML is dirty.

  {
    "location": {
      "latitude": 51.0,
      "longitude": -0.1,
      "altitude": 30.1,
      "accuracy": 1200.1,
      "altitude_accuracy": 10.1,
      "address": {
        "street_number": "100",
        "street": "Amphibian Walkway",
        "postal_code": "94043",
        "city": "Mountain View",
        "county": "Mountain View County",
        "region": "California",
        "country": "United States of America",
        "country_code": "US"
      }
    }
  }

The old json api is readable on this wiki page

Why this is good.

The geolocation api allows you to build location aware web applications which have access to native location apis. Bringing native hardware to web applications makes the future bright and takes us to a more webby non-native future.

How do I use it then?

Google maps V3 API has a great example of geocoding to put your location on a map.

  <!DOCTYPE html>
  <html>
  <head>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
  <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
  <title>Google Maps JavaScript API v3 Example: Map Geolocation</title>
  <link href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" rel="stylesheet" type="text/css" />
  <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
  <script type="text/javascript" src="http://code.google.com/apis/gears/gears_init.js"></script>
  <script type="text/javascript">
 
  var initialLocation;
  var siberia = new google.maps.LatLng(60, 105);
  var newyork = new google.maps.LatLng(40.69847032728747, -73.9514422416687);
  var browserSupportFlag =  new Boolean();
  var map;
  var infowindow = new google.maps.InfoWindow();
 
  function initialize() {
    var myOptions = {
      zoom: 6,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
 
    // Try W3C Geolocation method (Preferred)
    if(navigator.geolocation) {
      browserSupportFlag = true;
      navigator.geolocation.getCurrentPosition(function(position) {
        initialLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
        contentString = "Location found using W3C standard";
        map.setCenter(initialLocation);
        infowindow.setContent(contentString);
        infowindow.setPosition(initialLocation);
        infowindow.open(map);
      }, function() {
        handleNoGeolocation(browserSupportFlag);
      });
    } else if (google.gears) {
      // Try Google Gears Geolocation
      browserSupportFlag = true;
      var geo = google.gears.factory.create('beta.geolocation');
      geo.getCurrentPosition(function(position) {
        initialLocation = new google.maps.LatLng(position.latitude,position.longitude);
        contentString = "Location found using Google Gears";
        map.setCenter(initialLocation);
        infowindow.setContent(contentString);
        infowindow.setPosition(initialLocation);
        infowindow.open(map);
      }, function() {
        handleNoGeolocation(browserSupportFlag);
      });
    } else {
      // Browser doesn't support Geolocation
      browserSupportFlag = false;
      handleNoGeolocation(browserSupportFlag);
    }
  }
 
  function handleNoGeolocation(errorFlag) {
    if (errorFlag == true) {
      initialLocation = newyork;
      contentString = "Error: The Geolocation service failed.";
    } else {
      initialLocation = siberia;
      contentString = "Error: Your browser doesn't support geolocation. Are you in Siberia?";
    }
    map.setCenter(initialLocation);
    infowindow.setContent(contentString);
    infowindow.setPosition(initialLocation);
    infowindow.open(map);
  }
  </script>
  </head>
  <body onload="initialize()">
    <div id="map_canvas"></div>
 
  </body>
  </html>

View the working example

Simplest working example

Stick this in your firebug console and run it.

  if(navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
      alert("Your lat/lng pair is" + position.coords.latitude + ", " + position.coords.longitude);
    }
  } else {
    alert("Your browser does not support W3C geolocation.");
  }

Conclusion

So.. Geolocation. Hype or Hardcore? I think hardcore.

Node.js Brief Overview

July 5th, 2010 by pyrat

I managed to get the time to do some research into Node.js last week. I have been meaning to check out the new coolness for hipster nerds like myself. I will try to explain some of the node concepts as I understand them.

Event based

Concepts borrowed from ruby’s event machine, python’s twisted and the event based closure syntax of javascript.

Often the plan when it comes to scaling request serving in web apps is to use threads. However there is an alternative method which yields better results. This is the single thread event loop and a good example of event based vs threading is that of a load test between apache and nginx.

Apache the worlds most popular webserver. Nginx is a wee russian webserver which punches beyond its weight.


Nginx versus Apache (with the worker-MPM) for serving a small static file.


Because Nginx is event-based it doesn’t need to spawn new processes or threads for each request, so its memory usage is very low.

These graphs are borrowed from this excellent post on the subject

Its all about the IO man

RAM is fast. Disk, DB and Network are very slow in comparison. This results in programs spending a lot of time waiting for IO operations to complete. Node approaches this as being completely the wrong way of doing things and everything should be non-blocking.

The problem being that most IO libraries are blocking, so there is a movement to upgrade these libraries to be non-blocking but there is also a c based thread pool which node uses to achieve non-blocking whilst using blocking IO Drivers.

Event based is hard

Coming from an OOP MVC background is a hard approach direction to Event based programming. A better approach is looking at javascript in the browser and a working relationship with a framework such as jquery which shows how events can be used in the javascript world to achieve unobstrusive RIA functionality to your web application.

Do I really want to build a website with this?

Currently it seems strange to me that you would want to build a website with server-side javascript. There are a lot of great frameworks out there for building web applications and most of them are a lot more mature and powerful than the javascript offerings.

However, I think that the power of node is in the access to low level functionality to build your own low level network applications.

Previously, these areas have been limited to people with black art C skills in memory management and other old school tools. Now, any joe blow with some javascript skills and create something which does some powerful things with good performance.

So essentially, programmers who have grown up in the internet age can now write ace applications in a way which was previously not possible. In my view, this is the main merit of node.

Simple Proxy in Node

To achieve an http proxy you would typically install something like squid which has a lot of configuration options

Obviously squid is very powerful and bursting full of features that you need, you should probably use it actually. However it is really easy to write a proxy in node.

  var http = require('http');
  var sys  = require('sys');
 
 
 
  function server_callback (request, response) {
    var proxy = http.createClient(80, request.headers['host']);
    var proxy_request = proxy.request(request.method, request.url, request.headers);
 
    proxy_request.addListener('response', function (proxy_response) {
      proxy_response.addListener('data', function(chunk) {
        response.write(chunk, 'binary');
      });
      proxy_response.addListener('end', function() {
        response.end();
      });
      response.writeHead(proxy_response.statusCode, proxy_response.headers);
    });
    request.addListener('data', function(chunk) {
      proxy_request.write(chunk, 'binary');
    });
    request.addListener('end', function() {
      proxy_request.end();
    });
  }
 
 
  http.createServer(server_callback).listen(8080);
  sys.puts("Server running on port 8080");

There is a proxy which a little bit more functionality which is available node proxy

How can I have a go?

The easiest installation path I have seen is to install homebrew then

sudo brew install node

You can then launch the proxy example with:

node proxy.js

I want to put it LIVE

Best plan is to deploy it with nginx as a frontend which proxies request to the node instance. One option is using it with upstart and monit.

This blog post describes the process really well. Heroku are in the process of starting of offer node support; but this is still in a closed beta.

Conclusion

I hope this has given a brief overview of node and it helps you to decide whether to have a go or not.

Jquery Tiptip IE6

May 6th, 2010 by pyrat

Tiptip is a nice jquery plugin for displaying tooltips in a simple and elegant manner. All you need to do is set the title attribute with the tooltip content then give it a class name so it it picked up by the tooltip initializer.

However, it currently doesnt work in IE6 that well. Although users are falling I think you still need at least rudimentary support for IE6.

Create a conditional comment which includes a stylesheet load in your document header.

  <!--[if IE 6]>
     <link href="/stylesheets/ie6.css?1273083940" media="screen" rel="stylesheet" type="text/css" />
   <![endif]-->

And add the following rules to the stylesheet.

Christmas Card Labels Application

December 8th, 2009 by pyrat

santa

I have been keen to get my hands dirty with ExtJS, so jumped at the chance to make a christmas card list application which can print the list to labels; to stick on envelopes.

I have finally become mature enough to have a christmas card list along with my girlfriend, which is useful for keeping track of friends both in Trondheim and the United Kingdom.

To get it up and running on heroku it is pretty swift –

  git clone git://github.com/pyrat/christmas-card-labels.git
  cd christmas-card-labels
  sudo gem install heroku
  heroku create
  git push heroku master
  heroku rake db:migrate

You are now good to go, you may need to tweak the css (labels.css) to match your specific labels which can be a painful experience.

Default username / password is god / jul which is norwegian for merry christmas!

There is a demo version online

YUI Compressor vs Google Closure Compiler for Javascript Compression

November 24th, 2009 by pyrat

Introduction

In todays environment of Rich Internet Applications we rely heavily on Javascript. Often this javascript is in the form of a javascript framework. These typically enhance vanilla javascript and allow you to accomplish tasks with a nice syntax and more importantly abstract the differences in browser implementation.

Despite all the positives the main negative of javascript frameworks is the browser overhead when they are downloaded. Often the size of these assets can add up to a few hundred kilobytes. Coupled with the fact that they are normally split into a number of files (increases HTTP Overhead) this has the effect of decreasing the quality of the user experience while they wait for these files to load when loading your site.

There are a number of ways to increase client side performance specifically with javascript assets.

Decrease HTTP Overhead

Combining assets into single files is the best bet here. Prototype and Scriptaculous take up five or so separate uncompressed files. Decreasing HTTP overhead is one of the biggest time savers.

Caching

This involves telling browsers that they can cache a file for a time in the future. This is known as the expires header. Mod_expires is a way to achieve this with Apache. It is common to append a timestamp to the url eg.

/javascripts/defaults.js?343423434342

A technique which is applied by rails is that this number value is infact the last modified timestamp from the file so you can then set a long expires on this (maximum possible) as changing the default.js file will alter the file, change the timestamp and generate a new unique URL which can be recached.

Gzip Compression

Another big timesaver for big assets. This actually zips up the asset before pumping it down the pipe. You can configure this in your nginx configuration or use mod_deflate if you are on apache.

Javascript Compression and Optimisation

This area still developing, the main players at the moment at the YUI Compressor developed by Yahoo and the Closure Compiler developed by Google.

I use a basic prototype / scriptaculous framework for oentries so have used this for a little battle between the compressors.

Compilation commands are as follows for reference.

YUI

  java -jar /path/to/yuicompressor-2.4.2.jar --type js -o defaults.yui.js defaults.js

Closure (Standard mode)

  java -jar /path/to/compiler.jar  --js defaults.js --js_output_file defaults.google.js

Closure (Advanced Optimizations Mode)

  java -jar /path/to/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js defaults.js --js_output_file defaults.google-advanced.js

NOTE: You need to be running Java 6 to use the closure compiler.

This experiment was performed on a 1Gb Ubuntu Hardy Heron VPS Slice.

Comparison of Compression
Comparison of Compression (Kb)

YUI and Google Closure standard mode produce a similar result circa 60% of the original size. However closure with advanced optimisations leads the way at 43% of the original size!

There is however a BUT. The advanced optimisations mode actually removed methods which are not called! Have a look at these docs

In a standard RIA you will often call functions from inline HTML (onclick events) etc. This makes this form of aggressive optimisation too much for standard applications. You could however remove all javascript calls from HTML and so it all unobtrusively as it standard practice in JQuery.

Compression time
Comparison of Compression Time (Seconds)

YUI is substantially faster than google closure at JS compression. If you were to add this into your deployment strategy this gives YUI the advantage.

Compressor Conclusion

Whilst it looks like closure is a better compressor, I just don’t think it is safe to be this aggressive with compression for production environments.

If you then run closure on standard mode, the differences in compression vs YUI are minimal. With the speed advantage of YUI, I would definitely pick YUI. YUI has the other big advantage in that it can compress CSS as well.

Has anyone had any experience with Javascript Compressors? Comment if you do.

Conclusion

I hope this has given an insight into the wonderful world of speeding up the delivery of your javascript assets. Now get out there and compress!