JavaScript

Assignments From Chapter 19

Solutions Assignments JSN.1

Assignment JS.1.0

Take a close look at the following data and programming hints:

Example B.46. A Given Data Structure Plus Some Hints
var languages = [];     // languages is an indexed array, Key10a page 14
                        // each array element is an object, Key10a page 16
languages[0] = { countrycode: 'AFG'
    , language: 'Balochi', percentage: '0.9', population: '22720000' };
languages[1] = { countrycode: 'AFG'
    , language: 'Dari', percentage: '32.1', population: '22720000' };
languages[2] = { countrycode: 'AFG'
    , language: 'Pashto', percentage: '52.4', population: '22720000' };
languages[3] = { countrycode: 'AFG'
    , language: 'Turkmenian', percentage: '1.9', population: '22720000' };
languages[4] = { countrycode: 'AFG'
    , language: 'Uzbek', percentage: '8.8', population: '22720000' };
languages[5] = { countrycode: 'TJK'
    , language: 'Russian', percentage: '9.7', population: '6188000' };
languages[6] = { countrycode: 'TJK'
    , language: 'Tadzhik', percentage: '62.2', population: '6188000' };
languages[7] = { countrycode: 'TJK'
    , language: 'Uzbek', percentage: '23.2', population: '6188000' };
languages[8] = { countrycode: 'UZB'
    , language: 'Karakalpak', percentage: '2.0', population: '24318000' };
languages[9] = { countrycode: 'UZB'
    , language: 'Kazakh', percentage: '3.8', population: '24318000' };
languages[10] = { countrycode: 'UZB'
    , language: 'Russian', percentage: '10.9', population: '24318000' };
languages[11] = { countrycode: 'UZB'
    , language: 'Tadzhik', percentage: '4.4', population: '24318000' };
languages[12] = { countrycode: 'UZB'
    , language: 'Tatar', percentage: '1.8', population: '24318000' };
languages[13] = { countrycode: 'UZB'
    , language: 'Uzbek', percentage: '72.6', population: '24318000' };

// How to address and display two object properties given an index
var i = 10;
window.alert(languages[i].countrycode + " " + languages[i].percentage);


var countries = [];     // We create an array
                        // if there is nothing at a certain index
                        // index is associative
                        // then we put some data in there
if (! countries[languages[i].countrycode]) {
    countries[languages[i].countrycode] = languages[i].countrycode;
}

// how to display what is at a certain index in associative array
window.alert(countries[languages[i].countrycode]);
window.alert(countries['UZB']);

Copy the languages array code into a JavaScript file, and write code so that we get an associative array countries with exactly one entry per country. Print the array elements. Print the array length.

Hint: You may use window.alert() for output, but it may be more convenient to use console.log() in stead. If you do, press Ctrl->Shift->i and then test. This will give you the console log in a separate part of the window. The parameter for both those functions is a string. Later you will be taught to make output that is part of the page markup.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.1.1

Please refer to the JavaScript array given in the previous assignment and do as follows.

Write a page that loops through the languages array, and for each iteration, each object in the array, you must output the countrycode, the name of the language and a calculated number of how many people speak this language in that country.

Hint: You may use window.alert() for output, but it may be more convenient to use console.log() in stead. If you do, press Ctrl->Shift->i and then test. This will give you the console log in a separate part of the window. The parameter for both those functions is a string.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.1.1 Model Solution
Example B.47. js11.html
<!doctype html>
<html>
    <head>
        <title>JS1.0</title>
        <meta charset='utf-8'/>
        <script>
            var languages = [];     // languages is an indexed array, Key10a page 14
                                    // each array element is an object, Key10a page 16
            languages[0] = { countrycode: 'AFG', language: 'Balochi', percentage: '0.9', population: '22720000' };
            languages[1] = { countrycode: 'AFG', language: 'Dari', percentage: '32.1', population: '22720000' };
            languages[2] = { countrycode: 'AFG', language: 'Pashto', percentage: '52.4', population: '22720000' };
            languages[3] = { countrycode: 'AFG', language: 'Turkmenian', percentage: '1.9', population: '22720000' };
            languages[4] = { countrycode: 'AFG', language: 'Uzbek', percentage: '8.8', population: '22720000' };
            languages[5] = { countrycode: 'TJK', language: 'Russian', percentage: '9.7', population: '6188000' };
            languages[6] = { countrycode: 'TJK', language: 'Tadzhik', percentage: '62.2', population: '6188000' };
            languages[7] = { countrycode: 'TJK', language: 'Uzbek', percentage: '23.2', population: '6188000' };
            languages[8] = { countrycode: 'UZB', language: 'Karakalpak', percentage: '2.0', population: '24318000' };
            languages[9] = { countrycode: 'UZB', language: 'Kazakh', percentage: '3.8', population: '24318000' };
            languages[10] = { countrycode: 'UZB', language: 'Russian', percentage: '10.9', population: '24318000' };
            languages[11] = { countrycode: 'UZB', language: 'Tadzhik', percentage: '4.4', population: '24318000' };
            languages[12] = { countrycode: 'UZB', language: 'Tatar', percentage: '1.8', population: '24318000' };
            languages[13] = { countrycode: 'UZB', language: 'Uzbek', percentage: '72.6', population: '24318000' };

            for (var i = 0; i < languages.length; i++) {    // regular for loop
                var s = languages[i].countrycode + " ";     // put countrycode into string
                s += languages[i].language + " ";           // language into string
                s += Math.floor(languages[i].percentage * languages[i].population / 100);
                                                            // calculation into string
                                                            // Math.floor ditches decimals 
                console.log(s);                             // prints on log
            }
        </script>
    </head>
    <body>
        <h1>JS 1.1</h1>
        <p>
            Check the console.log, press Ctrl->Shift->i
        </p>
    </body>
</html>
        

Show in browser.


Assignment JS.1.2

Please refer to the JavaScript array given above and do as follows.

Write a page that loops through the languages array, and calculates how many people speak each language. You must create an array for each language, one element per language, and then loop through that array and print the results.

Hint: You may use window.alert() for output, but it may be more convenient to use console.log() in stead. If you do, press Ctrl->Shift->i and then test. This will give you the console log in a separate part of the window. The parameter for both those functions is a string.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.1.2 Model Solution
Example B.48. js12.html
<!doctype html>
<html>
    <head>
        <title>JS1.0</title>
        <meta charset='utf-8'/>
        <script>
            var languages = [];     // languages is an indexed array, Key10a page 14
                                    // each array element is an object, Key10a page 16
            languages[0] = { countrycode: 'AFG', language: 'Balochi', percentage: '0.9', population: '22720000' };
            languages[1] = { countrycode: 'AFG', language: 'Dari', percentage: '32.1', population: '22720000' };
            languages[2] = { countrycode: 'AFG', language: 'Pashto', percentage: '52.4', population: '22720000' };
            languages[3] = { countrycode: 'AFG', language: 'Turkmenian', percentage: '1.9', population: '22720000' };
            languages[4] = { countrycode: 'AFG', language: 'Uzbek', percentage: '8.8', population: '22720000' };
            languages[5] = { countrycode: 'TJK', language: 'Russian', percentage: '9.7', population: '6188000' };
            languages[6] = { countrycode: 'TJK', language: 'Tadzhik', percentage: '62.2', population: '6188000' };
            languages[7] = { countrycode: 'TJK', language: 'Uzbek', percentage: '23.2', population: '6188000' };
            languages[8] = { countrycode: 'UZB', language: 'Karakalpak', percentage: '2.0', population: '24318000' };
            languages[9] = { countrycode: 'UZB', language: 'Kazakh', percentage: '3.8', population: '24318000' };
            languages[10] = { countrycode: 'UZB', language: 'Russian', percentage: '10.9', population: '24318000' };
            languages[11] = { countrycode: 'UZB', language: 'Tadzhik', percentage: '4.4', population: '24318000' };
            languages[12] = { countrycode: 'UZB', language: 'Tatar', percentage: '1.8', population: '24318000' };
            languages[13] = { countrycode: 'UZB', language: 'Uzbek', percentage: '72.6', population: '24318000' };

            var countries = [];     // We create an array
            for (var i = 0; i < languages.length; i++) {
                if (! countries[languages[i].language]) {   // is language not there, put it there with calc number
                    countries[languages[i].language] = Math.floor(languages[i].percentage * languages[i].population / 100);
                } else {                                    // if language already there, add number
                    countries[languages[i].language] += Math.floor(languages[i].percentage * languages[i].population / 100);
                }
            }

            for (var idx in countries) {                    // special for loop (foreach)
                var s = idx + " ";                          // prints all elements in
                s += countries[idx];                        // associative array
                console.log(s);
            }
        </script>
    </head>
    <body>
        <h1>JS 1.2</h1>
        <p>
            Check the console.log, press Ctrl->Shift->i
        </p>
    </body>
</html>
        

Show in browser.


Assignment JS.Loops.2.2 Functions

Definition

A natural number p is called prime if p ≠ 1 and the only numbers that divide p are 1 and p itself.

Fundamental Theorem of Arithmetic

Every natural number greater than 1 is either prime or can be written uniquely as a product of prime numbers.

There is a nice proof of that theorem but since this is no math class, we shall skip that, and just trust that it is so, and use it.

Now you must solve at least number 1 of the following. If you have the energy and skill you may want to have a go at the next ones too, but please solve the rest of this chapter's assignments before spending time on that.

  1. Write a function isPrime(p) that returns true if p is prime, and false otherwise.
  2. Write a function that creates a collection of the primes dividing p if isPrime(p) === false.
  3. Write a procedure that lists the primes dividing p if isPrime(p) === false.
  4. If you haven't already done so in number 2 above, please augment that function so that it accepts and reflects that a prime may divide p more than once.

