The use of Angular.js in RIF Front End, April 2019

  1. Introduction
  2. General Layout of the RIF files
    1. Directory Structure
    2. Naming Convention
  3. Libraries
  4. The main module
    1. CSS
    2. Alerts
  5. Dashboards
    1. Login
    2. Submission
    3. Mapping and Viewer
    4. Export
    5. Backend
  6. Utilities
    1. Controllers
    2. Directives
    3. Partials
    4. Services
  7. Front End Issues
    1. Faults
    2. Major Enhancements
    3. Minor Enhancements
    4. Fixed, but open as not tested sufficently

Introduction

Assumes you are familiar with Angular nomenclature, so you know a partial from a directive.

General Layout of the RIF files

Directory Structure

The file are located in rifWebApplication\src\main\resources. From this file root, the RIF has the following directory structure:

Directory name Description
backend Functionality to deal with the database via the middleware
css RIF specific css
dashboards Functionality to deal with the main RIF tab states. e.g. viewer, login. Core dashboard modals, divided into export, login, mapping, submission and viewer and then sub divided into: controllers, directives, partials and services
images Images used by the RIF, divided into: colorBrewer, glyphicon and trees
libs All third-party libraries - Hardwired in, do not use remote sources. Generally browserified code is is standalone and other libraries including RIF modified ones are in the root (libs)
modules Contains the definition of the RIF angular module
utils Functionality shared over more than one part of the RIF, divided into controllers, directives, partials and services

In the root there is also the index.html. Here all the paths to third-party libraries are given (i.e the local libs directory), all RIF specific JavaScript files, css etc. The placeholder for the Angular content is also defined within a div in the html body - “data-ui-view” and also the directive for the notifications bar. Dashboards is further split into five directories, these represent the tabs seen in the RIF GUI, also in the RIF main module, these are the five states defined in the “$stateProvider” (see below). The utils directory has functionality that is shared by more than one of these dashboards, this is mostly to do with mapping of results.

Contained within these directories are separate folders for Angular controllers, directives, partials and services for the relevant part of the RIF.

Naming Convention

All RIF specific files use the same convention: rif(type)-(usedby)-(description).(extension)

For example:

File types can be:

Suffix Description Extension
c Angular controller .js
d Angular directive .js
m Angular module .js
s Angular service or factory .js
p HTML partial .html
x CSS .css

rif[c/p/d/s]-<specific dashboard or utility>-<name> E.g:

They will be found in dashboards/submission.

The abbreviations [c/p/d/s] are:

The specific dashboard or utility is:

Libraries

Library Files
AngularJS 1.5.8 angular.min.js
- CSS-based Animations angular-animate.min.js
- Sanitize HTML. angular-sanitize.min.js
- ARIA attributes angular-aria.min.js
- Vslidation messages angular-messages.min.js
- Simple logger angular-simple-logger.js
- Material Design components angular-material.min.js, libs/standalone/angular-material.min.css
- UI Bootstrap modal windows ui-bootstrap-tpls-2.3.0.min.js, bootstrap.min.css
- UI Router state machine angular-ui-router.min.js
- UI Grid ui-grid.min.js, ui-grid.min.css
- UI Layout uui-layout.css, ui-layout.js
- Notifications bar ngNotificationsBar.css, ngNotificationsBar.min.js
- Pattern restriction ng-pattern-restrict.min.js
- Logging angular-simple-logger.js
Leaflet 1.0.3 leaflet.css, leaflet.js
- Draw leaflet.draw.css, leaflet.draw.js
- Fullscreen Leaflet.fullscreen.min.js, leaflet.fullscreen.css
- Map sync L.Map.Sync.js
- Map spinner spin.min.js, spin.js, spin.css, leaflet.spin.min.js
- Geosearch l.control.geosearch.js, l.geosearch.provider.openstreetmap.js, l.geosearch.css
- Opacity slider leaflet-slider.js, leaflet-slider.css
- Shapefile support leaflet.shpfile.js, shp.min.js
- Image export leaflet-image.js
- Condensed attribution leaflet-control-condensed-attribution.js
- Distances, linear referencing leaflet.geometryutil.js
Aynsc library async.js
TopoJSON topojson.min.js
- TopoJSON GridLayer: Created from Leaflet.GeoJSONGridLayer topoJSON.js, TopoJSONGridLayer.js
- PouchDB JavaScript database pouchdb.js
D3 v4 and D3 export d3.v4.min.js, canvas-toBlob.js, FileSaver.min.js
Turfjs modular geospatial engine turf.min.js
Proj4js coordinare transformer proj4.js
JSON5 parser json5.js
Simple Statistics sstatistics.js
Save html2canvas screenshots html2canvas.js
Parse, validate, manipulate, and display dates and times moment.min.js

The main module

rifm-app: The definition of the RIF angular module. This is where the “$stateProvider” states URLs are defined. These broadly relate to the dashboards selected by the tabs in the main RIF toolbar. All subsequent angular code chains to: angular.module(“RIF”).

The principal purpose of the main module is to control state using the UI Route state machine and:

CSS

The RIF specific CSS is a bit of a mess and may have a lot of redundancy. This was inherited from the old RIF prototype. Neither DM or PH had time to go through it properly. How the split containers refresh on resize and on browser resize is now much improved. The map tables do not have ui-layout and do not resize correctly. This is a known issue: #154 in ui-layout and not the RIF. IT is probably best fixed by fitting UI-layout to the map tables.

Alerts

Alerts are handled in rifc-util-alert, which is right up at the root (on the body of index.html) of all the so easily available by inheritance to all other controllers/scopes in the RIF. The use of inheritance does not work in services modules and can be hard to predict especially for directives where they are re-used. A service was therefore created: rifs-util-alert. rifc-util-alert uses the html attribute: notifications-bar. Some of the errors thrown by the middleware can be a bit weird and not informative. The middleware should provide more human readable error messages.

Alerts are of two types: permanent (which have to be closed) and auto closing after five seconds. There is a modal from the submission modal which can view all alerts for a session.

Alerts and debug messages are logged to the middleware in: FrontEndLogger.YYYY-MM-DD-n.log

Dashboards

Each dashboard for a user session has its state stored in a service (e.g. rifs-dmap-mappingstate). This is a singleton (with closure) and is not destroyed during a RIF session. The state service are used to either restore a user’s choices on state changes (which destroys scope and controllers), but also to restore the RIF defaults if needed. The save/load study functions reads and writes to these singleton states.

Each dashboard also has an html partial (e.g. rifp-dmap-main) which renders in div defined in index.html with the data-ui-view attribute. Changing the tab on the main RIF tab bar changes the state (rifc-util-tabctrl) as defined in the module (rifm-app).

Each dashboard has a main controller. These are often quite large and could be refactored in the future, in particular there is a lot of functionality that could be moved into services. For example, it is not very ‘angular’ to have code that does not deal directly with the UI in the controller. In general, code has been moved into new services, e.g. rifs-util-rif40-num-denom.js. Specific directives usually refer to a unique feature such as a D3 plot (e.g. rifd-dmap-d3rrzoom).

As an example, the Rif40NumDenomService service in rifs-util-rif40-num-denom.js contains the code to initialise the data required for the study submission. The initialise() returns a promise so the controller can wait for initialisation. This leads to the following recommendations:

Where there is shared functionality between dashboards, this is usually found in the utils directory. For example, choropleth mapping (rifc-util-choro), basemaps (rifc-util-basemap, available maps are defined in rifs-util-basemap), notifications (rifc-util-alert) etc.

Login

rifc-login-login: Calls the login method for the RIF database. Ensures all states (i.e. previous user inputs) are reset, initialises the taxonomy service. On success we transition to “state1”, i.e. the submission dashboard. On failure, we remain with the login page.

The logout method (click on the running man on the tool bar) is handled by (rifc-util-tabctrl) via a yes/no modal.

Note that:

Although there is little to be done about refresh, the back button should be trappable and the users asked if it is OK.

Submission

rifc-dsub-main: Initially makes several chained calls to the database to fill all drop-downs etc depending on the user. Once loaded, several other controllers are responsible for entering user defined submission data. These all appear in bootstrap modal pop-ups. Each “tree” has at least its own controller, often multiple controllers.

The results of user selections are stored in the relevant states (see the submission/services). On clicking “Run”, we use these states to populate a lump of JSON (rifs-dsub-model). This JSON object is then posted to the database with the submitStudy method in rifs-back-requests as submissionFile.txt. No actual calculations are done by the front-end. The save (rifc-dsub-save), reset (rifc-dsub-reset) and open (rifc-dsub-fromfile) RIF job methods work with this JSON and the associated state services.

Comparison and Study areas are defined with the same dialog defined by the maptable directive (rifd-dsub-maptable) launched by either the respective rifc-dsub-comparea or rifc-dsub-studyarea controllers. See rifs-dsub-model for how the areas selected are submitted - there is a key for “map_areas” in the JSON object relating to either study area or comparison area, within this an area object is stored with attributes: id, gid, label and band (for risk analysis).

