How to stop jQuery Tools Scrollable from buffering clicks

jQuery Tools Scrollable is an awesome plugin for creating scrollable image & content galleries. We used it for the portfolio and footer sections on peacock.st. The only gripe I had with it is that it buffers clicks on navigation elements, which might be ok for some people but wasn’t desirable behaviour in our case. Thankfully it’s quite easy to change this behaviour so that any clicks on the navigation will automatically complete the current animation and animate to the next element in the scrollable.

All you need to do is open up the js file that contains scrollable (you can do this with the minified file, you don’t need the source), and find the part that says “h.animate(n,c,e.easing,k“. Replace this with “h.stop(true,true).animate(n,c,e.easing,k“. So just beforeĀ  the animate, you are putting a .stop(true,true) in. As you may already know, .stop() stops the current animation in it’s tracks (so it doesn’t complete). This isn’t always useful, in our case we do want the animation to complete but we want it to jump to the end instead of waiting for animation to complete. The second argument true tells .stop() to complete the animation immediately which is what we want. The first argument tells it to clear the animation queue. You can read more about jQuery .stop() here: api.jquery.com/stop/

I’m sure this will be of use to many people. If you have any questions about this post, please feel free to leave a comment below.

What I don’t like about Mac App Store

When OSX Lion came out, everyone in the office needed a copy of the latest xcode. Instead of 20 people downloading the same file individually, one person downloaded xcode via the app store and shared the installer with us. It all went fine, we were able to install it and it worked, however when it comes time to update, trouble arises. Basically the only way to update is if the original person signs in to their Apple account on your computer. You can’t update via Software Update. The only way to get updates without getting the original person to sign in is to uninstall xcode, redownload it, and reinstall it.

That’s right. To obtain updates, I need to uninstall an app I already have installed, and download an installer I already have. That – to me – seems like a big waste of bandwidth. I’ll go back to using serials so installers can be shared instead of being linked to accounts.

CMSO4GX3M1A1333C9 in 2011 MacBook Pro

There didn’t appear to be many people talking about Corsair CMSO4GX3M1A1333C9 4GB PC-10600 and it’s compatibility with 2011 MacBook Pros, so I thought I’d write a quick post about it. I bought 4 of these sticks, 2 for my 13″ 2.7GHz i7 MacBook Pro (8,1), and 2 for another 15″ 2.2GHz i7 Macbook Pro. We put them in and our MacBooks booted perfectly, neither machines have had any issues, so I’m confident to say that these modules work great in 2011 MacBook Pros. Despite the fact I never actually reached 4GB usage on the standard RAM, my MacBook feels snappier and quicker to boot. It’s probably just a placebo though. Either way, at $45 AUD a pop (so, $90 AUD to upgrade to 8GB), these modules are great value and well worth the upgrade.

jQuery – Resize image to parent container plugin

Recently I came across a problem whereby I had to dynamically resize an image to fill it’s parent container. The requirements are pretty straight forward – upscale if the image is too small, downscale if it’s too large, and always resize based on the smallest dimension in relation to the aspect ratio of the parent container (which means that you’ll never see any whitespace, the image will always overflow on either height or width). Strangely enough I couldn’t find a jQuery plugin to do quite what I wanted, so I created one.

Check out the demo.

The plugin is as follows:

/*
 * Plugin Name: Resize Image to Parent Container
 *
 * Author: Christian Varga
 * Author URI: http://christianvarga.com
 *
 */

jQuery.fn.resizeToParent = function(options) {
  var defaults = {
   parent: 'div'
  }

  var options = jQuery.extend(defaults, options);

  return this.each(function() {
    var o = options;
    var obj = jQuery(this);

    // bind to load of image
    obj.load(function() {
      // dimensions of the parent
      var parentWidth = obj.parents(o.parent).width();
      var parentHeight = obj.parents(o.parent).height();

      // dimensions of the image
      var imageWidth = obj.width();
      var imageHeight = obj.height();

      // step 1 - calculate the percentage difference between image width and container width
      var diff = imageWidth / parentWidth;

      // step 2 - if height divided by difference is smaller than container height, resize by height. otherwise resize by width
      if ((imageHeight / diff) < parentHeight) {
       obj.css({'width': 'auto', 'height': parentHeight});

       // set image variables to new dimensions
       imageWidth = imageWidth / (imageHeight / parentHeight);
       imageHeight = parentHeight;
      }
      else {
       obj.css({'height': 'auto', 'width': parentWidth});

       // set image variables to new dimensions
       imageWidth = parentWidth;
       imageHeight = imageHeight / diff;
      }

      // step 3 - center image in container
      var leftOffset = (imageWidth - parentWidth) / -2;
      var topOffset = (imageHeight - parentHeight) / -2;

      obj.css({'left': leftOffset, 'top': topOffset});
    });
  });
}

And to use it, simply call resizeToParent on your image, like so:

$('#myImage').resizeToParent();

The plugin will automatically resize the image as soon as it’s finished loading. By default, the image will get resized to the nearest parent div. If you want to target a specific parent, simply pass a selector to the function as the ‘parent’ parameter, like so:

$('#myImage').resizeToParent({parent: '.parentContainer'});

Also, don’t forget that the parent container must have ‘overflow: hidden’ so that the image doesn’t spill out of the parent, and the image must be positioned relatively or absolutely for it to be centered correctly.

Please feel free to leave any questions, comments, or suggestions in the comments below :)

How to calculate driving distance between 2 locations with Google Maps API

Although this is quite a common question, the majority of tutorials seem to be over-complicating the solution which may confuse people who are new to the Google Maps API. This tutorial is designed to show you an easy way to geocode 2 addresses and get the driving distance between them.

We are going to base our app off the directions-simple.html sample that Google provides. We only need to change a few things to make it display the driving distance.

The first thing we’ll do is create the HTML file. You can use the following code as a guide:

<html>
	<head>
		<title>Distance Calculator</title>
		<style type="text/css">
			#map_canvas {
				height: 100%;
			}
		</style>
	</head>
	<body>
		<div>
			<p>
				<label for="start">Start: </label>
				<input type="text" name="start" id="start" />

				<label for="end">End: </label>
				<input type="text" name="end" id="end" />

				<input type="submit" value="Calculate Route" />
			</p>
			<p>
				<label for="distance">Distance (km): </label>
				<input type="text" name="distance" id="distance" readonly="true" />
			</p>
		</div>
		<div id="map_canvas"></div>
	</body>