Write an HTML5 page that allows for testing your function(s).

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.2.2 Model Solution
Example B.49.  js22.js, js22.html
/*global document, window */
'use strict';

/*
 * js22.js
 */
var isNumeric = function () {
    var obj = process.argv[2];
    var arg = parseInt(obj);
    if (isNaN(arg) || arg <= 1 || arg > Number.MAX_SAFE_INTEGER) {
        process.exit(1);
    } else{
        return arg;
    }
}

var primality = function () {
    var arg = isNumeric();
    if (! arg) {
        return false;
    }
    let s = "";
    var start = new Date();
    let b = isPrime(arg);
    var stop = new Date();
    var elapsed = "      " + (stop - start) + " ms";
    if (b) {
        s = arg + " is a prime" + elapsed;
    } else {
        s = arg + " is not a prime" + elapsed;
    }
    console.log(s);
}

var primalityN = function () {
    var arg = isNumeric();
    if (! arg) {
        return false;
    }
    let s = "";
    var start = new Date();
    let b = isPrimeN(arg);
    var stop = new Date();
    var elapsed = "      " + (stop - start) + " ms";
    if (b) {
        s = arg + " is a prime" + elapsed;
    } else {
        s = arg + " is not a prime" + elapsed;
    }
    console.log(s);
}

var isPrime = function (arg) {
    if (arg % 2 === 0) 
        return false; 
    for (var i = 3; i <= Math.sqrt(arg); i += 2) {
        if (arg % i === 0) {
            return false;
        }
    }
    return true;
}

var isPrimeN = function (arg) {
    if (arg % 2 === 0 || arg % 3 === 0) 
        return false; 
                
    var i = 1;
    var lim = Math.sqrt(arg);
    var divm1 = 6 * i - 1;
    var divp1 = 6 * i + 1;
        
    while (divm1 <= lim || divp1 <= lim) {
        if (arg % divm1 === 0 || arg % divp1 === 0)
            return false;
        i++;
        divm1 = 6 * i - 1;
        divp1 = 6 * i + 1;
    }
    return true;
}

var factor = function (arg) {
    var arr = [];
    var i = 2;
    var modarg = arg / i;
    while (i <= modarg) {
        if (arg % i === 0) {
            arg /= i;
            if (!arr[i])
                arr[i] = 1;
            else
                arr[i]++;
        } else {
            i++;
        }
        if (arg === 1)
            break;
        if (isPrimeN(arg)) {
            i = arg;
        }
    }
    return arr;
}

var printPrimeFactors = function () {
    var arg = isNumeric();
    if (! arg) {
        return false;
    }

    var s = "";                     // init string
    if (isPrimeN(arg)) {
        s = " number is prime";     // either prime
    } else {
        var start = new Date();
        var pfa = factor(arg);
        var stop = new Date();
        for (var i in pfa) {
            s += i;                 // if not, place factor
            if (pfa[i] > 1) {
                s += '^' + pfa[i];  // power of factor if > 1
            }
            if (i < pfa.length -1 ) { // add asterisk execpt after last
                s += " * ";
            }
        }
    }
    console.log("Primefactors of " + arg + ": " + s + "     " + (stop-start) + " ms");
}

printPrimeFactors();
primality();
//primalityN();

        
nmlX240 testjs  $ node js22 52637369
Primefactors of 52637369:  number is prime     NaN ms
52637369 is a prime      0 ms
52637369 is a prime      0 ms
nmlX240 testjs  $ node js22 526373691001
Primefactors of 526373691001: 37 * 1091 * 13039703     7 ms
526373691001 is not a prime      0 ms
526373691001 is not a prime      0 ms

Assignment JS.2.3 Functions

Write a JavaScript function that calculates the factorial value of an integer. Write an HTML5 page that allows for testing it for different integer values. You may use window.prompt() and window.alert() for input/output.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.2.3 Model Solution
Example B.50.  js23.js, js23.html
/*global document, window */
'use strict';

/*
 * js23.js
 */
var validity = function () {
    var obj = document.forms.myform;
    var arg = parseInt(obj.num.value);
    if (isNaN(arg) || arg < 1) {
        obj.result.value = "invalid number";
        obj.num.focus();
        return false;
    }
    
    obj.result.value = factorial(arg);
    return true;
}

var factorial = function (arg) {
    if (arg === 1)
        return 1;
    else 
        return arg * factorial(arg - 1); 
}

var initialize = function () {
    document.getElementById('mybutton').addEventListener('click', validity);
}

window.addEventListener('load', initialize);
        
<!doctype html>
<html>
    <head>
        <title>JS2.3</title>
        <meta charset='utf-8'/>
        <script src="js23.js"></script>
    </head>
    <body>
        <h1>JS 2.3</h1>
        <form id='myform' action='#' method='post'>
            <p>
                Enter positive integer:<br/>
                <input type='text' name='num'/>&nbsp;&nbsp;&nbsp;
                <input type='text' name='result' readonly/>
            </p>
            <p>
                <input type='button' id="mybutton" value='Check'/>
                <input type='reset' value='Reset'/>
            </p>
        </form>
    </body>
</html>
        

Show in browser.


Assignment JS.2.4 Events

Write an HTML5 page with at least three div, or p elements in the body. A few lines of text in each. You may use http://lipsum.com/. Write some JavaScript such that when the user hovers over an element it's style is changed so that it will display a red outline with a 2px line. When the mouse is moved away, the outline must disappear.

Hint: You may want to research the mouseover, and mouseout events.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.2.4 Model Solution
Example B.51.  js24.js, js24.html
/*global document, window */
'use strict';

/*
 * js24.js
 */
var hovered = function (e) {
    e.target.style = 'outline: 2px solid red;';
}
var unhovered = function (e) {
    e.target.style = 'outline: 0px solid red;';
}

var initialize = function () {
    var arr1 = document.getElementsByTagName('p');
    var arr2 = document.getElementsByTagName('div');
    for (var i = 0; i < arr1.length; i++) {
        arr1[i].addEventListener('mouseover', hovered)
        arr1[i].addEventListener('mouseout', unhovered)
    }
    for (var i = 0; i < arr1.length; i++) {
        arr2[i].addEventListener('mouseover', hovered)
        arr2[i].addEventListener('mouseout', unhovered)
    }
}

window.addEventListener('load', initialize);
        
<!doctype html>
<html>
    <!-- js24.html -->
    <head>
        <meta charset="utf-8"/>
        <title>Form Example</title>
        <script src="js24.js"></script>
    </head>
    <body>
        <h1 id="headline">Model Sol</h1>
        <p>
            Write an HTML page with at least three div, or p elements in the body. A few lines of text in each. You may use http://lipsum.com/.  
        </p>
        <div>
            Write some JavaScript such that when the user hovers over an element it's style is changed so that it will display a red outline with a 2px line. When the mouse is moved away, the outline must disappear.
        </div>
        <p>
            Hint: You may want to research the mouseover, and mouseout events.
        </p>
        <div>
            Hint for beginners: You may prefer to work with embedded JavaScript
            while you test your code. Once it works as desired, separate the
            JavaScript into an individual .js file, test again, then hand
            in your solution.
        </div>
    </body>
</html>
        

Show in browser.


Assignment JS.2.5 Events

Write an HTML5 page with an empty div element in the body. Write some JavaScript such that when the user types on the keyboard, the entered data is display in the formerly empty div element.

Hint: You may want to research the innerHTML property of DOM elements, in addition to keydown, keyup, and/or keypress events.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.2.5 Model Solution
Example B.52.  js25.js, js25.html
/*global document, window */
'use strict';

/*
 * js25.js
 */
var insChar = function (e) {
    var key = String.fromCharCode(e.keyCode || e.charCode)
    $('abc').innerHTML += key;
}
var focused = function (e) {
    window.addEventListener('keypress', insChar);
    $('abc').focus();
    $('abc').addEventListener('mouseout', blurred);
    $('abc').style = 'outline: 2px solid red; width: 50%; height: 300px;';
}
var blurred = function (e) {
    window.removeEventListener('keypress', insChar);
    $('abc').style = 'outline: 1px solid red; width: 50%; height: 300px;';
}

var initialize = function () {
    $('abc').addEventListener('mouseover', focused);
    // window.alert('test');
}

window.addEventListener('load', initialize);

        
<!doctype html>
<html>
    <!-- js25.html -->
    <head>
        <meta charset="utf-8"/>
        <title>Code Example</title>
        <script src='nQuery.js'></script>
        <script src="js25.js"></script>
    </head>
    <body>
        <h1 id="headline">Model Sol</h1>
        <p>
            Write an HTML page with an empty div element in the body.
            Write some JavaScript such that when the user types on the
            keyboard, the entered data is display in the formerly empty
            div element.
        </p>
        <div id='abc' style='outline: 1px solid red; width: 50%; height: 300px;'/></div>
    </body>
</html>

        

Show in browser.


Assignment JS.2.6 IO Forms

Using the form from Example 19.30, add a text field, and a date field, then please write a PHP page displaying the values received from the form. All fields must be validated before being submitted. Hand in html file with form, js file with validation, and php file with output.

Hint: Generally form data are delivered to the recipient through the CGI interface in either the GET, or the POST array.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.2.6 Model Solution
Example B.53.  js26.js, js26.html, hitme.php
'use strict';
/*
 * js26.js
 */