So far this band attribute is not used as risk analysis cannot be done by the RIF backend yet. rifs-dsub-model also contains slots that vary depending if the study type is disease mapping or risk analysis (disease_mapping_study, risk_analysis_study). As risk mapping has not been done yet, how the two different study types are recognised may need to be thought through again. The database cannot handle “risk_analysis_study” and will throw an error. All this depends on how risk analysis will be handled in the database and middle ware.

Using rifd-dsub-maptable, areas can be selected at the required resolution:

The CommonMappingStateService (see: rifs-util-mapstate.js) stores map state, and removed a lot of code from the map table directive and maintains selected areas lists in both list and hash forms for efficient access. It is also used to implement intersection analysis. See also rifs-dmap-mappingstate.js which will be merged in time.

Investigation parameters is where the taxonomy service is used. This is a standalone service due to copyright issues with the ICD10 codes (we cannot distribute this on github). ICD 9 and 10 are the only services available; more taxonomies are planned to be incorporated. This dialog can now handle multiple covariates and additonal covariates. In future the modal could use set lists of ICD codes and support multiple investigations. The taxonomy list is a ui-grid table. UI-grid now supports “hierarchial” rows (in beta) and so the display could be improved to show a hierarchy, e.g. for C34:

Again, several calls are made to the middle ware (in rifc-dsub-params) to fill the drop-downs and results are saved in rifs-dsub-paramstate for submission. This part of the front-end will probably need the most work after the backend and middleware are updated.

Statistical methods (rifc-dsub-stats) selects which smoothing method to run. Possible methods are defined in the middleware (not hard-typed). So far we have HET, BYM, CAR and none. It is also possible to store parameters for the model, but this is not used at the moment.

Prior to submission, we can get an HTML formatted summary of the RIF job (rifc-dsub-summary) using the tags in rifc-dsub-model area table function. The model here is of JSON structure and is posted as a text file. To get the structure of this, use the ‘save’ option on the GUI to download a current job as a .json file. The model json structure has changed slightly in detail during RIF development, all changes are generally back compatible.

On submission, the job is run in the database behind the scenes. Clicking status (rifc-dsub-status) gives the status for a user’s RIF jobs. Status is also checked every 4 seconds to give a notification of completion of any pending jobs (this is done in by the tab controller rifc-util-tabctrl). This can report a study completing twice, this is because the main timer loop is “stacking” up and the code needs to be modified to prevent this.

Mapping and Viewer

These dashboards are very similar so will be explained together. During development, I could not get a straight answer as to what the difference with these should be and what actually is required, the two-tab approach is directly taken from Fred Fabbri’s initial prototype. Hopefully with some user feedback, the functionality of these should be refined.

The main difference is that the viewer allows a map and table view, while the mapper allows two maps and focuses on “bow-tie” plots of risks. Both allow choropleth mapping (rifc-util-choro) and changeable basemaps in Leaflet (rifc-util-basemap). Mapping and Viewer dashboards have their own main controllers (rifc-dmap-main and rifc-view-viewer), but the mapping itself is governed by the rifc-util-mapping controller as functionality is shared. The appropriate Leaflet container (div) is referenced as either “diseasemap1”, “diseasemap2” or “viewermap”.

Polygons are served up in topoJSON tiles as created by Peter’s tilemaker as an L.topoJsonGridLayer. This is very similar to handling normal geoJSON, just the call to the middle ware must be defined correctly: getTileMakerTiles. Once loaded, the tiled layer behaves as any geoJSON in Leaflet. This has since been extended to use bitmap tiles for all the areas in the geolevel not selected/part of a study. This code has only been fitted to the study and comparison selectors and requires more work to handle mous events efficiently.

The mapping initialisation code in the study and comparison area selector modals has been re-written as chained of promises and associated promise-ified functions. This has removed asynchronous races and this code is now more reliable. This also needs to be imnplemented for the mapping and viewer screens and the remaining mapping related code refactored into services. The asynchronous races in the map and viewer screens are the reason why the maps sometimes do not zoom to the selection and why automatic choropleth setup does not work.

There are a selection of mapping and selection tools as directives, see rifd-util-leafletTools. There are also tools to save the D3 plots to png (rifd-util-savechart). There exists a directive to save the Leaflet map with overlays in rifd-util-leafletTools (leafletToPng). This does not work very well and is inconsistent between browsers, it will need looking at. I think that it should actually be removed in favour of the export tools (explained later) or prompting the user to go full screen and use the screen dump (Print Scrn button) to clipboard.

