RPN Calculator is an HTML/CSS/JS app that provides a functioning calculator using Reverse Polish Notation, as was common on classic HP calculators. In addition to basic calculator functionality, this app provides a theming option that demonstrates the power of CSS3 for controlling the look and feel of an HTML based app.
The source code for this sample can be found here: https://github.com/gomobile/sample-rpn-calc.
List of Technologies
- flex box
- changing css links
- transitions, gradients,
- Object Oriented JS
Layout is done using the CSS3 flex box facility. The calculator consists of a <div> element containing a Display <div> element and a KeyPad. The KeyPad consists of a table of buttons, using flexbox to govern the horizontal distribution of the buttons, each of which is a <td> element. Each <td> element has the display property set to box, and the box-flex property set to 1, ensuring an equal distribution across 100% of the enclosing table. This works well on Chrome and other webkit-based environments, but Firefox seems to execute the layout somewhat differently, such that the width of the of each <td> element is affected by the width of the text contained therein. The difference can be seen in these screenshots:
|Chrome Screenshot||Firefox Screenshot|
+/-) but it is not very noticeable.
Two layouts are defined, the primary and secondary layout, that are switched by pressing the Fn button (which is present in both layouts). It would be possible to use html as well, but using this method provided some shortcuts, such as using constructors in some cases (e.g.
NumButton for buttons corresponding to digits) to simplify repetitive declarations and guarantee consistency.
class=theme which creates a list of available themes in the dom that can be cycled through when the Theme button is pressed. Each theme link is in the root html file, index.html, like so:
<link class=theme rel="stylesheet" type="text/css" href="css/themes/shinybuttons.css">
The list of themes is created from the dom:
var l = document.getElementsByClassName('theme');
which is then used by the toggleTheme method which is used by the
onclick method for the Theme button.
Each theme is defined by a separate CSS file, contained in css/themes. A variety of CSS techniques are illustrated among the various themes. For the default theme, "shinybuttons," a common background image is used for each button. This image was originally created as an svg file, which uses gradients and filters to achieve the lighting and transparency effects. Unfortunately, these images did not work on Android devices, so they were converted to png files, which work on all the platforms I tested. Other themes illustrate features such as boxes with rounded corners, css gradients and even animated transition effects.
One of the advantages of using the flex box layout is illustrated in the "bubbles" themes. In these themes, the hover selector is used to enlarge the size of the current element. Rather than simply pushing aside the surrounding buttons, they are shrunk, revealing a magnification effect. This is different than the scale transformation used in the "green" theme, where the zooming hover effect does not affect its neighbors.
|Bubbles - Magnification Effect||Green - Scaling on hover|
'+' button is pressed the top two elements of the stack are popped, added together with the result and pushed back onto the display. The display represents the current top of stack. Editing the display is a special case, as the display may be in one of several states, either in the process of being edited or already pushed. For example, when the display is pushed it retains a copy of itself, which is replaced if entry of a new number begins. Similarly, when the stack is popped the bottom entry of the stack is duplicated.
Testing, Quirks and Solutions
The app was tested on a number of devices and platforms, including Firefox and Chrome on a laptop and on various Android and IOS devices (phones and tablets). It turned out to be a great demonstration of the variety of difficulties and inconsistencies one may encounter on different platforms and browsers:
- On Mozilla, columns of buttons come out different widths
- Webkit doesn't have Mathml support
Originally, I had planned to use Mathml to generate mathematical symbols, like the square root symbol, exponentiation etc. Unfortunately, it turned out that some Webkit-based browsers don't support Mathml at this time. In particular, Chrome and Android based browsers do not appear to support Mathml. Instead I resorted to using special HTML characters like "
√" combined with a top border over the subsequent "x". This has the disadvantage that it requires a lot of trial and error to get a reasonable result, and it is inconsistent across fonts and devices. Unfortunately it also required further compromises as the multiplication symbol (
'×') doesn't seem to be well supported on Android devices. As a result, I used an asterisk (
'*') in its place, which is clear, if less aesthetically pleasing.
Though not implemented here, probably the most reliable solution would be to generate a foreground image with the appropriate symbols and text. This would ensure greater consistency at the loss of some flexibility (i.e., cannot easily change the font).
One other advantage would be that it would address the issue leading to varying button widths on the Mozilla browser, as each foreground image could be made to be the same width, eliminating the variations due to text width and height.
- Android doesn't properly support svg features
As mentioned above, this problem was solved by converting the svg image to a png file.
- No hover on touch devices
Some of the themes (green and bubble, among others) rely on the hover selector to generate changes when hovering, but this does not translate well to touch devices. A better solution would be to specialize, or even eliminate, some themes based on the device type being used.
Porting to Windows 8 Store App
Please see this article Porting HTML5 Samples to Windows 8* Store for detail information.