</html>

Next, we’ll add the map to the page. Include the following 2 lines in your head tag:

<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>

Then add a script tag to your head with the initialize function to set up the map:

<script type="text/javascript">
var directionDisplay;
var map;

function initialize() {
	directionsDisplay = new google.maps.DirectionsRenderer();
	var melbourne = new google.maps.LatLng(-37.813187, 144.96298);
	var myOptions = {
		zoom:12,
		mapTypeId: google.maps.MapTypeId.ROADMAP,
		center: melbourne
	}

	map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	directionsDisplay.setMap(map);
}
</script>

Finally, add the initialize function to the body onload, like so:

<body onload="initialize()">

If you load up your page, you should see a nice big Google map that doesn’t do much. Let’s change that.

Add a new variable called directionsService and a function called calcRoute() to your script, like so:

var directionsService = new google.maps.DirectionsService();

function calcRoute() {
	var start = document.getElementById("start").value;
	var end = document.getElementById("end").value;

	var request = {
		origin:start,
		destination:end,
		travelMode: google.maps.DirectionsTravelMode.DRIVING
	};

	directionsService.route(request, function(response, status) {
		if (status == google.maps.DirectionsStatus.OK) {
			directionsDisplay.setDirections(response);
		}
	});
}

Then change your submit button to call the function:

<input type="submit" value="Calculate Route" onclick="calcRoute()" />

If you save and reload your page, you should be able to enter 2 locations and the Google Maps API will geocode them and display the route on the map.

But of course, what you’ve really been waiting for is to get the distance of the trip. Let’s do it!

Inside the calcRoute() function, add a new variable called distanceInput (add it under the existing variables):

var distanceInput = document.getElementById("distance");

Last but not least, add the following line of code inside the directionsService response’s anonymous function (add it under the “directionsDisplay.setDirections(response);” line):

distanceInput.value = response.routes[0].legs[0].distance.value / 1000;

Save and reload your page. When you click Calculate Route, not only will the route be shown on the map, but the distance will be calculated too. Congratulations! If your code doesn’t seem to be working, you can view my working example at http://www.christianvarga.com/driving_distance.html to see what went wrong.

Let’s quickly discuss what we’re actually doing here so we can understand why we refer to the response like this.

The directions result object we receive from Google contains a routes array. Multiple routes can be returned if a request is sent with the provideRouteAlternatives field set to true (this is set in the request parameters), but this field defaults to false, and because we don’t set it, we are only ever dealing with one route so we refer to routes[0].

Inside the routes array is another array called legs, which contains details relating to each leg of the journey. A leg is defined as the trip from one waypoint to another. Waypoints can be set in the request parameters (these force the route to pass through the waypoint), however because we don’t set any waypoints, there is only one leg in the journey which is from the start location to the end location, so we refer to legs[0].

Finally, each leg of the journey contains a distance field, which you can either get the value of (in metres) by referring to .value, or you can get a textual representation in the locale’s units by referring to .text. I prefer to get the exact value in metres and then perform my own calculation (divide by 1000) to convert it into kilometres, so I call distance.value / 1000.

There’s a lot more to the Google Maps API, to get the most out of it you can have a look at the directions request/response documentation at http://code.google.com/apis/maps/documentation/javascript/services.html#Directions. This should get you started with extending the functionality of our little app.

If you have any questions or comments, please don’t hesitate to leave them below.