Deep Map™ Rules
If you look at the custom.mapRule file we added in the previous tutorial (see " Deep Map™ Styling"), you will notice there are some existing rule definitions. Rules can be used to dynamically change the styling of a map. The specifications for the rules can be found in the Documentation section under "Deep Map™ Rule specification". A rule definition adheres to the following structure:
<ruleName> is a free identifier for the rule.
<featureTypeName> is the name of the
style-feature to which the rules should be applied. The
<rule statement> is an SQL-like statement
mimicking the "where" clause. As long as the statement is true, the
rule is applied to the featureType. The
body> defines which changes should be made to
<featureTypeName>. Rules can also be nested.
This means it is possible to add another rule to a different
<rule body>. We will soon see how
this could be used. The only limitation is that the nested rules
featuretype may not be related by a child-parent relationship to
the exterior featuretype.
In the tutorial " Tap handling, object selection and annotations", a tap-handler was implemented to select objects. The reason why the selected objects change their color is due to the rules in the rule-file. We have a total of five rules, one for each of the following featuretypes: "stand_manual", "osm.building", "building", "stand_tables" and "stand_rooms". The rule statement is always the same: "isSelected()", so if an object with one of the aforementioned featuretypes is selected, the fill-color #ff5511 is applied to it.
It can be cumbersome to create one rule for each featuretype. It would be optimal if we could group similar objects together, and define one behavior for the whole group. This can be done in two ways: adding multiple targets to one rule and featuretype inheritance.
The Multiple Targets Approach:
It is possible to add multiple targets to a single rule. To do this, add all featuretype names to the rule (separated by commas). This way, the five rules in the custom.mapRule file could be combined in a single rule:
This approach should be used if a rule is applied to many targets that have no relation to each other. For example, "building" and "stand_tables" may behave very differently in the map, but both should be selectable. It is also more robust against user-errors than the following featuretype inheritance approach. When in doubt, use multiple targets.
The Featuretype Inheritance Approach:
Another way to apply a single rule to multiple targets is by grouping different featuretypes. This can be done with featuretype inheritance. Each feature-style definition consists of two parts: the featuretype name and a parent-featuretype name. The child style inherits all properties set by the parent - rules included! In order to group all selectable polygons together, we must define a new, imaginary featuretype called "selectable_polygon" right behind the polygon feature definition in the custom.mapStyle file:
A feature named "selectable_polygon" does not actually exist in the map, and since we only use it to group other featuretypes, we also do not need to set any properties. Featuretypes can now be assigned to each group by simply inheriting from it.
We only have to create one rule with "selectable_polygon" as the target:
Rule inheritance should be used if multiple featuretypes always share the same behaviour. However, some care has to be taken if nested rules are used, since the inheritance may cause unpredictable behaviour when it is not applied correctly.
Take a look at the building with the label "MA 5". You will notice that the building has some rooms and tables inside it. However, if we are far away, the rooms and tables are barely recognizable and distracting. On the other side, if we get close to the building, the label of the building becomes annoying, because we want to focus on the rooms. Ideally, everything inside the building will be hidden if the camera is far away, and the label of the building will be hidden when the camera is zoomed in. This can be done with rule-nesting. First, we must create two new featuretypes in the custom.mapStyle file, which inherit from "selectable_polygon":
Then we regroup our five featuretypes into the two new groups:
Now we have two groups of selectable_polygons: the building_type group, which have invisible labels, and a building_interior_type group of rooms and tables, which are fully visible. What we now have to do is create rules that make the labels of the building_types visible when the camera is further than 200m away, and make the building_interior_types invisible at the same time. This can be done by nesting two rules like this:
The rule combines two rules: The exterior rule is applied to all objects in the "building_type" group. As soon as an object is further than 200m away, the rule is applied and the text-visibilty is set to "true", so the labels of the buildings are displayed if the camera is far away. The nested rule is applied to all objects of the "building_interior_type" group which are children of the exterior object. Note that the nested rule has two additional targets: fg_polygons and fg_walls. Those types may also appear within a building, so we add them too. However, since they should not be selectable, we cannot let them inherit from building_interior_type, so we add them as additional targets. The inner rule will only be executed if the exterior rule is applied. The missing rule statement means that the rule will always be applied, so we get our desired behavior: