Formulas

  1. Formulas
    1. Variables
    2. Boolean
    3. String
    4. Number
    5. Rating
    6. Date
    7. Time
    8. Instant
    9. Position
    10. Geometry
    11. Color
    12. Appearance
    13. List
    14. Switcher
    15. Attachment
    16. Control
    17. Any
    18. Meta functions

Variables

Formulas can work with variables, which use the field values of a location, referring to them by their key.

Warning: Fields’ keys might have a dash (-), but a formula would interpret that as a subtraction. To use a field that has a dash in its name either encapsulate it in backwards ticks (`my-variable` > 10) or refer to it in camel casing (myVariable > 10).

Check if a variable exists:

  • has(Variable): Bool, e.g., has(myVariable)
  • Variable == nil: Bool, e.g., myVariable == nil
  • Variable != nil: Bool, e.g., myVariable != nil
  • ??: Nil coalescing, e.g., unknownVariable ?? 'not found' == 'not found'

Boolean

Indicates true/false states.

You can use the built-in constants true and false to reference them, compare them using == or != and negate an expression by prefixing it with !.

String

A text, which can be short or long.

Create it by enclosing text in double quotes (") or single quotes ('), and you can concatenate it using a ‘+’, e.g., "Hello" + " world". You can also compare two strings using == or !=.

You can also extract characters of a string using [Number], e.g., "Hello"[0] == "H".

Note that Maparoni also handles text that is formatted as Markdown or as HTML.

Constants

id: String

The ID of the location in its collection.

Global functions

find(needle: String, haystack: String) -> String

Finds the first String in the second String, returning what was matched.

The first String is typically a regular expression, and the second one a (longer) field from which you want to extract something. Wrap what you want to extract in brackets.

Note: Before doing the look-up the second String will get whitespace and new-line characters removed at the beginning and end of each line.

Examples:

  • Number(find('=(.*)', 'Value=42')) == 42: Extracts the numeric value from the String, which is then also a String, and then turns it into a Number.
  • find('<td>Status</td><td>(.*?)</td>', htmlField): Finds the content within a td HTML tag that’s following one with has “Status” as its content. Note the ? in the grouping to do a non-greedy search.

matches(haystack: String, needle: String) -> Boolean

Checks if the first String matches the second expression. E.g., matches('Hello', 'H?llo') == true

Note: Before doing the match the first String will get whitespace and new-line characters removed at the beginning and end of each line.

Functions

String.capitalized: String

Turn the string into a capitalized version

String.characters: Number

Counts the total number of characters.

String.contains(String) -> Boolean

Returns if the String contains the provided String.

String.hasPrefix(String) -> Boolean

Returns if the String starts with the provided String.

String.hasSuffix(String) -> Boolean

Returns if the String end with the provided String.

String.in(strings: List) -> Boolean

Returns if the String is contained in the provided list.

String.lowercase: String

Turn the string into lowercase

String.prefix(maxLength: Number) -> String

Returns the prefix of String with a maximum length.

String.reverse: String

Reverses a string

String.suffix(maxLength: Number) -> String

Returns the suffix of String with a maximum length.

String.uppercase: String

Turn the string into uppercase

String.words: Number

Counts the total number of words.

Number

A number, which can have decimals.

Constants

index: Number

The index of the location within the collection.

Warning: This does not account for the current filtering or sorting of the collection.

pi: Number

π, the ratio of a circle’s circumference to its diameter.

Global functions

avg(numbers: List) -> Number

Returns the average value of all the numbers in the list.

count(List) -> Number

Returns the number of elements in the provided list.

Any nil elements in the list are not counted!

format(Number, mode: String) -> String

Formats a Number according to the specified formatting mode.

  • format(Number, 'distance'): Formats the number, which is interpreted as metres, as a distance according to the current locale, e.g., format(160000, 'distance') == '160km'
  • format(Number, 'fiveStars'): Turns the number into little stars, e.g., format(3, 'fiveStars') == '★★★☆☆'
  • format(Number, 'percent'): Turns the number into a percentage, e.g., format(0.5, 'percent') == '50%'
  • format(Number, 'significant'): Turns the number into a formatted rounded number with a limited number of non-zero digits, e.g., format(0.51241, 'percent') == '0.51'

max(numbers: List) -> Number

Returns the maximum value in the provided list.

min(numbers: List) -> Number

Returns the minimum value in the provided list.

sum(numbers: List) -> Number

Returns the sum of all the numbers in the list.

Constructors

Number(String) -> Number

Turns text into a number.

Functions

Number.abs: Number

Gets the absolute value.

Rating

Can be constructed using Rating/2, Number of Number or using a mixture of ★ and ☆ such as ★★★☆☆.

Note that ratings don’t have to be out of five stars, but can be out of any positive maximum value.

Ratings aren’t regular number as they have special arithmetic rules to combine them:

  • Rating + Rating: Adds two ratings by averaging them, e.g., ★★★☆☆ + ★★★★★ == ★★★★☆
  • Number * Rating: Multiplies a rating to give it more weight, e.g., (2 * ★★★★☆) + ★☆☆☆☆ == ★★★☆☆

You can compare numbers to number, too, such as ★★★★★ > 3 == true, which is short-hand for ★★★★★.score > 3 == true

Constructors

Rating(score: Number, max: Number) -> Rating

The first value is the score and the second is the maximum score, e.g., Rating(3, 5) == ★★★☆☆.

There’s also syntactic sugar to write Number of Number to do the same, or mix ★ and ☆ as in the example above.

Functions

Rating.maxScore: Number

Gets the maximum score, e.g., ★★★☆☆.maxScore == 5.

Rating.score: Number

Gets the score of a rating, e.g., ★★★☆☆.score == 3.

Date

A date as on the calendar, e.g., 15th of April 2015.

These are interpreted by Maparoni according to the device’s timezone.

Global functions

daysBetween(start: Date, end: Date) -> Number

Constructors

Date(String) -> Date

Turns a yyyy-MM-dd String into a Date.

Date(Instant) -> Date

Extracts the Date part of a Instant.

Date(String, format: String) -> Date

Turns a String into a Date using the provided date format.

Date(year: Number, month: Number, day: Number) -> Date

Turns three numbers representing year, month and day into a date.

Functions

Date.day: Number Date.month: Number Date.monthName: String

Full name of the Date’s month in the language your device is set to.

Date.weekday: String

Full name of the Date’s day of the week in the language your device is set to.

Date.weekdayEn: String

Full name of the Date’s day of the week in English.

Date.year: Number

Time

A time as on the clock, e.g., 22:30.

These are interpreted by Maparoni according to the device’s timezone.

Constructors

Time(String) -> Time

Turns an HH:mm String into a Time.

Time(hour: Number, minute: Number) -> Time

Turns two numbers representing hour and minute into a relative Time.

Time(String, format: String) -> Time

Turns a String into a Time using the provided date format.

Functions

Time.hour: Number Time.minute: Number

Instant

An instant reflects a single moment in time, e.g., the exact moment you were both or a combination of date, time and a place, such as 15th of April 2015 at 22:30 in Sydney, Australia.

While an instant itself is unambiguous, it can be represented as many different dates - depending on the timezone. When Maparoni displays an instant, it used the time zone of your device.

Constants

now: Instant

The current instant.

Global functions

format(Instant) -> String

Turns the provided Instant into a nicely formatted text.

format(Instant, format: String) -> String

Formats a Instant according to the specified format String.

Special case for setting the second parameter to “ago”.

Examples:

  • format(Instant, 'HH:mm'): Hours in 24h format, plus the minutes.
  • format(Instant, 'ago'): Nicely formatted duration between now and the instant.

Constructors

Instant(isoText: String) -> Instant

Turns a ISO8601 String into a Instant.

Instant(String, format: String) -> Instant

Turns a String into a Instant using the provided date format.

Functions

Instant.day: Number Instant.hour: Number Instant.minute: Number Instant.month: Number Instant.monthName: String

Full name of the Instant’s month in the language your device is set to.

Instant.weekday: String

Full name of the Instant’s day of the week in the language your device is set to.

Instant.weekdayEn: String

Full name of the Instant’s day of the week in English.

Instant.year: Number

Position

A geo-coordinate that represents a latitude/longitude pair anywhere on the planet.

Constants

area: Number

The area for locations with associated polygons, in square metres. Returns zero for others.

coordinate: Position

The centre coordinates of the location.

currentLocation: Position

The coordinates of your current locations.

If access to your current location was not provided, or if your current location could not be found, this will return nil (i.e., this will not return an error).

distance: Number

Returns the distance in metres of the location to your current location. For polygons, polylines and multi-points is the minimum distance.

Requires access to your current location, otherwise the formula will return an error.

latitude: Number

The latitude of the centre coordinate of the location.

length: Number

The length for locations with associated polylines, in metres. Returns zero for others.

longitude: Number

The longitude of the centre coordinate of the location.

Global functions

distance(to: Position) -> Number

Returns the distance in metres of the location to the specified coordinates. For polygons, polylines and multi-points it is the minimum distance.

Constructors

Position(String) -> Position

Creates a geographical coordinate extracted from the provided String.

Position(latitude: Number, longitude: Number) -> Position

Creates a geographical coordinate with the provided latitude and longitude.

Functions

Position.country: Appearance

Returns a geometry map style of the country that includes this coordinate, typically this is the country’s polygon(s)

Position.distance(to: Position) -> Number

Returns the distance in metres to the provided geo coordinate.

Position.flag: String

Returns the flag emoji of the country that includes this coordinate.

Position.latitude: Number

Returns the latitude component of the geo coordinates.

Position.longitude: Number

Returns the longitude component of the geo coordinates.

Position.lookup(database: String) -> Appearance

Returns a geometry map style by looking up the coordinate in the provided database

Position.lookup(database: String, field: String) -> String

Returns the value for the provided field by looking up the coordinate in the provided database

Position.country(Color) -> Appearance

Use Coordinate.country.fill(Color) instead

Geometry

A GeoJSON-compatible geometry, which can be one of: Feature, FeatureCollection).

