Tutorial: Logger

Logger

Overview

Logger is an ol-ishare map that enables users to locate, and add a spatial reference to, their own information. This specialised map interface can be embedded within a CRM or other web application and requires two things: an iShare map profile and some Javascript knowledge.

Examples of its use include:

  • Reporting on faulty assets (e.g. street lights; bins; park benches)
  • Reporting potholes or issues related to public highways
  • Reporting incidents of fly-tipping
  • Reporting incidents of anti-social behaviour (e.g. graffiti; noise etc)
  • Inviting comment on public consultations

Configuration of all layer data, background maps, and address gazetteers is done in iShare Studio in exactly the same way as for other maps - if appropriate, Logger can use a profile created for another purpose, without modification.

Logger uses map layers in three different ways, they are:

  • target layers: these are used to determine where reports can be made on the map. If configured, a report will require a selection from one of the target layers, usually of point data (e.g. asset locations) or polygon data (e.g. constraining potholes to roads). If no target layers are configured then reports can be made anywhere on the map.
  • context layers: context layers allow useful additional data to be added to a Logger report. Feature data from these layers that intersects with the selection from a target layer (or the chosen location when no target layer configured) will be included in a report.
  • map layers: ordinary layers can be added to the map as with any other ol-ishare map. These do not get included in a report but might be useful to display to users, e.g. to highlight local landmarks. Any duplication with target or context layers will be ignored.

The report created by Logger is passed back to the embedding web application so that it can then submit the data, along with any other information entered by the user, into the relevant case management system. Reports can also be submitted into iShare for display on the map as ‘known incidents’.

Getting started

The following example shows how to create a Logger map for reporting on street lights.

Setup

Start with a HTML file which includes the required CSS and JavaScript, defines some basic styling and a map element that will contain the map.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Logger map for reporting on street lights</title>
    <meta
      name="viewport"
      content="initial-scale=1.0, user-scalable=no, width=device-width"
    />
    <link rel="icon" href="data:;base64,iVBORw0KGgo=" />
    <link
      rel="stylesheet"
      href="https://ol-ishare.services.astuntechnology.com/v1/apps/logger/logger.css"
    />
    <style type="text/css">
      html,
      body {
        height: 100%;
        padding: 0;
        margin: 0;
        font-family: sans-serif;
        font-size: small;
      }

      #map {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script src="https://ol-ishare.services.astuntechnology.com/v1/apps/logger/logger.js"></script>
    <script>
      // Logger code here...
    </script>
  </body>
</html>

CSS and JavaScript

The Logger CSS and JavaScript included in the page are bundles and include all dependencies such as OpenLayers.

CSS

The file logger.css includes all styles required to display a Logger map with default styles for controls, etc. — you can override these styles in your own CSS included after logger.css in the page.

<link
  rel="stylesheet"
  href="https://ol-ishare.services.astuntechnology.com/v1/apps/logger/logger.css"
/>
JavaScript

The file logger.js exposes a single global variable oli (short for ol-ishare) which exposes the ol-ishare JavaScript API. The constructor for the Logger map we will use shortly is available at oli.logger.LoggerMap.

The fact that the logger.js bundles its dependencies means embedding a Logger map is a matter of including a single JS reference. However, it does also mean that the API is limited to that of Logger itself - the OpenLayers API isn't exposed. Should you require access to OpenLayers then you've two options:

Create a LoggerMap

To create a LoggerMap in the #map element replace the empty <script> element in your html page:

<script>
  // Logger code here...
</script>

with the following JavaScript code:

    <script>
      var logger = new oli.logger.LoggerMap(
        // LiteMap options
        {
          target: 'map',
          iShareUrl: 'https://maps.demo.astuntechnology.com/',
          profile: 'mapsources/ol-ishare',
          layers: [],
          view: {
            easting: 500000,
            northing: 150000,
            zoom: 2000
          }
        },
        // LoggerMap options
        {
          reportOn: [{ layer: 'Street_lights', idField: 'fid' }],
          contextLayers: ['roadstrackspaths']
        }
      );

    </script>

The above code creates a new LoggerMap instance; the first object defines standard ol-ishare LiteMap options which include:

  • target - the id of an element on the page in which the map will be created
  • iShareUrl - the iShare Maps server to load data from (in this case the Astun Technology demo server)
  • profile - the iShare profile (also known as a MapSource) to load; the profile determines the available layers
  • layers - the names of any layers to display
  • view - the initial view of the map in the same coordinate system and units as the profile, in this case British National Grid in meters

ⓘ See the LiteMap options documentation for full details of the available options.

The second object defines Logger options:

  • reportOn - a list of target layers present in the profile that a users can make a selection from; each layer is represented as an object with two properties: layer, its name; and idField, the column containing a unique ID (used to identify a given feature, e.g. an asset number). In this instance we are reporting on the Street_lights layer, specifying the fid column.
  • contextLayers - (optional) names of layers from which to include details in a Report. Layers set here that are not already listed in mapOptions will be added to the map.

ⓘ See the Logger options documentation for full details.

At this point you should be able to open your html page in a browser and see a map showing street light features.

Logger events

A LoggerMap instance dispatches events for key interactions such as the user selecting a feature from a target layer. The LoggerMap class extends ol/Observable~Observable which provides methods such as on and un to subscribe and unsubscribe to events of a given type on an instance.

report event

When a user clicks on a street light in the map, Logger will emit a report event with an object containing all the selected map data.

To handle the report event add the following inside the <script> element directly below the JavaScript that creates the LoggerMap.

// Event handler for the Logger#report event
logger.on('report', function (evt) {
  console.info('Logger#report (event)');
  console.info(' - evt', evt);
});

The above code adds a report event handler to the LoggerMap instance (stored in the logger variable) as the first argument of the on method. The second argument is a function that in turn accepts an evt argument which provides information about the event.

ⓘ To see this in action, open your html page in a browser, open the browser's devtools Console tab and click on a street light on the map to see the evt object logged in the Console.

The report evt argument has a report property which is an instance of Report and has the following properties:

  • location - x, y coordinates of the click
  • selection - information about the selected target feature including it's uniqueId value, layer and the entire feature itself in GeoJSON format.
  • context - object with a key per layer name in contextLayers each of which is a GeoJSON FeatureCollection containing any features that intersect the location.

ⓘ The information provided by the report is commonly what is passed onto the parent web application (CRM, forms package etc.).

nothingSelected event

If the user does not click on a street light, then Logger emits a nothingSelected event in case the embedding application wants to show a reminder or warning to the user.

To handle the nothingSelected event add the following inside the <script> element directly below JavaScript that handles the report event.

logger.on('nothingSelected', function (evt) {
  console.info('Logger#nothingSelected (event)');
});

ⓘ To see this in action, click on the map at a location without a street light, this should trigger the event which will be logged in the devtools Console.

Handle multiple candidate selections

There will be times when the user clicks on a location which intersects multiple target features. In this case it's common to display a list of these candidate features to the user to allow them to select one to report on.

Logger allows for a number of functions to be set in LoggerMap options that allow the reporting workflow to be customised.

The LoggerMap options.selectAction property should be set to a function that will be called whenever multiple candidates are found, in order to determine which of them (if any) should be reported on.

To configure selectAction, update LoggerMap by replacing those currently specified.

The existing LoggerMap options:

    // LoggerMap options
    {
      reportOn: [{ layer: 'Street_lights', idField: 'fid' }],
      contextLayers: ['roadstrackspaths']
    }

Should be replaced with the following which also sets the selectAction property:

    // LoggerMap options
    {
      reportOn: [{ layer: 'Street_lights', idField: 'fid' }],
      contextLayers: ['roadstrackspaths'],
      selectAction: selectAction
    }

We then need to define the selectAction function that will be called by Logger, so add the following below the nothingSelected event handler code:

function selectAction(location, targetLayers, contextDetails, select, abandon) {
  console.info('Logger#selectAction');
  console.info('Logger#selectAction arguments:');
  console.info(' - location:', location);
  console.info(' - targetLayers:', targetLayers);
  console.info(' - contextDetails:', contextDetails);
  // Get a list of target layers that contain results
  var targetResultLayers = targetLayers.filter(function (l) {
    return l.selections && l.selections.length;
  });
  // Call `selected` with the first result in the first layer.
  // In a real implementation you might display the candidates to the user
  console.info(
    'Returning the first selection from the following candidates:',
    targetResultLayers
  );
  selected({ selection: targetResultLayers[0].selections[0] });
}

The selectAction function is given information about the location, selections from the target layers, and features from context layers. The selectAction function docs provide a full list of arguments including the select function which should be called in selectAction with the selection to report on.

ⓘ To see the selectAction function in action, zoom out so that you can see a cluster of street lights; clicking on the cluster should result in Logger identifying multiple candidate selections from the target layer, resulting in our selectAction function being called. This will log its arguments to the browser's devtools console before selecting the first candidate from the selections. In a real application the list of candidates would probably be displayed to the user.

Showing selections on the map

When a user selects a report or is choosing from a list of candidates it can be useful to zoom to the selections on the map and/ or highlight a given selection visually. The LoggerMap documentation provides details of methods such as highlightSelection, zoomToSelections etc..

Storage of reports in iShare

(Optional)(Compatible only with iShare v5.8.22 and above.)

In case there is a requirement to track Logger reports within iShare itself, ol-ishare provides Logger ReportsManager. Adding ReportsManager to an application requires no additional resources, but it is configured and used independently of LoggerMap.

To create a ReportsManager object to store reports from the above LoggerMap example add the following:

var streetlightReports = new oli.logger.ReportsManager({
  iShareUrl: 'https://maps.demo.astuntechnology.com/',
  profile: 'mapsources/ol-ishare',
  layerName: 'Street_lights'
});

Then update the handler for the 'report' event to store reports:

      // Event handler for the Logger#report event
      logger.on('report', function (evt) {
        console.info('Logger#report (event)');
        console.info(' - evt', evt);
      });
      streetlightReports.add(evt.report);
  };

Upgrades

Changes since beta.1

Action options

The selectAction option has been changed: the select callback must now return a single CompletedSelection object

Context layer options

The reportContext has been removed, and the behaviour of the contextLayers option has changed.

Previously the reportContext option had to be true in order for reports to contain data from context layers which, if not specified in contextLayers would be all non-target layers. This was considered confusing and has been removed in favour of always explicitly configuring each context layer.

Selection layer and object names

In the beta.1 version, target layers were referred to as asset layers, and Selection objects were called Asset objects. These have been renamed to better reflect the more general use to which they can be put. In addition, two function parameters have been retired as being considered superfluous.

The following LoggerMap configuration options have been changed as a consequence:

Old name New name Notes
autoAssetPicker (none) The selectAction function can be used instead
assetPicker selectAction
noAssetSelected (none) Add to, or create, a handler for the nothingSelected event

Changes since iShare Logger

Logger in ol-ishare is a ground-up rewrite of the most used capabilites of the decade-old Logger module in iShare, using lessons learned through many implementations, as well as modern technologies and development processes. As such it is a total replacement for the old Logger and does not have an upgrade path available from it.

In order to move from the old Logger to the new some implementation time will therefore be required. The remainder of this section outlines the major changes that will be needed.

Configuration changes

The old Logger required specialized map profiles with distinct and inflexible layer configuration. All Logger layer configuration within iShare should be recreated in a standard iShare MapSource.

Setup

There is no overlap between the setup for the two versions of Logger; treat a Logger upgrade as a new setup (due to all new embedded resources and a different way of creating a Logger map object).

Events

Interaction between the Logger map and the application in which it has been embedded is carried out through events. The way this works has changed substantially; jQuery is no longer used to emit or listen for events and the events themselves have been reworked or removed.

'logger_caseupdated'

The 'logger_caseupdated' event is the way that the old Logger would communicate that a selection had been made on the map through providing case objects. This is replaced by the 'report' event and Report objects:

case properties Equivalent in report event
lonlat location property
fields.assetid The exact equivalent is the selection.uniqueId property, but selection is a much more detailed and structured data object.
fields.caseid This has no direct correspondence in new Logger. 'Cases' as a concept have been removed as they were part of a paradigm that was little used in most implementations, where iShare/Logger would be part of the reporting workflow and would communicate through back-end web services.
fields.description Literally the description property, but this was often used to pass through additional information that is now available in the selection object and module:ol-ishare/logger.Context context.
'logger_setlayer'

There is currently no equivalent to this event, which was used to trigger a change in the Logger layer in use on the map.

'mapMoved'

There is no longer a custom Logger map event for map move events. Instead use the similar OpenLayers event 'moveend' (logger.map.on('moveend', function(evt){});), this returns an event object containing a reference to the map (evt.map) from which details such as the centre point can be derived.