- Low-Level Drawing APIs
- Understanding the Amino APIs
- Drawing Binary Clock Elements
- Summary
Drawing Binary Clock Elements
Though both Java and JavaScript have native functions to convert a number from decimal to binary, neither normalizes the output. So if you have a field with a maximum value of 31, and you convert 4 to binary, it outputs 100 rather than 00100. Depending on how you render your values, this format could cause an unintended error where a value 100 is misinterpreted as 10000. There are several ways to deal with this problem. One option is to render values starting with the least-significant digit. Another technique is to pad the values with leading zeros in order to normalize them to the proper length. I went with the second choice.
When we have the normalized values, we can draw the rectangles. The code in Listing 4 shows a function from the ClockLine Java class to instantiate a rectangle with a preset width and height, along with a function that adds the proper number of rectangles to the ClockLine group.
Listing 4Draw rectangles.
public void drawSquares() { Rect[] rect = new Rect[4]; for (int i=0; i<4; i++) { Rect r = createNewRect(); r.setY(i*(sideLength+gap)); rect[i] = r; } if (maxValue == 8) { add(rect[0]).add(rect[1]).add(rect[2]).add(rect[3]); } else if (maxValue == 4) { add(rect[0]).add(rect[1]).add(rect[2]); } else add(rect[0]).add(rect[1]); }
Now that we have code to draw the rectangles, we need to animate them. In the setTime function, we instantiate a variable with the current date and time; then we retrieve the components of the time (hours, minutes, and seconds). Next, we convert the number to a two-digit representation that's split and converted to binary. We then call setValue for each ClockLine. Listing 5 shows the JavaScript version of this code.
Listing 5Using setValue (JavaScript).
self.setValue = function(val) { var temp = Number(val); // convert string to number self.value = temp; var binaryText = temp.toString(2); if (self.maxValue == 8) { binaryText = binaryText.lpad("0", 4); } else if (self.maxValue == 4) { binaryText = binaryText.lpad("0", 3); } else { binaryText = binaryText.lpad("0", 2); } var count = 0; for (var i=0; i<binaryText.length; i++) { var v = binaryText[i]; if (v == "0") { self.components.getChild(i).setFill("red"); } else { self.components.getChild(i).setFill("green"); count++; } } };
We need this code to be executed on every frame refresh. Java has an interface called Callback that our BinaryClock class implements. The interface requires a single function call that takes a single object as its parameter. The call function holds the equivalent of the JavaScript code from setTime**. To make the application invoke the function, we need to call addCallback:
addCallback (self.setTime); // JavaScript version addCallback (this); // Java version
Runner (JavaScript) and Core (Java) both allow you to add an unlimited number of callbacks, permitting you to decouple your code as much as possible. Though there's no explicit function to remove a callback, the backing data structure uses arrays, so it would be easy enough to remove a callback in code. To start and pause our simulation/game, we need to call start and stop, respectively. Figure 3 shows our binary clock at 9:16.
Figure 3 Binary clock at 9:16:43.