Constants

geometry: Geometry

The GeoJSON geometry of the location.

LineString: Geometry

Creates a line (i.e., a GeoJSON LineString) of the provided coordinates.

If any of the arguments evaluate to nil, this function also returns nil rather than a line.

Polygon: Geometry

Creates a polygon of the provided coordinates.

If any of the arguments evaluate to nil, this function also returns nil rather than a polygon.

Global functions

geometryValue(json: String) -> Geometry

Parses the provided data field, which has to be a JSON object, as a GeoJSON geometry

Functions

Geometry.area: Number

Calculates the area for a geometry in square metres.

Geometry.center: Position

Returns a coordinate that’s on the geometry.

Note: This can be slow for complex lines and polygons.

Geometry.cluster(Color) -> Appearance

Specifies a cluster identifier to control whether nearby points can be merged into a single bubble when displaying them on the map. Only has an impact on points.

Geometry.fill(Color) -> Appearance

Applies the provided Color as the fill colour to each geometry. Only has an impact on points and polygons, for lines use .stroke instead.

Geometry.length: Number

Calculates the length of a geometry in metres.

For a lines, that’s the length, and for polygons, that’s the circumference.

Geometry.simplify: Geometry

Simplifies lines and polygons

Geometry.simplify(tolerance: Number) -> Appearance

