4.1.6 Create Observers

Observers are used to link graphical elements with the model. An observer is notified whenever the model has changed its state, i.e. whenever an event has been executed. In response, the observer will query the model’s state and triggers actions on the linked graphical elements in respect to the new state. In general, observers are written in JavaScript and should be placed in the script.js file. As an example, consider the following formula observer:

Listing 4.1: Formula Observer Displaying the Current Floor (JavaScript)

bms.observe("formula", {
  selector: "#txt_cur_floor",
  formulas: ["cur_floor"],
  trigger: function (origin, values) {
    origin.text(values[0])
  }
});

\includegraphics[width=7mm]{img/info_64.png}

Checkout Section 4.2.2 for more details about observers.

We are going to explain the JavaScript code line by line. In line 1 we register a formula observer on the graphical element with the id txt_cur_floor (line 2) that is located in our index.html file. BMotionWeb follows the jQuery selector syntax1 to select graphical elements. The prefix “#” denotes that we want to select an element by its id. In line 3 we define a list of observed formulas. In this case we observe the variable cur_floor. In line 4 to 6 we define a trigger function that is called after every state change with its origin (the origin parameter holds a reference to the graphical element that the observer is attached to) and the values (the values parameter contains the values of the defined formulas in an array, e.g. use values[0] to obtain the value of the first formula). The trigger function changes the text of the graphical element (origin) to the current value of the variable cur_floor (values[0]).

Let’s create another observer. Check out the following JavaScript snippet:

Listing 4.2: Formula Observer for the Lift Door (JavaScript)

bms.observe("formula", {
  selector: "#door",
  formulas: ["cur_floor", "door_open"],
  trigger: function (origin, values) {
    
    switch (values[0]) {
      case "0":
        origin.attr("y", "175");
        break;
      case "1":
        origin.attr("y", "60");
        break;
      case "-1":
        origin.attr("y", "275");
        break;
    }
    
    if(values[1] === "TRUE") {
      origin.attr("fill", "white");
    } else {
      origin.attr("fill", "lightgray");
    }
    
  }
});

In line 1 we register a formula observer on the graphical element that matches the selector “#door” (line 2) (similar to the previous defined formula observer). In line 3 we define the set of observed formulas (cur_floor and door_open). In line 4 to 24 we define a trigger function, that makes the following action: Line 5 to 15 will switch the y coordinate of the door (denoting the movement of the door between floors) according to the current value of the variable cur_floor (values[0]). Lines 18 to 22 affect that the attribute fill of the door will be set to “white” (denoting the door is open) whenever the formula door_open evaluates to TRUE in the current state (values[1]), otherwise to “lightgray” (denoting the door is closed).

Add both snippets to your script.js file, save the file and click on the Reload button. Let’s see how this affects our visualization: Setup and initialize the machine using the ProB events view. Execute some events and see what happens. For instance, Figure 4.2 shows the lift visualization where the lift is on floor 0 and the door is open.

\includegraphics[width=12cm]{img/tutorial/tut_04.png}
Figure 4.2: Lift visualization with observers

Footnotes

  1. For more information about jQuery and selectors we refer the reader to the jQuery API documentation http://api.jquery.com/category/selectors/.