reptile7's JavaScript blog
Tuesday, March 22, 2016
Your id, Señor Clock
Blog Entry #363
Our tour of the Java Goodies Calendars, Clocks, and Calculators sector next brings us to a "DHTML Clock" script, which we'll check over in today's entry. Authored by Paul Swonger in April 1998, the DHTML Clock script creates and displays a running digital clock. You can see the clock at the dhtmlclock.html page; the dhtmlclock.txt Grab the Script page is still available.
As regards running the script, Joe warns:
MSIE 4.0 Required- I'll address this in due course, but for the time being, let's just get right to the code, shall we?
A home for our clock
The DHTML Clock clock is housed in a styled, id="Clock"
<div>
.<div id="Clock" align="center"
style="font-family:Verdana;font-size:40;color:#0000ff;"> </div>
• The align attribute of the div element is obsoleted by HTML5: use a text-align:center; styling to horizontally center the clock in the div.
• CSS lengths lacking unit identifiers are illegal: specify the font-size:40; declaration as font-size:40px;.
Time starting materials
The clock is set in motion by a tick( ) function that fires when the script document has finished loading.
<script type="text/javascript">
function tick( ) { ... }
window.onload = tick;
</script>
The tick( ) function body begins by declaring eight variables.
var today, intHours, intMinutes, intSeconds, hours, minutes, seconds, ap;
Next, tick( ) creates a new Date( ) object, which is assigned to today; subsequent statements get the today hour, minute, and second, and assign them to intHours, intMinutes, and intSeconds, respectively.
today = new Date( );
intHours = today.getHours( );
intMinutes = today.getMinutes( );
intSeconds = today.getSeconds( );
Display components
The DHTML Clock clock is a 12-hour clock whose display includes an hours part, a minutes part, a seconds part, and an ap a.m./p.m.-type indicator.
hours and ap
With the intHours hour in hand, tick( ) determines the hours and ap parts of the clock via the following if...else if...else if...else series of statements:
if (intHours == 0) {
hours = "12:";
ap = "Midnight"; }
else if (intHours < 12) {
hours = intHours + ":";
ap = "A.M."; }
else if (intHours == 12) {
hours = "12:";
ap = "Noon"; }
else {
intHours = intHours - 12;
hours = intHours + ":";
ap = "P.M."; }
Somewhat strangely, the ap indicator will read Midnight for the entire 12 a.m. to 1 a.m. hour and Noon for the entire 12 p.m. to 1 p.m. hour - don't know 'bout you, but I don't like that* - here's how I'd handle all of this:
ap = intHours < 12 ? "a.m." : "p.m.";
if (intHours == 0) hours = "12:";
else if (intHours < 13) hours = intHours + ":";
else hours = (intHours - 12) + ":";
• Re the ap assignment, the < operator takes precedence over the conditional operator so there's no need to parenthesize the
intHours < 12
condition.*As it happens, there is in fact a "noonhour" word for the 12 p.m. to 1 p.m. hour, but I'm not gonna use that, either.
minutes and seconds
The minutes and seconds parts of the clock are set with:
if (intMinutes < 10) { minutes = "0" + intMinutes + ":"; }
else { minutes = intMinutes + ":"; }
if (intSeconds < 10) { seconds = "0" + intSeconds + " "; }
else { seconds = intSeconds + " "; }
I would compact these assignments with the conditional operator as well:
minutes = intMinutes < 10 ? "0" + intMinutes + ":" : intMinutes + ":";
seconds = intSeconds < 10 ? "0" + intSeconds + " " : intSeconds + " ";
Going live
The hours, minutes, seconds, and ap strings are concatenated
var timeString = hours + minutes + seconds + ap;
and the resulting timeString string is subsequently loaded into the Clock div.
Clock.innerHTML = timeString;
A setTimeout( ) command updates the clock every 100 milliseconds.
window.setTimeout("tick( );", 100);
The current versions of IE and Netscape in April 1998 were IE 4.x and Netscape 4.x, respectively. Unlike IE 4.x, Netscape 4.x does not support the use of standalone ids as object references - on my computer, Communicator 4.61 throws a
Clock is not definedJavaScript Error when it hits the
Clock.innerHTML = timeString;
line - so that's what the MSIE 4.0 Required business is all about. Microsoft would today recommend that we use the getElementById( ) method to locate the Clock div - see the Note below this example.document.getElementById("Clock").innerHTML = timeString;
One more point before moving on: Mozilla would today recommend that we use the
window.setTimeout(tick, 100);
setTimeout( ) syntax to update the clock.
A Netscape port
Netscape 4.x doesn't support the innerHTML property, either; indeed, classical JavaScript (JS 1.0-1.3, before the client-side stuff was shipped off to the DOM) doesn't have any properties for setting the text of a textual element - the closest we get is the text property of the anchor/link objects, which is read-only for Netscape 4.x (but is actually writable for some modern browsers, including Firefox). This doesn't mean that we can't adapt the DHTML Clock script for Netscape 4.x, however; here's how:
(1) Give the Clock div a relative positioning so as to layerize it.
body { background-color: white; }
#Clock, #Clock2 { text-align: center; font-family: Verdana; font-size: 40px; color: blue; position: relative; }
<body>
<div id="Clock"></div>
(2-4) Via the document property of the layer object and the write( ) method of the document object, write an id='Clock2' div containing the timeString string to the Clock layer. After that, close( )** the document.Clock.document. Wrap the document.Clock.document commands in an if (document.layers) { ... } conditional to keep non-Netscape 4.x browsers at bay.
if (document.layers) {
document.Clock.document.write("<div id='Clock2'>" + timeString + "<\/div>");
document.Clock.document.close( ); }
else Clock.innerHTML = timeString;
**It's not necessary to begin with a corresponding open( ) call, but the close( ) operation is definitely necessary to ensure that only one Clock2 div is written in the Clock layer.
Sensibly, Netscape abandoned the layer interface and brought innerHTML on board for Netscape 6.
Old-school dynamicity
The classical way of outputting a JavaScript digital clock is by loading it into an
<input type="text">
.document.clockForm.clockInput.value = timeString;
<form name="clockForm" action="">
<input name="clockInput">
</form>
We previously worked with an input digital clock in HTML Goodies' JavaScript Script Tips #25-28, which we discussed in Blog Entry #61.
Does an input clock also count as a DHTML clock? I would certainly say so, given that we are dynamically (the "D" stands for "Dynamic", right?) changing the value attribute of an HTML input element, good enough. Relatedly, I find that Firefox, Google Chrome, and Opera all apply the
#Clock
styles (vide supra) to an input clock display. BTW, the image-based clock discussed in Blog Entry #359 is a DHTML clock too.Demo
We may or may not get into some trigonometry in the following entry.
Saturday, March 12, 2016
Things of Shapes, Side B
Blog Entry #362
Let's get back now to our discussion of the Areas script's various functions.
areao( ) and volumerp( )
Ovals/ellipses
The terms "oval" and "ellipse" are often used interchangeably, and an "area of an oval" Google search returns many pages for calculating the area of an ellipse; in actuality, an ellipse
has a clearly defined shape and area but an oval doesn't.
With respect to the above ellipse image, the area of an ellipse is given by A = (width / 2) × (height / 2) × π. Assuming that "oval" really means "ellipse" in the Areas script, the areao( ) function gives us something altogether different:
function areao( ) {
var length = window.prompt("Enter the length");
var height = window.prompt("Enter the height");
var pi = 3.14159;
var sum = (pi * length) / height;
window.alert("The area is " + sum + ""); }
I don't know what shape, if any, the
pi * length / height
calculation is relevant to, but no matter: we'll use the right ellipse area formula in the demo below.Rectangular prisms
A rectangular prism ("rectangular box" is my preferred term for this shape)
is basically a three-dimensional rectangle; its volume is given by V = length × width × height, and that's what you get with the volumerp( ) function:
function volumerp( ) {
var length = window.prompt("Enter length");
var width = window.prompt("Enter width");
var height = window.prompt("Enter height");
var sum = length * width * height;
window.alert("The volume is " + sum + ""); }
Image credits
(6) The ellipse image appears courtesy of The GNOME Project. The oval image appears courtesy of ClipartPanda.com.
(7) The rectangular prism image appears courtesy of the 5th Grade Math and Science Team at Southwood Elementary School.
Merci beaucoup, guys.
Demo considerations
I didn't like the prompt( )/alert( ) interface in the Slope script*, and I don't like it in the Areas script, either; once again, I'd much rather gather the user's inputs with
<input type="text">
s and then display the results on the page by loading them into <samp>
s.(*We covered the Slope script in Blog Entry #360, which provides links to reference pages for the samp element, the getElementsByTagName( ) method, regular expressions, the toFixed( ) method, the Number( ) function, and the isNaN( ) function, which all crop up below.)
I wanted to
(a) access the
<input>
s for each area/volume determination and (b) vet the
<input>
s' values and(c) bound the number of output digits and
(d) print out the various outputs
via common units of code located in or called by a common getAorV( ) function. I also wanted to
(e) be able to reset the inputs and outputs for each determination
via a common reset( ) function.
I began by putting the HTML for each determination in a separate
<div>
with a parametric id: triangleDiv, circleDiv, etc. I then gave the aforementioned <samp>
s a related set of parametric ids: triangleSamp, circleSamp, etc.<div id="triangleDiv">
<h3>Area of a triangle</h3>
<img width="218" height="117" src="triangle.gif" alt="A triangle, its base, and its height"><br><br>
A = b × h / 2<br>
<label>Enter the length of the triangle base (b): <input size="5"></label><br>
<label>Enter the height (h) of the triangle: <input size="5"></label><br>
<button type="button" onclick="getAorV('triangle');">Get the area</button><br>
Your area is: <samp id="triangleSamp"></samp><br>
<button type="button" onclick="reset('triangle');">Reset</button>
</div><br> ...
We can now JavaScriptically tie the
<div>
s and <samp>
s together via a general shape variable:function getAorV(shape) {
var shapeInputs = document.getElementById(shape + "Div").getElementsByTagName("input");
...Vetting code...
var area_or_volume;
...Area/volume calculations...
if (/\.\d{3,}$/.test(area_or_volume)) area_or_volume = area_or_volume.toFixed(2);
document.getElementById(shape + "Samp").textContent = area_or_volume; }
For the
Vetting code
, I wanted to limit the user inputs to a 0 < x < 100 range, limit the input precision to two places past the decimal point, and of course weed out unwanted strings. Here we go:for (var i = 0; i < shapeInputs.length; i++) {
if (Number(shapeInputs[i].value) <= 0 || 100 <= Number(shapeInputs[i].value) || /\.\d{3,}$/.test(shapeInputs[i].value) || isNaN(shapeInputs[i].value) || shapeInputs[i].value === "") {
window.alert("Please enter positive numbers in the range\n0 \u003c x \u003c 100\nand with no more than two post-decimal point digits.");
shapeInputs[i].value = "";
shapeInputs[i].focus( );
return; } }
/* \u003c is the Unicode escape sequence for the < character. */
The
Area/volume calculations
themselves can be carried out via a series of if statements or a switch statement, as per your preference.if (shape == "triangle" || shape == "rhombus")
area_or_volume = shapeInputs[0].value * shapeInputs[1].value / 2;
if (shape == "circle")
area_or_volume = Math.PI * Math.pow(shapeInputs[0].value, 2);
// Etc.
And as we know how to access the
<input>
s and <samp>
for each determination it is simple enough to reset them by setting their values/textContent to empty strings:function reset(shape) {
var shapeInputs = document.getElementById(shape + "Div").getElementsByTagName("input");
for (var i = 0; i < shapeInputs.length; i++) shapeInputs[i].value = "";
document.getElementById(shape + "Samp").textContent = ""; }
Demo
The demo below incorporates the code presented in the preceding section - try it out with any inputs you like - the images therein are all 'homemade', BTW.
Area of polygons (and of a circle)!
Volume of three-dimensional figures
Another clock script is next.
Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)