reptile7's JavaScript blog
Wednesday, July 06, 2016
Calculator Capabilities, Continued
Blog Entry #371

Before we get started, and in the name of completeness...

Regarding the previous post's As for the log10e and log2e key labels... subsection, it has come to my attention that the JavaScript Math object has
(1) a LOG10E property, which returns log10(e), and
(2) a LOG2E property, which returns log2(e),
but these constants play no role in the AGSC script's base10_log( ) and base2_log( ) functions.

We wrap up our discussion of the Another Great Science Calculator (AGSC) script with today's post, specifically, we'll (inter alia)
(1) go over the trigonometry part of the script,
(2) briefly compare Jamie's calculator to an HTML Goodies calculator that we checked over previously, and
(3) finally get to that demo I promised you.


Jamie's calculator offers , , and keys for respectively determining the sine, cosine, and tangent of an angle in degrees.

var rad = 3.141592654 / 180;
function sin_form(form) { form.expr.value = Math.sin(form.expr.value * rad); }
function cos_form(form) { form.expr.value = Math.cos(form.expr.value * rad); }
function tan_form(form) { form.expr.value = Math.tan(form.expr.value * rad); }

<td><input type="button" value=" sin " onclick="sin_form(this.form);"></td>
<td><input type="button" value=" cos " onclick="cos_form(this.form);"></td>
<td><input type="button" value=" tan " onclick="tan_form(this.form);"></td>

The JavaScript Math.sin( ), Math.cos( ), and Math.tan( ) methods all expect an angle (arc length) argument specified in radians. The calculator anticipates that the user will input an angle in degrees and converts the user's input to an angle in radians via a rad = π radians / 180° conversion factor before feeding it to Math.sin( ), Math.cos( ), or Math.tan( ).

If you want to take the sine/cosine/tangent of an angle in radians, or if you want to 'go backward' from a length ratio to an angle via the JavaScript Math.asin( ), Math.acos( ), Math.atan( ), or Math.atan2( ) method, then you can, as per last time, input a relevant expression into the expr field and eval( ) it, e.g., Math.atan2(5, 5) * 180 / Math.PI outputs 45.

One last function

Clicking the calculator's key calls a clear_display( ) function that clears the expr field by setting its value to a space character.

function clear_display(arg) { arg.expr.value = " "; }

<td><input type="button" value=" C " onclick="clear_display(this.form);"></td>

Could we replace this code with an <input type="reset" value="Clear Entry"> input? That we could.

Jamie vs. Saries

This is actually our second go at a calculator script: not quite ten years ago we discussed the "rainbow calculator" script of HTML Goodies' JavaScript Script Tips #52-55 in Blog Entries #74 and #75. I have recently restored the missing demos and images in these entries, and you can see and make use of the rainbow calculator at the top of Blog Entry #74.

Crafted by "Saries" in 1999, the rainbow calculator has the following keys that Jamie's calculator doesn't have:
(1) , for subtracting the rightmost character in the name="text" input field;
(2) , for exponentiating x to the y power;
(3) , for returning the absolute value of x;
(4) , which inputs an E for expressing a number in scientific notation;
(5) , for rounding a floating-point number to the nearest integer;
(6) , for converting a number to its additive inverse;
(7) , for inputting a random floating-point number between 0 (inclusive) and 1 (exclusive); and
(8) , for inputting Math.PI.
All of these operations can be carried out 'by hand' with Jamie's calculator, however. You're up to the task of typing Math.random( ) in the expr field and clicking the key, aren't you?

Conversely, Jamie's calculator has two logarithm keys that Saries' calculator doesn't have. However, Saries' calculator itself uses a document.calculator.text.value = eval(document.calculator.text.value); command to evaluate arithmetic expressions, and we can enter and eval( ) Math.log(x)-containing expressions in the text field of Saries' calculator just like we can in the expr field of Jamie's calculator.

Decimal ↔ hexadecimal

Let me note one more cool and useful thing that you can do with Jamie's (or Saries') calculator: convert decimal numbers to hexadecimal numbers and vice versa.

Syntax #1: eval("numeric_literal .toString(radix)")
100 .toString(16) outputs 64
0xaa .toString(10) outputs 170

Yep, that's a space between the numeric_literal and the .toString(radix) call: it's there to prevent the dot property accessor from being interpreted as a decimal point*. This peculiarity of the toString( ) method of the Number object is buried in the JavaScript 1.5 Core Reference - there's no mention of it at the current Mozilla Number.prototype.toString( ) page. Note that hexadecimal integer literals are prefixed with 0x (or 0X).

*In practice with the OS X browsers on my computer, the space is actually unnecessary when converting a hexadecimal number to a decimal number but is definitely needed when converting a decimal number to a hexadecimal number.

Syntax #2: eval("(numeric_literal).toString(radix)")
(960).toString(16) outputs 3c0
(Thanks, W3Schools.)

In both cases, JavaScript automatically converts the numeric_literal to a temporary Number object, calls the toString( ) method, and then discards the temporary Number object, or at least I'm guessing that's what happens based on what happens when a String object method is called on a string literal.

Other decimal ↔ hexadecimal syntaxes are possible, e.g., eval("x = numeric_literal; x.toString(radix)"), but I'd go with the ones above.

But wait, there's more...

JavaScript (ECMAScript) has recently added seventeen new methods to the Math object including
(a) a cbrt( ) method for calculating cube roots,
(b) a hypot( ) method that can carry out a c = (a2 + b2)½ Pythagorean theorem calculation from a and b inputs, e.g., Math.hypot(5, 12) returns 13,
(c) a log10( ) method for calculating common logarithms, and
(d) a log2( ) method for calculating binary logarithms.
The (a-d) methods can be used with Jamie's (or Saries') calculator IF you are running the calculator with an up-to-date version of Firefox, Google Chrome, Opera, or Safari; IE doesn't support them yet.

Demo + changes

Table architecture

The demo calculator is laid out with one table. The Jamie's Calculator heading and the expr field (and their td/tr containers) have been placed in a <thead>; a <tbody> holds the rest of the content.

Key labels

The key now reads , the key now reads , the key now reads , and the key now reads . Re the last key, the &radic; radical symbol and the text-decoration:overline; vinculum over the x don't quite connect, but that's life.

Dot, binary, minus

var decimalsign = " . "; is now var decimalsign = "."; and var base_2 = Math.LN10; is now var base_2 = Math.LN2;. Also, the negativesign-inputting key has been replaced with a key that when clicked converts a number to its additive inverse:

<input type="button" value="  +|-  " onclick="addinverse(this.form);">

function addinverse(form) { form.expr.value = - form.expr.value; }

All right, here we go:

Jamie's Calculator

Thursday, June 23, 2016
Dr. Calculator and His eval( ) Powers
Blog Entry #370

Let's get back now to our ongoing analysis of the Another Great Science Calculator (AGSC) script. Near the end of the previous post, we saw that the AGSC script calls on a

function calculate(arg) { arg.expr.value = eval(arg.expr.value); }

to evaluate basic arithmetic expressions; we'll see below that we can leverage this functionality for a variety of other calculations, starting with...

Arithmetic extras


The factorial operation is an application of multiplication. Many calculators have an key although Jamie's calculator isn't one of them. However, we know via this code in Blog Entry #75 that we can calculate a fact factorial with

fact = 1; for (i = x; i > 0; i--) fact *= i;

and if we plug the above expression with a suitable x operand into the expr field and click the key, then we do in fact get the x! value, e.g., fact = 1; for (i = 7; i > 0; i--) fact *= i; outputs 5040 (7!): this is a consequence of the fact that in JavaScript a fact = some_value expression itself evaluates to some_value.

It would be great if JavaScript had a Math.fact(x) method for computing factorials, but it doesn't.


The modulo operation is an application of division. Most calculators, including Jamie's calculator, don't have a key (they do typically have a key for converting a number to a corresponding percent, i.e., dividing it by 100); nonetheless, we can calculate( ) a modulo remainder with Jamie's calculator upon inputting a dividend % divisor expression into the expr field, e.g., 200 % 16 outputs 8.


Jamie's calculator offers a key for squaring a number and a key for taking the square root of a number.

function calc_sqrt(form) { form.expr.value = Math.sqrt(form.expr.value); }

function calc_sqr(form) { form.expr.value = (form.expr.value * 1) * (form.expr.value * 1); }

<td><input type="button" value=" Sqrt " onclick="calc_sqrt(this.form);"></td>
<td><input type="button" value="  Sqr  " onclick="calc_sqr(this.form);"></td>

• The * 1 multiplications in the calc_sqr( ) function are unnecessary as the attempted multiplication of two numeric strings gives the expected product.

The calculator doesn't have and keys for calculating other powers and roots, but there's nothing stopping us from inputting Math.pow(base, exponent) commands into the expr field and eval( )-ing them, is there? Math.pow(2, 10) outputs 1024, Math.pow(1024, 1/10) outputs 2.


The calculator offers a key for calculating common (base 10) logarithms and a key for calculating binary (base 2) logarithms.

var base_10 = Math.LN10;
var base_2 = Math.LN10;

function base10_log(form) { form.expr.value = Math.log(form.expr.value) / base_10; }

function base2_log(form) { form.expr.value = Math.log(form.expr.value) / base_2; }

<td><input type="button" value="log10e" onclick="base10_log(this.form);"></td>
<td><input type="button" value=" log2e " onclick="base2_log(this.form);"></td>

JavaScript provides a Math.log(x) method for calculating the natural (base e) logarithm of x and, given that logb(a) = logd(a) / logd(b), also provides Math.LN10 (ln(10)) and Math.LN2 (ln(2)) constants for converting Math.log(x) returns to common logarithms and binary logarithms, respectively.

A global base_10 variable is set to Math.LN10, and the base10_log( ) function duly divides the natural logarithm of the form.expr.value by base_10 to give a common logarithm - so far, so good.

A global base_2 variable should be set to Math.LN2 but is inexplicably also set to Math.LN10; as a result, the base2_log( ) function's division of Math.log(form.expr.value) by base_2 gives a common logarithm as well. Of course, sorting this matter out is no more difficult than changing var base_2 = Math.LN10; to var base_2 = Math.LN2;.

The calculator doesn't have a key, but it is simple enough to input a Math.log(x) command into the expr field and eval( ) it. Moreover, we can use the logb(a) = logd(a) / logd(b) identity to calculate logarithms for other bases, e.g., to calculate log3(100), just enter and eval( ) Math.log(100) / Math.log(3).

As for the log10e and log2e key labels...

They're kind of confusing, aren't they? I think the "e" may stand for "exponent", which is what a logarithm operation returns, but an "e" on a calculator logarithm key makes me think of e = 2.71828..., and neither of those keys is meant to output a natural logarithm. Much better would be and , yes?

<td><button type="button" onclick="base10_log(this.form);">log<sub>10</sub>(x)</button></td>
<td><button type="button" onclick="base2_log(this.form);">log<sub>2</sub>(x)</button></td>

As shown, the 10 and 2 are subscripted via the sub element, which we can deploy in a <button> label but not in an <input type="button"> label. When the AGSC script went live at Java Goodies at the end of 1997, the current versions of IE and Netscape were IE 4.x and Netscape 4.x, respectively: the button element, with its almost-(%flow;)* content model, is supported (if a bit buggily) by the former but not by the latter. Alternatively, Jamie could have created log10(x) and log2(x) images and put them on <input type="image"> buttons although this strikes me as more trouble than it's worth.

While I'm on this topic, I should note that we can today use numeric character references to put a subscripted 1, 0, and/or 2 in an <input type="button"> label, e.g., <input type="button" name="" value="log&#8321;&#8320;(x)" onclick="base10_log(this.form);"> for , but we couldn't have done so back in 1997.

Mind you, you do also have the option of adding , , , , , and keys and corresponding functions to the AGSC script, but if you don't want to do that, then you have what you need.

We'll go through the trig part of the calculator in the following entry.

Monday, June 13, 2016
The Key to the Operation, Part 1
Blog Entry #369

In today's post we tuck into "Another Great Science Calculator", the next Calendars, Clocks, and Calculators (CCC) script. Authored by Jamie Beyore in 1997, the Another Great Science Calculator script codes a desktop calculator via which the user can carry out various mathematical operations, which we will detail in the discussion below.

Visualizing the calculator

The document holding the Another Great Science Calculator script code is still live as of this writing but the script's demo page shows...nothing. As it happens, two incorrectly formulated HTML comments stand in our way.

<!-- In the document head: -->
<!-- The Following Program Was ... (C) 1997 --- //>

<!-- In the document body: -->
<!-- Start Calculator Display --//>

HTML comments should end with a --> character sequence. The head comment contains three alien pre-> characters (the two slashes and the space that precedes them) and the body comment contains two alien pre-> characters (the two slashes); removing these characters brings the display to life.

Jamie's Calculator

This is just an image, not the actual calculator - I'll roll out a functioning demo in due course.

Structure notes

Jamie's calculator is laid out with four tables. Table #1 holds the Jamie's Calculator heading and the display/input field.

<table border="1" valgin="middle" algin="center">
<tr><td bgcolor="yellow" align="center">Jamie's Calculator</td></tr>
<tr><td bgcolor="lightgrey" align="center"><input type="text" name="expr" size="35" action="calculate(this.form);"></td></tr>

• Misspellings notwithstanding, the table element does not have a valign attribute whereas its align attribute is deprecated. An align="center" setting would horizontally center the table on the page, however; in practice, all of the calculator tables are horizontally centered by a center element (whose required </center> tag is missing).

• "lightgrey" is now a standard, W3C-approved color keyword: its #rrggbb value is #d3d3d3. The bgcolor="lightgrey" setting colors only a 1px cellpadding rectangle, which even the sharpest-eyed observers are unlikely to notice.

• The action attribute is valid for only the form element: it has a %URI; data type and is not used to call functions.

Tables #2-4 frame the calculator's operator and operand keys.
Table #2 holds the row of keys.
Table #3 holds the row of keys.
Table #4 holds the remainder.
The tables #2-4 code is pretty conventional and doesn't contain any red flags (for some keys the onclick setting contains an unnecessary line break but this doesn't cause any problems) so I won't burden you with it.

Could we code the whole shebang as a single table, maybe put the table #1 content in a thead element and/or code the Jamie's Calculator heading as a caption element? Yep, we could do that.

A form element (whose required </form> tag is missing) consolidates the tables and their controls.

<body bgcolor="red" valink="yellow" alink="yellow" link="yellow">
...table/input code...

Although there aren't any links in the scicalc.html code, let me lastly point out that the valink in the <body> tag should be vlink.

Operation types

We can organize the calculator operations into four categories:
(A) arithmetic
(E) exponential
(L) logarithmic
(T) trigonometric

(A) For an arithmetic calculation, the user enters an expression containing numbers and one or more operators - e.g., 3 * (5 - 7) / 9 - into the expr field and then clicks the key to display the answer.
(E,L,T) For exponential, logarithmic, and trigonometric calculations, the user enters a number into the expr field and then clicks the applicable operator key to display the answer.
Exception: The reciprocal key, which performs an arithmetic (division) operation, is like the (E,L,T) keys.

Operands and their inputs

The 0-9 digit keys call on an enter( ) function to enter their corresponding digits into the expr field, e.g.:

<script language="javascript">
function enter(arg, string) { arg.expr.value += string; }

<td><input type="button" value=" 7 " onclick="enter(this.form, 7);"></td>

Clicking the key calls enter( ) and passes thereto this.form and 7, which are respectively given arg and string identifiers; subsequently, enter( ) appends string to the value of the arg.expr field.

Inputting a decimal point is a bit different, and is problematic.

var decimalsign = " . ";

<td><input type="button" value=" . " onclick="enter(this.form, decimalsign);"></td>

The script's script element features a top-level section in which a space-dot-space string is assigned to a decimalsign variable; clicking the key appends decimalsign to the arg.expr.value as detailed above. As you would surmise, the spaces in decimalsign shouldn't be there, and they prevent the calculator from carrying out calculations on decimalsign-containing inputs, e.g., pressing returns NaN and not 10. Having said this, I should note that the expr field is an ordinary text input in which we can type values via a computer keyboard, and we do also have the option of inputting an unadorned . character via a . keyboard key. Still, we really ought to get rid of those decimalsign spaces, wouldn't you say?

The key does not convert a number to its additive inverse but instead inputs a negativesign for the purpose of entering a negative number.

// Right after the decimalsign declaration:
var negativesign = " -";

<td><input type="button" value=" neg " onclick="enter(this.form, negativesign);"></td>


The +, -, *, and / arithmetic operators are also variabilized

// Just before the decimalsign declaration:
var plussign = " + ";
var minussign = " - ";
var multiplysign = " * ";
var dividesign = " / ";

and are enter( )ed into the expr field à la the operand characters.

<td><input type="button" value=" + " onclick="enter(this.form, plussign);"> <input type="button" value=" - " onclick="enter(this.form, minussign);"></td> ...

Left and right parenthesis (( and )) characters are similarly available for overriding the multiplication/division-over-addition/subtraction order of operations.

var leftbracket = " (";
var rightbracket = ") ";

<td><input type="button" value=" ( " onclick="enter(this.form, leftbracket);"></td> <td><input type="button" value=" ) " onclick="enter(this.form, rightbracket);"></td>

Arithmetic expressions are evaluated by a calculate( ) function.

function calculate(arg) { arg.expr.value = eval(arg.expr.value); }

<td><input type="button" value=" = " onclick="calculate(this.form);"></td>

This is a case that really does require the eval( ) function, or at least I can't think of any other way to do what we want to do here.

Multiplicative inverse

A separate inverse( ) function handles the operation.

function inverse(form) { form.expr.value = 1 / form.expr.value; }

<td><input type="button" value=" 1 / X " onclick="inverse(this.form);"></td>

We'll continue our deconstruction of the calculator's functionality in the following entry.

Monday, May 30, 2016
Meet Me at the Quad, Part 2
Blog Entry #368

On the borders

The next CCC offering is "Perimeter of a Quadrilateral", which was authored by Sam S. Lachterman in late 1997. The Perimeter of a Quadrilateral script asks the user for the width and length of a quadrilateral and then plugs those values into a var perimeter = (width * 2) + (length * 2); statement to give a perimeter, whose scope we will flesh out below.

The Perimeter of a Quadrilateral script code is available here and (excepting its copyright comment) is reproduced below:

<script language="javascript">

function perim( ) { var width = window.prompt("Enter the width of the quadrilateral:", ""); var length = window.prompt("Enter the length of the quadrilateral:", ""); var perimeter = (width * 2) + (length * 2); window.alert("The perimeter of the quadrilateral is " + perimeter + ". This was solved using the formula 2(l+w)."); }
<body bgcolor="#ffffff" onload="perim( );">

Quick comment on the alert( ) message: A 2(l+w) perimeter formula would require us to numberify the width and length, which would otherwise be concatenated and not added.

var perimeter = 2 * (Number(length) + Number(width));