var isValid = function (e) {
    var a = parseInt(e.target.inpfield0.value);
    if (isNaN(a)) {
        window.alert("Erroneous input. Must be a number!");
        e.target.inpfield0.focus();
        e.preventDefault();
        return false;
    }
    if (!isTextValid(e.target.inpfield1, 5)) {
        e.preventDefault();
        return false;
    }
    if (!isTextValid(e.target.myxtext, 10)) {
        e.preventDefault();
        return false;
    }
    return true;
}

var isTextValid = function (txt, ll) { // extra func because more than 1 textfield
    if (txt.value.length < ll) {
        window.alert("Text must be at least " + ll + " chars!");
        txt.focus();
        txt.selectionEnd = txt.value.length;
        txt.selectionStart = txt.selectionEnd;
        return false;
    } else {
        return true;
    }
}

var initialize = function () {
    document.getElementById('myform').addEventListener('submit', isValid);
}

window.addEventListener('load', initialize);
        
<!doctype html>
<html>
    <!-- js26.html -->
    <head>
        <meta charset="utf-8"/>
        <title>Form Example</title>
        <script src="js26.js"></script>
    </head>
    <body>
        <h1 id="headline">Form Input Validation</h1>
        <p>
            Don't forget to validate client side submitted data.
        </p>
        <form id='myform' action='http://x15.dk/hitme.php' method='post'>
            <p>
                Number:<br/>
                <input type='text' name='inpfield0'/>
                <br/>
                Text:<br/>
                <input type='text' name='inpfield1'/>
                <br/>
                Date:<br/>
                <input type='date' name='mydate'/>
                <br/>
                Text:<br/>
                <input type='text' name='myxtext'/>
            </p>
            <p>
                <input type='submit' value='Send'/>
            </p>
        </form>
    </body>
</html>
        

Show in browser.

<?php
if ($_GET) {
	printf("<h2>Content of the %s array</h2>\n", '$_GET');
	foreach ($_GET as $key => $val)
		printf("%s = %s<br />\n", $key, $val);
}

if ($_POST) {
	printf("<h2>Content of the %s array</h2>\n", '$_POST');
	foreach ($_POST as $key => $val)
		printf("%s = %s<br />\n", $key, $val);
}
?>
        

Assignment JS.2.7 Functions
  • Write an HTML5 page in which you can input phrases to be checked for being palindromes.
  • A common definition of a palindrome is that it is a word or a phrase that reads the same backwards and forwards.
  • Write a function first, which will return the first character of the string. Use the string.charAt() function.
  • Write a function last, which will return the last character of the string. Use the string.charAt() function.
  • Write a function middle that will return the input string minus the first and last characters. Check the string.slice(), string.substr() , and the string.substring() functions.
  • Let us now redefine a palindrome recursively as a word or a phrase is a palindrome if the first and last characters are the same, and if whatever remains in the middle is a palindrome. Two letter words are palindromes if the two letters are the same. One letter words are palindromes.
  • Now write a recursive function isPalindrome which accepts a phrase as input, and returns true if the phrase is a palindrome, and false otherwise.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.2.7 Model Solution
Example B.54.  js27.js, js27.html
/*global document, window */
'use strict';

/*
 * js27.js
 */

var first = function (txt) {
    return txt.charAt(0);
}
var last = function (txt) {
    return txt.charAt(txt.length - 1);
}
var middle = function (txt) {
    return txt.substr(1, txt.length - 2);
}

var isPalindrome = function (phrase) {
    if (phrase.length <= 1)
        return true;

    if (first(phrase) !== last(phrase)) {
        return false;
    } 

    return isPalindrome(middle(phrase));

}

var doTheHonors = function () {
    if (isPalindrome(document.forms.myform.pal.value)) {
        document.forms.myform.feedback.value = 'Text is a palindrome';
    } else {
        document.forms.myform.feedback.value = 'Text is not a palindrome';
    }
}

var initialize = function () {
    $('mybutton').addEventListener('click', doTheHonors);
}

window.addEventListener('load', initialize);

        
<!doctype html>
<html>
    <!-- js27.html -->
    <head>
        <meta charset="utf-8"/>
        <title>Form Example</title>
        <script src='nQuery.js'></script>
        <script src="js27.js"></script>
    </head>
    <body>
        <h1 id="headline">Model Sol</h1>
        <p>
            Enter some text:
        </p>
        <form id='myform' method='post' action='#'>
            <textarea name='pal' rows='10' cols='50'></textarea>
            <br/>
            <input type='text' name='feedback' readonly/>
            <p>
                <input type='button' id='mybutton' value='Test Text'/>
            </p>
        </form>
    </body>
</html>

        

Show in browser.


Assignments From Chapter 20

Solutions Assignments JSN.7

Assignment JS.7.0

Take a look at this page. Play with the left side of the footer. Click, and click again.

Create equivalent handlers for the center and right of the footer so that it is dynamic in the same way. I do want, however, the text in the middle column to be yellow. Do remember, that UX is not to let your users guess what they have to do ;)

Solution Assignment JS.7.0

The solution is obvious. Repeat first column two times.

Assignment JS.10.0

On the basis of the code from Example 20.14 create a page with two or three links to videos. Adapt the controls with Jeremy's code, and feel free to add eg sound controls as well.

Solution Assignment JS.10.0

Christian's solution:

Example B.55. The JS, js10_videoControls.js
(function() {

    function createVideoControls() {
      var vids = document.getElementsByTagName('video');
      for (var i = 0 ; i < vids.length ; i++) {
        addControls( vids[i] );
      }
    }

    function addControls( vid ) {

      vid.removeAttribute('controls');


      // vid.height = vid.videoHeight;
      // vid.width = vid.videoWidth;
      // vid.parentNode.style.height = vid.videoHeight + 'px';
      // vid.parentNode.style.width = vid.videoWidth + 'px';
      vid.removeAttribute('style')

      var controls = document.createElement('div');
      controls.setAttribute('class','controls');

      var play = document.createElement('button');
      play.setAttribute('title','Play');
      play.innerHTML = '&#x25BA;';

      controls.appendChild(play);

      vid.parentNode.insertBefore(controls, vid);

      play.onclick = function () {
        if (vid.ended) {
          vid.currentTime = 0;
        }
        if (vid.paused) {
          vid.play();
        } else {
          vid.pause();
        }
      };

      vid.addEventListener('play', function () {
        play.innerHTML = '&#x2590;&#x2590;';
        play.setAttribute('paused', true);
      }, false);

      vid.addEventListener('pause', function () {
        play.removeAttribute('paused');
        play.innerHTML = '&#x25BA;';
      }, false);

      vid.addEventListener('ended', function () {
        vid.pause();
      }, false);
    }  // end of addControls

    window.addEventListener('load', function() {
            createVideoControls();
        }
    );

})();

Example B.56. The page, js10_videoControls.html
<!doctype html>
<html>
    <head>
        <meta charset='utf-8'/>
        <title>Video Controle</title>
        <!-- <link href='js7_DOM.css' rel='stylesheet'/> -->
        <script src='nQuery.js'></script>
        <!-- <script src='js10_videoControls.js'></script> -->
    </head>
    <body>
        <header>
            <nav>
                <h1>Video Controle</h1>
                <ul>
                    <li><a href='#'>vidONE</a></li>
                    <li><a href='#'>vidTWO</a></li>
                    <li><a href='#'>vidTHREE</a></li>
                </ul>
            </nav>
        </header>
        <main>
          <div class="video-wrapper">
            <video id="movie" controls>
                <source src="http://media.w3.org/2010/05/sintel/trailer.mp4" />
                <source src="http://media.w3.org/2010/05/sintel/trailer.webm"
                    type='video/webm; codecs="vp8, vorbis"' />
                <source src="http://media.w3.org/2010/05/sintel/trailer.ogv"
                    type='video/ogg; codecs="theora, vorbis"' />
                <p>Download movie as
                    <a href="http://media.w3.org/2010/05/sintel/trailer.mp4">MP4</a>,
                    <a href="http://media.w3.org/2010/05/sintel/trailer.webm">WebM</a>,
                    or <a href="http://media.w3.org/2010/05/sintel/trailer.ogv">Ogg</a>.</p>
            </video>
        </div>


        </main>
        <script type="text/javascript">
        (function() {

            function createVideoControls() {
              var vids = document.getElementsByTagName('video');
              for (var i = 0 ; i < vids.length ; i++) {
                addControls( vids[i] );
              }
            }

            function addControls( vid ) {

              vid.removeAttribute('controls');


              // vid.height = vid.videoHeight;
              // vid.width = vid.videoWidth;
              // vid.parentNode.style.height = vid.videoHeight + 'px';
              // vid.parentNode.style.width = vid.videoWidth + 'px';
              vid.removeAttribute('style')

              var controls = document.createElement('div');
              controls.setAttribute('class','controls');

              var play = document.createElement('button');
              play.setAttribute('title','Play');
              play.innerHTML = '&#x25BA;';

              controls.appendChild(play);

              var speedUp = document.createElement('button');
              speedUp.setAttribute('id','speedUp');
              speedUp.innerHTML = 'speedUp';

              controls.appendChild(speedUp);
              var speedDown = document.createElement('button');
              speedDown.setAttribute('id','speedDown');
              speedDown.innerHTML = 'speedDown';

              controls.appendChild(speedDown);

              vid.parentNode.insertBefore(controls, vid);

              play.onclick = function () {
                if (vid.ended) {
                  vid.currentTime = 0;
                }
                if (vid.paused) {
                  vid.play();
                } else {
                  vid.pause();
                }
              };

              speedUp.addEventListener('click', function() {
                vid.playbackRate += 0.2;
                console.log(vid.playbackRate)
              }, false);

              speedDown.addEventListener('click', function() {
                vid.playbackRate -= 0.2;
                console.log(vid.playbackRate)
              }, false);

              vid.addEventListener('play', function () {
                play.innerHTML = '&#x2590;&#x2590;';
                play.setAttribute('paused', true);
              }, false);

              vid.addEventListener('pause', function () {
                play.removeAttribute('paused');
                play.innerHTML = '&#x25BA;';
              }, false);

              vid.addEventListener('ended', function () {
                vid.pause();
              }, false);
            }  // end of addControls

            window.addEventListener('load', function() {
                    createVideoControls();
                }
            );

        })()

        </script>
    </body>
