Skip to main content

Box Property Expressions

Beginner users beware!

This guide is intended for advanced users of Enterprise Lens, who are comfortable with editing JSON and familiarising themselves with basic ideas featured in programming.

This guide also assumes you have built your illustrations using Name Associations.

In more complicated or intricate illustrations, you may want to extend the ability of your boxes beyond simply showing/hiding a value, border or style. For example you may want to:

  • Represent your boxes as a Gantt Chart or Bar Graph
  • Show additional information when you hover over a box
  • Change the appearance of a box or information according to the value of attribute(s)
  • Display attribute value(s) differently according to certain criteria

By the end of this guide, you should gain a holistic appreciation how Box Property Expressions work, and their various applications.

1. The Basics

Before we get started, we need to understand what Box Property Expressions are.

Definition

A Box Property Expression is a statement used to add or change the appearance of a box.

Box Property Expressions can only be created inside a specific type of Render Function, to do this:

  1. Open a Box Type in the Left Hand Menu
  2. Select the Attribute Types tab in the Edit Box Type Menu
  3. Edit an Attribute from the list provided
  4. Open the Render Functions tab in the new Edit Attribute Type Menu
  5. Either click Add or Edit next to an existing Render Function

From here, make sure to set the Render Function type to Set Box Properties from Expressions

Make sure to select the correct type

Without the correct Render Function type, the JSON featured later in this guide will not work!

An example render function





1.1. JSON Structure

The basic template for any Box Property Expression's Render Function looks like this:

{
"boxPropertyExpressions": {
"key": "expression"
},
"constants": {
"customkey": "value"
},
"variables": [
{
"name": "name",
"sourceType": "globalBoxChildrenById",
"globalBoxUuid": "UUID"
},
{
"name": "name",
"sourceType": "expression",
"expression": "variableexpression"
}
]
}
Important: You should understand how this JSON is being run

It's essential to understand the JSON structure above is being evaluated for every visible box that has this render function.

  • The boxes that have this render function are ones which have the same Box Type which has this Attribute, and subsequently this Render Function

Once the Render Function is turned on, the JSON is ran for each visible box from the perspective of the box.

  • Example: The render function has a box property expression to change colour where the attribute is low
    • Boxes with the render function will check inside themselves for the value of the attribute, if it is low, the colour of the box will change


1.1.1. boxPropertyExpressions

  1. The key references the box property you are changing to match the expression
  2. The expression references the expression you are setting to change that box property

Expressions can be comprised of simple statements, here are three examples:

Example 1. Change Text Colour
{
"boxPropertyExpressions": {
"textColor": "if (attr == \"Low\") { \"MediumSeaGreen\" } else { None }"
}
}

