Creating an image map from SVG

I was asked how I made the map in my examples earlier.

I wrote a small script to do it. (The script is quite limited – I only made it complete enough to handle the SVG files I was using. Others might break it. Also, it requires pyparsing… and hoo-boy is that slow.)

Example!

Wikipedia is good for this, and has provided me with the example file I’ll use, a map of the USA. If you have some GIS data already, I believe that ArcGIS 9.2 has native SVG support, or it looks like you can convert ESRI shapefiles with shp2svg.

My example file is filled with all sort of crud that isn’t a definition of state boundaries, though, so I need to get just that. Perusing it (in a text editor or a SVG editor like Inkscape) reveals that all the state borders are in a group named “States”. Helpful!

So I run my script: svg2imagemap.py Map_of_USA_with_state_names.svg 960 593 States

(The “960 593” is the size of the image I’m creating from the SVG file.)

This creates an html file named [svg name].html, so Map_of_USA_with_state_names.html. It only contains the area tags, so I dump them into an image map in a page set up like the one in the other examples…

And we get: A map of the USA.

Just to disclaim again: That script is unlikely to be immediately useful for any particular SVG image. You would almost certainly need to tweak it significantly to make it work for your purposes. But it’s a good start, at least.

One last time: I make no guarantee of this script working on an arbitrary SVG file. At best it’s an example of an approach to take. If you use it, expect to have to debug how it interacts with your particular file.

maphilight: image map mouseover highlighting

UPDATE 2011-05-04: Version 1.3 released. Works in IE9. (There’s a pattern here.)

UPDATE 2010-05-22: Version 1.2 released. Works in IE8.

I just released maphilight, a jQuery plugin that turns image maps into wonderful graphical masterpieces.

Image maps aren’t so popular any more, for some strange reason. So a quick definition: an imagemap is an <img> with the usemap attribute, pointing to a <map> that describes polygons that link places within that image.

This sprung from me wanting to display pretty highlighting of countries on a map, but not wanting to mess with flash for it. It involves enough annoying fiddling with <canvas> (and VML, because IE is in the stone age) that I feel I’m saving other people a decent amount of work by releasing it.

Simple demo
Pretty demo using a world map
Documentation
Download (requires jQuery)

(Tools like “HTML-Image map Creator WYSIWYG” might be handy if you want to make image maps yourself.)

Fixing sortForce in jQuery’s tablesorter

jQuery has a table-sorting plugin, part of their official UI project. It’s quite a nice table-sorting library, handling the common cases, with options making it configurable to suit many people’s needs.

However, I ran into a problem when using it in a project. The documentation and the functionality don’t quite line up.

It has an option, sortForce, which its documentation says you can use to “add an additional forced sort that will be appended to the dynamic selections by the user”. This is a handy concept – it lets you, say, keep records ordered by name, regardless of which other criteria the user chooses to sort by.

The problem is that it actually prepends the sort to the user’s selection, which means that the user is restricted to sorting within the forced sort. (This is also a potentially useful tool; it’s just not what the documentation indicates.)

So I wrote up a patch that fixes this, along with a few other niggling issues with sortForce. (Its interaction with the user sorting by multiple columns, and it locking the forced-sort column in one sort direction.) To preserve backwards-compatibility I added a new option, sortAppend, to provide the documented behavior.

I also submitted the patch to the maintainer, so hopefully it can get incorporated.

2008-08-27: My patch was incorporated as of version 2.0.2, so it’s all good.
2009-03-17: But bits of it weren’t applied, so it can’t be said to have been fixed. Oh well. I’ll resubmit.

Practicing JavaScript with Dilbert

I discovered that there was a flash widget displaying Dilbert archives in color, back to the start of 2007.

Naturally I thought to myself “aha, there must be an XML data feed somewhere in that!” Some light flash-decompilation later, I discovered that I was right.

I then seized on this as a learning opportunity, and wrote a much better viewer, in boring old JavaScript. Why is it better? Because it doesn’t require Flash, and is not limited to one panel at a time, that’s why.

My Dilbert viewer, can you view it?

Caveats:
1. It’s perfect in Firefox3 and Safari. Sundays aren’t quite right in IE7; the first and last buttons are missing in Opera. All else is untested.
2. For some reason, the widget seems to get different feeds for the last week or two, which means this viewer is a week behind. I suspect user-agent sniffing, but have not yet been motivated to work out what a flash-player’s user-agent is.

Things learned:
1. Cross-domain xmlhttprequest requiring a proxy is a pain, and has no obvious benefit.
2. jQuery is still awesome.
3. Forgetting to take out debug statements that rely on FireBug when uploading is dumb of me.
4. Decompiling these things is complex – the embed code provided loads a .swf, which loads a .swf, which finally loads the actual widget that displays the comics.

Update: I worked out the cause of the weird out-of-sync-ness I observed between the data files I received and the content seen in the official widget. The lesson is not to trust the data feed when it tries to tell you which domain to look at; it includes a tag, which seems like a perfect complement to the domain-less URLs given in the strip descriptions. However, that domain contains files that are several weeks out of date. So I just hardcoded the “real” URL.

They finally released this stuff to the main Dilbert site, so I just went through and fixed up the viewer to use the appropriate new feed format. Darn changes.

Three gigabytes free…ish

WordPress.com announced yesterday that all users get three gigabytes of upload space for free. This is a teensy upgrade from 50MB.

This seems to be primarily for psychological reasons, because there’s a big fat * after the upgrade.

The footnote is that Mr. Mullenweg mentions in this post that “[y]ou still need a space upgrade to upload certain file types, like movies”, and later in the comments that “[y]ou still need a space upgrade to be able to upload MP3s”. So you still have to pay them if you plan to do anything significant with their bandwidth. (Not sure where they stand on humongous zip files, or similar.)

Not that this is wrong of them. It rings a bit of being an arbitrarily large number chosen for PR reasons, but that’s understandable.

The 3 gig limit is very reassuring to an important segment of the blogoratispheroidalmass. Specifically, the people without their own hosting, who want to be able to post their photos on their blog and not worry about having to trim out old ones after a few months.

50MB = 300-500 decent quality JPEGs of photos. It’s easy to imagine that being a problem after a short while. 3 gigs… not so much.

Why I can’t play Dungeon Runners

Last night I thought to myself “hey, I know, I’ll try out Dungeon Runners!” It’s a pseudo-free pseudo-MMO, which could be described as a Diablo parody – that’s the sort of game that sounds appealing to me.

Sadly, I discovered that Dungeon Runners is not a game I can play.

You see, it requires that inbound port 80 be open for your initial connection to a world server. This is a mind-bogglingly weird decision.

Port 80 is an entrenched-by-standards ports – it’s what webservers listen on.

Thus Dungeon Runners is off-limits to two classes of people:

  1. People whose ISP block port 80 inbound, because they really don’t want people running servers. (Verizon did this for a while on my connection.)
  2. People who run a server. (That’s me.)

Okay, I could shuffle ports around, temporarily assigning 80 to my games computer whenever I wanted to log in. But that’s more effort than I want to put into this. Thus I effectively cannot play Dungeon Runners.

How to generate PDFs from XML using Apache FOP in Ruby on Rails

The title is a bit of a mouthful. Sorry.

Before we begin, I present the caveat that this code should not be used on a production system. It launches a java runtime for every single request, which would cripple you. This would need (a) output caching, and (b) some sort of persistent FOP server process before it could be considered usable.

But if you just need to generate PDFs on an intranet app, say, then this could be handy.

Step 1: Put FOP somewhere it can be found. Specifically, its “build” and “lib” folders. I created a “fop” directory in my project, and stuck everything in there. (I don’t promise that this is ideologically sound — I’m new to the whole Rails thing.)

Step 2: Add Mime::Type.register "application/pdf", :pdf to config/initializers/mime_types.rb (this gleaned from Dynamic Graphics with Rails 1.2).

Step 3: Use a controller action something like this:

# GET /documents/1
# GET /documents/1.xml
# GET /documents/1.pdf
def show
  @document = Document.find(params[:id])

  respond_to do |format|
    format.html # show.html.erb
    format.xml { render :xml => @document }
    format.pdf do
      # We generate the classpath by scanning the FOP lib directory
      command = "java -cp #{Dir.getwd}/fop/build/fop.jar"
      Dir.foreach("fop/lib") do |file|
        command << ":#{Dir.getwd}/fop/lib/#{file}" if (file.match(/.jar/))
      end
      command << " org.apache.fop.cli.Main "
      command << " -xml #{Dir.getwd}/fop/xml/#{@document.file}"
      command << " -xsl #{Dir.getwd}/fop/xslt/doc2fo.xsl"
      command << " -pdf #{Dir.getwd}/fop/tmp/#{@document.id}.pdf"
      if(Kernel.system command) then
          send_file "#{Dir.getwd}/fop/tmp/#{@document.id}.pdf",
            :type => "application/pdf"
      else
          render :text => command
      end
    end
  end
end

Then whenever someone asks for “documents/17.pdf” it’ll make a PDF and serve it right on up. In the event that something goes wrong it’ll just display the command it ran, for some rough-and-ready debugging.

For a proof-of-concept you could try this with the example XML and XSLT that comes with FOP. Look for “projectteam2fo.xsl” in the examples directory.

As I said above, this works, but should not be put anywhere near a publicly accessible site.

Thoughts on Ruby on Rails after one day of work

I started looking at Rails (leading to my talking about scaffolding) because I wanted to try writing my next work-project in it.

I don’t know about others… but I hate learning a language/framework in isolation from a project. Writing an insipid tutorial project that I don’t care about doesn’t involve me, and so I don’t learn as well. Also, the applications written alongside tutorials tend to be very carefully chosen to hit all the good parts of a framework, while ignoring the rough spots. Thus I’ve historically viewed “prototyping my next project” as a great time to pick up something new.

So. I started Rails tutorials on Friday, didn’t touch it at all over the weekend, and by mid-morning on Monday I had my proof-of-concept app. I’m storing legal documents described in XML, allowing people to fill in some defined fields on them, then generating custom PDFs/RTFs/PNGs/whatevers using Apache FOP. (That sounds more complex than it is. I’ll post an example later.)

Rails itself is being reasonably unobtrusive, which I approve of. I had to do minor research into how to set up custom mime types for response formats, but it turned out to be quite simple.