Simplifies lines and polygons using the provided tolerance value.

Default is 0.01.

Geometry.stroke(Color) -> Appearance

Applies the provided Color as the stroke colour to each geometry. Only has an impact on lines and polygons, for points use .fill instead.

Geometry.stroke(Color, width: Number) -> Appearance

Applies the provided Color as the stroke colour to each geometry using the Number for the stroke’s width. Only has an impact on lines and polygons, for points use .fill instead.

Geometry.transform(targetGeometry: String) -> Appearance

Transforms the geometry into the provided target geometry.

Allowed values are GeoJSON geometries, and a couple extra ones: Feature, FeatureCollection, Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection, BoundingBox, ConvexHull. Not all of these will make sense or work, depending on your data.

The extra geometries do the following:

  • “BoundingBox” results in a the smallest rectangular polygon containing the original geometry.
  • “ConvexHull” results in a the polygon containing the original geometry with the minimum circumference, as if stretching a rubber band around it.

Color

Colours can be constructed using a CSS-like hex formats like #fff, #ff80ee or the RGB/3 and RGBA/4 functions. You can also reference a small number of built-in colours just by their names: white, grey (or gray), black, and red, orange, yellow, green, teal, blue, purple, pink, brown and indigo.

Global functions

gradient(value: Number, mode: String, min: Number, max: Number) -> Color

