[mapguide-internals] CSS sprited legend images - RFC

Zac Spitzer zac.spitzer at gmail.com
Sun May 22 02:12:49 EDT 2011

Jackie and I have been working on this, we have extended LoadScaleRanges.php
to include the legend icon images as base64 data encoded urls. the
images are usually
130 odd bytes in size so the base64 encoded version is still small enough not to
matter much.

It works well, reducing the server load and allowing for speeding the
load time for
complex maps. The load time performance of one extremely complex map was
reduced by half, only IE7 / IE6 don't support this. IE8 works ok, taking 40s
to completely load this map gracefully, FF4/Chrome can load the same map in 16s.

But the crux of the problem is still the sheer number of
GETLEGENDIMAGE api requests.
Even doing this via the API is too slow, we have been limiting loading all the
legend images for every scale, leaving some images still to use the
original web tier urls.

I would like to propose a new GETLEGENDIMAGES API call which generates
every legend
image for a given layer, returning them in a json structure, base64
encoded, similar to what we
are returning from LoadScaleRanges.

Ideally, the logic from fusion's LoadMap.php and LoadScaleRanges.php
could be moved into
the server api, which would eliminate all the calls to read and parse
the layer definitions
from the server into the webtier, eliminating a lot of tcp/ip overhead.


On Wed, Jan 12, 2011 at 12:26 AM, Paul Spencer <pspencer at dmsolutions.ca> wrote:
> I don't think legend performance is strictly an issue of legend images since the tree implementation via Jx or Fusion's use of it is also likely to cause problems when dealing with large numbers of layers.  I thought we had done some work to improve that in the latest version of Jx and Fusion but that may not be in the regular distributions yet.   Mike can say better where that stuff is in the queue.
> On the sprited image thing, there are actually two pieces to legend icons on the mapserver side that are somewhat relevant.
> 1) fusion/Layers/MapServer/php/LegendIcon.php
> this is the non-sprited case for mapserver layers, they call this php script as the src for the legend icon image.  If you take a look, you'll see that we went to some effort to cache legend icons and provide cache control headers for browsers to improve performance on *subsequent* visits - meaning that the initial load for a new client or after a change to the map file is still heavy and only improves with  reloads or with new clients connecting (getting the disk-cached copy vs having to build it).
> It appears that for mapguide we use the GETLEGENDIMAGE operation.  I'm not sure what the internals of this operation do, I suspect they cache per session/mapdefinition but perhaps they cache across sessions?
> 2) fusion/Layers/MapServer/php/LoadScaleRanges.php
> The primary purpose of this file is to build a JSON object representing the layers and scale breaks to guide the legend's behaviour as the user zooms and pans.  However, around line 164 we have added code to build a sprited image of legend icons and the associated offsets.  Of note, the output JSON includes
> * a layers array that has, for each layer, a set of scale ranges and for each scale range, icon_x and icon_y offsets inside the sprited image
> * an icons_url property that points to where the sprited image can be loaded from
> * icons_width and icons_height properties giving the size of an individual icon.
> I believe that if the result of LoadScaleRanges.php includes these things (icon_x and icon_y per style and icons_url) then Legend.js will generically just work with the sprited image.
> For mapguide, there is a LoadScaleRanges.php file but it just returns something from the php session, the real work actually happens over in LoadMap.php specifically in the buildScaleRanges function.  This is where modifications would be needed to indicate support for sprited legend images by including icon_x and icon_y properties in each styleObj that gets saved.
> Also in LoadScaleRanges.php, the returned JSON could need to be modified to include the icons_url, icons_width and icons_height properties.
> So I guess there would need to be some method or function in mapguide that would iterate over all the layers in a Map and over each of the scale ranges and build a sprited image and also return the offset (x and y) of each.
> Note that the current design of this only supports icons that all have the same size.  If we ever needed to support different sized icons for different layers/scale ranges then it would require quite a large overall not only of the backend but also the tree code.
> Also note that the generic code should work for dynamically added layers as the fallback would be to use the GETLEGENDIMAGE operation for layers that don't have the icon_x and icon_y properties.
> There may also be some piece of magic required in MapGuide.js to make this work.  I can't see anything in MapServer.js that indicates this, it should just work if the correct metadata is provided in the return from LoadScaleRanges.php - but I've thought that before :)  If someone can get to the point where MapGuide's LoadScaleRanges.php returns the correct metadata and it doesn't Just Work (tm) then it shouldn't be too difficult to get it working.
> I hope this helps get things in perspective.  It wasn't that hard to make it work for MapServer but the php api is a lot simpler ... mapguide was, IIRC, somewhat opaque on the whole legend icon thing.  The logic could perhaps be ported almost directly if there was a method on a layer to generate a legend icon at a given size for a given scale but that wasn't there when I worked on this.  Oh and there is also the problem of compositing the images together into a single strip.  We (ab)used mapserver's image methods for this so we didn't need to save them to disk in order to use the GD api.  Not sure where things stand with mapguide and an api for manipulating images in this way.
> Cheers
> Paul
> On 2011-01-11, at 7:23 AM, Zac Spitzer wrote:
>> this post got a bit lost in discussion,
>> the ajax viewer performs better because it only renders a subset of
>> large legends,
>> abbreviating them [ .... ] fusion tries to render them all and ends up
>> DOSing the browser
>> CSS sprites for the legend is sorely needed
>> What's the technical requirements?
>> GetLegendImageStrip
>> GetLegendCSS
>> Proper http cache semantics for those operations
>> cached in the session repo? generated when requested,
>> cache invalidated after changes to the run time map,
>> but only after re-rendering and comparison of new and old
>> has changes
>> z
>> ---------- Forwarded message ----------
>> From: Jason Birch <Jason.Birch at nanaimo.ca>
>> Date: Sat, Apr 4, 2009 at 9:03 AM
>> Subject: [fusion-dev] RE: [mapguide-users] Fusion and Themed Layers - usability
>> To: "mapguide-users at lists.osgeo.org" <mapguide-users at lists.osgeo.org>
>> Cc: "fusion-dev at lists.osgeo.org" <fusion-dev at lists.osgeo.org>,
>> 'MapGuide at lists.osgeo.org, Internals Mail List'
>> <mapguide-internals at lists.osgeo.org>
>> Heh,
>> Yeah, I can see how that would be unmanageable.  I wouldn't be
>> surprised if your use case strains fusion to the level that it's not
>> workable for the current version or for 2.1.  I'm surprised it works
>> with the AJAX viewer, but maybe the viewer has a different strategy
>> for managing legend images.
>> Ideally, MapGuide would support a GetLegendImageStrip operation that
>> Fusion could then use with CSS sprites to reduce (in your case,
>> dramatically) the number of requests to the server.  I believe that
>> there may be functionality for this in MapServer layer types in Fusion
>> 2.0, but I don't think there is in MapGuide.  Bob Bray put in a ticket
>> for this functionality a _long_ time ago, but unfortunately I don't
>> think any work has been done on it:
>> http://trac.osgeo.org/mapguide/ticket/22
>> I think that there is a partial measure that could be done in Fusion
>> to improve the situation somewhat.  Currently, Fusion does a
>> reasonable job of caching images; it only requests a new legend image
>> once per scale range context switch.  However, the initial request is
>> done using the exact current scale.  If the request instead used a
>> fixed value within the scale range (bottom + x?) then the images could
>> be better cached by the browser.  If MapGuide sent cache headers (last
>> modified, based on the layer definition?) this would also help.
>> Any Fusion or MapGuide devs have thoughts on this?
>> Jason
>> _______________________________________________
>> mapguide-users mailing list
>> mapguide-users at lists.osgeo.org
>> http://lists.osgeo.org/mailman/listinfo/mapguide-users
>> _______________________________________________
>> fusion-dev mailing list
>> fusion-dev at lists.osgeo.org
>> http://lists.osgeo.org/mailman/listinfo/fusion-dev
>> --
>> Zac Spitzer
>> Solution Architect / Director
>> Ennoble Consultancy Australia
>> http://www.ennoble.com.au
>> http://zacster.blogspot.com
>> +61 405 847 168
>> _______________________________________________
>> mapguide-internals mailing list
>> mapguide-internals at lists.osgeo.org
>> http://lists.osgeo.org/mailman/listinfo/mapguide-internals
> __________________________________________
>   Paul Spencer
>   Chief Technology Officer
>   DM Solutions Group Inc
>   http://research.dmsolutions.ca/
> _______________________________________________
> mapguide-internals mailing list
> mapguide-internals at lists.osgeo.org
> http://lists.osgeo.org/mailman/listinfo/mapguide-internals

Zac Spitzer
Solution Architect / Director
Ennoble Consultancy Australia
+61 405 847 168

More information about the mapguide-internals mailing list