</html>

Embedded m speedup!     Xtrn JS u speedup!


Assignment JS.10.1

Create a page with a form containing, at least the following: a date, a slider for a number, and a number. The slider should cover integers from -279 - +6000 °K. The number a value between 0 - 100. The date must be valid. Submit the form to http://x15.dk/hitme.php. Verify results, and iterate until ok.

I want you to test in Opera/Chrome and Firefox. Your hand in must provide screenshots of the form just before submit in both browsers, as well as the code of course.

Solution Assignment JS.10.1

Kenneths solution

Example B.57. The JS, validate.js
'use strict';
let isDate = function (date) {
    return true;
}
let validate = function (e) {
    let date = $('date');
    var number = $('number');
    if (number.value > 100 || number.value < 0){
        number.focus();
        e.preventDefault();
        window.alert('The number must be between 0 and 100!');
        return false;
    } else {
        return true;
    }
    if (!isDate(date.value)) {
        date.focus();
        e.preventDefault();
        return false;
    }

    return true;
}

let dispSlide = function () {
    $('ranger').innerHTML =
            $('degree').value;
}

let followme = function () {
    $('formal').addEventListener('submit', validate);
    dispSlide();
    $('degree').addEventListener('mousemove', dispSlide);
}
window.addEventListener('load', followme);

Example B.58. The HTML,
<!DOCTYPE html>
<html>
    <head>
        <title>Assignment JS.10.1</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="nQuery.js" type="text/javascript"></script>
        <script src="validate.js" type="text/javascript"></script>
    </head>
    <body>
        <form action="http://x15.dk/hitme.php" method="post" id="formal">
            <div>
                <label for="date">Date</label>
                <input type="date" id="date" name="date" required>
            </div>
            <div>
                <label for="degree">Degree</label>
                <input type="range" id="degree" name="degree" min="-272" max="6000">
                <span id='ranger'></span>
            </div>
            <div>
                <label for="number">Number between 0 and 100</label>
                <input type="number" id="number" name="number" required>
            </div>
            <div>
                <input type="submit" value="Submit">
            </div>
        </form>
    </body>
</html>

Kenneths solution.


Assignments From Chapter 21

Solutions Assignments JSN.2

Assignment JS.4.3 Objects

In the beginning were the natural numbers, ℕ, they are the numbers used for counting. Later we got what is today know as the integers, ℤ, by adding zero, 0, and the negative numbers. Later again we got the fractions, in mathematical speak the rational numbers ℚ, and all was good.

The rational numbers are the integers plus the fractions. Fractions are represented as the ratio between two integers. As an example, 3/7 is a rational number. The 3 is called the numerator. The 7 is called the denominator. Integers are fractions with a denominator of 1.

In this assignment you are going to create an object for rational numbers, and several methods for doing calculations with them. You see, some of us love the rational numbers because they are beautiful and exact. The real numbers ℝ, the numbers with decimals, are approximations.

  1. Create an object Rational. It must have two properties, numerator, and denominator. The creating code must give values to these two properties.
  2. If the caller does not provide parameters, the function should create the fraction 0/1.
  3. Write a method toString() that will present the fraction as the string "3/7" for example. If the fraction is an integer it should be presented as a string with only the numerator, ie without the "/1".
  4. Write a method negate which will reverse the sign of the fraction from minus to plus, or vice versa.
  5. Write a method invert which will invert the fraction by swapping the numerator and the denominator. This is sometimes the reciprocal value of the fraction.
  6. Write a method toFloat. It must return the value of the fraction as a floating point number with decimals, as approximate asd they may be.
  7. Write a method reduce. It must reduce the fraction as much as possible. The calculation is done by dividing the numerator and the denominator with their greatest common denominator, the biggest number that divides both. I shall provide you with a function gcd(n, d) that will return this number given two integers as input.
  8. Write four methods add, sub, mul, and div that will add, subtract, multiply, and divide two fractions that are both represented as Rational objects. The calculations must always end with reducing the resulting fractions.
  9. /**
     * The world's oldest non trivial algorithm: 
     * Euclid's Elements, Book 7, ca. 300 BC.
     * Based on
     * if r = the remainder from the division a/b,
     * then a og b's commom divisors are the same as b's and r's.
     * This means that gcd(a,b) = gcd(b,r)
     *
     * By doing this continuously we get:
     * gcd(36,20) = gcd(20,16) = gcd(16,4) = gcd(4,0)
     * It is possible to prove that we will end with a pair
     * where the second number is 0. When that happens 
     * the first number of the pair equals their gcd.
     *
     * This is the quintessential example of recursive function programming!
     */
    
    /**
     * Euclid's algorithm
     *
     * calling sequence
     * let n = parseInt(prompt('Give me an integer:'));
     * let d = parseInt(prompt('Give me an integer:'));
     * n = Number(n);
     * d = Number(d);
     * gcd(n, d);
     */
    let gcd = function (a, b) {
        if (b == 0) {
            return a;
        } else {
            return gcd(b, a % b);
        }
    }
    
  10. In order to test your code, of course you must create an HTML5 page with a fraction calculator.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Solution Assignment JS.4.3
Example B.59. Rational.js
'use strict';

let Rational = {
    init(n, d) {
        this.numerator = n ? Number(n) : 0;
        this.denominator = d ? Number(d) : 1;
        this.reduce();
    },
    
    toString() {
        let s = '';
        if (this.numerator * this.denominator < 0) {
            s = '-';
        }
        s += Math.abs(this.numerator);
        if (Math.abs(this.denominator) === 1) {
            return s;
        } else if (this.numerator === 0) {
            return this.numerator;
        } else {
            return s + '/' + Math.abs(this.denominator);
        }
    },
    
    reduce() {
        let g = MyMath.gcd(this.numerator, this.denominator);
        this.numerator /= g;
        this.denominator /= g;
        return;
    },
    
    invert() {
        let t = Object.create(Rational);
        t.init(this.denominator, this.numerator);
        return t;
    },
    
    negate() {
        let t = Object.create(Rational);
        t.init(-this.numerator, this.denominator);
        return t;
    },
    
    toFloat() {
        return this.numerator / this.denominator;
    },
    
    add(oq) {
        let nq = Object.create(Rational);
        nq.init(this.numerator * oq.denominator + oq.numerator * this.denominator, this.denominator * oq.denominator);
        nq.reduce();
        return nq;
    },
    
    sub(oq) {
        return this.add(oq.negate());
    },
    
    mul(oq) {
        let nq = Object.create(Rational);
        nq.init(this.numerator * oq.numerator, this.denominator * oq.denominator);
        nq.reduce();
        return nq;
    },
    
    div(oq) {
        return this.mul(oq.invert());
    }
    
}

        

Example B.60. testRational.js
'use strict';

let str2frac = function(s) {
    let arr = s.value.split('/');
    let obj = Object.create(Rational);
    obj.init(Number(arr[0]), Number(arr[1]));
    return obj;
}

let calc = function(ev) {
    let f1 = str2frac($('f1'));
    let f2 = str2frac($('f2'));
    switch(ev.target.id) {
        case 'plus': f1 = f1.add(f2);
            break;
        case 'minus': f1 = f1.sub(f2);
            break;
        case 'mul': f1 = f1.mul(f2);
            break;
        case 'div': f1 = f1.div(f2);
    }
    $('f1').value = f1.toString();
    $('f2').value = '';
    $('f2').focus();
}


let begin = function() {
    $('plus').addEventListener('click', calc);
    $('minus').addEventListener('click', calc);
    $('mul').addEventListener('click', calc);
    $('div').addEventListener('click', calc);
}
window.addEventListener('load', begin);

        

Example B.61. testRational.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>Object-oriented JavaScript example</title>
        <link rel='stylesheet' href='style.css'/>
        <script src='nQuery.js'></script>
        <script src='MyMath.js'></script>
        <script src='Rational.js'></script>
        <script src='testRational.js'></script>
    </head>

    <body>
        <table>
            <tr>
                <td><label for="jscode">Enter fraction:</label></td>
                <td>&nbsp;</td>
                <td><label for="jscode">Enter fraction:</label></td>
            </tr>
            <tr>
                <td><input type="text" id="f1"/></td>
                <td>
                    <button id='plus'>+</button><br/>
                    <button id='minus'>-</button><br/>
                    <button id='mul'>*</button><br/>
                    <button id='div'>/</button>
                </td>
                <td><input type="text" id="f2"/></td>
            </tr>
        </table>

        <p></p>
    </body>
</html>
    

        

Show in browser.


Assignment JS.4.4

Create a JavaScript object for tunes, songs. The have titles, composers, and year as properties as well as an array of performers.

The Tune object must be used in an HTML5 page allowing the user to enter tunes data through a form. The entered Tune objects must be stored in an array. The page has a div element, where the array of tunes is displayed. Whenever the array is changed, the display must automatically be updated.

Optional extra: Consider introducing a possibility for deleting tunes from the tunes array.

Solution Assignment JS.4.4
Example B.62. Tune.js
let Tune = {
    bigbang(title, composer, year) {
        this.title = title;
        this.composer = composer;
        this.year = year;
        this.performers = [];
    },
    
    addPerformer(performer) {
        this.performers.push(performer);
    },
    
    toString() {
        let s = '<p>';
        s += this.composer + ': ';
        s += '<i>' + this.title + '</i>, ';
        s += this.year;
        s += '</p>';
        return s;
    }
}

        

