BenjaminBenBen @benjaminbenben

Visualising CSS selector matches 09 May 2013

I was working with a large css codebase and wanted to see if our rules were becoming more specific as the css source grew, so I built css.benjaminbenben.com to look at how css rules are applied to a page.

Active rules

This shows how many of the selectors are being used on a page, you can toggle to show only the active ones.

Overview

The ‘-’ link on the bottom right scales the rules so that they fit the height of the window. This is to show the how the impact changes as rules are added to the css.

An example (with notes) of the jsOxford site is below:

 How it works

The main part of this is a PhantomJS script which

  1. loads the page
  2. extracts all stylesheet rules
  3. finds matching elements for each rule and gets the positions of them
  4. takes a screenshot

All this is sent back to the client in a json object (including the image as a data-uri).

Example pages


Cross window communication part 1 24 April 2013

I was part of the "Rising Stars" track at the jQuery UK conference this year where I talked about sending messages between browser windows. This post covers the first half of my talk - sending events between local windows.

My slides are now online, though they are more prompts for me to talk, rather than being full of information. The demos wouldn’t really work with it being publically accessible, so I’m going to cover each of the techniques I mentioned on this blog.

The websockets/binaryJS/webRTC things are on the way - just working on getting the server side part hosted nicely.

postMessage

When you have a window that you can reference from with js - either by getting an iframe from the DOM, or as returned by window.open() - you can use postMessage to communicate with that window (crucially, even if that window has a different origin).

// Send messages from parent window
var win = window.open('http://benjaminbenben.com/pink.html','','width=200');
document.onselectionchange = function(e){
	win.postMessage(document.getSelection().toString(), '*' );
}

// (on the target window) listen for messages 
window.addEventListener('message', function(e){
	echo.textContent = e.data;
});

>demo opens a window and sends it the text selection from this page

For more information about postMessage - check out the entry on MDN and on John Resigs blog post about it.


Storage Events

When you aren’t able to access a window directly, but it shares the same origin - you can use storage events to synchronise data between windows.

A storage event is fired when another window changes the localStorage for that page. By listening to these events - you can keep objects in sync across windows.

// listen for changes from other windows
window.addEventListener("storage", function(e){
	if(e.key == 'example') $('#el').css(JSON.parse(e.newValue));
}, false);

// update a local element and notify other windows of the change
$('#el').css({color:"red"});
localStorage.setItem('example','{color:"red"}');

A nice side effect of this is that you have the state of an element persisted in localStorage, so you could render that on page load. See this gist for a general way of doing this.

This approach can become particularly interesting when the data being synced is displayed in different ways in different windows - in my talk I showed how the reveal.js slide deck could be viewed in both overview and normal views at the same time (see this gist to see how that can be implemented).

demo move your mouse over the area below, any other windows open on this page will update


Reading QR codes from getUserMedia with web workers 14 April 2013

[tl;dr] examples - (currently requires chrome):
>with web worker (should be smoother)
>without web worker


Web workers let you to take JavaScript execution off the main UI thread - which can be really useful if you are doing complex things with video

I came across a javascript qr-code reader a few days ago. When I started using it to scan from a getUserMedia stream - it worked fine, but the extra processing was blocking the ui, which was particularly noticable when you’re displaying the video.

I thought it was a pretty good candidate for taking the processing off to a web worker; which turned out pretty well.

Scanning QR code with getUserMedia

Once you’ve got the imageData from your canvas, you can run it through jsqrcode by setting attributes of the qrcode object, then call .render():

qrcode.imagedata = imagedata;
qrcode.width = imagedata.width;
qrcode.height = imagedata.height;

var content = qrcode.process();

It was pretty straightforward to pull the code into a web worker, I spent a bit of time before I realised that console.logs were making it fall over. Here’s the interface for responding to messages with the worker:

self.onmessage = function(event) {
    var imagedata = event.data;
    qrcode.imagedata = imagedata;
    qrcode.width = imagedata.width;
    qrcode.height = imagedata.height;

    var resp;
    try{
        resp = qrcode.process();
    } catch(e){
        resp = ''; // *mostly* "no code found"
    }
    postMessage(resp);
};

Back in the original page, you can creater the worker and deliver messages to it using the .postMessage function. You can optionally list Transferable objects to efficiently move them to the web worker.

var worker = new Worker("jsqrcode/worker.js"),
worker.onmessage = function(event) {
    console.log("qr code is:" + event.data);
}

// imagedata = ctx.getImageData(…)
worker.postMessage(imagedata, [imagedata.data.buffer]);

Jsqrcode is on github, as is my fork with the starts of the worker interface. You can either view source on the examples above, or view them on github.


Tweet Globe 07 April 2013

Plotting geocoded tweets on a globe with canvas

Requires Canvas Support

I gathered a few hours of geocoded tweets from the twitter streaming api (using the maptime code as a base). This was to explore some ideas that we’d been talking about at White October.

