Large video player in the YouTube Feather beta

The YouTube Feather beta allows you watch videos without a lot of useless features (no comments, Google+ crap, ...) The only downside is that they only offer the small video player. A simple bookmarklet solves this easily.

The bookmarklet has a customizable width for the player. For this example, I chose a width of 900 pixels. We'll set a new size for the container and video player, along with the correct height (16:9) for the video player. An extra height of 30 pixels is added for the player controls at the bottom. Finally the left margin is reset to 10 pixels.

If you want to adjust the width, change the w variable at the beginning.

var w=900;
document.getElementById('p').style.height=(w*9/16 + 30)+"px";

Simply drag this bookmarklet: YT900 containing the above code in your shortcut bar

Here's the bookmarklet for a 1280x720 resolution: YT720p

Converting an Illustrator drawing to an HTML image map

A while ago, I had to incorporate a map of Flanders into a site, so I had my designer draw the map in Illustrator. The problem was that different regions needed to be clickable, so I'd have to make an HTML image map. Image maps support polygon regions, so it would work fine, I only had to get the polygon data out of the Illustrator file into the HTML markup.

The map in Illustrator

The first attempt was using a site where you can upload an image, and draw your polygon manually. Obviously the polygons would be coarse and not match the outlines of the provinces very well, as you have to manually click each point of the polygon on a small image. After an accidental refresh of the page, losing all my polygons for practically the entire map, this approach of creating the image map was switfly abandoned.

Luckily, Illustrator can provide us with the polygon data. Simply export the drawing as an svg file, which is just an xml file. This xml file contains <polygon> and <polyline> tags which we'll need to process. Let's take a look at a snippet of the polygon data.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "">
<svg version="1.1" xmlns="" xmlns:xlink="" x="0px" y="0px"
	 width="690.615px" height="302.64px" viewBox="0 0 690.615 302.64" enable-background="new 0 0 690.615 302.64"
<g id="Layer_1">
	<polygon fill="#F3E969" points="342.887,230.002 351.096,231.173 355.201,224.138 351.683,220.035 355.201,212.412 361.65,214.17 
		368.687,207.134 366.928,204.789 370.445,203.031 371.619,199.677 369.977,200.029 369.391,196.511 365.286,200.615 
		361.182,198.857 360.009,196.511 360.596,191.82 360.009,185.371 357.077,179.507 364.113,173.057 373.494,174.816 
		378.186,171.884 386.395,168.953 385.863,160.987 385.222,151.362 383.376,152.237 374.081,156.64 368.217,156.053 
		362.941,159.571 360.596,164.848 351.8,169.54 350.627,177.162 336.555,177.748 323.655,186.543 309.583,186.543 297.856,194.166 
		293.751,192.408 294.338,183.612 279.093,192.408 273.229,197.097 267.953,196.511 262.675,199.443 261.502,197.097 
		256.812,196.511 256.812,201.789 252.707,200.029 246.844,200.615 240.394,205.306 239.808,202.96 231.013,201.203 
		219.164,201.696 220.458,207.652 214.595,215.275 217.527,217.033 212.249,220.551 214.009,224.07 219.872,224.07 219.286,229.933 
		215.181,229.933 213.422,237.555 216.354,239.901 221.868,236.684 232.068,226.484 236.172,224.725 239.104,227.656 
		245.554,230.002 247.312,227.071 254.349,233.521 255.522,238.21 261.972,237.039 275.458,237.625 281.321,234.107 287.771,239.97 
		290.703,235.866 294.221,237.625 297.152,237.625 301.257,235.866 305.361,234.107 307.707,247.592 310.052,248.179 
		321.193,235.279 325.883,235.279 332.333,237.039 338.197,239.97 343.474,236.452 	"/>
	<polyline fill="#FFFFFF" points="413.248,262.25 412.076,255.215 405.627,250.524 407.385,242.902 403.281,239.384 
		400.936,237.039 395.072,239.97 388.037,238.797 381.586,242.902 378.654,247.005 377.615,246.709 378.068,251.697 378.654,257.56 
		372.205,259.32 372.205,262.838 368.687,264.597 376.895,268.115 382.76,266.356 383.345,273.392 389.209,275.737 398.004,280.428 
		402.107,278.082 410.904,274.565 417.354,271.046 408.559,267.529 413.248,262.25 	"/>

There is a slight manipulation we have to perform. The points attributes above do indeed contain the polygon data, but the formatting differs a little from what is necessary for an HTML <area> element. In the SVG the x,y coordinates are separated by a comma, and there is a space between coordinate-groups, whereas in an HTML <area> element it's just a string of comma separated coordinates (x,y,x,y,x,y,…)

A small Python script can take care of that quite easily, as it would be too much work to manually convert all the formatting for the points arrays. Even if you'd entered the comma's manually and extracted the points out of the SVG file, another problem would pop up: the coordinates seemed to be offset on both the x and y axis ! This is particularly strange, seeing as in the SVG file, at the top, you can see that the viewbox and x and y offsets are zero. You would assume the zero origin would be the same in the HTML <area> element, but apparently there is a difference. Instead of spending hours figuring out where the difference comes from, we can easily add an offset in the Python script when parsing the points.

We'll start the Python script with importing the xml minidom module, and defining our offsets.

#!/usr/bin/env python
from xml.dom.minidom import parse
offsetX = -48
offsetY = -54

Now we'll parse the SVG file. In this example I only take a look at the first <g> element, which is actually the first layer in Illustrator. Make sure you keep the Illustrator file as simple as possible, in a single layer. This will keep the SVG file much cleaner. Next, all the child nodes of the <g> elements are processed, and we store the points attributes of the <polygon> and <polyline> elements away in the inputs array.

inputs = []
dom = parse("chart.svg")
group = dom.documentElement.getElementsByTagName('g')[0]
for child in group.childNodes:
	if child.nodeName == 'polygon' or child.nodeName == 'polyline':
		if child.hasAttribute('points'):

Finally, we'll loop over the inputs array containing all the points data. To get all individual coordinate pairs we'll split the string on every space, and to get to the x and y value of a coordinate, we split on the comma. Now that we have the x and y values we can add the offsets. All that is left is outputting the correct HTML <area> string, joining all the coordinates with a comma.

for input in inputs:
	outputarr = []
	components = input.split(" ")
	for component in components:
		xy = component.split(",")
		if len(xy) == 2:
			x = int(float(xy[0])) + offsetX
			y = int(float(xy[1])) + offsetY
			outputarr.append(str(x) + "," + str(y))
	print '<area shape="poly" coords="' + ",".join(outputarr) + '" href="#" alt="" title="" />'

What about the offset numbers? They seem quite arbitrary, and in fact they are. Determining the exact values can be somewhat difficult, because you can't see the polygon areas over your image when you're testing it out. There is however a nice jQuery plugin that allows you to outline the polygons: jQuery MapHighlight. With the aid of this plugin you can let Python process the SVG file, look at the HTML and see how much the polygons are shifted, so you can adjust appropriately.

A part of the processed map, with the maphighlight plugin