Example B.63. testTuneObj.js
'use strict';

let begin = function() {
    let tunes = [];
    
/* the following array elements are for test purposes 
 * with ajax the array might come by json from server file, re ajax lesson
 * with php the array may be generated on the server side from json, re REST
 */
    let tune = Object.create(Tune);
    tune.bigbang("Mac the Knife", "Kurt Weil", 1935);
    tune.addPerformer("Lotte Lenya");
    tunes.push(tune);
    
    tune = Object.create(Tune);
    tune.bigbang("Ode an der Freude", "Beethoven", 1835);
    tune.addPerformer("Berliner");
    tunes.push(tune);
    
    tune = Object.create(Tune);
    tune.bigbang("What a Wonderful World", "unknown", 1966);
    tune.addPerformer("Louis Armstrong");
    tunes.push(tune);
/* end of test data */
    
    let disp = function() {
        let div1 = $('tunearea');
        while (div1.firstChild) {    // Removing all children from an element
            div1.removeChild(div1.firstChild);
        }
        for (let tune of tunes) {
            div1.innerHTML += tune.toString();
        }
    };
    
    disp();
    $('butt').addEventListener('click', function() {
            let cmp = $('cmp').value;
            let title = $('title').value;
            let year = $('year').value;
            let perf = $('perf').value;
            if (cmp !== '' && title !== '' && perf !== '') {
                let tune = Object.create(Tune);
                tune.bigbang(title, cmp, year);
                tune.addPerformer(perf);
                tunes.push(tune);
                disp();
                $('cmp').value = '';
                $('title').value = '';
                $('perf').value = '';
            }
        }
    );
}
window.addEventListener('load', begin);

        

Example B.64. testTuneObj.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>Object-oriented JavaScript example</title>
        <script src='nQuery.js'></script>
        <script src='Tune.js'></script>
        <script src='testTuneObj.js'></script>
        <style>
            div { 
                float: left;
                height: 500px;
                margin: 1em;
                outline: 1px solid blue;
                padding: 1em;
                width: 40%;
            }
        </style>
    </head>

    <body>
        <h1>Tunes</h1>
        <div id='left'>
            <h2>Entry form</h2>
            <p>
                <label for='title'>Title:</label><br/>
                <input type='text' id='title' required/>
            </p>
            <p>
                <label for='cmp'>Composer:</label><br/>
                <input type='text' id='cmp' required/>
            </p>
            <p>
                <label for='year'>Year:</label><br/>
                <input type='number' id='year' min='1970' max='2018' value='1999' required/>
            </p>
            <p>
                <label for='perf'>Singer:</label><br/>
                <input type='text' id='perf' required/>
            </p>
            <p>
            </p>
            <p>
                <button id='butt'>Enter</button>
            </p>
        </div>
        <div id='right'>
            <h2>List of Tunes</h2>
            <div id='tunearea'></div>
        </div>
    </body>
</html>
    

        

Show in browser.


Assignments From Chapter 22

Solutions Assignments JSN.3

Assignment JS.3.5

Please refer to code in Example 22.2. Now alter the drawing of the polygon in such a way that you strike all three sides with the context method lineTo. Use a line width of 10.

Hand in an HTML5 as well as a JavaScript file. HTML5 must validate. JavaScript must be validated without errors on jslint.com, or jshint.com.

Assignment JS.3.6

Please refer to code in Example 22.2. Now alter the drawing of the polygon in such a way that you close the region of the polygon with the context method closePath. Use a line width of 10.

Hand in an HTML5 as well as a JavaScript file. HTML5 must validate. JavaScript must be validated without errors on jslint.com, or jshint.com.

Solutions Assignment JS.3.5 and JS.3.6
Example B.65. Code
/*globals document, window */
'use strict';

/* 
 * assignment 35 solution
 * function drawing a polygon 
 */
var poly35 = function () {
    var canvas = document.getElementById('myCanvas35');
    if (canvas.getContext) {
        var ctx = canvas.getContext('2d');

        ctx.beginPath();        // new path for polygon
        ctx.moveTo(50, 200);    // goto coordinate in canvas
        ctx.lineTo(150, 50);    // line to coordinate
        ctx.lineTo(180, 150);   // another line to coord

        ctx.lineTo(50, 200);    // connect to start of polygon

        ctx.fillStyle = 'silver';
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 40;
        ctx.fill();             // fills poly
        ctx.stroke();           // draws lines    
    }
}

/* 
 * assignment 36 solution
 * function drawing a polygon 
 */
var poly36 = function () {
    var canvas = document.getElementById('myCanvas36');
    if (canvas.getContext) {
        var ctx = canvas.getContext('2d');

        ctx.beginPath();        // new path for polygon
        ctx.moveTo(50, 200);    // goto coordinate in canvas
        ctx.lineTo(150, 50);    // line to coordinate
        ctx.lineTo(180, 150);   // another line to coord

        ctx.closePath();        // close path to start of polygon

        ctx.fillStyle = 'silver';
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 10;
        ctx.fill();             // fills poly
        ctx.stroke();           // draws lines    
    }
}

var init = function () {
    poly35();
    poly36();
}

window.addEventListener('load', init);
        
<!doctype html>
<html language="en">
    <head>
        <meta charset="utf-8"/>
        <title>Canvas Example II</title>
        <script src="js3536.js"></script>
    </head>
    <body>
        <h1>Canvas Example II, Solution 35 and 36</h1>
        <p>
            Polygon assignment 35.
        </p>
        <canvas id="myCanvas35" width="300" height="300" style="outline: 1px solid blue;">
            <p>Powered by &html;5 canvas if only</p>
        </canvas>
        <p>
            Polygon assignment 36.
        </p>
        <canvas id="myCanvas36" width="300" height="300" style="outline: 1px solid red;">
            <p>Powered by &html;5 canvas if only</p>
        </canvas>
    </body>
</html>
        

Show in browser.


Assignment JS.4.0

Create a webpage. In the right hand side of the webpage you must create a 'toolbox' canvas with four rectangles of different sizes, and a half circle. They represent the standard shapes in the toolbox.

In addition you must create another, separate canvas on the page. Let us call it the room. The size of that canvas must be with user entered width and height. Please let it's outline be visible.

I expect an html file, a css file, and one or more js files to make up the solution.

Hint for beginners: You may prefer to work with embedded JavaScript while you test your code. Once it works as desired, separate the JavaScript into an individual .js file, test again, then hand in your solution.

Assignment JS.4.0 Pseudo Code
Example B.66. Pseudo Code

It might be a good idea to sketch a web page and pencil in some names of divs and other stuff. Referring to this in your pseudo-, and in your actual code will be very beneficial.

Figure B.9. Sketchbook Page

Let me spell out the assignment in some pseudo code sections. First create the test case.

  • Create an HTML5 page.
  • Put two divs, work, and lib into the body, side by side preferably. Let the two divs have outlines, so that they are visible.
  • Create a form at the bottom. The form must accept input fields for width and height.
  • In the right hand side div, create a canvas for the required
  • Refer to a JavaScript file from the header.

After having done this your page should look somewhat like this

Figure B.10. Sketch 1
Sketch 1

  • The JavaScript file must create a load event listener.
  • The load handler should
    • Create an object variable ref to canvas in the right hand div toolbox.
    • Create a series of shapes for that canvas. Each shape should be pushed onto an array.
    • Create and call a function that reads the array and draws the shapes in it.
    • Create a click event listener for newly created form button. The handler should create a canvas inside the left div. Call the handler drawRoom for example, and create it as as empty function for the time being.

When you test again the page should look similar to

Figure B.11. Sketch 2
Sketch 2

Now you must create the content for the drawRoom handler

  • Refer to your textbook, chapter 7, and create a DOM canvas element.
  • Create three, 3, attributes for the canvas. They must be id, width, and height. You choose the value of the id, the values of width and height must come from the form.
  • Use the canvas class to create an object variable pointing to the room.
  • Create a click event handler, select for toolbox.

An array, and an object variable for each canvas should be defined outside any function. Next to the declaration of the load event listener. When you test now, you should get something similar to

Figure B.12. Sketch 3
Sketch 3


Assignment JS.4.1

With the webpage created in the previous assignment you must create an event such that you may click on a toolbox shape to select it. Then you must be able to click in the other canvas so that the standard shape will be drawn there.

The shapes must be kept at a minimum distance from the walls of the room.

This assignment should be solved by adding code to the JavaScript code file(s) made in the previous assignment.

Solution Assignment JS.4.1 Pseudo Code
Example B.67. Pseudo Code
  • In the select handler you must
    • Iterate through the array of shapes in the toolbox. For each you must check whether this was the clicked one. Hint: use my code from the lesson.
    • If it was, make it visibly selected.
      Figure B.13. Sketch 1
      Sketch 1

    • Make an eventlistener in the room call it's handler placeInRoom.
    • placeInRooms handler must create an object similar to the clicked one and place it in the array of shapes in the room.
    • It's canvas, and (x,y) coordinates must reflect the (x,y) coordinates of the click event in the room ie the mouse coordinates.
    • Adjust the (x,y) coordinates of the object in the room so that they conform to the rules of distance from walls.
    • Redraw the canvas of the toolbox to remove the selection graphics. Redraw the room canvas to draw the element.
      Figure B.14. Sketch 2
      Sketch 2

    • Remove the event listener from the room. Reestablish the event listener for the toolbox.