(Note that the directive used for the map area submissions, rifd-dsub-maptable duplicates a lot of the functionality used here. It was always the intention to refactor rifd-dsub-maptable to be more consistent with rifc-util-mapping and its associated directives).

All D3 plots are dealt with using directives to define a new HTML element. Note that these still need wrapping in a $watch to allow them to refresh. Capturing the keyboard events in angular for multiple maps and D3 graphs was quite challenging, there may still be bugs here.

The processed study being mapped are selected via the drop-downs. There is an info button next to these to display study details (rifd-util-info). This needs some work still on the back-end as not all of the relevant information is stored and/or retrieved, see the method getDetailsForProcessedStudy.

Choropleth mapping uses colour scales defined by colorbrewer.org (rifs-util-colorbrewer). Category definitions follow the usual methods; equal interval, quantile etc (rifs-util-choro). The code to do the rendering is a bit messy and could do with a tidy (rifc-util-choro)

Export

To get all the results out of the RIF in a zip file (rifc-expt-export). All the zipping etc. is done in the middle ware. So far this exports the map table (RIF results) and the extract table (data used by the RIF to make the results) as csv files. The study and comparison areas are also exported as geoJSON files (text, can be loaded into any GIS and converted to a shapefile). Other tables could be exported here too, e.g. a formatted table for input to SatScan.

This dashboard also allows a quick preview of the data and the map areas. This would need modification after user feedback.

After user testing, there will be loads of requests as to what needs to be outputted (“what-the-old-RIF-did” etc. etc.)

An important change will be to save the MappingStateService (rifs-dmap-mappingstate.js) saved zoom latitude and longitude and also the choropleth map setting (ChoroService rifs-util-choro.js) in the database so they can be used to render the midleware maps as they are setup by the user.

Backend

Deals with everything related to the connection with the RIF postgres or sqlserver databases via the Java middleware.

Utilities

Controllers

File name Description
rifc-util-alert.js Alert bars and notifications over whole application
rifc-util-basemap.js Basemap selection modal
rifc-util-choro.js Choropleth map symbology modal used by viewer and mapper
rifc-util-mapping.js Map panels
rifc-util-multiselect.js Re-enables multiple selections on ui-grids. Selections on ui-grid are disabled
rifc-util-tabctrl.js Handles tab transitions, logout and alert on new study completion

Directives

File name Description
rifd-util-d3riskGraph.js Risk Graph
rifd-util-d3riskGraph3.js Common Risk Graph
rifd-util-info.js Get info on a completed study - also covariates loss and homogeneity report
rifd-util-leafletTools.js Shared Leaflet tools
rifd-util-preventRight.js Prevents right click in Leaflet maps
rifd-util-savechart.js Save D3 charts to a PNG

Partials

File name Description
rifp-util-basemap.html Basemap modal
rifp-util-choro.html Symbology modal
rifp-util-info.html Study info modal
rifp-util-yesno.html Yes-No user choice modal

Services

File name Description
rifs-util-alert.js Alerts functions. Calls Alert controller
rifs-util-basemap.js Supply pre-defined basemaps tiles to leaflet
rifs-util-choro.js Render choropleth maps using Colorbrewer
rifs-util-colorbrewer.js Colorbrewer (http://colorbrewer.org/)
rifs-util-d3charts.js D3 charts helper functions
rifs-util-exceptionOverwrite.js Override Angular exception handling, use the AlertService: disabled breaks Firefox
rifs-util-gis.js Basic GIS operations
rifs-util-JSON.js JSON - text conversions
rifs-util-leafletdraw.js Extend leafletdraw library
rifs-util-mapping.js Mapping helper functions
rifs-util-mapstate.js Stored map state: see also rifs-dmap-mappingstate.js which will be merged in time
rifs-util-maptools.js Adds tool icons to leaflet containers
rifs-util-projection.js CRSS database - get projection from SRID
rifs-util-rif40-num-denom.js Numerator denominator pairs by geography and health theme
rifs-util-selectstate.js Store state of selection modal
rifs-util-uigrid.js UI-Grid helper functions

Front End Issues

There are 53 open issues at 17/4/2019. Of these, 25 are relevant to the front end

Faults

Major Enhancements

Minor Enhancements

Fixed, but open as not tested sufficently

Peter Hambly, April 2019