Styles Hierarchy
The styles hierarchy are a set of nested configuration rules that are used to conditionally apply styles to features or SVG images, allowing map content to be highly dynamic based on UI options, zoom levels or other application specific logic. The rules are a tree structure with a single root, where each node in the tree can have the following properties:
• comment: Allows the configuration to be documented - it is recommended to add useful comments to help with maintainability of the configuration in future
• match: The boolean logic to check to see whether to apply the settings of this item or its children. If this is missing, and there is no switch or case attribute then it is considered to be true. This can be one of 3 types:
• Simple attribute comparison, for example to match any features that have an attribute called CLASS with a value of 801 you could do this:
"match": {
"attributes": {
"CLASS": 801
}
}
This is the most efficient sort of check to perform in a match, so should be used wherever possible to control the logic, in order to achieve the best performance in the map. The exception to this rule is where a single value is compared by several rules in a block, in which case the most efficient way to do this is with a switch/case block.
Note: If you compare anything with true/false then javascript truthiness logic will be applied in order to compare with true/false, that is, the number 0, null, undefined or '' (empty string) will all be considered equal to false, and anything else will be considered true.
• Filter definition, this matches the same format used for Flex table filter definitions, for example:
"match": {
"filters": [
{
"field": "attributes.CLASS",
"operator": "=",
"value": 801
}
]
}
• A javascript expression which will be evaluated, for example
"match": "attributes.CLASS = 801"
• switch / case: For a list of nodes where each is being checked against a single test for a range of possible values, this is by far the most efficient check to perform, and should be used wherever possible to optimize the performance of the map. The switch property is an expression to evaluate against the feature, and the case property is a value, or list of values, to compare against the result of the switch expression, for example in the product configuration this is used for things like the symbol size and SVG file lookup
{
"comment": "---- Look up image and width styling ----",
"switch": "attributes.SYMBOL",
"children": [
{
"comment": "---- Supply Point ----",
"case": "SupplyPoint",
"width": 25,
"height": 25,
"image": "supply_point.svg"
},
{
"comment": "---- SwitchGear ----",
"case": "SwitchGear",
"width": 110,
"height": 110,
"image": "square.svg"
},
{
"comment": "---- Switch ----",
"case": ["Switch", "Switch270", "ScadaSwitch"],
"svgValues": "CALC: {OPEN: state.OPEN, CLOSED: state.CLOSED, MIXED: state.MIXED, ABN: state.ABN, RING: MAP_SETTINGS.options.ABNORMAL_RING, NOM_OPEN: attributes.NOMSTATUS === 'OPEN' && MAP_SETTINGS.options.DEVICE_NOMINAL_OPEN_SYMBOLS && ![128,146].includes(attributes.HANDLECLASS), STRUCT: (attributes.SYMBOL.endsWith('PM')?'PM':(attributes.SYMBOL.endsWith('UG')?'UG':'OH')), SCADA: attributes.SYMBOL.includes('Scada')}",
"image": {
"url": "js/symbols/switch_dyn.svg"
}
},
...
{
"comment": "---- Default symbol if nothing above matches ----",
"image": "invalid_symbol.svg",
"units": "pixels",
"width": 24,
"height": 24
}
]
}
• children: a list of child items to check if the match or case checks succeed for this node, or if there are no match or case properties.
• stopAtFirstMatch: if this is true then processing of the children will stop at the first one that it matches.
• Any one of the applicable style properties for the type of feature or SVG element being styled - if the match or case checks succeed for this node, or if there are no match or case properties, then these will be applied to the style or SVG element.
Dynamic Map Styling Configuration
The CALC: syntax is also used extensively in the map configuration to allow properties to be set based on calculated values, or to allow what amounts to variable declaration and then use of that variable in subsequent sections of the configuration.
Complex calculations on property setters - setting font height based on presence of HEIGHT attribute:
{
"comment": "---- Font Size ----",
"match": {
"attributes": {
"HEIGHT": true
}
},
"font": {
"size": "CALC: attributes.HEIGHT * 1.5"
}
}
Variable storage and reuse - setting the stateMarker variable
{
"comment": "---- 1PhaseCable-ABN-CLOSED ----",
"stateMarker": {
"state": "markerCondClosed"
}
}
Using the variable in a later section of the style evaluation, if some other conditions are true.
Note: Any properties applied in the map styling configuration are applied to the renderStyle of the element being rendered so we must reference the variable from there.
{
"comment": "---- MULTISTATE ----",
"match": {
"state": {
"MULTISTATE": true
},
"STYLE_STATES": {
"MULTISTATE": true
}
},
"markers": "CALC: renderStyle.stateMarker || {}",
}
This same technique can be used for any property of the element styles, for example the big symbol support in Flex uses the previously calculated width/height to apply a minimum width/height to the symbol based on the current zoom level and big symbols scale factor.
Note: It also ensures that the value does not make the minimum size less than any previously calculated minimum size, using the $max function and passing renderStyle.minWidth to it as well as the calculation for the big symbol min width.
{
"comment": "---- Big Symbols - Device Symbols ----",
"match": {
"MAP_SETTINGS": {
"options": {
"BIG_SYMBOLS": true
}
}
},
"children": [
{
"match": "$isDeviceClass(attributes.HANDLECLASS, 121, 307, 308, 126, 137, 198, 199, 357, 377, 378)",
"minWidth": "CALC: $max(renderStyle.minWidth, renderStyle.width * MAP_SETTINGS.options.BIG_SYMBOLS_SCALE) * (MAP_CONFIG.render.constants.big_symbol_zoom_scale[ZOOM_LEVEL])",
"minHeight": "CALC: $max(renderStyle.minHeight, renderStyle.height * MAP_SETTINGS.options.BIG_SYMBOLS_SCALE) * (MAP_CONFIG.render.constants.big_symbol_zoom_scale[ZOOM_LEVEL])"
}
]
}
Checking State and Settings
The map settings and current state can be checked in any of the match types by referencing any of these properties -
• IS_GEO: Is the map currently showing maps in a geographic coordinate system, as opposed to an schematic view.
• IS_FRAME_2: allows animation of features between 2 states, by checking this in a style rule and providing alternative styles when rendering the second frame.
• STYLE_STATES: can be used when styling conductors according to state in power flow related color modes, based on the powerflowOverride configuration options in the map configuration.
• MAP_CONFIG: allows access to the map configuration object, so values can be defined in the configuration and referenced in style rules.
• ZOOM_LEVEL: The current zoom scale - can be used to dynamically show/hide things at different zoom levels.
• ZOOM_SCALE: The actual zoom multiplier - a floating point value.
• RESOLUTION: The inverse of the ZOOM_SCALE - a floating point value.
• MAP_SETTINGS: The current map settings - allows checking of any option, for example to turn things on/off based on hide/display settings.
Look at the out of the box configuration for further examples using the above state and settings.