Creates a Color for the first number for a gradient mode between the provided start (third parameter) and end (forth parameter) values.

Available gradients:

  • 'alpha': Start is transparent, end is last color (i.e., requires a 5th parameter).
  • 'rainbow': Start is red, then goes via orange, yellow, green, blue, and indigo to purple.
  • 'traffic': Start is green, mid value is yellow, end is red.

You can provide a start value that is greater than the end to invert the gradient.

Examples:

gradient(-5, 'traffic', 0, 50) == green
gradient( 0, 'traffic', 0, 50) == green
gradient(25, 'traffic', 0, 50) == yellow
gradient(50, 'traffic', 0, 50) == red
gradient(99, 'traffic', 0, 50) == red

gradient(value: Number, mode: String, min: Number, max: Number, color: Color) -> Color

Creates a Color for the first number for a gradient mode between the provided start (third parameter) and end (forth parameter) values, using the provided end Color.

Available gradients:

  • 'alpha': Start is transparent, end is last color.
  • 'rainbow': Start is red, then goes via orange, yellow, green, blue, and indigo to purple. (Ignores last parameter.)
  • 'traffic': Start is green, mid value is yellow, end is red. (Ignores last parameter.)

You can provide a start value that is greater than the end to invert the gradient.

Examples:

gradient(-5, 'alpha', 0, 50, red) == RGB(255, 0, 0, 0.0)
gradient( 0, 'alpha', 0, 50, red) == RGB(255, 0, 0, 0.0)
gradient(25, 'alpha', 0, 50, red) == RGB(255, 0, 0, 0.5)
gradient(50, 'alpha', 0, 50, red) == RGB(255, 0, 0, 1.0)
gradient(99, 'alpha', 0, 50, red) == RGB(255, 0, 0, 1.0)

Constructors

Color(value: Any) -> Color

Creates a Color for the provided value.

For a String starting with ‘#’, it’ll try to interpret that first as a hex-encoded color. Otherwise it’ll use a random colour which will be the same for same values, but not necessarily the same across restarts.

RGB(red: Number, green: Number, blue: Number) -> Color

Creates an red-green-blue colour where each number should be in a range of 0 to 255.

RGBA(red: Number, green: Number, blue: Number, alpha: Number) -> Color

Creates an colour like RGB with an additional alpha component.

Functions

Color.alpha(percentage: Number) -> Color

Creates a colour updated with the provided alpha value (between 0 and 1)

Appearance

The appearance defines how a location is displayed on the map, defining both a geometric shape and a colour.

Some primary uses of this are drawing locations as dynamically-sized circles — defined as screen size in pixels or relative to the map in kilometres —, or displaying photo attachments right on the map.

This can even change the type of the location: A location might be saved to the collection as a single coordinate (i.e., with a specific latitude and longitude) but you can create a formula that instead draws it as a line from some other point. Or it might be saved on the collection as a polygon, but a formula can instead draw it as a pin (using a point centred in the polygon) or a bounding box.

Constants

linePoints: Appearance