Who's in and who's out

As quadrilateral types go, the (width * 2) + (length * 2) calculation duly applies to rectangles, and I guess we could say it applies to squares too, even as we would be stretching it to say that a square has a width and a length, but that's pretty much it.

A rectangle and a square

(I recognize that length and width are standard terms for the dimensions of a rectangle, but they really don't sit well with me: working with CSS conditions me to prefer width for the horizontal distance and height for the vertical distance.)

A more general (s1 * 2) + (s2 * 2) formulation could accommodate rhombuses, for which s1 and s2 are equal, and other parallelograms lacking right angles

A rhombus and a parallelogram without right angles

and also kites for which s1s2.

A kite

The (s1 * 2) + (s2 * 2) formula won't accommodate trapezoids and trapeziums, however.

A trapezoid and a trapezium

Parallelograms, kites, and trapezoids are convex quadrilaterals, for which both diagonals lie inside the perimeter.
A quadrilateral can be concave: one diagonal is inside the perimeter and one diagonal is outside the perimeter.
A quadrilateral can be complex ("self-intersecting"): both diagonals are outside the perimeter.
(As you would intuit, a trapezium can be convex, concave, or complex.)

A concave quadrilateral and a complex quadrilateral

(s1 * 2) + (s2 * 2) works for some concave and complex quadrilaterals but not for others.

The most general formula for calculating the perimeter of a quadrilateral, perimeter = s1 + s2 + s3 + s4, simply adds up the lengths of all four sides, and is applicable to all quadrilaterals, without exception. So get out your rulers and get measuring, folks.

You're so territorial

Sam also contributes a corresponding "Area of a Quadrilateral" script that asks the user for the width and length of a quadrilateral and then plugs those values into a var times = (width * length); statement to give a(n) times area. À la the Perimeter of a Quadrilateral script, the Area of a Quadrilateral script uses a prompt( ) interface to obtain the quadrilateral width and length and displays its output on an alert( ) box. The Area of a Quadrilateral script code is available here.

lw yea and nay

And how much mileage do we get with the width * length formula? Area = base × height is good for all parallelograms - close enough for government work, eh?

A parallelogram and its base and height

The gas runs out: width * length won't work for a kite that isn't a rhombus, for a trapezoid, or for any other kind of quadrilateral. As for a rhombus, we can get the area of a kite by multiplying the lengths of its diagonals and dividing the product by 2 (d1 * d2 / 2).

A kite and its two diagonals

We can get the area of a trapezoid by multiplying the average of its base lengths by its height.

There are a number of formulas for finding the area of a convex quadrilateral: Wikipedia catalogs them here. There is no general formula for finding the area of any quadrilateral although there is a general approach to doing so, namely,
(a) divide the quadrilateral into smaller shapes whose areas can be determined and then
(b) add up those areas.
Two Web videos that illustrate this approach are:
(1) Area of a quadrilateral on a grid from the Khan Academy
(2) Area of Complex Quadrilateral Figures from MissLichtle

We'll take up the next CCC script, "Another Great Science Calculator", in the following entry.

Wednesday, May 18, 2016
May the Circle Be Unbroken
Blog Entry #367

A couple of months ago we discussed an Areas script that calculates the areas of various two-dimensional geometric shapes. One of those shapes is a circle: upon inputting the radius of a circle, an areac( ) function determines the circle's area via a var sum = radius * radius * pi; operation.

The next Calendars, Clocks, and Calculators (CCC) script is "Circle Circumference", which was written by Sam S. Lachterman in late 1997. The Circle Circumference script should calculate the circumference of a circle from the circle's radius via a C = 2 × π × r equation; in practice, it plugs the radius into a var circl = (radius * radius) * pi; statement to give the area.

Code + brief deconstruction

Excepting the copyright comment in the <head>, the Circle Circumference script code is reproduced below:

<script language="javascript">

function circle( ) { var radius = window.prompt("Enter the radius of the circle:", ""); var pi = "3.141592654"; var circl = (radius * radius) * pi; window.alert("The circumference of the circle is " + circl + ". This was solved using the formula (Rpi)(R)"; }
<body bgcolor="#ffffff" onload="circle( );">

When the script document has loaded, a circle( ) function springs into action. A prompt( ) box soliciting a circle radius immediately pops up. The user inputs a radius and clicks the button on the box and the input is assigned to a radius variable. The radius radius is squared and then the radius2 is multiplied by a toFixed(9) pi value and the resulting product is assigned to a circl variable. Finally, circl plus some supplementary text is displayed on an alert( ) box.

alert( ) formulae

Suppose for a moment that we do want the circle area and that we input a radius of 1 into the prompt( ) box. The alert( ) output will be:

The alert( ) output showing a (Rpi)(R) formula.

The (Rpi)(R) area formula leaves something to be desired, wouldn't you say? Much nicer would be:

The alert( ) output showing an A = π × r² formula.

window.alert("The area of the circle is " + area + ". This was solved using the formula: A = \u03c0 \u00d7 r\u00b2");

Although neither π, ×, nor ² is an ASCII character, we can put all of them in an alert( ) message via their Unicode escape sequences. I find that FileFormat.Info is a useful site for tracking down these sequences; its pages for representing π, ×, and ² are here, here, and here, respectively: go to the "C/C++/Java source code" entry in the Encodings table(s) for the goods.

As for a circumference alert( ), I trust you can write that one out at this point.


The script demo at the Java Goodies radius.html page works as well as could be expected.
(a) The demo outputs a valid circle area if the prompt( ) input is a positive number.
(b) If the input is 0 or if the input field is left blank or if the button on the box is clicked, then the circl return is 0.
(c) A negative number input gives a positive circl - fair enough for an area calculation. If we were actually calculating the circumference, however, then a negative radius would give a negative circl, and that wouldn't make very much sense, now would it?
(d) If the input is a non-empty, non-numeric string (e.g., hello world), then circl is NaN.

Toward the end of getting the circumference I thought it appropriate to give you my own demo, so here we go:

Circumference of a circle

A circle, its circumference, and its radius

C = 2 × π × r

The circumference of the circle is:

Input • The prompt( ) input interface is too 'in your face' for my taste: much better to get the radius via a text input. <div id="circumferenceDiv"> ...Heading, image, and equation, and/or other meta-information as you see fit... <label>Enter the radius of the circle: <input type="text" id="radiusInput"></label> • Trigger circle( ) - wait, let's call it getCircumference( ) - by clicking a push button. function getCircumference( ) { var radius = document.getElementById("radiusInput").value; ... } <button type="button" onclick="getCircumference( );">Get the circumference</button> • No pre-circl validation is provided for the user's input: unwanted numbers and strings should be turned away. if (Number(radius) <= 0 || /\.\d{3,}$/.test(radius) || isNaN(radius) || radius === "") { window.alert("Please enter a positive number with no more than two post-decimal point digits."); document.getElementById("radiusInput").value = ""; document.getElementById("radiusInput").focus( ); return; } No upper limit is set for the radius - you may want to calculate the circumference of Jupiter, after all. • Use Math.PI in place of var pi = "3.141592654". Output • Calculate the circle circumference via a var circumference = 2 * Math.PI * radius; operation. • Lose the alert( ) output. Truncate circumference at the hundredths place and then load it into a samp placeholder on the page. document.getElementById("circumferenceSamp").textContent = circumference.toFixed(2); The circumference of the circle is: <samp id="circumferenceSamp"></samp> I/O • Add a reset capability. function resetCircumference( ) { document.getElementById("radiusInput").value = ""; document.getElementById("circumferenceSamp").textContent = ""; } <button type="button" onclick="resetCircumference( );">Reset</button> </div>

The next two CCC scripts respectively calculate the perimeter and area of a quadrilateral - we ought to be able to deal with both of them in one post.

Saturday, May 07, 2016
Paging Dr. Pythagoras
Blog Entry #366

OK, let's move on now to the next CCC script, "The Pythagorean Theorem". Authored by Greg Bland in early 1998, the Pythagorean Theorem script calculates the length of the hypotenuse (c) of a right triangle from the lengths of the other two sides (a and b) of the triangle via the equation a2 + b2 = c2.

A right triangle with sides a, b, and c

The script demo at the aforelinked Java Goodies pythag.html page works fine as long as you input integers for the a and b lengths - more on this here. The Java Goodies pythag.txt document holding the script code is still live.

What we've got on the rendered page

<form name="pythagorean">
<p>The Pythagorean Theorem<br>
-Geometry's most elegant theorem-<i>a(squared) + b(squared) = c(squared)
<p><input type="button" onclick="touse( );" value="To Use this....">
<p>a <input type="text" name="a" value="">
<p>b <input type="text" name="b" value="">
<p><input type="button" value="Compute.." onclick="solvepg( );">
<p>Output: <input type="text" name="theorem" value="">

The user enters the a and b lengths into text inputs named a and b, respectively. Clicking a push button above the a field calls a touse( ) function that displays a help message on an alert( ) box. Clicking a push button below the b field calls a solvepg( ) function that determines the c length and loads it into a text input named theorem.




A name="pythagorean" form contains the input fields and buttons; a center element horizontally centers the display. As shown, the form and center elements overlap, and they shouldn't do that.

The pythagorean form is prefaced with a header:

The Pythagorean Theorem
-Geometry's most elegant theorem- a(squared) + b(squared) = c(squared)

The a(squared) + b(squared) = c(squared) equation is italicized by an i element whose required </i> tag is missing. The italicization propagates to the a, b, and Output: field labels even though the i element has an (%inline;)* content model; you'd expect the browser to close the i element when it hits the %block; hr element but that doesn't happen.

Also regarding the equation, there's no need to write out (squared) when we can specify the squaring operations with superscripted 2s, e.g., a<sup>2</sup>.

Solve it

function solvepg( ) { a = document.pythagorean; b = a.a.value; c = a.b.value; c = parseInt(c); b = parseInt(b); b = b * b; c = c * c; d = b + c; e = Math.sqrt(d); document.pythagorean.theorem.value = e; }

The solvepg( ) function first gives the pythagorean form an a identifier. The values of the a and b fields of the a form are then assigned respectively to b and c variables. (The a.a and a.b reference expressions don't cause any problems, in case you were wondering.) The b and c strings are subsequently numberified with the parseInt( ) function.

Next, the b and c numbers are squared; b2 is assigned back to b and c2 is assigned back to c. The b and c squares are added: the sum is stored in a d variable. A Math.sqrt( ) operation takes the square root of d: the root is stored in an e variable. Finally, e is assigned to the value of the theorem field.

The parseInt( ) blues

If the a and b user inputs are floating-point numbers, then the parseInt( ) operations will effectively Math.floor( ) those numbers, and we don't want to do that. Consider the 3:4:5 right triangle. If the a input is 2.999 and the b input is 3.999, then the parseInt( ) floorings lead to e = 3.605551275463989 (√13) - not good. It's actually not necessary to explicitly numberify the a.a and a.b values as the attempted multiplication of two numeric strings gives the hoped-for product, although you could appropriately Number( ) them if you feel that doing so improves the code's readability.

Oh yeah...

The touse( ) function is:

function touse( ) { window.alert("Just enter a and b, don't square [them], your computer will do it for you."); }

I think that'll do it for our discussion of the Pythagorean Theorem script. I suppose at this point I could go through some additional changes I would make to the script's HTML (e.g., lose the <form>, convert the <center> to a <div>) and JavaScript (e.g., add a validation conditional that intercepts unwanted number/string inputs, truncate es that run many places past the decimal point) and roll out my own demo, but I trust that you yourself are up to the task of doing those things. Looking forward, then, the next CCC script is "Circle Circumference", and we'll check it out in our next episode.

Wednesday, April 20, 2016
Did We Really Count to Five Hundred?
Blog Entry #365

In today's post we'll go through the Calendars, Clocks, and Calculators (CCC) sector's "Count It!" script. Crafted by "Tigger" in March 1998, the Count It! script counts up from 0 to an inputted positive integer via a running display of integers in a text box. The document holding the Count It! script code is still live as of this writing.

The script demo at the "Tigger's Counting Script" countit.html page works in a sense but not satisfactorily so. If you input, say, 25 in the Count to: field and then click the button, your 25 will instantly appear in the below-the-button field and you won't see any counting at all, that is, the 024 intermediate numbers zoom by much too fast for you to see them. We'll slow things down below.

Control HTML

The user enters the target number into a name="number" text input; the counting takes place in a name="output" text input. A name="form" form contains the number field, a value=" Count! " push button, and the output field. The display is horizontally centered on the page by a center element.

<form name="form"><br><br><br>
Count to:<input type="text" name="number" length="3">
<input type="button" value=" Count! " onclick="go(document.form.number.value);">
<input type="text" name="output">

Neither the input element nor any other HTML element has a length attribute; as the target number is capped at 500 (vide infra), I suspect Tigger meant maxlength rather than length.
• FWIW, the starting space character and the ending space character of the " Count! " button label are rendered by all of the browsers on my computer except Firefox.

Let's go( )

Clicking the button calls a go( ) function and passes thereto the number field's value, which is given a number identifier.

<script language="JavaScript">
function go(number) { ... }

The go( ) function body first tests if number is greater than 500; if the test returns true, then
(a) a "That's pretty high, so I'll set it to 500" alert( ) pops up and
(b-c) number and the number field's value are lowered to 500.

if (number > 500) { window.alert("That's pretty high, so I'll set it to 500."); number = 500; document.form.number.value = "500"; }

number initially has a string data type and is converted to a number for the number > 500 comparison.

This is as much validation as we get from the go( ) function: there are no checks for non-numeric strings, floating-point numbers, or negative numbers.

With number capped at 500, the for statement below increments an n counter from 0 to number and sequentially loads the n values into the output field.

for (n = 0; n <= number; n++) { document.form.output.value = n; window.setTimeout("", 500); }

A setTimeout( ) command whose expression parameter is set to an empty string and whose msec parameter is set to 500 is meant to serve as a delaying tactic that allows us to see discrete ns as the loop runs. It doesn't work in practice, and you wouldn't expect it to work in practice, because...
window.setTimeout( ) does not stall the script. The script continues immediately (not waiting for the timeout to expire). The call simply schedules a future event.
So, we schedule "" to happen in 500 milliseconds and long before we get to that "" n will have reached number and the latter is all we see. Did the delaying work once upon a time when processors were more primitive than what we have today? Maybe, but that was then and this is now.

More generally, we shouldn't be using a loop to count n in the first place: loops are meant to iteratively execute one or more statements as quickly as possible vis-à-vis in a controlled, gradual manner. However, this doesn't mean that we have to start from scratch to sort out the situation; we can achieve the desired effect if we
(1) have the setTimeout( ) command recursively call go( ),
(2) externalize the n initialization, and
(3) deploy the remaining parts of the loop in a corresponding if conditional.

var n = 0, countID; function go(number) { ...number-vetting code... if (n <= number) { document.form.output.value = n; n++; countID = window.setTimeout(function ( ) { go(number) }, 500); } else n = 0; }


Let's go back to the original script for a moment. If we leave the number field blank and click the button, then our empty string 'input' is converted to 0 for the n <= number loop condition; in this case, the loop runs for one iteration and document.form.output.value = 0 is as high as we go.

All other non-numeric inputs convert to NaN for the n <= number condition. The 0 <= NaN comparison returns false and therefore the loop doesn't run for any iterations (the condition is evaluated a single time and that's all that happens) and no counting occurs. FYI: According to Netscape, NaN is not equal to anything, including NaN.

For a negative number input, the n <= number condition again returns false from the get-go and no counting occurs. (But perhaps you might like to count down to a negative number - we go in reverse here.)

For a floating-point number input, go( ) counts to Math.floor(Number(number)), which is OK, but I'd rather it count to Math.round(Number(number)).

All things considered, here's the number-vetting code I'd use:

if (Number(number) < 0 || 500 < Number(number) || isNaN(number) || number === "") { window.alert("Please enter a positive integer in the range:\n0 \u2264 n \u2264 500"); document.form.number.value = ""; document.form.number.focus( ); return; } if (number.toString( ).indexOf(".") != -1) { number = Math.round(Number(number)); document.form.number.value = number; window.alert("We're going to round your input to: " + Math.round(number)); }

• Upon round( )ing a floating-point number input in a first go( ) iteration it is necessary to toString( ) number for the indexOf( ) test in subsequent go( ) iterations. Alternatively, if we deparameterize go( ) and (re-)type number as a string at the beginning of the go( ) body via

var number;
function go( ) { number = document.form.number.value; ... countID = window.setTimeout(go, 500); ... }

<input type="button" value=" Count! " onclick="go( );">

then the toString( ) conversion is unnecessary.

\u2264 is the Unicode escape sequence for a ≤ character.

Bells and whistles

Stop it

You type 500 in the number field and click the button. When n hits 100 you think, "All right, I get the idea, let's pull the plug on this." For stopping the count in midstream we can add:

function stopCount( ) { window.clearTimeout(countID); }

<input type="button" value="Stop the Count" onclick="stopCount( );">

Start over

We naturally want to add a reset capability to the display. A complete reset requires us to not only blank the number and output fields but also send n back to 0.

If we hold onto the form form, then adding our reset is no more complicated than appending an <input type="reset" value="Reset" onclick="n=0;"> child to the form.

In the demo below, I replace the form and its <center> parent with a <div style="text-align:center;"> container, give the number field an id="numberInput", and exchange the output field for an id="outputSamp" samp placeholder, and I accordingly clear the decks with:

function resetCount( ) { n = 0; document.getElementById("numberInput").value = ""; document.getElementById("outputSamp").textContent = ""; }

Count to: <input id="numberInput" name="number">
The current count is: <samp id="outputSamp"></samp>
<button type="button" onclick="resetCount( );">Reset</button>

Color it

My demo randomly colors the n numbers with code borrowed from the HTML Goodies JavaScript Script Tips #81-83 script; the colors are accentuated by beefing up the n font-size to 48px.

#outputSamp { font-size: 48px; }

var defClrsArray, colorIndex;
defClrsArray = ["red", "purple", "aqua", "green", "blue", "fuchsia", "orange", "brown"];

function go( ) { ... if (n <= number) { colorIndex = Math.floor(Math.random( ) * defClrsArray.length); document.getElementById("outputSamp").style.color = defClrsArray[colorIndex]; document.getElementById("outputSamp").textContent = n; n++; countID = window.setTimeout(go, 500); } ... }


The current count is:

The financial countdown

On the CCC portal page, Joe comments that the Count It! script is useless - but fun. Hmmm... I think of the downward counts in the "Fast Money" part of Family Feud. If you won $20,000 by giving the right answers to questions during those counts, that wouldn't be so useless, would it? So let's put 20 seconds on the clock, which will start after I read the first question and you click the button below...
The current count is: 00:20
(I trust you can write out the code for this, yes?)
We'll briefly discuss some more geometry-related scripts and then perhaps start work on a calculator script in the following entry.

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Folgers' Classic Roast. ;-)