Here we have one expression which changes the Text Colour of a Box if the attribute is equal to Low.

  • textColor is the Box Property
  • if (attr == \"Low"\) { \"MediumSeaGreen\" } else { None } is the Expression
Example 2. Change Border Colour
{
"boxPropertyExpressions": {
"borderColor": "if (attr == \"Low\") { \"Blue\" } else { None }"
}
}

Here we have one expression which changes the Border Colour of a Box if the attribute is equal to Low.

  • borderColor is the Box Property
  • if (attr == \"Low"\) { \"Blue\" } else { None } is the Expression
Example 3. Change Text Size
{
"boxPropertyExpressions": {
"textSizeinPixels": "if (attr == \"Low\") { \"24\" } else { None }"
}
}

Here we have one expression which changes the Text Size of a Box if the attribute is equal to Low.

  • textSizeinPixels is the Box Property
  • if (attr == \"Low"\) { \"24\" } else { None } is the Expression

Here is what that all three examples look like put together.

Example 4. Change Text Colour, Size, and Border Colour
{
"boxPropertyExpressions": {
"textColor": "if (attr == \"Low\") { \"MediumSeaGreen\" } else { None }",
"borderColor": "if (attr == \"Low\") { \"Blue\" } else { None }",
"textSizeinPixels": "if (attr == \"Low\") { \"24\" } else { None }"
}
}

Here you can see the previous three expressions merged together. You can view the explanation for any one of these by clicking on the previous dropdowns.



1.1.2. Constants

These are static pieces of information that you can reference in box property expressions and variables.

Modifying our previous examples, we can use constants like so:

Example 1. Change Text Colour
{
"boxPropertyExpressions": {
"textColor": "if (attr == constants.criteria) { \"MediumSeaGreen\" } else { None }"
},
"constants": {
"criteria": "Low"
}
}

The expression has been modified to check if the attribute equals the criteria constant:

  • To reference a constant
    • First define it below the box property expression. Note the syntax used above
    • Insert constants. followed by the name of the constant wherever you wish to reference it
  • In this case, the constant criteria was referenced in the Box Property Expression
    • criteria is set to low, so the expression is still checking if the attribute is low (same as before) and setting the Box Text Colour to Green if it is low
Example 2. Change Border Colour
{
"boxPropertyExpressions": {
"borderColor": "if (attr == constants.criteria) { \"Blue\" } else { None }"
},
"constants": {
"criteria": "Low"
}
}

The expression has been modified to check if the attribute equals the criteria constant:

  • To reference a constant
    • First define it below the box property expression. Note the syntax used above
    • Insert constants. followed by the name of the constant wherever you wish to reference it
  • In this case, the constant criteria was referenced in the Box Property Expression
    • criteria is set to low, so the expression is still checking if the attribute is low (same as before) and setting the Border Colour to Blue if it is low
Example 4. Change Text Size
{
"boxPropertyExpressions": {
"textSizeInPixels": "if (attr == constants.criteria) { \"24\" } else { None }"
},
"constants": {
"criteria": "Low"
}
}

The expression has been modified to check if the attribute equals the criteria constant:

  • To reference a constant
    • First define it below the box property expression. Note the syntax used above
    • Insert constants. followed by the name of the constant wherever you wish to reference it
  • In this case, the constant criteria was referenced in the Box Property Expression
    • criteria is set to low, so the expression is still checking if the attribute is low (same as before) and setting the Text Size to 14 pixels if it is low

Here is what all three examples look like put together.

Example 4. Change Text Colour, Size, and Border Colour
{
"boxPropertyExpressions": {
"textColor": "if (attr == constants.criteria) { \"MediumSeaGreen\" } else { None }",
"borderColor": "if (attr == constants.criteria) { \"Blue\" } else { None }",
"textSizeInPixels": "if (attr == constants.criteria) { \"24\" } else { None }"
},
"constants": {
"criteria": "Low"
}
}

Here you can see the previous three expressions merged together. You can view the explanation for any one of these by clicking on the previous dropdowns.

All expressions share the same constant

The same constant is reused as all expressions check if the attribute is Low, eliminating the need to define three constants.



1.1.3. Variables

These are expressions that can be referenced in other variables and box property expressions.

This is particularly useful when you want to clearly break up your expressions and set things out in a logical order.

Adding onto our previous examples, here is what a new variable could look like:

Example 1. Change Text Colour
{
"boxPropertyExpressions": {
"textColor": "variables.evaluate_criteria"
},
"constants": {
"criteria": "Low"
},
"variables": [
{
"name": "evaluate_criteria",
"sourceType": "expression",
"expression": "if (attr == constants.criteria) { \"MediumSeaGreen\" } else { None }"
}
]
}

Notice how the box property expression has changed:

  • A variable has been referenced
    • The variable, called evaluate_criteria was defined below the constants
      • It's sourceType is an expression, this allows the variable to evaluate an expression
      • In the expression field, we inserted the previous statement:
        • if (attr == constants.criteria) { \"MediumSeaGreen\" } else { None }
    • The variable was then referenced in textColor by entering variables. followed by the name (evaluate_criteria)
Example 2. Change Border Colour
{
"boxPropertyExpressions": {
"borderColor": "variables.evaluate_criteria"
},
"constants": {
"criteria": "Low"
},
"variables": [
{
"name": "evaluate_criteria",
"sourceType": "expression",
"expression": "if (attr == constants.criteria) { \"Blue\" } else { None }"
}
]
}

Notice how the box property expression has changed:

  • A variable has been referenced
    • The variable, called evaluate_criteria was defined below the constants
      • It's sourceType is an expression, this allows the variable to evaluate an expression
      • In the expression field, we inserted the previous statement:
        • if (attr == constants.criteria) { \"Blue\" } else { None }
    • The variable was then referenced in borderColor by entering variables. followed by the name (evaluate_criteria)
Example 3. Change Text Size
{
"boxPropertyExpressions": {
"textSizeInPixels": "variables.evaluate_criteria"
},
"constants": {
"criteria": "Low"
},
"variables": [
{
"name": "evaluate_criteria",
"sourceType": "expression",
"expression": "if (attr == constants.criteria) { \"24\" } else { None }"
}
]
}

Notice how the box property expression has changed:

  • A variable has been referenced
    • The variable, called evaluate_criteria was defined below the constants
      • It's sourceType is an expression, this allows the variable to evaluate an expression
      • In the expression field, we inserted the previous statement:
        • if (attr == constants.criteria) { \"24\" } else { None }
    • The variable was then referenced in textSizeInPixels by entering variables. followed by the name (evaluate_criteria)

Here is what all three examples look like put together.

Example 4. Change Text Colour, Size, and Border Colour
{
"boxPropertyExpressions": {
"textColor": "variables.evaluate_text_colour_criteria",
"borderColor": "variables.evaluate_border_colour_criteria",
"textSizeInPixels": "variables.evaluate_text_size_criteria"
},
"constants": {
"criteria": "Low"
},
"variables": [
{
"name": "evaluate_text_colour_criteria",
"sourceType": "expression",
"expression": "if (attr == constants.criteria) { \"MediumSeaGreen\" } else { None }"
},
{
"name": "evaluate_border_colour_criteria",
"sourceType": "expression",
"expression": "if (attr == constants.criteria) { \"Blue\" } else { None }"
},
{
"name": "evaluate_text_size_criteria",
"sourceType": "expression",
"expression": "if (attr == constants.criteria) { \"24\" } else { None }"
}
]
}

Here you can see the previous three expressions merged together. You can view the explanation for any one of these by clicking on the previous dropdowns.

Same constant but different variables

Given each criteria evaluates a different outcome, each criteria is given a unique variable to be referenced in their respective box property expressions.

The same outcomes are achieved, but instead the individual expressions are shifted inside variables. The box property expressions are shorter because it references the variable, which will either return the colours/sizes or nothing at all.



1.1.4. Illustration Example

Using the final combined JSON featured in 1.1.3. we can see how this looks in practice.

  • Download this illustration by clicking here.

Illustration Example

In this example, we applied the expression to the Priority attribute.

  • When turned on, the render function is ran per box
  • Each box checks itself to see if Priority is set to Low (Priority == Low)
    • If Priority is set to Low, the expression is TRUE and the following occur:
      • textColor is set to MediumSeeGreen
      • borderColor is set to Blue
      • textSizeInPixels is set to 24
    • If Priority is not set to Low, the expression is FALSE and the following occurs:
      • textColor is set to None
      • borderColor is set to None
      • textSizeInPixels is set to None
      • Since we haven't defined None anywhere, all the above properties do not get changed and remain their defaults

Clicking on Box 1, which has green text, you can see the Priority attribute is set to Low.

Basic illustration's attribute

2. Aggregation

A use case for Box Property Expressions is the ability to run arithmetic across ranges of boxes, this is what's known in Enterprise Lens as aggregation.


Remember

Aggregation is still done via a Box Property Expression, run from the perspective of the box type that contains the Render Function.


  • In order for arithmetic to be useful, we usually confine the arithmetic we run to specific ranges of boxes

    • The most common way we do this is by imposing restrictions on an Associations basis
  • Two common ways to restrict the range of boxes to do arithmetic on are:

    • First Level Boxes
    • Second Level Boxes

Both levels of aggregation are explained below.

2.1. First Level

This is where you aggregate the immediate boxes that join the boxes containing the Aggregate Render Function.

  • e.g. "I would like to count the Project boxes that contain a Cost, which belong to their respective Business Functions"
  • e.g. "I would like to count the Project boxes, which belong to their respective Business Functions"
  • e.g. "I would like to add the Costs of Application boxes, which belong to their respective Business Functions"
Where the Render Function belongs

In all these scenarios, the Project/Application boxes belong to the Business Functions.

Since Business Functions are the highest level in these scenarios, we make the Aggregate Render Function on the Business Functions Box Type.


2.2. Second Level

This is where you aggregate the boxes that join to the immediate boxes, which in turn join to the boxes with the Arithmetic Render Function.

  • e.g. "I would like to count the Project boxes that contain a Cost, which belong to their respective Business Functions, which in turn belong to their respective Business Strategies"
  • e.g. "I would like to count the Project boxes, which belong to their respective Business Functions, which in turn belong to their respective Business Strategies"
  • e.g. "I would like to add the Costs of Application boxes, which belong to their respective Business Functions, , which in turn belong to their respective Business Strategies"
Where the Render Function belongs

While the Project/Application boxes belong to the Business Functions, we have specified that those Business Functions belong to Business Strategies.

Since Business Strategies are the highest level in these scenarios, we make the Aggregate Render Function on the Business Strategy Box Type.


2.3. Render Function

The below render function should be considered your starting point to building any aggregate, we will first explain how it works before sharing the numerous ways to modify it.

{
"boxPropertyExpressions": {
"badge24": "{ \"text\": variables.rounded_aggregate, \"horizontalPositionInPercent\": 50, \"verticalPositionInPercent\": 100, \"verticalAlignment\": \"none\", \"horizontalAlignment\": \"none\", \"borderRadius\": 5, \"backgroundColor\": \"Tomato\", \"textColor\": \"White\", \"width\": \"20%\", \"height\": \"20%\", \"fontFamily\": \"Arial\", \"textSizeInPixels\": 16 }"
},
"constants": {
"association": "association_attribute_name",
"number_1": "1st_attribute_name",
"number_2": "2nd_attribute_name",
"number_3": "3rd_attribute_name"
},
"variables": [
{
"name": "boxes",
"sourceType": "globalBoxChildrenById",
"globalBoxUuid": "boxes_uuid"
},
{
"name": "aggregate",
"sourceType": "expression",
"expression": "variables.boxes.sum(b => (toNumber(b[constants.number_1]) + toNumber(b[constants.number_2]) + toNumber(b[constants.number_3])) * (strCount(b[constants.association], current.Name) > 0))"
},
{
"name": "rounded_aggregate",
"sourceType": "expression",
"expression": "round(variables.aggregate, 2)"
}
]
}

2.4. Box Property Expression

Notably, the only box property key being modified is badge18.

  • This specific badge was selected as it is the least likely to conflict with any other badges you may be using, however it can be changed to any of the following:
    • badge1, badge2, badge3, badge4, badge5, badge6, badge7, badge8, badge9, badge10, badge11, badge12, badge13, badge14, badge15, badge16, badge17, badge18, badge19, badge20, badge21, badge22, badge23, badge24, badge25, badge26, badge27, badge28, badge29, badge30, badge31, badge32
  • Start by changing the badge number if your aggregate fails to show!

The aggregate is displayed by way of badge18, with the value of the box property key containing:

  • Badge JSON syntax - this contains styling for the badge that shows the aggregate number. e.g. textColor is #000000 (Black)
  • The aggregate value to display - the final number shown as your aggregate value is set as text, and is the Rounded Sum variable (variables.rounded_aggregate)


2.5. Constants

These contain the bits of information required to do your aggregation in the later defined variables. Let's break down what each constant does:

  • association - the value of this constant should be the the name of the Association Attribute that joins the boxes from/to the box type that contains this render function
    • i.e. If Projects has an attribute called JOIN TO Business Functions
    • The value of associations should then be JOIN TO Business Functions
    • To fetch the correct attribute name, you can view the steps in section 2.7.2.1.
  • number_1 - the value of this constant should be the name of the Attribute you want to aggregate
    • i.e. if Projects has an attribute called Assets Cost you want to sum
    • The value of associations should then be Assets Cost
  • number_2 - the value of this constant should be the name of the Attribute you want to aggregate
    • i.e. if Projects has an attribute called Investment Cost you want to sum
    • The value of associations should then be Investment Cost
  • number_3 - the value of this constant should be the name of the Attribute you want to aggregate
    • i.e. if Projects has an attribute called Capital Cost you want to sum
    • The value of associations should then be Maintenance Cost
WARNING: All Attribute Names are case sensitive!

Make sure to type all Attribute Names accurately, include any spaces and capital letters.



2.6. Variables

These contain the boxes to aggregate and the arithmetic that is calculated.


2.6.1 boxes

This is a special type of variable, known as a Global Box

  • This variable contains all the boxes to apply arithmetic to
  • It's sourceType is globalBoxChildrenById, this means the variable provides a list of all child boxes that are in a certain box
  • globalBoxUuid is value of the variable, that is the UUID of the box containing the list of all child boxes
    • e.g. There is a box called Projects which contains all the Project boxes
  • To fetch this UUID, you can view the steps in section 2.7.2.3.

How to fetch the UUID
  1. Click on the box that contains all the boxes inside it that you wish to apply arithmetic to
  2. Copy the UUID located on the top right of the Edit Box Menu

2.6.2 aggregate

This is where the aggregation happens, let's break down each component of the variable's expression:

  • variables.boxes.sum(b => ... )
    • This performs addition on each box contained in the Boxes variable (variables.boxes)
    • The b => indicates that each box (b) is added up individually according to the conditions to the right of the arrow
  • (toNumber(b[constants.number_1]) + toNumber(b[constants.number_2]) + toNumber(b[constants.number_3]))
    • This finds all the attribute in a box (as specified by their names in the constants section earlier) and adds them together
      • Each attribute is first converted to a number before being added, by toNumber()
    • The b in front of each [constants.number_X] means that each box's own attribute is added
  • * (strCount(b[constants.association], current.Name) > 0))
    • The added attributes are then multiplied by this condition
    • The strCount checks if the Associations Attribute specified earlier, in each box, has the name of the box that the aggregate function applies to
      • If it does contain the box name, it returns 1
      • If it does not contain the box name, it returns 0 and the attributes of that box are not added
      • It is impossible that the strCount returns a number greater than 1, as in Enterprise Lens you cannot select the same box in a Name Association attribute multiple times

To illustrate the condition, let's look an example:

  • Business Function 1 joins to Projects 1 and 2
  • Projects 1 and 2 have an association attribute which contains the value Business Function 1, this means they are joined to that business function
  • Project 3 joins to a different Business Function

Let's now apply the relevant parts of the aggregate variable in this scenario:

  • (toNumber(b[constants.number_1]) + toNumber(b[constants.number_2]) + toNumber(b[constants.number_3]))
    • All Project boxes (1, 2, and 3) have their attributes summed up
  • * (strCount(b[constants.association], current.Name) > 0))
    • Only Project boxes 1 and 2 return 1, as it is joined to Business Function 1
      • This means if their each of their attributes added to 5, they are counted in the final sum as 5*1=5
    • Project 3 returns 0, as it is NOT joined to Business Function 1
      • This means even if this Project's attributes added up to 5 too, it would not be counted as 5*0 = 0
  • The final sum as such is 5+5+0=10

2.6.3 rounded_aggregate

This is the variable that is displayed in the badge and viewed in the illustration. It has only one component:

  • round(variable.aggregate, 2)
    • This rounds the first input, which is the aggregate variable Sum (variable.sum) by the second input which is 2
    • e.g. If the aggregate sum of all boxes is 639.4426 it will be rounded to 639.45!


2.7. Example Complete Aggregate Render Function

Below, is an aggregate of People per State.

  • Mousing over WA, you can see all Projects that belong to WA
    • We can verify the calculations by summing all the highlighted boxes, like so: 11+69+31+98+94+58=361

Example Aggregate Illustration


2.7.1. Viewing the Render Function

In Edit Mode, you can view the Render Function. Below are the steps involved in doing this:

  1. Open the State Box Type
  2. In the Attributes Type tab, click Edit next to Count of People
  3. In the Render Functions tab, click Edit next toPeople per State

Below is the Render Function pasted in whole. You can find an annotated version of this Render Function at the end of this section.

{
"boxPropertyExpressions": {
"badge24": "{ \"text\": variables.rounded_aggregate, \"horizontalPositionInPercent\": 50, \"verticalPositionInPercent\": 100, \"verticalAlignment\": \"none\", \"horizontalAlignment\": \"none\", \"borderRadius\": 5, \"backgroundColor\": \"Tomato\", \"textColor\": \"White\", \"width\": \"20%\", \"height\": \"20%\", \"fontFamily\": \"Arial\", \"textSizeInPixels\": 16 }"
},
"constants": {
"association": "State",
"number_1": "People",
"number_2": "",
"number_3": "",
"number_4": ""
},
"variables": [
{
"name": "boxes",
"sourceType": "globalBoxChildrenById",
"globalBoxUuid": "8b841eb1-b57f-4ef0-9d91-bb22bb376f58"
},
{
"name": "aggregate",
"sourceType": "expression",
"expression": "variables.boxes.sum(b => (toNumber(b[constants.number_1]) + toNumber(b[constants.number_2]) + toNumber(b[constants.number_3])) * (strCount(b[constants.association], current.Name) > 0))"
},
{
"name": "rounded_aggregate",
"sourceType": "expression",
"expression": "round(variables.aggregate, 2)"
}
]
}
Annotated - Example Complete Aggregate Render Function

Annotated Example Complete Aggregate Render Function


2.7.2. Edits made to the Render Function

Rather than re-explain how this render function works, we will run through what we needed to edit from the Render Function contained in [2.3. Render Function](#23-Render Function). We have only changed the following:

  • association constant
  • number_1-3 constants
  • boxes variable UUID

We could have modified the sum to be a count or average, changed the display properties in `


2.7.2.1. association

This contains the name of the association attribute used to join the Project boxes to the States boxes

  • As with any two way association, there is an association attribute on both State and Project box types, that allows you to hover over either type of box and see all associations

  • To find the correct association attribute name, here is the method we used:

    1. Click on any State box in Edit Mode, as pictured below

      Example Edit Box 1

    2. Check under Associations if there is an entry field which reveals the Project(s) the State box is joined to If there is NO entry field, then do not use this attribute's name.

      Example Association Attribute to Avoid Seeing as there is no entry field. This is not the attribute name we should use.

    3. Instead, click on any Project box in Edit Mode, as pictured below

      Example Edit Box 2

    4. Check under Associations if there is an entry field which reveals the State(s) the Project box is joined to If there is NO entry field, then do not use this attribute's name.

      Example Association Attribute to Avoid Here we have an entry field that lists the state(s) a project box is joined to.

      As such, we used the association attribute name State in our render function.

You can use this method for any name based illustration to find the correct association attribute name to insert in your render function.


2.7.2.2. number_1-3

Given this illustration only aggregates the People attribute, we assigned number_1 to People and set the others to blank ("").


No further changes required.


2.7.2.3. boxes

The final change, we set the globalBoxUuid to the UUID of the box that contains all the Project boxes. Here is the method we used for this:

  1. In Edit Mode, click on the box that contains all the boxes you wish to aggregate (in this example, the box labelled PROJECTS) Example Edit Box 3

  2. Click on the Metadata tab and copy the Box UUID

    Example Box UUID


Pictured above is the same UUID we used from the illustration, in the render function for the boxes variable.


2.8. Modifications

You can modify the provided template to make various types of aggregation.


2.8.1. Restrict number of attributes to sum

Adding more attributes

If you want to add more attributes, you add more Constants.


For example, you can add this to the end of your Constants:

    "number_4": "4th_attribute_name",
"number_5": "5th_attribute_name",
"number_6": "6th_attribute_name"

You then need to add them to the aggregate variable, using the same example it would look like this:

    {
"name": "aggregate",
"sourceType": "expression",
"expression": "variables.boxes.sum(b => (toNumber(b[constants.number_1]) + toNumber(b[constants.number_2]) + toNumber(b[constants.number_3]) + toNumber(b[constants.number_4]) + toNumber(b[constants.number_5]) + toNumber(b[constants.number_6])) * (strCount(b[constants.association], current.Name) > 0))"
},

You can see all six constants being added above.


Pay attention to syntax

Notice how we have brackets enclosing the sum of all six attributes, ensure this is kept so the multiplication of the criteria is done correctly.


Removing attributes

To remove the number of attributes to sum, you just clear the value of the constants.


For example, if you want to sum only one attribute, your Constants section would look like this:

  "constants": {
"association": "association_attribute_name",
"number_1": "1st_attribute_name",
"number_2": "",
"number_3": ""
},

You do not need to edit anything else.


Keep the enclosing brackets

While you could remove the brackets around toNumber(b[constants.number_1]), if you change your mind and decide to add more attributes you will need them again.

As such, it's best advised you keep the enclosing brackets around your constant, even if there is only one.



2.8.2. How to Count or Average instead of Sum

Count
  1. Replace sum in the aggregate variable with count
  2. Remove all constants from the aggregate variable

Your aggregate variable should now look like this:

    {
"name": "aggregate",
"sourceType": "expression",
"expression": "variables.boxes.count(b => (strCount(b[constants.association], current.Name) > 0))"
},

This modified aggregate variable only containing the condition that checks for an association between the boxes.


Average
  1. Replace sum in the aggregate variable with avg

Your aggregate variable should now look like this:

    {
"name": "aggregate",
"sourceType": "expression",
"expression": "variables.boxes.avg(b => (toNumber(b[constants.number_1]) + toNumber(b[constants.number_2]) + toNumber(b[constants.number_3])) * (strCount(b[constants.association], current.Name) > 0))"
},

This modified aggregate variable still contains the attributes as it needs to sum them and average them accordingly.



2.8.3. How to show aggregate on box hover only

This is still simple to do, it just requires you to move your badge18 box property value into an attribute.

  1. To do this, you should create a new variable like the one below and name it to badge (just badge will do).

        {
    "name": "variable",
    "sourceType": "expression",
    "expression": ""
    },
  2. Then, paste the value of badge18 box property into the new variable . Here is what that looks like, assuming you haven't modified badge18.

    {
    "name": "badge",
    "sourceType": "expression",
    "expression": "{ \"text\": variables.rounded_aggregate, \"horizontalPositionInPercent\": 35, \"verticalPositionInPercent\": 75, \"verticalAlignment\": \"none\", \"horizontalAlignment\": \"none\", \"borderRadius\": 5, \"backgroundColor\": \"none\", \"textColor\": \"#000000\", \"width\": \"20%\", \"heightInPixels\": 15, \"fontFamily\": \"Arial\", \"textSizeInPixels\": 12 }"
    },
  3. Modify the badge18 box property to have this new value:

    "if (current.Name == highlighted.Name) { variables.badge } else { None }"

    This is what the entire boxPropertyExpressions section should look like now:

      "boxPropertyExpressions": {
    "badge24": "if (current.Name == highlighted.Name) { variables.badge } else { None }""
    },

Now, when you mouse over a box that has this render function you should see the value. Otherwise, it will not show.


Make sure to turn on the render function!

Typically you do this by creating a Lens and turning it on, otherwise to test you can just turn on the Render Function from the Advanced Box Types menu.

Otherwise, hovering over a box won't show anything.


2.8.4. How to do Two Level Aggregation

If you have forgotten what Two Levels referred to, click here.

  • So far, the render function we have discussed was for One Level

  • You can either copy the respective preconfigured JSON located at the end of this guide and re-setup your Render Function accordingly, or modify your existing Render Function.

  • We recommend at least trying to do it manually once to gain a greater appreciation for how aggregation works


You will need to :

  • Add a new constant
  • Add a new variable
  • Modify the aggregate variable

Here are the steps.

  1. Add the following new constant, I would suggest below the existing association constant:

        "association_2": "association_attribute_name_2",

  2. Add the following new variable, I would suggest placing it below the existing boxes variable.

        {
    "name": "boxes_2",
    "sourceType": "globalBoxChildrenById",
    "globalBoxUuid": "boxes_2_uuid"
    },

  3. Replace the expression of the aggregate variable with the new two level expression:

    variables.boxes_2.sum(b => if (strCount(b[constants.association_2], current.Name) > 0) { variables.boxes.sum(s => if (strCount(s[constants.association], b.Name) > 0) { toNumber(s[constants.number_1]) + toNumber(s[constants.number_2]) + toNumber(s[constants.number_3]) } else { 0 }) } else { 0 })

Explanation

Instead of adding the boxes immediately to your aggregate boxes, such as:

  • Adding all Applications that belong to Business Functions (Business Functions -> Applications)

You are now adding boxes that join to your immediate aggregate boxes, such as:

  • Adding all Processes that belong to your Applications, which in turn belong to your Business Functions
  • Processes > Applications > Business Functions

As such, when you configure your new association_2 constant, you need to specify the Association Attribute Name that joins those boxes to your immediate boxes. e.g. JOIN TO Applications


Using the same Business Functions, Applications, and Processes example here is what your constants would look like:

  "constants": {
"association": "JOIN To Business Functions",
"association_2": "JOIN TO Applications",
"number_1": "Development Cost",
"number_2": "Maintenance Cost",
"number_3": "Miscellaneous Cost"
},

Your attributes are now of different boxes
  • In a One Level scenario, the attributes specified in number_1-3 belonged to Applications.

  • In a Two Level scenario this changes, the attributes specified now belong to the Processes, which are the boxes that join the immediate boxes.


Additionally, you need to specify the boxes_2 variable.

To do this, with the current example you would:

  1. Click on the box that contains the Process boxes
  2. Copy the UUID located on the top right of the Edit Menu Box

Your boxes and boxes_2 UUIDs should not match

If they do, you have accidentally included the same children boxes twice.

  • Still using the same example it means one of two things:
    • You have included the box that contains your Applications twice
    • You have included the box that contains your Processes twice

To view a complete example, please look at the prefilled JSON examples for Two Level Aggregation that includes UUIDs at the end of this guide.



3. Render Function Templates

3.1. One Level

3.1.1. Count

3.1.2. Sum

3.1.3. Average

3.2. Two Level

3.2.1. Count

3.2.2. Sum

3.2.3. Average