Drawing the globe is relatively straightforward. The lat/long pairs are converted into position vectors, which are then transformed based on the mouse position. The Sylvester library was pretty handy for transforming the points (Pete talked about Sylvester at jsoxford recently).

The original plan was to animate this over a period of time, though it looked quite random/noisy so I went for this static view instead.

Gareth pointed me to a post about the effects in tron legacy which makes me want to make this a lot more awesome!


lllocal 05 April 2013

I built lllocal - which lets you find and listen to bands that will be playing in your area soon.

I’ve been thinking of this idea for a long time and I put up a public version a couple of months ago. It’s brilliant to get feedback from people and I’ve also got tickets to two events while testing it out for myself (Keaton Henson was great and we’re off to see Daughter in a couple of weeks).

My motivation for lllocal came from:

Lllocal inspiration

The gig listings come from the last.fm api and the Spotify web apis are used to find and play the bands on spotify.

There is still a huge amount to do - though I’m really happy to have something online. If you have any feedback or suggestions I’d love if you got in touch or left a message on the feedback page.

Lllocal is online at lllocal.com.


Maptime 05 December 2012

In time for our first JS Oxford meet - I put together a small node app which reads geocoded tweets from the twitter streaming api and pushes them to the browser to display on a map.

This is a stripped down version of a project that I worked on at White October this summer. This version is not at all for production use (your browser will grind to a halt if you leave it running for a while!), though I hope it’s a good/interesting example of linking up server and client js.

The code is all up at the jsoxford github account, I’ll go over a few bits of it:

app.js

This is the main node.js file it brings in some external packages:

Once these have been brought in, you can connect to the streaming api using ntwitter. This gives you access to a stream object, which you can add listeners for new tweets using the stream.on() function (see eventEmitter docs for more details).

twit.stream('statuses/filter', filterParams, function(stream) {
  // stream.on('data', yayFn)
});

We then want to serve some static files for our client side pages/scripts, you can use express to do this (express can do a whole lot more - if you want to have a look, I’d recommend using the executable to generate a basic app).

We also want to send data to the browser using faye, this has a really nice pubsub api based on the bayeux protocol. Attaching this to the http server will listen for websocket/ajax long-polling requests and serve a client js wrapper at /faye.js.

var app = express();
app.use(express.static(__dirname + '/public'));

var bayeux = new faye.NodeAdapter({mount: '/faye'});

var server = http.createServer(app);
bayeux.attach(server);
server.listen(3000);

Now, to link it all together - you can listen for events on the twitter stream, then publish them to a faye channel with the following code.

stream.on('data', function(data){
  if(data.geo)
    bayeux.getClient()
      .publish('/tweet', {
        geo: data.geo,
        text: data.text
      });
});

markers.html

Moving clientside (this code is in ./public and will be served to the browser), we first want to connect to the faye pubsub. To do this, we include the faye client library and connect to the endpoint that we mounted faye at on the server using Faye.Client.

<script type="text/javascript" src="/faye.js"></script>
<script type="text/javascript">
var client = new Faye.Client('/faye');
</script>

We’re using the google maps api to display the map and place the markers. The majority of the code for this is straight from the simple-markers example. (To get more of an introduction - have a look at the tutorial).

To get the tweet data from Faye, you use the client.subscribe function to listen to a channel - in this case we broadcast them over ‘/tweet’ from node.

var mapOptions = {
	// ...
};
var map = new google.maps.Map(document.getElementById("map"),mapOptions);

client.subscribe('/tweet', function(message) {
  if(message.geo && message.geo.coordinates){
    placeMarker(message.geo.coordinates);
  }
});

function placeMarker(coords){
  var latlng = new google.maps.LatLng(coords[0],coords[1]);
  new google.maps.Marker({
    position: latlng,
    map: map,
    title:""
  });
}

And that’s it! Have a look at the code on github (I’ve missed out a little bit of the surrounding bumf above) and have a play with it.

Also, if you are based around Oxford - come along to our next JSOxford meet on the 17th of January.


Lastfm Canvas Streamgraph 04 November 2012

A browser based last.fm streamgraph using canvas.

This is based on Lee Byrons listening histories project. I love this project - it’s a really interesting and engaging visualisation, and the last.fm data makes it really personal (I can’t think of any other services that give as much personalised data as last.fm).

There are services that let you download a pdf streamgraph: lastgraph.aeracode.org & last.fm playground (if you’re a subscriber).

My version is different as all the api requesting and graph drawing are done in the browser - this lets you see your graph as soon as any data is ready.

I originally started creating a large svg for the whole chart, though this became quite slow, so I used separate canvas elements for each week of data and . This is slightly limiting - I couldn’t sort or colour the artists based on when they appear in your history (as the original does).


Out With The Old 25 September 2012

After more than a year of no posts - I've left my old blog behind.

This new one is built with Jekyll and put it online with GitHub Pages. The source is on github.

It seems that a lot of Jekyll sites start with a post about the interesting way that they have been deployed. So, for the record, I kept it simple and went for the github jekyll generator.