Christian Heilmann

You are currently browsing the Christian Heilmann blog archives for May, 2010.

Archive for May, 2010

Rimshots for all – using HTML5 audio and CSS3 to make instantrimshot.com

Sunday, May 23rd, 2010

I’ve been annoyed with the plethora of articles lately showing off HTML5 vs. Flash and building actually worse solutions using open technology. Therefore I thought I’ll have a go at it myself, too.

Instant rimshot is a fun site that has a button that plays a rimshot (the “babumm-tish” after a bad gag at a comedy club) when you press a large red button. I thought this is a good target to convert to CSS and HTML5 and I give you HTML5 instant rimshot.

HTML5 instant rimshot by  you.

In essence this was fun, although Remy had beaten me to it some time ago.

As the background for my work I used HTML5Doctor’s Audio in the browser article and Robert Nyman’s CSS gradient example and I have to say a few things about this:

  • There are not many HTML5 audio tutorials out there – if you Google for HTML5 audio you get video examples – and a lot of them not working.
  • HTML5 articles do not seem to get many fixes – the audio one above for example has a bug in the detection code (mentioned in the comments)
  • I had a hard time making the button work with the sound playing from start to end when you click the button. If you try the “version that loads the audio once and then calls the play() method onclick”:http://isithackday.com/html5-rimshot/rimshot.html you will find that the second time you hit the button it plays the “badumm” twice in Firefox – why I don’t know. Therefore I needed to create a new audio object every time you click the button – which in Safari means it keeps loading the MP3.
  • The necessary browser support forking and the repetition of the file in MP3 and OGG format is simply annoying – if there is a new technology we should demand from browser makers to bloody well do it right and not as a repetition of the late 90ies madness. I guess the latest announcement on I/O solves that issue – but Safari would still need a plugin to play.
  • The same applies to CSS gradients – progressively enhancing the button (on Firefox < 3.6 and on Opera it gets a plain colour) was another annoyance. Westciv’s gradient generator was a good helper for that.
  • Another interesting bug I found was that you cannot position things absolutely inside a BUTTON element in Firefox. Originally I had the button link as a button but gave up soon enough – see the example here.

All in all I love the idea of the open web and HTML5 leading the way into the future but I am seeing us wasting a lot of time trying to make things work cross-browser and if the final result for the end user is not much better then it will be hard to convince our bosses that the effort is worth the time and money.

What we need for that first and foremost are good examples and not “look what we can do” tutorials that neither use HTML5 nor CSS3 but jQuery to simulate the lot whilst we still call it “HTML5 solutions”.

TTMMHTM: Google delivers, Guardian delivers and some more developer goodies

Friday, May 21st, 2010

Damn, life is good as a developer right now.

** We finally have an open video format with WebM which is a container based on Matroska with VP8 as the video and Vorbis for audio. It is backed by Opera, Mozilla and Google amongst other huge players. IE9 says it will support it with a plugin and Safari seems to be supporting it via a Quicktime plugin.

** Google released a library to make it easier to embed web fonts and also host quite a bunch of fonts for easy embedding – preliminary reports by friends of mine state that they look amazing on Mac but very bac on PC - can you verify this?

** Google Latitude now has an API but it also shows some problems

** Google also released BigQuery which is a REST API to analyse data in Google Storage. One of the uses they showed is the Prediction API which does natural language analysis and could become a contender for Open Calais.

** AppEngine got some good updates including a Comet API

** Android got a major update – it now runs the superfast V8 engine, you will have access to accelerometer and camera with a JavaScript API and you can send applications to the phone from computers via the cloud. Makes me want to kill the guy who dropped my Nexus One and hope HTC will be quick in repairing it.

My Google Nexus One died – or the perils of very early adoption

Wednesday, May 19th, 2010

When I went to California last I was lucky enough to meet some friends from Google for lunch at their office and as a surprise on the way out I got a Nexus One as a present:

Nexus One - thanks Google! by  you.

I loved it immediately. It is a very slick phone with a real “developer touch”. This means:

  • To get data on or off it I connect it to a USB port and copy the stuff – no need to fire up some “Media Explorer” or iTunes.
  • The handling was wonderful – even though I never had a touch phone before I had no issues with it at all (except when I tried to type German SMS with the English dictionary on)
  • The geolocation stuff, Google Goggles, Google Maps, Point by Point navigation and all the other stuff that only runs on this platform beat the pants off the iPhone (at least for me)
  • The camera is amazing and the display is crisp as can be

That is until yesterday night. When I gave the phone to someone at the Future of Web Design after party to have a look at it he dropped it. I didn’t check and just pocketed it and this morning I found the display to look like this:

Broken Nexus One by  you.

It has a bit of a Eastman Colour vibe to it but makes it impossible to use. Funnily enough the touch stuff still works perfectly but outside of artificial light you cannot see anything on it any longer.

Now I am busted:

  • Where can I get a free Nexus One repaired in the UK? This is a no contract phone.
  • What can I do about my Jewels and Layar addiction?

It is a great example how being a very, very early adopter can bite you in the bum if something as simple as gravity messes with you :(.

Building a mashup with Government Data – Warwickshire Info

Tuesday, May 18th, 2010

The Open Data Group of the lovely area of Warwickshire in England is running a hack competition right now and they ask hackers to build something cool with their data sets.

I looked at the catalogue of offers and took the simple way out – I created a mashup showing you the parks, museums, schools and libraries in the area both as lists with all the information and a an interactive map.

You can see the result here and by clicking the screenshot below.

Warwickshire information

In the following screencast I am talking people through the ideas and how I build the mashup:

If you want to build it yourself, get the source code from GitHub and here’s a quick step-by-step:

In the beginning, there was data, and it was good (to a degree)

The first thing I went for was to get my datasets:

Notice that the last dataset is vastly different to the others (uppercase elements for a start) and also that it contains the gem of 52.4786839 – would be good to spell-check your elements :) (that cost me 20 minutes of my life later on).

Now, I could load all of these one by one and then start converting the data to a useful format but as I am lazy I use YQL for that:

select * from xml where url in (
“http://ws.warwickshire.gov.uk/parks.xml”,
“http://ws.warwickshire.gov.uk/libraries.xml”,
“http://ws.warwickshire.gov.uk/museums.xml”,
“http://opendata.s3.amazonaws.com/schools/schools-warwickshire.xml”
)

This, sent to the right YQL webservice endpoint results in an aggregated XML document and means I only have to have one HTTP request to load the data. Check this link to see the aggregated file.

Planning the mashup

Now, I’ve built mashups like these tons of times and mostly they end up to be a quick but terrible mess. Therefore I thought I change my approach. As the main solution I simply wanted to show a list of all the parks, museums, libraries and schools. This would work regardless of environment and ability of the user agent. Instead of assembling a JSON object to plot the information on the map I wanted to use the HTML as my data source by adding some classes (much like Microformats were meant to be used before the world forgot about them to chase CSS3 transition effects).

The HTML and CSS

So the first thing to do was to make sure my CSS works out fine. I did this by using the YUI CSS grids for my layout (building the interface with the grids builder)

This gave me an HTML skeleton to work from and also got rid of all the font issues across browsers which meant that in the end all my CSS file had to do was to show and hide things and put on a lick of paint (don’t judge me – I built this in FireBug).

The last thing I needed was a container DIV with a placeholder for the map and one for the information to be displayed about the marker the user clicked on the map:




Retrieving and converting the data

With that out of the way, all I needed was to get the data from YQL into my own HTML - for this I used PHP and cURL:

$yql = ‘select * from xml where url in (‘.
‘”http://ws.warwickshire.gov.uk/parks.xml”,’.
‘”http://ws.warwickshire.gov.uk/libraries.xml”,’.
‘”http://ws.warwickshire.gov.uk/museums.xml”,’.
‘”http://opendata.s3.amazonaws.com/schools/schools-warwickshire.xml”’.
‘)’;
$url = ‘http://query.yahooapis.com/v1/public/yql?q=’.urlencode($yql).
‘&diagnostics=false&format=json’;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
$data = json_decode($output);

This gives me all the data in the $data variable as a native PHP object. All that I needed to do was to analyse the data coming back and wrap it in the right HTML.

Displaying the HTML for each section

echo ‘

Parks (‘.
sizeof($data->query->results->parks->park).
‘)

    ‘;
    foreach($data->query->results->parks->park as $k=>$p){
    echo ‘ if($p->image){echo’ class=”hasimg”’;}
    echo ’ id=”p’.$k.’”>‘;
    echo ‘

    ‘.
    $p->name.’

    ‘;
    if($p->image){
    echo ‘Location: ‘.
    $p->coordinates.’

    ‘;
    }

    echo ‘

‘;

I add a DIV with the class section around each of the parts I want to show and wrap the results in an unordered list with an ID. I add a class called hasimg to the list items that contain an image to allow for the right CSS layout and I wrap the name of the section in a SPAN with the class name. This allows me later on to read this information to plot it on a map. Each list item also gets a running ID of p1, p2, p3 and so on which allows me to read the information when the user clicks the marker on the map.

I’ve written a small helper function called addpara() to only write out the paragraphs of elements that have content as I wanted to avoid empty P elements. The section ends with a P with the class geo which contains a SPAN with the coordinates – once again to allow me to plot it on a map.

This gets repeated for parks, museums and libraries but the schools data set needed special treatment. First of all the format was different, but it also returned data in uppercase, which is just not fun.

That’s why I used ucwords() and strtolower() to clean up the data before displaying it:

echo ‘

Schools (‘.
sizeof($data->query->results->RECORDS->SCHOOL).
‘)

    ‘;
    foreach($data->query->results->RECORDS->SCHOOL as $k=>$s){
    echo ‘
  • ‘;
    echo ‘

    ‘.$s->SCH_NAME.’

    ‘;
    addpara(‘’,ucwords(strtolower($s->ADDRESS_1)));
    addpara(‘’,ucwords(strtolower($s->ADDRESS_2)));
    addpara(‘’,ucwords(strtolower($s->ADDRESS_3)));
    addpara(‘Post code’,$s->POSTCODE);
    addpara(‘Type’,$s->SCH_TYPE);
    addpara(‘’,$s->EDUC_AREA);
    echo ‘

    Location: ‘.
    $s->LATTIUDE.’,’.$s->LONGITUDE.’

  • ‘;
    }

    echo ‘

‘;

That’s the lot. If you turn off JavaScript in the mashup you can see the outcome of these efforts – a long list of different sights preceeded by a heading.

Adding the map and collapsing the sections

The next step in the process was to ad the JavaScript functionality. I added a class called js to the body of the document when JavaScript is available and included the Yahoo Maps API and the YUI library. The latter allows me simple and browser independent access to both the DOM and events in the browser, the former is of course needed to show the map.




Adding the class to the body saves me a lot of trouble. Instead of looping through all the lists and hiding them (as I want to show and hide them when you click on the headers), I can now do that in the CSS:

body.js .section ul{
position:absolute;
left:-9999px;
height:10px;
overflow:hidden;
}

body.js .show ul{
position:relative;
left:0;
top:0;
height:auto;
overflow:auto;
}

This hides all the lists and when I want to show them all I need is to add a class called show on the containing DIV.

Finishing up with the rest of the JavaScript functionality

The JavaScript to do the rest of the functionality is no magic:

wws = {};
YUI.use(‘node’,function(Y){
Y.one(‘body’).addClass(‘js’);
Y.all(‘.section h2’).set(‘tabIndex’,-1);
Y.all(‘.section ul’).set(‘tabIndex’,-1);
Y.one(‘#info’).set(‘tabIndex’,-1);
[...]
});

I define wws as a namespace, but I don’t need to worry about embedding the code in the closure as YUI’s use() method does that for me. I add the class to the body (as the HTML maintainer might remove the other JavaScript that does that – it is only there to fire as soon as possible). Then I add a tabIndex of -1 to all the elements I want to make interactive – this makes them available to keyboard users.

Using the wonders of Event Delegation it is very easy to make all the H2 headings in the #bd clickable and show and hide the following ULs:

Y.delegate(‘click’, function(e) {
e.preventDefault();
var dad = Y.one(e.target).ancestor(‘div’);
if(dad.hasClass(‘show’)){
dad.removeClass(‘show’);
} else {
dad.addClass(‘show’);
var next = Y.one(e.target).next(‘ul’);
next.focus();
}

}, ‘#bd’, ‘h2’);

I add and remove the show class to show and hide the ULs and move the focus to the list when the header is clicked.

Next I wanted to explain to the end users what can be done here. You will find a lot of mashups that will have this info in the HTML but what if JavaScript is not available? You explain functionality that is not available and confuse users. This is why I add the information to the info section and add a class to allow for different styling as this section will be re-used to show the information of the marker I clicked on.

Y.one(‘#info’).set(‘innerHTML’,

Get all the information here

‘+

Click any of the icons on the map to the right to get ‘+
‘detail information about the location.

‘+

You can make the map less busy by turning features on and off’+
‘with the buttons above.


).addClass(‘intro’);

Next up I start the map:

var points = [];
wws.map = new YMap(Y.one(‘#map’)._node);
wws.map.addTypeControl();
wws.map.addZoomLong();
wws.map.addPanControl();
wws.map.disableKeyControls();
wws.map.setMapType(YAHOO_MAP_HYB);

The points array will hold all the points I want to show on the map. Yahoo maps can get the right zoom level and map centre automatically for you when you give it an array of points. I disable the key controls to make sure the map doesn’t interfere with page scrolling and define hybrid as the map type. As the map needs to be globally accessible I attach it to the wws namespace.

var parks = Y.all(‘#parks .name’).get(‘innerHTML’);
var parklocs = Y.all(‘#parks .geo span’).get(‘innerHTML’);
for(var i=0,j=parks.length;i var coor = parklocs[i].split(‘,’);
var point = new YGeoPoint(coor[0],coor[1]);
points.push(point);
var img = new YImage();
img.src = ‘park.png’;
img.size = new YSize(32,32);
var marker = new YMarker(point,img,’mp’+i);
YEvent.Capture(marker, EventsList.MouseClick,
function(i){
var src = document.getElementById(i.thisObj.id.replace(‘m’,’‘));
wws.showinfo(src.innerHTML);
});
marker.addAutoExpand(parks[i] + ’ (click for more)’);
wws.map.addOverlay(marker);
};

And off we go.

So what’s going on here? I read the names of all the parks and the location of all the parks using the Y.all() method of YUI3. I then loop over the parks, split the coordinate information on the comma and create a new GeoPoint from it. I add the point to the points array, define an image for the point and create a new YMarker. In the marker I add the point, the image and a running ID. This will label the markers internally as mp0, mp1, mp2 and so forth. This I need to connect the marker with the content section in the list (remember I added a running ID on the list items when I wrote them out in PHP).

I then add a capturing function to the marker that fires when it is clicked. In this one I read out the ID of the marker (using the rather obtruse i.thisObj.id property), remove the “m” from the ID and get the content of the element with this ID - which is the connected list item. I send the content to the showinfo() function.

Furthermore I add an AutoExpand with the name of the park and a “click for more” message to the marker and add it to the map.

This functionality is repeated for all the different sections which seems a waste but years of building this kind of stuff taught me that a few weeks down the line you will have to make amendments for different sections anyway so a bit of copy and paste doesn’t hurt.

var zac = wws.map.getBestZoomAndCenter(points);
var level = zac.zoomLevel;
wws.map.drawZoomAndCenter(zac.YGeoPoint,level-2);

I get the best zoom level and the centre of the map and draw it. I remove two levels from the best level as the markers are very dense on this map and I didn’t want to overwhelm the end user.

Y.one(‘#container’).append(

);
Y.one(‘#container’).prepend(
‘+
‘+
‘+
‘+
‘+

);

I then needed some interactive elements to allow resizing of the map and to show and hide the different markers. For this I create buttons as that is what they are there for – firing JavaScript functionality. I add the buttons to the container element and give each an ID to differentiate between them.

Y.delegate(‘click’,function(event){
var t = Y.one(event.target);
switch(t.get(‘id’)){
case ‘size’:
if(t.get(‘innerHTML’).indexOf(‘smaller map’)!=-1){
t.set(‘innerHTML’,’↓ larger map ↓’);
Y.one(‘#map’).setStyle(‘height’,’280px’);
} else {
t.set(‘innerHTML’,’↑ smaller map ↑’);
Y.one(‘#map’).setStyle(‘height’,’600px’);
}

break;
case ‘librariesbutton’:
if(t.get(‘innerHTML’).indexOf(‘hide’)!=-1){
wws.toggleMarkers(‘ml’,0);
t.set(‘innerHTML’,’show libraries’);
t.addClass(‘inactive’);
} else {
wws.toggleMarkers(‘ml’,1);
t.set(‘innerHTML’,’hide libraries’);
t.removeClass(‘inactive’);
}

break;
[... repeated for the others …]
}

},’#container’,’button’);

Again I use event delegation to attach functionality to all buttons in the container element and differentiate by reading out the event target and its ID. For the resizing button I resize the map and change the content of the button. For the other buttons I call the toggleMarkers() method using the string to identify the markers and a boolean to turn them on or off and change the content of the button. To allow for extra styling I also add and remove a class called inactive.

wws.showinfo = function(html){
Y.one(‘#info’).set(‘innerHTML’,html).removeClass(‘intro’);
if(Y.one(‘#info a’)){
Y.one(‘#info a’).focus();
} else {
Y.one(‘#info’).focus();
}

};

The showinfo() function simply changes the content of the info element and removes the intro class to trigger the less “in your face” style the intro blurb had. It then checks if the content contains a link and sends the focus of the document to that one – or to the info element itself. This helps keyboard users.

wws.toggleMarkers = function(str,what){
var markers = wws.map.getMarkerIDs();
for(var i=0;i if(markers[i].indexOf(str)!==-1){
var m = wws.map.getMarkerObject(markers[i]);
if(what){
m.unhide();
} else {
m.hide();
}

}
}

};

The toggleMarkers() method retrieves all the marker IDs from the map and loops through them. If they match the ID string sent through by the button event handler it shows and hides all the markers of a certain type. Notice that the opposite of hide() is unhide() in the Yahoo Maps API :/.

That’s all folks

And that is the mashup – some styling in Firebug, a few PHP tricks to pack the content before sending it on the wire and doing local caching and I was done. And so can you. Go forth and hack.

FOWA Dublin – Powerful Tools that You Need (and Probably Don’t Know About)

Sunday, May 16th, 2010

Last Friday I was up in Dublin at the Future of Web apps and gave my talk “Powerful Tools that You Need (and Probably Don’t Know About)”. I took FOWA as an opportunity to (re-)introduce the audience to some of the tools Yahoo offers and to brand the drive of developers to do everything by themselves instead of using already built solutions as ineffective.

The slides of my talk are available on SlideShare:

The audio of the talk is on Archive.org:

The video of the talk is available on Ustream:

Here are the resources I talked about as links:

Also check the YDN blog in the next few days for a full FOWA report.