Monday 26 August 2013

MapGuide 2.6 feature showcase: New code samples

If you're uncertain how the new CREATERUNTIMEMAP and QUERYMAPFEATURES can help you, then have no fear: For 2.6, we've bundled a whole bunch of new code samples to show you how using everyone's favourite web mapping library: OpenLayers.

When you install the 2.6 preview release, make sure that the OpenLayers Samples feature is enabled.



After installation, load in the Sheboygan sample package using Maestro or the MapGuide Site Administrator and then go to the new samples landing page link on the start menu.



To simplify the installer, all the code samples have been aggregated into this single landing page. Just be aware that some of these links might be broken if you didn't choose to install the respective samples from the installer.

If you look at the bottom of the page you'll see a whole bunch of new samples demonstrating OpenLayers integration with MapGuide. The key thing to note with all these new samples is that none of them involve any .net/Java/PHP code using the MapGuide API. They are all pure client-side HTML/JavaScript communicating with the mapagent.


Have a play around and you may be surprised what you can do with just OpenLayers and jQuery in MapGuide 2.6. Note that mixed map and the Google/OSM examples won't work out of the box.


This is because these samples work with a Map Definition that is not part of the Sheboygan dataset. You can find the required Map Definition XML document in the directory where the sample is actually physically located


Load this document into the specified resource id via Maestro or the mapagent test pages. Reload the sample page and it should now work.


These samples aren't set in stone yet. We could probably automate/simplify this process of setting up example data files somehow.

Nevertheless, hopefully these new samples give you some ideas and/or inspiration.

MapGuide 2.6 feature showcase: QUERYMAPFEATURES improved

For this post, I will be talking about another useful enhancement to the mapagent: An improved QUERYMAPFEATURES operation.

To understand the motivation for this. Open up your Firebug or Chrome DevTools on the AJAX/Fusion viewer of your current stable/production installation of MapGuide/AIMS and make a selection on the map.

You probably see something like this for the AJAX viewer


And for Fusion, you probably see something even noisier


From a performance standpoint, firing off 3 and 5 requests respectively for a single selection smells of inefficiency. What is the actual root cause of such inefficiency? The answer is simply: QUERYMAPFEATURES

In its current form, the QUERYMAPFEATURES operation in the mapagent is simply inadequate for fulfilling the needs of our current suite of client-side map viewers.
  1. Select and give me back attributes of all the selected features? Not possible. That's why the AJAX viewer before RFC 71 could only show a number of selected features. Though RFC 71 introduced a getselectedfeatures.[php/jsp/aspx] to fetch this attribute information, it still needed an additional request to do it. It's also why Fusion has to make several extra requests through various PHP backend scripts to get this information.
  2. When you make a selection, the viewer then has to make an additional GETDYNAMICMAPOVERLAYIMAGE to retrieve the selection image.
  3. QUERYMAPFEATURES is also used for tooltip requests, but the response carries extra unnecessary baggage like selected feature attributes.
For 2.6, we introduce a more powerful and flexible QUERYMAPFEATURES operation that can handle all of the above scenarios, being an efficient one-stop shop for all viewer selection/tooltip needs. We can achieve this by using the same technique as the new CREATERUNTIMEMAP operation: The client application requests the pieces of information they are interested in, and the QUERYMAPFEATURES operation returns the appropriate information in the response.
  1. The application can fire off a QUERYMAPFEATURES request to include attributes of all selected features. This avoids the need for a request to getselectedfeatures.[php/jsp/aspx] in the AJAX Viewer (in fact, the introduction of this operation has rendered getselectedfeatures.[php/jsp/aspx] obsolete). In Fusion this avoids the need to call into the various PHP scripts for the same information
  2. The application can also request an inline base64 selection image as part of the QUERYMAPFEATURES response. Through the magic of data URIs, the AJAX viewer can directly set the selection image without needing to fire off an additional GETDYNAMICOVERLAYIMAGE request. However, for Fusion it still needs to do this because the OpenLayers.Layer.MapGuide instance doesn't support plugging in base64 selection images directly yet.
  3. The application can fire off a QUERYMAPFEATURES request and only ask for tooltip/hyperlink information.
All the above cases demonstrate the capabilities of the new QUERYMAPFEATURES operation:
  • Attributes of all selected features are included (if requested). AJAX viewer no longer needs getselectedfeatures.[php/jsp/aspx]. Fusion no longer needs to call the various PHP scripts to assemble this information.
  • Inline selection images are included (if requested) as data URIs. No need for an additional GETDYNAMICMAPOVERLAYIMAGE request for the selection image.
  • You only get what you ask for. No extra unnecessary information traveling down the wire.
So how does the request chatter look like with this new operation in place?

Here's the new request chain for the AJAX viewer. A single request to the enhanced QUERYMAPFEATURES operation asking for the kitchen sink. No need for an additional GETDYNAMICOVERLAYIMAGE because QUERYMAPFEATURES includes an inline base64 image that the viewer can insert as a data URI. No need to call getselectedfeatures.[php/jsp/aspx] because the response contains the attributes of all selected features.


Here's the new request chain for the Fusion viewer. I suspect the SaveSelection.php request is somewhat redundant here because QUERYMAPFEATURES already supports modifying the selection set.


Combine this enhanced QUERYMAPFEATURES with the new CREATERUNTIMEMAP/DESCRIBERUNTIMEMAP that I already talked about and you have a powerful set of out-of-the-box functionality for building your own map viewer without needing any .net/PHP/Java assistance.

For more information about this new feature, you can have a look at the RFC that introduced it: RFC 126.

MapGuide 2.6 feature showcase: CREATERUNTIMEMAP and DESCRIBERUNTIMEMAP

For this post, I will be introducing one of my new favourite features of MapGuide Open Source 2.6 that I've been hinting in some previous posts.

2.6 introduces new operations in the mapagent to allow for creating new MgMap instances and describing key information about the MgMap such as their layer/group structure, map name, coordinate system, etc without the need to write any .net/Java/PHP web extensions glue code to do this:
  • CREATERUNTIMEMAP - To create a new MgMap instance and return information about this instance
  • DESCRIBERUNTIMEMAP - Returns information about a MgMap instance, given a map name and session ID.
Both operations return the same XML/JSON structure, except they take different input parameters:
  • CREATERUNTIMEMAP requires a Map Definition ID and a session ID or MapGuide user credentials
  • DESCRIBERUNTIMEMAP requires a Map Name and a session ID
The motivation for implementing this feature was looking at the MapGuide example for OpenLayers. It was clear that to consume MapGuide from OpenLayers, key information that we needed to make a OpenLayers.Layer.MapGuide instance was missing from the mapagent, and to fill in this information you needed to write a glue layer in .net/Java/PHP that can tap into the MapGuide API to return this missing information.

Fusion which uses OpenLayers can get away with this because it calls into PHP code to bootstrap the application with the required information. However, if you were making a pure OpenLayers application, this was not possible. CREATERUNTIMEMAP/DESCRIBERUNTIMEMAP addresses this shortcoming.

These operations are made to be scalable depending on the needs of the client application.

You could ask for the bare-minimal information, which will give a response like this: This minimal response is enough to run the MapGuide example for OpenLayers without any assistance from .net/Java/PHP web tier glue code.

Or you could request the whole kitchen sink, which will return a response like this (useful if you wanted to build your own client-side map legend / layer toggling component):
Both operations also support JSON output, albeit with the same quirk that affects other JSON responses in the mapagent where all JSON properties a generally arrays (because the XML to JSON conversion code has no current way to infer cardinality of elements to be converted)

This new feature not only allows for new client application possibilities, Fusion has also been modified to take advantage of these new operations. Using CREATERUNTIMEMAP bypasses the request chain of LoadMap.php and LoadScaleRanges.php which returns the same information. Similarly, DESCRIBERUNTIMEMAP is used when a layer/group structure needs to be refreshed. Not only are less requests required as a result. the actual response payload and round-trip time is smaller and faster as well.

Here's a sample load time of the Sheboygan dataset in Fusion using the current LoadMap.php/LoadScaleRanges.php approach


Here's the same dataset loaded by Fusion using CREATERUNTIMEMAP


As you can see, not only does CREATERUNTIMEMAP gives smaller responses. The time/latency is also smaller as well. You'll be glad to know that as the map you're loading gets bigger, so do the size/time/latency savings. And the rub of all this? This is the first cut implementation. There are still unexplored caching opportunities on the server side that could make these response times even faster!

So even if you're not building your own custom map viewer, if you're using Fusion you should still see the benefits introduced with these new operations.

If you want to find out more about these new operations, check out the MapGuide RFCs:

MapGuide 2.6 feature showcase: New WebLayout

Here's the first of many posts, covering some of the new features in MapGuide Open Source 2.6.

For this release, we introduce a new version of the Web Layout schema.

With the AJAX viewer, we've seen a common pattern with regards to customizations:
  • Wanting to change the default selection color
  • Wanting to change the default image format
  • Wanting to add an application-specific javascript entry point function to their AJAX viewer
All these things currently possible, except:
  1. They require actual modifications to the AJAX viewer files
  2. These modifications are global and not application-specific
So for 2.6, we've introduced a new WebLayout schema that lets you plug this specific information directly into the WebLayout, avoiding the need to modify any AJAX viewer files.

The new WebLayout schema supports the following new features:
  • The ability to control the selection color
  • The ability to control the map/selection image formats
  • The ability to control the tolerance of point selections
  • The ability to call JavaScript code upon initialization of the viewer
Editor support doesn't currently exist in Maestro for this new version, so to use a 2.6 schema WebLayout currently requires editing XML by hand.

To turn an existing WebLayout into a 2.6, one you have to make the following changes.

Firstly, make the document use WebLayout-2.6.0.xsd as the XML schema


To change the selection color, include a SelectionColor element, containing the RGBA color string


To change the selection tolerance of point selections, include a PointSelectionBuffer element, specifying the tolerance in pixels


To change the map/selection image formats, include a MapImageFormat and/or SelectionImageFormat element respectively, specifying the desired image formats. Note that if you pick an image format that doesn't support transparency (ie. JPG), selections will obscure the map beneath it. MapGuide or the AJAX viewer will not do any kind of validation to prevent this.


Finally, to specify JavaScript code to execute upon viewer initialization, specify your JavaScript code in a StartupScript element.


The code you specify in the StartupScript element has the same scope as any Invoke Script command, thus any function from the AJAX Viewer API is available for you to use. Previously, you would've needed to do something like this to achieve the same effect. The StartupScript element eliminates the need for such code as it will only be called after all initialization is complete, avoiding the need to monitor for DOM readiness before calling your code as per the linked example.

One thing to note is that due to how XML schema validation works, if you specify any of these optional elements, you must specify them in the following order after the Map element:
  • EnablePingServer
  • SelectionColor
  • PointSelectionBuffer
  • MapImageFormat
  • SelectionImageFormat
  • StartupScript
We'll eventually add editor support in Maestro so you no longer have to worry about such details.

With these changes, customizing the AJAX viewer should be that much simpler.

Sunday 25 August 2013

Announcing: MapGuide Open Source 2.6 Preview

Want a sneak peek at what's new in 2.6?

Here's a preview release for you to try out. Windows-only, because the purpose of me putting out this release is to test and verify that the Windows Installer is all good for when we start the 2.6 release cycle proper.

In case the words "preview release" is foreign to you, this release is for testing purposes and not suitable for production use. You have been warned :)

Stay tuned for a series of posts detailing the new features of 2.6

Download

Friday 16 August 2013

New mg-desktop binaries

Since we've put out a new MapGuide Open Source release (and also because the mg-desktop build system rides off of the MapGuide one), here is a new release of mg-desktop to go along with it. This is a bug fix release with no new APIs or features. New NuGet packages of mg-desktop have also been uploaded.