The above images are not necessarily from the following working code. There are (at least) two bugs or omissions in the nmlCanvas80.js code. One was accidental at first, but I have decided to leave them in there for you to find and fix ;) The code does solve the less trivial problem of being able to copy shapes from the toolbox into the room.

Example B.68. nmlCanvas.js
/**
 * Canvas object
 */
let Canvas = {
    init(canvasId, color) {
        this.canvas = $(canvasId);
        this.context = this.canvas.getContext("2d");
        this.color = color;
        this.prep();
    },
    prep() {
        this.context.fillStyle = this.color;
        this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
    },
    clear() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },
    getContext() {
        return this.context;
    },
    getHeight() {
        return this.canvas.height;
    },
    getWidth() {
        return this.canvas.width;
    }
};

            

Example B.69. nmlShape.js
/*globals document, window */
'use strict';

/**
 * Shape object, simple
 */
let Shape = {
    init(cv, x, y, width, height, color) {
        this.ctx = cv.context;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    },

    draw() {
        this.ctx.fillStyle = this.color;
        this.ctx.fillRect(this.x, this.y, this.width, this.height);
    }
};

            

Example B.70. nmlCanvas80.js
'use strict';

/* 
 * nmlCanvas80.js
 */
let initialize = function () {
    /*
     * create two canvases and put two shapes into the right one
     * via an array
     */
    mycv1 = Object.create(Canvas);
    mycv1.init('myCanvas1', 'transparent');
    mycv1.canvas.addEventListener('click', select);
    mycv2 = Object.create(Canvas);
    mycv2.init('myCanvas2', 'transparent');
    // create objects
    // put in array
    let shape1 = Object.create(Shape);
    shape1.init(mycv1, 20, 10, 120, 40, 'blue');
    let shape2 = Object(Shape);
    shape2.init(mycv1, 200, 100, 80, 60, 'green');
    shapes.push(shape1);
    shapes.push(shape2);
    repeater(mycv1, shapes);
}

let redraw = function (cv, arr) {
    /* clear and redraw canvas from an array */
    cv.clear();
    cv.prep();
    for (var i = 0; i < arr.length; i++) {
        arr[i].draw();
    }
}

let repeater = function (cv, arr) {
    /* if this is an animation build a setInterval loop here
     * if not, just draw
     */
    redraw(cv, arr);
}

let select = function (ev) {
    for (let i = 0; i < shapes.length; i++) {
        let cx = shapes[i].ctx;
        cx.beginPath();
        cx.rect(shapes[i].x, shapes[i].y, shapes[i].width, shapes[i].height);
        cx.closePath();
        let bb = this.getBoundingClientRect();    // get canvas as std obj
        // convert mouse coordinates to canvas coordinates
        let x = (ev.clientX - bb.left) * (this.width / bb.width);
        let y = (ev.clientY - bb.top) * (this.height / bb.height);
        if (cx.isPointInPath(x, y)) {
            // we're in a loop, is this array element the 
            // one we clicked? If yes click in other canvas
            mycv2.canvas.addEventListener('click', function placeInRoom(e) {
                    let bb1 = this.getBoundingClientRect();    // yes
                    // other canvas as std object
                    // convert mouse coordinates to canvas coordinates
                    let x1 = (e.clientX - bb1.left) * (this.width / bb1.width);
                    let y1 = (e.clientY - bb1.top) * (this.height / bb1.height);
                    let obj = Object.create(Shape); // create new obj 
                    // with adapted properties
                    obj.init(mycv2, x1, y1, 
                                shapes[i].width, shapes[i].height,
                                shapes[i].color);
                    othershapes.push(obj);
                    mycv1.canvas.removeEventListener('click', select);
                    repeater(mycv2, othershapes);
                    mycv2.canvas.removeEventListener('click', placeInRoom);
                    mycv1.canvas.addEventListener('click', select);
                });
        } else {
            // window.alert("nohit: "+x+","+y);
        }
    }
}

let mycv1;
let mycv2;
let shapes = [];
let othershapes = [];

window.addEventListener('load', initialize);

            

Example B.71. nmlCanvas80.html
<!doctype html>
<html language="en">
    <!-- nmlCanvas80.html -->
    <head>
        <meta charset="utf-8"/>
        <title>Canvas Experiment LXXX</title>
        <script src="nQuery.js"></script>
        <script src="nmlCanvas.js"></script>
        <script src="nmlShape.js"></script>
        <script src="nmlCanvas80.js"></script>
    </head>
    <body>
        <h1>Canvas Experiment LXXX</h1>
        <p>
            Select shapes from right canvas and reporduce them in the
            left canvas where the mouse is clicked.
        </p>
        <canvas id="myCanvas2" width="400" height="400" 
                style="outline: 1px solid magenta; float:left;">
            <p>Powered by &html;5 canvas</p>
        </canvas>
        <canvas id="myCanvas1" width="400" height="400" 
                style="outline: 1px solid magenta; float: left; margin-left:20px;">
            <p>Powered by &html;5 canvas</p>
        </canvas>
    </body>
</html>

            

Show in browser.



Assignment JS.4.2

With the result of the previous assignment you must improve the placing of the shapes such that in addition to the minimum distance from the walls, the shapes may touch, but not overlap each other.

Again, this assignment should be solved by adding code to the JavaScript code files resulting from the previous assignment.

Solution Assignment JS.4.2 Pseudo Code
Example B.72. Pseudo Code

  • Describe in words what "not overlapping" means. Discuss it in your group. When you agree
  • Code the Shape.isOverlapping(obj) method as part of the Shape class. Internally this refers to the current object. The parameter obj must refer to the object with which we test for overlap. The method must return true if there's an overlap, otherwise it must result false.
  • Whenever a shape is placed in the room, or moved inside the room, it must be tested for overlap against all objects already in that room.

Assignment JS.5.0
  1. Write this HTML5 page. The outlined area is a canvas with the id myCanvas0. Show it to your prof.
    Figure B.15. 

  2. Create the necessary JavaScript to fill the canvas with fillStyle = 'silver'. Show it to your prof.
    Figure B.16. 

  3. This is a die in perspective:
    Figure B.17. 

    Here is the die seen from one side:
    Figure B.18. 

  4. Construct a die seen from one side with canvas drawing tools. Draw it on the canvas. Then show it to your prof.
    Figure B.19. 

  5. Change your HTML5 to add a Play! button such that when you click it, the code rolls the die; wipes the canvas; and redraws the canvas with the die reflecting its new value.
  6. Change the number of dice from 1 to 5. The behaviour, ie rolling the individual die to a new value when hitting play, must be on all the 5 dice.
  7. Add a lock to a die when you click it. If locked, the die does not change its value when you click Play! If you click a locked die, it must be released.
  8. Look at https://en.wikipedia.org/wiki/Yatzy and read the Scoring section. Then augment your HTML5 to make an interface reflecting the upper and lower section of the scoring pad.
  9. Create a gameplay in the JavaScript such that the user has three attempts, after which he must choose where to place his points. After that choice is made and displayed, He has three more attempts for the next score, and so on cyclically until the scoring pad is complete and the game is over.
  10. When the previous steps are programmed, the user interface allows score registration, we will introduce the computer as an opponent. This means that after each three attempts of yours, the program plays and automatically places its points in a second column on the score pad.
  11. The game is over when the pad is full, or when the player clicks to abort the game. The winner is whoever has more points at that moment. Create or maintain a cookie with scoring history.
  12. Create a New Game button and program it's behaviour.

Demo (teacher's host only).

Solution Assignment JS.5.0 - Yatzy (Partial Solution)
Example B.73. nCanvas.js
/**
 * Canvas object
 */
var Canvas = {
    init(canvasId, color) {
        this.canvas = $(canvasId);
        this.context = this.canvas.getContext("2d");
        this.color = color;
        this.prep();
    },

    prep() {
        this.clear();
        this.context.fillStyle = this.color;
        this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
    },

    clear() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },

    getContext() {
        return this.context;
    },

    getHeight() {
        return this.canvas.height;
    },

    getWidth() {
        return this.canvas.width;
    }
};

        

Example B.74. nDie.js
/**
 * Die object
 */
let Die = {
    init(cv, x, y, width, height, color) {
        this.ctx = cv.getContext();
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
        this.locked = false;
        this.value = 0;
        this.roll();
    },

    draw() {
        this.ctx.clearRect(this.x, this.y, this.width, this.height);
        this.ctx.beginPath();
        this.ctx.fillStyle = this.color;
        this.ctx.rect(this.x, this.y, this.width, this.height);
        if (this.locked) {
            this.ctx.fillStyle = "yellow";
            this.ctx.strokeStyle = "black";
            this.ctx.lineWidth = 2;
            this.ctx.stroke();
        }
        this.ctx.fill();
        this.ctx.closePath();
        this.drawFace();
    },

    drawFace() {
        var offset = 12;
        var r = 5;
        this.ctx.fillStyle = 'black';
        if (this.value % 2 === 1) {
            this.ctx.beginPath();
            this.ctx.arc(this.x + this.width / 2, this.y + this.height / 2, 
                         r, 0, Math.PI * 2, true);
            this.ctx.fill();
            this.ctx.closePath();
        }
        if (this.value > 1) {
            this.ctx.beginPath();
            this.ctx.arc(this.x + this.width - offset, this.y + offset, 
                         r, 0, Math.PI * 2, true);
            this.ctx.arc(this.x + offset, this.y + this.height - offset, 
                         r, 0, Math.PI * 2, true);
            this.ctx.fill();
            this.ctx.closePath();
        }
        if (this.value >= 4) {
            this.ctx.beginPath();
            this.ctx.arc(this.x + offset, this.y + offset, 
                         r, 0, Math.PI * 2, true);
            this.ctx.arc(this.x + this.width - offset, this.y + this.height - offset, 
                         r, 0, Math.PI * 2, true);
            this.ctx.fill();
            this.ctx.closePath();
        }
        if (this.value === 6) {
            this.ctx.beginPath();
            this.ctx.arc(this.x + offset, this.y + this.height / 2, 
                         r, 0, Math.PI * 2, true);
            this.ctx.arc(this.x + this.width - offset, this.y + this.height / 2, 
                         r, 0, Math.PI * 2, true);
            this.ctx.fill();
            this.ctx.closePath();
        }
    },

    move(dx, dy) {
        this.x += dx;
        this.y += dy;
    },

    roll() {
        let e = Math.floor(Math.random() * 6 ) + 1;
        this.value = e;
    },

    lockUnlock() {
        this.locked = this.locked ? false : true;
    }
};

        

