RPN Calculator

 

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-calculator  or download the Intel® XDK to check out all the HTML5 samples. 

Language Features

The app is written completely in HTML5, CSS3 and JavaScript, and demonstrates a number of features of each of these languages:

List of Technologies

  • HTML5
    • classes
  • CSS3
    • flex box
    • changing css links
    • transitions, gradients,
  • JavaScript
    • Object Oriented JS

Layout

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

Specifying which button goes in each element of a row is done with a JavaScript data structure, a list of lists of objects. The outmost list corresponds to the KeyPad, each element of which is a list of buttons corresponding to a row. Each element of the inner list is a button containing a text and fcn element. The text element contains the text that shows up on the button, while the fcn is called by the onclick attribute for that button. In fact, careful inspection reveals that even in Chrome the height of the rows varies slightly due to certain character combinations (e.g. exponentiation, +/-) 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.

Themes

"Themes" are set by using JavaScript to modify the link tags in the html file. Each theme is listed with 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.

The classic "gray" theme is selectable. In the "beige" theme, the hover selector is used to change the color of the current element. 

Classic Beige - Highlighting on hover

Semantics

The semantics of the calculator and its stack machine is implemented in JavaScript. The basic machine consists of a four element stack that is operated on by the various buttons. For example, when the '+' 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.

In general, the math provided by the calculator corresponds to the math the JavaScript interpreter provides. Thus, the '+' button simply adds two numbers together in JavaScript, regardless of type. This can result in numbers like Infinity appearing in the display; not typical for a calculator, but reasonable in JavaScript.

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 "&radic;" 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.

Download project assets on github


Download Now

 
有关编译器优化的更完整信息,请参阅优化通知