Since Google Code has removed support for binary downloads, the mg-desktop site on Google Code ceases to be of any use to me. As a result, mg-desktop is now a full sub-project of MapGuide Open Source (like Maestro currently is) and everything from hereon in is now hosted at OSGeo. The Google Code site will stay as-is if you want to grab old releases, other than that I won't be touching that site ever again.

The new download page for mg-desktop is now at the mg-desktop portion of the MapGuide wiki here

Announcing: MapGuide Open Source 2.4.1 and 2.5.1

The next major version of MapGuide Open Source won't come until at least early next year, so in the meantime here's the 2.4.1 and 2.5.1 point releases to fill the gap.

There are some useful bug fixes in both releases that make this a strongly recommended upgrade from 2.4 and 2.5. The release notes contains all the details

2.4.1 will be the only point release in the 2.4 line. 2.5 on the other hand, we will probably see some more point releases down the road.

Thursday 15 August 2013

Maestro IronPython Console tips and tricks

Now that I've hopefully sold you on how awesome the new IronPython Console feature of Maestro 5.0 is, here's some tips and tricks I've discovered while building and playing around with this new feature.

dir()

The dir() function lets you list members of a given variable. Very useful for see what properties and methods are available.



help()

The help() function does one better and actually dumps out the full definition of any object variable and gives you any attached API documentation as well. IronPython will auto-include any .net XML documentation of any .net type we've exposed to the IronPython scripting engine. The Maestro installation includes XML documentation for the Maestro API and Host Application, so most of the classes/methods you would be working will have documentation on hand.



However, given the small screen real estate, the help() command is somewhat impractical if the object being inspected has a lot of properties and methods. In terms of practicality, it's much easier to have the Maestro API reference help file on hand, which is included with the Maestro SDK.

.net-isms

The code you're writing is Python, but the code is running on the .net CLR so inevitably there are .net-isms that don't cleanly translate 1:1 to Python. Here's a few to take note of.

The Maestro API makes use of a lot of extension methods in its classes. However by default, these methods aren't available in the IronPython Console


To make extension methods recognisable, you have to use the ImportExtensions method from the clr module and pass in the namespace where you want the extension methods pulled in.



If you're wondering how does one know which namespace to pull the extension methods from as a general rule most, if not all extension methods in the Maestro API will be defined at the same namespace level as the classes they're extending. Note that the auto-complete functionality (or the help() function) doesn't currently pick up extension methods after they're imported, so in such cases having the Maestro API reference on hand is quite useful.

Another .net-ism to be aware of is nullable types. Most resource classes will have some nullable properties to denote XML elements which may or may not be specified. Assigning null (None in Python) to a nullable property generally won't produce the expected result.


So how do we make nullable properties actually null? Well to answer this question, lets take a step back.

As explained in a previous post, the Maestro API make heavy use of interfaces to wrap the assorted auto-generated classes into a consistent set of APIs. This was needed in order for an application to be able to access resources of various schema versions in a simple manner without having to reference the individual generated class for the specific resource schema version you want to work with.

Well, in Python there are no such thing as interfaces. What you see in the IronPython console is the full verbatim auto-generated class definition, and not the interface facade that we return to you in .net. What this means in practice is understanding how nullable properties are handled in .net XML serialization.

Simply put, each nullable property has a PropertyNameSpecified property that controls whether the property in question will be included or omitted when serializing back to XML. Such class properties are not included in their respective public interface, but since we're working with a language where there's no such thing as interfaces, you can get/set such properties directly. So to actually set a nullable property to null, you would set its respective PropertyNameSpecified property to false


Similarly, if you are setting a nullable property to a value that was initially null, you should make sure to set its respective PropertyNameSpecified property back to true.

The .net section of the IronPython documentation has a wealth of information about other .net-isms to be wary of.

Python standard library

IronPython includes the Python Standard Library, which we also bundle with Maestro, so anything from the Python Standard Library is usable in the IronPython console


However there are probably some parts of the Python standard library which may not play nice with the IronPython Console. I'm guessing anything involving threads, processes or asynchronous execution may have problems when used in the IronPython Console and are facilities you should probably avoid. So don't go too overboard in your script code.



Got any useful tips and tricks of your own to share? Comment on down below.