Using Mapguide selection with OpenLayers
Mapguide is a great solution for building web applications: it has the best administrative interface of all open-source (and some commercial) web servers, it is
very fast with vector data, it integrates nicely with AutoCAD Map 3D, ...
Even though I am
very satisfied with the basic viewer, it does not play well on mobile devices. Creating a viewer using OpenLayers seems the way to go, and it is in fact the library used by
the fusion viewer and AutoDesk's own mobile viewer.
Since I wanted my
mobile viewer integrated with an existing application, I prefered rolling my
own viewer based on OpenLayers: for integration with the rest of an existing
webapplication I prefer a simple viewer rather than having all the bells and whistles of the fusion viewer.
Creating only a
viewer without interactions is easy, just looking to the sample code of the mapguide on on OpenLayers
will work.
Things get more interesting when you want to use more of mapguide functionality, eg using selections.
The openlayers api
documentation is not very helpful: "Some server plumbing is required to read such a value".
But which plumbing
is required?
Ok let's try to find
out: For selection to
work a session must be created, and in
this session we can create a map with its own selection object. This is
actually the "server plumbing" required.
Interested in running your own version? Download the full code here, it will also require jQuery and Openlayers.
Stay tuned for my next blogpost where I will expand this viewer to an editor with snapping enabled!
<?php try { include 'C:\Program Files\OSGEO\mapguide\www\mapadmin/constants.php'; $locale = "en"; // localizable string $errorMsg = ""; // Initialize web tier with the site configuration file. The config // file should be in the directory above as this script. $webConfigFile = __FILE__; $pos = strrpos($webConfigFile, '\\'); if ($pos == false) $pos = strrpos($webConfigFile, '/'); $relativeLocation = '../'.MgConfigProperties::DefaultConfigurationFilename; $webConfigFile = substr_replace($webConfigFile, $relativeLocation, $pos+1); MgInitializeWebTier($webConfigFile); } catch ( MgException $e ) { $errorMsg = $e->GetExceptionMessage(); echo $errorMsg; } catch ( Exception $e ) { $errorMsg = $e->getMessage(); echo $errorMsg; } // Establish a connection with a MapGuide site. $user = new MgUserInformation('Anonymous', ''); $siteConnection = new MgSiteConnection(); $siteConnection->Open($user); // Create a session repository $site = $siteConnection->GetSite(); $sessionID = $site->CreateSession(); $user->SetMgSessionId($sessionID); // Get an instance of the required services. $resourceService = $siteConnection->CreateService(MgServiceType::ResourceService); $mappingService = $siteConnection->CreateService(MgServiceType::MappingService); // Get a runtime map from a map definition $resourceID = new MgResourceIdentifier('Library://MapsOnline/MapNL_intern.MapDefinition'); $map = new MgMap(); $map->Create($resourceService, $resourceID, 'MapsonlineOL'); $mapName = uniqid($mapTitle); $mapStateId = new MgResourceIdentifier("Session:" . $sessionID . "//" . $mapName . "." . MgResourceType::Map); //create an empty selection object and store it in the session repository $sel = new MgSelection($map); $sel->Save($resourceService, $mapName); $map->Save($resourceService, $mapStateId); // Show information about the map header("Content-type: application/json"); echo json_encode(array( "map" => $mapName, "sessionId" =>$sessionID )); ?>
The next thing which is needed is an event
handler on the clientside in OpenLayers itself. For this example I extended the
default selectioncontrol to run the function
"selectRectangle" if a selection is made with the shift-button down.
Next step is
implementing this selectRectangle function. Thisfunction will pass the bounding
box of the rectangle to the mapagent.
Note that there is a random seq value added to the request: this is in
place to make sure that no caching is done.
function selectRectangle(bounds) { var ll = map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.left, bounds.bottom)); var ur = map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.right, bounds.top)); var polygon = "POLYGON((" + ll.lon.toFixed(4) + " " + ll.lat.toFixed(4) + ", " + ll.lon.toFixed(4) + " " + ur.lat.toFixed(4) + ", " + ur.lon.toFixed(4) + " " + ur.lat.toFixed(4) + ", " + ur.lon.toFixed(4) + " " + ll.lat.toFixed(4) + ", " + ll.lon.toFixed(4) + " " + ll.lat.toFixed(4) + "))"; ; $.post(mapagent, { SESSION: session, MAPNAME: mapname, GEOMETRY: polygon 'MAXFEATURES': '-1', OPERATION: 'QUERYMAPFEATURES', PERSIST: '1', SEQ: Math.random(), VERSION: '1.0.0', SELECTIONVARIANT: 'INTERSECTS', CLIENTAGENT: "openlayers" }, showSelection, "xml" ); }After posting this form, the selection state is saved in the server session, but not yet visible on the client. Therefore we must redraw our dynamic layer (which contains the selection). I'm also calling a url from the basic viewer which will return me a json object of the selected features (wishlist: this function should be present in the mapagent). Finally I use a function to render this json to a table, so I can see what is actually selected :-)
function showSelection(data) { dynlayer.redraw(true); url = "/mapguide/mapviewerphp/getselectedfeatures.php $.get(url, { SESSION: session, MAPNAME: mapname, LOCALE: 'en', SEQ: Math.random() }, selectionJsonToTable, "json"); }
Interested in running your own version? Download the full code here, it will also require jQuery and Openlayers.
Stay tuned for my next blogpost where I will expand this viewer to an editor with snapping enabled!
Nice to see another MapGuide blog around here :)
ReplyDeleteNice method. We found one issue and I don't know if it is on ours only or what, but on the 2.5.1 install, the Anonymous account has issues with allowing a map to display. As soon as we switch it to like Administrator, everything works without changing anything else. Just wanted to pass this along to anyone else that might run into the same issue. Again, great method! Post more, this was very helpful.
ReplyDeleteThe createsessionandmap.php on GITHUB is different from the code here. For example, rather than JSON, it returns the following.
ReplyDelete// Show information about the map
echo "Name of map: '" . $map->GetName() . "'n";
echo " Session ID of map: " . $map->GetSessionId() . "n";
echo " Object ID: " . $map->GetObjectId() . "n";
Sweet solution otherwise!