A few days ago I started playing with Polymaps and TileStache, two very promising WebGIS building tools.
The final goal of this experiments was the integration with Django.
Polymaps
Polymaps is a Javascript library aimed to display svg maps in a web page, recently I’ve watched to an interesting talk about a Django-powered app built on top of Polymaps:
The main reason to give Polymaps a try is the interesting support to tiled vector layers, as far as I know a unique feature.
I’ve found the documentation of Polymaps a bit obscure and still incomplete (I just hope it isn’t another facade Open Source product where the lack of documentation and community support limits the use to commercial projects).
A quick look in the code shows no comments and rather obscure variable names, debbugging this library would certainly be a nightmare if you’re not the author, if you compare the source code with OpenLayers’s code you get the idea.
BTW I managed to make it work in a few hours (with all the server stuff).
TileStache
TileStache is a python library aimed to build, cache and manage map tiles. It’s similar to TileCache in scope and uses the well known Mapnik renderer while the data provider is implemented with shapely and OGR and can read the most widely used formats (postgis, shapefile, geojson).
TileStache is the ideal companion to Polymaps because it can handle and cache vector tiles (geojson) through the Vector class (don’t even try to use the PostgreSQL class you can find in Goodies, it’s kind of unofficially deprecated and it will let you waste your time).
I had to fork the project on github and made a pull request to fix the missing “port” parameter to the DB connection since I’m using a not-standard port.
SVG CSS
I admit I am a true beginner with SVG and while I was trying to experiment with the stylist features of Polymaps I discovered some counter-intuitive (at least for me, coming from XHTML CSS) behaviours:
You can define styles in three ways:
- CSS rules
- “style” attribute of the SVG element
- individual attributes (“stroke”, “fill” etc. etc.) of the SVG element
Strange enough, the priority is top-down, while I would have expected that point 3 had a higher priority.
Another thing worths noting is that what distinguish a polygon from a linestring in the Polymaps generated “path” SVG element is just that the “d” element (which contains the geometry) ends with a “Z”.
This is a linestring:
<path d="M101.99999715555555,189.9999971369224
L75.00000142222234,219.00000190473258
L75.00000142222234,242.49999834108655
L94.49999928888906,242.99999806558844
L102.49999928888906,255.4999976705726
L101.99970702222231,256"/>;
This is a polygon:
<path d="M95.07080533333351,256.00000052462633
L0,196.67516186124612
L0,192.0000022835775
L0,128.0000001888236L0,70.92093168072711
L175.92470186666674,0.000006325172648757871
L192,0.000006325172648757871
L256,0.000006325172648757871
L256,64.00000444302805
L256,128.0000001888236
L256,160.99230434784874
L113.66593991111131,256.00000052462633Z"/>;
Styling the plygon fill without hitting linestring in a GEOMETRYCOLLECTION layer turned out to be quite troublesome.
I ended up with a CSS-3 attribute CSS rule:
.layer path {
fill: cyan;
fill-opacity: .85;
stroke: #012;
stroke-linecap: round;
}
.layer circle {
fill: cyan;
fill-opacity: .85;
stroke: #012;
}
/* Don't fill in SVG */
.layer path:not([d$="Z"]){
fill: none;
stroke-width: 3px;
}
I wonder if there is a better way…
This story continues with: TileStache Django tiny wrapper.
Erik Dahlström
Interesting choice by Polymaps about the polygons and linestrings, I’d assume it’s to make it easier to do calculations on the data. SVG has a polygon element which could have been used to distinguish the two. However, should you wish my guess is that its’s pretty simple to add a class to the elements that you want to reach quickly with stylerules. That should be more efficient than using the ‘.layer path:not([d$=”Z”])’ rule.
Michal Migurski
Great article, and thanks for the patch to Tilestache! I’ve merged it in, and will push it out with the next release.
Alessandro Pasotti
@Erik
thanks for your comments, I myself was wondering why they’are not using the full set of geometric SVG elements (Polygon, Line etc.) instead of only Path and Circle.
About adding a class, the root of all my problems is that I’m using a GEOMETRYCOLLECTION type in my PostGIS DB. This triggers a lot of problems, to say one: Django OSM admin doesn’t support collections and OpenLayers has a longstanding bug in WKT format reader/writer, but I’ll write more on these topics in another post.
BTW I tried to add a class using a stylist (http://polymaps.org/docs/stylist.html) bound to the “load” or “show” event. Unfortunately this approach revealed to be problematic because the stylist receives a GeometryCollection object and not the individual components, there is a bug in the library that removes child elements in the SVG element, removing child geometries in case of collections.
I’m still trying to debug that messy library, Polymaps source code is a good example of how Javascript code can be similar to old good i386 assembly 🙁
Alessandro Pasotti
@Michal
Thanks for the pull, it’s nice to know that TileStache is open to contributions (also when they’re so tiny 🙂 )
I’ve also forked and pulled a request to Polymaps, it (hopefully) fixes the bug in Stylist.title when dealing with geometry collections, let’s see if they also accept patches.
Paolo Corti
Alessandro, this is definitely very interesting post 😉
Alessandro Pasotti
@Paolo
thanks Paolo, I’m happy to see how our “virtual life path” crosses again!