Skip to content

Workspace Configuration

dbauszus-glx edited this page Jun 11, 2024 · 79 revisions

The workspace is a JSON document which defines locales, layers, and locations available to the MAPP library through the XYZ host.

This page provides an overview of the different configuration blocks contained within the workspace.

.dbs

A default workspace.dbs is the fallback database connection for any query which does not have an implicit dbs parameter. The dbs key-value must have a corresponding DBS_* environment variable.

.templates{}

The JSON workspace.templates{} holds template objects which can be referenced by their unique key.

Template

A template can be a view, layer, or query [module].

Templates are only available to the XYZ API and are used to assemble a JSON locale and layers for the MAPP client.

.template

The .template key-value is a string representation of a SQL [query] or html [view] template. If not implicit in the template definition a template string can be loaded from an external source.

.src

The workspace is assembled and cached upon initialisation of an XYZ process. The template src is a reference for XYZ API to load the template from an external source. The source formats are supported:

  • https: The template is loaded from a public URL.
  • file: The template is loaded from the local file system. The root being the application root, only files from the /public/* directory can be loaded as templates when deployed. On the localhost it is possible to prefix the file path with a double dot to step out of the XYZ repository and load templates from other folders like so: file:../resources_repository/templates/etc
  • cloudflront: The template will be loaded from the Cloudfront CDN. A KEY_CLOUDFRONT environment variable is required to provide signed access to secured Cloudfront ressources.

SRC_*

The Workspace API which assembles and caches the workspace will interpolate src strings prior to loading templates. A variable defined within a interpolation expression (${variable}) will be substituted with the corresponding SRC_* environment variable.

Query [template]

A query template is referenced in parameterised request to prevent SQL injection. The XYZ API will never directly accept SQL as a paramater. A SQL query template must be referenced in a query request with parameters for the query template string interpolation being validated by the XYZ API or substituted in the database.

"table_parameter_query": {
 "template": "SELECT * from ${table}",
},
"nnearest_locations": {
  "src": "file:/public/js/queries/nnearest_locations.sql",
  "dbs": "DEV"
},
"module_query": {
  "src": "file:/public/js/queries/infotip.js",
  "module": true,
  "dbs": "DEV"
},

.module

A template flagged as a module (.module = true) must be loaded from an external source. The Workspace API will compile a JS module directly from the [file] source.

.render()

A template render method cannot be assigned as a string value in the JSON workspace. The Workspace API will the Module.exports as the template .render() method when compiling a module from its source.

View [template]

Application views are html templates available to the View API

e.g. https://geolytix.dev/latest/view/embedded

"embedded": {
 "src": "file:public/views/embedded.html"
}

Layer [template]

Layer templates allow for the same layer to be used in multiple locales without the need to duplicate the layer JSON. The XYZ host will assign the layer JSON template to the layer JSON if referenced as layer.template key-value. Partials can be defined in the layer.templates[] array. Partials will be merged with the layer JSON instead of using Object.assign().

.locale{}

The workspace.locale{} is the master template for all locales in a workspace.

.locales{}

Each object referenced by its key in the workspace.locales{} object represents a locale available to the XYZ API. An array of available locales dependending on user role restrictions can be requested from the Workspace API. It is recommended to use simple [locale] keys for ease of programmatic use.

A template matching the locale key will be assigned to the locale JSON.

Available locales are listed for access in a dropdown in the default MAPP view. Without specifying a locale URL parameter.

Locale

A locale defines the functional and geographical extent of a mapview. A locale JSON object can be retrieved from the Workspace API and must be passed to the MAPP.Mapview decorator with the params argument. The default script will check whether any of the locale keys match MAPP.plugins and provide the mapview as well as the key argument to the plugin method.

.name

A locale is referenced by it's key. A name can be defined for display in the locales dropdown. The locale key is assigned as name if undefined.

.extent{}

The locale extent defines the geopgraphic limits of the mapview. It is not possible to pan the viewport outside the defined extent. The extent will also limit the min zoom. It is not possible to zoom out to a level where the viewport would exceeed the extent. The mapview beyond the extent will covered with a shade if the mask flag is set in the extent configuration.

"extent": {
  "north": 91,
  "east": 91,
  "south": 91,
  "west": 91,
  "mask": true
}

.view{}

The centre of the mapview view[port] will be set to the fit the locale extent. The view can be set to an implicit lat, lng, and z.

"view": {
  "lat": 91,
  "lng": 91,
  "z": 15
}

.minZoom

The .minZoom integer value will limit the mapview's minimum zoom level. The relevant mapview zoom control will be disabled if the MinZoom level is matched by the current viewport.

.maxZoom

The .maxZoom integer value will limit the mapview's maximum zoom level. The relevant mapview zoom control will be disabled if the MinZoom level is matched by the current viewport.

The .ScaleLine property in the mapview configuration allows you to specify the unit for the scale bar, enhancing the localization of the scale representation on the map.

Configuration Options

  • ScaleLine (string, optional): Specifies the unit for the scale bar. Acceptable values are 'metric' or 'imperial'. If not specified, the default value is 'metric'.

.gazetteer{}

A gazetteer can be configured for a locale to provide a query tool for locations referenced by a location property matching a search term. The mapp.ui library provides an input interface to display the gazetteer query response in a dropdown for selection.

.layer

A layer must be referenced by its mapview.layers key in order to query and get a location from the layer. Any current [layer] filter as well as role restrictions will apply.

.qterm

The qterm defines the field which will be queried for the search term.

"gazetteer": {
  "layer": "retailpoints",
  "qterm": "store_name"
}

Optional configuration keys are:

.table

Query this table instead of the layer table.

.placeholder

Set the gazetteer input placeholder. Can not be set within .datasets[].

.label

The field which will be returned in the results. By default this is the qterm, however it is possible to query one field but display a different field as label in the gazetteer results.

.title

The title is shown next to the records in the gazetteer results. The title tag will default to layer.name, or provider is not implicit.

.leading_wildcard

Whether the SQL search term should be prefixed with a wildcard [%].

.limit

Limits the maximum number of results per search/dataset. Defaults to 10.

.no_result

The result string to be shown for a gazetteer/dataset query which doesn't return any results. No result entry will be shown for no_result:null.

.maxZoom

Limits the zoom level when setting the mapview viewport for a location from a gazetteer search.

.provider [plugin]

It is possible to enable external gazetteer services through plugins. These services may require API keys and are documented in their respective plugin documentation.

Plugins for access to Google [Places] and Mapbox [Forward-Geocoding] are available in the MAPP repository.

A new location is being created from the external gazetteer response. The gazetteer.layer and qterm will be ignored for provider queries.

.datasets[]

Additional queries are made for each dataset defined in the datasets array. A placeholder or provider can not be defined in a dataset. The layer and limit parameter will be taken from the gazetteer configuration if not implicit in the dataset configuration.

"gazetteer": {
  "layer": "retailpoints",
  "qterm": "store_name",
  "leading_wildcard": true,
  "limit": 5,
  "datasets": [{
    "title": "Postcode"
    "qterm": "postcode"
  }]
}

.roles{}

The locale.roles{} defines which user roles have access to a locale. A role is referenced by its key in the roles{} object. A role key prefixed with an exlamation mark indicates a negated role. The role expression applies to all users which do not have the negated role.

.queryparams{}

The locale.queryparams{} will be assigned to the layer.queryparams{} and location entry.queryparams{}.

.locator

The .locator:true flag can be set to add a locator button to the MAPP default view button column.

.plugins[]

Plugins are javascript modules which are loaded and executed from src strings in the locale.plugins[] array.

"plugins": ["path/script.js"]

.syncPlugins[]

An array of plugin method keys can be defined to be executed synchronously prior to any other plugins being executed asynchronously. By default the array of plugin methods defines the order of the buttons for the default view as zoomBtn, admin, and login.

syncPlugins: ['zoomBtn', 'admin', 'login']

.[custom]{} mapview plugin

The MAPP default view script checks any locale keys against the mapp.plugins{} after a locale is used to initialise the mapview, but before layers are added to the mapview. The [custom] locale key-value is provided as first argument to the plugin method, and the mapview itself is provided as second argument.

.svg_templates{}

SVG templates defined in the locale.svg_templates{} are cached as string values available for parameter substitution through the svgSymbols utility.

"svg_templates": {
  "template_pin": "https://geolytix.github.io/MapIcons/pins/pink_master_pin.svg"
}

.listview_records[]

An array for the symbol and colour being assigned to mapview.locations{} when the location [view] is added to a locations.listview. This defaults to a list A to J with a non repetitive rainbow spectrum for the colours.

"listview_records": [
  {
    "symbol": "1",
    "colour": "#000000"
  },
  {
    "symbol": "2",
    "colour": "#DD0000"
  },
  {
    "symbol": "3",
    "colour": "#FFCE00"
  }
],

.layer{}

The layer JSON will be merged with the locale.layer{} when a layer is added to a mapview. The locale.layer{} acts as a master template for all layers in a locale. This allows to assign the same filter or draw defaults to every layer in a locale.

"layer": {
  "filter": {
    "current": {
      "country_code": {
        "match": "GBR"
      }
    }
  },
  "draw": {
    "defaults": {
      "country_code": "GBR"
    }
  }
}

.layers{}

Only layers within the locale.layers{} object are available within the context of a locale being used to initialise a mapview.

A layer is referenced by its key in locale.layers{}. A JSON locale requested from the Workspace API will contain an array of layer [keys] available to the user requesting the locale for a mapview.

A [layer] template whose key is matching a key in the .layers{} object will be assigned to the layer object when the JSON layer is requested from the Workspace API.

Layer

A JSON layer is a configuration object which can be added to a mapview. The MAPP library will decorate the JSON layer when it is added to the mapview to create a functional layer object which can be accessed through the mapview.layers list object.

.template

The layer object will be merged into a template which matches the layer key. Alternatively a template can be referenced by the template property.

.templates[]

Multiple templates can be assigned to the JSON layer. The Workspace API will merge these templates in order into the layer object.

Please note the reversed order: The layer is merged into a template. But templates are merged into the layer.

.name

If not set the JSON layer key will be assigned as the layer's name. The name is assigned to the header of a layer view.

.meta

The meta property value will be parsed as innerHTML for an element in the layer.view node.

.group

Layer views will be grouped in a layer listview group drawer. The key-value of the layer.group property will be assigned as the group element header.

.groupmeta

The layer.groupmeta property value will be parsed as innerHTML for an element in the layer.group node which contains the layer.view node.

.display

The layer.display will determine whether the layer is displayed as default when added to a mapview without a layers URL parameter overriding which set of layers should be displayed.

.hidden

The layer.hidden flag controls whether a layer view is created and shown in the layers listview. A layer without a view element is still accessible programatically through the mapview.layers{} object.

.toggleLocationViewEdits

By default all location [infoj] entries with an edit key are editable. Setting the layer.toggleLocationViewEdits will prefix all edit entries with an underscore character. A spanner icon will be added to the location.view header to toggle the edit entries.

.roles{}

Role objects within the layer.roles{} define which user roles have access to a layer. Any role object referenced by its key in the mapp.user.roles[] array will be merged with the JSON layer when the layer is decorated by the MAPP library. Likewise any negated role object will be merged if the user does not have the referenced role.

A .filter{} object can be defined within a role. This filter will always be applied by any query which references the layer.

The asterisk role (*) is a reserved role which will not be returned from the roles.get() method to the admin panel. Setting "*": true as a layer role simply makes the layer available to every user, even user without any roles. This does not have an effect merging, or filter associated with other roles on the layer.

"roles": {
  "*": true,
  "foo": true,
  "!point": {
    "draw": {
      "polygon": true
    }
  },
  "draw_role": {
    "draw": {
      "point": true
    }
  },
  "fascia_filter": {
    "filter": {
      "fascia": {
        "in": ["Budgens", "Waitrose"]
      }
    }
  }
}

.filter{}

The layer.filter{} object will be created if undefined when a layer is decorated.

layer.filter.current{} stores the currently applied filter to a layer. Current filter can be modified or removed through the layer.view filter panel.

The XYZ sqlFilter.js module will turn JSON filter into SQL [Postgres] filter expression.

.default

The layer.filter.default will always be applied in addition to any role or current filter. The default filter is looked up directly from the layer JSON and can not be modified by a client request. The default filter can be defined as string or object.

// default filter as string
"default": "(NOT retailer = ANY (ARRAY['Booths','Co-op']))"

// default filter as object
"default": {
  "retailer": {
    "ni": [
      "Booths",
      "Co-op"
    ]
  }
}

gte (greater than or equal) filter

A gte filter will pass records where the filter field has a numeric value which is equal or greater than filter value. In a gt filter the value must be greater than.

"field": {
  "gte": 10000
}
WHERE "field" >= 1000

lte (lesser than or equal) filter

A lte filter will pass records where the filter field has a numeric value which is equal or lesser than filter value. In a lt filter the value must be lesser than.

"field": {
  "lte": 10000
}
WHERE "field" <= 1000

in [array] filter

Table records will be passed if the field value is in the filter array.

"field": {
  "in": ["A", "B", "C"]
}
WHERE "field" = ANY(['A', 'B', 'C'])

ni (not in [array]) filter

Table records will be passed if the field value is not in the filter array.

"field": {
  "ni": ["A", "B", "C"]
}
WHERE NOT "field" = ANY(['A', 'B', 'C'])

match filter

The match filter will pass if a string matches an ILIKE expression.

"field": {
  "match": "st pauls"
}
WHERE "field" ILIKE 'st pauls'

like filter

Similar to the match filter, the like filter will add a wildcard character to the filter expression.

"field": {
  "like": "st"
}
WHERE "field" ILIKE 'st%'

boolean filter

A record will pass the filter expression if the boolean field value matches the filter.

"field": {
  "boolean": true
}
WHERE "field" IS true

null filter

A record will pass the filter expression if the field value is (or is not [false]) null.

"field": {
  "null": true
}
WHERE "field" IS NULL

.qID

Requests to the Location API require the field name for a unique location identifier.

.table

The table name for the layer data at rest.

.tables{}

Instead of the layer.table a layer.tables{} configuration object can be assigned to the JSON layer. The keys in the tables object representing an integer zoom level. The key-value is the table name for the keyed zoom level. A null value as the smallest or largest zoom key-value will make the layer unavailable at or beyond that zoom level. Without a null value the last defined table name in the tables object will be used.

{
  7: null,
  8: "schema.table_1",
  9: "schema.table_2",
  10: "schema.table_3",
  11: null
}

.geom

The field name which stores the feature geometries in the layer table.

.geoms{}

Instead of the layer.geom a layer.geoms{} configuration object can be assigned to the JSON layer. The keys in the geoms object representing an integer zoom level. The key-value being is the feature geometry field name for the keyed zoom level. The smallest or largest zoom level key-value will be assigned as geometry field in requests which are outside the specified zoom level range.

{
  8: "geom_50m",
  9: "geom_10m",
  10: "geom"
}

.z_field [filter]

Features will be filtered if the .z_field integer value is below the current zoom level.

"z_field": "field"

.srid

The SRID/EPSG projection code for the layer geometry field.

.[custom]{} layer plugin

Any layer keys are checked against the mapp.plugins{} and mapp.layer{} methods when a layer is decorated. The decorated layer object which must have a mapview property is provided as only argument to the plugin/layer method.

.deleteLocation

The deleteLocation: true flag indicates whether a location can be deleted from the layer's dataset.

.draw{}

Entries in the .draw{} configuration define which types of geometry are created by the mapview draw interaction.

A .label value can be assigned to each drawing method. The label will be displayed as button text which toggles the drawing interaction.

"draw": {
  "polygon": {
    "label":"Add New Polygon"
  }
}

.defaults{}

The field values defined as .defaults{} will set for the fields for a newly created location. The .defaults{} can be set directly in the .draw{} config or within the individual drawing method configurations.

"edit": {
  "point": true,
  "delete": true,
  "defaults": {
    "field": "default_value"
  }
}

.point

Creates a single point geometry. There are no additional configuration keys for the point geometry draw interaction.

.line

Creates a single linestring geometry.

.polygon

Creates a single polygon geometry.

.rectangle

Creates a single rectangular polygon by defining two opposing corner points.

.circle_2pt

Creates a single circular polygon by defining the centre and a point on the circle edge.

.circle

  • Creates a single circular polygon from a centre point and parameters that describe the extent of the circle.
  • Default params for the circle configuration panel can be overwritten.
  • Providing hidePanel:true will hide the radius and units panel from the user, instead allowing them only to draw a circle using the defined defaults, or specified configuration. e.g.
"circle": {
          "hidePanel": true,
          "label": "1km Catchment",
          "radius": 1000,
          "units": "meter"
        }

.locator

Creates a single point geometry on the current locator position. There are no additional configuration keys for the rectangle geometry draw interaction.

snap

If defined within the drawing type, the snap:true flag will configure the drawing interaction snapping to geometries from the draw layer. A layer key for another layer added to the same mapview can be provided instead.

"draw": {
  "polygon": {
    "snap": {
      "layer": "layer_key"
    }
  }
}

.[custom]{} layer.draw plugin

A custom draw method can be created by assigning the method to mapp.ui.elements.drawing{}.

.format

The layer.format defines the nature of a layer when being added to a mapview and decorated.

MVT (Mapbox Vector Tile)

The layer data is provided as tiles in the Mapbox Vector Tile format. Requests to the XYZ Layer API must reference the tile using /zoom/x/y slippy tile name. Tiles maybe cached in the .mvt_cache table. Cached tiles may not be used with layer filter and dynamic feature properties.

MVT features can have any geometry type.

MVT feature geometry must be SRID:3857.

"format": "mvt",
"mvt_cache": "table_name",

Vector (WKT, Geojson, Cluster)

The Vector format should be used for wkt, geojson and cluster formats. As of v4.7.2 the methods have been combined into vector.mjs for ease of maintainability.

"type": "vector",
"cluster":{
  "resolution":0.2,
  "distance": 10,
  "label": "field",
  "hexgrid": true
}, 
"fade": true

Parameters: layer.cluster - Object containing:

  1. resolution (optional) - Required for cluster format layers. This is a fraction of the average tile length at a given zoom level [z param].
  2. distance (optional) - Required for WKT format layers.
    NOTE - resolution and distance are mutually exclusive, you CANNOT use them together.
  3. label (optional) - The label field to use when clicking on a cluster, defaults to the layer.qID.
  • layer.hexgrid - A flag that if set to true, A hex grid aggregation will be applied.
  • layer.fade - A flag that if set to true, will fade the layer while requesting new data.

MapLibre

The maplibre library will be dynamically loaded if not found as global. An .accessToken must be provided to access private datasets and styles hosted by mapbox.

"mapbox_light": {
  "format": "maplibre",
  "accessToken": "XXXXX",
  "preserveDrawingBuffer": true,
  "style": {
    "zIndex": 98,
    "URL": "mapbox://styles/XXX/XXX"
  }
}

.queryparams{}

The layer.queryparams will be used assigned to layer queries and to location entry.queryparams{}. The locale.queryparams{} will be assigned to the layer.queryparams{}.

.panelOrder[]

The order of layer panel in the layer view can be controlled with the .panelOrder[] array.

The default order is:

.panelOrder: [
  'draw-drawer',
  'dataviews-drawer',
  'filter-drawer',
  'style-drawer',
  'meta'
]

.style{}

The style object defines how layer features are styled.

.default{}

The default style will be applied to every feature in a dataset. Other style objects will be assigned to this default style before sending the style object to the feature render.

"default": {
  "fillColor": "#d9d9d9",
  "fillOpacity": 0.5,
  "strokeWidth": 0.01,
  "strokeColor":"#d9d9d9"
}

.highlight{}

A highlight styling can be provided which is used when you hover over a geometry. This is useful to let the client know which geometry they are selecting.

 "highlight": {
  "fillColor": "#DBD56E",
  "strokeColor": "#000",
  "strokeWidth":1,
  "fillOpacity": 0.7,
  "scale": 1.3
}

.cluster{}

The cluster style is applied to features which account for multiple locations in close proximity which form a location cluster.

If the default styling is an SVG and the cluster as a non-SVG, make sure to add svg: null to the cluster object to allow this. You can provide clusterScale: null if you wish for the cluster to be a single size, and not resize based on how many points are within it.

"cluster": {
  "clusterScale": 0.8
}

.label{}

Label can be used to display feature properties as text elements in the mapview.

.title

The label.title will be displayed in the dropdown to switch the label or as title for the display toggle with a single label.

.display

Whether the label is displayed by default.

.field

The feature property to be displayed as label.

.count

Whether the location count should be displayed on cluster features which do not have a single property value.

.font

The size and font family to use. Defaults to "12px sans-serif".

.fillColor

The font colour.

.strokeColor & .strokeWidth

The colour and width of a halo for the text.

.minZoom & .maxZoom

Limits the zoom level range at which the label can be displayed.

.offsetX & .offsetY

The offset of the text from the feature geometry [centre].

"label": {
  "field": "name",
  "title": "Toggle Label Display",
  "display": true,
  "overflow": true,
  "count": true,
  "font": "12px sans-serif",
  "fillColor": "#ee4b2b",
  "strokeColor": "#fff",
  "strokeWidth": 3,
  "minZoom": 9,
  "maxZoom": 15,
  "offsetX": -10,
  "offsetY": 10
}

.labels{}

A label{} config with the key matching a style.label string will be assigned as default, otherwise the first of multiple style.labels{} will be assigned as style.label{} when the layer is decorated.

.hover{}

The style.hover{} config object defines a feature hover method. mapp.layer.featureHover() will be defined as style.hover.method() if not already defined.

.method{}

The hover method receives the feature, and layer as arguments from the mapview.highlight interaction.

.display

The display flag controls whether the query in the default featureHover() method will be executed.

.field

The field will be provided as parameter for the default infotip query template.

.query

The query template for the featureHover() method. Defaults to the 'infotip' template.

.title

The title for the hover interface in the layer style panel.

.legend{}

The .layout and alignment of the content for a theme legend can be configured in the theme.legend{} JSON.

"legend": {
  "layout": "flex",
  "alignContents": "centered"
}

.hovers{}

A hover{} config with the key matching a style.hover string will be assigned as default, otherwise the first of multiple style.hovers{} will be assigned as style.hover{} when the layer is decorated.

.theme{}

A layer can be styled according to its features' property values. The theme.type defines the lookup method for a style to be assigned to the layers default style for a feature.

A theme will be assigned from style.themes{} if the theme key matches a style.theme string value.

.title

The theme title will displayed in theme legend or themes dropdown. The style.themes{} key will be assigned as name if not implicit. It is recommended to use simple keys for all themes in favour of assigning a theme name for display.

.meta

The meta value will be rendered as innerHTML in legend element below the title.

.field / template

The field which must be assigned as a feature property in the layer data. Depending on the theme type the feature style will be assigned from a lookup in the theme.cat{} or theme.cat_array[]. A query template will be used in the dataset query if the field matches a workspace.templates{} key.

.setLabel

A label with the setLabel key value will be set as the style.label{} from the style.labels{} object.

.setHover

A label with the setHover key value will be set as the style.hover{} from the style.hovers{} object.

.type: "categorized"

A categorized theme can be used to assign a style object from a cat{} where the cat key matches a feature's [field] property value. The cat .label can be set for display in the theme legend.

"type": "categorized",
"field": "colour",
"cat": {
  "red": {
    "label": "Red"
    "style": {
      "fillColor": "#f00"
    }
  },
  "green": {
    "label": "Green"
    "style": {
      "fillColor": "#0f0"
    }
  },
  "blue": {
    "label": "Blue"
    "style": {
      "fillColor": "#00f"
    }
  }
}
.distribution.count

A distribution: count key-value pair added to a categorized thematic will use the simple-statistics library to only show options in the legend that are present in the viewport. This will show the number of that option in the thematic too:
Red [10]
Green [8]
The configuration developer will just provide the style for each category in the data, and then the count is generated using the data within the viewport.
NOTE - to use this on an mvt format layer, you will need to pass layer.wkt_properties:true.
NOTE - to use this on an wkt or geojson format layer, you will need to pass layer.params.viewport:true.
If you do not pass this, you will get the counts for the whole dataset and it will not update as you zoom in and zoom out.

"type": "categorized",
"field": "colour",
"distribution": "count",
"cat": {
  "red": {
    "label": "Red"
    "style": {
      "fillColor": "#f00"
    }
  },
  "green": {
    "label": "Green"
    "style": {
      "fillColor": "#0f0"
    }
  },
  "blue": {
    "label": "Blue"
    "style": {
      "fillColor": "#00f"
    }
  }
}

.type: "graduated"

A graduated theme can be used to assign a style object from a cat_array[] entry where feature's [field] property value is below the entry .value.

  • The legend object allows the legend to be styled differently.
    layout:flex will turn the legend into a flexbox instead of grid.
    alignContents will allow the contents to be aligned.
    horizontal: true will turn the legend from vertical to horizontal.
    nowrap: true will force all legend entries onto one line, rather than wrapping.
"type": "graduated",
  "legend": {
        "layout": "flex",
        "alignContents": "centered",
        "horizontal": true,
        "nowrap": true
},
"field": "rank",
"cat_arr": [
  {
    "value": 0,
    "label": "Nought",
    "style": {
      "fillOpacity": 0.1
    }
  },
  {
    "value": 10,
    "label": "below 10",
    "style": {
      "fillOpacity": 0.3
    }
  },
  {
    "value": 100,
    "label": "10 to 100",
    "style": {
      "fillOpacity": 0.6
    }
  },
  {
    "value": 999999999,
    "label": "above 100",
    "style": {
      "fillOpacity": 1
    }
  }
]
.distribution.jenks

A distribution: jenks key-value pair added to a graduated thematic will use the simple-statistics library to generate the breaks using a jenks classification.
The configuration developer will just provide the style for each break required in the data, and then the jenks breaks are generated using the data within the viewport.
NOTE - to use this on an mvt format layer, you will need to pass layer.wkt_properties:true.
NOTE - to use this on an wkt or geojson format layer, you will need to pass layer.params.viewport:true.

   "jenks": {
              "label": "Thematic",
              "type": "graduated",
              "distribution": "jenks",
              "field": "field_name",
              "cat_arr": [
                {
                  "style": {
                    "fillColor": "#f7fcfd"
                  }
                },
                {
                  "style": {
                    "fillColor": "#e5f5f9"
                  }
                },
                {
                  "style": {
                    "fillColor": "#ccece6"
                  }
                },
                {
                  "style": {
                    "fillColor": "#99d8c9"
                  }
                },
                {
                  "style": {
                    "fillColor": "#66c2a4"
                  }
                },
                {
                  "style": {
                    "fillColor": "#41ae76"
                  }
                },
                {
                  "style": {
                    "fillColor": "#238b45"
                  }
                },
                {
                  "style": {
                    "fillColor": "#005824"
                  }
                }
              ]
            }

.type: "distributed"

A distributed theme will assign style objects from the .cat_array[] array in a manner the reduces the likelihood of the same style being applied to neighbouring features. The theme method will distribute each style equally among the layer features. A field can be assigned to distribute cat values. The same field value will be assigned the same cat style. This is optional by default the feature property id will be used to distribute cat styles.

"type": "distributed",
"field": "id",
"cat_arr": [
  {
    "fillColor": "#f00"
  },
  {
    "fillColor": "#0f0"
  },
  {
    "fillColor": "#00f"
  }
]

.themes{}

Multiple theme{} configurations can be provided as layer.style.themes{}. With layer.style.theme defined as a string value a theme with matching key will be assigned as default when the layer is decorated. Otherwise the first entry will be assigned as the default theme. The theme can be changed with a dropdown input in the layer style panel.

.skip{}

It is possible to skip themes by using the skip:true flag. This is useful when you wish to remove a theme from a template.
The example below would skip the Fascia theme.

  "style": {
    "themes": {
      "Fascia": {
        "skip": true
      }
}

Style

style{}

.icon[]

The icon can be defined as an array where the first item in the array will be rendered first and subsequent items will be rendered on top. Default legend icons are rendered 24 by 24px. A legendScale must be applied to scale down the icons to fit into the default sized canvas.

"icon": [
  {
    "svg": "https://geolytix.github.io/MapIcons/pins/mint.svg",
    "scale": 2,
    "legendScale": 0.35,
    "anchor": [0.5, 1]
  },
  {
    "svg": "https://geolytix.github.io/mapp/icons/emblem.svg",
    "scale": 0.03,
    "anchor": [0.5, 1.6]
  }
]

.icon{}

.type

type: "target"

type: "diamond"

type: "dot"

type: "svg"

type: "template"

Location

A location is associated with the features that make up a layer. It is possible to get a location from the XYZ Location API by sending a request providing the locale, layer, and a location's unique ID.

.infoj_skip[]

The infoj_skip array allows you to define a list of keys, fields, or queries to be skipped from the infoj of that layer.

"infoj_skip": [
  "field_to_skip",
  "key_to_skip",
  "query_to_skip"
]

.infoj_order[]

The infoj_order array can be defined as a list of lookup keys and entry objects.

"infoj_order": [
  {
    "type": "dataview",
    "dataview": "tabulator",
    "target": "tabview",
    "query": "query_template",
    "table": {
      "layout": "fitColumns",
      "columns": [],
      "autoColumns": true
    }
  },
  "entry_key",
  "char_field",
  "textarea"
]

Key strings will be used to lookup entries in the location layer infoj array for matching key, field, or query key values. This allows for the sorting and filtering of infoj entries.

Entry objects in the infoj_order will be spliced and decorated with the location object in place.

.infoj[entry]

The infoj is the term used to describe the information we provide in the left-hand panel of the map window when you click on a geometry. This is an array of objects that make up what the user wishes to see.

.field

.fieldfx

Fieldfx allows you to alter the value displayed in the infoj. This is particularly useful if you wish to apply formatting to a number, convert values or change the field "ROUND(numeric_value,2)". This can be provided as an SQL query, but must all be provided on a single line. If you wish to provide an SQL query, you must ensure the WHERE clause includes WHERE id= $1.

SELECT ROUND(numeric_value2,2) FROM table_2 LEFT JOIN table_1 ON t1.id = t2.id WHERE id=$1

It is possible to query a json field key through the fieldfx using the json arrow notatrion. The following fieldfx will return the 'age' value from the json_field column.

"fieldfx": "json_field -> 'age'",

.jsonb_field / .jsonb_key

Using a combination of jsonb_field and jsonb_key allows to update individual key values in a json type column.

The following example uses the json arrow notation to extract the age value from the json_field. The field value must be unique in order to assign the value from the get location request to the correct entry.

{
  "field": "json_field_age",
  "fieldfx": "json_field -> 'age'",
  "jsonb_field": "json_field",
  "jsonb_key": "age",
  "edit": true
}

.json_field / .json_key

The combination of of json_field and json_key may be used to create editable entries for a single json key/value.

A type:json entry must be added to the infoj array. The json_field value will be used as lookup to identify the entry with the matching field value.

The location.update method will update the key/value in the json entry before updating the object in the location data at rest.

{
  "field": "json_field",
  "type": "json",
  "skipEntry: true
},
{
  "json_field": "json_field",
  "json_key": "age",
  "edit": true
}

.query

The query template to use for a query which will populate the entry.value

.queryparams{}

The queryparams are used to create the url params for a request to the Query API. The layer.queryparams{}, and locale.queryparams{} will be assigned to the entry.queryparams{}.

The following queryparams flags are reserved.

"queryparams": {
  "locale": true, // locale key.
  "layer": true, // layer key.
  "table": true, // layer table.
  "filter": true, // layer current filter.
  "z": true, // mapview current z.
  "viewport": true, // mapview [west,south,east,north] bounds.
  "center": true, // mapview lat/lng center.
  "email": true, // user email.
}

.run / .queryCheck

A query will be run by the infoj process and the response will be assigned as entry.value before the entry.type method is called.

.value

The entry.value will be populated from the field or fieldfx value in location get response, or from a entry.query response.

.title

The value to be rendered into the title element which is appended to the entry.node.

.css_title

The entry.css_title value will be applied as inline style to the title element inside the entry.node.

.css_val

The entry.css_val value will be applied as inline style to the value element inside the entry.node.

.tooltip

The value to show as a tooltip when hovering over the title.
This will also append an SVG of a question mark to the end of the title so the user is aware that it has a tooltip.

.inline

The value element will be displayed in a separate row below the title element. If entry.inline: true the title and value will be rendered in the same row in the location view entry.node.

.prefix

Prefix allows you to add a prefix to the start of the field value in the infoj. This is useful if you are displaying currencies. prefix: '£'

.suffix

Suffix allows you to add a suffix to the end of the field value in the infoj. This is useful if you are displaying percentages. suffix: '%'

.group

You can put infoj objects into a group to help break up the information. You must provide a group name to do this, which will be displayed above the first infoj object with that group associated to it.

.groupClassList

The group drawer will be expanded if any of the entries which are added to a location view group have the .groupClassList: "expanded" flag set. (Note: .expanded: true is deprecated)

.objectMergeFromEntry

The .objectMergeFromEntry value can be used to look up an entry with matching type. The lookup entry will be merged into the entry.

{
  "title": "Merge into this entry",
  "objectMergeFromEntry": "mergeEntry"
},
{
  "type": "mergeEntry"
  "title": "This title will overwrite the original entry title."
}

.class

The entry.class value will be concatenated as class[List] property for the creation of the entry.node element. Assigning the display-none class prevent the entry.node from being displayed.

.nullValue

If configured null will be replaced as entry.value with the entry.nullValue.

.skipEntry

The entry will not be processed by the infoj method if flagged as true.

.skipNullValue

The entry will not be processed by the infoj method if the entry value is null (entry.value === null).

.skipFalsyValue

The entry will not be processed by the infoj method if the entry.value is falsy, e.g. undefined, null ,NaN ,0 ,"" (!entry.value).

.skipUndefinedValue

The entry will not be processed by the infoj method if the entry.value is undefined (typeof entry.value === 'undefined').

.filter

If a filter is taking a long time to load on the MAPP instance and it is a numeric or integer field - apply the max and min settings and make sure to apply an index to that field on the table on the database.

Numeric

Creates a slider bar and manual input box to filter numeric values that are greater than and less than the provided values.

  • For numeric filters specifying the min and max makes the filter query faster as it saves two calculations on the data.
  • Although min and max are not a requirement for field definitions there are mandatory for fieldfx definitions.
  • Uses the numeric formatting of the infoj entry that the filter is applied to.
"filter": {
        "type": "numeric",
        "min": 123.45678,
        "max": 123456.78
      }

Integer

Creates a slider bar and manual input box to filter integer values that are greater than and less than the provided values.

  • For numeric filters specifying the min and max makes the filter query faster as it saves two calculations on the data.
  • Although min and max are not a requirement for field definitions there are mandatory for fieldfx definitions.
  • Uses the numeric formatting of the infoj entry that the filter is applied to.
"filter": {
        "type": "integer",
        "min": 123,
        "max": 123456
      }

Match

Creates a free text box that will filter on exactly what is provided in the text box with the database field value.
By default this will search for your search term only search_term.
To search for the search term and anything before it, add leading_wildcard: true. This will search for %search_term.

"filter": {
        "type": "match"
      }

Like

Creates a free text box that will filter the database field value where the value contains the data provided in the free text box.
By default this will search for your search term and a wildcard for anything following it search_term%.
To search for the search term anywhere in the field, add leading_wildcard: true. This will search for %search_term%.

"filter": {
        "type": "like"
      }

in [array]

An in[] of filter values can be configured. A distinct values query will be used without an array of filter values. A entry.field is required for layer filter. Returns a list of checkboxes by default to toggle the individual in [array] values. Can be defined as dropdown or searchbox UI filter elements.

"field": "table_column",
"filter": {
  "type": "in",
  "in": ["A", 1, "Foo"],
  "dropdown": true
}

ni [not in]

An ni[] of filter values can be configured. A distinct values query will be used without an array of filter values. A entry.field is required for layer filter. Returns a list of checkboxes by default to toggle the individual in [array] values. Can be defined as dropdown or searchbox UI filter elements.

"field": "table_column",
"filter": {
  "type": "ni",
  "ni": ["A", 1, "Foo"],
  "searchbox": true
}

Datetime

Provides a filter using a calendar which includes both the date calendar and date time.

"filter": {
        "type": "datetime"
      }

.objectAssignFromField

This allows you to use a query to build a json_object that can then be passed into an object in the infoj.

This is particularly useful if you wish to define the title using values that may change (ie you wish to display the year from a year field that can be updated).

Here, you first create an infoj object to define the title, and set it to display-none (so the user cannot see). This infoj object will have a fieldfx to create the json object.

Then, you create a second infoj object for the field value (perhaps a count for a year), and assign the objectAssignFromField to this.

This will then assign your title object to the infoj object.

If you wish to use the field from this within a filter you will need to provide a label for the filter within the filter block.

{
  "field": "pass_yr_minus_1_title",
  "fieldfx": "json_build_object('title',  concat(('April ',(current_year - 2)))",
  "type": "json",
  "class": "display-none"
},
{
  "field": "pass_yr_minus_1",
  "objectAssignFromField": "pass_yr_minus_1_title",
  "type": "integer",
  "inline": true,
  "filter": {
    "title": "Passengers (past year)",
    "type": "numeric"
  }
}

.type:"[custom]"{} location entry plugin

A plugin may add a custom entry method to mapp.ui.locations.entries{}. These entry methods behave the same as any entry method and will receive the entry itself as only argument. The location, layer, and mapview can all be inferred from the entry object.

key

The type: key entry will be displayed by the layer name in the location view.

{
  "type": "key"
} 

pin

The type: pin entry will create a labelled and coloured pin for the location. The value must resolve to a coordinate array matching the entry srid. The layer.srid is assumed as the default.

{
  "type": "pin",
  "field": "pin",
  "fieldfx": "ARRAY[ST_X(geom_p_4326), ST_Y(geom_p_4326)]"
}

text

The type:text is the default entry type which will be assigned if not implicit. The edit config supports a placeholder for the input element and to define the maxlength for the input.

"type": "text",
"edit": {
  "placeholder": "Input placeholder text",
  "maxlength": 7
}

textarea

The type:textarea will provid a multiline textarea input for editing. The edit config supports a placeholder for the input element and to define the maxlength for the input.

"type": "textarea",
"edit": {
  "placeholder": "Input placeholder text",
  "maxlength": 7
}

integer

The type: integer entry will parse the value as an integer.

{
  "field": "field_name",
  "type": "integer"
}

numeric

The type: numeric will parse the value as a float. A formatterParams object can be provided to configure a toLocaleString conversion of the value for display.

Typically this will just want to be maximumFractiondigits which is the number of decimal places.

Further options can be found Here, by default the locale is set to en-GB

{
  "field": "field_name",
  "type": "numeric",
  "formatterParams": {
      "options": {
          "maximumFractionDigits": 5
      },
      "locale": "en-GB"
  }
}

rounnd:int can be used as a shorthand for formatterParams.options.maximumFractionDigits

{
  "field": "field_name",
  "type": "numeric",
  "round": 1
}

date

type: date Adds a date infoj entry.

Database field must be of type bigint.

By default this will show as dd/mm/yyyy, hh:mm:ss.
To return just the date in format dd/mm/yyyy add the locale and options object.

{
  "field": "date",
  "type": "date",
  "locale": "en-UK",
  "options": {
    "year": "numeric",
    "month": "2-digit",
    "day": "2-digit"
  }
}

datetime

type: datetime Adds a datetime infoj entry.

Database field must be of type bigint.

By default this will show as dd/mm/yyyy, hh:mm:ss.
You can control this with the locale and options object.

{
  "field": "date",
  "type": "datetime",
  "locale": "en-UK",
  "options": {
    "year": "numeric",
    "month": "2-digit",
    "day": "2-digit"
  }
}

time

type: time Adds a timeinfoj entry.

Database field must be of type numeric or varchar.

{
  "title": "Time",
  "field": "time_field",
  "type": "time"
}

link

The type:link entry will create a node containing an icon and anchor tag (link). The default icon class is mask-icon open-in-new. The default label for the link is "Link". An URL path must be defined as entry.url. The URL parameter are constructed from the params object. The icon style can be set as inline style provided as icon_style string value.

{
  "type": "link",
  "icon_class": "mask-icon open-in-new",
  "label": "Link",
  "url": "https://geolytix.com",
  "params": {
    "param": "value"
  }
} 

query_button

Creates a button element in the location view which run a parameterised query. The host, query[template] and queryparams can be configured in the entry.

An array of dependents [fields] can be defined. The matching entry values will be synched after the query has been resolved.

{
  "label": "Snap to Postal Sector",
  "type": "query_button",
  "query": "catchment_statistics_snap_to_postal_sector",
  "queryparams": {
    "id": true
  },
  "alert": "Query has executed!",
  "reload": true,
  "dependents": [
    "geom_3857",
    "perimeter",
    "area"
  ]
}

report [legacy]

The type:report entry is a legacy configuration that will resolve without warning to a type:link.

html

type: html This will allow you to output HTML directly into the infoj field.
This is useful as we can use this to control colouring, and text-formatting of information in the infoj for that field.

{
  "field": "field_name",
  "type": "html",
  "fieldfx": "CONCAT('<a href=',field,'>Hyperlink</a></span>')"
}

title

type: title This will allow you to just define a title as that infoj entry.
There is an optional css_title key that can be used to control the styling of the title.

{
  "type": "title",
  "title": "This is a title",
  "css_title": "font-weight:400"
}

json

The type:json entry value is a json object. The SQL field must be type json to support a json entry. The edit interface will attempt to parse a json object before allowing to store a new value in the location data at rest. .json_field with .json_key entries can be used to update individual key/values in the json field.

{
  "field": "json_field",
  "type": "json",
  "edit: true
}

pills

The type:pills entry value requires an array value. The array values will be displayed as pills.

{
  "field": "arr_field",
  "type": "pills"
}

image

The type:image entry will show a thumbnail of an image from a cloudinary url stored as the entry.field value. If editable it is possible to delete the image or upload an image if the value is null.

A cloudinary_folder must be provided to determine the location where the images are stored.

{
  "field": "field_name",
  "type": "image",
  "cloudinary_folder": "folder_name",
  "edit": true
}

A valid CLOUDINARY_URL must be in the process env in order to upload or remove images.

images

The type:images entry will be displayed as a gallery of thumbnails in the location view. The thumbnails can be previewed by clicking. An interface to upload or delete images is available with the entry.edit:true flag.

A cloudinary_folder must be provided to determine the location where the images are stored.

{
  "field": "field_name",
  "type": "images",
  "cloudinary_folder": "folder_name",
  "edit": true
}

The field to store references for cloudinary resources must be defined as a text array in the layer table.

images text[] DEFAULT '{}'::text[]

A valid CLOUDINARY_URL must be in the process env in order to upload or remove images.

dataview

The type: dataview allow output to a chart or table to the infoj, tabview or a HTML location within a custom view (report).

Table Infoj Dataview

A Table Dataview returns a table. This uses the Tabulator Package to do so, please refer to the documentation for table formatting options.
Further Dataview Functionality may be present in the Dataview Section.

     {
      "label": "Table Infoj Dataview",
      "type": "dataview",
      "target": "location",
      "query": "query_name",
      "queryparams": {
        "id": true,
        "table": true,
        "filter": true
      },
      "table": {
        "layout": "fitColumns",
        "columns": [
          {
            "title": "Field",
            "field": "field"
          },
          {
            "title": "Value",
            "field": "value",
            "formatter": "toLocaleString"
          }
        ]
      }
    }

Here we can provide:

  • label(optional) - This generates a checkbox with the name in the infoj, without the label the dataview cannot be toggled on/off.
  • target - This can be tabview (the tab at the bottom of the MAPP), location (the infoj), or a HTML location ('html-dataview').
    The HTML location is used when we wish to draw a chart directly into a report.
  • SkipEntry: true(optional) - This is used when we wish to skip the drawing of the chart, this is used when we want to draw a dataview to a HTML location within a report.
  • queryCheck: true(optional) - This will check whether the query for the dataview returns data, and if not will disable the checkbox if one is provided, or hide the dataview from display.
  • display: true(optional) - This will set the dataview to automatically display, the default is false.
  • queryparams - This provides the parameters you wish to pass to a query.
    This is typically id: true to select just information for a particular location.
    You can also provide table: true which will provide the table defined on the layer. This is especially useful when using a template but defining the table for each locale within the layer.json.
    This requires the SQL query to contain FROM ${table} to ensure it only returns information from the relevant table location.
    You can provide filter: true which will pass the filters selected on the layer to the query. This requires WHERE true ${filter} to be added to the query.
  • formatter: toLocaleString- This will add thousand separators to the number (1000 becomes 1,000).
Chart Infoj Dataview

A Chart Dataview returns a chart. This uses the ChartJS Package to do so, please refer to the documentation for chart formatting options.
Further Dataview Functionality may be present in the Dataview Section.

 {
    "label": "Chart Infoj Dataview",
    "type": "dataview",
    "display": false,
    "target": "location",
    "query": "query_name",
    "queryparams": {
      "id": true,
      "table": true, 
      "filter": true
    },
    "chart": {
      "options": {
        "aspectRatio": 1.4,
        "indexAxis": "x"
      }
    }
 }

Here we can provide:

  • label(optional) - This generates a checkbox with the name in the infoj, without the label the dataview cannot be toggled on/off.
  • target - This can be tabview (the tab at the bottom of the MAPP), location (the infoj), or a HTML location ('html-dataview').
    The HTML location is used when we wish to draw a chart directly into a report.
  • SkipEntry: true(optional) - This is used when we wish to skip the drawing of the chart, this is used when we want to draw a dataview to a HTML location within a report.
  • queryCheck: true(optional) - This will check whether the query for the dataview returns data, and if not will disable the checkbox if one is provided, or hide the dataview from display.
  • display: true(optional) - This will set the dataview to automatically display, the default is false.
  • queryparams - This provides the parameters you wish to pass to a query.
    This is typically id: true to select just information for a particular location.
    You can also provide table: true which will provide the table defined on the layer. This is especially useful when using a template but defining the table for each locale within the layer.json.
    This requires the SQL query to contain FROM ${table} to ensure it only returns information from the relevant table location.
    You can provide filter: true which will pass the filters selected on the layer to the query. This requires WHERE true ${filter} to be added to the query.

geometry

The type type:geometry field value must be geojson. The geometry will be added to the mapview with the provided style. The location style will be assigned to the entry.style. The location.layer.srid will be assumed as projection if not implicit as entry.srid. A fieldfx function can be used to generate the required format in the location.get() request.

A draw config block can be defined in the entry root or within the edit block. Drawing will always be available if defined on the root or can be toggled with editing if defined in the edit block.

The entry will be skipped with the hideNoEdit flag set and editing disabled.

{
  "label": "Label",
  "field": "field_name",
  "srid": "4326",
  "fieldfx": "ST_asGeoJson(geom_4326)",
  "type": "geometry",
  "style": {
    "strokeColor": "#e65100",
    "fillColor": "#e65100",
    "strokeWidth": 2,
    "fillOpacity": 0.2
  },
  "dependents": ["pin"],
  "hideNoEdit": true,
  "edit": {
    "modifyBtnOnly": {
      "label": "Move Site"
    },
    "draw": {
      "polygon": true
    }
  }
}

MVT Clone

type: mvt_clone allows you to create an infoj object from a different format: mvt layer.
To use this, you must have a layer.json in the workspace.json that you wish to copy the thematic from.
This infoj object will then create a tickbox and the thematic from the other layer.json when you select the location.

  • zIndex (optional) - This allows control of the order of drawing. If the zIndex for the type: mvt_clone is higher than for the geometries on the location, then the type:mvt_clone thematic will be drawn on top.
  • display (optional) - When set to true the thematic will load automatically when you click on a location.
  • layer - This is the layer that you wish to clone the thematic from.
  • label - This is the label associated with the checkbox in the infoj.
  • query - This is a query to select only the relevant geometries from the same table as is used in the layer to clone.
    For instance if you click on a polygon and want to clone the thematic for hexagons that have a polygon_id associated to them, the query would be SELECT hexagons FROM table WHERE polygon_id=%{id}.
  • queryparams - This is the parameters for the query.
  • style - If left off will default to the style from the layer you are cloning from, otherwise will use the style provided.
{
  "type": "mvt_clone",
  "zIndex": 99,
  "display": true,
  "layer": "footfall_2021",
  "label": "Footfall Count",
  "query": "footfall_rp",
  "queryparams": {
    "id": true
  },
"style": {
  "theme": {
    "type": "graduated",
    "field": "glx_ff_21",
    "cat_arr": [
      {
        "value": "0",
        "label": "0 - 5,000",
        "style": {
          "fillColor": "#8BB9E4"
        }
      },
      {
        "value": "5000",
        "label": "5,000 - 25,000",
        "style": {
          "fillColor": "#a1ccbd"
        }
      }
    ]
  }
 }
}

Vector Layer

type: vector_layer allows you to create an infoj object from a query (this is the equivalent of mvt_clone but for point data).
This infoj object will then create a tickbox and when checked will draw the points to the mapview.
You can apply thematic styling to this layer and use labels as you can with other layer formats.

  • zIndex (optional) - This allows control of the order of drawing.
  • display (optional) - When set to true the points will load automatically when you click on a location.
  • label - This is the label associated with the checkbox in the infoj.
  • query - This is a query to select only the relevant geometries.
    This requires a particular format as it cannot be a src but must be a template
    NOTE - You need to return the geometry in the correct format for that layer type. e.g. wkt requires ST_AsText(geom).
"query_vector": {
     "template": "SELECT ST_AsText(geom_p_4326), thematic_field, thematic_label FROM table WHERE site_id=%{id}"
}
  • queryparams - This is the parameters for the query.
    You MUST pass reduce:true to the queryparameters.
  • style - The style for the points.
    Note, to use label and theme/themes you must pass params.fields array containing the fields used.
{
    "label": "Label",
    "type": "vector_layer",
    "format": "wkt",
    "srid": "4326",
    "display": true,
    "query": "query_vector",
    "queryparams": {
        "id": true,
        "reduce": true
    },
    "params": {
      "fields": [
        "thematic_field",
        "thematic_label"
      ]
    },
    "style": {
        "default": {
            "icon": {
                "type": "dot",
                "fillColor": "#f2fc"
            }
        },
       "label": { 
       "field": "thematic_label",
       "title": "Label"
       },
       "theme": {
        "title": "Thematic",
        "type": "graduated",
        "field": "thematic_field",
        "cat_arr": [
          {
            "value": 0,
            "label": "0 to 500",
            "style": {
              "fillColor": "#f7fcf5",
              "fillOpacity": 0.5
            }
          },
          {
            "value": 500,
            "label": "500 to 750",
            "style": {
              "fillColor": "#e5f5e0",
              "fillOpacity": 0.5
            }
         }
       ]
      }
   }
}

.edit{}

Editing is possible on locations, so the user could for instance alter a field name, add a comment or move a geometry and this would be stored to the database.

Adding toggleLocationViewEdits: true will add a spanner to the location entry that can be toggled for editing.

This is particularly useful if any of your fields use formatting or fieldfx.

This should be used as the default as it is much neater for the user.

It is also possible to edit field values within a location, and save these to the database.

"edit": true

.placeholder

If configured a placeholder will be set on the edit input element where available (eg. text, textarea, options)

"edit": {
  "placeholder": "Select from list",
  "options": ["A", "B"]
}

Options

Three options here:

  1. Provide defined options
"edit": {
 "options": ["A", "B"]
}
  1. Provide empty options array
    This will then use the distinct_values template to get all values from the field on the table as provide them.
"edit": {
 "options": []
}
  1. Provide query
    This will then run the provided query to get the values for the options.
    This query must in the workspace.templates object.
"edit": {
 "query": "edit_options",
 "options": []
}

Modifying Geometry

If you wish to edit geometry, then we must specify this in the edit object.

  "infoj": [
     {
      "type": "geometry",
      "display": true,
      "field": "geom_p_4326",
      "fieldfx": "ST_asGeoJSON(geom_p_4326)",
      "edit": {
        "geometry": true
      }
    }
  ]
ModifyBtnOnly
  • When you edit a geometry, you open up a panel to click modify geometry and then an extra button.
  • To avoid this, you can specify ModifyBtnOnly as true, which will give the user a single click to modify geometries.
  • The added benefit of this is that you can control the label defined on the button, giving the user a tailored label rather than the default 'Modify Geometry'.
"edit": {
    "geometry": true,
    "modifyBtnOnly": {
        "label": "Move Site"
    }
}

.dependents

Dependents allow us to set certain fields to be updated when another is edited.
For instance, if the user can edit type: geometry we may wish to set the type: pin as a dependent, so that the pin is always shown in the correct location.
We also set dependents on a field that is not editable by the user, but will be edited via a trigger on the database side.
Here you can provide an array of field values that you wish to reload upon changes to the field in question.

   {
      "type": "geometry",
      "display": true,
      "field": "geom_p_4326",
      "fieldfx": "ST_asGeoJSON(geom_p_4326)",
      "dependents": ["pin","field_1","field_2"],
      "edit": {
        "geometry": true
      }
    },

Dataviews

A Layer Dataview (chart or table) is linked to a particular layer. Here the query used to create the dataview would likely select all rows from the table associated with the layer.

These Layer Dataviews are created within the dataviews object in the layer.json file.

Table [dataview]

A Table Dataview returns a table to the tabview. This uses the Tabulator Package to do so, please refer to the documentation for table formatting options.

"dataview_key": {
  "target": "tabview",
  "display": true,
  "query": "query_name",
  "placeholder": "No Data Available",
  "queryparams": {
    "table": true,
    "filter": true
  },
  "viewport": true,
  "mapChange": true,
  "events": {
    "rowClick": {
      "util": "select",
      "layer": "uk_health",
      "zoomToLocation": true
    },
    "rowDblClick": {
      "util": "select",
      "zoomToLocation": true
    }
  },
  "table": {
    "selectable": true,
    "layout": "fitColumns",
    "columns": [
      {
        "title": "Field",
        "field": "field",
        "headerSort": false
      },
      {
        "title": "Count",
        "field": "value",
        "headerSort": false,
        "formatter": "toLocaleString"
      }
    ]
  }
}

Here we can provide:

  • Dataview Name - This generates a checkbox with the name provided in the Dataviews pane of the layer.
  • target: tabview - This generates the dataview in the bar on the bottom of the MAPP window.
  • display: true(optional) - This generates the dataview and but hides it from display. By default this is false.
  • placeholder(optional) - This will display the text string to the user when no data is returned.
  • selectable: true(optional) - This will allow the rows to be highlighted on hover
    This must be provided inside the tables object, and the query used must return an id column.
  • selectable: true must also be paired with the events object.
  • events - This allows you to provide any Tabulator event and a function to run when that event occurs.
    Typically we would want to provide rowClick: select which would perform a function on a single click.
    If we wish to return a location from a different layer (cross-layer selection), then within the event we need to provide the key of that layer (uk_health in the example above), otherwise it will just return the location within the current layer.
    We can also provide on double click to select and also zoom to that location.
  • viewport: true(optional) - This will only return locations within the viewport (the map window) display.
    The query must contain `WHERE true ${viewport}' for this to work.
  • mapChange: true(optional) - This will refresh the dataview each time you stop zooming or panning in the map display display.
  • queryparams - This provides the parameters you wish to pass to a query.
    You can provide table: true which will provide the table defined on the layer. This is especially useful when using a template but defining the table for each locale within the layer.json.
    This requires the SQL query to contain FROM ${table} to ensure it only returns information from the relevant table location.
    You can provide filter: true which will pass the filters selected on the layer to the query. This requires WHERE true ${filter} to be added to the query.
    But can provide whatever we want, perhaps a table or filter: true to ensure all filters are applied to the dataview.
  • formatter: toLocaleString- This will add thousand separators to the number (1000 becomes 1,000).

HeaderFilters

headerFilters are provided to allow the user to filter the information in the Tabulator tables.
We have 3 headerFilters:

  • set
  • numeric
  • like
  • date

Set

This returns a dropdown with multiple options of which any number can be selected.

  {
                    "title": "Field",
                    "field": "field",
                    "headerFilter": "set",
                    "headerFilterParams": {
                       "placeholder": "Select to Remove",
                       "distinct": true,
                       "layerFilter": true,
                       "type": "ni"
                     }
   }   

The headerFilterParams allow you to provide:

  • A placeholder that is used on the dropdown on initial load.
  • distinct: true which will return all values in that field on the database.
  • You may also provide options: ["A", "B"] instead of distinct:true.
  • layerFilter: true which will update the map with the filters applied within the table.
  • type: ni which will remove from the table those values selected. The default is type: in.

Numeric

This returns two input boxes Min and Max for numeric filtering.

  {
                    "title": "Field",
                    "field": "numeric_field",
                    "headerFilter": "numeric"
              
   }   

Like

This returns a free text box for filtering.

  {
                    "title": "Field",
                    "field": "field",
                    "headerFilter": "like"
              
   }   

Date

The field to use this on must be of type bigint. This returns two input boxes Min and Max for date filtering. A full list of formatterParams for dates can be found here.

{
    "title": "Field",
    "field": "date_field",
    "headerFilter": "date",
    "formatter": "date",
    "formatterParams": {
        "options": {
            "year": "numeric",
            "month": "numeric",
            "day": "numeric"
        }
    }
}

.toolbar{}

.clear_table_filters

Adds a toolbar button which will clear all current headerFilter.

"toolbar": {
  "clear_table_filters": true
}

.download_csv{}

Tabulator Download
  • The .download_csv can be set to a value of true which will just download the data using the built in Tabulator formatter on any Tabulator dataview.
  "dataviews": {
          "table": {
            "display": true,
            "target": "tabview",
            "query": "query_dv",
            "toolbar": {
              "download_csv": true
            },
            "table": {
             "autoColumns":true,
             "columns":[]
             }
MAPP.Utils.csvDownload
  • You can also specify a custom object for the download the data which will specify: the fields, the titles and the formats of these fields.
Optional Params
  • string: true - Add this to a field to escape any value (this is required to prevent the download incorrectly breaking lines at commas if they exist in a field value).
  • Header - To specify that the title of each field is used as the header column, pass a value of true, by default this is false.
  • Separator - To specify the separator, by default this is a comma.
  • Type - To specify the download type, by default this is UTF-8 CSV.
  • Join - To specify the join, by default this is '\r\n'.
  • Title - To specify the title, by default this is file.
"download_csv": {
  "title": "DOWNLOAD_TITLE",
  "header": true, 
  "fields": [
    {
      "field": "field_1",
      "title": "Field 1",
      "string": true
    },
    {
      "field": "field_2",
      "title": "Field 2"
    }
  ]
}

Chart [dataview]

A Chart Dataview returns a table to the tabview. This uses the ChartJS Package to do so, please refer to the documentation for chart formatting options.

   "Dataview Name": {
              "target": "tabview",
              "display": true,
              "query": "query_name",
              "queryparams": {
                "table": true,
                "filter": true
              },
      "chart": {
        "options": {
          "aspectRatio": 1.4,
          "indexAxis": "x"
        }
      }
    }

Here we can provide:

  • Dataview Name - This generates a checkbox with the name provided in the Dataviews pane of the layer.
  • target: tabview - This generates the dataview in the bar on the bottom of the MAPP window.
  • display: true(optional) - This generates the dataview and but hides it from display. By default this is false.
  • queryparams - This provides the parameters you wish to pass to a query.
    You can provide table: true which will provide the table defined on the layer. This is especially useful when using a template but defining the table for each locale within the layer.json.
    This requires the SQL query to contain FROM ${table} to ensure it only returns information from the relevant table location.
    You can provide filter: true which will pass the filters selected on the layer to the query. This requires WHERE true ${filter} to be added to the query.
Clone this wiki locally