Example B.75. nQuery.js
/*
 * nQuery
 * @version 0.99, 2020-09
 * @author nml
 */

var $ = function(foo) {
    return document.getElementById(foo);
}

const roll = function(foo) {
    return Math.floor(Math.random() * foo + 1);
}

const copyr = function(bar) {
    let now = new Date();
    let sml = document.createElement("small");
    let cpr = document.createTextNode(`\u00a9nml, 2016-${now.getFullYear()}`);
    sml.appendChild(cpr);
    $(bar).appendChild(sml);
}

window.addEventListener("load", function() {
    if ($('cpryear'))
        copyr('cpryear');
});
        

Example B.76. nYPad.js
/*
 * nYPad.js Niels' Yatzy Pad
 * @version 0.9, 2016-04
 * @author nml
 */

const headers = ["Play", " ", "You", "Opponent"];

const plays = [
    ["1's", NoOfDice * 1],
    ["2's", NoOfDice * 2],
    ["3's", NoOfDice * 3],
    ["4's", NoOfDice * 4],
    ["5's", NoOfDice * 5],
    ["6's", NoOfDice * 6],
    ["Sum", NoOfDice * 21],
    ["Bonus", 50],
    ["One pair", 2 * 6],
    ["Two pairs", 2 * 6 + 2 * 5],
    ["Three alike", 3 * 6],
    ["Four alike", 4 * 6],
    ["Small straight", 1+2+3+4+5],
    ["Large straight", 2+3+4+5+6],
    ["Full house", 3 * 6 + 2 * 5],
    ["Chance", NoOfDice * 6],
    ["Yatzy", 50],
    ["Total", "x"]
];

const generate = function(arr, arrm) {
    let tab = document.createElement("table");
    tab.setAttribute("id", "ytable");
    
    let row = document.createElement("tr");
    for (let i = 0; i < headers.length; i++) {
        let cell = document.createElement("td");
        let t = document.createTextNode(headers[i]);
        cell.appendChild(t);
        row.appendChild(cell);
    }
    tab.appendChild(row);
    
    for (let i = 0; i < plays.length; i++) {
        let row = document.createElement("tr");
        let cell = document.createElement("td");
        if (i === 6 || i === 7 || i === plays.length - 1) {
            cell.setAttribute("style", "font-weight: 900");
        }
        let t1 = document.createTextNode(plays[i][0]);
        cell.appendChild(t1);
        row.appendChild(cell);
       
        cell = document.createElement("td");
        cell.setAttribute("class", "right");
        t1 = document.createTextNode(plays[i][1]);
        cell.appendChild(t1);
        row.appendChild(cell);
        tab.appendChild(row);

        let t2 = document.createTextNode(" ");
        cell = document.createElement("td");
        cell.setAttribute("id", "me" + i);
        cell.setAttribute("class", "right");
        if (!(i === 6 || i === 7 || i === plays.length - 1)) {
            cell.addEventListener("click", function rec() {
                for (let i = 0; i < arr.length; i++) {
                    arrm[arr[i]]++;
                    arrm[0] += arr[i];
                }
                console.log(arrm);
                record(cell.getAttribute("id"));
            });
        }
        cell.appendChild(t2);
        row.appendChild(cell);
        cell = document.createElement("td");
        cell.setAttribute("id", "they" + i);
        cell.appendChild(t2);
        row.appendChild(cell);
    }
    return tab;
}

const hangPadOnTree = function(foo, arr, arrm) {
    let c = generate(arr, arrm);
    $(foo).appendChild(c);
}

        

Example B.77. index.html
<!doctype html>
<html>
    <head>
        <title>Assignment 5.0</title>
        <meta charset="utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <link rel='stylesheet' href='./css/styles.css'/>
        <script src='./js/nQuery.js'></script>
        <script src='./js/nCanvas.js'></script>
        <script src='./js/nDie.js'></script>
        <script src='./js/nYPad.js'></script>
    </head>
    <body>
        <main>
            <h1>Assignment 5.0</h1>
            <p>
                Some content
            </p>
            <div id='divl'></div>
            <div id='divr'></div>
            <p id='av'>
                Some additional content.
            </p>
        </main>
    </body>
</html>

        

Show in browser.


Solutions to Assignments JS.11

Assignment JS.11.0

On the basis of the code from today's lesson please enhance the animation to move two objects around the canvas in linear fashions.

Assignment JS.11.0

In these two solutions only the HTML5 code has been changed from the lesson. Nothing else.

Example B.78. Example Code for Animation, the HTML, 2 Umos, Plain
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Canvas Test Animation</title>
        <script src='nQuery.js'></script>
        <script src='nmlCanvas.js'></script>
        <script src='nmlUmo.js'></script>
        <script>
            var c0;
            var c1;
            var canvas;
 
            var redraw = function () {      
                canvas.clear();     // clear canvas
                canvas.prep();      // prep canvas with background color
                c0.move();           // move thing
                c0.draw();           // draw thing
                c1.move();           // move thing
                c1.draw();           // draw thing
            }

            var repeater = function () {
                setInterval(redraw, 10);
            }

            var initialize = function () {
                canvas = Object.create(Canvas);
                canvas.init('canvas', '#ffff88');
                c0 = Object.create(Umo);
                c0.init(canvas, '#000088');
                c1 = Object.create(Umo);
                c1.init(canvas, '#cc0000');
                repeater();
            }
            
            var nml = window.addEventListener('load', initialize, false);
        </script>
    </head>
    <body>
        <section>
            <canvas id='canvas' width='400' height='300'>
                If you see this text, your browser is very old.
            </canvas>
        </section>
    </body>
</html>

View in browser


Example B.79. Example Code for Animation, the HTML, 2 Umos, Array
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Canvas Test Animation</title>
        <script src='nQuery.js'></script>
        <script src='nmlCanvas.js'></script>
        <script src='nmlUmo.js'></script>
        <script>
            var arr = [];
            var canvas;
 
            var redraw = function () {      
                canvas.clear();     // clear canvas
                canvas.prep();      // prep canvas with background color
                for (var i = 0; i < arr.length; i++) {
                    arr[i].move();
                    arr[i].draw();
                }
            }

            var repeater = function () {
                setInterval(redraw, 10);
            }

            var initialize = function () {
                canvas = Object.create(Canvas);
                canvas.init('canvas', '#ffff88');
                let c0 = Object.create(Umo);
                c0.init(canvas, '#000088');
                arr.push(c0);
                c0 = Object.create(Umo);
                c0.init(canvas, '#cc0000');
                arr.push(c0);
                c0 = Object.create(Umo);
                c0.init(canvas, '#009900');
                arr.push(c0);
                repeater();
            }
            
            var nml = window.addEventListener('load', initialize, false);
        </script>
    </head>
    <body>
        <section>
            <canvas id='canvas' width='400' height='300'>
                If you see this text, your browser is very old.
            </canvas>
        </section>
    </body>
</html>

View in browser


Assignment JS.11.1

On the basis of the code from today's lesson please enhance the animation to move an object according to a second degree polynomium, y = a * x2 + b * x + c. You experiment with with values of a, b , and c.

Assignment JS.11.1

The code not shown has not changed from the lesson, or the previous assignment.

Example B.80. Example Code for Animation, the JavaScript, Parabola
var Umo = {
    init(canvas, color) {
        this.canvas = canvas;
    //    this.x = this.canvas.getWidth() / 2;
        this.x = 0;
        this.y = 0;
        this.r = 3;
        this.dx = 1;
        this.color = color;
    },

    draw() {
        this.canvas.getContext().beginPath();
        this.canvas.getContext().fillStyle = this.color;
        this.canvas.getContext().arc(this.x, this.y, this.r,
                                     0, Math.PI * 2,
                                     false);
        this.canvas.getContext().fill();
        this.canvas.getContext().closePath();
    },

    move() {
        if (this.x + this.dx > this.canvas.getWidth() 
                || this.x + this.dx < 0)
              this.dx = -this.dx;
            
        this.x += this.dx;
        // a(x-h)^2 + k where h is offset to right, k is offset up
        // http://www.intmath.com/plane-analytic-geometry/4-parabola.php
        this.y = Math.pow(this.x - 200, 2) / 100;
        this.toString();
        if (this.y > this.canvas.getHeight())
            this.dx *= -1;
    },

    toString() {
        s = '';
        s += this.x + ':' + this.y;
        console.log(s);
    },
};

