Google Chart Geo Chart Zoom In Quiz Aesthetics Tutorial

Google Chart Geo Chart Zoom In Quiz Aesthetics Tutorial

Google Chart Geo Chart Zoom In Quiz Aesthetics Tutorial

We recently revisited the PHP web application we call …

Google Chart Geo Chart Zoom In Quiz

… last talked about at Google Chart Geo Chart Zoom In Quiz Sharing Tutorial, and noticed a bit of ugliness regarding its CSS styling, specifically related to the “too large” border-radius values we’d applied to the twin iframes cutting off wording in their bottom left corner.

This issue is an …

  • aesthetics, only …
  • CSS styling

… one … queue the Web Inspector! How come? Well, web inspectors, such as Google Chrome web browser’s one, allow you to …

  • in place … on our macOS MAMP local Apache/PHP/MySql web server system …
  • dynamically tweak …
  • CSS styling … especially good with inline CSS style syntax, that we happen to be very fond of too … so as to be able to …
  • make the changes for you to optionally re-tweak … ephemerally

… on a test system (ours being a macOS MAMP local Apache/PHP/MySql web server one) ahead of uploading and committing to a permanent change up at the live and public RJM Programming web server domain.

Take a look at how we went about what went into the aesthetically tweaked geo_chart.php Geo Chart interfacer at this live run link, where we remind you again, a substitution of “Survey” by “Quiz” at the first title prompt can show the “My World Zoom In Quiz” in a new window or click a button down below.


Previous relevant Google Chart Geo Chart Zoom In Quiz Sharing Tutorial is shown below.

Google Chart Geo Chart Zoom In Quiz Sharing Tutorial

Google Chart Geo Chart Zoom In Quiz Sharing Tutorial

Adding functionality to yesterday’s Google Chart Geo Chart Zoom In Quiz Tutorial we see an opportunity to …

  • add an element of “when” functionality onto the “where” strengths of the Google Chart Geo Chart recent work, via PHP TimeZones and interfacing to the work of the recent Looks Nice Nearby Speech to Text Game Video Tutorial … as well as …
  • means by which to share or collaborate with the “My World Zoom In Quiz” … via …
    1. email 📧 (via inline HTML PHP mail) … or …
    2. SMS 📟 (via “a” tag href=sms: link)

… and that last SMS methodology brought into focus our wish not to allow, yet, a URL approach to get directly to this new “My World Zoom In Quiz” (although we may change this strategy into the future). So, how to apply security over the use of a URL such as …

https://www.rjmprogramming.com.au/PHP/GeoChart/geo_chart.php?wqperspective=Monday+10+Feb+2020+17:57:15.7182

… not linked, above, because there is no point. We have already clicked it in an SMS we got sent, and that nullifies its use from then on? Huh?! Yes, we use the PHP itself, as we are fond of doing, storing (a form of) that “Monday+10+Feb+2020+17:57:15.7182” away as a comment in amongst the PHP code and, hence, “file_get_contents” checkable by its or some other PHP code for its existence (as well as the “file_put_contents” based clean up removal of said comment after the SMSee’s (body) link is ever clicked), as the security check for whether we navigate to the “My World Zoom In Quiz” (bringing up that last correct answer) via an SMS body URL link, clicked by an SMSee. And that collaborator can do the same thing back to the original sender for the next wrong answer’s similar 📟 emoji button press instigation of this sharing and collaboration Javascript logic …


function smswho() {
if (smsorig == '') { smsorig=document.getElementById('smssend').href.split('0000')[0]; }
if (smsdateorig == '') { smsdateorig=document.getElementById('smsdate').value; }
var smsto=prompt('SMS to?', document.getElementById('smssend').href.split('sms:')[1].split('?')[0]);
if (smsto == null) { smsto = ''; }
if (smsto.trim() != '') {
document.getElementById('smsdate').value=smsdateorig + '.' + gsv.substring(0,1).charCodeAt(0) + gsv.substring(1).substring(0,1).charCodeAt(0);
document.getElementById('smsbut').click();
document.getElementById('smssend').href=(smsorig + '' + gsv.substring(0,1).charCodeAt(0) + gsv.substring(1).substring(0,1).charCodeAt(0)).replace('sms:?','sms:' + smsto + '?');
document.getElementById('smssend').click();
}
}


function emailwho() {
var emto=prompt('Email to?', document.getElementById('emailto').value);
if (emto == null) { emto = ''; }
if (emto.indexOf('@') != -1) {
document.getElementById('emailto').value=emto;
document.getElementById('hcont').value='<html><body><form action=' + document.URL + ' method=POST><input type=hidden value=' + gsv + ' name=wqperspective></input><input type=submit value=\"My World Zoom In Quiz\" style=\"background-color:yellow;\"></input></form></body></html>';
document.getElementById('iemail').click();
}
}

… in the context of all these changes to geo_chart.php Geo Chart interfacer at this live run link, where we remind you again, a substitution of “Survey” by “Quiz” at the first title prompt can show the “My World Zoom In Quiz” in a new window.


Previous relevant Google Chart Geo Chart Zoom In Quiz Tutorial is shown below.

Google Chart Geo Chart Zoom In Quiz Tutorial

Google Chart Geo Chart Zoom In Quiz Tutorial

Today we’re combining …

… to create another form of quiz (we think of as “My World Zoom In Quiz”) the user can navigate to via the way they answer that first title prompt (substituting “Survey” with “Quiz”). You might prefer to think of it as the “Geographical Perspective Quiz” with a degree of difficulty, often, because to see a “Zoomed In” display of a country or region can be disorienting and challenging to recognize. And so, for incorrect dropdown answers, we provide a “zoomed out” world view of where that “zoomed in” view sits (like an inset).

In order to show you this below please click

Again, a bit of a different tack to yesterday with the reworked geo_chart.php Geo Chart interfacer at this live run link, where a substitution of “Survey” by “Quiz” at the first title prompt can show the “My World Zoom In Quiz” (like above) in a new window.


Previous relevant Google Chart Geo Chart Small Region Tutorial is shown below.

Google Chart Geo Chart Small Region Tutorial

Google Chart Geo Chart Small Region Tutorial

Meanwhile, resuming our dreams of Andorra, there must be hundreds of readers there a bit sick of us going on and on and on and on and on about our Google Chart Geo Chart interfacing Quizzes and the use of complex “width” (and “height”) prompt user interactions. After all, we came onto this topic more to do with “small countries”. Well, let’s go back to that and let’s say …

  • as well as the “markers” mode (geographicals) latitude and longitude (helped out by PHP TimeZone places) way of signifying the position of a small country on a world or continent map … always, there behind the scenes, set up ages ago, was the interfacing we had set up to …
  • connect with the Google Chart “smarts” regarding “region” mapping to be able to hone in on a “region” (which can mean a whole country too) of interest

… and that means, today, we revisit our imaginary jaunts in Andorra setting out from the big smoke of …


Andorra la Vella

… to the border tranquillity of …


Pas de la Casa

… in the scenario of today’s tutorial picture … honing in on the user interaction before the width one (yayyyyyy!) with that title prompt. At this prompt we make use of two extensions to default behaviour with our PHP web application, those being …

  1. prefix of “region code” + “;” ( in the case of Andorra an ISO 2 Character Country Code “AD” + “;” = porkAD; )
  2. suffix of “heads up” placename list (making it so you will probably not need to fish around for any latitude and longitude geographicals yourself) via &areplaces=[comma (and + if you want lines joining) separated placename list] … eg. &areplaces=Andorra la Vella,+Pas de la Casa

… to end up with a user title data item user interaction entry of …


AD;My World Survey&areplaces=Andorra la Vella,+Pas de la Casa

… as the lead in to “not much thinking” (and as long as you are not Pinocchio, “follow your nose” ease) required for the other non-quiz-based prompts (ie. no need for width or height mantissae …

… in this scenario).

Quite a bit of a different tack to yesterday’s Google Chart Geo Chart Quiz Tooltip Flag Tutorial that you can see how we needed to tweak geo_chart.php Geo Chart interfacer at this live run link, showing the versatility and usefulness of Google Chart Geo Charts.


Previous relevant Google Chart Geo Chart Quiz Tooltip Flag Tutorial is shown below.

Google Chart Geo Chart Quiz Tooltip Flag Tutorial

Google Chart Geo Chart Quiz Tooltip Flag Tutorial

Yesterday’s Google Chart Geo Chart Quiz on Mobile Tutorial‘s Google Chart Geo Chart interfacing uses …

  • onmouseover event tooltip functionality for non-mobile platforms … and, better something than nothing, we guess …
  • first onclick event tooltip functionality for mobile platforms

… a blessing, in our view, that an onmouseover (ie. on hover) piece of functionality thinking survives into the mobile platform wooooooooorrrrrlllddd in some way shape or form. We generally find tooltips an optimistic and useful webpage functionality tool.

And with this in mind, it was worth our mind’s attention to ask … “what about if the Geo Chart Quiz functionality can, optionally, help out the user a bit without giving the game away?” … in the sense that ISO 2 character country codes can be baffling, yet help to make the quiz a challenge, on occasions, though enough of a turn off for some users, we’re sure. But to place an Emoji Flag could be a feature some quizzers will like and appreciate.

Rather than add to the navigational data we’d rather “add” an Emoji Flag on being “flagged” (tee hee) to do so, that “flagging” being to add argument “&flag=y” into the mix, at the width value prompt, which is the same prompt whereby a user decides to create a quiz in the first place. And because Emojis represent text data (albeit multibyte ones) we won’t even need to change data structures, just data content involving the one string structure member of …


['Latitude','Longitude','Country','Countdown']

… which we’ve been sending as that country’s ISO 2 character code (to leave some challenge to the quizzer, where the user has been seeing that ISO code only “on hover” up to today) … but if the user has “flagged” &flag=y this code below swings into play appending text data onto that ISO Code text data (of PHP variable (and argument) “$instuff” below) via String.fromCodePoint() function, as per …

<?php

$lri=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
$dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

function maybequizflag($instuff) {
global $GETdata, $iso_country_codes, $flagentity, $lri, $dri;
if (isset($_GET['quiz']) || isset($_POST['quiz'])) {
if (isset($_GET['flag']) || isset($_POST['flag'])) {
if (strpos($instuff, "['Lat','Long',") !== false) {
return $instuff; //str_replace("'Country',", "'Country','Flag',", $instuff);
} else {
$outstuff=$instuff;
$cbits=explode("'", $instuff);
$outstuff=$cbits[0];
$uretv=" ' + '";
for ($iol=1; $iol<sizeof($cbits); $iol++) {
if (($iol % 2) == 1) {
if (strlen($cbits[$iol]) == 2) {
for ($jjm=0; $jjm<strlen($cbits[$iol]); $jjm++) {
for ($jm=0; $jm<sizeof($lri); $jm++) {
if (strtoupper(substr($cbits[$iol],$jjm,1)) == $lri[$jm]) {
$uretv=str_replace(" + '", " + String.fromCodePoint(" . $dri[$jm] . ") + '", $uretv); //uvaltosfcp($dri[$jm]);
}
}
}
$outstuff.="'" . $cbits[$iol] . $uretv;
$uretv="' + '";
} else {
$uretv=" ' + '";
for ($im=1; $im<sizeof($iso_country_codes); $im+=2) {
if ($uretv == " ' + '" && strpos(strtolower($iso_country_codes[$im]), strtolower(str_replace("%20"," ",str_replace("%E2%80%99","",str_replace("%2C",",",$cbits[$iol]))))) !== false) {
for ($jjm=0; $jjm<strlen($iso_country_codes[-1 + $im]); $jjm++) {
for ($jm=0; $jm<sizeof($lri); $jm++) {
if (strtoupper(substr($iso_country_codes[-1 + $im],$jjm,1)) == $lri[$jm]) {
$uretv=str_replace(" + '", " + String.fromCodePoint(" . $dri[$jm] . ") + '", $uretv); //uvaltosfcp($dri[$jm]);
}
}
}
}
}
$outstuff.="'" . $cbits[$iol] . $uretv;
$uretv="' + '";
}
} else {
$outstuff.="'" . $cbits[$iol];
}
}
return $outstuff; //str_replace("',9", "','x',9", str_replace("',8", "','x',8", str_replace("',7", "','x',7", str_replace("',6", "','x',6", str_replace("',5", "','x',5", str_replace("',4", "','x',4", str_replace("',3", "','x',3", str_replace("',2", "','x',2", str_replace("',1", "','x',1", str_replace("',0", "','x',0", $instuff))))))))));
}
}
}
return $instuff;
}

?>

Again, you can try the changed geo_chart.php Geo Chart interfacer at this live run link.


Previous relevant Google Chart Geo Chart Quiz on Mobile Tutorial is shown below.

Google Chart Geo Chart Quiz on Mobile Tutorial

Google Chart Geo Chart Quiz on Mobile Tutorial

We wanted to improve on the recent Google Chart Geo Chart More Quizzes Tutorial‘s “World Quiz” functionality approach of displaying window.open popups for mobile platforms. The reason for the concern on mobile platforms, and not such a concern on non-mobile platforms (though there is a concern about popup window web browser disabling settings), because the chance to “overlay” a popup window (via the use of a third argument to window.open calls) is ignored on mobile platforms, instead opening a new browser tab (at best). This can be disconcerting, akin to telling a room of students doing an important examination, to look out the window at an interesting magpie (warbling about Collingwood’s last triumph, no doubt).

Well, after extensive research, and first trying to position “anything new” down the bottom of the webpage we …

  • rejected idea of whole display of a relevant Wikipedia page content at the bottom (of a mobile user’s Geo Chart “quiz” webpage) … associated with a …
  • rejected “a” hashtag link down the bottom (but above proposed content above) to navigate back up to the quiz … to, instead …
  • start thinking that it is up to the mobile user to act themselves to ever navigate away from the quiz webpage, so, instead, initially condense the Wikipedia content down to an image that is …
    1. if HTTPS:// protocol being used, use the Google Page Insights screenshotting “smarts” you can see being used at PDF Slideshow and Form Creation Data URI Contents Tutorial
    2. if HTTP:// protocol being used, use the (thumbnail version of) the first image of the relevant Wikipedia webpage

    … encased by an “a” tag that the click of navigates the user to the relevant Wikipedia content in a new tab (at best), all positioned at the left hand side of the Geo Chart webpage’s H1 or H2 tag heading as a 70px width42px height thumbnail

The conduit here are Ajax Javascript techniques as per …


var myxhr = false;
var oursrc = '';
var woourl='';


function ajit(wourl) {
woourl=wourl;
var xurl = '';
if (document.URL.toLowerCase().indexOf('https') == 0) {
xurl='https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=' + encodeURIComponent(wourl) + '&screenshot=true';
} else {
xurl=document.URL.split('/GeoChart')[0] + '/fgc/?tdinto=&inurl=' + encodeURIComponent(wourl);
}
if (window.XMLHttpRequest) {
myxhr = new window.XMLHttpRequest;
}
else {
try {
myxhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (othermicrosoft) {
try {
myxhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (failed) {
myxhr = false;
}
}
}
if (myxhr) {
myxhr.onreadystatechange = backin;
myxhr.open('GET', xurl, true);
myxhr.send(null);
}
}


function backin() {
if (myxhr.readyState == 4) {
if (myxhr.status == 200) {
if (myxhr.responseText) {
var dbits = myxhr.responseText.split('\"data\":');
if (dbits.length > 1) {
oursrc='data:image/jpeg;base64,' + dbits[1].split('\"')[1].split('\"')[0].replace(/\_/g,'/').replace(/\-/g,'+');
ism='nm';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
ism='';
document.getElementById(ism + 'dwoalttwo').style.position='absolute';
document.getElementById(ism + 'dwoalttwo').style.left='20px';
document.getElementById(ism + 'dwoalttwo').style.top='0px';
document.getElementById(ism + 'dwoalttwo').style.opacity='0.95';
document.getElementById(ism + 'dwoalttwo').style.zIndex='51';
} else {
document.getElementById(ism + 'dwoalt').innerHTML='<br><a id=btta href=#myh title=Top>Back to top</a>';
}
document.getElementById(ism + 'dwoalttwo').innerHTML='<a target=_blank id=adw title=Wikipedia style=z-index:52; href=' + woourl + '><img title=Wikipedia style=width:80px;z-index:52; src=' + oursrc + '></img></a>';
document.getElementById('myh').onclick=function() { document.getElementById('adw').click(); }
if (ism != '') { location.href='#btta'; }
} else if (myxhr.responseText.indexOf('<img') != -1) {
dbits = myxhr.responseText.split('<img');
dbits=dbits[1].split(' src=');
ism='nm';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
ism='';
document.getElementById(ism + 'dwoalttwo').style.position='absolute';
document.getElementById(ism + 'dwoalttwo').style.left='20px';
document.getElementById(ism + 'dwoalttwo').style.top='0px';
document.getElementById(ism + 'dwoalttwo').style.opacity='0.95';
document.getElementById(ism + 'dwoalttwo').style.zIndex='51';
} else {
document.getElementById(ism + 'dwoalt').innerHTML='<br><a id=btta href=#myh title=Top>Back to top</a>';
}
document.getElementById(ism + 'dwoalttwo').innerHTML='<a target=_blank id=adw title=Wikipedia style=z-index:52; href=' + woourl + '><img title=Wikipedia style=width:80px;z-index:52; src=' + dbits[1].split(' ')[0].split('>')[0] + '></img></a>';
document.getElementById('myh').onclick=function() { document.getElementById('adw').click(); }
if (ism != '') { location.href='#btta'; }
}
}
}
}
}

… with the effect, for a mobile user, of not being interrupted from their quiz, unless this thumbnail (Wikipedia content) appears at the top left, that they can “long click” to open in a “New Tab” (or, perhaps, a “Split View”) as required, at least on the iPad we tried this with.

And so, you can try the changed geo_chart.php Geo Chart interfacer at this live run link, we hope representing an improvement for the Quizzing User Experience for our mobile user readers.


Previous relevant Google Chart Geo Chart More Quizzes Tutorial is shown below.

Google Chart Geo Chart More Quizzes Tutorial

Google Chart Geo Chart More Quizzes Tutorial

In allowing the World Quiz web applications of yesterday’s Google Chart Geo Chart World Quizzes Tutorial work accept more than about …

  • the 10 places (per continent Geo Chart) fitting into a $_GET arguments URL (of about 850 characters, for rjmprogramming.com.au domain) … the first cab off the rank allowing for …
  • a lot more than 10 can be accepted via $_POST in an HTML form method=POST action=./geo_chart.php

You may wonder why “first cab off the rank” here. Well, we’re not sure we won’t involve window.sessionStorage or window.localStorage in future plans. It being PHP we’re writing though, we will need a compelling reason to try this.

We allow you to ask the web application to try more places by (optionally) appending space characters onto the height values they enter.

You can try the changed (and note “function iftoobig()” in particular, here) geo_chart.php Geo Chart interfacer at this live run link, and try it with a few right space appended “heights” to try out this new functionality.


Previous relevant Google Chart Geo Chart World Quizzes Tutorial is shown below.

Google Chart Geo Chart World Quizzes Tutorial

Google Chart Geo Chart World Quizzes Tutorial

We’re heading towards “prove it for n” on top of the recent Google Chart Geo Chart Oceania Quiz Tutorial (“prove it for 2”) progress, making quizzes for …

  • Europe
  • South East Asia and Oceania
  • Africa
  • South America
  • North and Central America
  • Asia

… but feel we need more testing to bed it down, as far as reliability issues go, and we’ll keep you posted on that.

We found clutter issue with ISO 2 character Country Codes …

ISO Code 1 Country TZ Place 1 (Lat,Long) Too Close To Country TZ Place 2 (Lat,Long) ISO Code 2
VA Vatican City
(41.90222,
12.45305)
(-0.02,
+0.03)
Rome, Italy
(41.9,
12.48333)
IT
BJ Porto-Novo, Benin
(6.48333,
2.61666)
(-0.03,
+0.78)
Lagos, Nigeria
(6.45,
3.4)
NG

… and so “fashioned” this into a numerical basis for a “declutter” algorithm


function setsixteenquiz() {
var sixteen=16;
var allcontinents=['Europe','South East Asia and Oceania', 'Africa', 'South America', 'North and Central America', 'Asia'];
var thiscontinent=isquiz;
var cisq=-1;
var exclusions=',';
var sofarq=',-1,';
var ourselceqih=selceqih.replace(/\ data\-alt\-/g, ' data-');
if (thiscontinent == 'South East Asia and Oceania') {
sixteen=10;
} else if (thiscontinent == 'Africa') {
sixteen=17;
} else if (thiscontinent == 'South America') {
sixteen=10;
} else if (thiscontinent == 'North and Central America') {
sixteen=10;
}
for (var isqis=0; isqis<allcontinents.length; isqis++) {
if (allcontinents[isqis] != thiscontinent) {
while (ourselceqih.indexOf(' data-continent=\"' + allcontinents[isqis] + '\"') != -1) {
ourselceqih=ourselceqih.replace(' data-continent=\"' + allcontinents[isqis] + '\"','');
}
}
}
var sqws=ourselceqih.split(' data-continent=\"' + thiscontinent + '\" value=\"');
document.body.title='Awaiting quiz clickable circle symbols to score ...';
document.body.style.cursor=pcur;
if (document.getElementById('chart')) {
document.getElementById('chart').title='Awaiting quiz clickable circle symbols to score ... ';
document.getElementById('chart').style.cursor=pcur;
}
var latsofar=[], longsofar=[], thislats=0.0, thislongs=0.0;
var valid=true, ivalid=0, difflatlong=0.0;

while (quizisos.length < sixteen) {
cisq=-1;
while (sofarq.indexOf(',' + cisq + ',') != -1 || exclusions.indexOf(',' + cisq + ',') != -1) {
cisq=Math.floor(Math.random() * eval(-1 + sqws.length));
cisq++;
if (ourtzlist.indexOf(',' + sqws[cisq].split('\"')[0] + ',') != -1) {
thislats=(eval(ourtzlist.split(',' + sqws[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + sqws[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"').length)].split(',')[0]));
thislongs=(eval(ourtzlist.split(',' + sqws[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + sqws[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"').length)].split(',')[1]));
}

if (thiscontinent == 'South East Asia and Oceania') {
if (ourtzlist.indexOf(',' + sqws[cisq].split('\"')[0] + ',') != -1) {
if (eval(ourtzlist.split(',' + sqws[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + sqws[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"').length)].split(',')[1]) < 73.0) { // || eval(ourtzlist.split(',' + ourselceqih[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + ourselceqih[cisq].split('\"')[0] + ',')[0].split(' data-geo=\"').length)].split(',')[1]) >= 169.0) {
cisq=-1;
}
} else {
cisq=-1;
}
}
}
sofarq+='' + cisq + ',';
if (cisq != -1) {
if (sqws[cisq].split('\"')[0] == 'IT') { exclusions+='VA,'; } else if (sqws[cisq].split('\"')[0] == 'VA') { exclusions+='IT,'; }
if (sqws[cisq].split('\"')[0] == 'BJ') { exclusions+='NG,'; } else if (sqws[cisq].split('\"')[0] == 'NG') { exclusions+='BJ,'; }
difflatlong=0.0;
if (quizisos.length > 0) {
for (ivalid=0; ivalid<quizisos.length; ivalid++) {
difflatlong=Math.abs(eval('' + latsofar[ivalid]) - eval('' + thislats)) + Math.abs(eval('' + longsofar[ivalid]) - eval('' + thislongs));
}
}
if (difflatlong >= 2.0 || quizisos.length == 0) {
latsofar.push(thislats);
longsofar.push(thislongs);
quizisos.push(sqws[cisq].split('\"')[0]);
}

}
}
quizisos.push(\"\");
}

Here’s your chance to try the changed geo_chart.php Geo Chart interfacer at this live run link, and enter Africa, South America, North and Central America and Asia Quiz territory by following pointers at the “width” interactive entry (Javascript) prompt window.


Previous relevant Google Chart Geo Chart Oceania Quiz Tutorial is shown below.

Google Chart Geo Chart Oceania Quiz Tutorial

Google Chart Geo Chart Oceania Quiz Tutorial

Regular readers will know about our penchant for “mathematical induction” theory, in the way you …

  • prove it for 1
  • prove it for 2
  • prove it for n

… and earlier this morning “too proud” moi thought we’d be at “n”, skipping “2” by now getting our Geo Chart interfacing new “Quiz” functionality to have covered user interactions for all the major continents of greater than 10 (of category) places, looking towards the “10 is a bit lame” thinking, to follow. Oh, well! But maybe that’s the point of the “2” in the “mathematical induction” proof “game”. A lot might be discovered, and so it was for us, trying to open the door to … come in …


South East Asia and Oceania ...

… spinner! In broad brush concepts, we discovered …

  • we needed to start to worry about places with an ISO 2 code but no TimeZone …
  • we needed to start to worry about places off to the left, right, and top limits of the Geo Chart limits we establish via those weird width and height values you enter … and on this am sure many will have tweaked that the value integer parts are like a “scalar” measure and the mantissae are a “left zero padded percentage offset into the entire Geo Chart on which to lob” measure
  • we needed to rearrange the scoring system’s denominator as a “seconds timer” rather than a “number of goes”
  • we needed to, at least at the start, mention name of Quiz
  • we needed to start closing previous Wikipedia windows on opening a new one, as applicable
  • we needed to start to worry about clutter (eg. Vatican City and Rome geographicals for two different countries)
  • we needed to start to worry about “skewed representations” (going back to Europe Quiz) whereby the first mention of a country ISO 2 Code within the TimeZone list is a position of a colony or dominion

… whereas we optimistically imagined all we might need to worry about was just …

  • converting (boolean binary decision) variable isquiz=false/true (Javascript code logic) into (string ternary and more decision) variable isquiz=”/’Europe’/’South East Asia and Oceania’ (with more to come … until “n” (for) nirvana) … and associated …
  • adding data-continent=”South East Asia and Oceania” global data attributes into dropdown id=’selceq’ linking ISO 2 codes with Country names
  • trying to add a bit of cursor=’progress’ flagging of web application “thinking time”

Never mind! And so, onto yesterday’s Google Chart Geo Chart Europe Quiz Tutorial progress there is not that much difference user interaction wise, just the offer of another weird “width” value choice (on which to blow your mind) but behind the scenes a “hard working mathematical induction middlemanperson” can now offer you the chance to try the changed geo_chart.php Geo Chart interfacer at this live run link, and enter South East Asia and Oceania Quiz territory by following pointers at the “width” interactive entry (Javascript) prompt window.


Previous relevant Google Chart Geo Chart Europe Quiz Tutorial is shown below.

Google Chart Geo Chart Europe Quiz Tutorial

Google Chart Geo Chart Europe Quiz Tutorial

Up to yesterday’s Google Chart Geo Chart Sorted Small Countries Tutorial, as with interfacings to other Google Charts, we had a two phase aspect to the web application structures …

  1. ask for user interaction via the keyboard
  2. display the resultant Google Chart taking notice of that user interaction

… but today’s extension of Geo Chart interfacing functionality opens the door to the new

  • display the resultant Google Chart taking notice of that user interaction and allowing click/touch continuing interaction in the form of a quiz … first cab off the rank … Europe Quiz

The work recently has helped because …


function gck(igck) {
var ansis='';
if (document.getElementById('attachedImage' + ('' + igck).replace('-1',''))) {
var xxx=document.getElementById('attachedImage' + ('' + igck).replace('-1','')).getAttribute('title');
if (xxx.indexOf('#') != -1) {
if (isquiz) {
maybe_bad=false;
if (xxx.split('#')[1].indexOf('/') != -1) {
ansis=xxx.split('#')[1].split('/')[eval(-1 + xxx.split('#')[1].split('/').length)].toLowerCase();
} else {
ansis=xxx.split('#')[1];
}
if (document.getElementById('sans').getAttribute('data-title').toLowerCase().replace(/\ /g,'_') == ansis.toLowerCase().replace(/\ /g,'_')) {
score++;
goes++;
} else {
goes++;
}
document.getElementById('sans').innerHTML='? ' + score + '/' + goes;
}

window.open(xxx.split('#')[1],'_blank', 'top=50,left=50,width=500,height=500');
} else if (xxx == '') {
if (isquiz) {
maybe_bad=false;
if (document.getElementById('attachedImage' + ('' + igck).replace('-1','')).title.indexOf('/') != -1) {
ansis=document.getElementById('attachedImage' + ('' + igck).replace('-1','')).title.split('/')[eval(-1 + xxx.split('#')[1].split('/').length)].toLowerCase();
} else {
ansis=document.getElementById('attachedImage' + ('' + igck).replace('-1','')).title;
}
if (document.getElementById('sans').getAttribute('data-title').toLowerCase().replace(/\ /g,'_') == ansis.toLowerCase().replace(/\ /g,'_')) {
score++;
goes++;
} else {
goes++;
}
document.getElementById('sans').innerHTML='? ' + score + '/' + goes;
}

window.open(document.getElementById('attachedImage' + ('' + igck).replace('-1','')).title,'_blank', 'top=50,left=50,width=500,height=500');
} else {
if (isquiz) {
maybe_bad=false;
if (xxx.indexOf('/') != -1) {
ansis=xxx.split('/')[eval(-1 + xxx.split('/').length)].toLowerCase();
} else {
ansis=xxx;
}
if (document.getElementById('sans').getAttribute('data-title').toLowerCase().replace(/\ /g,'_') == ansis.toLowerCase().replace(/\ /g,'_')) {
score++;
goes++;
} else {
goes++;
}
document.getElementById('sans').innerHTML='? ' + score + '/' + goes;
}

window.open(xxx,'_blank', 'top=50,left=50,width=500,height=500');
}
}
}

… is an onclick place we’ve set aside for our SVG intervention work. Keep it to no keyboard for this Europe Quiz, and we are happy (with this new idea, reminiscent of recent tweaking at Google Chart Annotated Timeline Whitespace Delimitation Tutorial).

So, again, you can try the changed geo_chart.php Geo Chart interfacer at this live run link, and enter Europe Quiz territory by following pointers at the “width” interactive entry (Javascript) prompt window.


Previous relevant Google Chart Geo Chart Sorted Small Countries Tutorial is shown below.

Google Chart Geo Chart Sorted Small Countries Tutorial

Google Chart Geo Chart Sorted Small Countries Tutorial

Yesterday’s Google Chart Geo Chart Small Countries Overlay Tutorial‘s workings potentially using the geographicals (or marker) mode of use actually involve intervention logic within what Google provide SVG-wise for the Geo Chart content.

And so, for some time, the order in which we entered …

Country Surface Area (sq km)
Australia 7692024
New Zealand 269190
Andorra 468

… we entered, interactively by us, like, personally, like, in that order above, like. But for a day or two we were covering up a gap in the “wall of logic” plaster we had created for Google Chart select event logic (actually non-existant for the Geo Chart, but we code for onclick logic to navigate a user to a relevant Wikipedia page). The good news is we have fixed it now, not tying the user down to entering data in any particular order.

Fixed what, now? (I thought I heard you ask?!) Well, the alignment of &aregeographical= data to the symbology presented at the geographical positions on the Geo Map asks that the order we present corresponds to the relevant order of relevant Google SVG elements, and Google orders these from the largest numerical value down to the smallest, as you notice as far as Surface Area (sq km) suits an order of Australia, New Zealand, Andorra …

First non-overlay URL version goes https://www.rjmprogramming.com.au/PHP/GeoChart/geo_chart.php?title=Surface%20Areas%20(sq%20km)&width=1112&height=694&country=Country&popularity=Surface%20Area%20(sq%20km)&data=%20[-34.91667|138.58333|~Australia~,7692024]%20,%20[-36.86667|174.76666|~New%20Zealand~,269190]%20,%20[42.5|1.51666|~Andorra~,468]%20&aregeographicals=http.Australia%2Chttp.New%20Zealand%2Chttp.Andorra
Second overlay URL version goes https://www.rjmprogramming.com.au/PHP/GeoChart/geo_chart.php?title=Surface%20Areas%20(sq%20km)&width=1112&height=694&country=Country&popularity=Surface%20Area%20(sq%20km)&data=%20[-34.91667|138.58333|~Australia~,7692024]%20,%20[-36.86667|174.76666|~New%20Zealand~,269190]%20,%20[42.5|1.51666|~Andorra~,468]%20&overlay=y&aregeographicals=http.Australia%2Chttp.New%20Zealand%2Chttp.Andorra
But the recent work means overlay URL version created interactively with order New Zealand, Andorra, Australia https://www.rjmprogramming.com.au/PHP/GeoChart/geo_chart.php?title=Surface%20Areas%20(sq%20km)&width=1112&height=694&country=Country&popularity=Surface%20Area%20(sq%20km)&data=%20[-36.86667|174.76666|~New%20Zealand~,269190]%20,%20[42.5|1.51666|~Andorra~,468]%20,%20[-34.91667|138.58333|~Australia~,7692024]%20&overlay=y&aregeographicals=http.Australia%2Chttp.New%20Zealand%2Chttp.Andorra
also works

… and the changes necessary to ensure this go


// var pushfrom=[], pushto=[], pushag=[], selceqih='', saih='', oneistoosmall=false, oneisnotapplicable=false;
function assess_small(indatar) {
var ipl=0, jpl=0, kpl=0, pushxx=[];
var outsuffix='';
var outdatar=indatar;
if (pushfrom.length > 0 && !oneisnotapplicable && oneistoosmall) {
for (jpl=0; jpl<pushfrom.length; jpl++) { // for (var ipl=0; ipl<pushfrom.length; ipl++) {
if (jpl == 0) {
var huhdatas=indatar.split('~');
for (var ihuhdatas=2; ihuhdatas<huhdatas.length; ihuhdatas+=2) {
if (huhdatas[eval(-1 + eval('' + ihuhdatas))].split('~')[0].replace('%20',' ').indexOf(' ') != -1) {
pushxx.push(('00000000000000000000000' + huhdatas[ihuhdatas].split(',')[1].split(']')[0]).slice(-22) + ' ... ' + huhdatas[eval(-1 + eval('' + ihuhdatas))].split('~')[0]);
}
pushxx.push(('00000000000000000000000' + huhdatas[ihuhdatas].split(',')[1].split(']')[0]).slice(-22) + ' ... ' + encodeURIComponent(huhdatas[eval(-1 + eval('' + ihuhdatas))].split('~')[0]));
}
pushxx.sort();
pushxx.reverse();
}
ipl=jpl;
for (kpl=0; kpl<pushfrom.length; kpl++) {
if (ipl == jpl && pushxx[jpl].split(' ... ')[1] == pushfrom[kpl].split('~')[1].split('~')[0]) {
ipl=kpl;
pushxx[jpl]=pushxx[jpl].split(' ... ')[0] + ' ... ';
}
}

if (outdatar.indexOf(pushfrom[ipl]) != -1) {
if (outsuffix == '') {
outsuffix='&aregeographicals=' + pushag[ipl];
} else {
outsuffix+='%2C' + pushag[ipl];
}
while (outdatar.indexOf(pushfrom[ipl]) != -1) {
outdatar=outdatar.replace(pushfrom[ipl], pushto[ipl]);
}
}
}
}


return outdatar + outsuffix;
}

Yet again, you can try the changed geo_chart.php Geo Chart interfacer at this live run link.


Previous relevant Google Chart Geo Chart Small Countries Overlay Tutorial is shown below.

Google Chart Geo Chart Small Countries Overlay Tutorial

Google Chart Geo Chart Small Countries Overlay Tutorial

With “overlay” techniques available in life it might be tempting to say “never say never” because you don’t have to compromise a weak solution for a less weak solution. Yesterday’s Google Chart Geo Chart Small Countries Tutorial‘s Google Chart Geo Chart‘s homegrown interfacer tactics for Small Countries is a case in point.

You may recall from yesterday how we dynamically reverted to “geographicals mode” display (Google call it “Markers” mode) when the shading for a Small Country would lead to “data loss”. But what if we …

  • continue what we were doing yesterday “overlayed”

    … onto …

  • what we changed from URL-wise with “function assess_small()” (with the one codeline change

    outsuffix='&overlay=y&aregeographicals=' + pushag[ipl];

    ) … in the form of two new HTML iframe code below …
    <?php

    if (isset($_GET['overlay']) || isset($_POST['overlay'])) {
    echo "<script> function overlayit() {
    var ourls=documentURL.split('&overlay=')[0].split('[');
    var ourl=ourls[0];
    for (var iouris=1; iouris<ourls.length; iouris++) {
    if (ourls[iouris].substring(0,1) == '~') {
    ourl+='[' + ourls[iouris];
    } else {
    ourl+='[' + ourls[iouris].replace(ourls[iouris].split('~')[0],'');
    }
    }
    document.body.style.zIndex='-12';
    document.getElementById('doverlay').innerHTML='<iframe style=\"position:absolute;top:0px;left:0px;width:100%;height:100vh;z-index:2;opacity:0.95;\" src=\"' + ourl + '\"></iframe>';
    document.getElementById('doverlaytwo').innerHTML='<iframe style=\"position:absolute;top:0px;left:0px;width:100%;height:100vh;z-index:22;opacity:0.9;\" src=\"' + documentURL.replace('&overlay=','&qw=') + '&guess=' + '\"></iframe>';
    }
    setTimeout(overlayit, 2000);
    </script>
    ";
    }

    ?>

Again, you can try the changed geo_chart.php Geo Chart interfacer at this live run link.


Previous relevant Google Chart Geo Chart Small Countries Tutorial is shown below.

Google Chart Geo Chart Small Countries Tutorial

Google Chart Geo Chart Small Countries Tutorial

We last used the excellent Google Chart Geo Chart tool with the work of Window LocalStorage Client Versus Server Map Tutorial, and it was this project that alerted us to both a weakness and a strength of that chart …

  • a weakness being its inability to get the resolution to shade a small country (eg. today’s tutorial picture‘s Andorra) … but, the good news, as used with this integration work above …
  • a strength is the alternative display mechanism via geographical entries

… and so, what if …

  • as the user enters in their Country (or Geographical) data …
  • if we can determine it as being a Country being entered … and…
  • you have only ever been entering Countries … and …
  • any one Country so defined has a surface area less than 10000 square kilometers … then …
  • we navigate to a Geographical data version of this “only Countries entered” data set … so that …
  • even small such Countries will be displayed …
  • as they would not if still in the default “only Countries entered” mode of display

We introduce three new sources of data in order to piece together the (Javascript via PHP coding) logic for this …

  1. TimeZone and Geographicals and ISO 2 Letter Code information …

    var ourtzlist='<option value="Africa/Abidjan" data-geo="5.31666,-4.03334,GMT,CI,+0">Africa/Abidjan</option><option value="Africa/Accra" data-geo="5.55,-0.21667,GMT,GH,+0">Africa/Accra</option>'; // etcetera etcetera etcetera
  2. Country Name and ISO 2 Letter Code information (etcetera etcetera etcetera) …

    <div id=dlookups>
    <select id='selceq' style='display:none;'>
    <option value='AF'>Afghanistan</option>
    <option value='AX'>Aland Islands</option>
    <option value='AL'>Albania</option>
    </select></div>
  3. Surface Areas of Countries thanks to Wikipedia (etcetera etcetera etcetera) …

    <table style='display:none;' id='surface_area' border='1' cellpadding='2' cellspacing='0'>
    <tbody><tr bgcolor='#efefef'>
    <th>Pos
    </th><th>Country
    </th>
    <th>Area (km²)
    </th></tr>
    <tr>
    <td>1</td>
    <td><a data-href='/wiki/Russia' title='Russia'>Russia</a></td>
    <td>17098246
    </td></tr>
    <tr>
    <td>2</td>
    <td><a data-href='/wiki/Canada' title='Canada'>Canada</a></td>
    <td>9984670
    </td></tr>
    <tr>
    <td>3</td>
    <td><a data-href='/wiki/People%27s_Republic_of_China' title='People's Republic of China'>China</a></td>
    <td>9572900
    </td></tr>
    </tbody></table>

… used where we process a user Country (or Geographical) interaction Javascript code snippet where variable thisris is that user interaction result …


var pushfrom=[], pushto=[], pushag=[], selceqih='', saih='', oneistoosmall=false, oneisnotapplicable=false;

if (ourtzlist.indexOf(',' + thisris.toUpperCase() + ',') != -1 && thisris.length == 2) {
if (selceqih == '') { selceqih=document.getElementById('selceq').innerHTML; }
if (saih == '') { saih=document.getElementById('surface_area').innerHTML; }
pushfrom.push('[~' + thisris + '~');
pushto.push('[' + ourtzlist.split(',' + thisris.toUpperCase() + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + thisris.toUpperCase() + ',')[0].split(' data-geo=\"').length)].split(',')[0] + '|' + ourtzlist.split(',' + thisris.toUpperCase() + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + thisris.toUpperCase() + ',')[0].split(' data-geo=\"').length)].split(',')[1] + '|~' + thisris.toUpperCase() + '~');
if (selceqih.indexOf(' value=\"' + thisris.toUpperCase() + '\">') != -1) {
pushag.push('http.' + encodeURIComponent(selceqih.split(' value=\"' + thisris.toUpperCase() + '\">')[1].split('<')[0]));
} else {
pushag.push('');
}
if (saih.indexOf('>' + selceqih.split(' value=\"' + thisris.toUpperCase() + '\">')[1].split('<')[0]) != -1) {
thissa=saih.split('>' + selceqih.split(' value=\"' + thisris.toUpperCase() + '\">')[1].split('<')[0])[1].split('<td>')[1].split('<')[0].split(String.fromCharCode(10))[0];
if (eval('' + thissa) < 10000) {
oneistoosmall=true;
}
}
} else if (('' + thisris).trim() != '' && selceqih.toUpperCase().indexOf('>' + thisris.toUpperCase()) != -1) {
thisisocc=selceqih.toUpperCase().split('>' + thisris.toUpperCase())[0].split(' VALUE=\"')[eval(-1 + selceqih.toUpperCase().split('>' + thisris.toUpperCase())[0].split(' VALUE=\"').length)].split('\"')[0];
pushfrom.push('[~' + encodeURIComponent(thisris) + '~');
pushto.push('[' + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"').length)].split(',')[0] + '|' + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"').length)].split(',')[1] + '|~' + encodeURIComponent(thisris) + '~');
pushag.push('http.' + encodeURIComponent(thisris));
if (thisris.indexOf(' ') != -1) {
pushfrom.push('[~' + thisris + '~');
pushto.push('[' + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"').length)].split(',')[0] + '|' + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"')[eval(-1 + ourtzlist.split(',' + thisisocc + ',')[0].split(' data-geo=\"').length)].split(',')[1] + '|~' + encodeURIComponent(thisris) + '~');
pushag.push('http.' + encodeURIComponent(thisris));
}
if (saih.toUpperCase().indexOf('>' + thisris.toUpperCase()) != -1) {
thissa=saih.toUpperCase().split('>' + thisris.toUpperCase())[1];
thissa=thissa.split('<TD>')[1].split('<')[0].split(String.fromCharCode(10))[0];
if (eval('' + thissa) < 10000) {
oneistoosmall=true;
}
}
}

… and if remaining relevant just before the next navigation happens, where variable indatar represents the default “only Countries entered” mode of display value …


// var pushfrom=[], pushto=[], pushag=[], selceqih='', saih='', oneistoosmall=false, oneisnotapplicable=false;
function assess_small(indatar) {
var outsuffix='';
var outdatar=indatar;
if (pushfrom.length > 0 && !oneisnotapplicable && oneistoosmall) {
for (var ipl=0; ipl<pushfrom.length; ipl++) {
if (outdatar.indexOf(pushfrom[ipl]) != -1) {
if (outsuffix == '') {
outsuffix='&aregeographicals=' + pushag[ipl];
} else {
outsuffix+='%2C' + pushag[ipl];
}
while (outdatar.indexOf(pushfrom[ipl]) != -1) {
outdatar=outdatar.replace(pushfrom[ipl], pushto[ipl]);
}
}
}
}


return outdatar + outsuffix;
}

You can try the changed geo_chart.php Geo Chart interfacer at this live run link.


Previous relevant Window LocalStorage Client Versus Server Map Tutorial is shown below.

Window LocalStorage Client Versus Server Map Tutorial

Window LocalStorage Client Versus Server Map Tutorial

Get a good map, and a goodly number of times you’ll want a map of smaller or larger scale than the one you have. Murphy’s Law? This is probably why in the wonderful woooooooorrrrrrrrlllllld of Google Charts they have included …

  • Geo Chart topographic map of the world or of regions
  • Map Chart terrestrial/satellite map of your group of markers at a zoom level of your choosing

… and hope you can see that the latter can save the day for a Short Distance Trip (corner shop, anyone?!).

So we’ve added onto yesterday’s Window LocalStorage Client Versus Server Timeline Tutorial progress a new toggling button to view a scenario in either Google Chart scenario above.

You can see this integration work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link supervising a tweaked geo_chart.php Geo Chart interfacer.


Previous relevant Window LocalStorage Client Versus Server Timeline Tutorial is shown below.

Window LocalStorage Client Versus Server Timeline Tutorial

Window LocalStorage Client Versus Server Timeline Tutorial

Up to yesterday’s Window LocalStorage Client Versus Server User Tutorial‘s progress, our Capital City Find Matching Country Report web application project was all about …

  • where (and capital of “what”) … but we often seek out a way to add into the mix that 4th dimension …
  • when (ie. time)

… and regarding the current project, a …

  • where “map” … can interface with a …
  • when “Trip Plan Itinerary”

… and for this purpose, we’re going to interface to the excellent Google Charts Annotated Timeline Chart, thanks, because it combines links of “time” to “user annotations” in a timeline way, that similar way you might describe the qualities of a Trip, even before you’ve gone on that trip. We’ve also added it so that an unordered places list can be turned into a Trip Plan Itinerary at the click/touch of a new map 🗺 &#128506; emoji button.

Again, see how these timeline amendments were achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link and annotatedtimeline_chart.php which changed quite a lot.


Previous relevant Window LocalStorage Client Versus Server User Tutorial is shown below.

Window LocalStorage Client Versus Server User Tutorial

Window LocalStorage Client Versus Server User Tutorial

The inherent weakness with our current Capital City Find Matching Country Report web application project, to our minds, was that places of interest are not restricted to the Capital Cities of Countries, especially when “Trip Planning”. On the other hand, it would be impossible to cater for every “place” in the world. That is far too subjective for good web application applicability. What would be good though, is to allow in user defined …


Place name, Country name

… terms, the definitions of interest to a user. We can ask this …

  • flagged by the click/touch of an emoji button … and …
  • the interactive entry presented via a Javascript prompt window

. When thinking of data applicable to an individual, then that can be catered for by recording it in localStorage where it will be recalled on the next execution of that web application in the same web browser.

This, along with a Colour Wheel of the “nearest TimeZone place” onto the existing logic of yesterday’s Window SessionStorage Client Versus Server Order Tutorial progress could make for a more useful and practical tool for those Trip Planners out there!

See how this was achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

Did you know?

To click/touch one of those Google Chart Geo Chart lines between Emoji Flag Markers will show a new Google Maps directions web page with transport times and detail, as well as an inhouse crow fly distance of that trip leg, as shown up the top right of today’s tutorial picture.


Previous relevant Window SessionStorage Client Versus Server Order Tutorial is shown below.

Window SessionStorage Client Versus Server Order Tutorial

Window SessionStorage Client Versus Server Order Tutorial

If we are to honour our thoughts of being able to use our current Capital City Find Matching Country Report web application as a Trip Planner …

Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

… then yesterday’s Window SessionStorage Client Versus Server Flags Tutorial “progress to now” needs to take notice of a user’s order of multiple select (dropdown) element click/touching of Capital City option (sub)elements, just as we did with the recent User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial‘s web application project to allow for a user ordered YouTube video playlist.

Because what is a Trip Planner without an ordered trip? Well, that is debatable, but what isn’t (debatable), is that there will be people in the world who appreciate the “mapping out” of a proposed Trip Planning Itinerary. What could we call on here? We can think of the Google Chart Geo Chart work around about the time of Google Geo Chart Co-ordinate Emojis Tutorial, when we started using …

  • a world map … with …
  • emoji markers … and optionally …
  • joined up by straight lines

… an idea for a Trip Plan itinerary synopsis, perhaps?!

If you examined closely yesterday’s code changes you will have noticed our collecting of TimeZone Place geographical latitude and longitude information. Today, we start making use of that preparatory work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

Stop Press

The “emoji markers” above (as of 2 January 2020) will be “country flags” (as per Window SessionStorage Client Versus Server Flags Tutorial ideas), as defined.


Previous relevant Window SessionStorage Client Versus Server Flags Tutorial is shown below.

Window SessionStorage Client Versus Server Flags Tutorial

Window SessionStorage Client Versus Server Flags Tutorial

Yes, there’s more to do onto yesterday’s Window SessionStorage Client Versus Server CSS Tutorial‘s Capital City Find Matching Country Report web application project, in our eyes. We have not even mentioned “Internationalization” as a concept up to now. In this line of thinking …

Did you know?

Emoji flags via ISO 2 character country codes are dead easy via Regional Indicator Symbol characters …


var lri="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

var thiscc='AU'; // ISO 2 character countrycode for Australia
var ccsuff='', ccchar=' ';
for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
ccsuff+='&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
}
document.getElementById('lastflag').innerHTML=ccsuff;

… to result in (via <span style=font-size:64px;>&#127462;&#127482;</span>) …


🇦🇺

… providing interest and general translatability to the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.


Previous relevant Window SessionStorage Client Versus Server CSS Tutorial is shown below.

Window SessionStorage Client Versus Server CSS Tutorial

Window SessionStorage Client Versus Server CSS Tutorial

Further to yesterday’s Window SessionStorage Client Versus Server Integration Tutorial we have a two pronged improvements set for you today with our current Capital City Find Matching Country Report web application project …

  • CSS styling changes … and …
  • additional functionality for Email and SMS links back to our current Capital City Find Matching Country Report web application project (to complete the cycle)

We use several modes of CSS application (the first and last of particular relevance to today’s “highlighting of workflow” improvements) …

… the “static” measures often helping to highlight the web application’s main workflow of user interaction and the “dynamic” measures helping to alert the user as to where to proceed with their “workflow”.

In terms of CSS styling work …

  1. for non-mobile platforms we allow for more columns to be applied to our Capitals select (dropdown) element (in order to reduce some user scrolling, as does our new additional A-Z letter basis sorting functionality) as per … the “dynamic” Javascript DOM “class” modifications

    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('lefttd').className='lefttd';
    }

    … dovetailing with the “static” internal CSS coding

    <style>
    .lefttd {
    column-count: 4;
    max-height: 35%;
    vertical-align: top;
    max-width: 70%;
    font-size: 8px;
    background-color: rgba(205,205,205,0.5);
    background-image: -webkit-gradient(
    linear,
    right bottom,
    left top,
    color-stop(0, rgba(205, 205, 205, 0.8)),
    color-stop(0.50, rgba(255, 255, 0, 0.2))
    );
    background-image: -o-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
    background-image: -moz-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
    background-image: -webkit-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
    background-image: -ms-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
    background-image: linear-gradient(to left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);

    }
    </style>

    … and please note that around here at RJM Programming we have a “far from hard and fast rule” (but a rule regardless) regarding HTML element ID and class attributes that they concern (and (usually) be compartmentalised into) Javascript (DOM) manipulations and CSS styling issues respectively … and add a linear-gradient background to the table cell when expecting the initial user interaction on non-mobile platforms
  2. a “dynamic” Javascript DOM “class” modification … document.getElementById(‘myrepsb’).className=’dglow’; … is made to the “Report…” button at the Capitals select (dropdown) onfocusout event so as to highlight (with “glow” inspired styling) where user interaction may flow to

As far as links go, you may expect to need serverside means to construct these in online Email and SMS message interfacing, but email (client program) products like Gmail parse your ascii text and convert http: or https: protocol URLs in your Email body to hyperlinks, as does the Messages SMS application here on this MacBook Pro using macOS Mojave. Cute, huh?! So to close the circle back from remote thar’ parts back to our web application is a simple matter of, in broad brush terms …

  • adding two new buttons called “Email Columns and Links …” and “SMS Columns and Links …” that …
  • set a global variable andlinkto = true; … setting in play, within the report writing code (that likes monospaced fonts) …
  • add a new links column to the right with URLs like …
    https://www.rjmprogramming.com.au/HTMLCSS/wls_vs_php.htm?andgo=y&countries=Belize&capitals=Belmopan
    … to tell your client programs to form the hyperlinks for us (if they are “of the mood”, that is!)

To improve user experience we use “dynamic” Javascript DOM HTML “style” attribute change means to easier close the “Colour Wheel” helper web application “above the fold” by changing the CSS z-index (Javascript DOM [element].style.zIndex) of elements accordingly, when the user clicks other elements. You can see all this with the first “the changed” link above, where all “glow” CSS styling will also feature prominently.


Previous relevant Window SessionStorage Client Versus Server Integration Tutorial is shown below.

Window SessionStorage Client Versus Server Integration Tutorial

Window SessionStorage Client Versus Server Integration Tutorial

We hope, when performing a “software integration” task, that the two or more components of that integration work with each other’s talents, rather than a big tussle like reinventing the wheel. This ideal makes the work …

  • sometimes difficult but rewarding because …
  • the differences between two independent software components can be quite large and daunting … and the programmer has to see that …
  • care is applied so as not to wreck previous functionality and integrations in making the current integration work

… and that is why we’ve made corollaries to “building from scratch” (when planning and design is a huge component) can be a lot simpler than a software integration “renovation”, in the past, here at this blog.

Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

As a user experience improvement for “trip planners” perhaps, we allow the user to alphabetically sort the presented select (dropdown) element entries …


var firstopt='';
var wasopts='';
var restopts='';

function readyitforsort(iselid) {
var optsare=[];
var huhisel=document.getElementById(iselid).innerHTML;
var huhsopts=huhisel.split('</option>');
for (var ihuh=0; ihuh<huhsopts.length; ihuh++) {
if (huhsopts[ihuh].trim() != '') {
if (firstopt == '') {
firstopt=huhsopts[ihuh] + '</option>';
} else {
wasopts+=huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>';
optsare.push(huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>');
}
}
}
optsare.sort();
for (var jhuh=0; jhuh<optsare.length; jhuh++) {
restopts+=optsare[jhuh];
}
}

… controlled by a new dropdown in the left hand column header cell.

We also allow the user to move the iframe element with some positioning emoji buttons near the “Close” button one (of yesterday’s work).

Into the future, too, we’ll have more to say regarding the germination of an idea “to allow a mobile onmouseover simulator (of sorts)” be to allow the user to perform a swipe across an individual HTML element of interest on mobile platforms (ie. harness ontouchmove event) as per (so far) … kicked off by “<body onload=” setTimeout(athn, 5000); “>” …


var last24='';
var rectdc;

function nodivalert() {
document.getElementById('divalert').style.display='none';
document.getElementById('divalert').style.zIndex='-456';
document.getElementById('divalert').style.left=('-' + rectdc.left).replace('px','') + 'px';
document.getElementById('divalert').style.top=('-' + rectdc.top).replace('px','') + 'px';
}

function ourdivalert(inmsg) {
document.getElementById('divalert').style.position='absolute';
document.getElementById('divalert').style.left=('' + rectdc.left).replace('px','') + 'px';
document.getElementById('divalert').style.top='' + eval(-80 + eval(('' + rectdc.top).replace('px',''))) + 'px';
document.getElementById('divalert').style.backgroundColor='#e0e0e0';
document.getElementById('divalert').style.display='block';
document.getElementById('divalert').style.zIndex='456';
document.getElementById('divalert').style.opacity='0.8';
document.getElementById('divalert').style.padding='5px 5px 5px 5px';
document.getElementById('divalert').innerHTML=inmsg + '<br><br><input type=button value=Close onclick=nodivalert();></input>';
setTimeout(nodivalert,9000);
}

function athn() {
rectdc=document.getElementById('dc').getBoundingClientRect();
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('dc').ontouchmove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
} else {
document.getElementById('dc').onmousemove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
}
}

… working with the new HTML …


<div id=divalert></div>
</body>
</html>

… to try to allow the “explainer of an element” advantages non-mobile platforms have for hovering over an HTML element with a title attribute filled in.

And so, yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new Weather integration functionality. It caused the changed colour_wheel.html‘s colour wheel (at this live run link) to be affected (by integrations “up”).


Previous relevant Window SessionStorage Client Versus Server Ajax Tutorial is shown below.

Window SessionStorage Client Versus Server Ajax Tutorial

Window SessionStorage Client Versus Server Ajax Tutorial

We have a few “clientside chestnuts” to use with our current Capital City Find Matching Country Report web application project today, those being …

  • Ajax functionality, kicked off by an “onclick” event set of logic, allowing mobile platforms to also have a look in (the look in that they miss when the event logic is off the “onmouseover” event)
  • iframe and its …
    1. srcdoc attribute (“content” alternative to src “url” attribute) … along with, and crucially needing (because srcdoc ignores its own document.body onload goings on, that we need the “Iframe Client Pre-Emptive” methods below to circumvent) the …
    2. onload event opportunity of an iframe element (we group into “Iframe Client Pre-Emptive” methods, here)

… adding onto yesterday’s Window SessionStorage Client Versus Server Canvas Tutorial.

It’s not that involved with the Ajax work today, given that there are no cross-domain issues, though there are cross-protocol (SSL https: versus non-SSL http:) issues to be careful about. Those can be addressed because the web application is recalled to present its “Country Report” and that is the opportunity to check on protocol navigation requirements.

Along the way, we also make this happen for the user on …

  • click/touching a table row … it sets off new “tr” (table row) element logic calling our (inhouse) Timezone and Wikipedia Place Information helper (HTML) via Ajax (so not leaving the webpage) … and because of place name oddities we allow for …
  • “td” (table cell) element user amendments by setting their contenteditable attributes to “true” (since fixed, but we found the Timezone Europe/Tirane pointing at Tirane in Albania used to be spelt “Tirana”)

… that latter methodology normally a technique we apply to “div” elements (so, there you are!)

Also used are “overlay” techniques, two of the “usual suspects” here coming into play, to present to the “Ajax content to srcdoc iframe arrangements” …

Yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Ajax” functionality.


Previous relevant Window SessionStorage Client Versus Server Canvas Tutorial is shown below.

Window SessionStorage Client Versus Server Canvas Tutorial

Window SessionStorage Client Versus Server Canvas Tutorial

Yesterday’s Window SessionStorage Client Versus Server Share Tutorial dealt with ascii text clipboard copy assisted sharing options with our current Capital City Find Matching Country Report web application project. This suited both Email and SMS share options we coded for, but today’s extension of functionality from “ascii text” data to “graphical data” only suits Email sharing. The other caveat with our work is that no serverside (for us, PHP) help is allowed, so no PHP mail here.

What comes into play with a “graphical data” clientside (only) sharing approach? It will not surprise many readers that, for us, it involves …

  • canvas element … converting HTML table outerHTML “ascii text” data … via …
  • canvas drawing methods “[canvasContext].strokeRect()” and “[canvasContext].strokeText()” via “[cellElement].getBoundingClientRect()” … to convert that canvas element content via …
  • [canvasElement].toDataURL() … to an …
  • img element nested in a div contenteditable=true element … so as to hook in with today’s very useful helper link, thanks … use …

  • function tabletoclipboard(canvas) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
    var img = document.createElement('img');
    img.src = canvas.toDataURL();

    var div = document.createElement('div');
    div.contentEditable = true;
    div.appendChild(img);
    document.body.appendChild(div);

    // do copy
    SelectText(div);
    document.execCommand('Copy');
    document.body.removeChild(div);
    }

    function SelectText(element) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
    var doc = document;
    if (doc.body.createTextRange) {
    var range = document.body.createTextRange();
    range.moveToElementText(element);
    range.select();
    } else if (window.getSelection) {
    var selection = window.getSelection();
    var range = document.createRange();
    range.selectNodeContents(element);
    selection.removeAllRanges();
    selection.addRange(range);
    }
    }
  • to leave the user’s device’s clipboard containing a useful table (with linework) … ready to …
  • paste into an email body section

… sharing off to an emailee collaborator.

Again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Email Table” button functionality.


Previous relevant Window SessionStorage Client Versus Server Share Tutorial is shown below.

Window SessionStorage Client Versus Server Share Tutorial

Window SessionStorage Client Versus Server Share Tutorial

Yesterday’s Window SessionStorage Client Versus Server Tutorial has been amended today for two new sharing and collaboration options, those being …

  • email
  • SMS

… but you may well be familiar with the restrictions on email and SMS client (program) approaches to this, coming from HTML “a” link “mailto:” and “sms:” href property prefixes respectively. We’re going to need help with the 800 odd character (length) restrictions with the (resultant) web address (bar) URL, but what? How about working off the great advice of this wonderful link, thanks, to copy what we’d have assembled into an ascii text Report into the characters contained by the user’s device’s clipboard?


function copytoclipboard(str) { // thanks to https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
var el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
el.style.position = 'absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
}

An issue that springs up here using such clipboard ascii text content, whenever you get the Font choice given to you, pick a monospaced Font like Courier New or “Fixed Width”.

See the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new sharing functionality.


Previous relevant Window SessionStorage Client Versus Server Tutorial is shown below.

Window SessionStorage Client Versus Server Tutorial

Window SessionStorage Client Versus Server Tutorial

Sometimes it’s the case at this blog that we’d like to introduce a new topic, but do not do so, because we cannot show any real world (or real application) use of that concept. So it has been, up until now, with the concept of (web browser) window (object) sessionStorage property. But yesterday’s Window LocalStorage Client Versus Server Primer Tutorial represented an opportunity akin to when Haley’s Comet gets at its closest to the Earth … while you see a chance, take it … chance because of that nuance whereby we were not trying to store data for any other purpose than passing data onto …

  1. a known entity … ie. same web application … at …
  2. a known time … ie. immediately

… two conditions that make the code design “marginally” more ideal for the window object property concept of sessionStorage rather than localStorage, in that any …


localStorage.removeItem([knownLocalStorageName]);

… becomes superfluous as with sessionStorage data will disappear between web browser sessions, anyway.

We offer this new concept as a non-default option of a select (dropdown) element replacement to the h1 element hardcoding “localStorage” with the changed wls_vs_php.htm Capital City Find Matching Country Report live run. The other nuance of difference with sessionStorage usage is that in the document.body onload event logic, we may as well (as part of other changes) pre-emptively look for, and if there, respond to, any found sessionStorage data points, even without the user having flagged it specifically


var datamode='localStorage';

function checkforreport() {
var divcont='';
var dcaps, dctys, idis;
if (getcapitals == 'localStorage') {
if (window.localStorage) {
getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
localStorage.removeItem('wls_vs_php_capitals');
} else {
getcapitals='';
}
} else if (getcapitals == 'sessionStorage') {
document.getElementById('smode').value=getcapitals;
datamode=getcapitals;
if (window.sessionStorage) {
getcapitals=decodeURIComponent(sessionStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
} else {
getcapitals='';
}
}
else if (getcapitals == '' && window.sessionStorage) {
getcapitals=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_capitals')).replace(/^null$/g,'')).replace(/\+/g,' ');
if (getcapitals != '') {
document.getElementById('smode').value='sessionStorage';
datamode='sessionStorage';
}
}

if (getcountries == 'localStorage') {
if (window.localStorage) {
getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
localStorage.removeItem('wls_vs_php_countries');
} else {
getcountries='';
}
} else if (getcountries == 'sessionStorage') {
if (window.sessionStorage) {
getcountries=decodeURIComponent(sessionStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
if (getcapitals.replace('sessionStorage','') != '' && getcountries.replace('sessionStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
} else {
getcountries='';
}
}
else if (getcountries == '' && document.getElementById('smode').value == 'sessionStorage' && window.sessionStorage) {
getcountries=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_countries')).replace(/^null$/g,'')).replace(/\+/g,' ');
if (getcountries != '') {
document.getElementById('smode').value='sessionStorage';
datamode='sessionStorage';
}
}

if (getcapitals != '' && getcountries != '') {
divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
dcaps=getcapitals.split('|');
dctys=getcountries.split('|');
for (idis=0; idis<dcaps.length; idis++) {
divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
}
document.getElementById('dreport').innerHTML=divcont;
}
document.getElementById('smode').value=datamode;
}

Which beggars the question “What are the differences between sessionStorage and localStorage?” A quick reading might surmise that “the latter has an expiration date”. We leave you with an open ended Google search so that you may extend your readings on this.


Previous relevant Window LocalStorage Client Versus Server Primer Tutorial is shown below.

Window LocalStorage Client Versus Server Primer Tutorial

Window LocalStorage Client Versus Server Primer Tutorial

Even though we rave on a lot about serverside PHP and its $_POST method=POST (versus HTML/Javascript recipient via ? and & argument $_GET method=GET scenario) data length advantages as the recipient of an HTML form method=POST set of data that could be sizeable, we’ve just realized that there is a client Javascript and window.localStorage methodology that may help alleviate the need to involve PHP (and any other serverside intervention) on occasions.

Hint: Yes, we’ve raved on about this too?! Does the blog posting title give it away? Okay, yes, it should read “localStorage”, but thought we’d gone past such juvenile finickiness since the Whac-A-Mole controversy of 1st December 2019 (or even The Great Tea Trolley Disaster of ’67, we daresay).

It can even use a “self-destruct” approach to the use of this “localStorage” on having used it because …

  • the web application knows who is using it (localStorage) … and on having accessed and read it …
  • the web application knows it (localStorage) is of no use to any other user (in this web application’s case, at least)

… which is very pleasing for a Land Surveyor who likes to leave cow paddocks as they’ve seen them so to speak. Except it’s like having a ten tonne truck worth of data access in amongst the cow pats when having access to “localStorage” (or PHP), rather than a little piddle of calf wee (wee Metcalfes know a thing or two about these things!) data access of ? and & HTML/Javascript URL arguments (or even if we were to use HTTP Cookies).

It’s not as if we all have access to serverside language usage, though we do, because we really like PHP and MAMP and Apache/PHP/MySql web servers (and have arranged our development environment accordingly), but what if you are starting out in web development, and still want to allow for sizeable chunks of data with your web applications? Huh? Huh?! See the possibilities? Try our proof of concept Capital City Find Matching Country Report live run, and highlight a whole swathe of (multiple mode) dropdown option Capital Cities holding down the shift key before pressing the yellow “Report” button. If the URL ends up as …

https://rjmprogramming.com.au/HTMLCSS/wls_vs_php.html?capitals=localStorage&countries=localStorage

that’s because the web application’s …


function analyze() {
var purl=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);
if (purl.length > 800) {
if (phpexists) {
document.getElementById('myform').method='POST';
document.getElementById('myform').action='./wls_vs_php.php';
} else if (window.localStorage) {
localStorage.setItem('wls_vs_php_countries', encodeURIComponent(document.getElementById('countries').value));
localStorage.setItem('wls_vs_php_capitals', encodeURIComponent(document.getElementById('capitals').value));
document.getElementById('capitals').value='localStorage';
document.getElementById('countries').value='localStorage';
location.href=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);

return false;
}
}
return true;
}

… HTML form onsubmit event logic …

  1. discovered no PHP web application existant (via Client Pre-emptive Iframe techniques) … and …
  2. discovered (in a sanity check feeling way) that to go down the proposed HTML form method=GET approach was risking a …

    HTTP 414 "Request URI too long"

    … web browser error … and that …
  3. localStorage was a known web browser piece of functionality
  4. … and so as per our localStorage logic we …

  5. back out of the default HTML form method=GET navigation setup of the web application in favour of …
    • storing that data into localStorage
    • substituting into the URL ? and & arguments the hardcoding “localStorage” (and in so doing, getting back under the HTTP 414 “Request URI too long” limitation, piecing together (what amounts to) …
      location.href=document.URL.split(‘#’)[0].split(‘?’)[0] + ‘?capitals=localStorage&countries=localStorage’;)
      … that on a recall to this same web application a …
    • document.body onload event piece of Javascript logic checks the localStorage for its incoming Capital City Country Report data, as per …

      var phpexists=false;
      var getcapitals=location.search.split('capitals=')[1] ? decodeURIComponent(location.search.split('capitals=')[1].split('&')[0]).replace(/\+/g,' ') : '';
      var getcountries=location.search.split('countries=')[1] ? decodeURIComponent(location.search.split('countries=')[1].split('&')[0]).replace(/\+/g,' ') : '';

      function checkforreport() {
      var divcont='';
      var dcaps, dctys, idis;
      if (getcapitals == 'localStorage') {
      if (window.localStorage) {
      getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
      localStorage.removeItem('wls_vs_php_capitals');
      } else {
      getcapitals='';
      }
      }
      if (getcountries == 'localStorage') {
      if (window.localStorage) {
      getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
      if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
      localStorage.removeItem('wls_vs_php_countries');
      } else {
      getcountries='';
      }
      }

      if (getcapitals != '' && getcountries != '') {
      divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
      dcaps=getcapitals.split('|');
      dctys=getcountries.split('|');
      for (idis=0; idis<dcaps.length; idis++) {
      divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
      }
      document.getElementById('dreport').innerHTML=divcont;
      }
      }

      … the localStorage.removeItem() representing that “self-destruct” nuance we were talking about before

We may well use this methodology in future projects, and hope it has been of some little interest to you as well?!

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in Not Categorised | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Emoji Clothing Game Tutorial

Emoji Clothing Game Tutorial

Emoji Clothing Game Tutorial

While it’s fresh in the mind, and in line with that mathematical induction principle you …

  1. try the new idea for case 1 … “so yesterday” …
  2. try the new idea for case 2 … today’s work … and it did result in yesterday’s being tweaked (which is partly why we like that mathematical induction idea) …
  3. try the new idea for case n

    Would any/all of Nadia, Naomi, Noah, Nolan, Natasha, Nancy, Nova, Nadine, Nora, Nathan, Natalie, Noel, Nash, Nathaniel, Neil, Nikita, Nelson, Nalani, Natalia, Nina, Noelle, Nyx, Nicholas, Nico … please report to the main desk, please?

… using a lot of yesterday’s Emoji Objects Game Tutorial‘s “Emoji Object Game” logic to build on, today, we present a new “Emoji Clothing Game” which is …

  • drag and drop methodology based …
  • Emoji Clothing Game … involving linking an emoji to a single (again, noun) word (representing an “activity” type) … or vice versa … that we think could benefit via …
  • allowing a user to pick a non-English language to translate the whole web application into

Often in these “cloning” scenarios, 95% of the production of the new ( emoji_clothing_game.php ) web application is just the rearrangement of that “emoji data” source incoming, which we again thank Emojipedia for, regarding. That makes for “an easy day at the office”!

“Cloning” ideas are easier with brand new web applications, as well, because you model the design on what has worked in the recent past. It is usually a tad harder to add some functionality that works in the clones, that is to be applied to some web application of the past. We’re yet to try this with the Google Translate language translation interfacing we are bedding down, for a Drag and Drop web application from the past. We’ll cross that little Rubicon later!

Stop Press

In …

  • Google Translate overseeing mode
  • smaller device size
  • landscape orientation

… we’ve decided to help out with better programmatical scrolling, as per amended onload event logic as per


function ouronl() {
for (var i = 0; i < langs.length; i++) { select_language.options[i] = new Option(langs[i][0], i); } // Set default language / dialect ... thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html select_language.selectedIndex = 10; updateCountry(); noway=false; select_dialect.selectedIndex = 11; showInfo('info_start'); if (document.URL.indexOf('rjmprogramming-com-au.translate.goog') != -1) { document.getElementById('select_language').style.display='none'; if (window.parent != window) {
noway=noway;
} else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i)) {
if (window.outerWidth > window.outerHeight) {
document.getElementById('score').scrollIntoView();
}
}

}
}

… into that changed experimental_drag_and_drop.htm Drag and Drop basis.

Why the noway=noway; coding kludge above? Well, if we did no annoying programmatical scrolling into the HTML iframe Italian translation call below …

… that’s why!


Previous relevant Emoji Objects Game Tutorial is shown below.

Emoji Objects Game Tutorial

Emoji Objects Game Tutorial

Even though we have been using “Drag and Drop” methodologies a lot lately, it was way back in late September 2023, with Inhouse WordPress Blog Posting Game Tutorial, when we last needed to change that client HTML and Javascript Drag and Drop clientside basis, that all the PHP parents look to. But today we need to change it, because we have a new …

  • drag and drop methodology based …
  • Emoji Objects Game … involving linking an emoji to a single noun word (representing a “room” type) … or vice versa … that we think could benefit via …
  • allowing a user to pick a non-English language to translate the whole web application into

… as they try our “proof of concept” emoji_object_game.php Emoji Object Game tapping into that changed experimental_drag_and_drop.htm Drag and Drop basis.

So far only this Emoji Objects Game offers these new Drag and Drop Language interfacing smarts, because we found the Internationalization combination of “emojis” and “single noun word answers” as an irresistible combination to try this concept out with, and after bedding down this idea, we’re pretty sure we’ll improve on that “single use situation” over time!

As far as …

  • emoji data goes we’d like to thank Emojipedia for the emoji categorization help … and …
  • as far as language translations go we’d like to thank Google Translate

… profusely!


Previous relevant Inhouse WordPress Blog Posting Game Tutorial is shown below.

Inhouse WordPress Blog Posting Game Tutorial

Inhouse WordPress Blog Posting Game Tutorial

The WordPress 404.php Tutorial Picture image creation work in yesterday’s Interactively Change WordPress Blog Background Image on Scroll Tutorial set us to thinking of a Drag and Drop game (akin to those in the recent discussions) we could set up to …

  • show the user, in the “Drag” section a WordPress Blog Posting Title (and date) … which the user should drag to the appropriate …
  • table cell, nine of which exist in the “Drop Zone”, and are numbered and backgrounded by a random WordPress Tutorial Picture image

… in alignment with the adage …

Every picture is worth a thousand words.

As well, today, both in terms of …

  • providing hints … and/or …
  • providing information

… those table cells are associated with …

  • double click event (“ondblclick”) logic that shows the “Cut to the Chase” underlying “action item” associated with the WordPress Blog Posting involved … and, just quietly …
  • right click event (“oncontextmenu”) logic that shows the associated WordPress Blog Posting involved itself

… in our first draft “proof of concept” PHP based Inhouse WordPress Blog Posting Game (helped out by a tweaked experimental_drag_and_drop.htm Drag and Drop basis) we hope you get to try below (when it transforms into the Inhouse Blog Game after the default incarnation) …

… worked by our WordPress 404.php now containg the PHP code snippet …

<?php

if (strpos(('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'), '437195~') !== false) { // Drag and drop quiz
//file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.p','here');
$prevcontis='';
$ptfileis=$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'ptitledddata.html';
if (file_exists($ptfileis)) { // thanks to https://stackoverflow.com/questions/67707029/how-do-i-get-how-long-the-file-was-created-in-seconds-in-php
$modifdate = filemtime($ptfileis);
$secondsago = time() - $modifdate;
if ($secondsago < 50) {
unlink($ptfileis);
} else {
//$prevcontis=file_get_contents("http://www.rjmprogramming.com.au/ptitledddata.html" . "?random=" . rand(0,56453423));
$prevcontis=file_get_contents($ptfileis);
}
}
file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
// file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?random=' . explode(')',$_GET['random'])[0]);
//file_put_contents($ptfileis . "huh", $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//} else {
// file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.q',('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'));
}

?>

… to help out the game.


Previous relevant Interactively Change WordPress Blog Background Image on Scroll Tutorial is shown below.

Interactively Change WordPress Blog Background Image on Scroll Tutorial

Interactively Change WordPress Blog Background Image on Scroll Tutorial

With yesterday’s Interactively Change Background Image on Scroll User Settings Tutorial‘s offering were you “an intrepid”, typing …

//www.rjmprogramming.com.au/ITblog/600/400/

… into that newly minted Javascript prompt window designed for user interaction purposes? This populates the background images in our new Image Scrolling with Fixed Text web application with a random selection from the WordPress Blog you are reading. Because we have some control here, we researched whether our WordPress 404.php logic could be tweaked to help out more in this scenario. The way the PHP works here, detecting this situation, at the end of its workings, is to use an image header (exemplified by the GIF one below) …

<?php

header('Content-Type: image/gif');
echo file_get_contents($path);
exit;

?>

… where $path would point at a GIF image file residing on the RJM Programming domain web server. This design restricts us from any echo functionality before this, so what can we achieve? Anyone? Anyone? Yes, Rasmus, we can write to other web server files that could be like middle-people between the server (supplier of image data) and client (the webpage that called the server). After the server work …

<?php

if (strpos(('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'), '591734~') !== false) {
//file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.p','here');
$prevcontis='';
$ptfileis=$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'ptitledata.html';
if (file_exists($ptfileis)) { // thanks to https://stackoverflow.com/questions/67707029/how-do-i-get-how-long-the-file-was-created-in-seconds-in-php
$modifdate = filemtime($ptfileis);
$secondsago = time() - $modifdate;
if ($secondsago > 5) {
unlink($ptfileis);
} else {
$prevcontis=file_get_contents($ptfileis);
}
}
file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//file_put_contents($ptfileis . "huh", $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//} else {
// file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.q',('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'));
}

?>

… back at that client (which called the server with that appended “591734” placed onto the URL to indicate the intention to want to examine this return data), we have Ajax based Javascript logic …


var ptc='#';
var iptc=0;
var btlist=[];
var vsbtlist=[];
var omo='';

var zhr=null;
var zform=null;
var rawhtml='';

function defmaybe(inu) {
var retomo=omo;
if (omo != '') {
omo='';
return retomo;
}
return inu;
}

function stateChanged() {
var inm=1, jnm=1, thebtitle='';
if (zhr.readyState == 4) {
if (zhr.status == 200) {
rawhtml = zhr.response;
console.log('rawhtml=' + rawhtml);
if (rawhtml.indexOf('random=') != -1 && vsbtlist.length > 0) {
var rawrs=rawhtml.split('random=');
for (inm=1; inm<rawrs.length; inm++) {
for (jnm=0; jnm<vsbtlist.length; jnm++) {
if (vsbtlist[jnm].indexOf('?random=' + rawrs[inm].split(String.fromCharCode(10))[0]) != -1) {
console.log('found ...');
thebtitle=rawhtml.split('?random=' + rawrs[inm].split(String.fromCharCode(10))[0])[0].split(String.fromCharCode(10))[eval(-1 + rawhtml.split('?random=' + rawrs[inm].split(String.fromCharCode(10))[0])[0].split(String.fromCharCode(10)).length)];
console.log(thebtitle);
document.getElementById(vsbtlist[jnm].split('?')[0]).title=thebtitle + ' ... you can right click to navigate there';
document.getElementById(vsbtlist[jnm].split('?')[0]).onmouseout=function(){ omo=''; };
document.getElementById(vsbtlist[jnm].split('?')[0]).onmouseover=function(){ omo='//www.rjmprogramming.com.au/ITblog/' + thebtitle.split(' (')[0].toLowerCase().replace(/\ /g,'-'); };
document.getElementById(vsbtlist[jnm].split('?')[0]).oncontextmenu=function(){ window.open(defmaybe('//www.rjmprogramming.com.au/ITblog/' + thebtitle.split(' (')[0].toLowerCase().replace(/\ /g,'-')),'_blank','top=50,left=50,width=800,height=800'); };
}
}
}
}
}
}
}

function ajaxit() {
zhr = new XMLHttpRequest();
zhr.onreadystatechange=stateChanged;
zhr.open('get', '//www.rjmprogramming.com.au/ptitledata.html?random=' + Math.floor(Math.random() * 196756453), true);
zhr.send(null);
}

… adding oncontextmenu (ie. right click) functionality to the background images, so as a popup window can open to show the associated WordPress Blog posting linked to the image data.

… in today’s changed interactively_change_background_image_on_scroll.html web application you can also try way below.


Previous relevant Interactively Change Background Image on Scroll User Settings Tutorial is shown below.

Interactively Change Background Image on Scroll User Settings Tutorial

Interactively Change Background Image on Scroll User Settings Tutorial

If you are a regular reader, you’ll know with the web applications presented here, we usually try to allow the user to control …

  • how they function … and/or sometimes …
  • how they look

… in the ephemeral “this session” sense, and sometimes follow that up, depending, with recallable settings often calling on window.localStorage or HTTP Cookies, associated with the web browser being used.

Regarding that ephemeral “this session” sense above, building on the work of yesterday’s Interactively Change Background Image on Scroll Tutorial, we now allow the user control over defining any/all …

  • Background Image source URL
  • Refresh delay (in seconds)
  • Text Wording
  • Text Background Image source URL

… and regarding the use of that last one, we’ve decided, somewhat, to take over with the CSS regarding the Text Wording showing through amongst so many “image interests” with various opacities …


var mode='dw';

function preask() {
if (backimg.trim() != '') {
if (backimg.toLowerCase().replace(/\ /g,'') == 'lorempicsum') {
backimg='//picsum.photos/600/400' + suffix + '?random=' + Math.floor(Math.random() * 198765643);
if (mode == 'dw') {
mode='';
document.write('<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>');
} else {
document.getElementById('dstyle').innerHTML+='<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>';
}
backimg='lorempicsum';
} else {
if (mode == 'dw') {
mode='';
document.write('<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>');
} else {
document.getElementById('dstyle').innerHTML+='<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>';
}
}
}
}

Which beggars the observation …

Isn’t the CSS text-shadow property just great?!

We use it more and more often to help out foreground text presented with a lot of “overlay imagery” going on behind it.

Here is the Javascript prompt window “blurb” presented to the user should they want to delve into this woooooorrrrrlllllldddd just by clicking or touching in the non-text part of the webpage …

var ansis=prompt(‘Optionally enter in background source URL prefix [‘ + prefix + midbit + suffix + ‘] ( or type Lorem Picsum or for blog posting images you could try //www.rjmprogramming.com.au/ITblog/’ + sixhundred + ‘/’ + fourhundred + ‘/ ), hashtag delimited from an optional imagery refresh rate in seconds [‘ + ten + ‘], hashtag delimited from an optional Text element background image (or type Lorem Picsum), hashtag delimited from optional Text wording [‘ + tcont + ‘] we will assume involves a space.‘, ”);

… in the changed interactively_change_background_image_on_scroll.html web application you can also try below.


Previous relevant Interactively Change Background Image on Scroll Tutorial is shown below.

Interactively Change Background Image on Scroll Tutorial

Interactively Change Background Image on Scroll Tutorial

Regarding today’s “Interactively Change Background Image on Scroll” topic, we’d like to thank, profusely, two sources …

Queue … Lulu (no, not the dog, this time)!

Yes, we’ve just added “Interactively”, we hear you say (just maybe, perhaps, a tad sarcastically, shall we say … huh?!!!!). But, it’s the …

… that is all a bit new, at least to us, today, continuing on the recent wonder regarding contenteditable=true, mentioned in the recent Animated GIF SVG Quiz Automation Interaction Tutorial

And did you know, at least for non-mobile platforms, you can set the focus (on non-mobile platforms only, as there are the “keyboard getting in the way” issues we’re thankful for with mobile platforms which preclude any thoughts of a programmed [element].focus() operation) to one of these “contenteditable=true style elements”? We’d never been sure, only focussing to HTML input textboxes and textareas up to now, we believe.

… whereby non-mobile focus to a contenteditable=true HTML div type (innerHTML style) element is possible, adding to the original W3School’s content ideas swirling around …

  • CSS position: fixed; … for foreground text, in relation to …
  • scrolling … with …
  • background imagery

… for topics we hope you find as interesting as we did, in our new “proof of concept” web application you can also try below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Games, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Emoji Objects Game Tutorial

Emoji Objects Game Tutorial

Emoji Objects Game Tutorial

Even though we have been using “Drag and Drop” methodologies a lot lately, it was way back in late September 2023, with Inhouse WordPress Blog Posting Game Tutorial, when we last needed to change that client HTML and Javascript Drag and Drop clientside basis, that all the PHP parents look to. But today we need to change it, because we have a new …

  • drag and drop methodology based …
  • Emoji Objects Game … involving linking an emoji to a single noun word (representing a “room” type) … or vice versa … that we think could benefit via …
  • allowing a user to pick a non-English language to translate the whole web application into

… as they try our “proof of concept” emoji_object_game.php Emoji Object Game tapping into that changed experimental_drag_and_drop.htm Drag and Drop basis.

So far only this Emoji Objects Game offers these new Drag and Drop Language interfacing smarts, because we found the Internationalization combination of “emojis” and “single noun word answers” as an irresistible combination to try this concept out with, and after bedding down this idea, we’re pretty sure we’ll improve on that “single use situation” over time!

As far as …

  • emoji data goes we’d like to thank Emojipedia for the emoji categorization help … and …
  • as far as language translations go we’d like to thank Google Translate

… profusely!


Previous relevant Inhouse WordPress Blog Posting Game Tutorial is shown below.

Inhouse WordPress Blog Posting Game Tutorial

Inhouse WordPress Blog Posting Game Tutorial

The WordPress 404.php Tutorial Picture image creation work in yesterday’s Interactively Change WordPress Blog Background Image on Scroll Tutorial set us to thinking of a Drag and Drop game (akin to those in the recent discussions) we could set up to …

  • show the user, in the “Drag” section a WordPress Blog Posting Title (and date) … which the user should drag to the appropriate …
  • table cell, nine of which exist in the “Drop Zone”, and are numbered and backgrounded by a random WordPress Tutorial Picture image

… in alignment with the adage …

Every picture is worth a thousand words.

As well, today, both in terms of …

  • providing hints … and/or …
  • providing information

… those table cells are associated with …

  • double click event (“ondblclick”) logic that shows the “Cut to the Chase” underlying “action item” associated with the WordPress Blog Posting involved … and, just quietly …
  • right click event (“oncontextmenu”) logic that shows the associated WordPress Blog Posting involved itself

… in our first draft “proof of concept” PHP based Inhouse WordPress Blog Posting Game (helped out by a tweaked experimental_drag_and_drop.htm Drag and Drop basis) we hope you get to try below (when it transforms into the Inhouse Blog Game after the default incarnation) …

… worked by our WordPress 404.php now containg the PHP code snippet …

<?php

if (strpos(('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'), '437195~') !== false) { // Drag and drop quiz
//file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.p','here');
$prevcontis='';
$ptfileis=$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'ptitledddata.html';
if (file_exists($ptfileis)) { // thanks to https://stackoverflow.com/questions/67707029/how-do-i-get-how-long-the-file-was-created-in-seconds-in-php
$modifdate = filemtime($ptfileis);
$secondsago = time() - $modifdate;
if ($secondsago < 50) {
unlink($ptfileis);
} else {
//$prevcontis=file_get_contents("http://www.rjmprogramming.com.au/ptitledddata.html" . "?random=" . rand(0,56453423));
$prevcontis=file_get_contents($ptfileis);
}
}
file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
// file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?random=' . explode(')',$_GET['random'])[0]);
//file_put_contents($ptfileis . "huh", $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//} else {
// file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.q',('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'));
}

?>

… to help out the game.


Previous relevant Interactively Change WordPress Blog Background Image on Scroll Tutorial is shown below.

Interactively Change WordPress Blog Background Image on Scroll Tutorial

Interactively Change WordPress Blog Background Image on Scroll Tutorial

With yesterday’s Interactively Change Background Image on Scroll User Settings Tutorial‘s offering were you “an intrepid”, typing …

//www.rjmprogramming.com.au/ITblog/600/400/

… into that newly minted Javascript prompt window designed for user interaction purposes? This populates the background images in our new Image Scrolling with Fixed Text web application with a random selection from the WordPress Blog you are reading. Because we have some control here, we researched whether our WordPress 404.php logic could be tweaked to help out more in this scenario. The way the PHP works here, detecting this situation, at the end of its workings, is to use an image header (exemplified by the GIF one below) …

<?php

header('Content-Type: image/gif');
echo file_get_contents($path);
exit;

?>

… where $path would point at a GIF image file residing on the RJM Programming domain web server. This design restricts us from any echo functionality before this, so what can we achieve? Anyone? Anyone? Yes, Rasmus, we can write to other web server files that could be like middle-people between the server (supplier of image data) and client (the webpage that called the server). After the server work …

<?php

if (strpos(('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'), '591734~') !== false) {
//file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.p','here');
$prevcontis='';
$ptfileis=$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'ptitledata.html';
if (file_exists($ptfileis)) { // thanks to https://stackoverflow.com/questions/67707029/how-do-i-get-how-long-the-file-was-created-in-seconds-in-php
$modifdate = filemtime($ptfileis);
$secondsago = time() - $modifdate;
if ($secondsago > 5) {
unlink($ptfileis);
} else {
$prevcontis=file_get_contents($ptfileis);
}
}
file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//file_put_contents($ptfileis . "huh", $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//} else {
// file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.q',('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'));
}

?>

… back at that client (which called the server with that appended “591734” placed onto the URL to indicate the intention to want to examine this return data), we have Ajax based Javascript logic …


var ptc='#';
var iptc=0;
var btlist=[];
var vsbtlist=[];
var omo='';

var zhr=null;
var zform=null;
var rawhtml='';

function defmaybe(inu) {
var retomo=omo;
if (omo != '') {
omo='';
return retomo;
}
return inu;
}

function stateChanged() {
var inm=1, jnm=1, thebtitle='';
if (zhr.readyState == 4) {
if (zhr.status == 200) {
rawhtml = zhr.response;
console.log('rawhtml=' + rawhtml);
if (rawhtml.indexOf('random=') != -1 && vsbtlist.length > 0) {
var rawrs=rawhtml.split('random=');
for (inm=1; inm<rawrs.length; inm++) {
for (jnm=0; jnm<vsbtlist.length; jnm++) {
if (vsbtlist[jnm].indexOf('?random=' + rawrs[inm].split(String.fromCharCode(10))[0]) != -1) {
console.log('found ...');
thebtitle=rawhtml.split('?random=' + rawrs[inm].split(String.fromCharCode(10))[0])[0].split(String.fromCharCode(10))[eval(-1 + rawhtml.split('?random=' + rawrs[inm].split(String.fromCharCode(10))[0])[0].split(String.fromCharCode(10)).length)];
console.log(thebtitle);
document.getElementById(vsbtlist[jnm].split('?')[0]).title=thebtitle + ' ... you can right click to navigate there';
document.getElementById(vsbtlist[jnm].split('?')[0]).onmouseout=function(){ omo=''; };
document.getElementById(vsbtlist[jnm].split('?')[0]).onmouseover=function(){ omo='//www.rjmprogramming.com.au/ITblog/' + thebtitle.split(' (')[0].toLowerCase().replace(/\ /g,'-'); };
document.getElementById(vsbtlist[jnm].split('?')[0]).oncontextmenu=function(){ window.open(defmaybe('//www.rjmprogramming.com.au/ITblog/' + thebtitle.split(' (')[0].toLowerCase().replace(/\ /g,'-')),'_blank','top=50,left=50,width=800,height=800'); };
}
}
}
}
}
}
}

function ajaxit() {
zhr = new XMLHttpRequest();
zhr.onreadystatechange=stateChanged;
zhr.open('get', '//www.rjmprogramming.com.au/ptitledata.html?random=' + Math.floor(Math.random() * 196756453), true);
zhr.send(null);
}

… adding oncontextmenu (ie. right click) functionality to the background images, so as a popup window can open to show the associated WordPress Blog posting linked to the image data.

… in today’s changed interactively_change_background_image_on_scroll.html web application you can also try way below.


Previous relevant Interactively Change Background Image on Scroll User Settings Tutorial is shown below.

Interactively Change Background Image on Scroll User Settings Tutorial

Interactively Change Background Image on Scroll User Settings Tutorial

If you are a regular reader, you’ll know with the web applications presented here, we usually try to allow the user to control …

  • how they function … and/or sometimes …
  • how they look

… in the ephemeral “this session” sense, and sometimes follow that up, depending, with recallable settings often calling on window.localStorage or HTTP Cookies, associated with the web browser being used.

Regarding that ephemeral “this session” sense above, building on the work of yesterday’s Interactively Change Background Image on Scroll Tutorial, we now allow the user control over defining any/all …

  • Background Image source URL
  • Refresh delay (in seconds)
  • Text Wording
  • Text Background Image source URL

… and regarding the use of that last one, we’ve decided, somewhat, to take over with the CSS regarding the Text Wording showing through amongst so many “image interests” with various opacities …


var mode='dw';

function preask() {
if (backimg.trim() != '') {
if (backimg.toLowerCase().replace(/\ /g,'') == 'lorempicsum') {
backimg='//picsum.photos/600/400' + suffix + '?random=' + Math.floor(Math.random() * 198765643);
if (mode == 'dw') {
mode='';
document.write('<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>');
} else {
document.getElementById('dstyle').innerHTML+='<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>';
}
backimg='lorempicsum';
} else {
if (mode == 'dw') {
mode='';
document.write('<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>');
} else {
document.getElementById('dstyle').innerHTML+='<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>';
}
}
}
}

Which beggars the observation …

Isn’t the CSS text-shadow property just great?!

We use it more and more often to help out foreground text presented with a lot of “overlay imagery” going on behind it.

Here is the Javascript prompt window “blurb” presented to the user should they want to delve into this woooooorrrrrlllllldddd just by clicking or touching in the non-text part of the webpage …

var ansis=prompt(‘Optionally enter in background source URL prefix [‘ + prefix + midbit + suffix + ‘] ( or type Lorem Picsum or for blog posting images you could try //www.rjmprogramming.com.au/ITblog/’ + sixhundred + ‘/’ + fourhundred + ‘/ ), hashtag delimited from an optional imagery refresh rate in seconds [‘ + ten + ‘], hashtag delimited from an optional Text element background image (or type Lorem Picsum), hashtag delimited from optional Text wording [‘ + tcont + ‘] we will assume involves a space.‘, ”);

… in the changed interactively_change_background_image_on_scroll.html web application you can also try below.


Previous relevant Interactively Change Background Image on Scroll Tutorial is shown below.

Interactively Change Background Image on Scroll Tutorial

Interactively Change Background Image on Scroll Tutorial

Regarding today’s “Interactively Change Background Image on Scroll” topic, we’d like to thank, profusely, two sources …

Queue … Lulu (no, not the dog, this time)!

Yes, we’ve just added “Interactively”, we hear you say (just maybe, perhaps, a tad sarcastically, shall we say … huh?!!!!). But, it’s the …

… that is all a bit new, at least to us, today, continuing on the recent wonder regarding contenteditable=true, mentioned in the recent Animated GIF SVG Quiz Automation Interaction Tutorial

And did you know, at least for non-mobile platforms, you can set the focus (on non-mobile platforms only, as there are the “keyboard getting in the way” issues we’re thankful for with mobile platforms which preclude any thoughts of a programmed [element].focus() operation) to one of these “contenteditable=true style elements”? We’d never been sure, only focussing to HTML input textboxes and textareas up to now, we believe.

… whereby non-mobile focus to a contenteditable=true HTML div type (innerHTML style) element is possible, adding to the original W3School’s content ideas swirling around …

  • CSS position: fixed; … for foreground text, in relation to …
  • scrolling … with …
  • background imagery

… for topics we hope you find as interesting as we did, in our new “proof of concept” web application you can also try below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Games, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Australian Postcode Place Initial Bearings Tutorial

Australian Postcode Place Initial Bearings Tutorial

Australian Postcode Place Initial Bearings Tutorial

The recent Australian Postcode Place Images Tutorial, we think, could benefit by not only showing …

  • great circle distances (ie. crow fly distances) … but, as of today’s work, also …
  • initial bearings (ie. crow fly starting out directions)

… which uses new Javascript …

<?php echo ”

function great_circle_bearing(talis, gnolis, latis, longis) {
var latdir=' N', longdir=' E';
var latd=0, longd=0;
var latm=0, longm=0;
var lats=0.0, longs=0.0;
var latrest=0.0, longrest=0.0;
var insg='';
var lls=[];

// Let ‘R’ be the radius of Earth,
// ‘L’ be the longitude,
// ‘θ’ be latitude,
// ‘β‘ be Bearing.

// Bearing from point A to B, can be calculated as,
// β = atan2(X,Y),
// where, X and Y are two quantities and can be calculated as:
// X = cos θb * sin ∆L
// Y = cos θa * sin θb – sin θa * cos θb * cos ∆L

var ourbrg=eval(eval(360.0 + eval(eval(eval(180.0 / Math.PI) * Math.atan2(
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + latis))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval(eval('' + longis) - eval('' + gnolis))))),
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + talis))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + latis)))) -
eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + talis))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + latis))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval(eval('' + longis) - eval('' + gnolis)))))
)))) % 360.0);


lls=('' + ourbrg).split(' ');
if (lls[0].indexOf('+') != -1) {
lls[0]=lls[0].replace('+','');
} else if (lls[0].indexOf('-') != -1) {
latdir=' S';
lls[0]=lls[0].replace('-','');
}
latd=lls[0].split('.')[0];
latrest=eval('0.' + (lls[0] + '.0').split('.')[1]);
latm=Math.floor(latrest * 60);
lats=eval((latrest * 3600) - Math.floor(latm * 60)).toPrecision(3);
if (('' + lats).indexOf('e') != -1) {
lats=eval(('' + lats).split('.')[0]);
}
if (lats >= 60.0) {
latm++;
lats-=60.0;
if (latm >= 60) {
latd++;
latm-=60;
}
}

return '' + latd + '°' + ('0' + latm).slice(-2) + "`" + ('0' + lats).split('.')[0].slice(-2) + ((('' + lats).indexOf('.') != -1) ? ('.' + ('' + lats).split('.')[1].split('00000')[0]) : '') + '``' + ' ... ' + ourbrg;
}

“; ?>

… for onmouseover titles viewable on the top and bottom sets of three Google Maps Directions link sets in the middle of the tabular results, with the changed australia_place_crowfly_distances.php‘s live run link.


Previous relevant Australian Postcode Place Images Tutorial is shown below.

Australian Postcode Place Images Tutorial

Australian Postcode Place Images Tutorial

We think, on top of the work of yesterday’s Australian Postcode Northern Territory Place Tutorial, it would be good to enhance the existant …

Australian place linked to Australian postcode linked to Australian Google Charts Geo Chart user experience

… and, today, add some Wikipedia image possibilities into the mix. How best to approach this idea, given it is an enhancement and not part of the primary workflow thinking? We think, perhaps, turn the webpage’s body element into a “screenful palette” (at least initially) and fill it with background images via the …

  • left top
  • center top
  • right top
  • right center
  • right bottom
  • center bottom
  • left bottom
  • left center

… CSS background-position positioning options as an approach to an attempt to represent an unknown number and order and quality of Wikipedia image data, displayable each time a user enters a placename or postcode that has a Wikipedia entry (that we hope is about that place, though no guarantees here). The new Javascript “function ulit” introduced yesterday is changed for today’s work as per …


var goes=0;

function ulit(ino, inpl) {
var suff='';
if (inpl == inpl.toLowerCase() || inpl == inpl.toUpperCase()) {
var outpl='', outdl='';
var wds=inpl.toLowerCase().split(' ');
for (var inb=0; inb<wds.length; inb++) {
if (wds[inb].length > 2 || outpl.replace('mt','').replace('st','') == '') {
outpl+=outdl + wds[inb].substring(0,1).toUpperCase() + (wds[inb] + ' ').substring(1).trim();
} else if (wds[inb] == 'po') {
outpl+=outdl + wds[inb].toUpperCase();
} else {
outpl+=outdl + wds[inb];
}
outdl=' ';
}
if (ino) { ino.innerHTML=outpl; }
if (document.getElementById('imageson').checked) {
if (('' + document.getElementById('mytable').outerHTML).split('>')[0].indexOf('15') == -1) {
document.getElementById('mytable').style.marginTop='149px';
} else {
document.getElementById('myh1').style.marginLeft='265px';
document.getElementById('myh3').style.marginLeft='265px';
document.getElementById('myh4').style.marginLeft='265px';
}
document.getElementById('sdesc').innerHTML=outpl + ' ';
suff=' ';
document.getElementById('sdesc').style.backgroundColor='white';
document.getElementById('tzi').src=document.getElementById('tzi').src.split('?')[0] + '?tzexact=' + encodeURIComponent(outpl) + '&tznickname=' + encodeURIComponent(outpl.replace(/_/g,' ')) + '&avaJUNKtar=multiply'; // + avatar_at;
} else if (('' + document.getElementById('mytable').outerHTML).indexOf('15') != -1) {
document.getElementById('mytable').style.marginTop='0px';
if (1 == 2) { document.getElementById('sdesc').innerHTML=''; }
} else if (1 == 2) {
document.getElementById('sdesc').innerHTML='';
}
goes++;
if (goes == 2) {
document.getElementById('ourcanvas').style.height='100%';
}

return outpl + suff;
} else {
if (document.getElementById('imageson').checked) {
if (('' + document.getElementById('mytable').outerHTML).split('>')[0].indexOf('15') == -1) {
document.getElementById('mytable').style.marginTop='149px';
} else {
document.getElementById('myh1').style.marginLeft='265px';
document.getElementById('myh3').style.marginLeft='265px';
document.getElementById('myh4').style.marginLeft='265px';
}
document.getElementById('sdesc').innerHTML=inpl + ' ';
suff=' ';
document.getElementById('sdesc').style.backgroundColor='white';
document.getElementById('tzi').src=document.getElementById('tzi').src.split('?')[0] + '?tzexact=' + encodeURIComponent(inpl) + '&tznickname=' + encodeURIComponent(inpl.replace(/_/g,' ')) + '&avaJUNKtar=multiply'; // + avatar_at;
} else if (('' + document.getElementById('mytable').outerHTML).indexOf('15') != -1) {
document.getElementById('mytable').style.marginTop='0px';
if (1 == 2) { document.getElementById('sdesc').innerHTML=''; }
} else if (1 == 2) {
document.getElementById('sdesc').innerHTML='';
}
goes++;
if (goes == 2) {
document.getElementById('ourcanvas').style.height='100%';
}

return inpl + suff;
}
}

… in the changed australia_place_crowfly_distances.php‘s live run link.


Previous relevant Australian Postcode Northern Territory Place Tutorial is shown below.

Australian Postcode Northern Territory Place Tutorial

Australian Postcode Northern Territory Place Tutorial

We had cause to revisit the PHP web application of Australian Postcode Place Modal Backdrop Popup Move Tutorial recently, and we were lucky (in a masochistic sense) to do a test showing an error we hadn’t detected initially, designing it.

That weakness, we had to learn, revolved around Northern Territory places in Australia. Clear thinking may have got us there earlier, but the problem “actually” was that postcodes in the Northern Territory start with “0” (ie. zero) and somewhere down the track in all the code our “mapping” of that postcode lost its leading zero, and so “refeeding” that “non-leading-zero” postcode back into the latitude and longitude lookup, the web application could fail.

But thinking outside the box, if we don’t want to wade through to the “string becomes integer” issue in the code, another fact we can “hang our hat on” is that Australian Postcodes are four characters long, and so the Javascript tweak below also fixed our issues, as per …


document.getElementById(indivo.id.replace('_01','_02')).innerHTML=('0000' + findit[eval(-1 + kk)].split(';')[eval(-1 + findit[eval(-1 + kk)].split(';').length)] + ii).slice(-4);

… in the changed australia_place_crowfly_distances.php‘s live run link.


Previous relevant Australian Postcode Place Modal Backdrop Popup Move Tutorial is shown below.

Australian Postcode Place Modal Backdrop Popup Move Tutorial

Australian Postcode Place Modal Backdrop Popup Move Tutorial

Today’s extension to yesterday’s Australian Postcode Place Modal Backdrop Popup Tutorial predominantly CSS themes is the “prove to ourselves” working of …

  • window.open based Window with that 3rd argument popup positioning used …
  • Window object method moveTo … when that Window URL is …
  • cross-domain

… and me being the optimist that I am thought though our Google Directions URL involved was cross-domain we would be able to harness the cuteness of moveTo so that it could ring around the Modal Backdrop Popup over time.

Alas, no such luck, and guess there are good (web browser) security reasons here.

Instead what we did was …

  • window.open based Window with that 3rd argument popup positioning used …
  • that [last Window object].close() then another window.open based Window with that 3rd argument popup new positioning … for that Window URL that is …
  • cross-domain

Make the scenario not be cross-domain and no worries regarding Window object method moveTo method.

And so, again, feel free to try the changed australia_place_crowfly_distances.php‘s live run link.


Previous relevant Australian Postcode Place Modal Backdrop Popup Tutorial is shown below.

Australian Postcode Place Modal Backdrop Popup Tutorial

Australian Postcode Place Modal Backdrop Popup Tutorial

Yesterday’s Australian Postcode Place Nearby Tutorial had us attending to an “Australian Postcode Nearby” subset of functionality in terms of the event …

  • onmouseover … or “on hover” which programmers out there will know, in “mobile land” is about as useful as a screen door on a submarine … so, today, we attend to some event logic everybody relates to, that being …
  • onclick

… and today, for an aesthetic change, we’re going to show our Google Charts Map Chart interfacing functionality in a Modal Backdrop Popup “window” (ie. not a window as such, but more an HTML nested div that acts like a “modal” (has to be attended to) popup).

Consequently, that Javascript nearestto function changed as per


function nearestto(ogset, gset) {
var iou=0, outset=gset, this_lat=0.0, this_long=0.0, this_diff=-1.0, smallest_diff=-1.0, largest_diff=-1.0, smallest_num=0;
var sofar=';', pa='';
var things=[];
ourarguments='?title=' + encodeURIComponent('Australian Postcode Places Nearby ' + ogset.innerHTML) + '&onclick=y&label=%5b%27Lat%27,&value=%27Lon%27,%20%27Name%27%5d&data=';
if (postcodea.length > 1) {
this_long=eval(gset.split(' ')[0].split(',')[1]);
this_lat=eval(gset.split(' ')[0].split(',')[0]);
for (iou=0; iou<postcodea.length; iou++) {
this_diff=eval(Math.abs(eval(('' + this_long)) - eval(('' + longa[iou]))) + Math.abs(eval(('' + this_lat)) - eval(('' + lata[iou]))));
if (this_diff < 20 && this_diff > 0.00001) {
sofar+='' + iou + '+' + placea[iou] + '+' + longa[iou] + '+' + lata[iou] + '-' + this_diff + ';';
things.push('' + eval(1000000.0 + eval('' + this_diff)) + ' ~' + lata[iou] + '~' + longa[iou] + '~ near to ' + placea[iou] + ',' + postcodea[iou]);
if (smallest_diff < 0.0 || eval('' + this_diff) < eval('' + smallest_diff)) {
smallest_diff=this_diff;
smallest_num=iou;
}
if (largest_diff < 0.0 || eval('' + this_diff) > eval('' + largest_diff)) {
largest_diff=this_diff;
}
} else if (this_diff < 20 && this_diff <= 0.00001) {
ourarguments+=',%20[' + lata[iou] + ',' + longa[iou] + ',~' + encodeURIComponent(placea[iou] + ',' + postcodea[iou]) + '~]';

}
}
things.sort();
outset+=' near to ' + placea[smallest_num] + ',' + postcodea[smallest_num];
ourarguments+=',%20[' + lata[smallest_num] + ',' + longa[smallest_num] + ',~' + encodeURIComponent(placea[smallest_num] + ',' + postcodea[smallest_num]) + '~]';
pa="//www.rjmprogramming.com.au/PHP/Map/map.php" + ourarguments;

for (iou=0; iou<=15; iou++) {
if (things.length > iou && outset.indexOf(things[iou].split(' near to ')[1]) == -1) {
outset+=' and near to ' + things[iou].split(' near to ')[1];
pa+=',%20[' + things[iou].split('~')[1] + ',' + things[iou].split('~')[2] + ',~' + encodeURIComponent(things[iou].split(' near to ')[1]) + '~]';
if (pa.length < 751) { ourarguments='?' + pa.split('?')[1]; }

}
}
// Modal backdrop below ...
if (ogset.innerHTML != '') {
ogset.onclick=function() {
document.getElementById('mypopup').style.display='block';
document.getElementById('mypopup-inner').style.display='block';
if (1 == 1) {
document.getElementById('myiframe').src="//www.rjmprogramming.com.au/PHP/Map/map.php" + ourarguments;
} else {
document.getElementById('mypopup-inner').innerHTML='<a title="Close" id="alertclose" class="popup-close" data-popup-close="popup-alert" onclick=" event.stopPropagation(); document.getElementById(' + "'" + 'mypopup' + "'" + ').style.display=' + "'" + 'none' + "'" + ';" href="#">&#10060;</a><br><iframe onclick=" event.stopPropagation(); " src="//www.rjmprogramming.com.au/PHP/Map/map.php' + ourarguments + '" id=myiframe style="width:500px;height:500px;"></iframe>';
}
};
}

}
return outset;
}

This type of “popup” should not startle the “popup blocker” horses on your modern web browsers!

Once again feel free to try the changed australia_place_crowfly_distances.php‘s live run link.


Previous relevant Australian Postcode Place Nearby Tutorial is shown below.

Australian Postcode Place Nearby Tutorial

Australian Postcode Place Nearby Tutorial

Back in “the where of life” web application wooooooorrrrrllllldd it’s all fine and good to know “crowfly distances” as we did in Australian Postcode Place Distances Map Chart Tutorial but that level of mathematics is not everybody’s cup of tea. Often we just want to know a …

  • nearby
  • place

… and that is all fine and good using that incredible Australian Postcode resource we talked about below.

What broad brush steps were done to arrange this information be displayed hovering over an Australian Postcode Place, in addition to ideas of that previous blog post, and its predecessors?

  • a top priority in all software integration is to first protect whatever already works, and that involved the establishment of a blank ” ” delimitation rule to the “hovering over text” … it used to be latitude,longitude and this is separated by “nearby” information by a space ” ” character delimitation … and in any existing Javascript code it is a simple matter of appending …

    .split(" ")[0]

    … onto any Javascript DOM “.title” usages (as the title attribute is what is displayed when hovering)
  • add global arrays …

    var postcodea=[];
    var placea=[];
    var lata=[];
    var longa=[];

  • at document.body onload event arrange to have …

    function fillcomparray(dataarr) {
    var fldsa, ij, jk, cdelim='', thisplace='', lm=-1, xpc='';
    for (ij=1; ij<dataarr.length; ij++) {
    if ((dataarr[ij] + ' ').substring(0,1) >= '0' && (dataarr[ij] + ' ').substring(0,1) <= '9') {
    fldsa=dataarr[ij].split(',');
    //postcodea.push(fldsa[0]);
    xpc=fldsa[0];
    cdelim='';
    thisplace='';
    lm=-1;
    for (jk=1; jk<fldsa.length; jk++) {
    if ((fldsa[jk] + ' ').substring(0,1) == '-' || ((fldsa[jk] + ' ').substring(0,1) >= '0' && (fldsa[jk] + ' ').substring(0,1) <= '9')) { if (lm < 0) { lm=jk; } }
    if (lm == -1) {
    thisplace+=cdelim + fldsa[jk];
    cdelim=',';
    }
    }
    if (fldsa[lm].match(/^[0-9-.]*$/) && fldsa[eval(1 + eval('' + lm))].match(/^[0-9-.]*$/)) {
    postcodea.push(xpc);
    placea.push(thisplace);
    longa.push(fldsa[lm]);
    lm++;
    lata.push(fldsa[lm]);
    }
    }
    }
    }

    … populate those global arrays … ready for user places of interest to trigger …
  • onblur logic that when determining a “.title” attribute, now does

    document.getElementById('setofthree_' + eval(-1 + setofthree) + '_01').title=nearestto(findit[jj].split(',')[eval(4 - indivo.innerHTML.split(',').length)] + ',' + findit[jj].split(',')[eval(3 - indivo.innerHTML.split(',').length)]);

    … and within that new Javascript function …
  • Javascript array sort() method becomes a useful intervention as per

    function nearestto(gset) {
    var iou=0, outset=gset, this_lat=0.0, this_long=0.0, this_diff=-1.0, smallest_diff=-1.0, largest_diff=-1.0, smallest_num=0;
    var sofar=';';
    var things=[];
    if (postcodea.length > 1) {
    this_long=eval(gset.split(' ')[0].split(',')[1]);
    this_lat=eval(gset.split(' ')[0].split(',')[0]);
    for (iou=0; iou<postcodea.length; iou++) {
    this_diff=eval(Math.abs(eval(('' + this_long)) - eval(('' + longa[iou]))) + Math.abs(eval(('' + this_lat)) - eval(('' + lata[iou]))));
    if (this_diff < 20 && this_diff > 0.00001) {
    sofar+='' + iou + '+' + placea[iou] + '+' + longa[iou] + '+' + lata[iou] + '-' + this_diff + ';';
    things.push('' + eval(1000000.0 + eval('' + this_diff)) + ' near to ' + placea[iou] + ',' + postcodea[iou]);
    if (smallest_diff < 0.0 || eval('' + this_diff) < eval('' + smallest_diff)) {
    smallest_diff=this_diff;
    smallest_num=iou;
    }
    if (largest_diff < 0.0 || eval('' + this_diff) > eval('' + largest_diff)) {
    largest_diff=this_diff;
    }
    }
    }
    things.sort();
    outset+=' near to ' + placea[smallest_num] + ',' + postcodea[smallest_num];
    for (iou=0; iou<=15; iou++) {
    if (things.length > iou && outset.indexOf(things[iou].split(' near to ')[1]) == -1) {
    outset+=' and near to ' + things[iou].split(' near to ')[1];
    }
    }
    }
    return outset;
    }

    … which does the job of appending 15 or so nearby Australian Postcode Places to the user entered one and displayed as the user hovers over information

Feel free to try the changed australia_place_crowfly_distances.php‘s live run link.


Previous relevant Australian Postcode Place Distances Map Chart Tutorial is shown below.

Australian Postcode Place Distances Map Chart Tutorial

Australian Postcode Place Distances Map Chart Tutorial

Yesterday’s “where of life” themed Australian Postcode Place Distances Primer Tutorial lacked something … anyone, anyone? … yes, Anaximander … a map … and you’d like to swap my horse for one … well okay, there’s one called Ed out the back … but we digress.

Queue the great Google Charts Map Chart (which can transition very easily to Geo Chart, where “from” to “to” lines are drawn) and which can be called in an HTML iframe element to add that visual interest to our changed australia_place_crowfly_distances.php‘s live run link.

There isn’t anything much better than a map to trip plan, or study geography, in our books … but alas we ran out of pamphlettes today … sorrrrrrryyyyyy.


Previous relevant Australian Postcode Place Distances Primer Tutorial is shown below.

Australian Postcode Place Distances Primer Tutorial

Australian Postcode Place Distances Primer Tutorial

It’s time to return to a “where of life” web application tutorial. Why? No, “where”. Who’s on second. But, seriously, the reason is that we found a great Australian Postcode resource for geodata lookups of these Australian placenames or postcodes … thanks.

Combine this …

  • Australian postcode (or placename) latitude and longitude … with …
  • another Australian postcode (or placename) latitude and longitude … and we can …
  • show the user a great circle distance between the two places … as well as a link to …
  • Google Maps Directions map between the two places … and there you can imagine we have a bit of a …
  • trip planner

… on our hands.

We can add our own client geographical position into the mix via …


function getLocation() {
if (navigator.geolocation) {
try {
navigator.geolocation.getCurrentPosition(showPosition);
setTimeout(later, 2000);
} catch(err) {
setTimeout(later, 2000);
}
} else {
document.getElementById('you').innerHTML='(0,0)';
if (document.getElementById('inlat') && document.getElementById('inlong')) {
document.getElementById('inlat').value=userlatitude;
document.getElementById('inlong').value=userlongitude;
}
if (document.getElementById('ipostcode')) {
document.getElementById('ipostcode').click();
newthree();
}
}
}


function showPosition(position) {
if (userlatitude == 0.0 && userlongitude == 0.0) {
userlatitude=eval('' + position.coords.latitude);
userlongitude=eval('' + position.coords.longitude);
if (document.getElementById('inlat') && document.getElementById('inlong')) {
document.getElementById('inlat').value=userlatitude;
document.getElementById('inlong').value=userlongitude;
}
if (document.getElementById('ipostcode')) {
document.getElementById('ipostcode').click();
newthree();
}
}
}

… that you can see involved in the PHP australia_place_crowfly_distances.php‘s live run link, for your perusal.

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Nimh Game URL Tutorial

Nimh Game URL Tutorial

Nimh Game URL Tutorial

Were you readers when we presented User Interactive Entry Dynamically Controlled Javascript Primer Tutorial and said …

As time goes on, more and more we see the benefits of URLs that start with “/” (but not HTTP:// nor HTTPS:// absolute URL designations), especially when it comes to pointing at a “tool” (eg. external Javascript). It has
the benefits of …

  • is programmer controlled, so they can place the tool in Document Root folder (in the case of an Apache web server) … and, in so doing …
  • it’s irrelevant where the “parent” (calling) web application is placed … and …
  • mixed content issues are avoided by not using an absolute URL, though it kind of, is!

?

Well, we applied these new ideas to our Nimh game PHP and HTML code to improve it, a few examples following …

<?php

// Used to be
$gobod3 = $drt."nimh.php".$qmk."isess=".substr($_GET['isess'],0,4)."&iam=".andsms(who_am_i(""));
$gobod = " onclick='window.location = ".'"'.$drt."nimh.php".$qmk."isess=".substr($_GET['isess'],0,4)."&iam=".andsms(who_am_i("")).'";'."'";
$gobodhome = " onclick='window.location = ".'"'.$drt."nimh.php".$qmk."isess=".substr($_GET['isess'],0,4)."&iam=".andsms(who_am_i("")).'";'."'";
// ... now becoming ...
$gobod3 = "/Games/Nimh/nimh.php".$qmk."isess=".substr($_GET['isess'],0,4)."&iam=".andsms(who_am_i(""));
$gobod = " onclick='window.location = "."'/Games/Nimh/nimh.php".$qmk."isess=".substr($_GET['isess'],0,4)."&iam=".andsms(who_am_i("")).'";'."'";
$gobodhome = " onclick='window.location = "."'/Games/Nimh/nimh.php".$qmk."isess=".substr($_GET['isess'],0,4)."&iam=".andsms(who_am_i("")).'";'."'";

?>

… and we figure (and you can try for yourself using the iframe below using src attribute /Games/Nimh as an example of application)

… or use an absolute URL link working equally well.

While we were at it we also revisited Battleships and Cruisers using /Games/Battleshipsandcruisers link.


Previous relevant User Interactive Entry Dynamically Controlled Javascript Primer Tutorial is shown below.

User Interactive Entry Dynamically Controlled Javascript Primer Tutorial

User Interactive Entry Dynamically Controlled Javascript Primer Tutorial

We’re combining the work of two different recent tutorials, today, in our efforts to code for an external Javascript tool to allow a web application, just via the calling of this external Javascript, clientside functionality whereby the user can dynamically change (effectively override) Javascript code well after the document.body onload event’s passing …

  1. yesterday’s HTML Form Use of Disabled Input Elements Tutorial‘s establishment of a methodology to override Javascript functions dynamically via user interactive entry
  2. the recent Blog Kaleidoscopic View Detail Tutorial‘s web application, as a candidate “parent” calling our “tool” via …

    <script type=text/javascript src='/fix_javascript_later.js?leftpos=60%25&toppos=30%25'></script>

… via “tool” external Javascript fix_javascript_later.js (proof of concept, first draft) code, so far, which looks like …


// fix_javascript_later.js
// RJM Programming
// June, 2023

var inithih='';
var fncodes=[], fncodenames=[''];
var fixoo=null, fixooih='', visword='hidden', vist=0, lasttvn=0;
var leftpos='calc(50% - 100px)', toppos='calc(50% - 100px)';

var lposx=(document.URL + document.head.innerHTML).split('left' + 'pos=');
var tposx=(document.URL + document.head.innerHTML).split('top' + 'pos=');

if (eval('' + lposx.length) > 1) { leftpos=decodeURIComponent(lposx[1].split('&')[0].split("'")[0].split('"')[0]); }
if (eval('' + tposx.length) > 1) { toppos=decodeURIComponent(tposx[1].split('&')[0].split("'")[0].split('"')[0]); }

function resetc() {
vist=0;
visword='hidden';
document.getElementById('dbnmt').style.visibility='visible';
document.getElementById('mypgr').value='' + vist;
}

function postscourjs(tvn) {
resetc();
lasttvn=eval('' + tvn);
if (eval('' + tvn) < 0) {
document.getElementById('djta').innerHTML='<textarea style=background-color:pink; onresize=resetc(); onchange=resetc(); onfocus=resetc(); onclick=resetc(); onblur=fix_the_js(this); id=jta>async function ' + fncodes[eval(('' + tvn).replace('-',''))].split('</script>')[0] + '</textarea>';
//alert('async function ' + fncodes[eval(('' + tvn).replace('-',''))]);
} else {
document.getElementById('djta').innerHTML='<textarea style=background-color:pink; onresize=resetc(); onchange=resetc(); onfocus=resetc(); onclick=resetc(); onblur=fix_the_js(this); id=jta>function ' + fncodes[eval(('' + tvn).replace('-',''))].split('</script>')[0] + '</textarea>';
//alert('function ' + fncodes[eval(('' + tvn).replace('-',''))]);
}
}

function scourjs() {
var ibn=0;
if (inithih == '') {
inithih=document.head.innerHTML;
fncodes=inithih.split('function ');
for (ibn=1; ibn<fncodes.length; ibn++) {
if ((fncodes[eval(-1 + ibn)].trim() + '~~').indexOf('async~~') != -1) {
fncodenames.push('async ' + fncodes[ibn].split('(')[0].trim());
} else {
fncodenames.push(fncodes[ibn].split('(')[0].trim());
}
}
if (eval('' + fncodes.length) > 1) {
fixooih='<div title="Double click to resurrect." ondblclick="putback();" id=dbnmt style="position:absolute;z-index:123;opacity:0.5;left:' + leftpos + ';top:' + toppos + ';border:5px dashed green;"><h3>Optionally change Javascript ...</h3><br><br><progress id=mypgr min=0 max=15 value=0></progress><br><br>&nbsp;&nbsp;&nbsp;<button id=bnmt onclick=bnmt(); style=background-color:orange;>No More Thanks</button><br><br><br><br><select style=background-color:yellow; onresize=resetc(); id=jcsel onchange=postscourjs(this.value);><option value="">Javascript function definitions ...</option></select><br><br><div id=djta><textarea style=background-color:pink; onresize=resetc(); onchange=resetc(); onfocus=resetc(); onclick=resetc(); onblur=fix_the_js(this); id=jta></textarea></div></div>';
for (ibn=1; ibn<fncodes.length; ibn++) {
if (fncodenames[ibn].trim() != fncodenames[ibn]) {
fixooih=fixooih.replace('</select>', '<option value="-' + ibn + '">async function ' + fncodes[ibn].split(')')[0] + ')</option></select>');
} else {
fixooih=fixooih.replace('</select>', '<option value=' + ibn + '>function ' + fncodes[ibn].split(')')[0] + ')</option></select>');
}
}
document.body.innerHTML+=fixooih;
fixooih=fixooih.replace('0.5','1.0');
setTimeout(vistog, 1000);
} else {
inithih='';
}
}
}

function putback() {
vist=0;
document.getElementById('dbnmt').innerHTML=fixooih;
document.getElementById('dbnmt').style.zIndex=123;
visword='hidden';
setTimeout(vistog, 1000);
}

function vistog() {
if (document.getElementById('mypgr')) {
setTimeout(vistog, 1000);
vist++;
document.getElementById('mypgr').value='' + vist;
if (vist >= 15) {
if (visword == 'hidden') {
visword='visible';
} else {
visword='hidden';
}
document.getElementById('dbnmt').style.visibility=visword;
vist=0;
}
}
}

function bnmt() {
document.getElementById('dbnmt').innerHTML='';
//document.getElementById('dbnmt').style.zIndex=-786;
}

function fix_the_js(ota) {
var tag = document.createElement('script');
tag.innerHTML = ota.value;
fncodes[lasttvn]=ota.value;
var firstScriptTag = document.getElementsByTagName('script')[eval(-1 + document.getElementsByTagName('script').length)];
firstScriptTag.insertAdjacentElement("afterend", tag);
}

setTimeout(scourjs, 5000);

… and you can see in action with the tweaked rjmgoogleimages.htm‘s adjusted web application.

As time goes on, more and more we see the benefits of URLs that start with “/” (but not HTTP:// nor HTTPS:// absolute URL designations), especially when it comes to pointing at a “tool” (eg. external Javascript). It has
the benefits of …

  • is programmer controlled, so they can place the tool in Document Root folder (in the case of an Apache web server) … and, in so doing …
  • it’s irrelevant where the “parent” (calling) web application is placed … and …
  • mixed content issues are avoided by not using an absolute URL, though it kind of, is!

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Games, Tutorials | Tagged , , , , , , , , , , | Leave a comment

SVG Shapes Collaboration Tidy Up Tutorial

SVG Shapes Collaboration Tidy Up Tutorial

SVG Shapes Collaboration Tidy Up Tutorial

It’s the day further to the recent SVG Shapes Iframe Srcdoc Double Quote Tutorial‘s …

Will we be leaving our SVG Show Some Shapes project with a blog posting titled, weirdly, “SVG Shapes Iframe Srcdoc Double Quote Tutorial”? Who’s to know? We’ll see what tomorrow brings?!

… worry, when we can finally say …

No worries!

But, just as with leaf blowing, we’ve just moved the issue onto another “poor sap” of a blog posting with another weird title … “SVG Shapes Collaboration Tidy Up Tutorial” … it having come to pass that this also sounds funny as a final blog posting in a series. So we’re sacking the author! Oh! It’s moi.

Let’s explain the issue with a speech bubble (and who doesn’t want to be lectured to by a speech bubble?)

What have we got at our disposal, on our Apache/PHP/MySql Linux web server, as an independent back up for deleting these temporary files? How about …

… as a great Fred and Ginger style combination, if ever we heard one?!

  • Korn Shell scripting … /etc/init.d/cron_is_working.ksh # had appended to it …
    #
    ksh -c ‘for i in `find /tmp -name “existtemporarily*.*” -mmin +122`; do rm -f “$i”; done’
    # is called every minute by …
  • crontab scheduling … via entry
    * * * * * /etc/init.d/cron_is_working.ksh

… as a sweeperer uperer of the web application moving on too fast to get to its own tidying up …


Previous relevant SVG Shapes Iframe Srcdoc Double Quote Tutorial is shown below.

SVG Shapes Iframe Srcdoc Double Quote Tutorial

SVG Shapes Iframe Srcdoc Double Quote Tutorial

It’s tempting to think, for a given scenario, you’ve written code that can satisfy you forever. How about, for a day?! Well, with the recent SVG Shapes Aesthetics Tutorial it may well have ended up “a day” before we noticed an issue. Yes, a step forwards was a step sideways, because something we’d thought was a streamlining had interfered with the audio/video media data inputs via HTML iframe srcdoc means of display.

This was caused by us being overcautious. This is what we overcompensated for. We started using Javascript code that went like (the pseudo code)


document.getElementById('myiframe').srcdoc="[a Javascript string which contains double quotes]";

… and what we “overcompensated” doing, and caused problems for every audio/video media data item was to code like (the pseudo code)


document.getElementById('myiframe').srcdoc="[a Javascript string which contains double quotes].replace(/\"/g, "\\" + '"')";

Wrong move! Even though, often, backslash escaping is the answer to data delimitation issues, it is not the case for this scenario! We’d not tested this change with enough of the “out there” functionalities we were trying to cater for.

Of course, the danger of this increases as a project moves through its phases. And that is why it is good to have a separated testing team on a sizeable project, being your project’s “honest broker”, unafraid to tell you in more polite terms than …

You stuffed it!

… that … you stuffed it. And as projects go on, if your “honest broker” is only there to report weekly, it might be hard to backtrack and wade through a week of changes to pinpoint the source of the problem. Even a day’s worth of wading made it reasonably difficult for us, but luckily we had an interim (and extra to the usual) backup of the code to help pinpoint this issue.

Supposing you leave the double quotes unattended, what happens examining the HTML iframe content? Well, you see the use of HTML entity &quot; used a lot, but no inherent problems despite this, whereas our Javascript replace did much more damage, with audios and videos effectively destroyed by what we’d attempted, above.

Which beggars the question …

Where do you see HTML entity &quot; used a lot?

Well, in a web inspector, opening up the HTML iframe of relevance to view its document.body content, you’ll see these &quot; HTML entities used a lot. See how great are your modern web browser Web Inspectors for web development? Now, it might be that the code things you rely on here do need you to cater for these &quot; in the logic, but, for us, we had either already catered for it, or we didn’t need to, especially. Either way … yayyyyyy!!! … and ahhhhhhhh!! What a relief!

Will we be leaving our SVG Show Some Shapes project with a blog posting titled, weirdly, “SVG Shapes Iframe Srcdoc Double Quote Tutorial”? Who’s to know? We’ll see what tomorrow brings?!

Try our changed tenth draft Show Some Shapes web application (you can also try below).


Previous relevant SVG Shapes Aesthetics Tutorial is shown below.

SVG Shapes Aesthetics Tutorial

SVG Shapes Aesthetics Tutorial

In a sizeable online web application project, it can be that you “put off” annoyances to follow through on “the main game”, so to speak. But, don’t forget to come back to at least try to fix the annoyances!

And so it was with our SVG Shapes project ever since we allowed “shadowing” into the mix, because “shadowing” involved faux SVG element content to the right and bottom not agreeing with the SVG element dimensions defined. Annoying? Yes … very, but still just, “annoying”. We wanted to get the “main game” bedded down first.

Also, into the mix, is our trepidation meddling with a “dimensions issue” that involves units that are not “%” nor “vh” nor “vx”. You’ll probably have read a zillion responsive design webpage advice segments telling you to stick with “%” … if only “%” was a dance?! It’s true, though, that if you want happiness across the board, and even to get noticed at all on the search engines, you stand more of a chance designing web content that never mentions a “hard and fast” dimension. Of course, no programmer that’s done anything “involved” can stick to that rule, but those people can use Javascript DOM and its [element].getBoundingClientRect() methodology (or some other approach) to help here, sometimes. However, with SVG work, we find, at least, that you have many “hard and fast” dimensioning situations cropping up.

And so, regarding SVG, with this aesthetics only issue, up to today, swimming away in the background of our thinking regarding this annoyance, was that we had not resorted to much “viewBox” attribute

The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.

The value of the viewBox attribute is a list of four numbers: min-x, min-y, width and height. The numbers min-x and min-y represent the top left coordinates of the viewport. The numbers width and height represent its dimensions. These numbers, which are separated by whitespace and/or a comma, specify a rectangle in user space which is mapped to the bounds of the viewport established for the associated SVG element (not the browser viewport).

… thinking. All this being the case, today, we tried out the idea that the SVG element itself should not be touched in any way shape (tee hee) or form (chortle, chortle) regarding its co-ordinates or dimensions, but that every SVG element defined in our WordPress TwentyTen theme’s 404.php code for this project should have defined a new or updated “viewBox” attribute (like the exemplified one, below, for an SVG circle) …

<?php

header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"ht
tp://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '"
viewBox="0 0 ' . floor($newWidth / 0.90) . ' ' . floor($newHeight / 0.90) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . $deffilter . '
<circle' . $usefilter . ' cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" r="' . (($newWidth + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" >' . $animationaroundperhaps . '</circle>
' . $plusline . '</svg>';
exit;


?>

And we’re happy to say … it helped! Yayyyyyy!! Even with “overlay” scenarios, we think, and are happy about, because we applied this fix throughout the 404.php code consistently, we figure.

And there’s nothing quite like fixing a “nagging at you” aesthetics annoyance, which you’ve been putting off! Oddly, this change to the recent SVG Shapes Collaboration Tutorial work needed no parent HTML/Javascript/CSS clientside Show Some Shapes web application fixing?! Double yayyyyyy!


Previous relevant SVG Shapes Collaboration Tutorial is shown below.

SVG Shapes Collaboration Tutorial

SVG Shapes Collaboration Tutorial

We are all not islands! Though Tahiti sounds nice! Be that as it may, with our Show Some Shapes web application, further to yesterday’s SVG Media Shapes Tutorial we’ve reached the … anyone, anyone? Yes, Aoife

We’re “missing UYou too” … but don’t you think that’s a bit beside the point. And besides, weren’t you supposed to be cleaning windows this afternoon?

Okay Brian … yes, you can be an island, if you like. But, can we get back to brass tacks … over there next to the “point”?

What’s the “C” word that goes with “Sharing” (yes, thanks Ivan “and caring””)? Yes, that’s all well and good, but can we get back to the “C” word. “Co” … “Col” … “Coll” … (no, Colleen … not “Collyflower”) … give up … how about …

Collaborate

? Yes, people share and collaborate. But, in order to collaborate …

  • somebody has to initiate … and hopefully …
  • a collaborator reads and/or listens … then, often optionally …
  • returns a measured response … and so on and so forth etcetera etcetera etcetera

Class??!! …………………. class?! …… dismissed

In the online world, good “initiators”, we find, are either …

  • email … and/or …
  • SMS …

… respectively catered for, in HTML, via “a” links featuring an href attribute starting with “mailto:” or “sms:” …


document.write("<a style=display:none; id=asms href='sms:&body=" + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + '?via=') + "'></a><a style=display:none; id=aemail href='mailto:?subject=Show%20Some%20Shapes" + encodeURIComponent(' (link validity expires in 10 minutes from now)') + "&body=" + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + '?via=') + "'></a><iframe frameborder=0 name=ifstyle id=ifstyle src='//www.rjmprogramming.com.au/PHP/fgc/index.php" + via + "' style=display:none;></iframe>");

… respectively. Later, we append to those href attribute URLs an encodeURIComponent version of a uniquifier (for an initiator) …


var alltemp='';

function alltempf() {
if (imageoverlay && iframeoverlay) {
alltemp=('<html><head></head><body oncontextmenu="parent.pnosharenow();" onclick="window.open(' + "'" + document.URL.split('#')[0].split('?')[0] + "','_blank','top=200,left=200,width=800,height=800'" + ');" title="Click to make your own Shapes in new window or right click for finished here and make your own Shapes below">' + simage + siframe + document.getElementById('doverlay').outerHTML + '</body></html>');
} else if (imageoverlay) {
alltemp=('<html><head></head><body oncontextmenu="parent.pnosharenow();" onclick="window.open(' + "'" + document.URL.split('#')[0].split('?')[0] + "','_blank','top=200,left=200,width=800,height=800'" + ');" title="Click to make your own Shapes in new window or right click for finished here and make your own Shapes below">' + simage + document.getElementById('doverlay').outerHTML + '</body></html>');
} else if (iframeoverlay) {
alltemp=('<html><head></head><body oncontextmenu="parent.pnosharenow();" onclick="window.open(' + "'" + document.URL.split('#')[0].split('?')[0] + "','_blank','top=200,left=200,width=800,height=800'" + ');" title="Click to make your own Shapes in new window or right click for finished here and make your own Shapes below">' + siframe + document.getElementById('doverlay').outerHTML + '</body></html>');
} else {
alltemp=('<html><head>' + document.head.innerHTML + '</head>' + document.body.outerHTML.replace('<body', '<body' + ' oncontextmenu="parent.pnosharenow();" onclick="window.open(' + "'" + document.URL.split('#')[0].split('?')[0] + "','_blank','top=200,left=200,width=800,height=800'" + ');" title="Click to make your own Shapes"') + '</html>');
}
document.getElementById('alltemporarily').value=alltemp;
}

function smsit() {
var smsno=prompt('Please enter SMS number.', '');
if (smsno != null) {
document.getElementById('existtemporarily').value='';
alltempf();
document.getElementById('mysubbut').click();
if (document.getElementById('asms').href.indexOf(encodeURIComponent(window.btoa(document.getElementById('storevia').value))) == -1) {
document.getElementById('asms').href=document.getElementById('asms').href + encodeURIComponent(window.btoa(document.getElementById('storevia').value));
}
document.getElementById('asms').href='sms:' + smsno + '&' + document.getElementById('asms').href.split('&')[1];
document.getElementById('asms').click();
}
}

function emailit() {
var emailaddr=prompt('Please enter Email address.', '');
if (emailaddr != null) {
document.getElementById('existtemporarily').value='';
alltempf();
document.getElementById('mysubbut').click();
if (document.getElementById('aemail').href.indexOf(encodeURIComponent(window.btoa(document.getElementById('storevia').value))) == -1) {
document.getElementById('aemail').href=document.getElementById('aemail').href + encodeURIComponent(window.btoa(document.getElementById('storevia').value));
}
document.getElementById('aemail').href='mailto:' + emailaddr + '?' + document.getElementById('aemail').href.split('?')[1];
document.getElementById('aemail').click();
}
}

… a method=POST form navigation taking care of storing the relevant snapshot of the data involved, ready to be recalled should a Collaborator click an email or SMS link they were sent.

There are limits, as there are with address bar URLs, as to how long these href attributes can be, to succeed. Ones in the thousands are just not likely to work. So, how do the media data URIs produced fit in? Well, maybe not at all, because even they represent data too long for uploading limits, but we are going to offer the service of trying, and we work to keep all that data storage arrangements, more or less, to ourselves, and offer a 10 minute surviving email or SMS link, to work towards amalgamating data URIs and SVG svg+xml protocol “shape data” to present to a Collaborator in an email or SMS initiated by you, a user of our changed ninth draft Show Some Shapes web application (you can also try below).


Previous relevant SVG Media Shapes Tutorial is shown below.

SVG Media Shapes Tutorial

SVG Media Shapes Tutorial

To have a web application such as the Show Some Shapes one of yesterday’s SVG Image Shapes Tutorial be able to claim that it accepts all “media” inputs, it should, at least, accept, in some way shape (chortle, chortle), or form (tee hee)

  • image … data input, even as yesterday’s did … but also, as today’s attends to …
  • video … and …
  • audio

… data inputs. At first, in doing these last two media categories, we’d work it, using …

… in achieving this new functionality. The pivotal HTML form (plug and play) onsubmit event logic newly added …


function maybepost() {
if (document.getElementById('existtemporarily').value.indexOf('image/') != -1) { return true; }
if (lastfocus.indexOf('iframe') != -1 || lastfocus.indexOf('image') != -1) {
imagestring='data:';
equalsr=encodeURIComponent(imagestring);
equalsrif=encodeURIComponent(imagestring);
if (document.getElementById('existtemporarily').value.indexOf('audio/') != -1) {
document.getElementById('myiframe' + iframeprevs).src=thenifagain(document.getElementById('myiframe' + iframeprevs).src.replace(lastiframesuffix.toUpperCase(), 'image').replace(lastiframesuffix, 'image')).split('=')[0] + '=' + maybenoifshadows(encodeURIComponent(imagestring)); //equalsrif;
document.getElementById('myiframe' + iframeprevs).srcdoc='<html><body style="opacity:0.2;width:' + ififw + 'px;height:' + ififh + 'px;"><audio controls="true" loop="true" muted="true" crossorigin="anonymous"><source' + typeeq + ' src="' + document.getElementById('existtemporarily').value.split('#audio')[0] + '"></source></audio></body></html>';
document.getElementById('thiframeopt').innerText='Iframe ... showing audio above';
document.getElementById('seliframeoverlay').value='overlay';
} else if (document.getElementById('existtemporarily').value.indexOf('video/') != -1) {
document.getElementById('myiframe' + iframeprevs).src=thenifagain(document.getElementById('myiframe' + iframeprevs).src.replace(lastiframesuffix.toUpperCase(), 'image').replace(lastiframesuffix, 'image')).split('=')[0] + '=' + maybenoifshadows(encodeURIComponent(imagestring)); //equalsrif;
document.getElementById('myiframe' + iframeprevs).srcdoc='<html><body style="opacity:0.8;width:' + ififw + 'px;height:' + ififh + 'px;"><video controls="true" height="90%" width="90%" autoplay="true" loop="true" muted="true" crossorigin="anonymous"><source' + typeeq + ' src="' + document.getElementById('existtemporarily').value.split('#video')[0] + '"></source></video></body></html>';
document.getElementById('thiframeopt').innerText='Iframe ... showing video above';
document.getElementById('seliframeoverlay').value='overlay';
}
imagestring='';
lastiframesuffix='image';
document.getElementById('thiframesel').value='';
}
document.body.style.cursor='pointer';
return false;
}

… refers to an overriding srcdoc attribute filled out and populated, and which overrides any other src attribute linked to the relevant HTML iframe element. We thought including audio media input as an option, could open the door to, eventually, share an SVG based annotated presentation which includes an (optionally used) audio commentary.


Previous relevant SVG Image Shapes Tutorial is shown below.

SVG Image Shapes Tutorial

SVG Image Shapes Tutorial

Am sure some of you have been waiting for it?! Here it is …

What (some of) you’ve been waiting for?

Yes, images are the input to our shapes web application as today’s work. And yes, SVG has an image element type.

And so, on top of yesterday’s SVG Shapes Animations Tutorial, today, we offer either …

  • image URL … or …
  • browsed for image

… in amongst the “iframe modus operandi” choices, as a new functionality option.

Once the image, as SVG, is in place, you may then be tempted to overlay other SVG or line or text annotations on top, for your creation.

The WordPress PHP 404.php needed to cater for this …

<?php

$rvalis=str_replace('+',' ',urldecode(explode('&',explode('=', $_SERVER['QUERY_STRING'])[1])[0]));
$semicrvals=explode(';', $rvalis);
if (strpos($_SERVER['QUERY_STRING'], '=+data') !== false || strpos($_SERVER['QUERY_STRING'], '=%20data') !== false) {
if (file_exists(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt')) {
while (filesize(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt') == 0) {
sleep(3);
}
sleep(3);
$rvalis=' ' . file_get_contents(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt');
unlink(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt');
} else {
exit;
}
} else if (strpos($_SERVER['QUERY_STRING'], '=data') !== false || strpos($_SERVER['QUERY_STRING'], '=data') !== false) {
if (file_exists(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt')) {
while (filesize(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt') == 0) {
sleep(3);
}
sleep(3);
$rvalis='' . file_get_contents(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt');
unlink(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'existtemporarily' . fgcserver_remote_addr() . '.txt');
} else {
exit;
}
}
//
// ahead of
//
if (strpos(strtolower($_SERVER['QUERY_STRING']), 'image=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(ourexplode('image=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$plusline=str_replace('fillc', $fillc, str_replace('strokec', $strokec, $plusline));
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
if (substr(trim(($rvalis . '0')),0,1) >= '0' && substr(trim(($rvalis . '0')),0,1) <= '9') {
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . $deffilter . '
<rect' . $usefilter . ' x="0" y="0" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="none" >' . $animationaroundperhaps . '</rect>
' . $plusline . '</svg>';
} else {
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . $deffilter . '
<image' . $usefilter . ' x="0" y="0" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" href="' . str_replace(' ','+',trim($rvalis)) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" >' . $animationaroundperhaps . '</image>
' . $plusline . '</svg>';
}
exit;
}

?>

… in the changed seventh draft Show Some Shapes web application (you can also try below).


Previous relevant SVG Shapes Drop Shadow Filter Tutorial is shown below.

SVG Shapes Drop Shadow Filter Tutorial

SVG Shapes Drop Shadow Filter Tutorial

With the overall …

  • overlay … and …
  • annotation

… feel to the blog posting thread recent posts regarding our “Show Some Shapes” latest web application with yesterday’s SVG Shapes Text Annotation Tutorial we became keen to follow up …

  • 3D data arrangement talk … with …
  • 3D SVG display feel

As you might expect, there are a variety of ways to approach this using SVG filters, and we’d like to thank W3School’s SVG Drop Shadow filter advice for what we decided to adopt, here, at least for now, to make the SVG shapes pop out of the webpage in a 3D way, using shadowing.

It’s a generic change, and was only a change affecting 404.php work whereby we defined two new variables, as per …

<?php

$deffilter=' <defs>
<filter id="f1" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
';
$usefilter=' filter="url(#f1)" ';

?>

… applied like as in the exemplified case of an SVG circle below …

<?php

echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . $deffilter . '
<circle' . $usefilter . ' cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" r="' . (($newWidth + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
' . $plusline . '</svg>';

?>

… in the Show Some Shapes web application you can also try below.


Previous relevant SVG Shapes Text Annotation Tutorial is shown below.

SVG Shapes Text Annotation Tutorial

SVG Shapes Text Annotation Tutorial

Yesterday’s SVG Shapes Line Annotation Tutorial was a fantastic lead in for today’s Text Annotation ideas with our “Show Some Shapes” web application, of recent times.

The reason is, partly, we reckon, because if you lead off your development with the harder option, that …

  • Line Annotation is, with its x1,y1,x2,y2 sets of data needed … has more work behind it than …
  • Text Annotation has, a lot of the time, with its application quite often sufficing with x1,y1 only (and assuming a horizontal alignment), whereas if the x1,y1,x2,y2 is defined, in the code, we can still use a …

    <text x="167" y="167" transform="rotate(90,167,167)" stroke-width="2" stroke="black" fill="rgb(0,0,255)">diameter</text>
    <line x1="167" y1="0" x2="167" y2="334" stroke-width="2" stroke="black" fill="rgb(0,0,255)"><title>diameter</title></line>

… example of ### (as explained later) style of SVG text arrangement where …

  1. text positional x and y are halfway along the “line” SVG element they are describing (which in the x1,y1 only case, is coded to end up being x1,y1) … and …
  2. SVG text has a great transform attribute rotate three argument call going like …

    The rotate(<a> [<x> <y>]) transform function specifies a rotation by a degrees about a given point. If optional parameters x and y are not supplied, the rotation is about the origin of the current user coordinate system. If optional parameters x and y are supplied, the rotation is about the point (x, y).

    … we make use of angling our SVG text appropriately

… then this is the better way around to approach the project. For the user, this “text annotation” interest can now be flagged via a …

  • ## delimitation (of textbox entries) creates SVG text only (with no SVG line) annotation creation … while …
  • ### delimitation (of textbox entries) creates SVG text and SVG line annotation (with a SVG title hover component) creation … augmenting the existant …
  • # delimitation (of textbox entries) creates SVG line annotation only (with a SVG title hover component) creation

… as far as text annotations now go in the only mildly changed fourth draft Show Some Shapes web application (you can also try below).

More work, though, was asked of 404.php, as per …

<?php

$plusline='';
$annoword='title';

if (strpos($_SERVER['QUERY_STRING'], '=') !== false) {
$rvalis=str_replace('+',' ',urldecode(explode('&',explode('=', $_SERVER['QUERY_STRING'])[1])[0]));
$semicrvals=explode(';', $rvalis);
for ($ijk=0; $ijk$annoword='title';
$theangle=-999.0;
if (sizeof($crvals) == 2 && strpos($semicrvals[$ijk], '##') !== false) {
array_push($crvals, $crvals[0]);
array_push($crvals, $crvals[1]);
$theangle=0.0;
} else if (sizeof($crvals) == 4) {
if (explode('#',$crvals[0])[0] == explode('#',$crvals[2])[0] && explode('#',$crvals[1])[0] == explode('#',$crvals[3])[0]) {
$theangle=0.0;
}
}

if (sizeof($crvals) >= 4) {
for ($hj=0; $hj<4; $hj++) { $comsb=explode('#', $crvals[$hj]); if (sizeof($comsb) > 1) {
if (sizeof($comsb) > 2 && $comsb[1] == '') {
$annoword='text';
if ($theangle < -361.0) { $radvalalt=atan2((explode('#',$crvals[3])[0] - explode('#',$crvals[1])[0]),(explode('#',$crvals[2])[0] - explode('#',$crvals[0])[0])); $radval=atan2((explode('#',$crvals[2])[0] - explode('#',$crvals[0])[0]),(explode('#',$crvals[3])[0] - explode('#',$crvals[1])[0])); $theangle=fmod((450 - rad2deg($radval) + 360),360); if ($theangle > 180.0) { $theangle-=360.0; }
}
$plusline.='<' . $annoword . ' x="' . ((explode('#',$crvals[0])[0] + explode('#',$crvals[2])[0]) / 2) . '" y="' . ((explode('#',$crvals[1])[0] + explode('#',$crvals[3])[0]) / 2) . '" transform="rotate(' . $theangle . ',' . ((explode('#',$crvals[0])[0] + explode('#',$crvals[2])[0]) / 2) . ',' . ((explode('#',$crvals[1])[0] + explode('#',$crvals[3])[0]) / 2) . ')" stroke-width="2" stroke="strokec" fill="fillc">' . $comsb[-1 + sizeof($comsb)] . '';
$theangle=-999.0;
if (sizeof($comsb) > 3) {
$annoword='title';
$combit='<' . $annoword . '>' . $comsb[-1 + sizeof($comsb)] . '';
}
} else {

$combit='<' . $annoword . '>' . $comsb[1] . '' . $annoword . '>';
}
}
}
if ($annoword == 'title') {
$plusline.='' . $combit . '';
}
if (sizeof($crvals) >= 6) {
for ($ibv=6; $ibv<=sizeof($crvals); $ibv+=2) { $combit=''; $annoword='title'; for ($hj=-4; $hj<=-1; $hj++) { $comsb=explode('#', $crvals[$hj + $ibv]); if (sizeof($comsb) > 1) {
if (sizeof($comsb) > 2 && $comsb[1] == '') {
$annoword='text';
if ($theangle < -361.0) { $radvalalt=atan2((explode('#',$crvals[-1 + $ibv])[0] - explode('#',$crvals[-3 + $ibv])[0]),(explode('#',$crvals[-2 + $ibv])[0] - explode('#',$crvals[-4 + $ibv])[0])); $radval=atan2((explode('#',$crvals[-2 + $ibv])[0] - explode('#',$crvals[-4 + $ibv])[0]),(explode('#',$crvals[-1 + $ibv])[0] - explode('#',$crvals[-3 + $ibv])[0])); $theangle=fmod((450 - rad2deg($radval) + 360),360); if ($theangle > 180.0) { $theangle-=360.0; }
}
$plusline.='<' . $annoword . ' x="' . ((explode('#',$crvals[-4 + $ibv])[0] + explode('#',$crvals[-2 + $ibv])[0]) / 2) . '" y="' . ((explode('#',$crvals[-3 + $ibv])[0] + explode('#',$crvals[-1 + $ibv])[0]) / 2) . '" transform="rotate(' . $theangle . ',' . ((explode('#',$crvals[-4 + $ibv])[0] + explode('#',$crvals[-2 + $ibv])[0]) / 2) . ',' . ((explode('#',$crvals[-3 + $ibv])[0] + explode('#',$crvals[-1 + $ibv])[0]) / 2) . ')" stroke-width="2" stroke="strokec" fill="fillc">' . $comsb[-1 + sizeof($comsb)] . '';
$theangle=-999.0;
if (sizeof($comsb) > 3) {
$annoword='title';
$combit='<' . $annoword . '>' . $comsb[-1 + sizeof($comsb)] . '';
}
} else {

$combit='<' . $annoword . '>' . $comsb[1] . '' . $annoword . '>';
}
}
}
if ($annoword == 'title') {
$plusline.='' . $combit . '';
}
}
}
} // else if (sizeof($crvals) == 3) { if (strpos(substr($crvals[2] . ' ',1),'-') !== false) { $rvalis=$rvalis; } }
}
}

?>

You want to try those same practical examples as yesterday, but with text annotation, as well? Type …

167###radius,167,334,167;167###diameter,0,167,334;167###chord,334,334,167;1###tangent,0,1,334;20###secant,0,20,334

… into the iframe fill textbox … or try the equivalent resultant URL …

https://www.rjmprogramming.com.au/ITblog/334/334/?svg0000ff+circle=167%23%23%23radius%2C167%2C334%2C167%3B167%23%23%23diameter%2C0%2C167%2C334%3B
167%23%23%23chord%2C334%2C334%2C167%3B1%23%23%23tangent%2C0%2C1%2C334%3B20%23%23%23secant%2C0%2C20%2C334

… or view it below …


Previous relevant SVG Shapes Line Annotation Tutorial is shown below.

SVG Shapes Line Annotation Tutorial

SVG Shapes Line Annotation Tutorial

Our “Show Some Shapes” web application of SVG Shapes Overlay Tutorial was well set up for …

  • linear annotation … especially considering …
  • lines use the stroke colour the user defines and the other shape types mainly show the fill colour

… and so, generally speaking, line features can “overlay” other shapes, like annotation helps clarify a diagram or document.

In order to allow for this we’re now accepting these styles of entry (via any textbox presented to the user) …

  • comma (and/or semicolon ; pen up) separated x1,y1,x2,y2 co-ordinate set(s)
  • comma (and/or semicolon ; pen up) separated x1,y1,bearing-distance set(s)
  • justification code from to justification code to ( eg. the default tltobr )… where …
    1. tl … top left
    2. tc … top centre
    3. tr … top right
    4. cl … centre left
    5. cc … centre centre
    6. cr … centre right
    7. bl … bottom left
    8. bc … bottom centre
    9. br … bottom right

    … relative to the SVG window width x height dimensions, comma (and/or semicolon ; pen up) separated

… allowing “hover” titles via # (hashtag) delimited comments (hopefully missing commas and semicolons) helped out by a new Javascript function …


function equalsrcheck(ioo) {
var thisval=ioo.value;
var justs=['tl','tc','tm','tr','bl','bc','bm','br','cl','cc','cm','cr','ml','mc','mm','mr'];
var jusxw=[0.00,0.50,0.50,1.00,0.00,0.50,0.50,1.00,0.00,0.50,0.50,1.00,0.00,0.50,0.50,1.00];
var jusyh=[0.00,0.00,0.00,0.00,1.00,1.00,1.00,1.00,0.50,0.50,0.50,0.50,0.50,0.50,0.50,0.50];
var xfofarc='', iix, xtoflds=[], jjx;
//if (thisval.trim() == '' || thisval.indexOf(',') == -1) { equalsr='y'; }
if (thisval.indexOf(',') != -1) {
var cflds=thisval.split(',');
for (var inm=0; inm<cflds.length; inm++) {
if (cflds[inm].split('#')[0].toLowerCase().indexOf('to') == 2 && eval('' + cflds[inm].split('#')[0].length) == 6) {
xfofarc='';
xtoflds=cflds[inm].split('#')[0].toLowerCase().split('to');
for (iix=0; iix<justs.length; iix++) {
if (xtoflds[0] == justs[iix] || xtoflds[0] == (justs[iix].substring(1) + justs[iix].substring(0,1))) {
if (ioo.id.indexOf('mage') != -1) {
xfofarc='' + eval(jusxw[iix] * imifw) + ',' + eval(jusyh[iix] * imifh) + ',';
} else if (ioo.id.indexOf('frame') != -1) {
xfofarc='' + eval(jusxw[iix] * ififw) + ',' + eval(jusyh[iix] * ififh) + ',';
}
}
}
if (xfofarc != '') {
for (jjx=0; jjx<justs.length; jjx++) {
if (xtoflds[1] == justs[jjx] || xtoflds[1] == (justs[iix].substring(1) + justs[iix].substring(0,1))) {
if (ioo.id.indexOf('mage') != -1) {
xfofarc+='' + eval(jusxw[jjx] * imifw) + ',' + eval(jusyh[jjx] * imifh) + '';
} else if (ioo.id.indexOf('frame') != -1) {
xfofarc+='' + eval(jusxw[jjx] * ififw) + ',' + eval(jusyh[jjx] * ififh) + '';
}
}
}
}
if (eval('' + xfofarc.split(',').length) == 4) {
thisval=thisval.replace(cflds[inm].split('#')[0], xfofarc);
}
}
cflds=thisval.split(',');
}
if (eval('' + cflds.length) >= 3) {
if (eval('' + cflds.length) >= 4 && (cflds[2] + ' ').substring(1).indexOf('-') == -1) {
equalsr=encodeURIComponent(thisval);
if (ioo.id.replace('cp','sel').indexOf('sel') != -1) { ioo.value=''; }
thisval='';
} else if ((cflds[2] + ' ').substring(1).indexOf('-') > 0) {
var pcx=eval('' + cflds[0].split('#')[0]);
var pcy=eval('' + cflds[1].split('#')[0]);
var radialssofar='', fdel='';
for (var jj=2; jj<cflds.length; jj++) {
if ((cflds[jj] + ' ').substring(1).indexOf('-') > 0) {
pcx=eval(pcx + Math.sin(Math.PI * eval('' + cflds[jj].split('#')[0].split('-')[0]) / 180.0) * eval('' + cflds[jj].split('#')[0].split('-')[1]));
pcy=eval(pcy + Math.cos(Math.PI * eval('' + cflds[jj].split('#')[0].split('-')[0]) / 180.0) * eval('' + cflds[jj].split('#')[0].split('-')[1]));
radialssofar+=fdel + cflds[0] + ',' + cflds[1] + ',' + pcx + ',' + pcy;
pcx=eval('' + cflds[0].split('#')[0]);
pcy=eval('' + cflds[1].split('#')[0]);
fdel=';';
} else {
radialssofar+=',' + cflds[jj].split('#')[0];
}
}
equalsr=encodeURIComponent(radialssofar);
if (ioo.id.replace('cp','sel').indexOf('sel') != -1) { ioo.value=''; }
thisval='';
} else {
equalsr='y';
thisval='' + cflds[0].split('#')[0];
}
}
} else if (thisval.split('#')[0].toLowerCase().indexOf('to') == 2 && eval('' + thisval.split('#')[0].length) == 6) {
var toflds=thisval.toLowerCase().split('to');
var combit='';
if (thisval.indexOf('#') != -1) { combit='#' + thisval.split('#')[1].split(',')[0].split(';')[0]; }
var fofarc='';
for (var ii=0; ii<justs.length; ii++) {
if (toflds[0].split('#')[0] == justs[ii] || toflds[0].split('#')[0] == (justs[ii].substring(1) + justs[ii].substring(0,1))) {
if (ioo.id.indexOf('mage') != -1) {
fofarc='' + eval(jusxw[ii] * imifw) + ',' + eval(jusyh[ii] * imifh) + ',';
} else if (ioo.id.indexOf('frame') != -1) {
fofarc='' + eval(jusxw[ii] * ififw) + ',' + eval(jusyh[ii] * ififh) + ',';
}
}
}
if (fofarc != '') {
for (var jj=0; jj<justs.length; jj++) {
if (toflds[1].split('#')[0] == justs[jj] || toflds[1].split('#')[0] == (justs[jj].substring(1) + justs[jj].substring(0,1))) {
if (ioo.id.indexOf('mage') != -1) {
fofarc+='' + eval(jusxw[jj] * imifw) + ',' + eval(jusyh[jj] * imifh) + '';
} else if (ioo.id.indexOf('frame') != -1) {
fofarc+='' + eval(jusxw[jj] * ififw) + ',' + eval(jusyh[jj] * ififh) + '';
}
}
}
}
if (eval('' + fofarc.split(',').length) == 4) {
equalsr=encodeURIComponent(fofarc + combit);
if (ioo.id.replace('cp','sel').indexOf('sel') != -1) { ioo.value=''; }
thisval='';
}
}
return thisval;
}

… in our changed third draft Show Some Shapes web application (you can also try below).

And yes, 404.php had to accomodate these new $_GET argument value expansions (previously only the pretty dumb y as a value always), via $plusline linear annotation append PHP as per …

<?php

$plusline='';

if (strpos($_SERVER['QUERY_STRING'], '=') !== false) {
$rvalis=str_replace('+',' ',urldecode(explode('&',explode('=', $_SERVER['QUERY_STRING'])[1])[0]));
$semicrvals=explode(';', $rvalis);
for ($ijk=0; $ijk<sizeof($semicrvals); $ijk++) {
$crvals=explode(',', $semicrvals[$ijk]);
$combit='';
if (sizeof($crvals) >= 4) {
for ($hj=0; $hj<4; $hj++) {
$comsb=explode('#', $crvals[$hj]);
if (sizeof($comsb) > 1) {
$combit='<title>' . $comsb[1] . '</title>';
}
}
$plusline.='<line x1="' . explode('#',$crvals[0])[0] . '" y1="' . explode('#',$crvals[1])[0] . '" x2="' . explode('#',$crvals[2])[0] . '" y2="' . explode('#',$crvals[3])[0] . '" stroke-width="2" stroke="strokec" fill="fillc">' . $combit . '</line>';
if (sizeof($crvals) >= 6) {
for ($ibv=6; $ibv<=sizeof($crvals); $ibv+=2) {
$combit='';
for ($hj=-4; $hj<=-1; $hj++) {
$comsb=explode('#', $crvals[$hj + $ibv]);
if (sizeof($comsb) > 1) {
$combit='<title>' . $comsb[1] . '</title>';
}
}
$plusline.='<line x1="' . explode('#',$crvals[-4 + $ibv])[0]. '" y1="' . explode('#',$crvals[-3 + $ibv])[0] . '" x2="' . explode('#',$crvals[-2 + $ibv])[0] . '" y2="' . explode('#',$crvals[-1 + $ibv])[0] . '" stroke-width="2" stroke="strokec" fill="fillc">' . $combit . '</line>';
}
}
} // else if (sizeof($crvals) == 3) { if (strpos(substr($crvals[2] . ' ',1),'-') !== false) { $rvalis=$rvalis; } }
}
}

?>

You want to try some practical examples of use? Type …

167#radius,167,334,167;167#diameter,0,167,334;167#chord,334,334,167;1#tangent,0,1,334;20#secant,0,20,334

… into the iframe fill textbox … or try the equivalent resultant URL …

https://www.rjmprogramming.com.au/ITblog/334/334/?svg0000ff+circle=167%23radius%2C167%2C334%2C167%3B167%23diameter%2C0%2C167%2C334%3B167%23chord%2C334%2C334%2C
167%3B1%23tangent%2C0%2C1%2C334%3B20%23secant%2C0%2C20%2C334

… or view it below …


Previous relevant SVG Shapes Overlay Tutorial is shown below.

SVG Shapes Overlay Tutorial

SVG Shapes Overlay Tutorial

The dimensions discussed in yesterday’s SVG Shapes Dimensions and Colour Tutorial were the “what we normally talk about as 2D” dimensions …

  1. width … which you could think of as X … and …
  2. height … which you could think of as Y … and, today, we want to add into the mix …
  3. “overlay” … or depth … … which you could think of as Z … or elevation … the three of which we all know of as … anyone, anyone? Yes, Fayette, we see you, again, but not in degrees … but … in … anyone, anyone? Yes, Kate, something’s coming to you? Yes … yes … three thingos … thingos being … maybe … yes … 3 dimensions!

This opens up the variety of “shapes” you can come up with considerably, even without involving any opacity, and so far we have not coded for CSS z-index usage (just good ol’ position:absolute usage so far). Should you stumble upon a useful “overlay creation” a right click can open it up in a new web browser tab, should you prefer that arrangement.

To achieve this change asked nothing more of our 404.php code, but rather asked of the client web application the turning of the “Height” hardcoding into a new select (dropdown) like …


<select onchange=fixv(this); id=selimageoverlay><option value="">Height</option><option value="overlay">Height ... Overlayed</option></select>
<div id="doverlay"></div>

… and accompanying new Javascript global variables and “onchange event logic” …


var imageoverlay=false, iframeoverlay=false;
var imageprevs='', iframeprevs='';
var imagelasts='', iframelasts='';
var imageurlpush=[], iframeurlpush=[];
var imagerect=[], iframerect=[];
var snapshotoh='';
var bigwo=[];

… with new Javascript “onchange event logic” code like …


function fixv(oselinvo) {
var theval=oselinvo.value;
switch('' + oselinvo.id) {
case 'selimageoverlay': // overlay flag
if (theval.trim() == '') {
imageoverlay=false;
//imageurlpush=[];
//imagerect=[];
} else {
if (eval('' + imageurlpush.length) == 0) {
snapshotoh='<html><head>' + document.head.innerHTML + '</head>' + document.body.outerHTML + '</html>';
}
imageoverlay=true;
imageurlpush.push(document.getElementById('myimage' + imagelasts).src);
imagerect=[];
imagerect.push(document.getElementById('myimage' + imagelasts).getBoundingClientRect());
imagelasts='' + imageurlpush.length;
}
break;


case 'seliframeoverlay': // overlay flag
if (theval.trim() == '') {
iframeoverlay=false;
//iframeurlpush=[];
//iframerect=[];
} else {
if (eval('' + iframeurlpush.length) == 0) {
snapshotoh='<html><head>' + document.head.innerHTML + '</head>' + document.body.outerHTML + '</html>';
}
iframeoverlay=true;
iframeurlpush.push(document.getElementById('myiframe' + iframelasts).src);
iframerect=[];
iframerect.push(document.getElementById('myiframe' + iframelasts).getBoundingClientRect());
iframelasts='' + iframeurlpush.length;
}
break;
//
// more cases would follow
//
default:
break;
}
}

… setting up the “oncontextmenu” (ie. right click) event logic …


function windowopen(purl, pway) {
bigwo.push(window.open('','_blank'));
if (imageoverlay && iframeoverlay) {
bigwo[eval(-1 + bigwo.length)].document.write(snapshotoh.replace(' id="my' + 'iframe" style="',' id="my' + 'iframe" style="visibility:hidden;').replace(' id="my' + 'image" style="',' id="my' + 'image" style="visibility:hidden;').replace(' id="do' + 'verlay">', ' id="do' + 'verlay">' + document.getElementById('doverlay').innerHTML));
} else if (imageoverlay) {
bigwo[eval(-1 + bigwo.length)].document.write(snapshotoh.replace(' id="my' + 'ifrXame" style="',' id="my' + 'ifrXame" style="visibility:hidden;').replace(' id="my' + 'image" style="',' id="my' + 'image" style="visibility:hidden;').replace(' id="do' + 'verlay">', ' id="do' + 'verlay">' + document.getElementById('doverlay').innerHTML));
} else if (iframeoverlay) {
bigwo[eval(-1 + bigwo.length)].document.write(snapshotoh.replace(' id="my' + 'iframe" style="',' id="my' + 'iframe" style="visibility:hidden;').replace(' id="my' + 'imaXge" style="',' id="my' + 'imXage" style="visibility:hidden;').replace(' id="do' + 'verlay">', ' id="do' + 'verlay">' + document.getElementById('doverlay').innerHTML));
} else {
bigwo[eval(-1 + bigwo.length)].document.write('<html><head>' + document.head.innerHTML + '</head>' + document.body.outerHTML + '</html>');
}
}

… and all helped out by two “wrapper functions” that wrap the image and/or iframe “src” attribute “calculation” code, as per …


function thenimagain(inurl) {
if (imageoverlay) {
var wasp=imageprevs;
//setTimeout(function() {
imageprevs=imagelasts;
imageurlpush.push(inurl);
document.getElementById('doverlay').innerHTML+='<img title="Click for new window version or right click showing overlays" oncontextmenu="windowopen(this.src,' + "'_blank'" + ');" onclick="window.open(this.src,' + "'_blank'" + ');" style=' + "'width:" + imifw + "px;height:" + imifh + "px;left:" + imagerect[0].left + "px;top:" + imagerect[0].top + "px;position:absolute;'" + ' id=myimage' + imagelasts + ' src="' + inurl + '"></img>';
imagerect=[];
imagerect.push(document.getElementById('myimage' + imagelasts).getBoundingClientRect());
imagelasts='' + imageurlpush.length;
//}, 1000);
return document.getElementById('myimage' + wasp).src + '#';
}
return inurl;
}

function thenifagain(inurl) {
if (iframeoverlay) {
var wasp=iframeprevs;
//setTimeout(function() {
iframeprevs=iframelasts;
iframeurlpush.push(inurl);
document.getElementById('doverlay').innerHTML+='<iframe title="Click for new window version or right click showing overlays" oncontextmenu="windowopen(this.src,' + "'_blank'" + ');" onclick="window.open(this.src,' + "'_blank'" + ');" frameborder=0 style=' + "'width:" + ififw + "px;height:" + ififh + "px;left:" + iframerect[0].left + "px;top:" + iframerect[0].top + "px;position:absolute;'" + ' id=myiframe' + iframelasts + ' src="' + inurl + '"></iframe>';
iframerect=[];
iframerect.push(document.getElementById('myiframe' + iframelasts).getBoundingClientRect());
iframelasts='' + iframeurlpush.length;
//}, 1000);
return document.getElementById('myiframe' + wasp).src + '#';
}
return inurl;
}

… in our changed third draft Show Some Shapes web application (you can also try below.


Previous relevant SVG Shapes Dimensions and Colour Tutorial is shown below.

SVG Shapes Dimensions and Colour Tutorial

SVG Shapes Dimensions and Colour Tutorial

It’s not so much fun, for a lot of us, learning about things when it’s just dished up. It’s usually better, especially for our visual or kinesthetic learners out there, that the user can change a setting to see a changed result. And so, further to yesterday’s SVG Shapes Game Primer Tutorial‘s start to our changed second draft Show Some Shapes web application (you can also try below), we’ve added …

  • dimensional width and height “input” controls
  • fill colour and stroke colour “input” colour picker controls … including “Transparent” and “None” choices presented in an accompanying dropdown
  • fill colour opacity and stroke colour opacity “input” controls

Our strategy, here was to allow URLs to our 404.php be a lot more complex via …

<?php

$opacityis="1.0";
$fopacityis="1.0";
$sopacityis="1.0";

function restcheck($inideacol) {
global $opacityis, $fopacityis, $sopacityis, $linemode;
$outideacol=trim($inideacol);
$inideacol=$outideacol;
if (strlen($inideacol) >= 4) {
if (strpos(strtolower(substr($inideacol, -4, 3)), "to") !== false) {
if ( str_replace('l','r',str_replace('t','r',str_replace('b','r',str_replace('c','r',str_replace('m','r', strtolower(substr($inideacol, -1, 1))))))) == 'r') {
$rbit=explode('to', strtolower($inideacol))[-1 + sizeof(explode('to', strtolower($inideacol)))];
$lbitis=explode('to' . $rbit, strtolower($inideacol))[-1 + sizeof(explode('to' . $rbit, strtolower($inideacol)))];
$lpref='';
if ( str_replace('l','r',str_replace('t','r',str_replace('b','r',str_replace('c','r',str_replace('m','r', strtolower(substr($lbitis, -1, 1))))))) == 'r') {
$lpref=strtolower(substr($lbitis, -1, 1));
if ( str_replace('l','r',str_replace('t','r',str_replace('b','r',str_replace('c','r',str_replace('m','r', strtolower(substr($lbitis, -2, 1))))))) == 'r') {
$linemode=strtolower(substr($lbitis, -2, 1)) . $lpref . 'to' . $rbit;
$outideacol=substr($inideacol,0,(strlen($inideacol) - strlen($linemode)));
} else {
$linemode=$lpref . 'to' . $rbit;
$outideacol=substr($inideacol,0,(strlen($inideacol) - strlen($linemode)));
}
} else {
$linemode=$lpref . 'to' . $rbit;
$outideacol=substr($inideacol,0,(strlen($inideacol) - strlen($linemode)));
}
}
}
if (strpos(strtolower(substr($outideacol, -2, 2)), ".") !== false && strpos(strtolower(substr($outideacol, -2, 2)), ")") === false) {
$rbit=explode('.', strtolower($outideacol))[-1 + sizeof(explode('.', strtolower($outideacol)))];
$lbitis=explode('.' . $rbit, strtolower($outideacol))[0];
$lpref='';
if ($rbit == "" || (substr(($rbit . ' '),0,1) >= '0' && substr(($rbit . ' '),0,1) <= '9' )) {
if ((substr(($lbitis . ''),-1,1) >= '0' && substr(($lbitis . ''),-1,1) <= '9' )) {
//echo $outideacol . ' ' . substr(($lbitis . ''),-1,1) . '.' . $rbit . '?' . $lbitis . '!';
//exit;
$outideacol=substr($outideacol,0,(strlen($outideacol) - strlen(substr(($lbitis . ''),-1,1) . '.' . $rbit)));
//echo $outideacol;
//exit;
$opacityis=substr(($lbitis . ''),-1,1) . '.' . str_replace('00','0',substr(($rbit . '0'),0));
} else {
$outideacol=substr($outideacol,0,(strlen('.' . $rbit)));
$opacityis='0' . '.' . str_replace('00','0',substr(($rbit . '0'),0));
}
}
}
}
return $outideacol;
}

function ffcolcheck($outideacol) {
global $opacityis, $fopacityis, $sopacityis;
// echo ' ' . $fopacityis . ' ' . $sopacityis . ' ' . $opacityis . ' ... ' . $outideacol;
// exit;
$awso=$opacityis;
$fopacityis=$opacityis;
$inideacol=restcheck($outideacol);
if ($fopacityis != $opacityis) { $fopacityis=$opacityis; $opacityis=$waso; }
// echo $inideacol . ' ' . $fopacityis . ' ' . $sopacityis . ' ' . $opacityis . ' ... ' . $outideacol;
// exit;
if (strlen($inideacol) == 6) {
if (str_replace('A','',str_replace('a','',str_replace('B','',str_replace('b','',str_replace('C','',str_replace('c','',str_replace('D','',str_replace('d','',str_replace('E','',str_replace('e','',str_replace('F','',str_replace('f','', str_replace('0','',str_replace('1','',str_replace('2','',str_replace('3','',str_replace('4','',str_replace('5','',str_replace('6','',str_replace('7','',str_replace('8','',str_replace('9','', $inideacol)))))))))))))))))))))) == '') {
if ($fopacityis != '1.0') {
// echo 'rgba(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ',' . $fopacityis . ')';
// exit;
return 'rgba(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ',' . $fopacityis . ')';
}
return 'rgb(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ')';
}
}
return $inideacol;
}

function fcolcheck($outideacol) {
global $opacityis, $fopacityis, $sopacityis;
// echo ' ' . $fopacityis . ' ' . $sopacityis . ' ' . $opacityis . ' ... ' . $outideacol;
// exit;
$sopacityis=$opacityis;
$inideacol=restcheck($outideacol);
if ($sopacityis != $opacityis) { $fopacityis=$opacityis; $opacityis=$sopacityis; }
// echo $inideacol . ' ' . $fopacityis . ' ' . $sopacityis . ' ' . $opacityis . ' ... ' . $outideacol;
// exit;
if (strlen($inideacol) == 6) {
if (str_replace('A','',str_replace('a','',str_replace('B','',str_replace('b','',str_replace('C','',str_replace('c','',str_replace('D','',str_replace('d','',str_replace('E','',str_replace('e','',str_replace('F','',str_replace('f','', str_replace('0','',str_replace('1','',str_replace('2','',str_replace('3','',str_replace('4','',str_replace('5','',str_replace('6','',str_replace('7','',str_replace('8','',str_replace('9','', $inideacol)))))))))))))))))))))) == '') {
if ($fopacityis != '1.0') {
// echo 'rgba(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ',' . $fopacityis . ')';
// exit;
return 'rgba(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ',' . $fopacityis . ')';
}
return 'rgb(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ')';
}
}
return $inideacol;
}

function colcheck($outideacol) {
global $opacityis, $fopacityis, $sopacityis;
if ($opacityis != '1.0' && $sopacityis != $opacityis) { $sopacityis=$opacityis; }
$wasop=$opacityis;
$inideacol=restcheck($outideacol);
if ($wasop != $opacityis) { $sopacityis=$opacityis; }
if (strlen($inideacol) == 6) {
if (str_replace('A','',str_replace('a','',str_replace('B','',str_replace('b','',str_replace('C','',str_replace('c','',str_replace('D','',str_replace('d','',str_replace('E','',str_replace('e','',str_replace('F','',str_replace('f','', str_replace('0','',str_replace('1','',str_replace('2','',str_replace('3','',str_replace('4','',str_replace('5','',str_replace('6','',str_replace('7','',str_replace('8','',str_replace('9','', $inideacol)))))))))))))))))))))) == '') {
if ($sopacityis != '1.0') {
// echo 'rgba(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ',' . $sopacityis . ')';
// exit;
return 'rgba(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ',' . $sopacityis . ')';
}
return 'rgb(' . hexdec(substr($inideacol,0,2)) . ',' . hexdec(substr($inideacol,2,2)) . ',' . hexdec(substr($inideacol,4,2)) . ')';
}
}
return $inideacol;
}

function createScaledImage($newWidth,$newHeight,$path,$datauri) { // thanks to https://stackoverflow.com/questions/16774521/scale-image-using-php-and-maintaining-aspect-ratio
global $ptitle, $reltopic, $filterstuff, $randstr, $opacityis, $linemode;
$image_name=explode(DIRECTORY_SEPARATOR, $path)[-1 + sizeof(explode(DIRECTORY_SEPARATOR, $path))];
$theextis='';

if (($newWidth == 32 && $newHeight == 32) || strpos(('?' . $_SERVER['QUERY_STRING']), '?svg') !== false) {
$fillc="red";
$strokec="black";
if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false || strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$fillc="none";
if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('arc=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
} else if (strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('semicircle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
}
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M ' . ($newWidth / 2) . ' 0 A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 0, ' . ($newWidth / 2) . ' ' . $newHeight . ' " stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" />
</svg>';
exit;


} else if (strpos($_SERVER['QUERY_STRING'], 'pie=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('pie=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" r="' . (($newWidth + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
<path d="M ' . ($newWidth / 2) . ' 0 A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 1, ' . ($newWidth / 1) . ' ' . ($newHeight / 2) . ' ' . $thehome . '" stroke="white" stroke-width="3" fill="white" />
</svg>';
exit;

} else if (strpos($_SERVER['QUERY_STRING'], 'circle=') !== false) {
header('Content-Type: image/svg+xml');
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('circle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=fcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" r="' . (($newWidth + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'ellipse=') !== false) {
header('Content-Type: image/svg+xml');
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('ellipse=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" rx="' . (($newWidth + $newWidth) / 4) . '" ry="' . (($newHeight + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'square=') !== false || strpos($_SERVER['QUERY_STRING'], 'rectangle=') !== false) {
header('Content-Type: image/svg+xml');
if (strpos($_SERVER['QUERY_STRING'], 'square=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('square=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
} else if (strpos($_SERVER['QUERY_STRING'], 'rectangle=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('rectangle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
}
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=fcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'rhombus=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('rhombus=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="-' . ($newWidth / 2) . '" y="-' . ($newHeight / 2) . '" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" transform="translate(' . ($sbone / 2) . ', ' . ($sbone / 2) . ') rotate(45)"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'octagon=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('octagon=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=fcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="-' . ($newWidth / 2) . '" y="-' . ($newHeight / 2) . '" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" transform="translate(' . ($newWidth / 2) . ', ' . ($newHeight / 2) . ') rotate(45)"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'triangle=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('triangle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon points="' . $newWidth . ',' . $newHeight . ' ' . ($newWidth / 2) . ',0 0,' . $newHeight . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" />
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'line=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('line=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=fcolcheck($inbw[0]);
$strokec=$fillc;
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line x1="' . $newWidth . '" y1="' . $newHeight . '" x2="0" y2="0" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" />
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'bezier=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('bezier=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
$fillc="none";
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M 0 ' . $newHeight . ' q ' . (($newWidth / 2) - 0) . ' ' . (0 - $newHeight) . ' ' . ($newWidth - 0) . ' ' . ($newHeight - $newHeight) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" />
</svg>';
exit;

} else if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false || strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$fillc="none";
if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('arc=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
} else if (strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('semicircle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
}
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=fcolcheck($inbw[0]); }
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M ' . ($newWidth / 2) . ' 0 A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 0, ' . ($newWidth / 2) . ' ' . $newHeight . ' " stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" />
</svg>';
exit;


} else if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false || strpos($_SERVER['QUERY_STRING'], 'crescent=') !== false) {
$fillc="none";
$thehome='';
if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('quadrant=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
} else if (strpos($_SERVER['QUERY_STRING'], 'crescent=') !== false) {
$inbetween=restcheck(str_replace(':',' ',str_replace('`',' ',str_replace(';',' ',str_replace('+',' ',urldecode(explode('crescent=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0]))))));
}
if ($inbetween != '') {
$inbetween=trim($inbetween); $inbw=explode(' ', str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',str_replace(' ',' ',$inbetween)))));
if (sizeof($inbw) == 1) {
$fillc=ffcolcheck($inbw[0]);
if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false) {
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
}
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') {
$fillc=fcolcheck($inbw[0]);
if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false) {
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
}
}
if (trim($inbw[1]) != '') { $strokec=colcheck($inbw[1]); }
}
}
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M 0 ' . ($newHeight / 2) . ' A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 1, ' . ($newWidth / 2) . ' 0 ' . $thehome . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" />
</svg>';
exit;
}
}

if (!$datauri) {
if (isset($_GET['random'])) {
if (substr(($_GET['random'] . ' '),0,1) == '0') {
$thist=' ' . time();
$thistminustwo=substr($thist,0,(strlen($thist) - 2));
if (!file_exists('./rjmlist.htm')) {
file_put_contents('./rjmlist.htm', '<body><pre>' . "\n" . $thist . '|' . $_GET['random'] . '|' . $ptitle . "\n</pre></body>");
} else {
$sofarc=file_get_contents('./rjmlist.htm');
$newones=explode($thistminustwo, $sofarc);
$lastiis=0;
if (strpos($sofarc, ' ') !== false) { $lastiis=explode('|',explode(' ', $sofarc)[1])[0]; }
if (sizeof($newones) == 1 && (time() - $lastiis) > 100) {
file_put_contents('./rjmlist.htm', '<body><pre>' . "\n" . $thist . '|' . $_GET['random'] . '|' . $ptitle . "\n</pre></body>");
} else {
$sofarcs=explode('|' . $_GET['random'] . '|', $sofarc);
if (sizeof($sofarcs) > 1) {
$sofarpref=' ' . explode(' ', $sofarcs[0])[-1 + sizeof(explode(' ', $sofarcs[0]))] . '|' . $_GET['random'] . '|' . explode("\n", $sofarcs[1])[0] . "\n";
$sofarc=str_replace($sofarpref, "", $sofarc);
}
file_put_contents('./rjmlist.htm', '<body><pre>' . "\n" . $thist . '|' . $_GET['random'] . '|' . $ptitle . "\n" . str_replace('<body><pre>' . "\n", '', $sofarc));
}
}
}
}
}

$mime = getimagesize($path);

if ($mime['mime']=='image/png') {
if ($filterstuff != '') {
header('Content-Type: image/png');
echo ourimagecreatefromcontent(file_get_contents($path), 'png');
exit;
}
$src_img = imagecreatefrompng($path);
}
if ($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
if ($filterstuff != '') {
header('Content-Type: image/jpeg');
echo ourimagecreatefromcontent(file_get_contents($path), 'jpeg');
exit;
}
$src_img = imagecreatefromjpeg($path);
}
if ($mime['mime']=='image/gif') {
//echo 'data:image/gif;base64,' . base64_encode(file_get_contents($path));
header('Content-Type: image/gif');
echo ourimagecreatefromcontent(file_get_contents($path), 'gif');
exit;
$src_img = imagecreatefromgif($path);
}

$old_x = imageSX($src_img);
$old_y = imageSY($src_img);

if ($old_x > $old_y) {
$thumb_w = $newWidth;
$thumb_h = $old_y/$old_x*$newWidth;
}

if ($old_x < $old_y) {
$thumb_w = $old_x/$old_y*$newHeight;
$thumb_h = $newHeight;
}

if ($old_x == $old_y) {
$thumb_w = $newWidth;
$thumb_h = $newHeight;
}

$dst_img = imagecreatetruecolor($thumb_w,$thumb_h);

imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y);

// New save location
$new_thumb_loc = '/tmp/' . $image_name;

if (!$datauri) {
if($mime['mime']=='image/png') {
$theextis='png';
header('Content-Type: image/png');
imagepng($dst_img); //,$new_thumb_loc,8);
if (file_exists($new_thumb_loc)) {
unlink($new_thumb_loc);
}
imagedestroy($dst_img);
imagedestroy($src_img);
exit;
} else if ($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
$theextis='jpeg';
header('Content-Type: image/jpeg');
imagejpeg($dst_img); //,$new_thumb_loc,80);
if (file_exists($new_thumb_loc)) {
unlink($new_thumb_loc);
}
imagedestroy($dst_img);
imagedestroy($src_img);
exit;
} else if ($mime['mime']=='image/gif') {
$theextis='gif';
header('Content-Type: image/gif');
imagegif($dst_img); //,$new_thumb_loc,80);
if (file_exists($new_thumb_loc)) {
unlink($new_thumb_loc);
}
imagedestroy($dst_img);
imagedestroy($src_img);
exit;
}
exit;
}

$result="";
if ($mime['mime']=='image/png') {
$theextis='png';
imagepng($dst_img,$new_thumb_loc,8);
$result = file_get_contents($new_thumb_loc);
}
if ($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
$theextis='jpeg';
imagejpeg($dst_img,$new_thumb_loc,80);
$result = file_get_contents($new_thumb_loc);
}
if ($mime['mime']=='image/gif') {
$theextis='gif';
imagegif($dst_img,$new_thumb_loc);
$result = file_get_contents($new_thumb_loc);
}

imagedestroy($dst_img);
imagedestroy($src_img);

if (file_exists($new_thumb_loc)) {
unlink($new_thumb_loc);
}

return ourimagecreatefromcontent($result, $theextis);
}

?>


Previous relevant SVG Shapes Game Primer Tutorial is shown below.

SVG Shapes Game Primer Tutorial

SVG Shapes Game Primer Tutorial

Although we do not mention it in today’s blog posting title, today’s work primarily hinges on some changes we made to our WordPress Blog (you are reading) 404.php logic, further to the last foray into WordPress TwentyTen theme’s 404.php means by which unsuccessful http://www.rjmprogramming.com.au/ITblog/ prefixing URLs get processed, as we talked about with Interactively Change WordPress Blog Background Image on Scroll Tutorial.

We’ve opened up a new segment of functionality here, allowing the user to receive SVG (via svg+xml protocol) image based data for a URL such as …


http://www.rjmprogramming.com.au/ITblog/620/350/?svgbluerectangle=y

As you probably know, SVG is a boon to people trying to explain geometry or shapes, as with today’s “proof of concept” Show Some Shapes web application you can also try below …

… which beggars the question …

What does the changed 404.php PHP code look like?

Glad you asked!

<?php

if (($newWidth == 32 && $newHeight == 32) || strpos(('?' . $_SERVER['QUERY_STRING']), '?svg') !== false) {
$fillc="red";
$strokec="black";
if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false || strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$fillc="none";
if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('arc=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
} else if (strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('semicircle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
}
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M ' . ($newWidth / 2) . ' 0 A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 0, ' . ($newWidth / 2) . ' ' . $newHeight . ' " stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" />
</svg>';
exit;


} else if (strpos($_SERVER['QUERY_STRING'], 'pie=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('pie=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" r="' . (($newWidth + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
<path d="M ' . ($newWidth / 2) . ' 0 A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 1, ' . ($newWidth / 1) . ' ' . ($newHeight / 2) . ' ' . $thehome . '" stroke="white" stroke-width="3" fill="white" />
</svg>';
exit;


} else if (strpos($_SERVER['QUERY_STRING'], 'circle=') !== false) {
header('Content-Type: image/svg+xml');
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('circle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" r="' . (($newWidth + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'ellipse=') !== false) {
header('Content-Type: image/svg+xml');
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('ellipse=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="' . ($newWidth / 2) . '" cy="' . ($newHeight / 2) . '" rx="' . (($newWidth + $newWidth) / 4) . '" ry="' . (($newHeight + $newHeight) / 4) . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'square=') !== false || strpos($_SERVER['QUERY_STRING'], 'rectangle=') !== false) {
header('Content-Type: image/svg+xml');
if (strpos($_SERVER['QUERY_STRING'], 'square=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('square=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
} else if (strpos($_SERVER['QUERY_STRING'], 'rectangle=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('rectangle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
}
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'rhombus=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('rhombus=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="-' . ($newWidth / 2) . '" y="-' . ($newHeight / 2) . '" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" transform="translate(' . ($sbone / 2) . ', ' . ($sbone / 2) . ') rotate(45)"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'octagon=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('octagon=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="-' . ($newWidth / 2) . '" y="-' . ($newHeight / 2) . '" width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" transform="translate(' . ($newWidth / 2) . ', ' . ($newHeight / 2) . ') rotate(45)"/>
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'triangle=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('triangle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon points="' . $newWidth . ',' . $newHeight . ' ' . ($newWidth / 2) . ',0 0,' . $newHeight . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" />
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'line=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('line=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line x1="' . $newWidth . '" y1="' . $newHeight . '" x2="0" y2="0" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" />
</svg>';
exit;
} else if (strpos($_SERVER['QUERY_STRING'], 'bezier=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('bezier=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
$fillc="none";
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
$bone=$newWidth;
if ($newHeight > $bone) { $bone=$newHeight; }
$sbone=sqrt($bone * $bone * 2);
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" viewbox="0 0 ' . ($newWidth / 1) . ' ' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M 0 ' . $newHeight . ' q ' . (($newWidth / 2) - 0) . ' ' . (0 - $newHeight) . ' ' . ($newWidth - 0) . ' ' . ($newHeight - $newHeight) . '" stroke-width="2" stroke="' . $strokec . '" fill="' . $fillc . '" />
</svg>';
exit;

} else if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false || strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$fillc="none";
if (strpos($_SERVER['QUERY_STRING'], 'arc=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('arc=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
} else if (strpos($_SERVER['QUERY_STRING'], 'semicircle=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('semicircle=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
}
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') { $fillc=$inbw[0]; }
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M ' . ($newWidth / 2) . ' 0 A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 0, ' . ($newWidth / 2) . ' ' . $newHeight . ' " stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" />
</svg>';
exit;


} else if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false || strpos($_SERVER['QUERY_STRING'], 'crescent=') !== false) {
$fillc="none";
$thehome='';
if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('quadrant=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
} else if (strpos($_SERVER['QUERY_STRING'], 'crescent=') !== false) {
$inbetween=str_replace(':',',',str_replace('.',',',str_replace(' ',',',str_replace('+',',',urldecode(explode('crescent=', str_replace('?svg','',str_replace('??svg','',('?' . $_SERVER['QUERY_STRING']))))[0])))));
}
if ($inbetween != '') {
$inbw=explode(',', $inbetween);
if (sizeof($inbw) == 1) {
$fillc=$inbw[0];
if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false) {
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
}
} else if (sizeof($inbw) >= 2) {
if (trim($inbw[0]) != '') {
$fillc=$inbw[0];
if (strpos($_SERVER['QUERY_STRING'], 'quadrant=') !== false) {
$thehome=' L ' . ($newWidth / 2) . ' ' . ($newHeight / 2) . ' Z';
}
}
if (trim($inbw[1]) != '') { $strokec=$inbw[1]; }
}
}
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . ($newWidth / 1) . '" height="' . ($newHeight / 1) . '" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M 0 ' . ($newHeight / 2) . ' A ' . (($newWidth + $newWidth) / 4) . ' ' . (($newHeight + $newHeight) / 4) . ', 0, 0, 1, ' . ($newWidth / 2) . ' 0 ' . $thehome . '" stroke="' . $strokec . '" stroke-width="2" fill="' . $fillc . '" />
</svg>';
exit;
}
}

?>


Previous relevant Interactively Change WordPress Blog Background Image on Scroll Tutorial is shown below.

Interactively Change WordPress Blog Background Image on Scroll Tutorial

Interactively Change WordPress Blog Background Image on Scroll Tutorial

With yesterday’s Interactively Change Background Image on Scroll User Settings Tutorial‘s offering were you “an intrepid”, typing …

//www.rjmprogramming.com.au/ITblog/600/400/

… into that newly minted Javascript prompt window designed for user interaction purposes? This populates the background images in our new Image Scrolling with Fixed Text web application with a random selection from the WordPress Blog you are reading. Because we have some control here, we researched whether our WordPress 404.php logic could be tweaked to help out more in this scenario. The way the PHP works here, detecting this situation, at the end of its workings, is to use an image header (exemplified by the GIF one below) …

<?php

header('Content-Type: image/gif');
echo file_get_contents($path);
exit;

?>

… where $path would point at a GIF image file residing on the RJM Programming domain web server. This design restricts us from any echo functionality before this, so what can we achieve? Anyone? Anyone? Yes, Rasmus, we can write to other web server files that could be like middle-people between the server (supplier of image data) and client (the webpage that called the server). After the server work …

<?php

if (strpos(('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'), '591734~') !== false) {
//file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.p','here');
$prevcontis='';
$ptfileis=$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'ptitledata.html';
if (file_exists($ptfileis)) { // thanks to https://stackoverflow.com/questions/67707029/how-do-i-get-how-long-the-file-was-created-in-seconds-in-php
$modifdate = filemtime($ptfileis);
$secondsago = time() - $modifdate;
if ($secondsago > 5) {
unlink($ptfileis);
} else {
$prevcontis=file_get_contents($ptfileis);
}
}
file_put_contents($ptfileis, $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//file_put_contents($ptfileis . "huh", $prevcontis . "\n" . $ptitle . '?' . str_replace(');%20}','',$_SERVER['QUERY_STRING']));
//} else {
// file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'p.q',('' . str_replace(');%20}','',$_SERVER['QUERY_STRING']) . '~'));
}

?>

… back at that client (which called the server with that appended “591734” placed onto the URL to indicate the intention to want to examine this return data), we have Ajax based Javascript logic …


var ptc='#';
var iptc=0;
var btlist=[];
var vsbtlist=[];
var omo='';

var zhr=null;
var zform=null;
var rawhtml='';

function defmaybe(inu) {
var retomo=omo;
if (omo != '') {
omo='';
return retomo;
}
return inu;
}

function stateChanged() {
var inm=1, jnm=1, thebtitle='';
if (zhr.readyState == 4) {
if (zhr.status == 200) {
rawhtml = zhr.response;
console.log('rawhtml=' + rawhtml);
if (rawhtml.indexOf('random=') != -1 && vsbtlist.length > 0) {
var rawrs=rawhtml.split('random=');
for (inm=1; inm<rawrs.length; inm++) {
for (jnm=0; jnm<vsbtlist.length; jnm++) {
if (vsbtlist[jnm].indexOf('?random=' + rawrs[inm].split(String.fromCharCode(10))[0]) != -1) {
console.log('found ...');
thebtitle=rawhtml.split('?random=' + rawrs[inm].split(String.fromCharCode(10))[0])[0].split(String.fromCharCode(10))[eval(-1 + rawhtml.split('?random=' + rawrs[inm].split(String.fromCharCode(10))[0])[0].split(String.fromCharCode(10)).length)];
console.log(thebtitle);
document.getElementById(vsbtlist[jnm].split('?')[0]).title=thebtitle + ' ... you can right click to navigate there';
document.getElementById(vsbtlist[jnm].split('?')[0]).onmouseout=function(){ omo=''; };
document.getElementById(vsbtlist[jnm].split('?')[0]).onmouseover=function(){ omo='//www.rjmprogramming.com.au/ITblog/' + thebtitle.split(' (')[0].toLowerCase().replace(/\ /g,'-'); };
document.getElementById(vsbtlist[jnm].split('?')[0]).oncontextmenu=function(){ window.open(defmaybe('//www.rjmprogramming.com.au/ITblog/' + thebtitle.split(' (')[0].toLowerCase().replace(/\ /g,'-')),'_blank','top=50,left=50,width=800,height=800'); };
}
}
}
}
}
}
}

function ajaxit() {
zhr = new XMLHttpRequest();
zhr.onreadystatechange=stateChanged;
zhr.open('get', '//www.rjmprogramming.com.au/ptitledata.html?random=' + Math.floor(Math.random() * 196756453), true);
zhr.send(null);
}

… adding oncontextmenu (ie. right click) functionality to the background images, so as a popup window can open to show the associated WordPress Blog posting linked to the image data.

… in today’s changed interactively_change_background_image_on_scroll.html web application you can also try way below.


Previous relevant Interactively Change Background Image on Scroll User Settings Tutorial is shown below.

Interactively Change Background Image on Scroll User Settings Tutorial

Interactively Change Background Image on Scroll User Settings Tutorial

If you are a regular reader, you’ll know with the web applications presented here, we usually try to allow the user to control …

  • how they function … and/or sometimes …
  • how they look

… in the ephemeral “this session” sense, and sometimes follow that up, depending, with recallable settings often calling on window.localStorage or HTTP Cookies, associated with the web browser being used.

Regarding that ephemeral “this session” sense above, building on the work of yesterday’s Interactively Change Background Image on Scroll Tutorial, we now allow the user control over defining any/all …

  • Background Image source URL
  • Refresh delay (in seconds)
  • Text Wording
  • Text Background Image source URL

… and regarding the use of that last one, we’ve decided, somewhat, to take over with the CSS regarding the Text Wording showing through amongst so many “image interests” with various opacities …


var mode='dw';

function preask() {
if (backimg.trim() != '') {
if (backimg.toLowerCase().replace(/\ /g,'') == 'lorempicsum') {
backimg='//picsum.photos/600/400' + suffix + '?random=' + Math.floor(Math.random() * 198765643);
if (mode == 'dw') {
mode='';
document.write('<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>');
} else {
document.getElementById('dstyle').innerHTML+='<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>';
}
backimg='lorempicsum';
} else {
if (mode == 'dw') {
mode='';
document.write('<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>');
} else {
document.getElementById('dstyle').innerHTML+='<style> .bg-text { background: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),URL("' + backimg + '"); background-size: contain; background-repeat: repeat; text-shadow:-2px 2px 2px #ff2d95; opacity: 0.9; } </style>';
}
}
}
}

Which beggars the observation …

Isn’t the CSS text-shadow property just great?!

We use it more and more often to help out foreground text presented with a lot of “overlay imagery” going on behind it.

Here is the Javascript prompt window “blurb” presented to the user should they want to delve into this woooooorrrrrlllllldddd just by clicking or touching in the non-text part of the webpage …

var ansis=prompt(‘Optionally enter in background source URL prefix [‘ + prefix + midbit + suffix + ‘] ( or type Lorem Picsum or for blog posting images you could try //www.rjmprogramming.com.au/ITblog/’ + sixhundred + ‘/’ + fourhundred + ‘/ ), hashtag delimited from an optional imagery refresh rate in seconds [‘ + ten + ‘], hashtag delimited from an optional Text element background image (or type Lorem Picsum), hashtag delimited from optional Text wording [‘ + tcont + ‘] we will assume involves a space.‘, ”);

… in the changed interactively_change_background_image_on_scroll.html web application you can also try below.


Previous relevant Interactively Change Background Image on Scroll Tutorial is shown below.

Interactively Change Background Image on Scroll Tutorial

Interactively Change Background Image on Scroll Tutorial

Regarding today’s “Interactively Change Background Image on Scroll” topic, we’d like to thank, profusely, two sources …

Queue … Lulu (no, not the dog, this time)!

Yes, we’ve just added “Interactively”, we hear you say (just maybe, perhaps, a tad sarcastically, shall we say … huh?!!!!). But, it’s the …

… that is all a bit new, at least to us, today, continuing on the recent wonder regarding contenteditable=true, mentioned in the recent Animated GIF SVG Quiz Automation Interaction Tutorial

And did you know, at least for non-mobile platforms, you can set the focus (on non-mobile platforms only, as there are the “keyboard getting in the way” issues we’re thankful for with mobile platforms which preclude any thoughts of a programmed [element].focus() operation) to one of these “contenteditable=true style elements”? We’d never been sure, only focussing to HTML input textboxes and textareas up to now, we believe.

… whereby non-mobile focus to a contenteditable=true HTML div type (innerHTML style) element is possible, adding to the original W3School’s content ideas swirling around …

  • CSS position: fixed; … for foreground text, in relation to …
  • scrolling … with …
  • background imagery

… for topics we hope you find as interesting as we did, in our new “proof of concept” web application you can also try below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in Animation, eLearning, Event-Driven Programming, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Javascript Lazy Evaluation Sun Angle Game Tutorial

Javascript Lazy Evaluation Sun Angle Game Tutorial

Javascript Lazy Evaluation Sun Angle Game Tutorial

In this world we all look up at the same …

  • Sun
  • Moon

… as our “usual companions” of space. One is tempted to say G’Day but we’re too scared of misspelling it, so we’ll just say …

Good Morning Sunshine

… to welcome today’s new Geography Quiz game mode

  • Country Capitals Game
  • In the Hour Game
  • Languages Game
  • In the Timestamp Game
  • Geographicals Game
  • Crow Fly Game
  • Bearing Game … and today we present …
  • Noon Sun Angle Game

Yes, astronomers (and many cultures throughout history, before, it should be said) know a lot about the relative positions of the Earth with respect to the Sun (and Moon) especially, and we retrace much of the way we created the PHP Sun Information Software Integration Tutorial. So much so, that we left the Sun’s styling to be expressed just below our draggable “p” element, in a new HTML iframe element, with the following “onload” event logic …


function sunangle(iois) {
if (iois != null) {
var aconto=(iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
if (iois.src.indexOf('longd=') != -1 && iois.src.indexOf('latd=') != -1) {
if (aconto.body.innerHTML.indexOf('): (') != -1) {
sunangleblurb=aconto.body.innerHTML.replace(aconto.body.innerHTML.split('): (')[1].split(')')[0], '?,?').replace(/\<br\>/g,' ').replace('" id="myh2"', 'margin-top:-40px;" id="myh2"');
document.getElementById('ddstyle').innerHTML+='<style> ' + aconto.head.innerHTML.split('<style>')[1].split('</style>')[0] + ' </style>';
if (1 == 1) {
aconto.body.innerHTML=sunangleblurb;
document.getElementById('isun').style.display='inline-block';
} else {
document.getElementById('source').innerHTML=sunangleblurb;
}
}
}
}
}
}
}

… that is tweaked so as not to give the game away, but displays information much as that PHP Sun Angle web application intended. The aim of this Noon Sun Angle Game mode of use, within our Geography Quiz theme, is to drop the draggable label above this Noon Sun Angle (and other) information into the correct of the nine Google Geo Chart country maps below, to score.

Further to the recent Javascript Lazy Evaluation Game Sharing Tutorial to make this happen, see our changed gradual_reveal_country_game.html‘s Noon Sun Angle and/or Bearing and/or Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.

Did you know?

We can navigate using the Sun and stars. Land surveyors lacking two known co-ordinated survey marks can set up on one known survey mark and take measurements of the Sun (careful here not to directly look at the Sun) to determine an initial bearing (or azimuth), and off that swing an angle with their theodolites to begin a survey traverse.


Previous relevant Javascript Lazy Evaluation Game Sharing Tutorial is shown below.

Javascript Lazy Evaluation Game Sharing Tutorial

Javascript Lazy Evaluation Game Sharing Tutorial

In thinking about a sharing, via email or SMS, component on top of the progress of the recent Javascript Lazy Evaluation Bearing Game Tutorial, with our current …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… game modes we thought the best approach would be if a user could share with another the same Geography Quiz based question they have been asked, to compare notes.

Which begs the question?

What can give a game (or quiz) a random feel?

Well, with Javascript, we’re always using …


var arandom=Math.floor(Math.random() * anarrayofchoices.length); // anarrayofchoices is an array of choices and arandom ends up as an index into that array's contents

… types of statements … or variations on this style of statement. So we zeroed in on these and set about unrandomising these places in the code, to, if asked, simulate that same random way the question was framed for the emailer …


var complex=location.search.split('simple=')[1] ? decodeURIComponent(location.search.split('simple=')[1].split('&')[0]) : '';
var drilldown=complex.split('_')[0];
var simple=location.search.split('simple=')[1] ? (drilldown == '' ? false : true) : false;

var mflist=drilldown + '_', mfcount=0;

var answer=Math.min(9, eval(Math.floor(Math.random() * 9) + 1)); // first example of use
if (complex.indexOf('_' + mfcount + '.') != -1) {
answer=eval(complex.split('_' + mfcount + '.')[1].split('_')[0]);
}
mflist+='' + mfcount + '.' + answer + '_';
mfcount++;

… used by new helping Javascript code …


<div id=das style=display:none;></div>
<script type='text/javascript'>
setTimeout(function() { document.getElementById('das').innerHTML+=("<a style=display:none; id=asms href='sms:&body=" + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + '?simple=' + encodeURIComponent(mflist)) + "'>SMS</a>"); document.getElementById('bsharesms').style.visibility='visible'; }, 18000);
setTimeout(function() { document.getElementById('das').innerHTML+=("<a style=display:none; id=aemail href='mailto:?subject=Geography%20Quiz&body=" + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + '?simple=' + encodeURIComponent(mflist)) + "'>Email</a>"); document.getElementById('bshareemail').style.visibility='visible'; }, 18500);
</script>

… and will happen for the emailee …


function savesms(defsms) {
var wasv=('' + window.localStorage.getItem('smsgrcg')).replace(/^null$/g,'').replace(/^undefined$/g,'');
if (defsms.indexOf(defsms.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('smsgrcg'); }
} else if (defsms.indexOf(defsms.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('smsgrcg'); }
window.localStorage.setItem('smsgrcg', defsms.trim());
} else if (defsms == '' && wasv.trim() != '') {
return wasv;
}
return defsms;
}

function saveemail(defemail) {
var wasv=('' + window.localStorage.getItem('emailgrcg')).replace(/^null$/g,'').replace(/^undefined$/g,'');
if (defemail.indexOf(defemail.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('emailgrcg'); }
} else if (defemail.indexOf(defemail.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('emailgrcg'); }
window.localStorage.setItem('emailgrcg', defemail.trim());
} else if (defemail == '' && wasv.trim() != '') {
return wasv;
}
return defemail;
}

function smsit() {
var smsno=savesms(smsee);
if (smsno.trim() != '' && smsno.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
smsno=prompt('Please enter SMS number. Add space to remember or more than three to unremember.', smsno);
} else {
smsno=prompt('Please enter SMS number. Add space to remember or more than three to unremember.', '');
}
if (smsno != null) {
if (smsno.trim() != '' && smsno.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
if (smsno != smsno.trim()) { smssave(smsno); }
if (smsee == '') { smsee=smsno.trim(); }
document.getElementById('asms').href='sms:' + smsno.trim() + '&' + document.getElementById('asms').href.split('&')[1];
document.getElementById('asms').click();
}
}
}

function emailit() {
var emailaddr=saveemail(emailee);
if (emailaddr.indexOf('@') != -1) {
emailaddr=prompt('Please enter Email address. You can comma separate a list. Add space to remember or more than three to unremember.', emailaddr);
} else {
emailaddr=prompt('Please enter Email address. You can comma separate a list. Add space to remember or more than three to unremember.', '');
}
if (emailaddr != null) {
if (emailaddr.indexOf('@') != -1) {
if (emailaddr != emailaddr.trim()) { saveemail(emailaddr); }
if (emailee == '') { emailee=emailaddr.trim(); }
document.getElementById('aemail').href='mailto:' + emailaddr.trim() + '?' + document.getElementById('aemail').href.split('?')[1];
//alert(document.getElementById('aemail').href);
document.getElementById('aemail').click();
}
}
}

… should they click on their email’s game link in our changed gradual_reveal_country_game.html‘s Bearing and/or Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Bearing Game Tutorial is shown below.

Javascript Lazy Evaluation Crow Fly Game Tutorial

Javascript Lazy Evaluation Bearing Game Tutorial

Let’s just suppose you’ve got a “hardy crow” (like those in Javascript Lazy Evaluation Crow Fly Game Tutorial) and it doesn’t mind “a bit of chill” on occasions. To minimize the distance it flies to get to a given destination in that shortest distance (or “great circle distance” discussed yesterday) it needs to set out at a particular bearing (or direction) where zero degrees is North and ninety degrees is East and 3 degrees? Glad you asked!

With this bearing being able to be calculated …


function great_circle_bearing(talis, gnolis, latis, longis) {
// Let ‘R’ be the radius of Earth,
// ‘L’ be the longitude,
// ‘θ’ be latitude,
// ‘β‘ be Bearing.

// Bearing from point A to B, can be calculated as,
// β = atan2(X,Y),
// where, X and Y are two quantities and can be calculated as:
// X = cos θb * sin ∆L
// Y = cos θa * sin θb – sin θa * cos θb * cos ∆L

var ourbrg=eval(eval(360.0 + eval(eval(eval(180.0 / Math.PI) * Math.atan2(
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + latis))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval(eval('' + longis) - eval('' + gnolis))))),
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + talis))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + latis)))) -
eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + talis))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + latis))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval(eval('' + longis) - eval('' + gnolis)))))
)))) % 360.0);

return '' + ourbrg;
}

… it gave us an idea for a …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… game to add to

  • Country Capitals Game
  • In the Hour Game
  • Languages Game
  • In the Timestamp Game
  • Geographicals Game
  • Crow Fly Game … and today we present …
  • Bearing Game

… our games mode list, further to yesterday’s Javascript Lazy Evaluation Crow Fly Game Tutorial. Like yesterday, we think you’ll find this game a challenge!

Again, feel free to try out our changed gradual_reveal_country_game.html‘s Bearing and/or Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Crow Fly Game Tutorial is shown below.

Javascript Lazy Evaluation Crow Fly Game Tutorial

Javascript Lazy Evaluation Crow Fly Game Tutorial

To be a crow on the Mercator Projection is to be the “moron” in oxymoron. Yes, have a read of Why is the ‘straight line’ path across continent so curved? Or do they have a “shot of Mercator” and move this way? Well, we’re not asking the class, this time!

But those distances of that direct way crows allegedly fly is able to be calculated …


function great_circle_distance(talis, gnolis, latis, longis) {
var ourdist=0.0;
var rgnol=eval((gnolis) * Math.PI / 180.0);
var rtal=eval((talis) * Math.PI / 180.0);
var rlong=eval((longis) * Math.PI / 180.0);
var rlat=eval((latis) * Math.PI / 180.0);
var deltalong = Math.abs(eval(((gnolis)-(longis)) * Math.PI / 180.0));
var acof = eval(Math.sin(rtal) * Math.sin(rlat)) + (Math.cos(rtal) * Math.cos(rlat) * Math.cos(deltalong)); // via //en.wikipedia.org/wiki/Great-circle_distance ... thanks
ourdist = eval(Math.round((Math.acos(acof) * 6371000.0) + 0.00001) * 100) / 100;
return '' + ourdist;
}

… and forms the basis of our latest game

  • Country Capitals Game
  • In the Hour Game
  • Languages Game
  • In the Timestamp Game
  • Geographicals Game … and today we present …
  • Crow Fly Game

… in the …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… series, whereby a user is presented with a draggable piece of text such as …

14446.128 kilometers from Mogadishu of Somalia

… and the user, to score, is asked to drop this text into the appropriate one of the nine table cells displayed below.

We think this is pretty hard, but am sure there are experts out there who can score well in this game mode?!

And so, further to yesterday’s Javascript Lazy Evaluation Geographicals Game Tutorial, feel free to try out our changed gradual_reveal_country_game.html‘s Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Geographicals Game Tutorial is shown below.

Javascript Lazy Evaluation Geographicals Game Tutorial

Javascript Lazy Evaluation Geographicals Game Tutorial

Today, we’ve arrived back at our …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… blog posting thread we last visited with the recent Javascript Lazy Evaluation Timestamp Game Tutorial. Why? Well, there are more geography quiz ways to allow for an interesting learning experience should world geography be your thaing!

Today’s premise for a new option to our last talked about game type list of …

  • Country Capitals Game
  • In the Hour Game … and today we introduce the …
  • Languages Game … snapshot of main dropdown functionality choices, today, we add …
  • In the Timestamp Game

… is a “Geographicals Game”. In other words, just present a


Longitude,Latitude

… pairing that falls within one of the Country Google Geo Chart maps presented in one of the nine table cells displayed below. Simple as falling off a log, really. But if you want to make it more challenging for yourself, use a rhythm method to solve a logarithm (ever so small chortle, chortle).

These days, online, you are probably used to seeing Geographicals presented as decimal degree Longitude,Latitude or vice versa, but we add a touch of interest by turning those decimal degree Geographicals into entries like …


58°35'00" E , 23°36'00.00" N

… as a notation navigators and aviators and astronomers and surveyors and Wikipedia readers and others would be quite at home with …


function aslongfollowslat(inllstr) {
var latdir=' N', longdir=' E';
var latd=0, longd=0;
var latm=0, longm=0;
var lats=0.0, longs=0.0;
var latrest=0.0, longrest=0.0;
var insg='';


var lls=inllstr.split(',');
if (eval('' + lls.length) >= 2) {
if (lls[0].indexOf('+') != -1) {
lls[0]=lls[0].replace('+','');
} else if (lls[0].indexOf('-') != -1) {
latdir=' S';
lls[0]=lls[0].replace('-','');
}
latd=lls[0].split('.')[0];
latrest=eval('0.' + (lls[0] + '.0').split('.')[1]);
latm=Math.floor(latrest * 60);
lats=eval((latrest * 3600) - Math.floor(latm * 60)).toPrecision(3);
if (lats >= 60.0) {
latm++;
lats-=60.0;
if (latm >= 60) {
latd++;
latm-=60;
}
}
if (lls[1].indexOf('+') != -1) {
lls[1]=lls[1].replace('+','');
} else if (lls[1].indexOf('-') != -1) {
longdir=' W';
lls[1]=lls[1].replace('-','');
}
longd=lls[1].split('.')[0];
longrest=eval('0.' + (lls[1] + '.0').split('.')[1]);
longm=Math.floor(longrest * 60);
longs=eval((longrest * 3600) - Math.floor(longm * 60)).toPrecision(3);
if (longs >= 60.0) {
longm++;
longs-=60.0;
if (longm >= 60) {
longd++;
longm-=60;
}
}

return ('' + longd + '&#176;' + ('0' + longm).slice(-2) + "'" + ('0' + longs).split('.')[0].slice(-2) + ((('' + longs).indexOf('.') != -1) ? ('.' + ('' + longs).split('.')[1].split('00000')[0]) : '') + '" ' + longdir + ' , ' + latd + '&#176;' + ('0' + latm).slice(-2) + "'" + ('0' + lats).split('.')[0].slice(-2) + ((('' + lats).indexOf('.') != -1) ? ('.' + ('' + lats).split('.')[1].split('00000')[0]) : '') + '" ' + latdir).replace(/\.\"/g, '"');

}
return inllstr;
}

… and which we’ve often wondered why the Standards Boards never got to, to rather show angles in a decimal way, as distinct from this degrees, minutes and seconds methodology?! For some clues, you might want to read the excellent Longitude book.

Feel free to try out this new Geographicals Game with our changed gradual_reveal_country_game.html‘s Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Timestamp Game Tutorial is shown below.

Javascript Lazy Evaluation Timestamp Game Tutorial

Javascript Lazy Evaluation Timestamp Game Tutorial

Where does your “good value” index lie? We ask, because an underlying principle of this blog, is that we are most interested in online facilities that are free. Always have been. Always will be. Let me talk about a few
examples in this blog posting thread, those being …

  • Wikipedia … encyclopaedic data …
  • Google Geo Chart … map data …
  • emojis … are a free resource, out there on the net, helping out we “graphically challenged” content producers … thanks, whoever … and today, we’ve been interested before, but today, we go further, regarding the free aspects to …
  • Internationalization … in the online world, thanks … today acting a tad like a free language translator … albeit …

… just for date timestamps, only. Still, and all, these generous arrangements online, should be applauded. Thanks, peepholespeople! Of course, there should be more of them, but to discover some of them, allows for that “added joy of discovery” stumbling upon what is possible, for free, out there!

And so, adding onto yesterday’s Javascript Lazy Evaluation Languages Game Tutorial‘s …

  • Country Capitals Game
  • In the Hour Game … and today we introduce the …
  • Languages Game … snapshot of main dropdown functionality choices, today, we add …
  • In the Timestamp Game

… as a hybrid between …

  • In the Hour Game … regarding its “when” datetime arrangements and …
  • Languages Game … regarding its “locale” smarts … we add to

    function getnextcountrycode(inforce) {
    var ccr='', sccr='', wasccr='', interimh=0, thiscc='', lno=0, ctylist=[], irx=0, myccis='', ijk=0;
    if (eval('' + ccodes.length) < 9) {
    var mycc=document.getElementById('myctable').innerHTML;
    var opts=document.getElementsByTagName('option'), longis='', latis='';
    var ths=document.getElementsByTagName('th');

    if (goodatry > 0 && inforce != 0 && eval(1 + eval('' + cplaces.length)) == Math.abs(inforce)) {
    //alert(gproposedanswer + ' vs ' + cplaces.length);
    atry=goodatry;
    optfinds+=opts[eval('' + atry)].value + ' ';
    ccodes.push(opts[eval('' + atry)].value);
    cnames.push(opts[eval('' + atry)].innerText);
    ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
    subfroms.push('[-89.0000|-88.0000|~From~,2]');
    goodatry=eval(-1 * Math.abs(goodatry));
    //sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
    tzas.push(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]);
    interimh=eval(eval(eval(eval('' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24);
    if (uhour < interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') != -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(-1); }
    } else if (uhour > interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') == -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(1); }
    } else {
    for (ijk=1; ijk<=9; ijk++) { doff.push(0); }
    }
    if (gcinthehourspush != '') {
    cinthehours.push(gcinthehourspush);
    gcinthehourspush='';
    } else {
    cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
    }
    //var newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    //alert(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0] + ': ' + newd + ' vs ' + cinthehours[eval(-1 + cinthehours.length)]);
    thiscc=opts[eval('' + atry)].value;
    lastsubtos='[' + yourtzlist.split(',' + thiscc + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + thiscc + ',')[0].split('"').length)].split(',')[0] + '|' + yourtzlist.split(',' + thiscc + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + thiscc + ',')[0].split('"').length)].split(',')[1] + '|~' + encodeURIComponent(yourtzlist.split(',' + thiscc + ',')[1].split('"')[1].split('>')[1].split('<')[0].replace(yourtzlist.split(',' + thiscc + ',')[1].split('"')[1].split('>')[1].split('<')[0].split('/')[0] + '/', '').replace(/\_/g,' ')) + '~,2]';
    subtos.push(lastsubtos);
    cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
    if (drilldown == 'lang') {
    sofarlang+=rellang + ' ';
    if (gcrellang != '') {
    clangs.push(gcrellang);
    clanges.push(gcrellange);
    clangkbs.push(gcrellangkb.replace('-','_'));
    cinintl.push('' + gcreldatenow);
    gcrellang='';
    gcrellangkb='';
    //gcreldatenow='';
    } else {
    clangs.push(rellang);
    clanges.push(lastengl);
    clangkbs.push(rellangkb.replace('-','_'));
    cinintl.push(('' + reldatenow));
    }
    //alert(rellang + ' is spoken in country ' + opts[eval('' + atry)].innerText);
    } else {
    clangs.push('');
    clanges.push('');
    clangkbs.push('');
    cinintl.push('');
    }
    return '';
    }

    if (optslength < 0) {
    for (iii=0; iii<opts.length; iii++) {
    if (('' + opts[iii].value).indexOf(',') != -1 && optslength < 0) { optslength=eval(-1 + iii); }
    }
    if (optslength < 0) { optslength=eval('' + opts.length); }
    }
    var atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
    atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    }
    while (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') == -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
    atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    if (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') != -1) {
    while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
    atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    }
    }
    }
    if (!simple) {
    if (drilldown == 'lang') {
    sofarlang+=rellang + ' ';
    clangs.push(rellang);
    clangs.push(lastengl);
    clangkbs.push(rellangkb.replace('-','_'));
    //alert(rellang + ' is spoken in country ' + opts[eval('' + atry)].innerText);
    } else {
    clangs.push('');
    clanges.push('');
    clangkbs.push('');
    }
    optfinds+=opts[eval('' + atry)].value + ' ';
    ccodes.push(opts[eval('' + atry)].value);
    cnames.push(opts[eval('' + atry)].innerText);
    ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
    subfroms.push('[-89.0000|-88.0000|~From~,2]');
    ccr=ccapitals[eval(-1 + ccapitals.length)];
    wasccr=ccr;
    sccr=document.getElementById('spops').innerHTML;
    if (!document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20'))) {
    while (eval('' + ccr.length) > 4 && eval('' + sccr.split(' id="' + ccr).length) != 2) {
    ccr=ccr.substring(0, eval(-1 + eval('' + ccr.length)));
    }
    if (ccr != wasccr && eval('' + ccr.length) > 4 && eval('' + sccr.split(' id="' + ccr).length) == 2) {
    wasccr=ccr;
    ccr=wasccr + sccr.split(' id="' + ccr)[1].split('"')[0];
    }
    }
    if (document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20'))) {
    longis='' + document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20')).value.split(',')[0].split('|')[0];
    latis='' + document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20')).value.substring(eval(1 + eval('' + longis.length)));
    cplaces.push(latis + '|' + longis);
    subtos.push('[' + cplaces[eval(-1 + cplaces.length)] + '|~' + encodeURIComponent(ccapitals[eval(-1 + ccapitals.length)]).replace(/\_/g,'%20') + '~,2]');
    } else {
    try {
    lastsubtos='[' + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"').length)].split(',')[0] + '|' + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"').length)].split(',')[1] + '|~' + encodeURIComponent(yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[1].split('"')[1].split('>')[1].split('<')[0].replace(yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[1].split('"')[1].split('>')[1].split('<')[0].split('/')[0] + '/', '').replace(/\_/g,' ')) + '~,2]';
    //alert('no ' + lastsubtos);
    lastsubtos=lastsubtos.replace('~]', encodeURIComponent(' near ' + ccapitals[eval(-1 + ccapitals.length)].replace(/\'/g,'')) + '~]');
    cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
    subtos.push(lastsubtos);
    } catch(hggf) {
    cplaces.push('');
    subtos.push('[-89.0000|-88.0000|~From~,2]');
    }
    }
    //doff.push(0);
    chours.push(-99);
    cinthehours.push("");
    cinintl.push("");
    tzas.push("");
    } else {
    if (inforce > 0) {
    goodatry=atry;
    var cinthehourspush=(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
    newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    var newh=eval(('' + newd).split(':')[0].split(' ')[eval(-1 + ('' + newd).split(':')[0].split(' ').length)]);

    nhour = newd.getHours();
    nmin = newd.getMinutes();
    nday = newd.getDay();
    nsec = 0;
    ndate = newd.getDate();
    nmonth = newd.getMonth();
    nyear = newd.getFullYear();
    reldatenow=newd; //new Date(newd.toLocaleString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    //alert('Reldatenow=' + reldatenow);

    if (cinthehourspush.indexOf('' + ('0' + newh).slice(-2)) != 0) {
    var oldh=eval('' + cinthehourspush.split(':')[0]);
    if (oldh != newh) {
    //alert('uhour=' + uhour + ' and oldh=' + oldh + cinthehourspush.substring(2) + ' goes with ' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' and newh=' + newh + cinthehourspush.substring(2));
    if (newh < uhour && newh == 0 && uhour == 23) {
    sofarhrs+='+' + eval(24 - uhour) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert(1);
    } else if (newh > uhour && newh == 23 && uhour == 0) {
    sofarhrs+='-' + eval(24 - newh) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(2);
    } else if (oldh > uhour) {
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(oldh - uhour), '' + eval(newh - uhour)) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1)); // test?
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert('3 ' + sofarhrs + ' newh=' + newh + ' oldh=' + oldh + ' rellangkb=' + rellangkb + ' tz=' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]);
    } else if (oldh < uhour) {
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(uhour - oldh), '' + eval(uhour - newh)) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1)); // test?
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(4);
    } else if (newh < uhour && newh == 0 && uhour == 23) {
    sofarhrs+='+' + eval(24 - uhour) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert(5);
    } else if (newh > uhour && newh == 23 && uhour == 0) {
    sofarhrs+='-' + eval(24 - newh) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(6);
    } else if (newh > uhour) {
    sofarhrs+='+' + eval(newh - uhour) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert(7);
    } else if (newh < uhour) {
    sofarhrs+='-' + eval(uhour - newh) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(8);
    }
    }


    //alert('ReldatenoW=' + newd);
    try {
    nmin = newd.getMinutes();
    nday = newd.getDay();
    nsec = 0;
    ndate = newd.getDate();
    nmonth = newd.getMonth();
    nyear = newd.getFullYear();
    try {
    nhour = newd.getHours();
    } catch(eyyre) {
    nhour = eval('' + newh);
    }
    } catch(esdfgh) {
    }
    gcinthehourspush='' + ('0' + newh).slice(-2) + cinthehourspush.substring(2);
    }
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
    gcrellang='' + rellang;
    gcrellange='' + lastengl;
    gcrellangkb='' + rellangkb;
    //reldatenow=new Date(newd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}) + newd.toLocaleTimeString());

    var vdate = new Date();
    var now_utc = Date.UTC(vdate.getUTCFullYear(), vdate.getUTCMonth(),
    vdate.getUTCDate(), vdate.getUTCHours(),
    vdate.getUTCMinutes(), 0, 0);
    //alert(vdate.toISOString());
    //newd = new Date(new Date(now_utc).toLocaleString("en-US", {timeZone: 'UTC'}));
    newd = new Date(vdate.toLocaleString("en-US", {timeZone: 'UTC'}));
    //alert('' + newd + ' vdate=' + vdate);
    //newd = new Date(new Date(now_utc).toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    // Sun Oct 15 2023 04:59:00 GMT+1100
    // 2020-04-13T00:00:00.000+08:00
    // 2023-10-15T07:12:00.000+11:00
    //alert('' + newd + ' ... ' + ('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + ('0' + ('' + newd).split(' ')[4].split(':')[0]).slice(-2) + cinthehourspush.substring(2) + ':00.000' + ('' + newd).split(' GMT')[1].substring(0,3) + ':' + ('' + newd).split(' GMT')[1].substring(3).split(' (')[0]);
    var zd = new Date(('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + ('0' + newh).slice(-2) + cinthehourspush.substring(2) + ':00.000' + ('' + newd).split(' GMT')[1].substring(0,3) + ':' + ('' + newd).split(' GMT')[1].substring(3).split(' (')[0]);
    //var zd = new Date(('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + ('0' + ('' + newd).split(' ')[4].split(':')[0]).slice(-2) + cinthehourspush.substring(2) + ':00.000-13' + ':' + ('' + newd).split(' GMT')[1].substring(3).split(' (')[0]);
    //alert('' + newd + ' zd.getDay()=' + zd.getDay() + ' newd.getDay()=' + newd.getDay());
    //alert(('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + gcinthehourspush + ':00.000' + ('' + newd).split(' GMT')[1].substring(0,2) + ':' + ('' + newd).split(' GMT')[1].substring(2) + ' ... zd=' + zd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    //zd.toLocaleString('en-US', { timeZone: 'America/New_York' })
    if (1 == 7) {
    if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('sun') == 0) {
    dotwi=0;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('mon') == 0) {
    dotwi=1;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('tue') == 0) {
    dotwi=2;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('wed') == 0) {
    dotwi=3;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('thu') == 0) {
    dotwi=4;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('fri') == 0) {
    dotwi=5;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('sat') == 0) {
    dotwi=6;
    }
    }

    var ourloc=rellangkb.replace('_','-');
    //alert(ourloc);
    //alert(zd.toLocaleTimeString(rellangkb.replace('_','-')));
    //reldatenow='' + (zd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + ' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'));
    reldatenow='' + ((new Date(now_utc)).toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + ' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'));
    //reldatenow='' + ((new Date(vdate.toISOString())).toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + ' ' + (new Date(vdate.toISOString())).toLocaleTimeString(rellangkb.replace('_','-'));
    //alert('' + reldatenow);
    // ud.toLocaleDateString('de-DE', options), {timeZone: 'Australia/Sydney'}
    //gcreldatenow='' + ( (new Date(now_utc)).toLocaleString('ja-JP', options, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + (' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'), optionstime, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}).substring(0,1));
    gcreldatenow='' + ( (new Date(now_utc)).toLocaleDateString(ourloc, options, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + (' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'), optionstime, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    return '';
    }
    if (drilldown == 'lang') {
    sofarlang+=rellang + ' ';
    clangs.push(rellang);
    clanges.push(lastengl);
    clangkbs.push(rellangkb.replace('-','_'));
    cinintl.push('' + reldatenow);
    //alert(rellang + ' is spoken in country ' + opts[eval('' + atry)].innerText);
    } else {
    clangs.push('');
    clanges.push('');
    clangkbs.push('');
    cinintl.push('');
    }
    optfinds+=opts[eval('' + atry)].value + ' ';
    ccodes.push(opts[eval('' + atry)].value);
    cnames.push(opts[eval('' + atry)].innerText);
    ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
    subfroms.push('[-89.0000|-88.0000|~From~,2]');
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
    tzas.push(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]);
    if (1 == 8) {
    interimh=eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24);
    if (uhour < interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') != -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(-1); }
    } else if (uhour > interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') == -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(1); }
    } else {
    for (ijk=1; ijk<=9; ijk++) { doff.push(0); }
    }
    }
    cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
    subtos.push(lastsubtos);
    cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
    }
    }
    //}

    if (eval('' + cinthehours.length) >= 9) {
    console.log(cinthehours);
    console.log(cplaces);
    console.log(ccodes);
    console.log(cnames);
    console.log(ccapitals);
    console.log(subfroms);
    console.log(subtos);
    console.log(sofarhrs);
    }

    }

… logics, asking the user to match a …

  • datetime snapshot in time “time” value … and …
  • datetime “locale” presentation

… to combine as a way a “timestamp drag element” can be dragged to an appropriate “drop country iframe Geo Chart map content” correct answer element, in order for a user to score, in our new “In the Timestamp” game incarnation, involving new “but” code …


function nocaret(inx) {
if (inx.indexOf('<') != -1) {
document.getElementById('dspare').innerHTML=inx;
return document.getElementById('dspare').innerText;
} else {
return inx;
}
}

function appblurb(ontowhat) {
if (curblurb == '') { return '' + ontowhat; }
return '' + ontowhat + String.fromCharCode(10) + String.fromCharCode(10) + nocaret(('' + curblurb)) + String.fromCharCode(10) + String.fromCharCode(10);
}

function mybutclick(selo) {
var suffix='';
if (selo.value == '') {
if (simple) { document.getElementById('mybut').click(); }
} else {
they=selo.value;
//if (!simple) { document.getElementById('mybut').click(); }
if (document.URL.indexOf('?') == -1) { suffix='?simple=' + drilldown; } else if (document.URL.indexOf('simple=') == -1) { suffix='&simple=' + drilldown; }
location.href=(document.URL.split('#')[0] + suffix).replace('simple=' + drilldown, 'simple=' + they);
drilldown=they;
}
}

function butrand(asify) {
var myccis='', lno=0, irx=0, ctylist=[], jrx=-1;
var opts=[];
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
if (drilldown.replace(/^Y/g,'lang') == 'lang') {
opts=document.getElementsByTagName('option');
while (jrx == -1) {
lno=Math.floor(Math.random() * 59);
document.getElementById('select_language').value='' + lno;
updateCountry();
rellang=document.getElementById('select_language').innerHTML.split(' value="' + lno + '">')[1].split('<')[0];
ctylist=document.getElementById('select_dialect').innerHTML.split('-');
jrx=eval(1 + Math.floor(Math.random() * eval(-1 + ctylist.length)));
myccis=ctylist[jrx].split('"')[0];
//alert(myccis + ' ... ' + opts[0].value + ' +++ ' + ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)] + '-' + myccis);
for (irx=0; irx<optslength; irx++) {
//alert(opts[irx].value + ' vs ' + myccis);
if (opts[irx].value == myccis) { atry=irx; rellangkb=butviacml(ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)]) + '_' + myccis; try { reldatenow=new Date(newd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}) + ' ' + newd.toLocaleTimeString(rellangkb.replace('_','-'))); } catch(ertsd) { reldatenow=null; } return atry; }
}
jrx=-1;
}
}
}
}
return asify;
}

function butviacml(inlcode) {
var bparts=cmylang.split('>' + inlcode + '<');
lastengl='';
if (eval('' + bparts.length) > 1) {
var nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
if (eval('' + nextcell.length) <= 3) {
bparts=cmylang.split('>' + nextcell + '<');
nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
lastengl=nextcell;
} else {
lastengl=nextcell;
}
}
return inlcode;
}

function butmaybeisspokenin(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
//alert(cnames[eval(-1 + answer)] + ' language spot on=' + clangs[eval(-1 + answer)] + ' language one on on=' + clangs[eval(0 + answer)] + ' language one back on=' + clangs[eval(-2 + answer)]);
return asify.replace('en_AU', clangkbs[eval(-1 + answer)]) + ' is spoken ';
}
}
return asify;
}

function butmaybe(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
//alert('answer=' + answer + ' and gproposedanswer=' + gproposedanswer);
if (document.getElementById('selmode').value == 'Y') {
return gcreldatenow; // + ' ' + clangkbs[eval(-1 + answer)]; //'English';
} else {
if (clanges[eval(-1 + answer)] == '') {
document.getElementById('source').title='';
lasthome='';
document.getElementById('source').oncontextmenu=function(){ homelang=homelang; };
} else {
document.getElementById('source').title='Right click to reveal language name in English';
lasthome=clanges[eval(-1 + answer)];
document.getElementById('source').oncontextmenu=function(){ alert(lasthome); };
}
return clangs[eval(-1 + answer)]; //'English';
}
}
}
return asify;
}

function butmaybeno(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
return '';
}
}
return asify;
}

function butmaybenone(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
return '';
}
}
return asify;
}

function butthen(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game wants you to drag a spoken Language (appearing later) to table cell with a Country map where that language is spoken.';
} else if (document.getElementById('selmode').value == 'lang') {
return 'In the Timestamp Game wants you to drag a Timestamp presented in that regional way (appearing later) to table cell with a Country map where that timestamp format is familiar and the time is just after the correct local time.';
}
}
return asify;
}

function butthentwo(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game';
} else if (document.getElementById('selmode').value == 'lang') {
return 'In the Timestamp Game';
}
}
return asify;
}

function ouronl() {
if (itblurb != '') {
document.getElementById('myh3').innerHTML+=' ... ' + itblurb;
}
cmylang=document.getElementById('mylangt').innerHTML;
if (drilldown != '') { document.getElementById('selmode').value=drilldown; }
for (var i = 0; i < langs.length; i++) {
select_language.options[i] = new Option(langs[i][0], i);
}
// Set default language / dialect ... thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
select_language.selectedIndex = 10;
updateCountry();
select_dialect.selectedIndex = 11;
showInfo('info_start');
}

function showInfo(s) { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
if (s) {
for (var child = info.firstChild; child; child = child.nextSibling) {
if (child.style) {
child.style.display = child.id == s ? 'inline' : 'none';
}
}
//info.style.visibility = 'visible';
} else {
info.style.visibility = 'hidden';
}
}

function updateCountry() { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
for (var i = select_dialect.options.length - 1; i >= 0; i--) {
select_dialect.remove(i);
}
var list = langs[select_language.selectedIndex];
for (var i = 1; i < list.length; i++) {
select_dialect.options.add(new Option(list[i][1], list[i][0]));
}
select_dialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible';
}

… with our changed gradual_reveal_country_game.html‘s In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Languages Game Tutorial is shown below.

Javascript Lazy Evaluation Languages Game Tutorial

Javascript Lazy Evaluation Languages Game Tutorial

Now that we have three game modes, further to the recent Javascript Lazy Evaluation Game Scroll Into View Tutorial, with …

  • Country Capitals Game
  • In the Hour Game … and today we introduce the …
  • Languages Game

… the HTML button element “traffic cop” for this, up to now, is given a rest, in favour of a new HTML “select” (ie. dropdown) element that is much better equipped for scenarios of more than two choices.

The “Languages Game” concept would be really simple if every country had one spoken language, but the world does not work this way. But, do you remember when we last presented Fairy Story Chrome Dictation Punctuation Tutorial? There, we were referencing Text to Speech software that Google has demonstrated at https://www.google.com/intl/en/chrome/demos/speech.html (for you Google Chrome users out there). Well, it’s full of great ideas regarding …

  • the mapping of a given Language name (along with its associated code) … to …
  • one or more locales

    In computing, a locale is a set of parameters that defines the user’s language, region and any special variant preferences that the user wants to see in their user interface. Usually a locale identifier consists of at least a language code and a country/region code. Locale is an important aspect of i18n.

… and this forms the basis of how we might map a language code back to a country code, for our Languages Game today.

Take a look at some new Javascript to help here …


function mybutclick(selo) {
var suffix='';
if (selo.value == '') {
if (simple) { document.getElementById('mybut').click(); }
} else {
they=selo.value;
//if (!simple) { document.getElementById('mybut').click(); }
if (document.URL.indexOf('?') == -1) { suffix='?simple=' + drilldown; } else if (document.URL.indexOf('simple=') == -1) { suffix='&simple=' + drilldown; }
location.href=(document.URL.split('#')[0] + suffix).replace('simple=' + drilldown, 'simple=' + they);
drilldown=they;
}
}

function butrand(asify) {
var myccis='', lno=0, irx=0, ctylist=[], jrx=-1;
var opts=[];
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
if (drilldown == 'lang') {
opts=document.getElementsByTagName('option');
while (jrx == -1) {
lno=Math.floor(Math.random() * 59);
document.getElementById('select_language').value='' + lno;
updateCountry();
rellang=document.getElementById('select_language').innerHTML.split(' value="' + lno + '">')[1].split('<')[0];
ctylist=document.getElementById('select_dialect').innerHTML.split('-');
jrx=eval(1 + Math.floor(Math.random() * eval(-1 + ctylist.length)));
myccis=ctylist[jrx].split('"')[0];
//alert(myccis + ' ... ' + opts[0].value + ' +++ ' + ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)] + '-' + myccis);
for (irx=0; irx<optslength; irx++) {
//alert(opts[irx].value + ' vs ' + myccis);
if (opts[irx].value == myccis) { atry=irx; rellangkb=butviacml(ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)]) + '_' + myccis; return atry; }
}
jrx=-1;
}
}
}
}
return asify;
}

function butviacml(inlcode) {
var bparts=cmylang.split('>' + inlcode + '<');
lastengl='';
if (eval('' + bparts.length) > 1) {
var nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
if (eval('' + nextcell.length) <= 3) {
bparts=cmylang.split('>' + nextcell + '<');
nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
lastengl=nextcell;
} else {
lastengl=nextcell;
}
}
return inlcode;
}

function butmaybeisspokenin(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
//alert(cnames[eval(-1 + answer)] + ' language spot on=' + clangs[eval(-1 + answer)] + ' language one on on=' + clangs[eval(0 + answer)] + ' language one back on=' + clangs[eval(-2 + answer)]);
return asify.replace('en_AU', clangkbs[eval(-1 + answer)]) + ' is spoken ';
}
}
return asify;
}

function butmaybe(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
//alert('answer=' + answer + ' and gproposedanswer=' + gproposedanswer);
if (clanges[eval(-1 + answer)] == '') {
document.getElementById('source').title='';
lasthome='';
document.getElementById('source').oncontextmenu=function(){ homelang=homelang; };
} else {
document.getElementById('source').title='Right click to reveal language name in English';
lasthome=clanges[eval(-1 + answer)];
document.getElementById('source').oncontextmenu=function(){ alert(lasthome); };
}
return clangs[eval(-1 + answer)]; // + ' ' + clangkbs[eval(-1 + answer)]; //'English';
}
}
return asify;
}

function butmaybeno(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return '';
}
}
return asify;
}

function butmaybenone(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return '';
}
}
return asify;
}

function butthen(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game wants you to drag a spoken Language (appearing later) to table cell with a Country map where that language is spoken.';
}
}
return asify;
}

function butthentwo(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game';
}
}
return asify;
}

function ouronl() {
cmylang=document.getElementById('mylangt').innerHTML;
if (drilldown != '') { document.getElementById('selmode').value=drilldown; }
for (var i = 0; i < langs.length; i++) {
select_language.options[i] = new Option(langs[i][0], i);
}
// Set default language / dialect ... thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
select_language.selectedIndex = 10;
updateCountry();
select_dialect.selectedIndex = 11;
showInfo('info_start');
}

function showInfo(s) { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
if (s) {
for (var child = info.firstChild; child; child = child.nextSibling) {
if (child.style) {
child.style.display = child.id == s ? 'inline' : 'none';
}
}
//info.style.visibility = 'visible';
} else {
info.style.visibility = 'hidden';
}
}

function updateCountry() { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
for (var i = select_dialect.options.length - 1; i >= 0; i--) {
select_dialect.remove(i);
}
var list = langs[select_language.selectedIndex];
for (var i = 1; i < list.length; i++) {
select_dialect.options.add(new Option(list[i][1], list[i][0]));
}
select_dialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible';
}

… with our changed gradual_reveal_country_game.html‘s Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Game Scroll Into View Tutorial is shown below.

Javascript Lazy Evaluation Game Scroll Into View Tutorial

Javascript Lazy Evaluation Game Scroll Into View Tutorial

Within the changes involved in the recent Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial you may have seen the change


if (window.self !== window.top) { answer=answer; } else { document.getElementById('source').scrollIntoView(); }

What is the motivation for that change? Well, if a blog posting contains an HTML iframe pointing at our latest Country Capital or In the Hour Game web application, it would annoyingly scroll down to the webpage position of element document.getElementById(‘source’) in that iframe without the user having clicked any buttons. Dead annoying!

But then, can this same idea, or a similar scrolling equivalence help us out sometimes, on the other side of the coin? Well, yes, and that ability, encapulated in the logic of two clonish dropdowns …

  • one dropdown up the top of the webpage … and another “clone” …
  • dropdown to right in the middle of the table heightwise, roughly, as a position:fixed

    function overtoright(inspano) {
    if (window.self !== window.top) { answer=answer; } else {
    var rectxo=document.getElementById('mytable').getBoundingClientRect();
    inspano.style.position='fixed';
    inspano.style.left='' + eval(10 + eval('' + rectxo.right)) + 'px'; //'' + eval(-20 + screen.width) + 'px';
    inspano.style.top='' + Math.floor(eval(rectxo.top + rectxo.bottom) / 2) + 'px';
    inspano.style.zIndex='99';
    inspano.style.display='inline-block';
    }
    return inspano;
    }

    … element, so as to be within view more often

… helping to offer …

  • scrolling positional possibilities, as above … is timely way to be able to help out …
  • Geo Chart iframe scaling of itself and its contents …

    function siv(selo) {
    var ijk=0, ifsz=[], newishw=0, newishh=0;
    if (('' + selo.value).trim() != '') {
    if (('' + selo.value).trim() == '0') {
    window.scrollTo(0,0);
    } else if (('' + selo.value).trim() == '++') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) * 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) * 1.1)) + 'px';
    newishw=ifsz[ijk].src.split('width=')[1].split('&')[0];
    newishh=ifsz[ijk].src.split('height=')[1].split('&')[0];
    ifsz[ijk].src=ifsz[ijk].src.replace('width=' + newishw, 'width=' + Math.floor(eval(1.1 * eval('' + newishw)))).replace('height=' + newishh, 'height=' + Math.floor(eval(1.1 * eval('' + newishh))));
    }
    }
    } else if (('' + selo.value).trim() == '--') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) / 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) / 1.1)) + 'px';
    newishw=ifsz[ijk].src.split('width=')[1].split('&')[0];
    newishh=ifsz[ijk].src.split('height=')[1].split('&')[0];
    ifsz[ijk].src=ifsz[ijk].src.replace('width=' + newishw, 'width=' + Math.floor(eval(eval('' + newishw) / 1.1))).replace('height=' + newishh, 'height=' + Math.floor(eval(eval('' + newishh) / 1.1)));
    }
    }
    } else if (('' + selo.value).trim() == '+') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) * 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) * 1.1)) + 'px';
    }
    }
    } else if (('' + selo.value).trim() == '-') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) / 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) / 1.1)) + 'px';
    }
    }
    } else {
    window.scrollTo(stoisleft[eval(-1 + eval('' + selo.value))], stoistop[eval(-1 + eval('' + selo.value))]);
    stos[eval(-1 + eval('' + selo.value))].scrollIntoView();
    }
    }
    }

Behind the scenes, we won’t say here exactly, but there is another Hint piece of logic activated. We’ll just say Map as an element to look for, as a first idea in a two part Hint mechanism?!

Yet again, we hope you try the changed gradual_reveal_country_game.html‘s Country Capital and/or In the Hour Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial is shown below.

Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial

Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial

Regarding yesterday’s Javascript Lazy Evaluation Country Game Hints Tutorial progress with the “In the Hour” mode of game play, we thought there would only be the rare annoyance regarding Daylight Saving alterations to the default timezone offsets to GMT time, but there were more than we realized, prompting us to start using codelines like …


var newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));

… to start working out timezone offsets in the client world (as you may remember us discussing with SVG Network Clock Minimize Tutorial in recent times) checking on those PHP timezone derivations we default to, but might be wrong by an hour, regarding Daylight Saving timezone arrangements in place for certain times of the year in some countries …


var cinthehourspush=(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
var newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
var newh=eval(('' + newd).split(':')[0].split(' ')[eval(-1 + ('' + newd).split(':')[0].split(' ').length)]);
if (cinthehourspush.indexOf('' + ('0' + newh).slice(-2)) != 0) {
var oldh=eval('' + cinthehourspush.split(':')[0]);
if (oldh != newh) {
//alert('uhour=' + uhour + ' and oldh=' + oldh + cinthehourspush.substring(2) + ' goes with ' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' and newh=' + newh + cinthehourspush.substring(2));
if (newh < uhour && newh == 0 && uhour == 23) {
sofarhrs+='+' + eval(24 - uhour) + ' ';
} else if (newh > uhour && newh == 23 && uhour == 0) {
sofarhrs+='-' + eval(24 - newh) + ' ';
} else if (oldh > uhour) {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(oldh - uhour), '' + eval(newh - uhour)) + ' ';
} else if (oldh < uhour) {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(uhour - oldh), '' + eval(uhour - newh)) + ' ';
} else if (newh > uhour) {
sofarhrs+='+' + eval(newh - uhour) + ' ';
} else if (newh < uhour) {
sofarhrs+='-' + eval(uhour - newh) + ' ';
}
}
gcinthehourspush='' + ('0' + newh).slice(-2) + cinthehourspush.substring(2);
}

We’ve also added in more linking that adds on to yesterday’s existant …

  • Placename links to Wikipedia … so that now we also have …
  • Country links to Wikipedia … and …
  • TimeZone information links added to the “just after” times shown

Also added, today, is another hint, we’ve called “Regions”, which colour codes Geo Charts (albeit in a subtle way) according to those Regional first words in a TimeZone name like …


Asia/Singapore

… where that “Asia” is differentiated via our new arrays …


var rcolmaps=['Africa','Asia','Europe','GMT','America','Pacific','Arctic','Atlantic','Indian','Australia','Antarctica'];
var rcolmapred=['15','45','55','55','75','85','95','a5','b5','d5','e5'];

We also thought “right now” was a bit of a waste of time, when we could show the user (a phrase like) “on Monday” (ie. on day of the week).

And so, yet again, we hope you try the changed gradual_reveal_country_game.html‘s Country Capital and/or In the Hour Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation Country Game Hints Tutorial is shown below.

Javascript Lazy Evaluation Country Game Hints Tutorial

Javascript Lazy Evaluation Country Game Hints Tutorial

Ideally, yesterday’s Javascript Lazy Evaluation Country In the Hour Game Tutorial suits …

  • geography buffs … all the way through to …
  • geography students

… alike. Or at least we’d like to help this be so, and in that respect we decided to offer two modes of Hints for the Country Game (whether that be Capitals Game or In the Hour Game) play …

  • show country flags (ie. those “combination emojis” for the country flags, derivable from that country’s ISO 2 letter country code) …

    var useflags=location.search.split('flags=')[1] ? true : false;
    useflags=location.search.split('wimgs=')[1] ? true : useflags;

    function checkflags(cbo, cbochecked) {
    if (cbochecked || document.getElementById('wimgs').checked) {
    useflags=true;
    } else {
    useflags=false;
    }
    applyhints('');
    }

    function orflag(thiscc) {
    var ccchar='', ccsuff='';
    var lri='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var dri=['127462','127463','127464','127465','127466','127467','127468','127469','127470','127471','127472','127473','127474','127475','127476','127477','127478','127479','127480','127481','127482','127483','127484','127485','127486','127487'];
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+=String.fromCodePoint(eval('' + dri[eval('' + lri.indexOf(ccchar))])); //'&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    return ccsuff;
    }


    function applyhints(towhat) {
    var yt='', nnyt='';
    if (useflags) {
    if (document.getElementById('flags').checked) {
    myflag=orflag(ccodes[eval(-1 + answer)]);
    document.getElementById('source').style.backgroundImage='URL("' + svgtemp.replace('48','96').replace('30%','49%').replace('>1 +', '>' + myflag) + '")';
    document.getElementById('source').style.backgroundPosition='right center';
    document.getElementById('source').style.backgroundRepeat='no-repeat';
    }
    if (document.getElementById('wimgs').checked) {
    if (yourtzlist.indexOf(',' + ccodes[eval(-1 + answer)] + ',') != -1) {
    yt=yourtzlist.split(',' + ccodes[eval(-1 + answer)] + ',')[1].split('>')[1].split('<')[0];
    nnyt=yt.replace(yt.split('/')[0] + '/','');
    //alert(document.getElementById('tzi').src.split('?')[0].split('#')[0] + '?tzexact=' + encodeURIComponent(yt.replace(/\ /g,'_')) + '&tznickname=' + encodeURIComponent( nnyt.replace(/\ /g,'_') ));
    document.getElementById('tzi').src=document.getElementById('tzi').src.split('?')[0].split('#')[0] + '?tzexact=' + encodeURIComponent(yt.replace(/\ /g,'_')) + '&tznickname=' + encodeURIComponent( nnyt.replace(/\ /g,'_') );
    }
    }
    } else {
    document.getElementById('source').style.backgroundImage='';
    document.getElementById('source').style.backgroundRepeat='no-repeat';
    document.getElementById('ourcanvas').style.backgroundImage='';
    document.getElementById('ourcanvas').style.backgroundRepeat='no-repeat';
    }
    return towhat;
    }

    …and/or …
  • Wikipedia images …

    function checkwimgs(cbo, cbochecked) {
    if (cbochecked || document.getElementById('flags').checked) {
    useflags=true;
    } else {
    useflags=false;
    }
    applyhints('');
    }

    function fgcit(iois) {
    var outof=["left top","left center","left bottom","right top","right center","right bottom","center top","center center","center bottom"];
    var startwith='', endwith='', imglist=[];
    if (iois != null) {
    if (iois.src.indexOf('tzexact=') != -1) {
    var aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (aconto.body.outerHTML.replace(/\"\;/g,"'").indexOf("document.getElementById('ourcanvas').style.background") != -1) {
    //document.getElementById('ourcanvas').style.backgroundRepeat='no-repeat';
    startwith="document.getElementById['ourcanvas'].style.background" + aconto.body.outerHTML.replace(/\&\;/g,"&").replace(/\"\;/g,"'").split("document.getElementById('ourcanvas').style.background")[1].split(';')[0] + ';';
    imglist=startwith.split(',');
    for (var jiu=0; jiu<imglist.length; jiu++) {
    if (jiu == 0) {
    endwith=imglist[jiu].trim().replace(/\)/g, ') ' + outof[0] + ' no-repeat').replace('URL(', 'linear-gradient(rgba(255,255,255,0.7),rgba(255,255,255,0.7)),URL(');
    } else {
    endwith+=',' + imglist[jiu].replace(')', ') ' + outof[eval(jiu % outof.length)] + ' no-repeat')
    }
    }
    eval(endwith.replace("document.getElementById['ourcanvas'].", "document.getElementById('ourcanvas')."));
    }
    }
    }
    }
    }
    }

After all, most of us are not destined to visit or travel or tour all these countries, alas!

And so, again, hope you try the changed gradual_reveal_country_game.html‘s Country Capital and/or In the Hour Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation Country In the Hour Game Tutorial is shown below.

Javascript Lazy Evaluation Country In the Hour Game Tutorial

Javascript Lazy Evaluation Country In the Hour Game Tutorial

The “genericization drive” regarding “country map iframe Geo Chart content” has passed us now, as last discussed in yesterday’s Javascript Lazy Evaluation Country Capital Game Context Tutorial, about our …

  • Country Capital Game … and today we start down the road to other game types that could involve “country map iframe Geo Chart content” and came up with a …
  • Country “In the Hour” Game

… whereby a user matches …

  • a “draggable” source time in some country … with …
  • a “droppable intoabletarget “country map iframe Geo Chart content” table cell

… the correct selection of which scores for the game player. You could think of it as a TimeZone Game, perhaps?!

The PHP TimeZone smarts helped derive the huge Javascript variable we now define in the game, and used


var ud = new Date();
var uhour = ud.getUTCHours();
var umin = ud.getUTCMinutes();
var chours=[], cinthehours=[], sofarhrs=' ';



var yourtzlist="<option value=\"GMT\" data-geo=\"51.4934,0.0098,GMT,GB,+0\">GMT</option><option value=\"Africa/Abidjan\" data-geo=\"5.31666,-4.03334,GMT,CI,+0\">Africa/Abidjan</option><option value=\"Africa/Accra\" data-geo=\"5.55,-0.21667,GMT,GH,+0\">Africa/Accra</option><option value=\"Africa/Addis_Ababa\" data-geo=\"9.03333,38.7,EAT,ET,+3\">Africa/Addis_Ababa</option><option value=\"Africa/Algiers\" data-geo=\"36.78333,3.05,CET,DZ,+1\">Africa/Algiers</option>"; // etcetera etcetera etcetera

function choosejusttheone(thes, thiscc) {
if (!thes) { return false; }
if (eval('' + yourtzlist.split(',' + thiscc + ',').length) != 2) { return true; }
if (yourtzlist.split(',' + thiscc + ',')[1].split('"')[0].indexOf('.') != -1) { return true; }
if (sofarhrs.indexOf(' ' + yourtzlist.split(',' + thiscc + ',')[1].split('"')[0] + ' ') != -1) { return true; }
return false;
}


function getnextcountrycode() {
if (eval('' + ccodes.length) < 9) {
var mycc=document.getElementById('myctable').innerHTML;
var opts=document.getElementsByTagName('option');
var ths=document.getElementsByTagName('th');
var atry=Math.floor(Math.random() * eval('' + opts.length));
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
}
while (mycc.indexOf('>' + opts[eval('' + atry)].innerText + '<') == -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
if (mycc.indexOf('>' + opts[eval('' + atry)].innerText + '<') != -1) {
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
}
}
}
optfinds+=opts[eval('' + atry)].value + ' ';
ccodes.push(opts[eval('' + atry)].value);
cnames.push(opts[eval('' + atry)].innerText);
ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
if (!simple) {
chours.push(-99);
cinthehours.push("");
} else {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
}

}
}

… as required. The user can toggle between the two game modes by clicking that top button.

We, again, hope you try the changed gradual_reveal_country_game.html‘s Country Capital and In the Hour Game web application, below too, yourself?!

Stop Press

We wanted to start involving Wikipedia links and update Geo Charts in either mode of play for the games above, and as a result “function getnextcountrycode” became …


function getnextcountrycode() {
if (eval('' + ccodes.length) < 9) {
var mycc=document.getElementById('myctable').innerHTML;
var opts=document.getElementsByTagName('option'), longis='', latis='';
var ths=document.getElementsByTagName('th');
if (optslength < 0) {
for (iii=0; iii<opts.length; iii++) {
if (('' + opts[iii].value).indexOf(',') != -1 && optslength < 0) { optslength=eval(-1 + iii); }
}
if (optslength < 0) { optslength=eval('' + opts.length); }
}
var atry=Math.floor(Math.random() * eval('' + optslength));
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
}
while (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') == -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + optslength));
if (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') != -1) {
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + optslength));
}
}
}
optfinds+=opts[eval('' + atry)].value + ' ';
ccodes.push(opts[eval('' + atry)].value);
cnames.push(opts[eval('' + atry)].innerText);
ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
subfroms.push('[-89.0000|-88.0000|~From~,2]');
if (!simple) {
if (document.getElementById(ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20').replace(/\ /g,'%20'))) {
longis='' + document.getElementById(ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20').replace(/\ /g,'%20')).value.split(',')[0].split('|')[0];
latis='' + document.getElementById(ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20').replace(/\ /g,'%20')).value.substring(eval(1 + eval('' + longis.length)));
cplaces.push(latis + '|' + longis);
subtos.push('[' + cplaces[eval(-1 + cplaces.length)] + '|~' + ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20') + '~,2]');
} else {
cplaces.push('');
subtos.push('[-89.0000|-88.0000|~From~,2]');
}
chours.push(-99);
cinthehours.push("");
} else {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
subtos.push(lastsubtos);
cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
}
}
}


Previous relevant Javascript Lazy Evaluation Country Capital Game Context Tutorial is shown below.

Javascript Lazy Evaluation Country Capital Game Context Tutorial

Javascript Lazy Evaluation Country Capital Game Context Tutorial

The improvements, today, onto yesterday’s Javascript Lazy Evaluation Country Capital Game Tutorial‘s “Country Capital Game” web application revolve around “context” …

  • there’s the “context” between land masses and sea … as well as …
  • there’s the “context” between country and world view

… both of which take us further into the realms of Google Chart Geo Chart usage, even “unique usage for us”, as far as the first one above.

Regarding the “context” between land masses and sea, wouldn’t it be good, on the map to colour the land with a greener tinge? Anyone, anyone, is green the go? Yes, 3GPP, or is that CP3O, disguised as R2D2 … anyway … yes, we could …

  • isolate the inherent map contents in its SVG guise … but if we could just censure the content here just that teensy weensy bit, now
  • we could torture that SVG to reveal its fill colourwe could do research and development, via a web browser web inspector, into that SVG’s path element fill colour … spoiler alert … #f5f5f5 (grey) … and …
  • liquidate its assetsgently coerce the map into thinking its SVG path element fill colour should be #c5f5f5 (our greenish tinge)

Thanks, can I call you 3o?


function hashit(iois) {
if (iois != null) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
aconto.getElementById('myh').style.display='none'; // aconto.getElementById('chart_div').scrollIntoView();
// Thanks to https://stackoverflow.com/questions/6088409/svg-drop-shadow-using-css3
setTimeout(function(){ aconto.getElementById('chart_div').innerHTML=aconto.getElementById('chart_div').innerHTML.replace('</svg>', '</svg><style> .shadow { -webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); } </style>').replace(/\#f5f5f5\;\"/g,'#c5f5f5;" class="shadow"').replace(/\#f5f5f5\"/g,'#c5f5f5" class="shadow"'); }, 4000);
}
}
}
}

Oh, okay then. Sorry. Thanks, 3GPPsubsection III! You do get straight to the point, there!

And then, regarding the “context” between country and world view, we have a two part improvement to matters here, we feel. Firstly, we hope to help contextualize “where in the world” is a country, and secondly, we wanted to “value add” for these popup windows we might open as the user hovers over a “country map” cell (filled with iframe Google Chart Geo Chart content), otherwise such interventions can be annoying, and we hope we’re not making the game too easy by adding to …

  • the existant onmouseover event creating popup window … now …
  • identical #c5f5f5 filled land mass “country map” … our newly added …
  • “world map” view of that same country, highlighted

for context


var wmapurl='<iframe src="//www.rjmprogramming.com.au/PHP/GeoChart/geo_chart.php?title=World%20Map&width=834&height=520&country=Country&popularity=Popularity&data=%20[~IT~,2]"></iframe>';

var subfrom='~IT~';
var subto='~IT~';

function woit(thissrc,thiso) {
if (thissrc.indexOf(hastoinvolve.replace(' src=','//')) != -1 && thissrc.replace('http:','').replace('https:','') != lastwosrc.replace('http:','').replace('https:','') && sowoa.replace(/http\:/g,'').replace(/https\:/g,'').indexOf(' ' + thissrc.replace('http:','').replace('https:','') + ' ') == -1) {
lastwosrc=thissrc;
var therect=thiso.getBoundingClientRect();
if (wo) {
if (!wo.closed) {
wo.close();
}
wo=null;
sowoa+=thissrc + ' ';
subto='~' + thissrc.split('?title=')[1].split(';')[0] + '~';
wo=window.open(thissrc,'_blank','top=' + therect.top + ',left=' + therect.left + ',width=' + eval(2 * thewidth) + ',height=' + eval(2 * theheight));
//wo.focus();
wo.onload = function() {
setTimeout(function(){ wo.document.getElementById('chart_div').innerHTML=wo.document.getElementById('chart_div').innerHTML.replace('</svg>', '</svg><style> .shadow { -webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); } </style>').replace(/\#f5f5f5\;\"/g,'#c5f5f5;" class="shadow"').replace(/\#f5f5f5\"/g,'#c5f5f5" class="shadow"'); wo.document.getElementById('chart_div').innerHTML+=wmapurl.replace(subfrom,subto); }, 4000);
};

} else {
sowoa+=thissrc + ' ';
subto='~' + thissrc.split('?title=')[1].split(';')[0] + '~';
wo=window.open(thissrc,'_blank','top=' + therect.top + ',left=' + therect.left + ',width=' + eval(2 * thewidth) + ',height=' + eval(2 * theheight));
//wo.focus();
wo.onload = function() {
setTimeout(function(){ wo.document.getElementById('chart_div').innerHTML=wo.document.getElementById('chart_div').innerHTML.replace('</svg>', '</svg><style> .shadow { -webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); } </style>').replace(/\#f5f5f5\;\"/g,'#c5f5f5;" class="shadow"').replace(/\#f5f5f5\"/g,'#c5f5f5" class="shadow"'); wo.document.getElementById('chart_div').innerHTML+=wmapurl.replace(subfrom,subto); }, 4000);
};

}
}
}

… where element chart_div represents all the Google Chart Geo Chart smarts, thanks!

We hope you try the changed gradual_reveal_country_game.html‘s Country Capital Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation Country Capital Game Tutorial is shown below.

Javascript Lazy Evaluation Country Capital Game Tutorial

Javascript Lazy Evaluation Country Capital Game Tutorial

Just like with yesterday’s Javascript Lazy Evaluation Game Involvement Tutorial

… of recent times. But this time, with our gradual_reveal_country_game.html Drag and Drop Country Capital Game we introduce to the target “Drop Zone” table cell content, for the first time, we have …

… to match the associated source “Drag” element available for the user to drag and drop into the correct table cell below, to score in today’s geography game.


Previous relevant Javascript Lazy Evaluation Game Involvement Tutorial is shown below.

Javascript Lazy Evaluation Game Involvement Tutorial

Javascript Lazy Evaluation Game Involvement Tutorial

Yes, we’ve decided to involve the Lazy Evaluation and async and await and Promise and setTimeout Javascript logic of yesterday’s Javascript Lazy Evaluation Promise Tutorial into a Drag and Drop mathematics game for Small Integers from 1 to 9. Can you hear Alice in the middle room?!

Our “mathematical sentences” to solve in this game, where the operators can be + or – or / or * or %, and integer is number from 1 to 9, can be …

  • hard … made up of …
    integer operator integer operator integer operator
    integer operator integer operator
    integer operator
    integer operator integer operator integer

    … or …

  • simple … made up of …
    integer operator integer
    operator integer
    operator
    integer operator integer

… parts to the “mathematical sentence” revealed gradually, using those aforesaid mentioned Javascript techniques, the less revealed as the user answers, the bigger the score, if correct.

The (non-mobile only) cursor and cell background images are formed via data URI svg+xml formats …

Cursor Cell

<style>
* {
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='48' width='126' viewport='0 0 100 100'><polyline points='40,2 20,15 80,10 60,20 126,30 86,48' style='fill:none;stroke:black;stroke-width:3' /><text y='90%'>\002753</text><ellipse cx='24' cy='20' rx='22' ry='13' style='fill:purple' /><ellipse cx='22' cy='17' rx='19' ry='12' style='fill:lime' /><ellipse cx='21' cy='14' rx='16' ry='12' style='fill:yellow' /><rect x='40' y='20' width='80' height='25' style='fill:blue'><animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='5s' repeatCount='indefinite' /></rect>Sorry, your browser does not support inline SVG.</svg>") 16 16, crosshair;
}
</style>

var svgtemp="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='48' width='126' viewport='0 0 100 100'><text x='20%' y='30%' stroke='blue'>1 +</text></svg>";
// ... used later regarding tdsos = document.getElementsByTagName('td'); // ... and nextanswer is ... next answer ...
setTimeout(() => { tdsos[eval(-1 + nextanswer)].style.backgroundImage='URL("' + svgtemp.replace('>1 +', '>' + parts[eval(-1 + nextanswer)].trim()) + '")'; getnextanswer(); }, 200);

… in our gradual_reveal_game.html Small Integer Game you can also try below …


Previous relevant Javascript Lazy Evaluation Promise Tutorial is shown below.

Javascript Lazy Evaluation Promise Tutorial

Javascript Lazy Evaluation Promise Tutorial

Working on yesterday’s Javascript Lazy Evaluation Follow Up Tutorial subject matter further today, we’d like to introduce a glossary of terms for beginners here …

  • async
    function

    The async function declaration creates a binding of a new async function to a given name. The await keyword is permitted within the function body, enabling asynchronous, promise-based behavior to be written in a cleaner style and avoiding the need to explicitly configure promise chains.

  • await
    operator

    The await operator is used to wait for a Promise and get its fulfillment value. It can only be used inside an async function or at the top level of a module.

  • Promise
    object (thenable)

    The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

  • Lazy
    syntax (function)

    Lazy evaluation means to delay the evaluation of an expression until it’s needed. Lazy evaluation is sometimes referred to as call-by-need.

    The opposite of lazy evaluation is an eager evaluation. It’s an evaluation strategy used in most programming languages.

    Lazy evaluation makes it possible to:

    define potentially infinite data structures
    increase performance by avoiding needless computations
    customize iteration behavior for data structures that want its elements accessible to the public

  • setTimeout
    function (global)

    The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires.

Meanwhile you can (re-)try our Javascript modified lazy_async.htm web application in a new tab or below …


Previous relevant Javascript Lazy Evaluation Follow Up Tutorial is shown below.

Javascript Lazy Evaluation Follow Up Tutorial

Javascript Lazy Evaluation Follow Up Tutorial

Further to yesterday’s Javascript Lazy Evaluation Primer Tutorial‘s subject matter regarding Lazy Evaluations and Javascript async functions, we’ve stumbled upon another great resource, thanks, from which we can base, to develop a web application, we’re hoping.

Within this “proof of concept” code basis you will find setTimeout (timer) references to Lazy Evaluations like …


setTimeout(() => {
aminterested='Just';
resolve("fast");
consolelog("fast promise is done");
aminterested='';
}, 1000);

… as a function that …

  • attempts to start in one second’s time …
  • as needed that function is performed

The possibilities here are multifaceted, and varied, and definitely worth experimenting with, within Javascript client work.

So our starting web application can be tried in a new tab or below …


Previous relevant Javascript Lazy Evaluation Primer Tutorial is shown below.

Javascript Lazy Evaluation Primer Tutorial

Javascript Lazy Evaluation Primer Tutorial

Do you remember, with the presentation of …

  • Promise Object Sleeping and Doing Primer Tutorial we talked about the Javascript Promise object? Well today, in that similar line of thinking, we wanted to touch on …
  • Lazy Evaluation in Javascript …

    Lazy evaluation means to delay the evaluation of an expression until it’s needed. Lazy evaluation is sometimes referred to as call-by-need.

    The opposite of lazy evaluation is an eager evaluation. It’s an evaluation strategy used in most programming languages.

    Lazy evaluation makes it possible to:

    define potentially infinite data structures
    increase performance by avoiding needless computations
    customize iteration behavior for data structures that want its elements accessible to the public

Personally, we’re more your “eager” types, but we’ve had help in the past from brilliant “lazy” types too, especially when we presented Selection API and Clipboard API Tutorial, and so, we honed in on some Javascript “Lazy Evaluation” code, and put together some status information shown regarding timings and calls with respect to Javascript …

  • “Lazy Evaluation” in Javascript … classical syntax goes …

    f = () => expression;

    … and …
  • async function in Javascript … classical syntax example goes …

    function resolveAfter2Seconds() {
    return new Promise((resolve) => {
    setTimeout(() => {
    resolve('resolved');
    }, 2000);
    });
    }

    async function asyncCall() {
    console.log('calling');
    const result = await resolveAfter2Seconds();
    console.log(result);
    // Expected output: "resolved"
    }

… into the changed clipboard_api_test.html Selection and Clipboard API usage web application for you to try yourself with some image or text clipboard usages.


Previous relevant Promise Object Sleeping and Doing Primer Tutorial is shown below.

Promise Object Sleeping and Doing Primer Tutorial

Promise Object Sleeping and Doing Primer Tutorial

We’re here today to fulfil yesterday’s Web Application Controlled Progress Cursor Primer Tutorial‘s pledge …

… which reminded me that we need to learn some more about the promise object

… and were happy to discover the Promise object talents of …

  • sleeping … allowing for …
  • multitasking
  • doing … all using clientside Javascript

… very interesting. The serverside languages such as PHP make it a doddle to multitask (via sleep) but Javascript sleep has not always been a straightforward proposition, until we could promise, that is!

Today’s await.html‘s use of it to sleep and in between show …

  1. analogue clock … and …
  2. Dams of the USA (via dams_usa.html changed this way)

… asynchronously both doing their own thing while the await.html works away in the background too, feeding off “child 2” clicks of “child 1” above to know when to say how long the dams took to load. Yes, the “child 2” “onload” event, alone, cannot help determine this, but more “drilling into” the inner workings of the code behind “child 2″‘s progress element, via …


<html>
<head>
<script type='text/javascript'>
var numsleeps=700000;
var ix=0;
var d=new Date();
var marks=[new Date(), new Date()];
var imark=0;

function sleep(ms) { // thanks to https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
console.log(numsleeps + ' Taking a break...' + d);
await sleep(2000);
d=new Date();
console.log(numsleeps + ' Two seconds later, showing sleep in a loop...' + d);

// Sleep in loop
for (let i = 0; i < 5; i++) {
if (i === 3) {
await sleep(2000);
d=new Date();
console.log(numsleeps + ' ' + d);


}
}
numsleeps--;
if (('' + numsleeps) != '0' && ('' + numsleeps).indexOf('-') == -1) { setTimeout(demo, 1); }
}

function betw() {
var seconds = (marks[1].getTime() - marks[0].getTime()) / 1000;
document.getElementById('sh1').innerHTML='It took ' + seconds + ' seconds (from ' + marks[0] + ' to ' + marks[1] + ') to load the dams.';
numsleeps=0;
}

function markit() {
marks[imark]=d;
imark++;
console.log('mark ' + imark + ': ' + d);
if (imark == 2) { setTimeout(betw, 800); imark=0; }
}

demo();
</script>
</head>
<body>
<h1>Sleeping and Doing via Promise Object - RJM Programming - July, 2021 <span id=sh1></span></h1>
<table style=width:100%;height:90%;><tr><td><iframe onclick="markit();" id=lif src=./analogue_clock.htm style=width:100%;height:100%;></iframe></td><td><iframe id=rif src=./dams_usa.html?rand=7564675 style=width:100%;height:100%;></iframe></td></tr>
</body>
</html>


Previous relevant Web Application Controlled Progress Cursor Primer Tutorial is shown below.

Web Application Controlled Progress Cursor Primer Tutorial

Web Application Controlled Progress Cursor Primer Tutorial

We had occasion to revisit the card game (and more) recent web application exploits highlighted in the recent Just Javascript Card Game Cursor Tutorial thread of blog postings and shaped to play Bridge via …


https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=04.1:ara

… and was “personally relatively” happy up to the first Javascript prompt popup window. Huh?! What’s with “personally relatively”? Can I be serious? Well, I’m insulted!

The thing is, I don’t mind, when I’m writing the code (funny about that?!) very complex and convoluted prompt window instructions and options. But …

  • not everybody is willing to read such long diatribes
  • actions can speak louder than words, so we figure between those first two prompt windows in a Bridge or 500 card game, it would be beneficial to show a “progress cursor” (ie. usually associated with the user waiting for a process to finish) between the first and second prompt windows to help show the players there could be waiting and irrelevant players turning away should all four players want to play fairly in their game

It was an interesting Javascript coding exercise …

  1. (sort of) overload the “prompt” function with our inhouse “superprompt” function via …
    • globally replace ” prompt(” with ” superprompt(“
    • globally replace “=prompt(” with “=superprompt(“
  2. add the following Javascript code …

    var aheadoffirst=(('' + document.URL.replace('?', '&').indexOf('&card_') != -1) ? trueize() : 0);

    function dbcpp() {
    if (aheadoffirst == 2) {
    document.body.style.cursor='progress'; // between first and second prompt windows
    setTimeout(dbcpp, 1000);
    } else if (aheadoffirst == 0) {
    document.body.style.cursor='pointer';
    } else {
    document.body.style.cursor='pointer';
    setTimeout(dbcpp, 1000);
    }
    }

    function trueize() { // bit like a promise
    setTimeout(dbcpp, 1000);
    return 1;
    }


    function superprompt(opone, optwo) {
    if (aheadoffirst == 3) {
    document.body.style.cursor='pointer';
    aheadoffirst=0;
    } else if (aheadoffirst != 0) {
    aheadoffirst++;
    if (aheadoffirst == 3) {
    document.body.style.cursor='progress'; // between first and second prompt windows
    }
    }
    return prompt(opone, optwo);
    }

… which reminded me that we need to learn some more about the promise object.

See this in action with the changed cards_usefocus.html code behind the “Just Javascript” Memories Card Game or live run with single window (good for mobile) or default live run (for your platform, and if non-mobile it will try child popup windows).

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Games, Land Surveying, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Javascript Lazy Evaluation Game Sharing Tutorial

Javascript Lazy Evaluation Game Sharing Tutorial

Javascript Lazy Evaluation Game Sharing Tutorial

In thinking about a sharing, via email or SMS, component on top of the progress of the recent Javascript Lazy Evaluation Bearing Game Tutorial, with our current …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… game modes we thought the best approach would be if a user could share with another the same Geography Quiz based question they have been asked, to compare notes.

Which begs the question?

What can give a game (or quiz) a random feel?

Well, with Javascript, we’re always using …


var arandom=Math.floor(Math.random() * anarrayofchoices.length); // anarrayofchoices is an array of choices and arandom ends up as an index into that array's contents

… types of statements … or variations on this style of statement. So we zeroed in on these and set about unrandomising these places in the code, to, if asked, simulate that same random way the question was framed for the emailer …


var complex=location.search.split('simple=')[1] ? decodeURIComponent(location.search.split('simple=')[1].split('&')[0]) : '';
var drilldown=complex.split('_')[0];
var simple=location.search.split('simple=')[1] ? (drilldown == '' ? false : true) : false;

var mflist=drilldown + '_', mfcount=0;

var answer=Math.min(9, eval(Math.floor(Math.random() * 9) + 1)); // first example of use
if (complex.indexOf('_' + mfcount + '.') != -1) {
answer=eval(complex.split('_' + mfcount + '.')[1].split('_')[0]);
}
mflist+='' + mfcount + '.' + answer + '_';
mfcount++;

… used by new helping Javascript code …


<div id=das style=display:none;></div>
<script type='text/javascript'>
setTimeout(function() { document.getElementById('das').innerHTML+=("<a style=display:none; id=asms href='sms:&body=" + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + '?simple=' + encodeURIComponent(mflist)) + "'>SMS</a>"); document.getElementById('bsharesms').style.visibility='visible'; }, 18000);
setTimeout(function() { document.getElementById('das').innerHTML+=("<a style=display:none; id=aemail href='mailto:?subject=Geography%20Quiz&body=" + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + '?simple=' + encodeURIComponent(mflist)) + "'>Email</a>"); document.getElementById('bshareemail').style.visibility='visible'; }, 18500);
</script>

… and will happen for the emailee …


function savesms(defsms) {
var wasv=('' + window.localStorage.getItem('smsgrcg')).replace(/^null$/g,'').replace(/^undefined$/g,'');
if (defsms.indexOf(defsms.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('smsgrcg'); }
} else if (defsms.indexOf(defsms.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('smsgrcg'); }
window.localStorage.setItem('smsgrcg', defsms.trim());
} else if (defsms == '' && wasv.trim() != '') {
return wasv;
}
return defsms;
}

function saveemail(defemail) {
var wasv=('' + window.localStorage.getItem('emailgrcg')).replace(/^null$/g,'').replace(/^undefined$/g,'');
if (defemail.indexOf(defemail.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('emailgrcg'); }
} else if (defemail.indexOf(defemail.trim() + ' ') == 0) {
if (wasv != '') { window.localStorage.removeItem('emailgrcg'); }
window.localStorage.setItem('emailgrcg', defemail.trim());
} else if (defemail == '' && wasv.trim() != '') {
return wasv;
}
return defemail;
}

function smsit() {
var smsno=savesms(smsee);
if (smsno.trim() != '' && smsno.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
smsno=prompt('Please enter SMS number. Add space to remember or more than three to unremember.', smsno);
} else {
smsno=prompt('Please enter SMS number. Add space to remember or more than three to unremember.', '');
}
if (smsno != null) {
if (smsno.trim() != '' && smsno.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
if (smsno != smsno.trim()) { smssave(smsno); }
if (smsee == '') { smsee=smsno.trim(); }
document.getElementById('asms').href='sms:' + smsno.trim() + '&' + document.getElementById('asms').href.split('&')[1];
document.getElementById('asms').click();
}
}
}

function emailit() {
var emailaddr=saveemail(emailee);
if (emailaddr.indexOf('@') != -1) {
emailaddr=prompt('Please enter Email address. You can comma separate a list. Add space to remember or more than three to unremember.', emailaddr);
} else {
emailaddr=prompt('Please enter Email address. You can comma separate a list. Add space to remember or more than three to unremember.', '');
}
if (emailaddr != null) {
if (emailaddr.indexOf('@') != -1) {
if (emailaddr != emailaddr.trim()) { saveemail(emailaddr); }
if (emailee == '') { emailee=emailaddr.trim(); }
document.getElementById('aemail').href='mailto:' + emailaddr.trim() + '?' + document.getElementById('aemail').href.split('?')[1];
//alert(document.getElementById('aemail').href);
document.getElementById('aemail').click();
}
}
}

… should they click on their email’s game link in our changed gradual_reveal_country_game.html‘s Bearing and/or Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Bearing Game Tutorial is shown below.

Javascript Lazy Evaluation Crow Fly Game Tutorial

Javascript Lazy Evaluation Bearing Game Tutorial

Let’s just suppose you’ve got a “hardy crow” (like those in Javascript Lazy Evaluation Crow Fly Game Tutorial) and it doesn’t mind “a bit of chill” on occasions. To minimize the distance it flies to get to a given destination in that shortest distance (or “great circle distance” discussed yesterday) it needs to set out at a particular bearing (or direction) where zero degrees is North and ninety degrees is East and 3 degrees? Glad you asked!

With this bearing being able to be calculated …


function great_circle_bearing(talis, gnolis, latis, longis) {
// Let ‘R’ be the radius of Earth,
// ‘L’ be the longitude,
// ‘θ’ be latitude,
// ‘β‘ be Bearing.

// Bearing from point A to B, can be calculated as,
// β = atan2(X,Y),
// where, X and Y are two quantities and can be calculated as:
// X = cos θb * sin ∆L
// Y = cos θa * sin θb – sin θa * cos θb * cos ∆L

var ourbrg=eval(eval(360.0 + eval(eval(eval(180.0 / Math.PI) * Math.atan2(
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + latis))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval(eval('' + longis) - eval('' + gnolis))))),
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + talis))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + latis)))) -
eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + talis))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + latis))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval(eval('' + longis) - eval('' + gnolis)))))
)))) % 360.0);

return '' + ourbrg;
}

… it gave us an idea for a …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… game to add to

  • Country Capitals Game
  • In the Hour Game
  • Languages Game
  • In the Timestamp Game
  • Geographicals Game
  • Crow Fly Game … and today we present …
  • Bearing Game

… our games mode list, further to yesterday’s Javascript Lazy Evaluation Crow Fly Game Tutorial. Like yesterday, we think you’ll find this game a challenge!

Again, feel free to try out our changed gradual_reveal_country_game.html‘s Bearing and/or Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Crow Fly Game Tutorial is shown below.

Javascript Lazy Evaluation Crow Fly Game Tutorial

Javascript Lazy Evaluation Crow Fly Game Tutorial

To be a crow on the Mercator Projection is to be the “moron” in oxymoron. Yes, have a read of Why is the ‘straight line’ path across continent so curved? Or do they have a “shot of Mercator” and move this way? Well, we’re not asking the class, this time!

But those distances of that direct way crows allegedly fly is able to be calculated …


function great_circle_distance(talis, gnolis, latis, longis) {
var ourdist=0.0;
var rgnol=eval((gnolis) * Math.PI / 180.0);
var rtal=eval((talis) * Math.PI / 180.0);
var rlong=eval((longis) * Math.PI / 180.0);
var rlat=eval((latis) * Math.PI / 180.0);
var deltalong = Math.abs(eval(((gnolis)-(longis)) * Math.PI / 180.0));
var acof = eval(Math.sin(rtal) * Math.sin(rlat)) + (Math.cos(rtal) * Math.cos(rlat) * Math.cos(deltalong)); // via //en.wikipedia.org/wiki/Great-circle_distance ... thanks
ourdist = eval(Math.round((Math.acos(acof) * 6371000.0) + 0.00001) * 100) / 100;
return '' + ourdist;
}

… and forms the basis of our latest game

  • Country Capitals Game
  • In the Hour Game
  • Languages Game
  • In the Timestamp Game
  • Geographicals Game … and today we present …
  • Crow Fly Game

… in the …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… series, whereby a user is presented with a draggable piece of text such as …

14446.128 kilometers from Mogadishu of Somalia

… and the user, to score, is asked to drop this text into the appropriate one of the nine table cells displayed below.

We think this is pretty hard, but am sure there are experts out there who can score well in this game mode?!

And so, further to yesterday’s Javascript Lazy Evaluation Geographicals Game Tutorial, feel free to try out our changed gradual_reveal_country_game.html‘s Crow Fly and/or Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Geographicals Game Tutorial is shown below.

Javascript Lazy Evaluation Geographicals Game Tutorial

Javascript Lazy Evaluation Geographicals Game Tutorial

Today, we’ve arrived back at our …

  • Javascript Lazy Evaluations themed …
  • Drag and Drop themed …
  • Geography Quiz themed …

… blog posting thread we last visited with the recent Javascript Lazy Evaluation Timestamp Game Tutorial. Why? Well, there are more geography quiz ways to allow for an interesting learning experience should world geography be your thaing!

Today’s premise for a new option to our last talked about game type list of …

  • Country Capitals Game
  • In the Hour Game … and today we introduce the …
  • Languages Game … snapshot of main dropdown functionality choices, today, we add …
  • In the Timestamp Game

… is a “Geographicals Game”. In other words, just present a


Longitude,Latitude

… pairing that falls within one of the Country Google Geo Chart maps presented in one of the nine table cells displayed below. Simple as falling off a log, really. But if you want to make it more challenging for yourself, use a rhythm method to solve a logarithm (ever so small chortle, chortle).

These days, online, you are probably used to seeing Geographicals presented as decimal degree Longitude,Latitude or vice versa, but we add a touch of interest by turning those decimal degree Geographicals into entries like …


58°35'00" E , 23°36'00.00" N

… as a notation navigators and aviators and astronomers and surveyors and Wikipedia readers and others would be quite at home with …


function aslongfollowslat(inllstr) {
var latdir=' N', longdir=' E';
var latd=0, longd=0;
var latm=0, longm=0;
var lats=0.0, longs=0.0;
var latrest=0.0, longrest=0.0;
var insg='';


var lls=inllstr.split(',');
if (eval('' + lls.length) >= 2) {
if (lls[0].indexOf('+') != -1) {
lls[0]=lls[0].replace('+','');
} else if (lls[0].indexOf('-') != -1) {
latdir=' S';
lls[0]=lls[0].replace('-','');
}
latd=lls[0].split('.')[0];
latrest=eval('0.' + (lls[0] + '.0').split('.')[1]);
latm=Math.floor(latrest * 60);
lats=eval((latrest * 3600) - Math.floor(latm * 60)).toPrecision(3);
if (lats >= 60.0) {
latm++;
lats-=60.0;
if (latm >= 60) {
latd++;
latm-=60;
}
}
if (lls[1].indexOf('+') != -1) {
lls[1]=lls[1].replace('+','');
} else if (lls[1].indexOf('-') != -1) {
longdir=' W';
lls[1]=lls[1].replace('-','');
}
longd=lls[1].split('.')[0];
longrest=eval('0.' + (lls[1] + '.0').split('.')[1]);
longm=Math.floor(longrest * 60);
longs=eval((longrest * 3600) - Math.floor(longm * 60)).toPrecision(3);
if (longs >= 60.0) {
longm++;
longs-=60.0;
if (longm >= 60) {
longd++;
longm-=60;
}
}

return ('' + longd + '&#176;' + ('0' + longm).slice(-2) + "'" + ('0' + longs).split('.')[0].slice(-2) + ((('' + longs).indexOf('.') != -1) ? ('.' + ('' + longs).split('.')[1].split('00000')[0]) : '') + '" ' + longdir + ' , ' + latd + '&#176;' + ('0' + latm).slice(-2) + "'" + ('0' + lats).split('.')[0].slice(-2) + ((('' + lats).indexOf('.') != -1) ? ('.' + ('' + lats).split('.')[1].split('00000')[0]) : '') + '" ' + latdir).replace(/\.\"/g, '"');

}
return inllstr;
}

… and which we’ve often wondered why the Standards Boards never got to, to rather show angles in a decimal way, as distinct from this degrees, minutes and seconds methodology?! For some clues, you might want to read the excellent Longitude book.

Feel free to try out this new Geographicals Game with our changed gradual_reveal_country_game.html‘s Geographicals and/or In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Timestamp Game Tutorial is shown below.

Javascript Lazy Evaluation Timestamp Game Tutorial

Javascript Lazy Evaluation Timestamp Game Tutorial

Where does your “good value” index lie? We ask, because an underlying principle of this blog, is that we are most interested in online facilities that are free. Always have been. Always will be. Let me talk about a few
examples in this blog posting thread, those being …

  • Wikipedia … encyclopaedic data …
  • Google Geo Chart … map data …
  • emojis … are a free resource, out there on the net, helping out we “graphically challenged” content producers … thanks, whoever … and today, we’ve been interested before, but today, we go further, regarding the free aspects to …
  • Internationalization … in the online world, thanks … today acting a tad like a free language translator … albeit …

… just for date timestamps, only. Still, and all, these generous arrangements online, should be applauded. Thanks, peepholespeople! Of course, there should be more of them, but to discover some of them, allows for that “added joy of discovery” stumbling upon what is possible, for free, out there!

And so, adding onto yesterday’s Javascript Lazy Evaluation Languages Game Tutorial‘s …

  • Country Capitals Game
  • In the Hour Game … and today we introduce the …
  • Languages Game … snapshot of main dropdown functionality choices, today, we add …
  • In the Timestamp Game

… as a hybrid between …

  • In the Hour Game … regarding its “when” datetime arrangements and …
  • Languages Game … regarding its “locale” smarts … we add to

    function getnextcountrycode(inforce) {
    var ccr='', sccr='', wasccr='', interimh=0, thiscc='', lno=0, ctylist=[], irx=0, myccis='', ijk=0;
    if (eval('' + ccodes.length) < 9) {
    var mycc=document.getElementById('myctable').innerHTML;
    var opts=document.getElementsByTagName('option'), longis='', latis='';
    var ths=document.getElementsByTagName('th');

    if (goodatry > 0 && inforce != 0 && eval(1 + eval('' + cplaces.length)) == Math.abs(inforce)) {
    //alert(gproposedanswer + ' vs ' + cplaces.length);
    atry=goodatry;
    optfinds+=opts[eval('' + atry)].value + ' ';
    ccodes.push(opts[eval('' + atry)].value);
    cnames.push(opts[eval('' + atry)].innerText);
    ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
    subfroms.push('[-89.0000|-88.0000|~From~,2]');
    goodatry=eval(-1 * Math.abs(goodatry));
    //sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
    tzas.push(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]);
    interimh=eval(eval(eval(eval('' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24);
    if (uhour < interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') != -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(-1); }
    } else if (uhour > interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') == -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(1); }
    } else {
    for (ijk=1; ijk<=9; ijk++) { doff.push(0); }
    }
    if (gcinthehourspush != '') {
    cinthehours.push(gcinthehourspush);
    gcinthehourspush='';
    } else {
    cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
    }
    //var newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    //alert(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0] + ': ' + newd + ' vs ' + cinthehours[eval(-1 + cinthehours.length)]);
    thiscc=opts[eval('' + atry)].value;
    lastsubtos='[' + yourtzlist.split(',' + thiscc + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + thiscc + ',')[0].split('"').length)].split(',')[0] + '|' + yourtzlist.split(',' + thiscc + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + thiscc + ',')[0].split('"').length)].split(',')[1] + '|~' + encodeURIComponent(yourtzlist.split(',' + thiscc + ',')[1].split('"')[1].split('>')[1].split('<')[0].replace(yourtzlist.split(',' + thiscc + ',')[1].split('"')[1].split('>')[1].split('<')[0].split('/')[0] + '/', '').replace(/\_/g,' ')) + '~,2]';
    subtos.push(lastsubtos);
    cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
    if (drilldown == 'lang') {
    sofarlang+=rellang + ' ';
    if (gcrellang != '') {
    clangs.push(gcrellang);
    clanges.push(gcrellange);
    clangkbs.push(gcrellangkb.replace('-','_'));
    cinintl.push('' + gcreldatenow);
    gcrellang='';
    gcrellangkb='';
    //gcreldatenow='';
    } else {
    clangs.push(rellang);
    clanges.push(lastengl);
    clangkbs.push(rellangkb.replace('-','_'));
    cinintl.push(('' + reldatenow));
    }
    //alert(rellang + ' is spoken in country ' + opts[eval('' + atry)].innerText);
    } else {
    clangs.push('');
    clanges.push('');
    clangkbs.push('');
    cinintl.push('');
    }
    return '';
    }

    if (optslength < 0) {
    for (iii=0; iii<opts.length; iii++) {
    if (('' + opts[iii].value).indexOf(',') != -1 && optslength < 0) { optslength=eval(-1 + iii); }
    }
    if (optslength < 0) { optslength=eval('' + opts.length); }
    }
    var atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
    atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    }
    while (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') == -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
    atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    if (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') != -1) {
    while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
    atry=butrand(Math.floor(Math.random() * eval('' + optslength)));
    }
    }
    }
    if (!simple) {
    if (drilldown == 'lang') {
    sofarlang+=rellang + ' ';
    clangs.push(rellang);
    clangs.push(lastengl);
    clangkbs.push(rellangkb.replace('-','_'));
    //alert(rellang + ' is spoken in country ' + opts[eval('' + atry)].innerText);
    } else {
    clangs.push('');
    clanges.push('');
    clangkbs.push('');
    }
    optfinds+=opts[eval('' + atry)].value + ' ';
    ccodes.push(opts[eval('' + atry)].value);
    cnames.push(opts[eval('' + atry)].innerText);
    ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
    subfroms.push('[-89.0000|-88.0000|~From~,2]');
    ccr=ccapitals[eval(-1 + ccapitals.length)];
    wasccr=ccr;
    sccr=document.getElementById('spops').innerHTML;
    if (!document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20'))) {
    while (eval('' + ccr.length) > 4 && eval('' + sccr.split(' id="' + ccr).length) != 2) {
    ccr=ccr.substring(0, eval(-1 + eval('' + ccr.length)));
    }
    if (ccr != wasccr && eval('' + ccr.length) > 4 && eval('' + sccr.split(' id="' + ccr).length) == 2) {
    wasccr=ccr;
    ccr=wasccr + sccr.split(' id="' + ccr)[1].split('"')[0];
    }
    }
    if (document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20'))) {
    longis='' + document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20')).value.split(',')[0].split('|')[0];
    latis='' + document.getElementById(ccr.replace(/\'/g,'').replace(/\_/g,'%20').replace(/\ /g,'%20')).value.substring(eval(1 + eval('' + longis.length)));
    cplaces.push(latis + '|' + longis);
    subtos.push('[' + cplaces[eval(-1 + cplaces.length)] + '|~' + encodeURIComponent(ccapitals[eval(-1 + ccapitals.length)]).replace(/\_/g,'%20') + '~,2]');
    } else {
    try {
    lastsubtos='[' + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"').length)].split(',')[0] + '|' + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"')[eval(-1 + yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[0].split('"').length)].split(',')[1] + '|~' + encodeURIComponent(yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[1].split('"')[1].split('>')[1].split('<')[0].replace(yourtzlist.split(',' + ccodes[eval(-1 + ccodes.length)] + ',')[1].split('"')[1].split('>')[1].split('<')[0].split('/')[0] + '/', '').replace(/\_/g,' ')) + '~,2]';
    //alert('no ' + lastsubtos);
    lastsubtos=lastsubtos.replace('~]', encodeURIComponent(' near ' + ccapitals[eval(-1 + ccapitals.length)].replace(/\'/g,'')) + '~]');
    cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
    subtos.push(lastsubtos);
    } catch(hggf) {
    cplaces.push('');
    subtos.push('[-89.0000|-88.0000|~From~,2]');
    }
    }
    //doff.push(0);
    chours.push(-99);
    cinthehours.push("");
    cinintl.push("");
    tzas.push("");
    } else {
    if (inforce > 0) {
    goodatry=atry;
    var cinthehourspush=(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
    newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    var newh=eval(('' + newd).split(':')[0].split(' ')[eval(-1 + ('' + newd).split(':')[0].split(' ').length)]);

    nhour = newd.getHours();
    nmin = newd.getMinutes();
    nday = newd.getDay();
    nsec = 0;
    ndate = newd.getDate();
    nmonth = newd.getMonth();
    nyear = newd.getFullYear();
    reldatenow=newd; //new Date(newd.toLocaleString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    //alert('Reldatenow=' + reldatenow);

    if (cinthehourspush.indexOf('' + ('0' + newh).slice(-2)) != 0) {
    var oldh=eval('' + cinthehourspush.split(':')[0]);
    if (oldh != newh) {
    //alert('uhour=' + uhour + ' and oldh=' + oldh + cinthehourspush.substring(2) + ' goes with ' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' and newh=' + newh + cinthehourspush.substring(2));
    if (newh < uhour && newh == 0 && uhour == 23) {
    sofarhrs+='+' + eval(24 - uhour) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert(1);
    } else if (newh > uhour && newh == 23 && uhour == 0) {
    sofarhrs+='-' + eval(24 - newh) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(2);
    } else if (oldh > uhour) {
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(oldh - uhour), '' + eval(newh - uhour)) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1)); // test?
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert('3 ' + sofarhrs + ' newh=' + newh + ' oldh=' + oldh + ' rellangkb=' + rellangkb + ' tz=' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]);
    } else if (oldh < uhour) {
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(uhour - oldh), '' + eval(uhour - newh)) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1)); // test?
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(4);
    } else if (newh < uhour && newh == 0 && uhour == 23) {
    sofarhrs+='+' + eval(24 - uhour) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert(5);
    } else if (newh > uhour && newh == 23 && uhour == 0) {
    sofarhrs+='-' + eval(24 - newh) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(6);
    } else if (newh > uhour) {
    sofarhrs+='+' + eval(newh - uhour) + ' ';
    newd=new Date(newd.setHours(newd.getHours() + 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() + 1));
    //alert(7);
    } else if (newh < uhour) {
    sofarhrs+='-' + eval(uhour - newh) + ' ';
    newd=new Date(newd.setHours(newd.getHours() - 1));
    reldatenow=new Date(reldatenow.setHours(reldatenow.getHours() - 1));
    //alert(8);
    }
    }


    //alert('ReldatenoW=' + newd);
    try {
    nmin = newd.getMinutes();
    nday = newd.getDay();
    nsec = 0;
    ndate = newd.getDate();
    nmonth = newd.getMonth();
    nyear = newd.getFullYear();
    try {
    nhour = newd.getHours();
    } catch(eyyre) {
    nhour = eval('' + newh);
    }
    } catch(esdfgh) {
    }
    gcinthehourspush='' + ('0' + newh).slice(-2) + cinthehourspush.substring(2);
    }
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
    gcrellang='' + rellang;
    gcrellange='' + lastengl;
    gcrellangkb='' + rellangkb;
    //reldatenow=new Date(newd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}) + newd.toLocaleTimeString());

    var vdate = new Date();
    var now_utc = Date.UTC(vdate.getUTCFullYear(), vdate.getUTCMonth(),
    vdate.getUTCDate(), vdate.getUTCHours(),
    vdate.getUTCMinutes(), 0, 0);
    //alert(vdate.toISOString());
    //newd = new Date(new Date(now_utc).toLocaleString("en-US", {timeZone: 'UTC'}));
    newd = new Date(vdate.toLocaleString("en-US", {timeZone: 'UTC'}));
    //alert('' + newd + ' vdate=' + vdate);
    //newd = new Date(new Date(now_utc).toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    // Sun Oct 15 2023 04:59:00 GMT+1100
    // 2020-04-13T00:00:00.000+08:00
    // 2023-10-15T07:12:00.000+11:00
    //alert('' + newd + ' ... ' + ('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + ('0' + ('' + newd).split(' ')[4].split(':')[0]).slice(-2) + cinthehourspush.substring(2) + ':00.000' + ('' + newd).split(' GMT')[1].substring(0,3) + ':' + ('' + newd).split(' GMT')[1].substring(3).split(' (')[0]);
    var zd = new Date(('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + ('0' + newh).slice(-2) + cinthehourspush.substring(2) + ':00.000' + ('' + newd).split(' GMT')[1].substring(0,3) + ':' + ('' + newd).split(' GMT')[1].substring(3).split(' (')[0]);
    //var zd = new Date(('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + ('0' + ('' + newd).split(' ')[4].split(':')[0]).slice(-2) + cinthehourspush.substring(2) + ':00.000-13' + ':' + ('' + newd).split(' GMT')[1].substring(3).split(' (')[0]);
    //alert('' + newd + ' zd.getDay()=' + zd.getDay() + ' newd.getDay()=' + newd.getDay());
    //alert(('' + newd).split(' ')[3] + '-' + ('' + newd).split(' ')[1].replace('January','01').replace('February','02').replace('March','03').replace('April','04').replace('May','05').replace('June','06').replace('July','07').replace('August','08').replace('September','09').replace('October','10').replace('November','11').replace('December','12').replace('Jan','01').replace('Feb','02').replace('Mar','03').replace('Apr','04').replace('May','05').replace('Jun','06').replace('Jul','07').replace('Aug','08').replace('Sep','09').replace('Oct','10').replace('Nov','11').replace('Dec','12') + + '-' + ('0' + ('' + newd).split(' ')[2]).slice(-2) + 'T' + gcinthehourspush + ':00.000' + ('' + newd).split(' GMT')[1].substring(0,2) + ':' + ('' + newd).split(' GMT')[1].substring(2) + ' ... zd=' + zd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    //zd.toLocaleString('en-US', { timeZone: 'America/New_York' })
    if (1 == 7) {
    if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('sun') == 0) {
    dotwi=0;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('mon') == 0) {
    dotwi=1;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('tue') == 0) {
    dotwi=2;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('wed') == 0) {
    dotwi=3;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('thu') == 0) {
    dotwi=4;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('fri') == 0) {
    dotwi=5;
    } else if (('' + (new Date(now_utc))).split(' ')[0].toLowerCase().indexOf('sat') == 0) {
    dotwi=6;
    }
    }

    var ourloc=rellangkb.replace('_','-');
    //alert(ourloc);
    //alert(zd.toLocaleTimeString(rellangkb.replace('_','-')));
    //reldatenow='' + (zd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + ' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'));
    reldatenow='' + ((new Date(now_utc)).toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + ' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'));
    //reldatenow='' + ((new Date(vdate.toISOString())).toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + ' ' + (new Date(vdate.toISOString())).toLocaleTimeString(rellangkb.replace('_','-'));
    //alert('' + reldatenow);
    // ud.toLocaleDateString('de-DE', options), {timeZone: 'Australia/Sydney'}
    //gcreldatenow='' + ( (new Date(now_utc)).toLocaleString('ja-JP', options, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + (' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'), optionstime, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}).substring(0,1));
    gcreldatenow='' + ( (new Date(now_utc)).toLocaleDateString(ourloc, options, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]})) + (' ' + zd.toLocaleTimeString(rellangkb.replace('_','-'), optionstime, {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
    return '';
    }
    if (drilldown == 'lang') {
    sofarlang+=rellang + ' ';
    clangs.push(rellang);
    clanges.push(lastengl);
    clangkbs.push(rellangkb.replace('-','_'));
    cinintl.push('' + reldatenow);
    //alert(rellang + ' is spoken in country ' + opts[eval('' + atry)].innerText);
    } else {
    clangs.push('');
    clanges.push('');
    clangkbs.push('');
    cinintl.push('');
    }
    optfinds+=opts[eval('' + atry)].value + ' ';
    ccodes.push(opts[eval('' + atry)].value);
    cnames.push(opts[eval('' + atry)].innerText);
    ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
    subfroms.push('[-89.0000|-88.0000|~From~,2]');
    sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
    tzas.push(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]);
    if (1 == 8) {
    interimh=eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24);
    if (uhour < interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') != -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(-1); }
    } else if (uhour > interimh && yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].indexOf('-') == -1) {
    for (ijk=1; ijk<=9; ijk++) { doff.push(1); }
    } else {
    for (ijk=1; ijk<=9; ijk++) { doff.push(0); }
    }
    }
    cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
    subtos.push(lastsubtos);
    cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
    }
    }
    //}

    if (eval('' + cinthehours.length) >= 9) {
    console.log(cinthehours);
    console.log(cplaces);
    console.log(ccodes);
    console.log(cnames);
    console.log(ccapitals);
    console.log(subfroms);
    console.log(subtos);
    console.log(sofarhrs);
    }

    }

… logics, asking the user to match a …

  • datetime snapshot in time “time” value … and …
  • datetime “locale” presentation

… to combine as a way a “timestamp drag element” can be dragged to an appropriate “drop country iframe Geo Chart map content” correct answer element, in order for a user to score, in our new “In the Timestamp” game incarnation, involving new “but” code …


function nocaret(inx) {
if (inx.indexOf('<') != -1) {
document.getElementById('dspare').innerHTML=inx;
return document.getElementById('dspare').innerText;
} else {
return inx;
}
}

function appblurb(ontowhat) {
if (curblurb == '') { return '' + ontowhat; }
return '' + ontowhat + String.fromCharCode(10) + String.fromCharCode(10) + nocaret(('' + curblurb)) + String.fromCharCode(10) + String.fromCharCode(10);
}

function mybutclick(selo) {
var suffix='';
if (selo.value == '') {
if (simple) { document.getElementById('mybut').click(); }
} else {
they=selo.value;
//if (!simple) { document.getElementById('mybut').click(); }
if (document.URL.indexOf('?') == -1) { suffix='?simple=' + drilldown; } else if (document.URL.indexOf('simple=') == -1) { suffix='&simple=' + drilldown; }
location.href=(document.URL.split('#')[0] + suffix).replace('simple=' + drilldown, 'simple=' + they);
drilldown=they;
}
}

function butrand(asify) {
var myccis='', lno=0, irx=0, ctylist=[], jrx=-1;
var opts=[];
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
if (drilldown.replace(/^Y/g,'lang') == 'lang') {
opts=document.getElementsByTagName('option');
while (jrx == -1) {
lno=Math.floor(Math.random() * 59);
document.getElementById('select_language').value='' + lno;
updateCountry();
rellang=document.getElementById('select_language').innerHTML.split(' value="' + lno + '">')[1].split('<')[0];
ctylist=document.getElementById('select_dialect').innerHTML.split('-');
jrx=eval(1 + Math.floor(Math.random() * eval(-1 + ctylist.length)));
myccis=ctylist[jrx].split('"')[0];
//alert(myccis + ' ... ' + opts[0].value + ' +++ ' + ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)] + '-' + myccis);
for (irx=0; irx<optslength; irx++) {
//alert(opts[irx].value + ' vs ' + myccis);
if (opts[irx].value == myccis) { atry=irx; rellangkb=butviacml(ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)]) + '_' + myccis; try { reldatenow=new Date(newd.toLocaleDateString(rellangkb.replace('_','-'), {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}) + ' ' + newd.toLocaleTimeString(rellangkb.replace('_','-'))); } catch(ertsd) { reldatenow=null; } return atry; }
}
jrx=-1;
}
}
}
}
return asify;
}

function butviacml(inlcode) {
var bparts=cmylang.split('>' + inlcode + '<');
lastengl='';
if (eval('' + bparts.length) > 1) {
var nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
if (eval('' + nextcell.length) <= 3) {
bparts=cmylang.split('>' + nextcell + '<');
nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
lastengl=nextcell;
} else {
lastengl=nextcell;
}
}
return inlcode;
}

function butmaybeisspokenin(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
//alert(cnames[eval(-1 + answer)] + ' language spot on=' + clangs[eval(-1 + answer)] + ' language one on on=' + clangs[eval(0 + answer)] + ' language one back on=' + clangs[eval(-2 + answer)]);
return asify.replace('en_AU', clangkbs[eval(-1 + answer)]) + ' is spoken ';
}
}
return asify;
}

function butmaybe(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
//alert('answer=' + answer + ' and gproposedanswer=' + gproposedanswer);
if (document.getElementById('selmode').value == 'Y') {
return gcreldatenow; // + ' ' + clangkbs[eval(-1 + answer)]; //'English';
} else {
if (clanges[eval(-1 + answer)] == '') {
document.getElementById('source').title='';
lasthome='';
document.getElementById('source').oncontextmenu=function(){ homelang=homelang; };
} else {
document.getElementById('source').title='Right click to reveal language name in English';
lasthome=clanges[eval(-1 + answer)];
document.getElementById('source').oncontextmenu=function(){ alert(lasthome); };
}
return clangs[eval(-1 + answer)]; //'English';
}
}
}
return asify;
}

function butmaybeno(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
return '';
}
}
return asify;
}

function butmaybenone(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value.replace(/^Y/g,'lang') == 'lang') {
return '';
}
}
return asify;
}

function butthen(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game wants you to drag a spoken Language (appearing later) to table cell with a Country map where that language is spoken.';
} else if (document.getElementById('selmode').value == 'lang') {
return 'In the Timestamp Game wants you to drag a Timestamp presented in that regional way (appearing later) to table cell with a Country map where that timestamp format is familiar and the time is just after the correct local time.';
}
}
return asify;
}

function butthentwo(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game';
} else if (document.getElementById('selmode').value == 'lang') {
return 'In the Timestamp Game';
}
}
return asify;
}

function ouronl() {
if (itblurb != '') {
document.getElementById('myh3').innerHTML+=' ... ' + itblurb;
}
cmylang=document.getElementById('mylangt').innerHTML;
if (drilldown != '') { document.getElementById('selmode').value=drilldown; }
for (var i = 0; i < langs.length; i++) {
select_language.options[i] = new Option(langs[i][0], i);
}
// Set default language / dialect ... thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
select_language.selectedIndex = 10;
updateCountry();
select_dialect.selectedIndex = 11;
showInfo('info_start');
}

function showInfo(s) { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
if (s) {
for (var child = info.firstChild; child; child = child.nextSibling) {
if (child.style) {
child.style.display = child.id == s ? 'inline' : 'none';
}
}
//info.style.visibility = 'visible';
} else {
info.style.visibility = 'hidden';
}
}

function updateCountry() { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
for (var i = select_dialect.options.length - 1; i >= 0; i--) {
select_dialect.remove(i);
}
var list = langs[select_language.selectedIndex];
for (var i = 1; i < list.length; i++) {
select_dialect.options.add(new Option(list[i][1], list[i][0]));
}
select_dialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible';
}

… with our changed gradual_reveal_country_game.html‘s In the Timestamp and/or Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Languages Game Tutorial is shown below.

Javascript Lazy Evaluation Languages Game Tutorial

Javascript Lazy Evaluation Languages Game Tutorial

Now that we have three game modes, further to the recent Javascript Lazy Evaluation Game Scroll Into View Tutorial, with …

  • Country Capitals Game
  • In the Hour Game … and today we introduce the …
  • Languages Game

… the HTML button element “traffic cop” for this, up to now, is given a rest, in favour of a new HTML “select” (ie. dropdown) element that is much better equipped for scenarios of more than two choices.

The “Languages Game” concept would be really simple if every country had one spoken language, but the world does not work this way. But, do you remember when we last presented Fairy Story Chrome Dictation Punctuation Tutorial? There, we were referencing Text to Speech software that Google has demonstrated at https://www.google.com/intl/en/chrome/demos/speech.html (for you Google Chrome users out there). Well, it’s full of great ideas regarding …

  • the mapping of a given Language name (along with its associated code) … to …
  • one or more locales

    In computing, a locale is a set of parameters that defines the user’s language, region and any special variant preferences that the user wants to see in their user interface. Usually a locale identifier consists of at least a language code and a country/region code. Locale is an important aspect of i18n.

… and this forms the basis of how we might map a language code back to a country code, for our Languages Game today.

Take a look at some new Javascript to help here …


function mybutclick(selo) {
var suffix='';
if (selo.value == '') {
if (simple) { document.getElementById('mybut').click(); }
} else {
they=selo.value;
//if (!simple) { document.getElementById('mybut').click(); }
if (document.URL.indexOf('?') == -1) { suffix='?simple=' + drilldown; } else if (document.URL.indexOf('simple=') == -1) { suffix='&simple=' + drilldown; }
location.href=(document.URL.split('#')[0] + suffix).replace('simple=' + drilldown, 'simple=' + they);
drilldown=they;
}
}

function butrand(asify) {
var myccis='', lno=0, irx=0, ctylist=[], jrx=-1;
var opts=[];
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
if (drilldown == 'lang') {
opts=document.getElementsByTagName('option');
while (jrx == -1) {
lno=Math.floor(Math.random() * 59);
document.getElementById('select_language').value='' + lno;
updateCountry();
rellang=document.getElementById('select_language').innerHTML.split(' value="' + lno + '">')[1].split('<')[0];
ctylist=document.getElementById('select_dialect').innerHTML.split('-');
jrx=eval(1 + Math.floor(Math.random() * eval(-1 + ctylist.length)));
myccis=ctylist[jrx].split('"')[0];
//alert(myccis + ' ... ' + opts[0].value + ' +++ ' + ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)] + '-' + myccis);
for (irx=0; irx<optslength; irx++) {
//alert(opts[irx].value + ' vs ' + myccis);
if (opts[irx].value == myccis) { atry=irx; rellangkb=butviacml(ctylist[eval(-1 + jrx)].split('"')[eval(-1 + ctylist[eval(-1 + jrx)].split('"').length)]) + '_' + myccis; return atry; }
}
jrx=-1;
}
}
}
}
return asify;
}

function butviacml(inlcode) {
var bparts=cmylang.split('>' + inlcode + '<');
lastengl='';
if (eval('' + bparts.length) > 1) {
var nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
if (eval('' + nextcell.length) <= 3) {
bparts=cmylang.split('>' + nextcell + '<');
nextcell=bparts[1].split('</t')[0].split('>')[eval(-1 + bparts[1].split('</t')[0].split('>').length)];
lastengl=nextcell;
} else {
lastengl=nextcell;
}
}
return inlcode;
}

function butmaybeisspokenin(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
//alert(cnames[eval(-1 + answer)] + ' language spot on=' + clangs[eval(-1 + answer)] + ' language one on on=' + clangs[eval(0 + answer)] + ' language one back on=' + clangs[eval(-2 + answer)]);
return asify.replace('en_AU', clangkbs[eval(-1 + answer)]) + ' is spoken ';
}
}
return asify;
}

function butmaybe(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
//alert('answer=' + answer + ' and gproposedanswer=' + gproposedanswer);
if (clanges[eval(-1 + answer)] == '') {
document.getElementById('source').title='';
lasthome='';
document.getElementById('source').oncontextmenu=function(){ homelang=homelang; };
} else {
document.getElementById('source').title='Right click to reveal language name in English';
lasthome=clanges[eval(-1 + answer)];
document.getElementById('source').oncontextmenu=function(){ alert(lasthome); };
}
return clangs[eval(-1 + answer)]; // + ' ' + clangkbs[eval(-1 + answer)]; //'English';
}
}
return asify;
}

function butmaybeno(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return '';
}
}
return asify;
}

function butmaybenone(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return '';
}
}
return asify;
}

function butthen(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game wants you to drag a spoken Language (appearing later) to table cell with a Country map where that language is spoken.';
}
}
return asify;
}

function butthentwo(asify) {
if (document.getElementById('selmode').value.replace(/^y/g,'') != '') {
if (document.getElementById('selmode').value == 'lang') {
return 'Language Game';
}
}
return asify;
}

function ouronl() {
cmylang=document.getElementById('mylangt').innerHTML;
if (drilldown != '') { document.getElementById('selmode').value=drilldown; }
for (var i = 0; i < langs.length; i++) {
select_language.options[i] = new Option(langs[i][0], i);
}
// Set default language / dialect ... thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
select_language.selectedIndex = 10;
updateCountry();
select_dialect.selectedIndex = 11;
showInfo('info_start');
}

function showInfo(s) { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
if (s) {
for (var child = info.firstChild; child; child = child.nextSibling) {
if (child.style) {
child.style.display = child.id == s ? 'inline' : 'none';
}
}
//info.style.visibility = 'visible';
} else {
info.style.visibility = 'hidden';
}
}

function updateCountry() { // thanks to Google https://www.google.com/intl/en/chrome/demos/speech.html
for (var i = select_dialect.options.length - 1; i >= 0; i--) {
select_dialect.remove(i);
}
var list = langs[select_language.selectedIndex];
for (var i = 1; i < list.length; i++) {
select_dialect.options.add(new Option(list[i][1], list[i][0]));
}
select_dialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible';
}

… with our changed gradual_reveal_country_game.html‘s Languages and/or Country Capital and/or In the Hour Game web application, below too.


Previous relevant Javascript Lazy Evaluation Game Scroll Into View Tutorial is shown below.

Javascript Lazy Evaluation Game Scroll Into View Tutorial

Javascript Lazy Evaluation Game Scroll Into View Tutorial

Within the changes involved in the recent Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial you may have seen the change


if (window.self !== window.top) { answer=answer; } else { document.getElementById('source').scrollIntoView(); }

What is the motivation for that change? Well, if a blog posting contains an HTML iframe pointing at our latest Country Capital or In the Hour Game web application, it would annoyingly scroll down to the webpage position of element document.getElementById(‘source’) in that iframe without the user having clicked any buttons. Dead annoying!

But then, can this same idea, or a similar scrolling equivalence help us out sometimes, on the other side of the coin? Well, yes, and that ability, encapulated in the logic of two clonish dropdowns …

  • one dropdown up the top of the webpage … and another “clone” …
  • dropdown to right in the middle of the table heightwise, roughly, as a position:fixed

    function overtoright(inspano) {
    if (window.self !== window.top) { answer=answer; } else {
    var rectxo=document.getElementById('mytable').getBoundingClientRect();
    inspano.style.position='fixed';
    inspano.style.left='' + eval(10 + eval('' + rectxo.right)) + 'px'; //'' + eval(-20 + screen.width) + 'px';
    inspano.style.top='' + Math.floor(eval(rectxo.top + rectxo.bottom) / 2) + 'px';
    inspano.style.zIndex='99';
    inspano.style.display='inline-block';
    }
    return inspano;
    }

    … element, so as to be within view more often

… helping to offer …

  • scrolling positional possibilities, as above … is timely way to be able to help out …
  • Geo Chart iframe scaling of itself and its contents …

    function siv(selo) {
    var ijk=0, ifsz=[], newishw=0, newishh=0;
    if (('' + selo.value).trim() != '') {
    if (('' + selo.value).trim() == '0') {
    window.scrollTo(0,0);
    } else if (('' + selo.value).trim() == '++') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) * 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) * 1.1)) + 'px';
    newishw=ifsz[ijk].src.split('width=')[1].split('&')[0];
    newishh=ifsz[ijk].src.split('height=')[1].split('&')[0];
    ifsz[ijk].src=ifsz[ijk].src.replace('width=' + newishw, 'width=' + Math.floor(eval(1.1 * eval('' + newishw)))).replace('height=' + newishh, 'height=' + Math.floor(eval(1.1 * eval('' + newishh))));
    }
    }
    } else if (('' + selo.value).trim() == '--') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) / 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) / 1.1)) + 'px';
    newishw=ifsz[ijk].src.split('width=')[1].split('&')[0];
    newishh=ifsz[ijk].src.split('height=')[1].split('&')[0];
    ifsz[ijk].src=ifsz[ijk].src.replace('width=' + newishw, 'width=' + Math.floor(eval(eval('' + newishw) / 1.1))).replace('height=' + newishh, 'height=' + Math.floor(eval(eval('' + newishh) / 1.1)));
    }
    }
    } else if (('' + selo.value).trim() == '+') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) * 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) * 1.1)) + 'px';
    }
    }
    } else if (('' + selo.value).trim() == '-') {
    ifsz=document.getElementsByTagName('iframe');
    for (ijk=0; ijk<ifsz.length; ijk++) {
    if (ifsz[ijk].src.indexOf('title=') != -1) {
    if (('' + ifsz[ijk].style.width).trim() == '') { ifsz[ijk].style.width='' + ifsz[ijk].getBoundingClientRect().width + 'px'; }
    ifsz[ijk].style.width='' + Math.floor(eval(eval(('' + ifsz[ijk].style.width.replace('100%','834px')).replace('px','')) / 1.1)) + 'px';
    ifsz[ijk].style.height='' + Math.floor(eval(eval(('' + ifsz[ijk].style.height).replace('px','')) / 1.1)) + 'px';
    }
    }
    } else {
    window.scrollTo(stoisleft[eval(-1 + eval('' + selo.value))], stoistop[eval(-1 + eval('' + selo.value))]);
    stos[eval(-1 + eval('' + selo.value))].scrollIntoView();
    }
    }
    }

Behind the scenes, we won’t say here exactly, but there is another Hint piece of logic activated. We’ll just say Map as an element to look for, as a first idea in a two part Hint mechanism?!

Yet again, we hope you try the changed gradual_reveal_country_game.html‘s Country Capital and/or In the Hour Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial is shown below.

Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial

Javascript Lazy Evaluation In the Hour Game Daylight Saving Tutorial

Regarding yesterday’s Javascript Lazy Evaluation Country Game Hints Tutorial progress with the “In the Hour” mode of game play, we thought there would only be the rare annoyance regarding Daylight Saving alterations to the default timezone offsets to GMT time, but there were more than we realized, prompting us to start using codelines like …


var newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));

… to start working out timezone offsets in the client world (as you may remember us discussing with SVG Network Clock Minimize Tutorial in recent times) checking on those PHP timezone derivations we default to, but might be wrong by an hour, regarding Daylight Saving timezone arrangements in place for certain times of the year in some countries …


var cinthehourspush=(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
var newd = new Date(new Date().toLocaleString("en-US", {timeZone: yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('>')[1].split('<')[0]}));
var newh=eval(('' + newd).split(':')[0].split(' ')[eval(-1 + ('' + newd).split(':')[0].split(' ').length)]);
if (cinthehourspush.indexOf('' + ('0' + newh).slice(-2)) != 0) {
var oldh=eval('' + cinthehourspush.split(':')[0]);
if (oldh != newh) {
//alert('uhour=' + uhour + ' and oldh=' + oldh + cinthehourspush.substring(2) + ' goes with ' + yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' and newh=' + newh + cinthehourspush.substring(2));
if (newh < uhour && newh == 0 && uhour == 23) {
sofarhrs+='+' + eval(24 - uhour) + ' ';
} else if (newh > uhour && newh == 23 && uhour == 0) {
sofarhrs+='-' + eval(24 - newh) + ' ';
} else if (oldh > uhour) {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(oldh - uhour), '' + eval(newh - uhour)) + ' ';
} else if (oldh < uhour) {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('' + eval(uhour - oldh), '' + eval(uhour - newh)) + ' ';
} else if (newh > uhour) {
sofarhrs+='+' + eval(newh - uhour) + ' ';
} else if (newh < uhour) {
sofarhrs+='-' + eval(uhour - newh) + ' ';
}
}
gcinthehourspush='' + ('0' + newh).slice(-2) + cinthehourspush.substring(2);
}

We’ve also added in more linking that adds on to yesterday’s existant …

  • Placename links to Wikipedia … so that now we also have …
  • Country links to Wikipedia … and …
  • TimeZone information links added to the “just after” times shown

Also added, today, is another hint, we’ve called “Regions”, which colour codes Geo Charts (albeit in a subtle way) according to those Regional first words in a TimeZone name like …


Asia/Singapore

… where that “Asia” is differentiated via our new arrays …


var rcolmaps=['Africa','Asia','Europe','GMT','America','Pacific','Arctic','Atlantic','Indian','Australia','Antarctica'];
var rcolmapred=['15','45','55','55','75','85','95','a5','b5','d5','e5'];

We also thought “right now” was a bit of a waste of time, when we could show the user (a phrase like) “on Monday” (ie. on day of the week).

And so, yet again, we hope you try the changed gradual_reveal_country_game.html‘s Country Capital and/or In the Hour Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation Country Game Hints Tutorial is shown below.

Javascript Lazy Evaluation Country Game Hints Tutorial

Javascript Lazy Evaluation Country Game Hints Tutorial

Ideally, yesterday’s Javascript Lazy Evaluation Country In the Hour Game Tutorial suits …

  • geography buffs … all the way through to …
  • geography students

… alike. Or at least we’d like to help this be so, and in that respect we decided to offer two modes of Hints for the Country Game (whether that be Capitals Game or In the Hour Game) play …

  • show country flags (ie. those “combination emojis” for the country flags, derivable from that country’s ISO 2 letter country code) …

    var useflags=location.search.split('flags=')[1] ? true : false;
    useflags=location.search.split('wimgs=')[1] ? true : useflags;

    function checkflags(cbo, cbochecked) {
    if (cbochecked || document.getElementById('wimgs').checked) {
    useflags=true;
    } else {
    useflags=false;
    }
    applyhints('');
    }

    function orflag(thiscc) {
    var ccchar='', ccsuff='';
    var lri='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var dri=['127462','127463','127464','127465','127466','127467','127468','127469','127470','127471','127472','127473','127474','127475','127476','127477','127478','127479','127480','127481','127482','127483','127484','127485','127486','127487'];
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+=String.fromCodePoint(eval('' + dri[eval('' + lri.indexOf(ccchar))])); //'&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    return ccsuff;
    }


    function applyhints(towhat) {
    var yt='', nnyt='';
    if (useflags) {
    if (document.getElementById('flags').checked) {
    myflag=orflag(ccodes[eval(-1 + answer)]);
    document.getElementById('source').style.backgroundImage='URL("' + svgtemp.replace('48','96').replace('30%','49%').replace('>1 +', '>' + myflag) + '")';
    document.getElementById('source').style.backgroundPosition='right center';
    document.getElementById('source').style.backgroundRepeat='no-repeat';
    }
    if (document.getElementById('wimgs').checked) {
    if (yourtzlist.indexOf(',' + ccodes[eval(-1 + answer)] + ',') != -1) {
    yt=yourtzlist.split(',' + ccodes[eval(-1 + answer)] + ',')[1].split('>')[1].split('<')[0];
    nnyt=yt.replace(yt.split('/')[0] + '/','');
    //alert(document.getElementById('tzi').src.split('?')[0].split('#')[0] + '?tzexact=' + encodeURIComponent(yt.replace(/\ /g,'_')) + '&tznickname=' + encodeURIComponent( nnyt.replace(/\ /g,'_') ));
    document.getElementById('tzi').src=document.getElementById('tzi').src.split('?')[0].split('#')[0] + '?tzexact=' + encodeURIComponent(yt.replace(/\ /g,'_')) + '&tznickname=' + encodeURIComponent( nnyt.replace(/\ /g,'_') );
    }
    }
    } else {
    document.getElementById('source').style.backgroundImage='';
    document.getElementById('source').style.backgroundRepeat='no-repeat';
    document.getElementById('ourcanvas').style.backgroundImage='';
    document.getElementById('ourcanvas').style.backgroundRepeat='no-repeat';
    }
    return towhat;
    }

    …and/or …
  • Wikipedia images …

    function checkwimgs(cbo, cbochecked) {
    if (cbochecked || document.getElementById('flags').checked) {
    useflags=true;
    } else {
    useflags=false;
    }
    applyhints('');
    }

    function fgcit(iois) {
    var outof=["left top","left center","left bottom","right top","right center","right bottom","center top","center center","center bottom"];
    var startwith='', endwith='', imglist=[];
    if (iois != null) {
    if (iois.src.indexOf('tzexact=') != -1) {
    var aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (aconto.body.outerHTML.replace(/\"\;/g,"'").indexOf("document.getElementById('ourcanvas').style.background") != -1) {
    //document.getElementById('ourcanvas').style.backgroundRepeat='no-repeat';
    startwith="document.getElementById['ourcanvas'].style.background" + aconto.body.outerHTML.replace(/\&\;/g,"&").replace(/\"\;/g,"'").split("document.getElementById('ourcanvas').style.background")[1].split(';')[0] + ';';
    imglist=startwith.split(',');
    for (var jiu=0; jiu<imglist.length; jiu++) {
    if (jiu == 0) {
    endwith=imglist[jiu].trim().replace(/\)/g, ') ' + outof[0] + ' no-repeat').replace('URL(', 'linear-gradient(rgba(255,255,255,0.7),rgba(255,255,255,0.7)),URL(');
    } else {
    endwith+=',' + imglist[jiu].replace(')', ') ' + outof[eval(jiu % outof.length)] + ' no-repeat')
    }
    }
    eval(endwith.replace("document.getElementById['ourcanvas'].", "document.getElementById('ourcanvas')."));
    }
    }
    }
    }
    }
    }

After all, most of us are not destined to visit or travel or tour all these countries, alas!

And so, again, hope you try the changed gradual_reveal_country_game.html‘s Country Capital and/or In the Hour Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation Country In the Hour Game Tutorial is shown below.

Javascript Lazy Evaluation Country In the Hour Game Tutorial

Javascript Lazy Evaluation Country In the Hour Game Tutorial

The “genericization drive” regarding “country map iframe Geo Chart content” has passed us now, as last discussed in yesterday’s Javascript Lazy Evaluation Country Capital Game Context Tutorial, about our …

  • Country Capital Game … and today we start down the road to other game types that could involve “country map iframe Geo Chart content” and came up with a …
  • Country “In the Hour” Game

… whereby a user matches …

  • a “draggable” source time in some country … with …
  • a “droppable intoabletarget “country map iframe Geo Chart content” table cell

… the correct selection of which scores for the game player. You could think of it as a TimeZone Game, perhaps?!

The PHP TimeZone smarts helped derive the huge Javascript variable we now define in the game, and used


var ud = new Date();
var uhour = ud.getUTCHours();
var umin = ud.getUTCMinutes();
var chours=[], cinthehours=[], sofarhrs=' ';



var yourtzlist="<option value=\"GMT\" data-geo=\"51.4934,0.0098,GMT,GB,+0\">GMT</option><option value=\"Africa/Abidjan\" data-geo=\"5.31666,-4.03334,GMT,CI,+0\">Africa/Abidjan</option><option value=\"Africa/Accra\" data-geo=\"5.55,-0.21667,GMT,GH,+0\">Africa/Accra</option><option value=\"Africa/Addis_Ababa\" data-geo=\"9.03333,38.7,EAT,ET,+3\">Africa/Addis_Ababa</option><option value=\"Africa/Algiers\" data-geo=\"36.78333,3.05,CET,DZ,+1\">Africa/Algiers</option>"; // etcetera etcetera etcetera

function choosejusttheone(thes, thiscc) {
if (!thes) { return false; }
if (eval('' + yourtzlist.split(',' + thiscc + ',').length) != 2) { return true; }
if (yourtzlist.split(',' + thiscc + ',')[1].split('"')[0].indexOf('.') != -1) { return true; }
if (sofarhrs.indexOf(' ' + yourtzlist.split(',' + thiscc + ',')[1].split('"')[0] + ' ') != -1) { return true; }
return false;
}


function getnextcountrycode() {
if (eval('' + ccodes.length) < 9) {
var mycc=document.getElementById('myctable').innerHTML;
var opts=document.getElementsByTagName('option');
var ths=document.getElementsByTagName('th');
var atry=Math.floor(Math.random() * eval('' + opts.length));
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
}
while (mycc.indexOf('>' + opts[eval('' + atry)].innerText + '<') == -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
if (mycc.indexOf('>' + opts[eval('' + atry)].innerText + '<') != -1) {
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
}
}
}
optfinds+=opts[eval('' + atry)].value + ' ';
ccodes.push(opts[eval('' + atry)].value);
cnames.push(opts[eval('' + atry)].innerText);
ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
if (!simple) {
chours.push(-99);
cinthehours.push("");
} else {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
}

}
}

… as required. The user can toggle between the two game modes by clicking that top button.

We, again, hope you try the changed gradual_reveal_country_game.html‘s Country Capital and In the Hour Game web application, below too, yourself?!

Stop Press

We wanted to start involving Wikipedia links and update Geo Charts in either mode of play for the games above, and as a result “function getnextcountrycode” became …


function getnextcountrycode() {
if (eval('' + ccodes.length) < 9) {
var mycc=document.getElementById('myctable').innerHTML;
var opts=document.getElementsByTagName('option'), longis='', latis='';
var ths=document.getElementsByTagName('th');
if (optslength < 0) {
for (iii=0; iii<opts.length; iii++) {
if (('' + opts[iii].value).indexOf(',') != -1 && optslength < 0) { optslength=eval(-1 + iii); }
}
if (optslength < 0) { optslength=eval('' + opts.length); }
}
var atry=Math.floor(Math.random() * eval('' + optslength));
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + opts.length));
}
while (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') == -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + optslength));
if (mycc.indexOf('<th>' + opts[eval('' + atry)].innerText + '</th><th>') != -1) {
while (optfinds.indexOf(' ' + opts[eval('' + atry)].value + ' ') != -1 || opts[eval('' + atry)].value == 'MK' || choosejusttheone(simple, opts[eval('' + atry)].value)) {
atry=Math.floor(Math.random() * eval('' + optslength));
}
}
}
optfinds+=opts[eval('' + atry)].value + ' ';
ccodes.push(opts[eval('' + atry)].value);
cnames.push(opts[eval('' + atry)].innerText);
ccapitals.push(mycc.split("<th>" + opts[eval('' + atry)].innerText + "</th><th>")[1].split("<")[0]);
subfroms.push('[-89.0000|-88.0000|~From~,2]');
if (!simple) {
if (document.getElementById(ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20').replace(/\ /g,'%20'))) {
longis='' + document.getElementById(ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20').replace(/\ /g,'%20')).value.split(',')[0].split('|')[0];
latis='' + document.getElementById(ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20').replace(/\ /g,'%20')).value.substring(eval(1 + eval('' + longis.length)));
cplaces.push(latis + '|' + longis);
subtos.push('[' + cplaces[eval(-1 + cplaces.length)] + '|~' + ccapitals[eval(-1 + ccapitals.length)].replace(/\_/g,'%20') + '~,2]');
} else {
cplaces.push('');
subtos.push('[-89.0000|-88.0000|~From~,2]');
}
chours.push(-99);
cinthehours.push("");
} else {
sofarhrs+=yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0] + ' ';
cinthehours.push(('0' + eval(eval(eval(eval(yourtzlist.split(',' + opts[eval('' + atry)].value + ',')[1].split('"')[0].replace('+','')) + uhour) + 24) % 24)).slice(-2) + ':' + ('0' + umin).slice(-2));
subtos.push(lastsubtos);
cplaces.push(decodeURIComponent(lastsubtos.split('~')[1]));
}
}
}


Previous relevant Javascript Lazy Evaluation Country Capital Game Context Tutorial is shown below.

Javascript Lazy Evaluation Country Capital Game Context Tutorial

Javascript Lazy Evaluation Country Capital Game Context Tutorial

The improvements, today, onto yesterday’s Javascript Lazy Evaluation Country Capital Game Tutorial‘s “Country Capital Game” web application revolve around “context” …

  • there’s the “context” between land masses and sea … as well as …
  • there’s the “context” between country and world view

… both of which take us further into the realms of Google Chart Geo Chart usage, even “unique usage for us”, as far as the first one above.

Regarding the “context” between land masses and sea, wouldn’t it be good, on the map to colour the land with a greener tinge? Anyone, anyone, is green the go? Yes, 3GPP, or is that CP3O, disguised as R2D2 … anyway … yes, we could …

  • isolate the inherent map contents in its SVG guise … but if we could just censure the content here just that teensy weensy bit, now
  • we could torture that SVG to reveal its fill colourwe could do research and development, via a web browser web inspector, into that SVG’s path element fill colour … spoiler alert … #f5f5f5 (grey) … and …
  • liquidate its assetsgently coerce the map into thinking its SVG path element fill colour should be #c5f5f5 (our greenish tinge)

Thanks, can I call you 3o?


function hashit(iois) {
if (iois != null) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
aconto.getElementById('myh').style.display='none'; // aconto.getElementById('chart_div').scrollIntoView();
// Thanks to https://stackoverflow.com/questions/6088409/svg-drop-shadow-using-css3
setTimeout(function(){ aconto.getElementById('chart_div').innerHTML=aconto.getElementById('chart_div').innerHTML.replace('</svg>', '</svg><style> .shadow { -webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); } </style>').replace(/\#f5f5f5\;\"/g,'#c5f5f5;" class="shadow"').replace(/\#f5f5f5\"/g,'#c5f5f5" class="shadow"'); }, 4000);
}
}
}
}

Oh, okay then. Sorry. Thanks, 3GPPsubsection III! You do get straight to the point, there!

And then, regarding the “context” between country and world view, we have a two part improvement to matters here, we feel. Firstly, we hope to help contextualize “where in the world” is a country, and secondly, we wanted to “value add” for these popup windows we might open as the user hovers over a “country map” cell (filled with iframe Google Chart Geo Chart content), otherwise such interventions can be annoying, and we hope we’re not making the game too easy by adding to …

  • the existant onmouseover event creating popup window … now …
  • identical #c5f5f5 filled land mass “country map” … our newly added …
  • “world map” view of that same country, highlighted

for context


var wmapurl='<iframe src="//www.rjmprogramming.com.au/PHP/GeoChart/geo_chart.php?title=World%20Map&width=834&height=520&country=Country&popularity=Popularity&data=%20[~IT~,2]"></iframe>';

var subfrom='~IT~';
var subto='~IT~';

function woit(thissrc,thiso) {
if (thissrc.indexOf(hastoinvolve.replace(' src=','//')) != -1 && thissrc.replace('http:','').replace('https:','') != lastwosrc.replace('http:','').replace('https:','') && sowoa.replace(/http\:/g,'').replace(/https\:/g,'').indexOf(' ' + thissrc.replace('http:','').replace('https:','') + ' ') == -1) {
lastwosrc=thissrc;
var therect=thiso.getBoundingClientRect();
if (wo) {
if (!wo.closed) {
wo.close();
}
wo=null;
sowoa+=thissrc + ' ';
subto='~' + thissrc.split('?title=')[1].split(';')[0] + '~';
wo=window.open(thissrc,'_blank','top=' + therect.top + ',left=' + therect.left + ',width=' + eval(2 * thewidth) + ',height=' + eval(2 * theheight));
//wo.focus();
wo.onload = function() {
setTimeout(function(){ wo.document.getElementById('chart_div').innerHTML=wo.document.getElementById('chart_div').innerHTML.replace('</svg>', '</svg><style> .shadow { -webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); } </style>').replace(/\#f5f5f5\;\"/g,'#c5f5f5;" class="shadow"').replace(/\#f5f5f5\"/g,'#c5f5f5" class="shadow"'); wo.document.getElementById('chart_div').innerHTML+=wmapurl.replace(subfrom,subto); }, 4000);
};

} else {
sowoa+=thissrc + ' ';
subto='~' + thissrc.split('?title=')[1].split(';')[0] + '~';
wo=window.open(thissrc,'_blank','top=' + therect.top + ',left=' + therect.left + ',width=' + eval(2 * thewidth) + ',height=' + eval(2 * theheight));
//wo.focus();
wo.onload = function() {
setTimeout(function(){ wo.document.getElementById('chart_div').innerHTML=wo.document.getElementById('chart_div').innerHTML.replace('</svg>', '</svg><style> .shadow { -webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7)); } </style>').replace(/\#f5f5f5\;\"/g,'#c5f5f5;" class="shadow"').replace(/\#f5f5f5\"/g,'#c5f5f5" class="shadow"'); wo.document.getElementById('chart_div').innerHTML+=wmapurl.replace(subfrom,subto); }, 4000);
};

}
}
}

… where element chart_div represents all the Google Chart Geo Chart smarts, thanks!

We hope you try the changed gradual_reveal_country_game.html‘s Country Capital Game web application, below too, yourself?!


Previous relevant Javascript Lazy Evaluation Country Capital Game Tutorial is shown below.

Javascript Lazy Evaluation Country Capital Game Tutorial

Javascript Lazy Evaluation Country Capital Game Tutorial

Just like with yesterday’s Javascript Lazy Evaluation Game Involvement Tutorial

… of recent times. But this time, with our gradual_reveal_country_game.html Drag and Drop Country Capital Game we introduce to the target “Drop Zone” table cell content, for the first time, we have …

… to match the associated source “Drag” element available for the user to drag and drop into the correct table cell below, to score in today’s geography game.


Previous relevant Javascript Lazy Evaluation Game Involvement Tutorial is shown below.

Javascript Lazy Evaluation Game Involvement Tutorial

Javascript Lazy Evaluation Game Involvement Tutorial

Yes, we’ve decided to involve the Lazy Evaluation and async and await and Promise and setTimeout Javascript logic of yesterday’s Javascript Lazy Evaluation Promise Tutorial into a Drag and Drop mathematics game for Small Integers from 1 to 9. Can you hear Alice in the middle room?!

Our “mathematical sentences” to solve in this game, where the operators can be + or – or / or * or %, and integer is number from 1 to 9, can be …

  • hard … made up of …
    integer operator integer operator integer operator
    integer operator integer operator
    integer operator
    integer operator integer operator integer

    … or …

  • simple … made up of …
    integer operator integer
    operator integer
    operator
    integer operator integer

… parts to the “mathematical sentence” revealed gradually, using those aforesaid mentioned Javascript techniques, the less revealed as the user answers, the bigger the score, if correct.

The (non-mobile only) cursor and cell background images are formed via data URI svg+xml formats …

Cursor Cell

<style>
* {
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='48' width='126' viewport='0 0 100 100'><polyline points='40,2 20,15 80,10 60,20 126,30 86,48' style='fill:none;stroke:black;stroke-width:3' /><text y='90%'>\002753</text><ellipse cx='24' cy='20' rx='22' ry='13' style='fill:purple' /><ellipse cx='22' cy='17' rx='19' ry='12' style='fill:lime' /><ellipse cx='21' cy='14' rx='16' ry='12' style='fill:yellow' /><rect x='40' y='20' width='80' height='25' style='fill:blue'><animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='5s' repeatCount='indefinite' /></rect>Sorry, your browser does not support inline SVG.</svg>") 16 16, crosshair;
}
</style>

var svgtemp="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='48' width='126' viewport='0 0 100 100'><text x='20%' y='30%' stroke='blue'>1 +</text></svg>";
// ... used later regarding tdsos = document.getElementsByTagName('td'); // ... and nextanswer is ... next answer ...
setTimeout(() => { tdsos[eval(-1 + nextanswer)].style.backgroundImage='URL("' + svgtemp.replace('>1 +', '>' + parts[eval(-1 + nextanswer)].trim()) + '")'; getnextanswer(); }, 200);

… in our gradual_reveal_game.html Small Integer Game you can also try below …


Previous relevant Javascript Lazy Evaluation Promise Tutorial is shown below.

Javascript Lazy Evaluation Promise Tutorial

Javascript Lazy Evaluation Promise Tutorial

Working on yesterday’s Javascript Lazy Evaluation Follow Up Tutorial subject matter further today, we’d like to introduce a glossary of terms for beginners here …

  • async
    function

    The async function declaration creates a binding of a new async function to a given name. The await keyword is permitted within the function body, enabling asynchronous, promise-based behavior to be written in a cleaner style and avoiding the need to explicitly configure promise chains.

  • await
    operator

    The await operator is used to wait for a Promise and get its fulfillment value. It can only be used inside an async function or at the top level of a module.

  • Promise
    object (thenable)

    The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

  • Lazy
    syntax (function)

    Lazy evaluation means to delay the evaluation of an expression until it’s needed. Lazy evaluation is sometimes referred to as call-by-need.

    The opposite of lazy evaluation is an eager evaluation. It’s an evaluation strategy used in most programming languages.

    Lazy evaluation makes it possible to:

    define potentially infinite data structures
    increase performance by avoiding needless computations
    customize iteration behavior for data structures that want its elements accessible to the public

  • setTimeout
    function (global)

    The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires.

Meanwhile you can (re-)try our Javascript modified lazy_async.htm web application in a new tab or below …


Previous relevant Javascript Lazy Evaluation Follow Up Tutorial is shown below.

Javascript Lazy Evaluation Follow Up Tutorial

Javascript Lazy Evaluation Follow Up Tutorial

Further to yesterday’s Javascript Lazy Evaluation Primer Tutorial‘s subject matter regarding Lazy Evaluations and Javascript async functions, we’ve stumbled upon another great resource, thanks, from which we can base, to develop a web application, we’re hoping.

Within this “proof of concept” code basis you will find setTimeout (timer) references to Lazy Evaluations like …


setTimeout(() => {
aminterested='Just';
resolve("fast");
consolelog("fast promise is done");
aminterested='';
}, 1000);

… as a function that …

  • attempts to start in one second’s time …
  • as needed that function is performed

The possibilities here are multifaceted, and varied, and definitely worth experimenting with, within Javascript client work.

So our starting web application can be tried in a new tab or below …


Previous relevant Javascript Lazy Evaluation Primer Tutorial is shown below.

Javascript Lazy Evaluation Primer Tutorial

Javascript Lazy Evaluation Primer Tutorial

Do you remember, with the presentation of …

  • Promise Object Sleeping and Doing Primer Tutorial we talked about the Javascript Promise object? Well today, in that similar line of thinking, we wanted to touch on …
  • Lazy Evaluation in Javascript …

    Lazy evaluation means to delay the evaluation of an expression until it’s needed. Lazy evaluation is sometimes referred to as call-by-need.

    The opposite of lazy evaluation is an eager evaluation. It’s an evaluation strategy used in most programming languages.

    Lazy evaluation makes it possible to:

    define potentially infinite data structures
    increase performance by avoiding needless computations
    customize iteration behavior for data structures that want its elements accessible to the public

Personally, we’re more your “eager” types, but we’ve had help in the past from brilliant “lazy” types too, especially when we presented Selection API and Clipboard API Tutorial, and so, we honed in on some Javascript “Lazy Evaluation” code, and put together some status information shown regarding timings and calls with respect to Javascript …

  • “Lazy Evaluation” in Javascript … classical syntax goes …

    f = () => expression;

    … and …
  • async function in Javascript … classical syntax example goes …

    function resolveAfter2Seconds() {
    return new Promise((resolve) => {
    setTimeout(() => {
    resolve('resolved');
    }, 2000);
    });
    }

    async function asyncCall() {
    console.log('calling');
    const result = await resolveAfter2Seconds();
    console.log(result);
    // Expected output: "resolved"
    }

… into the changed clipboard_api_test.html Selection and Clipboard API usage web application for you to try yourself with some image or text clipboard usages.


Previous relevant Promise Object Sleeping and Doing Primer Tutorial is shown below.

Promise Object Sleeping and Doing Primer Tutorial

Promise Object Sleeping and Doing Primer Tutorial

We’re here today to fulfil yesterday’s Web Application Controlled Progress Cursor Primer Tutorial‘s pledge …

… which reminded me that we need to learn some more about the promise object

… and were happy to discover the Promise object talents of …

  • sleeping … allowing for …
  • multitasking
  • doing … all using clientside Javascript

… very interesting. The serverside languages such as PHP make it a doddle to multitask (via sleep) but Javascript sleep has not always been a straightforward proposition, until we could promise, that is!

Today’s await.html‘s use of it to sleep and in between show …

  1. analogue clock … and …
  2. Dams of the USA (via dams_usa.html changed this way)

… asynchronously both doing their own thing while the await.html works away in the background too, feeding off “child 2” clicks of “child 1” above to know when to say how long the dams took to load. Yes, the “child 2” “onload” event, alone, cannot help determine this, but more “drilling into” the inner workings of the code behind “child 2″‘s progress element, via …


<html>
<head>
<script type='text/javascript'>
var numsleeps=700000;
var ix=0;
var d=new Date();
var marks=[new Date(), new Date()];
var imark=0;

function sleep(ms) { // thanks to https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
console.log(numsleeps + ' Taking a break...' + d);
await sleep(2000);
d=new Date();
console.log(numsleeps + ' Two seconds later, showing sleep in a loop...' + d);

// Sleep in loop
for (let i = 0; i < 5; i++) {
if (i === 3) {
await sleep(2000);
d=new Date();
console.log(numsleeps + ' ' + d);


}
}
numsleeps--;
if (('' + numsleeps) != '0' && ('' + numsleeps).indexOf('-') == -1) { setTimeout(demo, 1); }
}

function betw() {
var seconds = (marks[1].getTime() - marks[0].getTime()) / 1000;
document.getElementById('sh1').innerHTML='It took ' + seconds + ' seconds (from ' + marks[0] + ' to ' + marks[1] + ') to load the dams.';
numsleeps=0;
}

function markit() {
marks[imark]=d;
imark++;
console.log('mark ' + imark + ': ' + d);
if (imark == 2) { setTimeout(betw, 800); imark=0; }
}

demo();
</script>
</head>
<body>
<h1>Sleeping and Doing via Promise Object - RJM Programming - July, 2021 <span id=sh1></span></h1>
<table style=width:100%;height:90%;><tr><td><iframe onclick="markit();" id=lif src=./analogue_clock.htm style=width:100%;height:100%;></iframe></td><td><iframe id=rif src=./dams_usa.html?rand=7564675 style=width:100%;height:100%;></iframe></td></tr>
</body>
</html>


Previous relevant Web Application Controlled Progress Cursor Primer Tutorial is shown below.

Web Application Controlled Progress Cursor Primer Tutorial

Web Application Controlled Progress Cursor Primer Tutorial

We had occasion to revisit the card game (and more) recent web application exploits highlighted in the recent Just Javascript Card Game Cursor Tutorial thread of blog postings and shaped to play Bridge via …


https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=04.1:ara

… and was “personally relatively” happy up to the first Javascript prompt popup window. Huh?! What’s with “personally relatively”? Can I be serious? Well, I’m insulted!

The thing is, I don’t mind, when I’m writing the code (funny about that?!) very complex and convoluted prompt window instructions and options. But …

  • not everybody is willing to read such long diatribes
  • actions can speak louder than words, so we figure between those first two prompt windows in a Bridge or 500 card game, it would be beneficial to show a “progress cursor” (ie. usually associated with the user waiting for a process to finish) between the first and second prompt windows to help show the players there could be waiting and irrelevant players turning away should all four players want to play fairly in their game

It was an interesting Javascript coding exercise …

  1. (sort of) overload the “prompt” function with our inhouse “superprompt” function via …
    • globally replace ” prompt(” with ” superprompt(“
    • globally replace “=prompt(” with “=superprompt(“
  2. add the following Javascript code …

    var aheadoffirst=(('' + document.URL.replace('?', '&').indexOf('&card_') != -1) ? trueize() : 0);

    function dbcpp() {
    if (aheadoffirst == 2) {
    document.body.style.cursor='progress'; // between first and second prompt windows
    setTimeout(dbcpp, 1000);
    } else if (aheadoffirst == 0) {
    document.body.style.cursor='pointer';
    } else {
    document.body.style.cursor='pointer';
    setTimeout(dbcpp, 1000);
    }
    }

    function trueize() { // bit like a promise
    setTimeout(dbcpp, 1000);
    return 1;
    }


    function superprompt(opone, optwo) {
    if (aheadoffirst == 3) {
    document.body.style.cursor='pointer';
    aheadoffirst=0;
    } else if (aheadoffirst != 0) {
    aheadoffirst++;
    if (aheadoffirst == 3) {
    document.body.style.cursor='progress'; // between first and second prompt windows
    }
    }
    return prompt(opone, optwo);
    }

… which reminded me that we need to learn some more about the promise object.

See this in action with the changed cards_usefocus.html code behind the “Just Javascript” Memories Card Game or live run with single window (good for mobile) or default live run (for your platform, and if non-mobile it will try child popup windows).

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Games, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment