Wednesday, 7 December 2016

React-ing to the need for a modern MapGuide viewer (Part 7): Laying out the blueprints

With the latest release of mapguide-react-layout out of the way, it's time to continue the journey of porting across the remaining fusion templates across.

One of the "problems" we have right now with this new viewer is that although we have got most of the foundational stuff right, the UI lacks stylistic cohesion. This is due to the viewer being a mish-mash of various react components, each with their own unique styling quirks. I really wanted a react-based UI toolkit that had a good enough baseline set of widgets/components with a unified look for building desktop-centric web applications (with an option to go mobile down the road).

Most of these UI toolkits however, take the reverse direction. They are mobile/tablet first, trying to emulate Material Design, iOS or Bootstrap and when trying to adapt such toolkits for a desktop-centric web application design, just look horribly out of place. Most of the UI toolkits that would've passed my desired criteria (like kendo, ExtJS, jQuery UI, etc) suffered from being imperative JavaScript APIs (meaning it would be a painstaking effort to interop with React and/or TypeScript), or some had incompatible/undesirable licenses to boot.

Well, I think my wish for such a toolkit has now been fulfilled, and its name is Blueprint.

What sold me on this particular UI toolkit was:
  • It is React-based
  • It has a good wide range of components that covers most of what I need to port across the remaining Fusion templates
  • It comes with a diverse set of icon fonts
  • It has a friendly license (BSD)
  • It is written in TypeScript and the library comes bundled with TypeScript definitions
  • It looks good!
With so many good selling points, I've decided to adopt Blueprint as the UI foundation for all my viewer templates. This means.

We have better looking modal dialogs (as seen in our updated Aqua template)



We have better styled UI for certain tools

 

And we have key components needed to start bringing across the other remaining Fusion templates, like the TurquoiseYellow template.

Compare the original Fusion template



With our blueprint-powered version


Looks good enough doesn't it?

Now there is one executive decision I'm making with the Fusion templates I'm porting over. The overview map will always be present as a toggle-able button on the main map viewer component and not outside of the map viewport.

Part of the problem is having the OpenLayers OverviewMap control render its content outside of the map viewport doesn't really play nice with React component updates in my attempts thus far, so I've taken the creative decision to not bother trying to get everything 1:1 when porting these templates over. As long as the main elements and styles are there, it's good enough for me.

Now sadly, despite having made several existing libraries and React components redundant (and they have been removed as a result), taking on Blueprint has added a lot of extra weight to our final bundle

Fortunately, this is still significantly under the current Fusion production bundle size, and as we are still in the process of reaching functional parity with our existing AJAX/Fusion viewers, bundle optimization is not a priority at the moment. When that time comes, we can look at things like custom OpenLayers build profiles and moving to Webpack 2 for its tree shaking feature, which should make some in-roads in cutting down our production bundle size to more acceptable levels.

Friday, 25 November 2016

Announcing: mapguide-react-layout 0.6.2

Here's a new release of mapguide-react-layout.

This release has been updated to use the latest version of OpenLayers and fixes some breaking issues around viewing maps with Base Layer Groups (ie. tiled maps)

Sadly, no new Fusion templates have been ported over for this release as my hunt for a suitable tab and accordion component (that the remaining 4 fusion templates all use in one form or another) is still ongoing.

Download

Wednesday, 19 October 2016

Announcing: mapguide-react-layout 0.6.1

This is a quick release to fix the viewer so that it can load maps that contain raster layers.

Download

Monday, 17 October 2016

Announcing: mapguide-react-layout 0.6

Previously, I mentioned a series of blocking issues (in the process of porting over the Aqua Fusion template) that I needed to clear before I can safely put out a new release of mapguide-react-layout. Well, those roadblocks have been cleared, so here's a new release.

Here's a summary of the cool stuff since the first official release.

Aqua Template

The first of 5 fusion templates have been ported across.


Here's how the road blocks were cleared

1. Task Pane / Selection Panel / Legend does not play nice with Modal Dialogs

It turns out that all we really needed to do was have each modal dialog containee component support the notion of a maximum height and overflow:scroll its inner content if that height is exceeded. As these modal dialogs are of a known height, we know what max height that will have to be applied to each top-level component that is to be housed inside a modal dialog

2. We sort of need InvokeScript support as that is what the original templates use to show the Task Pane / Selection Panel / Legend / etc. 

I've decided to nip this one in the bud and just hard code into the template 3 toggling buttons that you can see on the top-right hand corner of the screenshot. If you close any of the affected modals, you can hit the respective button to bring it back.



3. Flyout menus don't play nice either

This one looked to be hard, but thankfully the react-flyout component I've chosen allowed for my workaround to (ahem) work with minimal amount of legwork.

The key was to introduce a new top-level FlyoutRegion component which all flyout menus render into (regardless of what toolbar they come from). As this FlyoutRegion component is top-level, the flyout menus rendered inside do not have a direct parent-child relationship with the toggling button (from whatever toolbar it may originate from), therefore it is not subject to being caught up in any toolbar CSS overflow shenanigans.

The only catch with this is that all the flyout menus will always render to the top left corner (I'm guessing this wasn't a usage scenario envisioned by the react-flyout author). So as a minor hack I've introduced new redux actions to dispatch the opening/closing of flyout menus, which the FlyoutRegion listens on, and the flyout menu buttons dispatch such actions when clicked, also flowing back DOM element dimensions (of the toggling button), so the listening FlyoutRegion component knows exactly where to position the flyout menu to be rendered.

This isn't perfect, as this animation shows


But it's a small (and acceptable) price to pay for what is now mostly functional flyout menus.

Application Definition (aka. Flexible Layout) support

As porting across the Aqua template would imply, the viewer now accepts Application Definition resource ids in addition to Web Layout resource ids. Please note that currently only certain templates can accept Web Layouts and others only accept Application Definitions. You can find out which template supports what in this document.

This support is not 100% yet, and so you will invariably find error placeholders for un-implemented widgets strewn across various toolbars and menus like so.


If you hover your mouse over these items, you can see what the viewer currently doesn't support or map across yet.


So when you encounter such buttons, the only practical thing to do at the moment is to remove such buttons from your Application Definition. The error placeholder mechanism is a nice and easy way to identify such unsupported elements.

If your Application Definition has external base layers defined, this release will recognize the following base layer types:

  • OpenStreetMap: Mapnik/CycleMap/TransportMap
  • Stamen: Toner/Terrain/Watercolor

Better Startup

The initial release of mapguide-react-layout wasn't really graceful about any errors that occur during the process of initialization. All you had was a white screen of nothingness to tell you that something went wrong. So naturally in the interest of providing a good out-of-the-box experience, this was something that needed to be rectified.

If there's a problem on startup, we'll show it to you now. For example, the MapGuide Server isn't running or reachable.


Another common silent error is loading a map with an EPSG code not known to proj4js (ie. Anything not EPSG:4326 or EPSG:3857). Now for such EPSG codes that aren't known to proj4js on startup, we'll automatically fetch the appropriate proj4js definition from https://epsg.io, register it with proj4js and continue on our merry way.

More OpenLayers goodies baked in

The base map viewer component now has these extra OL controls baked in.

An overview map



A rotation reset button that's shown when you rotate the map. You can rotate the map by holding ALT+SHIFT and dragging the map to rotate it.


And lots more!

All is covered in the associated release notes for this release.

Download

Tuesday, 11 October 2016

Announcing: MapGuide Open Source 3.1 and mg-desktop/nuget packages

The wait is over. MapGuide Open Source 3.1 has arrived.

The only change from RC1 is a fix to the QUERYMAPFEATURES operation and its consuming map viewers (both AJAX and Fusion) to respect the display order of attributes in Layer Definitions.

Along with this release are updated mg-desktop binaries and nuget packages. Just a friendly reminder about nuget packages: Install the version of the nuget package for the version of MapGuide you are intending to be running your application against.

Download MapGuide

Download mg-desktop

Thursday, 6 October 2016

React-ing to the need for a modern MapGuide viewer (Part 6): Emulating the Aqua fusion template

After announcing mapguide-react-layout to the public, the next major task was to bring the viewer up to parity with Fusion by:
The first part was actually pretty simple. The Application Definition schema is actually simpler to model than the Web Layout one (due to the heavy emphasis on key-value pairs, which is why the schema is still at v1.0.0, the key-value pair mechanism allows for arbitrary extension to support new features). It was a case of mapping the loaded Application Definition to the common initialization structure that the Web Layout currently maps to.

Though we didn't have any of the 5 templates ported at this point, we could throw an Application Definition at the "ajax-viewer" template and it is able to understand a majority of the widgets, with the exception of toolbars, because toolbars are uniquely named for each Fusion template and the Application Definition is expected to be referencing the template-specific toolbars.


So at this point, it was now a case of porting across the 5 templates. As we currently lack an accordion or tab component, the logical place to start is the Aqua template, which uses neither.

We start off with the existing "ajax-viewer" template, re-arrange the layouts of the various toolbars/menus and using our modal dialogs to house the Task Pane, Legend, etc, and taking advantage of widespread modern browser support for CSS gradients and we get ...



Let's compare that to the original


What do you reckon? I think it's a good visual emulation of the original.

And here's an extra added bonus. Currently, the toolbars (in any layout component) do not handle overflowing toolbar items at all. It turns out that applying a standard CSS overflow:auto on the toolbar container element gives us a very usable solution:


I've decided to activate this for toolbars with horizontal orientation only, as this trick doesn't work very nicely on toolbars with vertical orientation and I am going on the assumption that one wouldn't pack a vertically oriented toolbar with too many items.

Unfortunately, the process of porting across the Aqua template has revealed some teething issues.

1. Task Pane / Selection Panel / Legend does not play nice with Modal Dialogs

All the work in making these components full height presents issues when housed within our modal dialogs. For example, here's what the selection panel looks like


It completely overwrites the container for the modal dialog, so we can't hide the dialog or drag it around. The Task Pane has the same problem.

2. We sort of need InvokeScript support as that is what the original templates use to show the Task Pane / Selection Panel / Legend / etc. 

Failing that, we probably have to hard-code this toggling functionality into the layout component.

3. Flyout menus don't play nice either


See that scrollbar? The flyout menu is overflowing inside the toolbar container! I hope the react-flyout component we're using allows us to break out of parent-child element relationships for a flyout menu and its toggling button, otherwise we'd have to look at an alternative.


Once these problems are solved. That's when I think I'll put out a new release.

Tuesday, 27 September 2016

Introducing mapguide-react-layout. A modern viewer for MapGuide

Let's recap the story thus far:
Up until now, I have intentionally withheld the GitHub repo where all this development action was taking place as I wasn't going to reveal something that I didn't think was ready to be revealed. Well, it's now reached a point where I am comfortable with finally unveiling this project for general public consumption.

I'm proud to introduce mapguide-react-layout, the new modern map viewer for MapGuide Open Source and Autodesk Infrastructure Map Server.

mapguide-react-layout requires at a minimum MapGuide Open Source 3.0 or an equivalent version of Autodesk Infrastructure Map Server. As I've stated in part 2 of this series, this viewer will require a modern web browser, which practically speaking is any of the following:
  • Google Chrome (stable channel)
  • Mozilla Firefox (stable channel)
  • Internet Explorer 11. Older versions of IE will not be supported
  • Microsoft Edge
  • For iOS: Mobile Safari
  • For Android: Google Chrome or Mozilla Firefox
Overview

Conceptually speaking, you can think of mapguide-react-layout as the logical successor to Fusion and the AJAX viewer and it carries similar high-level concepts as well:
  • mapguide-react-layout has templates just like Fusion.
  • Your application consists of various components (as opposed to widgets in Fusion)
  • Components subscribe and dispatch actions to push data to a centralized redux store for application state. (as opposed to widgets having to explicitly subscribing to each other with event handler spaghetti). Application state is significantly easier to reason about in mapguide-react-layout as opposed to Fusion or the AJAX viewer.
  • mapguide-react-layout offers the same extension points for custom functionality for your MapGuide applications, such as InvokeURL commands.
  • Just like before, a mapguide-react-layout viewer is driven by a Web Layout or a Application Definition (this is not implemented at this stage, but is something I intend to complete).
It is the last point which is probably the most salient. Because a mapguide-react-layout viewer accepts a Web Layout or Application Definition, the authoring and development workflow for MapGuide applications using this viewer remains unchanged

Instead of pointing a Web Layout to an AJAX viewer URL or an Application Definition to a Fusion template URL, you just point either resource to your mapguide-react-layout viewer.

Templates

The mapguide-react-layout viewer includes the following layout templates out of the box:

1. AJAX Viewer



This template visually mimics the original MapGuide AJAX viewer (with much less frames!)

2. Sidebar


This template is a responsive layout based on the sidebar-v2 map viewer template. Well suited for phone/tablet sized displays.

In future releases (once I get the Application Definition support implemented), I'll look at bringing across the existing 5 Fusion templates as well.

Getting the viewer/code

The code to mapguide-react-layout can be found on my GitHub repo. There you will also find installation instructions and other various documentation/notes.

Feedback, questions and pull requests welcome.