Example B.81. Example Code for Animation, the HTML, Parabola
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Canvas Test Animation</title>
        <script src='nQuery.js'></script>
        <script src='nmlCanvas.js'></script>
        <script src='nmlUmo001.js'></script>
        <script>
            var arr = [];
            var canvas;
 
            var redraw = function () {      
                canvas.clear();     // clear canvas
                canvas.prep();      // prep canvas with background color
                for (var i = 0; i < arr.length; i++) {
                    arr[i].move();
                    arr[i].draw();
                }
            }

            var repeater = function () {
                setInterval(redraw, 50);
            }

            var initialize = function () {
                canvas = Object.create(Canvas);
                canvas.init('canvas', '#ffff88');
                let c = Object.create(Umo);
                c.init(canvas, '#000088');
                arr.push(c);
                repeater();
            }
            
            var nml = window.addEventListener('load', initialize, false);
        </script>
    </head>
    <body>
        <section>
            <canvas id='canvas' width='400' height='400'>
                If you see this text, your browser is very old.
            </canvas>
        </section>
    </body>
</html>

View in browser


Assignment JS.11.2

On the basis of the code from today's lesson please enhance the animation to move an object following a sine, or cosine curve.

Assignment JS.11.2

The code not shown has not changed from the lesson, or the previous assignment.

Example B.82. Example Code for Animation, the JavaScript Sine
var Umo = {
    init(canvas, color) {
        this.canvas = canvas;
    //    this.x = this.canvas.getWidth() / 2;
        this.x = 0;
        this.y = 0;
        this.r = 3;
        this.dx = 1;
        this.color = color;
    },

    draw() {
        this.canvas.getContext().beginPath();
        this.canvas.getContext().fillStyle = this.color;
        this.canvas.getContext().arc(this.x, this.y, this.r,
                                     0, Math.PI * 2,
                                     false);
        this.canvas.getContext().fill();
        this.canvas.getContext().closePath();
    },

    move() {
        if (this.x + this.dx > this.canvas.getWidth() 
                || this.x + this.dx < 0)
              this.dx = -this.dx;
            
        this.x += this.dx;
        this.y = 20 * Math.sin(this.x * Math.PI / 100) + 200;
        this.toString();
    },

    toString() {
        s = '';
        s += this.x + ':' + this.y;
        console.log(s);
    }
}

Example B.83. Example Code for Animation, the HTML, Sine
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Canvas Test Animation</title>
        <script src='nQuery.js'></script>
        <script src='nmlCanvas.js'></script>
        <script src='nmlUmo002.js'></script>
        <script>
            var arr = [];
            var canvas;
 
            var redraw = function () {      
//                canvas.clear();     // clear canvas
//                canvas.prep();      // prep canvas with background color
                for (var i = 0; i < arr.length; i++) {
                    arr[i].move();
                    arr[i].draw();
                }
            }

            var repeater = function () {
                setInterval(redraw, 100);
            }

            var initialize = function () {
                let canvas = Object.create(Canvas);
                canvas.init('canvas', '#ffff88');
                let u = Object.create(Umo);
                u.init(canvas, '#000088');
                arr.push(u);
/*
                u = new Umo(canvas, '#cc0000');
                arr.push(u);
                u = new Umo(canvas, '#009900');
                arr.push(u);
*/
                repeater();
            }
            
            var nml = window.addEventListener('load', initialize, false);
        </script>
    </head>
    <body>
        <section>
            <canvas id='canvas' width='400' height='400'>
                If you see this text, your browser is very old.
            </canvas>
        </section>
    </body>
</html>

View in browser


Assignment JS.11.3

On the basis of the code from today's lesson please enhance the animation to move two objects around one canvas. One of the curves must move as a sine wave, the other as a cosine wave.

Assignment JS.11.3

The code not shown has not changed from the lesson, or the previous assignment.

Example B.84. Example Code for Animation, the JavaScript, Sine, Cosine
var Umo = {
    init(canvas, color) {
        this.canvas = canvas;
        this.x = 0;
        this.y = 0;
        this.r = 3;
        this.dx = 2;
        this.color = color;
        this.yoffset = 100;
        this.dyoffset = 100;
    },

    draw() {
        this.canvas.getContext().beginPath();
        this.canvas.getContext().fillStyle = this.color;
        this.canvas.getContext().arc(this.x, this.y, this.r,
                                     0, Math.PI * 2,
                                     false);
        this.canvas.getContext().fill();
        this.canvas.getContext().closePath();
    },

    move() {
        if (this.x + this.dx > this.canvas.getWidth() 
                || this.x + this.dx < 0) {
              this.dx = -this.dx;
              this.yoffset += this.dyoffset
        }
            
        this.x += this.dx;
        if (this.color === 'blue')
            this.y = 20 * Math.sin(this.x * Math.PI / 100) + this.yoffset;
        else
            this.y = 20 * Math.cos(this.x * Math.PI / 100) + this.yoffset;
        this.toString();
    },

    toString() {
        s = '';
        s += this.x + ':' + this.y;
        console.log(s);
    }
}

Example B.85. Example Code for Animation, the HTML, Sine, Cosine
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Canvas Test Animation</title>
        <script src='nQuery.js'></script>
        <script src='nmlCanvas.js'></script>
        <script src='nmlUmo003.js'></script>
        <script>
            var arr = [];
            var canvas;
 
            var redraw = function () {      
//                canvas.clear();     // clear canvas
//                canvas.prep();      // prep canvas with background color
                for (var i = 0; i < arr.length; i++) {
                    arr[i].move();
                    arr[i].draw();
                }
            }

            var repeater = function () {
                setInterval(redraw, 100);
            }

            var initialize = function () {
                let canvas = Object.create(Canvas);
                canvas.init('canvas', '#ffff88');
                let u = Object.create(Umo);
                u.init(canvas, 'red');
                arr.push(u);
                u = Object.create(Umo);
                u.init(canvas, 'blue');
                arr.push(u);
/*
                u = new Umo(canvas, '#cc0000');
                arr.push(u);
                u = new Umo(canvas, '#009900');
                arr.push(u);
*/
                repeater();
            }
            
            var nml = window.addEventListener('load', initialize, false);
        </script>
    </head>
    <body>
        <section>
            <canvas id='canvas' width='1000' height='400'>
                If you see this text, your browser is very old.
            </canvas>
        </section>
    </body>
</html>

View in browser


Solutions Assignments JSN.8

Assignment JS.8.0

Make an HTML5 page with a form. On the form you must, with radio buttons be able to choose between two colleges, say IBA Business Academy Kolding, and EAAA Business Academy Aarhus. Minimal styling required.

When you check one of the radio buttons, a new section of the form must be created by AJaX. You must add a drop down, select, with four programmes you can study at the respective colleges.

  • IBA Business Academy Kolding
    • Entrepreneur and Design Manager
    • Produktion Technology
    • Financial Controller
    • Euro-Asia Business Management
  • EAAA Business Academy Aarhus
    • Multimedia Design
    • Agro Business Manager
    • Chemical and Biotechnical Science
    • Software Development

When the two parts of the form have been completed, not before, it must be submitted to http://x15.dk/hitme.php.

Solution Assignment JS.8.0
Example B.86.  js80.js, js80.html
'use strict';

var getAjax = function () {
    return new XMLHttpRequest();
}

var getExt = function (e) {
    var request = getAjax();
    var fil = 'js80.ajx.php?code=' + e.target.id;

    if (request) {
        request.open('GET', fil, true);
        request.addEventListener('readystatechange', function () {
            if (request.readyState === 4) {
                document.getElementById('fext').innerHTML = request.responseText;
            }
        });
        request.send(null);
    } else {
        window.alert('Your browser does not support AJaX (XMLHttpRequest).');
    }
}

var check = function (e) {
    if (document.forms.myform.prog.value == "") {
        window.alert("Error, input required");
        document.forms.myform.prog.focus();
        e.preventDefault();
        return false;
    }
}

var go = function () {
    document.forms.myform.eaaa.addEventListener('click', getExt);
    document.forms.myform.iba.addEventListener('click', getExt);
    document.forms.myform.addEventListener('submit', check);
}

window.addEventListener('load', go);
        
<!doctype html>
<html>
    <!-- js80.html -->
    <head>
        <meta charset="utf-8"/>
        <title>Form AJaX Example</title>
        <link rel='stylesheet' href='js80.css'/>
        <script src="js80.js"></script>
    </head>
    <body>
        <header>
            <h1 id="headline">AJaX Dynamic Form</h1>
        </header>
        <main>
            <p>
                Build form content based on previous data input.
            </p>
            <form id='myform' action='http://localhost/hitme.php' method='post'>
                <p>
                    <b>Please select an academy:</b> 
                    <br/>
                    <input type='radio' name='radion' id='eaaa' value='EAAA'/>
                    EAAA Business Academy Aarhus
                    <br/>
                    <input type='radio' name='radion' id='iba' value='IBA'/>
                    IBA Business Academy Kolding
                </p>
                <p id='fext'></p>
                <p id='buttons'>
                    <input type='submit' id='b1' value='Go'/>
                    <input type='reset' value='Reset'/>
                </p>
            </form>
        </main>
        <footer>
            <address>&copy; nml, 2015-09-30</address>
        </footer>
    </body>
</html>

        

View in browser

The dynamic content in the form comes from

<?php
require_once 'dbparams.inc.php';
require_once 'dbconnect.inc.php';

$code = isset($_GET['code']) ? strtoupper($_GET['code']) : 'IBA';

$sql = "select kode, school, program";
$sql .= " from liste";
$sql .= " where kode = :code";

try {
    $q = $dbh->prepare($sql);
    $q->bindValue(':code', $code);
    $q->execute();
    $out = "<p><b>Please select a program from " . $code . "</b></p>\n";
    $out .= "<select name='prog'>\n";
    while ($row = $q->fetch()) {
        $out .= sprintf("<option>%s</option>\n", 
                $row['program']);
    }
    $out .= "</select>\n";
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}
header('Content-Type: text/html');
print($out);