reptile7's JavaScript blog
Sunday, April 18, 2021

The Arc of the Trigonometric Covenant
Blog Entry #414

At the end of our last episode we pointed out that the Super Calculator's sine, cosine, and tangent functionality does not have an arcsine, arccosine, and arctangent counterpart - we will rectify this omission with a bit of help from our friends in Mountain View in today's post.

Invert it

A calculator Google search brings up a calculator widget, pictured below, when using Google Chrome or Opera on my computer.

The widget has sin, cos, and tan keys
and Rad and Deg keys for toggling between RAD (the default in this case) and DEG modes.
The widget also has an Inv key that when clicked changes inter alia* the sin, cos, and tan keys to sin-1, cos-1, and tan-1 keys

for getting the arcsine, arccosine, and arctangent of a number, respectively;
the click also changes the Inv key's background color from #dadce0 to #f1f3f4.
(The backgrounds and borders of the widget keys are discussed below.)
Reclicking the clicked Inv key brings back
the sin, cos, and tan keys and
the original Inv key.

*The Inv key also toggles
the ln key with an ex key,
the log key with a 10x key,
the key with an x2 key,
the Ans key (see here) with a Rnd key that generates a random number between 0 and 1, and
the xy key with a y√x key.

All of the widget keys are coded as <div>s rather than <button>s or <input>s.
The Inv-controlled keys are housed in 16 separate divs
versus 8 divs whose labels and underlying behaviors are switched back and forth;
however, the Inv/Inv key is just one div.

We previously added a DEG capability to the SC's native RAD mode, and we can do the Inv/arc thing too (and in a much more straightforward way than Google does). Let's start by adding our own key
to either a new Trigonometry section or
to the Special functions section if we want to use the key in a more general way.

<button id="invButton" type="button" onclick="invert( );">Inv</button>

We'll bind the button to an invert( ) function that toggles the trig key labels according to an inverted boolean flag.

var inverted = 0;
function invert( ) {
var trigButtons = document.getElementsByClassName("trigButton");
if (! inverted) {
for (var i = 0; i < trigButtons.length; i++) trigButtons[i].innerHTML += "<sup>-1<\/sup>";
inverted = 1; }
else {
for (var i = 0; i < trigButtons.length; i++) trigButtons[i].innerHTML = trigButtons[i].innerHTML.substring(0, 3);
inverted = 0; } }

<button class="trigButton" type="button" onclick="getinput(sine);">sin</button>
<button class="trigButton" type="button" onclick="getinput(cosine);">cos</button>
<button class="trigButton" type="button" onclick="getinput(tangent);">tan</button>

• Grouping the trig buttons via a class identifier allows us to ordinally collect them with the DOM getElementsByClassName( ) method.
• We can append a -1 <sup>erscript to the trig button labels with the DOM innerHTML property: note that the </ character sequence of the sup element's end tag is escaped with a backslash.
• For reverting to the original trig labels, the -1 superscripts can be easily shaved off via the String object's substring( ) method.

And of course, we'll need , , and Math.atan( )-based counterparts to the DEG-RAD sine( ) function we crafted earlier, e.g.:

function arcsine(mode, obj) {
var trig_mode, alert_message, aa, a;
trig_mode = document.mainform.trig_mode[0].checked ? 1 : 0;
if (trig_mode) alert_message = "In DEG mode, this function maps a sine input to the corresponding angle in degrees.";
else alert_message = "In RAD mode, this function maps a sine input to the corresponding angle/arc length in radians.";
if (mode) window.alert(alert_message);
if (obj.value != "" && obj.value != "0") {
aa = window.prompt("Do you want to find the arcsine of the number in the total text box?", "y or n");
if (aa == "y") {
a = trig_mode ? Math.asin(obj.value) * 180 / Math.PI : Math.asin(obj.value);
doit(a, obj); }
else {
a = window.prompt("Enter a number to find the arcsine of:", "");
a = trig_mode ? Math.asin(a) * 180 / Math.PI : Math.asin(a);
more("(" + a + ")", obj); } }
else {
a = window.prompt("Enter a number to find the arcsine of:", "");
a = trig_mode ? Math.asin(a) * 180 / Math.PI : Math.asin(a);
doit(a, obj); } }

Note that the Math.asin( ) outputs are DEG-RAD bifurcated.

The preceding arcsine( ) function can be called from the getinput( ) function

if (func == sine) {
if (! inverted) return sine(mode, a);
else return arcsine(mode, a); }

or from the sine( ) function itself.

function sine(mode, obj) {
if (inverted) return arcsine(mode, obj); ...

Number validation

Google will generate an interactive graph of a y = f(x) function (e.g., y = x^3, y = ln(x), y = tan(x)) upon searching for that function, again when using Google Chrome or Opera - a very cool feature if I do say so myself.

The y = sin(x) and y = cos(x) functions crest at 1 and trough at -1; Math.asin(x) and Math.acos(x) consequently return NaN if x lies outside the -1x1 range. Per the Non-empty, non-numeric subsection of Blog Entry #411, we can use a suitable while gate to stop outsiderly xs, e.g., something like:

/* Place this guy just before each Math.asin(a) DEG-RAD bifurcation: */
while (Number(a) < -1 || 1 < Number(a) || isNaN(a))
a = window.prompt("Your sine input must be a number in the range:\n-1 \u2264 x \u2264 1", "");

• The Number( ) operations are actually unnecessary as the JavaScript engine will automatically convert the a string to a number for the while comparisons - remove them if you like, or keep them if you feel that they add readability to the code.
\u2264 is the Unicode escape sequence for the ≤ symbol.

Style extras

As noted earlier, the widget's Inv key has a #dadce0 background color whereas the 'inverse' Inv key has an #f1f3f4 background color.
The 16 Inv-controlled keys have a #dadce0 background color, as do the remaining operation keys except the  =  key, which has a #4285f4 background color.
The widget's 11 number keys have an #f1f3f4 background color.
Each widget key has a 1px solid border whose color is the same as the background color and is therefore not noticeable.
Each key has a 4px border radius that slightly rounds the key corners.
Lastly, the key label color is #202124 (why someone would use an off-black text color rather than black itself is beyond me).

A detailed discussion of the backgrounds and shapes of the SC keys would take up more space than it's worth: suffice it to say that
the SC keys typically have a non-uniform off-white background color in the neighborhood of #eee
and they are usually stadium-shaped but sometimes they are perfectly rectangular
depending on the browser and on the browser's zoom level.
Moreover, all of the SC keys have borders and those borders have an outset(-like) style in a majority of cases.

We can apply all, some, or none of the widget's key styles to the SC keys.
At the least I reckon we should toggle the button's background color.
Toward this end, I would explicitly set the initial key backgrounds to white (#fff)
and then switch the Inv background to #c8c8c8 and back to white respectively via
document.getElementById("invButton").style.backgroundColor = "#c8c8c8"; and
document.getElementById("invButton").style.backgroundColor = "white"; statements
in the if and else clauses of the invert( ) function.

But why stop there? Upon giving the SC keys a good solid border
and imparting a good rounding to the border
and bolding the labels as per the border
I liked how it all looked:

button { background-color: white; border: solid 2px black; border-radius: 10px; font-weight: bold; }

Trigonometry:
DEG RAD

Adding the -1 superscript to the , , and buttons increases their widths by 12px or so - try it out above by clicking the button - this effect can be smoothed out by stretching the Trigonometry buttons a bit with an
#invButton, .trigButton { width: 48px; } styling.

Operational oddity

One last point regarding an unexpected something that I have only recently noticed...
Clicking the widget's sin-1 key duly enters
an arcsin( string
into the user input field but it also switches all of the Inv-toggled keys and the Inv key itself back to their predecessor keys.
This doesn't happen with my code: the , , , and keys stay in place until the key is clicked.
We'll cover the SC's key and its Memory section keys in the following entry.

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)