Turns shapes into markers for every corners, with numbers inside representing their order in the line.

simplify: Appearance

Use geometry.simplified instead

Global functions

circle(radius: Number) -> Appearance

Show location as a circle annotation of the provided radius, which maintains the same radius as you zoom in and out.

circle(radius: Number, Position) -> Appearance

Show location at the provided coordinate as a circle annotation of the provided radius in screen points, which maintains the same radius as you zoom in and out.

fillColor(Color) -> Appearance

Applies the Color as the fill colour of each circle, or polygon. For markers use markerColor, and for lines use strokeColor.

fixedCircle(radius: Number) -> Appearance

Show location as a circle of the provided radius, where the radius is a fixed actual distance in metres from the centre, i.e., it’ll appear smaller or larger as you zoom in and out.

fixedCircle(radius: Number, Position) -> Appearance

Show location at the provided coordinate as a circle of the provided radius, where the radius is a fixed actual distance in metres from the centre, i.e., it’ll appear smaller or larger as you zoom in and out.

marker(letter: Any) -> Appearance

Show location as a pin with the provided letter

marker(letter: Any, Position) -> Appearance

Show location at the provided coordinate as a marker with the provided letter inside.

markerColor(Color) -> Appearance

Applies the Color as the colour of each marker. For circles and polygons use fillColor, and for lines use strokeColor.

strokeColor(Color) -> Appearance

Applies the Color as the stroke colour of each line, circle, or polygon. For markers use markerColor instead.

strokeWidth(Number) -> Appearance

Sets the stroke to a width of the provided Number in screen points for each line, circle, or polygon. Does not impact markers.

circle(radius: Number, Color) -> Appearance

Use circle(radius: Number).fill(Color) instead

colored(Color) -> Appearance

Use fillColor(color: Color).strokeColor(color: Color) instead.

colored(fill: Color, stroke: Color) -> Appearance

Use fillColor(fill: Color).strokeColor(stroke: Color) instead.

line(origin: Position) -> Appearance

Use LineString(coordinate, origin) instead

line(origin: Position, Color) -> Appearance

Use line(Coordinate).fill(Color) instead

pin(letter: Any, cluster: Any) -> Appearance

Use marker(letter: Any).cluster(Any) instead

pin(letter: Any, Color, cluster: Any) -> Appearance

Use marker(letter: Any, cluster: Any).fill(Color) instead

transform(geometry: String) -> Appearance

Use geometry.transform(targetGeometry) instead

Constructors

Appearance(Geometry) -> Appearance

Turns a GeoJSON geometry into a Appearance, so that it can get colours applied.

By itself, this doesn’t do much, but it can then be combined with other functions on the Appearance to colour it. For example, show the bounding box as thin green outlines by using:

Style(geometry.transform("BoundingBox"))
  .strokeColor(green)
  .strokeWidth(1)
  .fillColor(clear)

Functions

Appearance.cluster(Any) -> Appearance

Specifies a cluster identifier to control whether nearby locations can be merged into a single bubble when displaying them on the map.

Appearance.color(Color) -> Appearance

Applies the provided Color to each marker, line, circle, or polygon in the collection.

For more control over colouring, you can instead use .fillColor, .markerColor, and .strokeColor.

Appearance.fillColor(Color) -> Appearance

Applies the provided Color to each circle, or polygon in the collection. For markers use .markerColor, and for lines use .strokeColor instead.

Appearance.markerColor(Color) -> Appearance

Applies the provided Color to each marker in the collection. For circles and polygons use .fillColor, and for lines use .strokeColor instead.

Appearance.stroke(Color, width: Number) -> Appearance

Applies the Color to the stroke of each line, circle, or polygon in the collection, and sets the Number for the stroke’s width in points. Does not impact markers.

Appearance.strokeColor(Color) -> Appearance

Applies the Color to the stroke of each line, circle, or polygon in the collection. For markers use .markerColor instead.

Appearance.strokeWidth(Number) -> Appearance

Applies the Number for the stroke’s width to each line, circle, or polygon.

List

A list of any of the other types. Typically each element in the list should be of the same type as the others, but this is not enforced and lists of elements of mixed types are allowed.

Functions

List.contains(needle: Any) -> Boolean

Returns whether this list contains the provided value.

List.join(String) -> String

Combines a list of strings or numbers, by inserting the provided separator between each of them.

Any nil elements in the list are skipped and removed from the resulting list.

List.reverse: List

Reverses a list

List.sort: List

Sorts the provided List by their natural order, e.g., numerical or alphabetical.

Returns a list of numbers, if the input is all numbers, otherwise it’ll return a list of strings.

Any nil elements in the list are skipped and removed from the resulting list.

Examples:

sort([3,2,1,4,5]) == [1,2,3,4,5]
sort('3 🐅', nil, '20 🦁', '4 🐘') == ['3 🐅', '4 🐘', '20 🦁']

Switcher

A helper type for building switch statements.

Global functions

switch(value: Any, …) -> Switcher

The switch function checks specified expressions and returns a value based on the first condition that matches. Note: If no condition matches and the default/1 value is set, then that’s returned, otherwise nil is returned.

There are two ways to use this:

  1. switch/1 with a single parameter (the value), followed by different case/2 conditions, and, optionally, a default/1 value.
  2. switch/3+ with pairs of conditions and, optionally, a final default value.

Example (for more see case/2):

switch(distance)
  .case(..<2000, "🚶‍♂️")
  .case(..<10000, "🚴‍♀️")
  .default("🚌")

Functions

Switcher.case(pattern: Any, result: Any) -> Switcher

A condition for a switch/1 function, where the first argument is the pattern to match against the switch’s value and the second argument is the result to return, if the pattern matches.

What patterns you can use depends on the type of the switch’s value:

  • Boolean: true or false
  • Number: A Number, or ranges, e.g., 0...5, ..<500, 10..., ..<(150km)
  • String: A String, or a list of them.

Switcher.default(result: Any) -> Any

The value to return from a switch/1 function, when no case/2 condition matches.

Attachment

Represents attachments on locations, such as photo.

Global functions

photo(Attachment) -> Appearance

Show location as a photo.

photo(Attachment, Position) -> Appearance

Show location at the provided coordinate as a photo.

photoDate(Attachment) -> Date

The date an image attachment was taken, according to its EXIF or TIFF data.

Example: photoDate(maparoniPhoto), i.e., gets the capture date of the of photo in the default ‘Photo’ field (which has the key maparoniPhoto).

Control

An interactive control that will be placed in the user interface. The selected value will be passed back to the formula and evaluated.

Global functions

controlPicker(key: String) -> Any

Creates a picker control in the user interface for picking a value of the field with the provided ‘key’, which then returns the selected value.

controlRange(min: Number, max: Number) -> Any

Creates a range control in the user interface for picking a values range between ‘min’ and ‘max’, which then returns the selected range.

controlSlider(min: Number, max: Number) -> Number

Creates a slider control in the user interface for picking a value between ‘min’ and ‘max’, which then returns the selected number value.

Any

A metatype that says that any type can be used.

Global functions

has(Any) -> Boolean

Returns whether the location has the provided value. Same as checking key == nil.

value(key: String) -> Any

Returns the value for the provided key.

value(key: String, default: Any) -> Any

Returns the value for the provided key or, if it that key does not exist, the provided default.

Meta functions

When viewing multiple collections at once, you can also use these ‘Meta functions’ when organising the view. You can use this to provide information about the collection that each item is in, or you can use it to do cross-collection lookup.

Constants

collectionColor: Color

Color of the collection that contains the location.

collectionLetter: String

Letter/emoji of the collection that contains the location.

collectionName: String

Name of the collection that contains the location.

Global functions

container(collection: String) -> Any

Finds the first item in location named with the first parameter.

container(collection: String, key: String) -> Any

Finds the first item in location named with the first parameter, and returns the field with the same key as the second parameter.