Web design at paulcarvill.com, the home of Paul Carvill on the web

link: paulcarvill at flickr

paulcarvill.com

Hi, I'm Paul Carvill and I'm a web developer. I am Head of Interface Development at LBi, Europe's largest digital agency.

I also like walking, cooking, Bollywood and rock 'n' roll.

Archive for the ‘Web design’ Category

My India travel diary for 2007 and 2008, now online

Sunday, June 14th, 2009

indadiarythumb1I finally got around to typing up my handwritten diaries from my India trip back in 2008. It was a hugely enjoyable exercise reading through the diaries again 12 months later — probably the reason it took me so long to plough through them.

Why put them online? A couple of reasons. I wanted to be able to access them quickly wherever I was, as I often find myself talking to someone about a particular place or event in India that I want to be able to show them a more detailed description of, or sometimes just to remember the name of a hotel to recommend to someone. I also thought they might be useful for other travellers considering a trip to India. Before we went, other than IndiaMike I couldn’t really find any useful ‘on the ground’ reports of day to day travelling around India. In some ways this was a good thing, as we tend to travel extremely independently and this allowed us to travel without any preconceptions. But some people might feel they want to get a flavour of a place before they get there. Also, and probably the most pressing reason, I wanted another nice, simple idea to practice my Django development on.

So I put the new site here: http://www.indiadiary.co.uk. Please check it out and let me know what you think. I’ve included photos of the trip from Flickr and a recommended reading list of the books we went through as we travelled around.

Geocoding location data in a Google spreadsheet

Wednesday, June 3rd, 2009

The problem: I have a spreadsheet full of locations, addresses and place names that I want to publish, along with a map, for at least tens of thousands of people to view.

A solution: Easy — I can put it in a Google spreadsheet, publish it, add a Google map to a page, download the data, geocode the locations and display them on the map.

Another problem: While this is ok in most cases, with a large spreadsheet the geocoding can take a very long time, making my page appear unresponsive and slow. In addition, I have no way of checking that the location data is good enough to map with.

Another solution: Download the data, geocode it using Yahoo!’s Placemaker service, generate a new spreadsheet containing accurate latitude/longitde data and use that in place of the original. The client then does no geocoding their side, it’s all supplied along with the data. Everybody’s happy!

— Go straight to the spreadsheet geocoder! —

I’ve done just that with this PHP script. It takes a Google spreadsheet key, and you must tell it what columns your location data is in. It will download the spreadsheet data, concatenate those location columns, make a request to Placemaker to geocode each location, and return a new CSV file with the geodata columns appended on the end.

I’ve detailed here the various bits that make up the script. The workflow is as follows:

Capture spreadsheet data from user > Load in spreadsheet from Google > For each line in spreadsheet make a Placemaker request > Append geolocation data columns to spreadsheet > Output all results into a CSV file

The script is set to not autodisambiguate, meaning that if it’s not sure what location you’ve supplied, it will return all likely candidates, in order of likelihood. I should mention that Yahoo!’s Placemaker is utterly awesome in find out the ‘whereness‘ of things.

To build your own version of my script will need a Placemaker API key. Other than that, please feel free to copy and paste the code, fix it, amend it and let me know if it’s useful, or if it needs more commenting, or how I could improve it. I wrote this code to fix a particular problem I was encountering, but I’m sure it could work in a few more cases too.

Something to note before I start: the script doesn’t much like having commas in the location data in your spreadsheet. Because Google only output CSV with a comma delimiter, this upsets my CSV parsing. Any suggestions welcome.

This function gets some CSV data from a published Google spreadsheet using a supplied key:


<?php

function getCsvDataFromGoogle($spreadsheetKey) {
	$key = $spreadsheetKey;
	$output = 'csv';
	$apiendpoint = 'http://spreadsheets.google.com/pub?key='.$key.'&output='.$output;
	$ch = curl_init();
	$options = array(CURLOPT_URL => $apiendpoint,
	                 CURLOPT_HEADER => false,
	                 CURLOPT_RETURNTRANSFER => true
	                );
	curl_setopt_array($ch, $options);
	$r = curl_exec($ch);
       curl_close($ch);
	return $r;
}

This function makes a Placemaker geocode request:


function getPlacemakerGeodata ($location) {
	$key = 'MY_PLACEMAKER_API_KEY';
	$apiendpoint = 'http://wherein.yahooapis.com/v1/document';
	$inputType = 'text/plain';
	$outputType = 'xml';
	$focus = '28298150'; // sets focus to Great Britain, not sure how effective this is yet
	$autoDisambiguate = 'false'; // returns the 1 most-likely place, else returns many likely places
	$post = 'appid='.$key.'&documentContent='.$location.'&documentType='.$inputType.'&outputType='.$outputType.'&focusWoeid='.$focus.'&autoDisambiguate='.$autoDisambiguate;
	$ch = curl_init($apiendpoint);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	$results = curl_exec($ch);
	return $results;
}

