Friday, June 15, 2012

About "about:about"

I just learned about "about:about", which (in current versions of Firefox and Chrome, at least) gives you a menu of all the "about:" pages (which in Chrome are actually chrome:// pages).  How lovely!  Here's the blog post that mentioned it.

Tuesday, June 5, 2012

Cache OpenLayers Tiles With Web SQL Database

(Note: this post has been edited to reflect the current state of OpenLayers and my code.)

As of this edit, there's an open pull request to provide a pluggable offline cache system for OpenLayers.  A few months ago, there was only a single CacheRead/CacheWrite implementation using localstorage.  I needed Web SQL Database support because localstorage currently maxes out at 5MB on iOS (with ungraceful failures), whereas Web SQL Database will grow to 50MB with user confirmation.

ahocevar's pull request for the initial implementation indicated that adding backends for other databases would be as easy as providing a different implementation for OpenLayers.Control.CacheWrite.cache and OpenLayers.Control.CacheRead.fetch.  This is true...ish.  Because Web SQL Database is asynchronous (apparently no vendor ever implemented the synchronous API, at least on mobile), there are a lot of gotchas.  Rather than list them all here, I'll link again to my comment on the current pull request, where I note a few.

I got a public github account and committed some code before being asked for an OpenLayers Contributors License Agreement and learning that my university really has no process for approving things like that.  But since this blog post had already linked to my modified CacheWrite and CacheRead controls, I'm leaving the links live.  I've also committed my latest versions, which fix some bugs.  Feel free to use this code as a guide for OpenLayers caching code, but don't submit it verbatim to OpenLayers until I get a CLA.  Thanks!

Note that this code (and all OpenLayers caching code) is affected by an OpenLayers bug that allows slightly different URLs to be calculated for essentially the same tiles, leading to cache misses that should be hits.  Be my guest and fix this bug to make caching work more reliably!  (Read the issue comments to understand what the fix requires.)

Be aware that this code doesn't properly notify on "cachefull" situations.  At least on iOS, I found that there was no way to distinguish between a quota error and a unique constraint violation.  That is, inserts that fail due to exceeding the disk quota are reported as constraint violations.  I think this is a bug in Safari, but probably one that will never be fixed now that Web SQL Database is deprecated.

Happy coding!

Split OpenLayers Polygons with JSTS

Update: I've put several months of development into our app since this post was first published, with probably a couple weeks' extra work into the SplitPolygon tool.  Our tool is now production quality, but I won't post it here until I get word from our legal department on an OpenLayers CLA.  I'm leaving the old code up, but be warned that it's more like demo quality.  In particular, note that because this version doesn't split edges of "unaffected" polygons adjacent to affected polygons, split polygons may not merge cleanly back with their neighbors.  Also, because Mobile Safari likes to terminate long-running tasks without warning, I did significant rework to break tasks into the smallest pieces I could without modifying JSTS itself, and running the pieces on timers.  This was nice for other reasons, as it allowed me to display progress updates, etc.  Anyway, hopefully I'll get the real version posted... someday.

So I've got a half-baked SplitPolygon control for OpenLayers that's good enough for our use in a project here at work but not ready for submission back to OpenLayers (if they'd even accept a control with an external dependency), and I thought I should find some way to share it for others trying to do the same thing.  It seems like the typical route is one's personal "code blog."  So I made this lovely personal code blog, where I will share such thing(s).

Here's the SplitPolygon code.  It's just the OpenLayers Split Control, slightly mangled to handle polygons instead of polylines.  The Split control will technically handle any OpenLayers.Geometry with a "split" method, but as of OpenLayers 2.12, only polylines have this method.

It depends on the excellent JSTS, a JavaScript port of Martin Davis's JTS Topology Suite by the illustrious Björn Harrtell, who (through his employer, SWECO Position AB), for a very reasonable fee, ported the critical Polygonizer.  The logic in the considerSplit function is ripped from a desktop application we wrote for the USDA.

The tool works through the supplied layer and splits all eligible features with the provided polyline.  The polyline can be arbitrarily complex, with self-intersections and other goodness.   It can split a single polygon into several pieces.  I put some code in to limit the splits to visible features because that was a requirement for our app.

Because we're using it on touch devices, which can't use CTRL-Z and ESC for undo and cancel, it adds two links to the map (one for undo and one for cancel).

I commented out some code we weren't using, and I mostly ignored parts of it that I didn't understand.  So this might serve as a base for your own tool but probably shouldn't be taken as-is.

Hope this helps!