Thursday, June 21, 2012

This is gonna be three in a row where I complain about Leaflet. Honestly, I'm not being a jerk: my biggest project right now is based on Leaflet, so it's their turn to host the latest raves and rants. Don't get too annoyed: it's constructive criticism, and by September it'll probably be some other framework that gets the "how I figured this out despite the docs" and "what I had to fix today" posts.

SCALEBAR

Leaflet 3 lacks a scalebar control. This is really too bad: we're showing a map of parks, and people need to know whether that pavilion is 500 feet or 1.5 miles.

UPDATE: This is now posted to Leaflet https://github.com/CloudMade/Leaflet/issues/823
I would be interested to hear whether this is something worth improving; the current customer is happy with it as-is.

UPDATED UPDATE: Apparently this is now in the Master version of Leaflet 4. Hooray for the late adopters, too bad for us early adopters, eh?

WKT PARSER

Leaflet also lacks a parser to convert OCG Well Known Text (WKT) into a Marker, a Polyline, et cetera. I have written the beginnings of one. Again, being centric to this project its development is 100% driven by the needs of this project. At this time it only supports LINESTRING and MULTILINESTRING geometries, converting them to L.Polyline and L.MultiPolyline

Here's the program code thus far. As usual, use as your own risk, no warranty of your computer not catching fire, and so forth.

/*
 * parse Well Known Text (WKT) and return a PolyLine, MultiPolyline, et cetera
 * params:
 * - wkt, String WKT to be parsed
 * - options, object to be passed to the new feature as it is constructed, e.g. fillColor, strokeWidth
 * returns:
 * - an instance of a L.Path subclass, e.g. L.Polyline
 *
 * The supported options depends on the type of feature found   http://leaflet.cloudmade.com/reference.html#path
 */
L.WKTtoFeature = function (wkt,options) {
    // really, this is a wrapper to the WKTtoFeature.parse* functions
    wkt = wkt.replace(/^\s*/g,'').replace(/\s*$/,'');
    if (wkt.indexOf('LINESTRING') == 0)      return L.WKTtoFeature.parseLinestring(wkt,options);
    if (wkt.indexOf('MULTILINESTRING') == 0) return L.WKTtoFeature.parseMultiLinestring(wkt,options);
};


L.WKTtoFeature.parseLinestring = function (wkt,options) {
    // split on , to get vertices. handle possible spaces after commas
    var verts = wkt.replace(/^LINESTRING\s*\(/, '').replace(/\)$/, '').split(/,\s*/);

    // collect vertices into a line
    var line = [];
    for (var vi=0, vl=verts.length; vi<vl; vi++) {
        var lng = parseFloat( verts[vi].split(" ")[0] );
        var lat = parseFloat( verts[vi].split(" ")[1] );
        line[line.length] = new L.LatLng(lat,lng);
    }

    // all set, return the Polyline with the user-supplied options/style
    var feature = new L.Polyline(line, options);
    return feature;
}


L.WKTtoFeature.parseMultiLinestring = function (wkt,options) {
    // some text fixes
    wkt = wkt.replace(/^MULTILINESTRING\s*\(\(/, '').replace(/\)\)$/, '');

    // split by () content to get linestrings, split linestrings by commas to get vertices
    var multiline = [];
    var getLineStrings = /\((.+?)\)/g;
    var getVerts = /,\s*/g;
    while (lsmatch = getLineStrings.exec(wkt)) {
        var line = [];
        var verts = lsmatch[1].split(getVerts);
        for (var i=0; i<verts.length; i++) {
            var lng = parseFloat( verts[i].split(" ")[0] );
            var lat = parseFloat( verts[i].split(" ")[1] );
            line[line.length] = new L.LatLng(lat,lng);
        }
        multiline[multiline.length] = line;
    }

    // all set, return the MultiPolyline with the user-supplied options/style
    var feature = new L.MultiPolyline(multiline, options);
    return feature;
}

No comments:

Post a Comment