This function does the bulk of the work, and makes calls to all the other functions:


function parseCsvData($googleSpreadsheetKey) {
	$lines=split( "\n", getCsvDataFromGoogle($googleSpreadsheetKey) );
	if($_POST['format'] == 'csv') {
		if($_POST['locationColumns'] == '' || $_POST['key'] == '') {
			echo "please go back and specify both your google spreadsheet key and which columns contain your location data (in comma separated format, zero-indexed e.g. 0,1,9)";
			exit();
		}
		else {
			// get location columns from url
			$locations = $_POST['locationColumns'];
			$splitLocations = split(',', $locations);
			// set headers to 'csv'
			header("Content-type: application/csv;");
			header("Content-Disposition: attachment; filename=yourgeodata.csv");
			$out = fopen('php://output', 'w');
			for($i=1;$i

This function parses the XML which gets returned from Yahoo! Placemaker:


function parsePlacemakerXML($results, $delineator) {
	if($delineator == 'comma') { $delStart = ''; $delEnd = ','; }
	else { $delStart = '<td>'; $delEnd = '</td>'; }

	$places = simplexml_load_string($results, 'SimpleXMLElement', LIBXML_NOCDATA);
	$locarr = array();
	if($places->document->placeDetails) {
		foreach($places->document->placeDetails as $p) {
			if($delineator == 'comma') {
				$locarr[] = $p->place->name;
				$locarr[] = $p->place->centroid->latitude;
				$locarr[] = $p->place->centroid->longitude;
				return $locarr;
			}
			else {
				echo $delStart.$p->place->name.$delEnd;
				echo $delStart.$p->place->centroid->latitude.$delEnd;
				echo $delStart.$p->place->centroid->longitude.$delEnd;
			}
		}
	}
}

This bit runs when you load the page and works out if you're submitting some data or just viewing the page. If you've submitted data, it runs the main function:

if(ISSET($_POST['submit'])) {
	parseCsvData($_POST['key']);
}

Or if you're viewing the page for 1st time, you get a form to fill out:

else {
	echo "<html><head><title></title></head>";
	echo "<body>";
	echo "<p>Please enter your spreadsheet key and specify which columns contain your location data (use comma separated list e.g. 9,10,11):</p>";
	echo "<form method=POST><p><label>Key:<input type='text' name='key' /></label></p><p><label>Location columns: <input type='text' name='locationColumns' /></label></p><p><label>Format: <select name='format'><option value='csv'>csv</option><option value='table'>table</option></select></label></p><p><input type='submit' name='submit' /></p></form>";
	echo "</body></html>";
}
?>

HTML for humans

Saturday, April 18th, 2009

The most recent Road to HTML5 blogpost is on the subject of link relations. To sum up in one sentence, link relations ‘explain why you’re pointing to another page’. But that is to miss all the detail and nuance of the article, so go there and read it if you’re at all interested in web development.

The whatwg blog continues to be a friendly, highly readable and discursive source of information on upcoming HTML5 developments. It also clarifies many misconceptions you may have had about previous HTML specs and the reasoning behind any changes, often in a satisfyingly wry style. On the subject of the ‘rev=made’ attribute it has this to say,

“The decision to drop the rev attribute [from HTML5] seems especially controversial. The same question flares up again and again on the working group’s mailing list: “what happened to the rev attribute?” But in the face of almost-universal misunderstanding (among people who try to use it) and apathy (among everyone else), no one has ever made a convincing case for keeping it that didn’t boil down to “I wish the world were different.” Hey, so do I, man. So do I.”

http://blog.whatwg.org/

How to do music lists

Monday, March 16th, 2009

How to do a list of songs on a newspaper or magazine website:

And how not to:

  • The Telegraph’s 100 Greatest Songs Of All Time — in which the adjudicating panel of one – Neil McCormick – hilariously abandons grammar in favour of enigmatic SMS-length capsule reviews. Sample description of The Doors’ Light My Fire, “Provocative, sensual, slinky song weaving erotic desire.” And another one of U2’s Still Haven’t Found What I’m Looking For: “Gospel rock hymn of doubt and spiritual quest.”
  • Esquire’s 50 Songs Every Man Should Be Listening To — let me get this straight: you want me to click through at least 50 times, even more with ads, and if I haven’t heard the band you’re talking about the onus is on me to wade through the internet to find one of their songs to listen to? OK, thanks.

You’ll miss me when I’m gone: IE6, cross-browser consistency and device independence

Saturday, February 14th, 2009

A flurry of IE6 related activity on the web this week coincided with a discussion we are having at The Guardian on the same subject. We have been talking about the relative benefits of keeping website performance in IE6 consistent with that of other browsers, and the disproportionate amount of work this requires on the parts of developers and the QA team. We’ve been trying to figure out better processes to reduce the number of styling bugs in IE6, while not compromising the user experience or the hard work put in by our design team.

It turns out people have surprisingly strong views on cross-browser consistency. For some, IE6 represents much more than just ‘a browser’. It also represents, variously: a large market share; an important group of corporate users; a user’s freedom to choose whichever device she wishes to browse the web. Once you start dropping a browser for technological reasons, the argument goes, you might as well arbitrarily drop support for anything which you consider below par – mobile browsers, text browsers, people with small monitors.

The opposing view says that IE6 is many years old and two versions out of date, a huge security risk and a drain on resources. We shouldn’t be pandering to slow or paranoid IT departments who refuse to upgrade their systems. Anyway no one chooses to use IE6, it is forced upon them by said IT departments.

I’m loath to branch the code to produce a separate version of the site for any reason, be it a device or a browser. But I also see the amount of pain IE6 causes developers, especially when they’re trying to do something fancy with JavaScript, and even more especially trying to do so without using a standard library which might easily provide you with cross-browser methods for doing stuff.

I support IE because I have to. But I do also believe strongly in wide accessibility, through as many devices as possible. We should assume nothing — nothing — about how our users access the web. But I don’t think this is the point here. The point here is adhering web standards, which apply to both code and content. Remember, the content itself — the information — usually isn’t broken. It’s what you’re trying to do with it that’s broken. The CSS and the JavaScript. Go back to Tim Berners-Lee’s 2002 document on universality and device independence for a lesson in what putting stuff on the web is all about. Work with the web, not against it. It’s really good at presenting and sharing text and pictures. But it’s not a magazine layout. Berners-Lee once said,

“Anyone who slaps a ‘this page is best viewed with Browser X’ label on a Web page appears to be yearning for the bad old days, before the Web, when you had very little chance of reading a document written on another computer, another word processor, or another network.”

We can infer from this that a site isn’t ‘best viewed in’ anything: it’s just ‘viewed’, however it might end up. So, yes, your site might look lovely, but if getting it there is so complex that it breaks browsers, or takes up 50% of your development time, then you’re plainly doing something wrong.

Try taking your page back to basics, get rid of the awful advertisement JavaScript and the three different kinds of page tracking, and start paying more than just lip-service to web standards and accessibility. That XHTML doctype declaration you’re using, trying adhering to it. There, it probably works a lot better now, yes?

But ultimately, and as usual, I think the whole issue comes down to a business decision: how much time/money are we spending on development versus how much money that development brings in. It’s a brave person who decides to cut off 25% of their users.

Some points that came up as part of our ongoing discussion:

  1. Should the design be 100% consistent across all browsers, or would our designers be happy to sacrifice certain style elements? We currently stop a code release if something looks bad in IE6, although we have already made one or two decisions to remove an element from IE6 in order to expedite a code release. In both cases we ran things past the Guardian’s Creative Editor, Mark Porter, before doing so.
  2. If you want to drop suport for IE6, you have to completely and utterly drop support for it. And in all likelihood never look at it again. Because the next time you do, it will be horrifically broken. Stopping development on that browser doesn’t just mean it won’t get cool new features. It still gets the features, but they won’t be tailored to it, and will break it. That smart Javascript widget you just wrote? That breaks the page in IE6. Some new element you put in with a fixed width and margins? That breaks the page in IE6. You have to cut the cord. Be strong, give it a firm handshake and say goodbye.
  3. Turns out Microsoft haven’t quite cut the cord yet, though. Microsoft support Windows XP Service Pack 3 as a current product (it shipped in April 2008), and will retire support for it 2 years after the next service pack is released, or at the end of the Windows XP product lifecycle, whichever comes first. IE6, which shipped as a component of XPSP3, continues to have Mainstream Support as part of that product:
  4. Our current browser usage figures look like this:
    • IE 7: 35%
    • IE 6: 25%
    • Firefox 3: 25%
    • Safari: 7%
    • Firefox 2: 3%
    • Google Chrome: 1.5%
    • Opera: 0.5%
  5. We currently have a problem even testing in IE6, because the corporate build on the PCs we use doesn’t contain it, it has IE7 as standard. And you can’t run IE7 and IE6 concurrently. Ironically, our technical infrastructure is sufficiently advanced that we have difficulty supporting old technology.

That flurry of activity in full: