Sunday, 28 April 2013

MapGuide tidbits: OpenLayers in relation to Fusion

I'd had been holding off on this particular post for quite some time because what is written below wasn't exactly true or applicable until MapGuide RFC 132 was implemented. Now that the RFC is completed, the time to publish this post is more suitable.

As some of you know, Fusion is built on top of the powerful OpenLayers library.

But what you may not know (and probably want to know) are the specifics.

What version of OpenLayers?

Believe it or not, I myself do not know what version of OpenLayers is currently bundled with the Fusion that comes with MapGuide Open Source 2.5 (or older releases). Our bundled copy in Fusion has the release version number scrubbed out by SVN making it hard to determine the actual version number.

I strongly believe it is OpenLayers 2.10 due to the lack of touch event support.

For the next release of MapGuide Open Source (2.6) the answer will be crystal clear: Fusion will be using OpenLayers 2.12. What OpenLayers 2.12 brings to the table for Fusion will be the topic of another post.

What OpenLayers build profile?

As some of you may know, OpenLayers is not a monolithic library. It can be customized with various build profiles to include/exclude certain parts of the OpenLayers library. What that means in practice is that some parts of the OpenLayers API may not be available to be used in Fusion because we use our own custom build profile for OpenLayers. Our custom build profile is defined in fusion.cfg, there you can see what parts of the OpenLayers API we've included and what parts we've excluded.

Now sadly, the way OpenLayers is set up within the fusion source tree (before RFC 132) is that we are keeping in a "built" version of OpenLayers.js and have customizations done on that one file. This makes customizing your own OpenLayers build for use with Fusion much more harder as our current audit trail of Fusion-specific customizations is very hard to track. This means that customizing your own OpenLayers for Fusion may not be as simple as:
  1. Download the OpenLayers zip/tarball
  2. Build it with your desired build profile
  3. Overwrite Fusion's OpenLayers.js with your built copy.
For the Fusion that will come MapGuide Open Source 2.6, this will be much more clearer. We'll be reserving a section of the Fusion repo, for Fusion-specific customizations to individual js files in OpenLayers such that customizing your own OpenLayers becomes:
  1. Download the OpenLayers 2.12 zip/tarball
  2. Overlay the directory (where you unzip/untared) with our Fusion-specific modified files
  3. Build OpenLayers with your desired build profile
  4. Overwrite Fusion's OpenLayers.js with your built copy
  5. Re-build and re-minify Fusion with your custom OpenLayers.
This way, the OpenLayers build you customize will retain our Fusion-specific changes where necessary, and allows you to tap into parts of OpenLayers that we may have excluded from our custom build.

Thursday, 25 April 2013

MapGuide tidbits: Is your FDO provider smart enough when handling SQL?

So if you saw my previous MapGuide/pgRouting example, I mentioned that the whole example was only possible because any SQL queries (that involves geometry columns or expressions) that we send off to PostgreSQL through the MapGuide API, the FDO provider correctly translates such column values back into FDO geometry values and not as un-readable BLOBs.

Although we can't directly create a layer off of such a query, we can still feed the query result into a temporary SDF/SHP/SQLite feature source and create a layer off of that instead, which is how we got to display the shortest path results in MapGuide from a pgRouting SQL query.

So how do you know if your FDO provider:

 a) Supports SQL?
 b) Is smart enough to translate any geometry values in a SQL query result into FDO geometries and not un-usable BLOBs?

Simply connect to this database through the FDO provider with FDO Toolbox and launch a Data Query.

Do you see a SQL query mode in the Data Query tab? Then the provider supports SQL commands

When you run a SQL query in the Data Query tab, do you see WKT in the geometry column in the results pane?

If so, the provider is probably correctly translating these values back into FDO geometries.

But just to be sure, can you see the result visually?

If so, then there is no doubt that your provider is smart enough, and when the FDO provider can handle such cases, you can pretty much tap into whatever spatial functionality your underlying database has to offer through SQL if the standard MapGuide/FDO APIs do not fit the bill, as was the case in our MapGuide/pgRouting example.

Announcing: FDO Toolbox 1.2

As suggested in my previous release, every time a new version of FDO is released, we should have a complementary version of FDO Toolbox using it.

Since FDO 3.8 is now final (and used by MapGuide Open Source 2.5), here's a new complementary version of FDO Toolbox using it.

A summary of changes include:

  • FDO Toolbox now uses FDO 3.8 final
  • FDO Toolbox includes a custom build of the PostgreSQL FDO provider (r6796), allowing FDO Toolbox to create PostGIS 2.0 data stores (as the FDO 3.8 final provider cannot do this).
  • Fix a potential infinite loop in the spatial context creation/updating logic during Bulk Copy.
  • Fix "Create class if not exist" checkbox not being enabled under certain conditions in the "New Copy Task" dialog.

Thursday, 18 April 2013

MapGuide and pgRouting: A shortest path example

Ok folks, here's how you do this

For a little back-story, since reading Jo Cook's pgRouting example with MapServer, I wanted to do an equivalent one for MapGuide just to see for myself (and many others) if the MapGuide and pgRouting combination was indeed possible.

This blog post will show you a basic PHP proof of concept example of pgRouting integration with MapGuide using the following stack:
  • MapGuide Open Source 2.5
  • PostgreSQL 9.2
  • PostGIS 2.0.3
  • pgRouting 1.0.7
For different versions of PostGIS and/or pgRouting, you may have to adjust some of the code shown here.

This example has only been tested on Windows, but assuming you satsify the above pre-requisites I couldn't see why this example won't work for Linux as well.

You can find the code and sample package here for reference. This example works with both the AJAX and Fusion viewers

Getting the source data

This example uses the GeoBase "National Road Network" dataset for British Columbia ( This is the same reference dataset used in the pgRouting tutorial.

Creating the PostGIS database

Using pgAdmin or the command-line tools, create a new database "pgrouting_example" using "template_postgis_20". 

In case you're wondering, FDO Toolbox does not support creating a PostGIS 2.0 data store because the provider's data store and spatial index creation logic hasn't been updated for PostGIS 2.0. If you're using the PostgreSQL FDO provider that has this changeset compiled in, then you have this support. This change didn't make it for the PostgreSQL provider in FDO 3.8, so as it stands MapGuide Open Source 2.5 can connect to PostGIS 2.0 databases but not create them, which is still okay for this example as we're using external tools to set it up.

Enabling pgRouting

The pgrouting_example database is PostGIS-enabled, but not pgRouting-enabled. Execute this SQL on that database to enable pgRouting support:


Loading our Roads Shape File

We use the shp2pgsql utility to load our roads shape file into PostGIS

Why don't we eat our own dogfood and use FDO Toolbox to do this? Again, some shortcomings:
  • FDO Toolbox bulk copies geometries as-is, multi-linestrings don't get converted to linestrings. This is important for pgRouting in terms of building a routable network as you'll see in the next step
  • FDO Toolbox lacks PostGIS 2.0 support in its bundled FDO provider (as mentioned above).
So for now, we'll have to do with shp2pgsql

For our example dataset, the shape file in question is NRN_BC_9_0_ROADSEG.shp. The necessary command to load this into our PostGIS database (using the postgres db account) is:

shp2pgsql -s 4617 -I -S NRN_BC_9_0_ROADSEG.shp roads | psql -d pgrouting_example -U postgres

4617 is the SRID to load these geometries in. The "-S" switch instructs the tool to generate simple geometries instead of MULTI geometries, ensuring our lines are put into PostGIS as LINESTRING geometries and not MULTILINESTRING geometries. You'll see why this is important in the next step.

Making this data routable

We now need to extend our imported roads table to support pgRouting, we need to add the following columns:
  • source (integer, the source node id)
  • target (integer, the target node id)
  • length (double precision, the geometric length of the road line segment)
The following SQL creates these columns

alter table roads add column source integer;
alter table roads add column target integer;
alter table roads add column length double precision;

Then we use the pgr_assign_vertex_id function in pgRouting to populate the columns we just added. This function only works on linestrings and not multi-linestrings. This is why we use shp2pgsql, which can do this necessary conversion. This function was called assign_vertex_id in older versions of pgRouting. We call it like so:

select pgr_assign_vertex_id('roads', 0.00000001, 'geom', 'gid');

The 0.00000001 value is the "snap tolerance", since this dataset is in latitudes and longitudes (thus degree-based units) we need a really fine-grained value. This value varies from dataset to dataset.

This command will take a few minutes. Then we need to set the length column:

update roads set length = st_length(geom);

And finally, apply the necessary indexes for good performance (no need for a spatial index, as shp2pgsql already created one):

create index source_idx on roads(source);
create index target_idx on roads(target);

Consuming PostGIS from MapGuide

As mentioned, as of MapGuide Open Source 2.5, the bundled PostgreSQL FDO provider supports connecting to PostGIS 2.0 databases. It just can't create them, which is okay because the MapGuide API does not support Feature Source creation for RDBMS providers anyways. So setting up the Feature Source and layers is fairly straight-forward. 

But to save time and words on this post, just load in the referenced sample package, and tweak the credentials of Library://pg_routing/Data/postgis.FeatureSource to match your PostgreSQL credentials as required.

The sample package has two maps, a normal map (for consumption with the AJAX viewer) and a "Web Mercator" projected version (for consumption with Fusion with an OpenStreetMap backdrop).

Installing the sample application

Assuming the standard installation directory of C:\Program Files\OSGeo\MapGuide, extract the sample application to the C:\Program Files\OSGeo\MapGuide\Web\www directory.

The extracted directory should look like this

Running the sample application

The sample application works with both the AJAX viewer and Fusion viewer. Load them like so:

AJAX Viewer: 




Plug in the port numbers as necessary into the URL for Apache configurations

The Demo

Regardless of the viewer, the Task Pane will be loaded with the main page of the sample application.

Now this is a proof of concept, so the UI is very simplistic and barebones and requires you to enter the source and target node ids to compute the shortest path. Ideally, you would record the start/end points with the digitizing viewer API, tap into PostGIS trickery server-side to "snap" to the nearest road segments, extract the relevant source and target IDs and calculate shortest path from there.

In our case, this has to be done manually, so select the road segment closest to your start point and observe its "source" property value.

Repeat for the selected road segment closest to your end point. But this time, observe its "target" property value.

Once you've noted both ids, plug them into the form, click the "Calculate" button and pgRouting will do its magic!

So what does the "Calculate" button do exactly? It does this:

1. Creates a temporary MapGuide Feature Source (SDF) to store the shortest path result

2. Creates a MgLayer pointing to the shortest path result Feature Source

3. Use MgFeatureService.ExecuteSqlQuery() to execute the following SQL:

select gid, geom from roads 
            join (select * from shortest_path('select gid as id, source::integer, target::integer, length::double precision as cost from roads', source_id, target_id, false, false)) as route 
            on roads.gid = route.edge_id

The key thing to take from this, is that any PostGIS geometry columns in that SQL query will be correctly interpreted as FDO geometry values in the MgSqlDataReader we get back. If what I just said didn't ignite any light bulbs, well then it should!

Because this means for cases where our standard MapGuide Data Access APIs doesn't support or cover, we can always use MgFeatureService.ExecuteSqlQuery() as an "escape hatch" API to tap into the full set of geospatial/routing functionality offered by pgRouting/PostGIS and if any such SQL queries involve geometry columns, we can trust the PostgreSQL FDO provider to properly translate such values back as FDO geometry values in the returning SQL reader (and not as unrecognizable BLOBs), allowing us to do geometry operations on such results with the MapGuide API.

Does this technique only work for the PostgresSQL provider? No, the King.Oracle provider is also known to properly translate FDO geometry values from raw SQL query results via FDO. MySQL, SQL Server and SQLite are currently unknown. Please do comment if you know if this technique also works on these providers.

Now we can't create a Layer Definition off of a SQL query result (wouldn't that be a nice feature to have?), so we do the next best thing, which is to:

4. Copy the SQL reader contents into our temporary SDF feature source (that's why we created it). On subsequent calculations, the temporary SDF feature source is cleared first before copying in the new results from the SQL reader.

5. Save the MgMap and output a client-side JS call to refresh the map.

So that's the jist of this example. You can read the PHP code in the sample for all the gory details.

Caveats (or: pgRouting-isms)

EDIT: Thanks to dkastl for pointing out the very high tolerance value I had previously in my pgr_assign_vertex_id() example. A proper tolerance value will ensure proper display of routing results. Consider what was previously written below as a case of what happens if you specify a tolerance value that's too high.

If I haven't made it clear, this is a proof of concept example. There's some data/pgRouting related things that baffle me. For example, zoom in closer to that shortest path. Why is it broken off in some parts?

This shortest path result is straight from the pgRouting shortest_path() function.

Is the source data bad? Did I set up the network routing information incorrectly? Is my pgRouting SQL query bad? Did I base this example off of semi-inaccurate/outdated tutorial documentation? Is it a bug in pgRouting itself?

These are questions a more seasoned expert on pgRouting could probably explain. But if you do know why such results would be the case, I'd like to know through the comments on this post.

But besides that, the root question of whether MapGuide be integrated with pgRouting has been answered.

With an emphatic YES!

Wednesday, 17 April 2013

Yes it's possible!

I'll be showing you how shortly. Stay tuned.

Thursday, 11 April 2013

MapGuide tidibts: Stylization error logging

Ever look at an image of a map, and you know something is not right? You look at the error logs and you don't see anything amiss?

Try setting this value in serverconfig.ini:

LogsDetail = MappingService:2

What does this setting do? It sets the logging detail for Mapping Service related operations to Trace, Warnings and Errors

When an error occurs during individual feature stylization, caught exceptions are logged as warnings, which sort of makes sense as MapGuide would be pretty flimsy if the rendering bailed out on the first bad feature it encounters during stylization.

What this means however is that if errors do occur on individual feature stylization you won't see anything in the logs because the default logging level is Errors only.

What could trigger such errors that won't be logged by default? Things involving FDO expressions in any styling or symbolization property in your Layer Definition.

  • Malformed FDO expression syntax
  • Calls to non-existent FDO expression functions
  • References to non-existent feature properties
Applying the above setting will reveal such errors.

Be warned though, logging can be extremely noisy as stylization errors for each feature are logged. So use this setting with care (obviously turn it on for debugging purposes, and turn it off when done).

Wednesday, 10 April 2013

MapGuide tidbits: FDO stylization expression functions

Believe it or not, these aren't the only expression functions that aren't documented.

You may have noticed these functions pop up when using the Expression Editor in Maestro or Studio/AutoCAD Map

  • ARGB
  • IF
* Denotes a MapGuide-specific FDO expression function (ie. Not supported/recognised in AutoCAD Map)

While some of these functions have been explained, others have not. Also there isn't really many solid examples, so it's understandable if you don't have much of an idea where and how such functions may prove useful.

So firstly, what are these functions? These functions are FDO Expression Functions that are only applicable during rendering and stylization of features. That means these functions can be used in any expression for:
  • A tooltip
  • A hyperlink
  • A feature label
  • Any styling/symbolization property that accepts FDO expressions
However, due to their scope you cannot use said functions in:
  • A layer filter (rendering/stylization doesn't happen at this stage)
  • Any part of a MgFeatureQueryOptions object (computed property or filter).
These functions are universally supported regardless of providers, as they are application-level functions provided by the FDO Expression Engine, so you don't have to worry about provided capabilities like regular FDO functions. Also unlike the custom aggregate functions, these functions are actual FDO functions so you can nest and chain these function calls with other FDO functions.

So like the other post, here's what each function in this list does.


The ARGB function returns a 32-bit integer, which represents the color computed by this function. It's signature is:
  • ARGB(alpha, red, green, blue)
  • alpha, red, green, blue are numbers between 0 and 255 inclusive
Remarks: This function can be used in place of any layer style property that takes a color (eg. A border or fill)


The DECAP function returns an auto-capitalized version of the input string. It's signature is:
  • DECAP(inputString)
  • inputString is a string
For example the expression DECAP('HELLO WORLD') will return the string "Hello World"

Remarks: This function I would imagine would primarily be used for normalizing string values for labelling.


The FEATURECLASS function returns the fully qualified FDO class name that the currently stylized feature originates from. It takes no parameters.

Remarks: This function I would imagine is primarily used for tooltips or hyperlinks. Probably for displaying useful "debugging" information about a feature or maybe as part of some URL link you're building into the tooltip content.


The FEATUREID function returns the base64 encoded key of the currently stylized feature. This is the same base64 key value that would be in a selection XML string if this feature was selected. It takes no parameters

Remarks: Probably the same use case as the FEATURECLASS expression function


If you used excel, this function should be familiar to you. It's signature is:
  • IF(condition, trueExpr, falseExpr)
  • condition is a string representing the FDO condition to evaluate
  • trueExpr is the expression to return if the specified condition evaluates to true
  • falseExpr is the expression to return if the specified condition evaluates to false
Remarks: Obviously useful for binary expressions


The LAYERID function returns the unique id of the layer that the currently stylized feature belongs to. This unique id is the same value returned by MgLayerBase::GetObjectId() for that same layer. It takes no parameters

Remarks: Probably used for tooltips or hyperlinks, in conjunction with some server-side logic (invoked through a built tooltip content URL) that does something with the runtime layer (MgLayer) state.


The LOOKUP function implements a lookup table where each key is associated with a single value. Its signature is:
  • LOOKUP(expr, defaultValue, key1, value1, ... keyN, valueN)
  • expr is the FDO expression that evaluates to a string or number
  • defaultValue is the value to return if none of the keys are equal to the given expression
  • key[1...n] is the value to compare the evaluated expression against for equality
  • value[1...n] is the value to return if the corresponding key is equal to the evaluated expression
For example, this expression:

LOOKUP(RTYPE, 'Unknown', 'AGR', 'Agriculture', 'MFG', 'Manufacturing', 'RES', 'Residential')

Will return the following values based on the value of the RTYPE attribute of the currently stylized feature:
  • RTYPE = 'AGR': Expression returns 'Agriculture'
  • RTYPE = 'MFG': Expression returns 'Manufacturing'
  • RTYPE = 'RES': Expression returns 'Residential'
  • RTYPE is NULL or does not match any of the above: Expression returns 'Unknown'

Remarks: A scenario where I can see this function being useful is for creating "legendless" themes. Read on to understand what I'm talking about.


The MAPNAME function returns the name of the runtime map that the current stylized feature is part of. It takes no parameters.

Remarks: Once again, it's probably going to be mostly used for tooltips or hyperlinks. Either for "debugging" or building tooltip content URLs to server-side logic using the MapGuide API. 


The RANGE function is similar to LOOKUP in that it's a function that can return one of many values based on a given expression. The difference is the expression is compared against a min/max range instead of a fixed value. It's signature is:
  • RANGE(expr, defaultValue, min1, max1, value1, ... minN, maxN, valueN)
  • expr is the FDO expression that evaluates to a number
  • defaultValue is the value to return if none of the expression does not fall within any of the specified range
  • min[1...n] defines the lower bound of a given range
  • max[1...n] defines the upper bound of a given range
  • value[1...n] defines the value to return if the evaluated expression lies within the respective min and max of this range
For example, the following expression:

RANGE(POPULATION, 4.0, 100000, 1000000, 6.0, 1000000, 10000000, 8.0)

Will return the following values based on the value of the POPULATION attribute of the currently stylized feature:
  • 100000 <= POPULATION < 1000000: Expression returns 6.0
  • 1000000 <= POPULATION < 10000000: Expresion returns 8.0
  • POPULATION is NULL or does not fit within any of the above ranges: Expression returns 4.0
Remarks: Same use case as LOOKUP. A way to create "legendless" themes.


The SESSION function returns the current MapGuide id of the session that initiated this rendering/stylization operation. It takes no parameters

Remarks: Same use case as MAPNAME. Most likely used in conjunction with MAPNAME, seeing as most server-side logic require both the session id and the map name in order to do anything useful with the runtime map (MgMap)


The URLENCODE function encodes the input string. It's signature is:
  • URLENCODE(inputStr)
  • inputStr is the string to URL encode
Remarks: Probably used to encode content when building URLs in the tooltip or for hyperlinks.

So there's the overview of these functions. How about some examples? I got some right here.

Example 1: A comprehensive tooltip

This example layer definition shows all of the above stylization functions in a tooltip so you can get an idea of what these functions are returning based on the Sheboygan parcels data.

Example 2: A "legendless" themed layer

This example layer definition shows how the normal Parcels layer from the Sheboygan dataset using the LOOKUP expression function to dynamically theme the parcels. Note how the legend does not show the individual theme rules. This is because the Layer Definition only has one rule, but that one rule uses the LOOKUP function to compute the fill based on the type (RTYPE) of the Parcel feature.

Maestro does not currently offer any assistance in creating "legendless" themes. It's something I've put into consideration.

Hopefully this post sheds greater light on what these functions are and how they work. These functions may provide layer stylization options that you didn't think was previously possible.

Sunday, 7 April 2013

New mg-desktop binaries

Coinciding with the final release of MapGuide Open Source 2.5, is a new release of mg-desktop.

So if you're wondering that that screenshot was all about, that was a simple test application using the new experimental Java API for mg-desktop. This is based on the enhanced Java API work for the Web API in 2.5, so it has none of the cruftiness of the original MapGuide Java wrapper API.

The Java API is also windows only as the MapGuideDesktopApi.jar is a SWIG-generated JNI wrapper around the native mg-desktop libraries. Since these libraries currently only exist as windows dlls, this jar obviously will not work on platforms that are not Microsoft Windows.

This Java API is there so you can explore what can be done with mg-desktop in the Java ecosystem. I myself am not fully proficient in Java (the platform) to be able to extend mg-desktop in Java in the same way as I have done for .net (so uh ... is swing still what you use for GUIs in Java?).

The Java API is only bundled with the zip package of mg-desktop. The mg-desktop nuget package does not include the Java API (it wouldn't make much sense to include it either).

Besides the new experimental Java API, mg-desktop itself has some small API enhancements as well:

  • IMapViewer now includes a new overload of SelectByGeometry() that accepts a callback and allows you to do "one-shot" programmatic selection that does not trigger the selection events that are normally raised by the viewer and does not require event subscription/unsubscription.
  • The MgdRenderingService::RenderDynamicOverlay() method now has a new behaviour flag value (8 to render base layers). If you logically OR this new flag value into the rendering options behaviour, your overlay image will include the map's base (tiled) layers as well. This means that you no longer have to use the RenderMap API to get a map image that includes tiled layers, and this one has the advantage of not having it's background pre-filled (it's an overlay image after all). Secondly this new behaviour is the viewer default, meaning you don't have to use the currently documented workarounds and also means that pre-rendering hooks in the viewer are actually useful on a map with tiled layers for once!
For this release, I've decided to stop doing .net 2.0 builds of mg-desktop. It's just too much effort to produce a .net 2.0 build of mg-desktop nowadays  For a .net 2.0 build, the whole FDO/MapGuide stack has to be built in VS2008. Whereas with .net 4.0 build, we can just ride the coat-tails of the current MapGuide Open Source build process where 80% of the stuff is already built for us. Plus I'd figure most of you would be on .net 4.0 anyway. 

This means that the mg-desktop build used by the Local Connection mode in Maestro 4.0.x will forever be on the same version as it is right now. Maestro 4.0.x is a maintenance branch that we aren't actively developing new features into so this shouldn't be much of an issue.

On the nuget front, this release replaces the 2.4 series. I'm not sure if this is how new versions are supposed to be put out as nuget doesn't really have the notion of "branches". If you install a new mapguide nuget package, it will now be pulling down the 2.5 package by default unless you explicitly specify the version number.

So a command like this:

Install-Package mapguide-api-base-x86

will install the 2.5 version of the package (this release), but a command like this:

Install-Package mapguide-api-base-x86 -Version

will install the latest 2.4 package. If you don't know the specific number, you can hit tab after the -Version parameter and the Package Manager Console will display an autocomplete prompt with all the applicable versions. You want to pick the latest major.minor version that matches the installed major.minor version of MapGuide that you're working with.

Something to take note of if you're building MapGuide web applications where the version you're working with matters, or if you need to fetch the correct CS-Map dictionaries for an older mg-desktop package.

MapGuide Open Source 2.5 released

Here it is! The final release of MapGuide Open Source 2.5.


This final release includes the following changes from RC2


We landed in a big changeset which should put this whole saga of conflicting widgets behind us:

  • Quick Plot, Select Radius and Select Polygon widgets are no longer mutually-exclusive widgets. For Select Radius/Polygon this means they are now "click once to select once" affairs. If you need to re-select, just re-click the menu/toolbar item.
  • All digitizer actions now raise a new MAP_DIGITIZER_ACTIVATED event when digitization begins and raise a new MAP_DIGITIZER_DEACTIVATED event when digitization stops. All widgets that would require the user to draw a geometric shape will raise these events
  • The maptip, pan and zoom widgets will disable/restore themselves on these digitizer events to prevent them for interfering with you drawing your geometry. You can still mouse wheel zoom while digitizing, panning while digitizing is not possible. Ideally, we'd like to still pan around while digitizing with the middle mouse button, but the mouse button is hard-coded in OpenLayers :( Something that's nice to address in the future.
  • Fix the z-index on the Scalebar widget which caused it to be drawn *below* the map viewer.
  • Small UI tweaks on the FeatureInfo/Query/Redline widgets
  • All digitization prompts now have a cancellation link attached just in case the manual button (eg. Measure) or ESC key cancellation method is not available

Other changes

What's next?

I've been trying to push for faster release cycles (I think we can all agree 2.4 to 2.5 has been much faster than 2.2 to 2.4), but realistically I don't think we will see a 2.6 release until early 2014 at the most.

This is because MapGuide is strongly tied to FDO and unlike MapGuide, I don't have much influence with FDO's release cycle. I don't really want to put out new releases of MapGuide that use a trunk build of FDO unless they're preview releases. I cannot consider starting a release cycle for 2.6 until the next FDO at least hits beta and since history has shown that new binary releases of FDO happen around December-April, we should try to adjust the MapGuide release cycle to be in sync with FDO as much as we can.

This isn't necessarily a bad thing. As it means we have plenty of time in the interim to land in this backlog of new features that couldn't make it into 2.5 and flesh out some sandboxed work into fully working new features that can realistically land in 2.6.

So I guess what that means realistically is that in terms of any future MapGuide releases this year, you'll probably only be seeing 2.5.x point releases and maybe the occasional 2.6 preview release as a "snapshot" of what's happening for 2.6. 2.6 proper probably won't happen until 2014 ticks over.

Wednesday, 3 April 2013

Not all is quiet on the mg-desktop front

Looks like it's working so far!