… style of arrangement in the past, but we’ve found it useful recently (a couple of times) because we find we want to, more and more, use …
hashtagged data
reassembled into a …
form
method=POST
action=[URLofInterestOfPHP]
target=_self
… arrangement …
… that way keeping any window.parent and window.self and/or window.opener and window.self connections intact, and at the same time, being able to involve very long (mostly hashtagged data) URLs in the arrangements.
Let’s show you an example. In the recently talked about Google ChartsImage Chart Map Chart inhouse interfacer called image_chart.php downaways into the code it now goes …
<?php
$screenheight='0';
<br>
// ;Continent;CC1|CC2|:blLAT,blLONG,trLAT,trLONG:width,height:scblX,scblY,sctrX,sctrY
$continfo=';Europe;IS|CY|:35.16666,-27.6,67.0,33.36666:468,450:422,560,890,140'; // 53 523
$continfo.=';Australia;AU|AU|:-44,113.65,-10.26667,161.28333:600,450:422,560,866,140';
$continfo.=';Asia;FI|WS|:-14,37,81,179.9:600,450:422,560,866,140';
$continfo.=';America;GS|US|:-56,-179.9,77,-35:600,450:422,560,866,140';
$continfo.=';Africa;TF||:-35,-17,37,52:600,450:422,560,890,140';
if (isset($_GET['screenheight'])) {
$screenheight=str_replace('+',' ',urldecode($_GET['screenheight']));
}
if (isset($_POST['screenheight'])) {
$screenheight=str_replace('+',' ',urldecode($_POST['screenheight']));
}
<br>
if (isset($_GET['nothing'])) {
exit;
} else if ($screenheight != '0' && !isset($_GET['returnxytoparent']) && (!isset($_POST['returnxytoparent']) && !isset($_POST['ix']))) {
echo "<html>
<head>
<script type=text/javascript>
function tryit() {
if (('' + location.hash).indexOf('returnxytoparent=') != -1) {
document.getElementById('returnxytoparent').value=decodeURIComponent(('' + location.hash).split('returnxytoparent=')[1].split('&')[0].split('#'));
document.getElementById('submy').click();
}
}
</script>
</head>
<body onload=tryit();>
<form style=display:none; target=_self action=/PHP/GeoChart/image_chart.php method=POST>
<input type=hidden name=returnxytoparent id=returnxytoparent value=\"\"></input>
<input type=hidden name=screenheight value=" . $screenheight . "></input>
<input type=submit style=display:none; value=Submit id=submy></input>
</form>
</body>
</html>";
exit;
} else if (isset($_GET['returnxytoparent']) || (isset($_POST['returnxytoparent']) && !isset($_POST['ix']))) {
// more code to do with real returnxytoparent data follows
}
// more code follows
?>
… called from our inhouse Region Picker in this way now (where inhouse Javascript function windowdotdotopen can be thought of as window.open for these purposes) …
… setting up a two way understanding between window.opener Region Picker and window.self Google Charts Image Chart Map Chart inhouse interfacer. Using that target=_self arrangement above allows …
despite the “double dipping” transfer of hashtagged URL data (when longer than 750 characters, that is) into method=POST form data (of considerable size) …
that understanding between window.open Region Picker and window.self Google Charts Image Chart Map Chart inhouse interfacer remains intact
Yayyyyyy!
If this was interesting you may be interested in this too.
… in a variety of ways, so as to use it (as a tool) to determine whether Google Charts Image Charts are active (though unlikely, because they are deprecated)
So, if Image Charts are deprecated, why bother? As Lleyton would say … come on! We live in hope!
And we like keeping the user informed, where possible.
Curl HTTP Request Methods Querying Primer Tutorial
We’re not allowed to start a blog posting with “Did you know?” … that would be just so bad?!
But … Did you know?
That wonderful curl tool can help you … ↘️ 👩🏼💻 ↙️ … yes, you, find out the list of HTTP Request Methods available at a website of interest …
from the web server command line
user@Users-Air htdocs % curl -X OPTIONS https://www.rjmprogramming.com.au -i
HTTP/1.1 200 OK
Date: Wed, 22 May 2024 00:09:44 GMT
Server: Apache/2.2.29 (Unix) mod_ssl/2.2.29 OpenSSL/1.0.1e-fips mod_bwlimited/1.4
Allow: GET,HEAD,POST,OPTIONS,TRACE
Content-Length: 0
Connection: close
Content-Type: text/html
background-image:url(‘data:image/svg+xml;utf8, blahde blah ‘); nor background-image:url(‘data:image/svg+xml;base64, blahde blah ‘); ideas were not working for us … but today, we started to try …
overlay HTML div position:absolute; opacity:0.5; z-index:-4; …
We can’t remember a “foreground overlay” scenario so resembling a “background image feeling” end result, the transparent colour introduced into the Google ChartsGeo ChartSVG being crucial to help make this all work.
We want to be able to control the way a Google Charts Geo Chart can be nested within an HTML div element, for instance. We started the day wanting to be able to make …
a Google Charts Geo Chart be a background image to a div element … alas, on this first draft we couldn’t get there (but will continue with the research here) … whereas we succeeded …
adding the Google Charts Geo Chart interfacer’s resultant SVG data as the innerHTML (ie. content) …
<?php echo ”
function newbackin() {
if (dmyxhr.readyState == 4) {
if (dmyxhr.status == 200) {
if (dmyxhr.responseText) {
var m_t='image/jpeg';
var h_t='179';
var w_t='320';
var dbits = dmyxhr.responseText.split('\"height\": ');
if (dbits.length > 1) {
h_t=dbits[1].split(',')[0].split(String.fromCharCode(10))[0].split('}')[0].trim();
}
dbits = dmyxhr.responseText.split('\"mime_type\": \"');
if (dbits.length > 1) {
m_t=dbits[1].split('\"')[0];
}
dbits = dmyxhr.responseText.split('\"width\": ');
if (dbits.length > 1) {
w_t=dbits[1].split(',')[0].split(String.fromCharCode(10))[0].split('}')[0].trim();
}
dbits = dmyxhr.responseText.split('\"data\":');
dbits = dmyxhr.responseText.split('\"data\":');
if (dbits.length > 1) {
// replace all '_' with '/' and all '-' with '+' thanks to https://stackoverflow.com/questions/757675/website-screenshots
dgsbi='<img alt=\"Blog Posting Image\" style=\"width:' + w_t + 'px;height:' + h_t + 'px;\" width=' + w_t + ' height=' + h_t + ' src=\"data:' + m_t + ';base64,' + dbits[1].split('\"')[1].split('\"')[0].replace(/\_/g,'/').replace(/\-/g,'+') + '\"></img>';
//alert('dgsbi=' + dgsbi);
}
}
}
}
}
function ajaxit(urlin) {
if (urlin.length > 0) {
aurl=urlin;
if (window.XMLHttpRequest) {
dmyxhr = new window.XMLHttpRequest;
}
else {
try {
dmyxhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (othermicrosoft) {
try {
dmyxhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (failed) {
dmyxhr = false;
}
}
}
var xurl = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=' + encodeURIComponent(urlin) + '&screenshot=true';
if (dmyxhr) {
dmyxhr.onreadystatechange = newbackin;
dmyxhr.open('GET', xurl, true);
dmyxhr.send(null);
}
}
}
function wbtoa(instris) {
var outstris=instris;
while (outstris.indexOf(String.fromCharCode(10)) != -1) {
outstris=outstris.replace(String.fromCharCode(10),'');
}
var xzs=prompt(outstris, outstris);
return outstris.replace(/\\\"/g, \"'\");
}
In that Nearest Places form part of the TimeZone places webpage, we noticed that even when shaping to enter a TimeZone Placename in the first textbox we made no attempt to fill in …
latitude
longitude
… when we have the information to do so, and even if we’re misunderstanding a placename designation, that should not stop us from trying, because those two numerical fields above can be corrected, and the form resubmitted, in these scenarios.
Apart from making a PHP derived Javascript variable be made available to the code, we “wrap” …
GeoJson World Countries Drag and Drop Makeover Nuance Tutorial
Nuance alert! We’re not sure if you noticed, but if you tried out the Drag and Drop functionality in the World Countries web application of yesterday’s GeoJson World Countries Drag and Drop Makeover Tutorial you may have noticed …
for a country with lots of TimeZone places, like Brazil, you could get a decent Google Chart Geo Chart map up … but if you were to click the “Map?” link down the bottom of that iframe …
it would fail to show a Google Chart Map Chart for that country’s TimeZone places
This fix, believe it or not, is interesting, perhaps only in an “internal use only” sense, we grant you. But our solution got us delving even more into hashtagging data, so that the solution we came up with was a hybrid whereby …
stayed with PHP $_GET[] (ie. address bar ? and & argumented) data (versus using PHP $_POST[] methodologies) … but …
where it came to the &data=[most of the data] part, other than its first character, we hashtagged the rest
… so that the logic flows as per usual, but we intervene at places and flesh it out via location.hash (client side only) means. We won’t bore you too much with all the places of intervention except the receiving map.php’s “easiest to get” intervention …
In addition to the Wikipedia information, at the very least, presented following a successful drag and drop operation, from today, we also start presenting a new HTML iframe element containing …
Nearest TimeZone places along with Google Charts for each unique country involved
we wanted the first popup window content be aligned to the top and left … and then …
we thought it would be good to also, in “Drag and Drop land”, relevant countries nearby to the user’s drop point TimeZone Places be showing below that (and it panned out the best way to show this, for us, was via an iframe pointing at another incarnation of the tz_places.php webpage, because it could have GET arguments iso, iso2, iso3 etcetera to point at ISO 2 letter country codes, which we made more readily available (via a new data-ccglobal data attribute applied to the select option subelements presented) for the changed external Javascript countries.js we decided should get into the mix via a new Javascript function …
function tzagain(inhtml) {
var outhtml=inhtml, dccs=[], getarg='?', theone=1;
if (inhtml.indexOf('left:0px;') != -1 && inhtml.indexOf(' data-cc=') != -1) {
dccs=inhtml.split(' data-cc=');
for (var ii=1; ii<dccs.length; ii++) {
if (getarg == '?') {
getarg+='iso=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2);
theone++;
} else if (getarg.indexOf('=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2)) == -1) {
getarg+='&iso' + theone + '=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2);
theone++;
}
}
if (getarg != '?') {
if (inhtml.indexOf('</bo' + 'ody>') != -1) {
outhtml=inhtml.split('</bo' + 'dy>')[0] + '<iframe src="./tz_places.php' + getarg + '" style="position:absolute;left:0px;top:120px;width:100%;height:900px;"></iframe></body></html>';
} else {
outhtml=inhtml + '<iframe src="./tz_places.php' + getarg + '" style="position:absolute;left:0px;top:120px;width:100%;height:900px;"></iframe>';
}
}
}
return outhtml;
}
… that superfluous looking ?rand=blah measure being pretty useful really regarding getting around the cache keeping old external Javascript in its mind after changes.
Curiously, the grandparent regions.php starting off all this needed no changing! We hope you like these tweaks!
add similar drag and drop logic into our World Coastlines GeoJson web application … and along the way, also for the World Countries web application …
hold off involving the (pretty kludgy looking) vertical scrollbar of our drag and drop pin’s underlying HTML iframe …
<iframe scrolling=no frameborder=0 name=iftr id=iftr style=display:none; srcdoc="<body style=background-color:transparent;><p id=mg title='Wikipedia country page below via drag and drop to world map' draggable='true'>📍</p><br><br><div id=myh1></div><script type='text/javascript' src='./countries.js?rand=321156747657' defer></script></body>" data-src=></iframe>
… until the first drag operation starting, calls on …
parent.document.getElementById('iftr').scrolling='yes';
… proving a Javascript DOM control of the “scrolling” attribute works (as we weren’t sure, having never done this before)
It’s worth beavering away at a guinea pig web application until (just about complete) satisfaction (for now) before having a parallel set of code changes happening simultaneously, we’ve always found.
So, what happened in “external Javascript land”? No need for a “regions.js” here, as parent.document.URL can be scrutinised in that “external Javascript land” to discover which web application is the parent, and act accordingly. So changed were our changed external Javascript countries.js in …
our GeoJson World Countries web application Drag and Drop logic worked on an iPhone … but …
our GeoJson World Countries web application Drag and Drop logic did not work on an iPad
They’re both iOS! And usually the smaller iPhone has the problem and the larger iPad is okay when there is an odd scenario happening. So, what gives? Well, the odd thing is, it was just rearrangements of code and iframe srcdoc usage …
<iframe frameborder=0 name=iftr id=iftr style=display:none; srcdoc="<body style=background-color:transparent;><p id=mg title='Wikipedia country page below via drag and drop to world map' draggable='true'>📍</p><br><br><div id=myh1></div><script type='text/javascript' src='./countries.js?rand=321156747657' defer></script></body>" data-src=></iframe>
… that ended up helping us fix the issues. Figure this, on iPad our emoji pin could not be made visible down the bottom left of iPad screen but could be made to work in the title elements section?! Of course, we might have been having a bad day, but in our defence, even debugging in Safari via …
iPad Safari web browser invocation …
Apple white lead from iPad to MacBook Air …
MacBook Air Safari web browser Develop menu dropdown got us to debugging functionality
“long hover” (ie. on non-mobile, wait for a long while after the onmouseover event initiation to see whether the user is still hovering) … and today, a bit like that, is the new, for us …
“long drag” (the user waits a long time between the drag initialization and the drop event)
… and because we found “dawdling” on a drag and drop fairly unnatural, we think this “long drag” idea “has legs”, in that it works well as a deliberate act made by a user, knowing at the end they benefit from their actions. For us, with our GeoJSON Map web application, yesterday, with GeoJson World Drag and Drop Pin Tutorial, the drag and drop led to …
Wikipedia country information webpage … and today, we allow a “long drag” get you to …
Google Maps drop position information webpage … if the “long drag” is for 10 or more seconds …
Google Earth drop position information webpage … if the “very long drag” is for 20 or more seconds
onclick event logic … and today, we start to also include …
drag and drop event logic (like, but nuanced as explained below, the experimental drag and drop ideas included in the recent Planet Moon Game Tutorial) … the nuanced differences involving …
the drag part of the events occurs in an iframe (populated via small amount of srcdoc HTML and Javascript) able to reference its originator via window.parent …
drop part of the events occurs in that originator parent and so several Javascript function called by the child reside in the parent … and …
the child “drag” event controller uses the new external Javascript countries.js …
// countries.js
// July, 2023
// RJM Programming
// Help out countries.html and countries.php
var pos3=0, pos4=0, tdid='', poligono, punto, coone='', prectis;
// var poligono = [[2,9],[8,6],[12,10],[15,2],[10,4],[5,1]];
// var punto = [6, 5];
function pointInPolygon(polygon, point) { // thanks to https://community.appinventor.mit.edu/t/geofence-check-if-a-point-is-inside-a-polygon-javascript-map/57091
var odd = false;
for (var i = 0, j = polygon.length - 1; i < polygon.length; i++) {
if (((polygon[i][1] > point[1]) !== (polygon[j][1] > point[1]))
&& (point[0] < ((polygon[j][0] - polygon[i][0]) * (point[1] - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0]))) {
odd = !odd;
}
j = i;
}
return odd;
}
function andlaterstill() {
if (9 == 6) { // temporary
if (tdid != '') {
document.getElementById(tdid).innerHTML=document.getElementById(tdid).innerHTML.substring(0,1);
} else if (document.getElementById('mytable').innerHTML.indexOf(clonedatatwo) != '') {
document.getElementById('myh1').innerHTML=document.getElementById('myh1').innerHTML.split('</table>')[0] + '</table>';
}
if (document.getElementsByTagName('div')[0].innerHTML.indexOf(clonedatatwo) != -1) {
document.getElementsByTagName('div')[0].innerHTML=document.getElementsByTagName('div')[0].innerHTML.replace(clonedatatwo,'');
} else if (document.getElementsByTagName('div')[0].innerHTML.indexOf(clonedatatwo.replace('dragging','')) != -1) {
document.getElementsByTagName('div')[0].innerHTML=document.getElementsByTagName('div')[0].innerHTML.replace(clonedatatwo.replace('dragging',''),'');
} else if (document.body.innerHTML.split('<table')[0].indexOf(clonedatatwo.replace('dragging','')) != -1) {
document.body.innerHTML=document.body.innerHTML.replace(document.body.innerHTML.split('<table')[0], document.body.innerHTML.split('<table')[0].replace(clonedatatwo.replace('dragging',''),''));
} else if (document.body.innerHTML.split('<table')[0].indexOf(clonedatatwo) != -1) {
document.body.innerHTML=document.body.innerHTML.replace(document.body.innerHTML.split('<table')[0], document.body.innerHTML.split('<table')[0].replace(clonedatatwo,''));
}
}
tdid='';
}
function getprectis() {
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
return window.opener.document.body.getBoundingClientRect();
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
return parent.document.body.getBoundingClientRect();
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
return parent.document.body.getBoundingClientRect();
}
}
return null;
}
function wod(ididea) {
if (window.opener) {
if (window.opener.document.getElementsByTagName(ididea)[0]) {
return window.opener.document.getElementsByTagName(ididea)[0];
} else if (window.parent) {
if (parent.document.getElementsByTagName(ididea)[0]) {
return parent.document.getElementsByTagName(ididea)[0];
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName(ididea)[0]) {
return parent.document.getElementsByTagName(ididea)[0];
}
}
return null;
}
function ccit() {
var divs, esot=[], bodyois=null;
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
bodyois=window.opener.document.getElementsByTagName('body')[0];
divs=window.opener.document.getElementsByTagName('div');
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
bodyois=parent.document.getElementsByTagName('body')[0];
divs=parent.document.getElementsByTagName('div');
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
bodyois=parent.document.getElementsByTagName('body')[0];
divs=parent.document.getElementsByTagName('div');
}
}
function andqlater() {
//alert('HeRe');
tdid='';
var ppig='[]', coo='', coos=[], ip=0;
var squares; //=window.opener.document.getElementsByTagName('area');
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
squares=window.opener.document.getElementsByTagName('area');
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
squares=parent.document.getElementsByTagName('area');
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
squares=parent.document.getElementsByTagName('area');
}
}
window.addEventListener("DOMContentLoaded", () => {
const source = document.querySelector("#mg");
console.log('source.id=' + source.id);
source.addEventListener("dragstart", (ev) => {
console.log("dragStart");
// Change the source element's background color
// to show that drag has started
ev.currentTarget.classList.add("dragging");
// Clear the drag data cache (for all formats/types)
ev.dataTransfer.clearData();
// Set the drag's format and data.
// Use the event target's id for the data
ev.dataTransfer.setData("text/plain", ev.target.id);
//ev.dataTransfer.setData("text/html", ev.target.outerHTML);
});
source.addEventListener("dragend", (ev) =>
ev.target.classList.remove("dragging")
);
const target = wod('body'); //window.opener.document.getElementsByTagName('body')[0];
target.id='usemap';
console.log('target.id=' + target.id);
target.addEventListener("dragover", (ev) => {
console.log("dragOver");
ev.preventDefault();
});
target.addEventListener("drop", (ev) => {
console.log("Drop");
ev.preventDefault();
// Get the data, which is the id of the source element
const data = ev.dataTransfer.getData("text");
const source = document.getElementById(data);
… where heap memory concerns related to the global variables memory used in our GeoJson World Coastlines webpage could cause mobile platform usage reloads of the web application, reminiscent of the external Javascript concerns we had back at GeoJson World Countries SVG Overlay Safari Error Tutorial.
There, as for here, mobile usage got better by swapping global variable usage for HTML content static PHP …
GeoJson World Coastline Function Noun Naming Tutorial
We’re working on an extension to yesterday’s GeoJson World Coastline Rivers Quiz Tutorial‘s Rivers Quiz functionality within our GeoJson World Coastlines web application, and have …
settled on an approach … but …
not yet finished on deployment issues
… but it is this approach we wanted to talk about today.
Our approach borrows from Object Oriented Programming (OOP) the idea that …
just as with OOP thinking class names are like nouns and the methods within that class are like verbs … we, with our approach …
help readability of our non-OOP functional code by including those nouns and verbs, as well as ideas like use of plurals to indicate array involvement, with our Javascript function naming
… we can best illustrate to you via showing you new functions and variables and modified code to show you this approach in code …
var rivers='', arivers=[], iguess=-1, isofar=' ', jscore=0, jgoes=0, elema=null, contexta=null, rectisleft=0, rectistop=0, isokto=true;
var populations='', apopulations=[], jguess=-1, jsofar=' ', both=false, jlastn='';
var idone=false;
function askapopulation() {
var another=false;
var origboth=both;
var midbit='';
var thing='population';
if (!both) { midbit='Append spaces to also answer a question regarding the Rivers Quiz, or R to just do Rivers Quiz.'; } else { thing='river'; }
var retthis=prompt('What is the name of this new red population area plotted on the world map? ' + midbit + ' Enter ? to get given more time looking at (longitude,latitude) = (' + apopulations[jguess].split(':')[1].split(',')[0] + ',' + apopulations[jguess].split(':')[1].split(',')[1] + ')', '');
if (retthis == null) {
both=false;
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (retthis.toLowerCase().trim() == 'r') {
both=false;
isokto=true;
getariver();
return '';
} else if (retthis.trim() == '?') {
if (retthis.trim() != retthis && !origboth) { both=true; }
setTimeout(askapopulation, 9000);
return '';
} else if (retthis.trim() == '') {
if (retthis != '' && !origboth) { thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
if (retthis != '' && !origboth) { isokto=true; both=true; getariver(); }
} else if (jlastn.toLowerCase().indexOf(retthis.toLowerCase()) != -1 && jlastn.toLowerCase() == retthis.toLowerCase() && retthis.trim().length >= 1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (jlastn.toLowerCase().indexOf(retthis.toLowerCase()) == -1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (jlastn.toLowerCase() == retthis.toLowerCase()) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Well done! Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (retthis.trim().length >= 1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
}
if (both) { contexta.clearRect(0,0,360,180); }
if (both && !origboth) { isitok=true; getariver(); return ''; }
if (another) { if (both) { getariver(); getapopulation(); } else { getapopulation(); } } else { contexta.clearRect(0,0,360,180); }
return '';
}
function plotapopulation(which) {
if (isokto) { contexta.clearRect(0,0,360,180); }
//if (both) { isokto=true; }
jlastn=apopulations[which].split(':')[0];
var rest=apopulations[which].split(':')[1];
var restlonglat=[]; //rest.split(',');
restlonglat=rest.split(',');
if (eval('' + restlonglat.length) >= 2) {
contexta.fillStyle = 'red';
contexta.fillRect(eval(180.0 + eval('' + restlonglat[0])), eval(90.0 - eval('' + restlonglat[1])),1,1);
contexta.fill();
}
}
It’s time to turn our attention away from GeoJson World Countries, as talked about with yesterday’s GeoJson World Countries Plotted Ports Tutorial, and back to GeoJson World Coastline ideas. Why? We want to add a …
Rivers Quiz
… via the (generously provided) HTTP://geojson.xyz rivers lake centerlines GeoJSON data we download and then uploaded to become rivers.geojson data file. Now we were wondering out of …
use the URL to this GeoJSON file as the “src” attribute of an HTML iframe …
<iframe id=ifrivers onload=getthejson(this); style=display:none; src=./rivers.geojson></iframe>
… element (and then access the content via the onload event …
var rivers='', arivers=[], iguess=-1, isofar=' ', jscore=0, jgoes=0, elema=null, contexta=null, rectisleft=0, rectistop=0;
function getthejson(iois) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
rivers='' + aconto.body.innerHTML;
setTimeout(populaterivers, 500);
}
}
}
… function) would suffice, or if we would end up using …
Ajax call
… to access this data, and were a bit surprised the former method was all fine. Of course there are snazzy inbuilt Javascript hierarchical calls you can make to process the data, but we find, with GeoJSON data, in the client realm (where we’re keen to stay with today’s work (though PHP serverside can, of course, be purloined to do all this work, should you have that available)), of Javascript, we just need very basic string functions …
The progress with GeoJson World Countries helped too. We knew to add another HTML canvas layer as per …
document.body (now with the new onmousemove=airportplot(event); event logic) lowest level …
overlayed by HTML canvas element plotted with world country linework … now including …
overlayed by HTML canvas element dedicated to nearest airport plotting …
<canvas id=myacanvas height='180' width='360' style='background-color:transparent;z-index:55;display:inline-block;position:absolute;top:0px;left:0px;'></canvas>
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… and to, at document.body onload logic …
// ... and extended document.body onload event logic has added, up near its top ...
elema = document.getElementById('myacanvas');
contexta = elema.getContext('2d');
… and supplement with another HTML sub “emoji button” ❓ ( ❓ ) type element …
function askariver() {
var another=false;
var retthis=prompt('What is the name of this new blue river plotted on the world map? Enter ? to get given more time looking at (longitude,latitude) = (' + arivers[iguess].split(':')[1].split(',')[0] + ',' + arivers[iguess].split(':')[1].split(',')[1] + ')', '');
if (retthis == null) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (retthis.trim() == '?') {
setTimeout(askariver, 8000);
return '';
} else if (retthis.trim() == '') {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (lastn.toLowerCase().indexOf(retthis.toLowerCase()) == -1) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (lastn.toLowerCase() == retthis.toLowerCase()) {
jgoes++;
jscore++;
another=confirm('Well done! Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (retthis.trim().length >= 1) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else {
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
}
if (another) { getariver(); } else { contexta.clearRect(0,0,360,180); }
return '';
}
… to work the Rivers Quiz. Finally, though, for all good practicalities we also need those zoom logics out of GeoJson World Countries logic, via “emoji button” 🔎 ( 🔎 ) …
where to modularise … we think “data collection” commonality is a good reason, and so we make these changes to intair.php
making an (“animated emoji”) button dual purpose on top of originally being a single purpose button …
<sub title='Show Nearby Airports' onclick='doair=how(true,this); twothousand*=2; this.title=this.title.substring(0,4) + String.fromCharCode(105) + String.fromCharCode(110) + String.fromCharCode(103) + this.title.replace(this.title.split(String.fromCharCode(32))[0] + String.fromCharCode(32), String.fromCharCode(32));' data-type=9992 style=cursor:pointer; id=portsub>✈</sub>
… working with the intairsuffix global variable that could add a new GET argument where both the “port” label in &port=[value] and that [value] can affect behaviour from the intair.php PHP helper tool above …
var intairsuffix='', zhra=null, zhrb=null, kklat=0, kklong=0, doair=false, vsll=[-999.0], answered=true;
function how(atr, isub) {
var curgd=isub.getAttribute('data-type');
if (('' + curgd) == '9992') { // airport
if (intairsuffix != '') {
intairsuffix='&port=air';
isub.title='Showing Nearby Airports and Ports';
document.getElementById('title').value='Nearby Timezone Places and Airports and Ports';
}
} else if (('' + curgd) == '128674') { // port
if (intairsuffix == '') {
if (doair) {
intairsuffix='&port=air';
isub.title='Showing Nearby Airports and Ports';
document.getElementById('title').value='Nearby Timezone Places and Airports and Ports';
} else {
intairsuffix='&port=y';
isub.title='Showing Nearby Ports';
document.getElementById('title').value='Nearby Timezone Places and Ports';
}
}
}
return true;
}
function feedhow() {
var isub=document.getElementById('portsub');
var curgd=isub.getAttribute('data-type');
if (('' + curgd) == '9992') { // airport
isub.innerHTML='🚢';
isub.setAttribute('data-type', '128674');
} else if (('' + curgd) == '128674') { // port
isub.innerHTML='✈';
isub.setAttribute('data-type', '9992');
}
}
Ajax asynchronous usage for second half of a synchronous previous usage …
var intairsuffix='', zhra=null, zhrb=null, kklat=0, kklong=0, doair=false, vsll=[-999.0], answered=true;
function stateChangedb() {
if (zhrb.readyState == 4) {
if (zhrb.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhrb.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
}
}
}
function stateChangeda() {
if (zhra.readyState == 4) {
if (zhra.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhra.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
if (intairsuffix.indexOf('&port=air') != -1) {
zhrb = new XMLHttpRequest();
zhrb.onreadystatechange=stateChangedb;
zhrb.open('get', '/HTMLCSS/intair.php?num=6&lat=' + kklat + '&long=' + kklong + '&port=y', true);
zhrb.send(null);
}
answered=true;
}
}
}
… keeps a fastish synchronous call (that we enforce via that answered global variable) but truely invokes an asynchronous arrangement extracting Nearby Ports data to plot, as applicable
Introducing the Map Chart recognition of nearby Airports with yesterday’s GeoJson World Countries Nearest Airports Tutorial‘s progress on our latest GeoJson World Countries PHP web application, it set us to seeing …
the combination of Google Directions‘s talents allowing you to reposition on the fly … and …
the onmousemove event, at least for our non-mobile users
… could mean that if we pre-plot airports on the world map, given that the user has clicked the ✈ ( ✈ ) “Show an Interest in Airports” emoji button, as a non-mobile user hovers over the world map, this pre-plotting might help trip planners with their travel options, should air travel be part of their interest, in the same way it is an option up at Google Directions in our changedcountries.phpweb application you can also try below. The overlay scenario now reads …
document.body (now with the new onmousemove=airportplot(event); event logic) lowest level …
overlayed by HTML canvas element plotted with world country linework … now including …
overlayed by HTML canvas element dedicated to nearest airport plotting …
<canvas id=myacanvas height='180' width='360' style='background-color:transparent;z-index:55;display:inline-block;position:absolute;top:0px;left:0px;'></canvas>
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… worked by new (sometimes Ajax) Javascript code …
function inarray(needle, haystack) { // thanks to https://stackoverflow.com/questions/784012/javascript-equivalent-of-phps-in-array
var length = haystack.length;
for (var i = 0; i < length; i++) {
if (haystack[i] == needle) return true;
}
return false;
}
function stateChangeda() {
if (zhra.readyState == 4) {
if (zhra.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhra.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
answered=true;
}
}
}
function naira(klat, klong) {
if (answered && doair) {
answered=false;
zhra = new XMLHttpRequest();
zhra.onreadystatechange=stateChangeda;
zhra.open('get', '/HTMLCSS/intair.php?num=6&lat=' + klat + '&long=' + klong, true);
zhra.send(null);
}
}
function airportplot(e) {
if (answered) {
var rectis=null; //document.body.getBoundingClientRect();
var blat=0, blong=0;
var topllong=-180.0;
var topllat=90.0;
onepixelequals=eval(0.0 + eval(1.0 * izoom));
e = e || window.event;
e.preventDefault();
if (e.touches) {
if (e.touches[0].pageX) {
naira(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY)); //if (drawac(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY))) e = e; }
} else {
rectis=document.body.getBoundingClientRect();
naira(eval(-rectis.left + e.touches[0].clientX), eval(-rectis.top + e.touches[0].clientY)); //if (drawac(eval(-rectis.left + e.touches[0].clientX), eval(-rectis.top + e.touches[0].clientY))) { e = e; }
}
} else if (e.pageX || e.pageY) {
blat=eval(eval(eval(topllat * onepixelequals - eval(-rectistop + e.pageY) * 1)) / onepixelequals);
blong=eval(eval(eval(topllong * onepixelequals + eval(-rectisleft + e.pageX) * 1)) / onepixelequals);
if ((blat >= -90.0 && blat <= 90.0) && (blong >= -180.0 && blong <= 180.0)) {
naira(blat, blong); //if (drawac(eval(-rectisleft + e.pageX), eval(-rectistop + e.pageY))) { e = e; }
}
} else {
rectis=document.body.getBoundingClientRect();
naira(eval(-rectis.left + e.clientX), eval(-rectis.top + e.clientY)); //if (drawac(eval(-rectis.left + e.clientX), eval(-rectis.top + e.clientY))) { e = e; }
}
}
}
// ... and extended document.body onload event logic has added, up near its top ...
elema = document.getElementById('myacanvas');
contexta = elema.getContext('2d');
add interfacing functionality to the excellent Google Directions part of Google Maps, perhaps to help with Trip planning, or even just to associate a Placename with a latitude and longitude as clicked by the user, via the very simple URL arrangement … https://www.google.com/maps/dir/[decimalLatitudeDegrees]/[decimalLongitudeDegrees]
… helped out by new Javascript functions …
var lastlats=[], lastlongs=[], lastlat=-99.0, lastlong=-99.0, thislat=0.0, thislong=0.0;
function preface(inblurb) {
var extras='';
var outblurb=inblurb;
if (Math.abs(eval('' + lastlat)) > 0.0 || Math.abs(eval('' + lastlong)) > 0.0) {
if (Math.abs(eval('' + lastlat)) <= 90.0 && Math.abs(eval('' + lastlong)) <= 180.0) {
extras=' Add G for Google Directions between (' + lastlat + ',' + lastlong + ') to (' + thislat + ',' + thislong + ') and spaces (also more trip legs) to hashtag navigate to Google Charts later. ';
}
}
return extras + outblurb;
}
function alats(inlat) {
if (inlat == 0 && lastlats.length == 0) { inlat=inlat; } else { lastlats.push(inlat); }
return inlat;
}
Onto yesterday’s GeoJson World Countries TimeZone Times Tutorial GeoJson World Countries web application’s capabilities we want to add zooming, that doesn’t rely on web browser functionality (which continues to work). With that in mind we create a new emoji ( 🔎 ) 🔎 link, with this onclick event code …
var jzoom=1.0, izoom=location.search.split('zoom=')[1] ? eval(decodeURIComponent(location.search.split('zoom=')[1].split('&')[0])) : 1.0;
… to multiply the webpage zoom factor in a programmatical way. To acheive this, we have a two way approach (as you might have surmised from above) …
for mobile, the logic is easier by introducing a new meta name=viewport …
<meta id="myviewport" name="viewport" content="width=device-width, initial-scale=1, minimum-scale=0.1, maximum-scale=8, user-scalable=yes" >
… tag … while …
for non-mobile we needed to realize that event.pageX and event.pageY co-ordinates grow in proportion to the zoom factor, and that better latitude and longitude determining lines of code would go …
function canvasclick(e) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
onepixelequals=eval(0.0 + eval(1.0 * izoom));
//document.title='canvasclick';
e = e || window.event;
e.preventDefault();
if (e.touches) {
if (e.touches[0].pageX) {
//lastl='Longitude,Latitude coordinates are ' + eval(topllong + eval(-rectis.left + e.touches[0].pageX) * onepixelequals) + ',' + eval(topllat - eval(-rectis.top + e.touches[0].pageY) * onepixelequals);
if (drawc(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY))) {
thislat=eval(topllat - eval(-rectistop + e.touches[0].pageY) * onepixelequals);
thislong=eval(topllong + eval(-rectisleft + e.touches[0].pageX) * onepixelequals);
//console.log('rectistop=' + rectistop + ' and rectisleft=' + rectisleft + ' and rectisy=' + rectisy + ' and thislat=' + thislat);
document.getElementById('nearestif').src='/PHP/tz_places.php?place=&latitude=' + encodeURIComponent('' + eval(topllat - eval(-rectistop + e.touches[0].pageY) * onepixelequals)) + '&longitude=' + encodeURIComponent('' + eval(topllong + eval(-rectisleft + e.touches[0].pageX) * onepixelequals)) + '&ntztontz=y';
}
} else {
Some readers might be aware of our “theory regarding adverbs” and “web applications” on the net …
the most catered for adverb relates to the “where of life” … and the second banana is …
the “when of life”
… and, further to yesterday’s GeoJson World Countries SVG Overlay Safari Error Tutorial‘s emphasis on the “where of life”, today we add in a bit of the “when of life”, something right down the line of the remit of TimeZone talents.
Seriously though, a lot of us dream of the rest of the world on a world map, and wonder what time it is in other parts of the world. Phone call to relatives? A reminder SMS call? Email a game collaboration? It could all be part of life’s rich tapestry!
The expresion of this, for us, today, improving the communications with our current GeoJsom World Countries web application, take the form of emoji clocks from the 12 hour clock example forms such as …
1 o’clock is 🕐 🕐
2 o’clock is 🕑 🕑
12 o’clock is 🕛 🕛
2:30 is 🕝 🕝
11:30 is 🕦 🕦
12:30 is 🕧 🕧
… to show in “prompt” and “confirm” popup windows, as well as Map Chart maps … via new Javascript functions …
Also, in these same places we add in Time Place country ISO-2 character code based emoji flags, adding to information and colour pizazz in the informational parts to the workings of our changedcountries.phpweb application you can also try below.
On discovering our first solution theory of turning yesterday’s mapsvg.js external Javascript work into an async piece of work made no difference to this situation, we surmised that the huge amount of content held in the Javascript (ie. client side) global variable appendtoinnerHTML was causing memory issues. We couldn’t shift much to do with the overall amount of “data” needing to be handled, in order to implement country SVG colour infilling, but we could shift the data from being …
client side (external) Javascript held … to, instead, (have that data) be (determined on the) …
server side PHP filling in the contents of our (relevant) HTML div id=svgd ahead of the document.body onload event timing …
<?php
$icnt=0;
function apptohtmstuff($coordsare, $origc) {
global $icnt;
$minl=-1;
$mint=-1;
$maxl=-1;
$maxt=-1;
$zysare=explode(',', $coordsare);
$svgcis='';
for ($ij=0; $ij<sizeof($zysare); $ij+=2) {
if ($minl < 0) {
$minl=$zysare[$ij];
$maxl=$zysare[$ij];
$mint=$zysare[1 + $ij];
$maxt=$zysare[1 + $ij];
} else {
if ($zysare[$ij] < $minl) { $minl=$zysare[$ij]; }
if ($zysare[$ij] > $maxl) { $maxl=$zysare[$ij]; }
if ($zysare[1 + $ij] < $mint) { $mint=$zysare[1 + $ij]; }
if ($zysare[1 + $ij] > $maxt) { $maxt=$zysare[1 + $ij]; }
}
}
…everywhere … and an idea we’d ditched yesterday of …
idea to pre-colour “land” parts of the world GeoJson map green (ahead of the document.body onload event) also came good (after causing problems yesterday)
… meaning now, “overlay” wise, we could say …
document.body lowest level …
overlayed by HTML canvas element plotted with world country linework …
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… and we (reckon we’ve) improved the colour coding user experience at the same time.
We noticed that tweaks in the changed …
var lastflagged='', appendtoinnerHTML='', waitplease=false; // used to make sure "area" element onclick code precedes any document.body onmousedown or ontouchdown code
… also lessened the burden on the client side by only asking any Javascript DOM command operations act on single HTML element at a time, not a whole swathe of hosted ones, in any operation.
What deducible data item needs to be determined for these Geo Charts to work? We need a way to deduce ISO-2 character country codes from the ISO-3 character codes existing in the GeoJson “countries.geojson” data from yesterday’s work. We happened upon the extremely generous mapping data webpage to help with these ISO-2 character deductions …
… in our image map area elements PHP creation code above. As you can see, extra “intelligence”, moving forward, is contained in area element global data attributes.
Geo Chart can involve emoji (🏠 &127968;) or image (SVG) circle based symbology for the “User Clicked Place” and nearby TimeZone places respectively …
all these symbols can be clicked to open popup windows containing TimeZone Place Wikipedia webpages of relevance …
an emoji national flag (eg. Zambia “ZA” could be used to derive 🇿🇦 🇿🇦 flag emoji) derived from those ISO-2 character codes can supplement the GeoJson (more ISO-3 character based) names presented in the underlying data, in the Geo Chart title …
contextualizing the accompanying Map Chart … and …
vice versa regarding hovering over symbology (which works on Map Chart, but not Geo Chart) …
within the Map Chart iframe a “Geo” link can glean a “zoomed out” world Geo Chart view of your TimeZone places
Know your GeoJson! Yes, pretty obviously, any two GeoJson datasets might display the same in that “map plotting” sense, but one might have different and/or more “intelligence” than the other. Often, an XML has more “intelligence” than equivalent HTML (barring the use of global data attributes, that is), as today’s Corollacorollary.
Luckily for programmers all over, the organization of TimeZones has had an International flavour in its development and maintenance. As such, given the “purely coastline” GeoJson data involved in our fledgling PHP web application of yesterday’s GeoJson World Coastline Primer Tutorial a useful arrangement for improvement involves …
document.body onclick event co-ordinates … able to be converted to …
longitude, latitude (easily, only because of our simplistic map projection, of course) … onfed to …
… can have us helping out your curious web “clicking” user with the 3 nearest TimeZone places, as a reference as to where they are “clicking” in the world.
in a discrete click methodology of interest, you could adopt a non-mobile “onmousedown” logic set that does not get interfered with by a mobile “ontouchdown” logic set (perhaps leaving “onclick” event, which both non-mobile and mobile both recognise, for another event logic role) … and …
neither will interrupt the mobile gestures associated with swiping and pinching, which refer to the events “ontouchstart” and “ontouchend” at either end of their lifespan
And so, we arrive at a long planned for tilt at Image Map functionality that we often turn to Mobilefish.Com and its excellent Image Map Creation to help us out … but not today?! Why not? We have a funny set of needs, they being …
our Image Map’s image will have a variable set of width x height dimensions …
our Image Map’s image will be transparent
our Image Map needs to have a hole left aside inside it where the functionality that originally existed (and pointed to WordPress Blog content like you are reading), is still working
background-image:url(‘data:image/svg+xml;utf8, blahde blah ‘); nor background-image:url(‘data:image/svg+xml;base64, blahde blah ‘); ideas were not working for us … but today, we started to try …
overlay HTML div position:absolute; opacity:0.5; z-index:-4; …
We can’t remember a “foreground overlay” scenario so resembling a “background image feeling” end result, the transparent colour introduced into the Google ChartsGeo ChartSVG being crucial to help make this all work.
We want to be able to control the way a Google Charts Geo Chart can be nested within an HTML div element, for instance. We started the day wanting to be able to make …
a Google Charts Geo Chart be a background image to a div element … alas, on this first draft we couldn’t get there (but will continue with the research here) … whereas we succeeded …
adding the Google Charts Geo Chart interfacer’s resultant SVG data as the innerHTML (ie. content) …
<?php echo ”
function newbackin() {
if (dmyxhr.readyState == 4) {
if (dmyxhr.status == 200) {
if (dmyxhr.responseText) {
var m_t='image/jpeg';
var h_t='179';
var w_t='320';
var dbits = dmyxhr.responseText.split('\"height\": ');
if (dbits.length > 1) {
h_t=dbits[1].split(',')[0].split(String.fromCharCode(10))[0].split('}')[0].trim();
}
dbits = dmyxhr.responseText.split('\"mime_type\": \"');
if (dbits.length > 1) {
m_t=dbits[1].split('\"')[0];
}
dbits = dmyxhr.responseText.split('\"width\": ');
if (dbits.length > 1) {
w_t=dbits[1].split(',')[0].split(String.fromCharCode(10))[0].split('}')[0].trim();
}
dbits = dmyxhr.responseText.split('\"data\":');
dbits = dmyxhr.responseText.split('\"data\":');
if (dbits.length > 1) {
// replace all '_' with '/' and all '-' with '+' thanks to https://stackoverflow.com/questions/757675/website-screenshots
dgsbi='<img alt=\"Blog Posting Image\" style=\"width:' + w_t + 'px;height:' + h_t + 'px;\" width=' + w_t + ' height=' + h_t + ' src=\"data:' + m_t + ';base64,' + dbits[1].split('\"')[1].split('\"')[0].replace(/\_/g,'/').replace(/\-/g,'+') + '\"></img>';
//alert('dgsbi=' + dgsbi);
}
}
}
}
}
function ajaxit(urlin) {
if (urlin.length > 0) {
aurl=urlin;
if (window.XMLHttpRequest) {
dmyxhr = new window.XMLHttpRequest;
}
else {
try {
dmyxhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (othermicrosoft) {
try {
dmyxhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (failed) {
dmyxhr = false;
}
}
}
var xurl = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=' + encodeURIComponent(urlin) + '&screenshot=true';
if (dmyxhr) {
dmyxhr.onreadystatechange = newbackin;
dmyxhr.open('GET', xurl, true);
dmyxhr.send(null);
}
}
}
function wbtoa(instris) {
var outstris=instris;
while (outstris.indexOf(String.fromCharCode(10)) != -1) {
outstris=outstris.replace(String.fromCharCode(10),'');
}
var xzs=prompt(outstris, outstris);
return outstris.replace(/\\\"/g, \"'\");
}
In that Nearest Places form part of the TimeZone places webpage, we noticed that even when shaping to enter a TimeZone Placename in the first textbox we made no attempt to fill in …
latitude
longitude
… when we have the information to do so, and even if we’re misunderstanding a placename designation, that should not stop us from trying, because those two numerical fields above can be corrected, and the form resubmitted, in these scenarios.
Apart from making a PHP derived Javascript variable be made available to the code, we “wrap” …
GeoJson World Countries Drag and Drop Makeover Nuance Tutorial
Nuance alert! We’re not sure if you noticed, but if you tried out the Drag and Drop functionality in the World Countries web application of yesterday’s GeoJson World Countries Drag and Drop Makeover Tutorial you may have noticed …
for a country with lots of TimeZone places, like Brazil, you could get a decent Google Chart Geo Chart map up … but if you were to click the “Map?” link down the bottom of that iframe …
it would fail to show a Google Chart Map Chart for that country’s TimeZone places
This fix, believe it or not, is interesting, perhaps only in an “internal use only” sense, we grant you. But our solution got us delving even more into hashtagging data, so that the solution we came up with was a hybrid whereby …
stayed with PHP $_GET[] (ie. address bar ? and & argumented) data (versus using PHP $_POST[] methodologies) … but …
where it came to the &data=[most of the data] part, other than its first character, we hashtagged the rest
… so that the logic flows as per usual, but we intervene at places and flesh it out via location.hash (client side only) means. We won’t bore you too much with all the places of intervention except the receiving map.php’s “easiest to get” intervention …
In addition to the Wikipedia information, at the very least, presented following a successful drag and drop operation, from today, we also start presenting a new HTML iframe element containing …
Nearest TimeZone places along with Google Charts for each unique country involved
we wanted the first popup window content be aligned to the top and left … and then …
we thought it would be good to also, in “Drag and Drop land”, relevant countries nearby to the user’s drop point TimeZone Places be showing below that (and it panned out the best way to show this, for us, was via an iframe pointing at another incarnation of the tz_places.php webpage, because it could have GET arguments iso, iso2, iso3 etcetera to point at ISO 2 letter country codes, which we made more readily available (via a new data-ccglobal data attribute applied to the select option subelements presented) for the changed external Javascript countries.js we decided should get into the mix via a new Javascript function …
function tzagain(inhtml) {
var outhtml=inhtml, dccs=[], getarg='?', theone=1;
if (inhtml.indexOf('left:0px;') != -1 && inhtml.indexOf(' data-cc=') != -1) {
dccs=inhtml.split(' data-cc=');
for (var ii=1; ii<dccs.length; ii++) {
if (getarg == '?') {
getarg+='iso=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2);
theone++;
} else if (getarg.indexOf('=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2)) == -1) {
getarg+='&iso' + theone + '=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2);
theone++;
}
}
if (getarg != '?') {
if (inhtml.indexOf('</bo' + 'ody>') != -1) {
outhtml=inhtml.split('</bo' + 'dy>')[0] + '<iframe src="./tz_places.php' + getarg + '" style="position:absolute;left:0px;top:120px;width:100%;height:900px;"></iframe></body></html>';
} else {
outhtml=inhtml + '<iframe src="./tz_places.php' + getarg + '" style="position:absolute;left:0px;top:120px;width:100%;height:900px;"></iframe>';
}
}
}
return outhtml;
}
… that superfluous looking ?rand=blah measure being pretty useful really regarding getting around the cache keeping old external Javascript in its mind after changes.
Curiously, the grandparent regions.php starting off all this needed no changing! We hope you like these tweaks!
add similar drag and drop logic into our World Coastlines GeoJson web application … and along the way, also for the World Countries web application …
hold off involving the (pretty kludgy looking) vertical scrollbar of our drag and drop pin’s underlying HTML iframe …
<iframe scrolling=no frameborder=0 name=iftr id=iftr style=display:none; srcdoc="<body style=background-color:transparent;><p id=mg title='Wikipedia country page below via drag and drop to world map' draggable='true'>📍</p><br><br><div id=myh1></div><script type='text/javascript' src='./countries.js?rand=321156747657' defer></script></body>" data-src=></iframe>
… until the first drag operation starting, calls on …
parent.document.getElementById('iftr').scrolling='yes';
… proving a Javascript DOM control of the “scrolling” attribute works (as we weren’t sure, having never done this before)
It’s worth beavering away at a guinea pig web application until (just about complete) satisfaction (for now) before having a parallel set of code changes happening simultaneously, we’ve always found.
So, what happened in “external Javascript land”? No need for a “regions.js” here, as parent.document.URL can be scrutinised in that “external Javascript land” to discover which web application is the parent, and act accordingly. So changed were our changed external Javascript countries.js in …
our GeoJson World Countries web application Drag and Drop logic worked on an iPhone … but …
our GeoJson World Countries web application Drag and Drop logic did not work on an iPad
They’re both iOS! And usually the smaller iPhone has the problem and the larger iPad is okay when there is an odd scenario happening. So, what gives? Well, the odd thing is, it was just rearrangements of code and iframe srcdoc usage …
<iframe frameborder=0 name=iftr id=iftr style=display:none; srcdoc="<body style=background-color:transparent;><p id=mg title='Wikipedia country page below via drag and drop to world map' draggable='true'>📍</p><br><br><div id=myh1></div><script type='text/javascript' src='./countries.js?rand=321156747657' defer></script></body>" data-src=></iframe>
… that ended up helping us fix the issues. Figure this, on iPad our emoji pin could not be made visible down the bottom left of iPad screen but could be made to work in the title elements section?! Of course, we might have been having a bad day, but in our defence, even debugging in Safari via …
iPad Safari web browser invocation …
Apple white lead from iPad to MacBook Air …
MacBook Air Safari web browser Develop menu dropdown got us to debugging functionality
“long hover” (ie. on non-mobile, wait for a long while after the onmouseover event initiation to see whether the user is still hovering) … and today, a bit like that, is the new, for us …
“long drag” (the user waits a long time between the drag initialization and the drop event)
… and because we found “dawdling” on a drag and drop fairly unnatural, we think this “long drag” idea “has legs”, in that it works well as a deliberate act made by a user, knowing at the end they benefit from their actions. For us, with our GeoJSON Map web application, yesterday, with GeoJson World Drag and Drop Pin Tutorial, the drag and drop led to …
Wikipedia country information webpage … and today, we allow a “long drag” get you to …
Google Maps drop position information webpage … if the “long drag” is for 10 or more seconds …
Google Earth drop position information webpage … if the “very long drag” is for 20 or more seconds
onclick event logic … and today, we start to also include …
drag and drop event logic (like, but nuanced as explained below, the experimental drag and drop ideas included in the recent Planet Moon Game Tutorial) … the nuanced differences involving …
the drag part of the events occurs in an iframe (populated via small amount of srcdoc HTML and Javascript) able to reference its originator via window.parent …
drop part of the events occurs in that originator parent and so several Javascript function called by the child reside in the parent … and …
the child “drag” event controller uses the new external Javascript countries.js …
// countries.js
// July, 2023
// RJM Programming
// Help out countries.html and countries.php
var pos3=0, pos4=0, tdid='', poligono, punto, coone='', prectis;
// var poligono = [[2,9],[8,6],[12,10],[15,2],[10,4],[5,1]];
// var punto = [6, 5];
function pointInPolygon(polygon, point) { // thanks to https://community.appinventor.mit.edu/t/geofence-check-if-a-point-is-inside-a-polygon-javascript-map/57091
var odd = false;
for (var i = 0, j = polygon.length - 1; i < polygon.length; i++) {
if (((polygon[i][1] > point[1]) !== (polygon[j][1] > point[1]))
&& (point[0] < ((polygon[j][0] - polygon[i][0]) * (point[1] - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0]))) {
odd = !odd;
}
j = i;
}
return odd;
}
function andlaterstill() {
if (9 == 6) { // temporary
if (tdid != '') {
document.getElementById(tdid).innerHTML=document.getElementById(tdid).innerHTML.substring(0,1);
} else if (document.getElementById('mytable').innerHTML.indexOf(clonedatatwo) != '') {
document.getElementById('myh1').innerHTML=document.getElementById('myh1').innerHTML.split('</table>')[0] + '</table>';
}
if (document.getElementsByTagName('div')[0].innerHTML.indexOf(clonedatatwo) != -1) {
document.getElementsByTagName('div')[0].innerHTML=document.getElementsByTagName('div')[0].innerHTML.replace(clonedatatwo,'');
} else if (document.getElementsByTagName('div')[0].innerHTML.indexOf(clonedatatwo.replace('dragging','')) != -1) {
document.getElementsByTagName('div')[0].innerHTML=document.getElementsByTagName('div')[0].innerHTML.replace(clonedatatwo.replace('dragging',''),'');
} else if (document.body.innerHTML.split('<table')[0].indexOf(clonedatatwo.replace('dragging','')) != -1) {
document.body.innerHTML=document.body.innerHTML.replace(document.body.innerHTML.split('<table')[0], document.body.innerHTML.split('<table')[0].replace(clonedatatwo.replace('dragging',''),''));
} else if (document.body.innerHTML.split('<table')[0].indexOf(clonedatatwo) != -1) {
document.body.innerHTML=document.body.innerHTML.replace(document.body.innerHTML.split('<table')[0], document.body.innerHTML.split('<table')[0].replace(clonedatatwo,''));
}
}
tdid='';
}
function getprectis() {
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
return window.opener.document.body.getBoundingClientRect();
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
return parent.document.body.getBoundingClientRect();
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
return parent.document.body.getBoundingClientRect();
}
}
return null;
}
function wod(ididea) {
if (window.opener) {
if (window.opener.document.getElementsByTagName(ididea)[0]) {
return window.opener.document.getElementsByTagName(ididea)[0];
} else if (window.parent) {
if (parent.document.getElementsByTagName(ididea)[0]) {
return parent.document.getElementsByTagName(ididea)[0];
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName(ididea)[0]) {
return parent.document.getElementsByTagName(ididea)[0];
}
}
return null;
}
function ccit() {
var divs, esot=[], bodyois=null;
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
bodyois=window.opener.document.getElementsByTagName('body')[0];
divs=window.opener.document.getElementsByTagName('div');
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
bodyois=parent.document.getElementsByTagName('body')[0];
divs=parent.document.getElementsByTagName('div');
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
bodyois=parent.document.getElementsByTagName('body')[0];
divs=parent.document.getElementsByTagName('div');
}
}
function andqlater() {
//alert('HeRe');
tdid='';
var ppig='[]', coo='', coos=[], ip=0;
var squares; //=window.opener.document.getElementsByTagName('area');
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
squares=window.opener.document.getElementsByTagName('area');
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
squares=parent.document.getElementsByTagName('area');
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
squares=parent.document.getElementsByTagName('area');
}
}
window.addEventListener("DOMContentLoaded", () => {
const source = document.querySelector("#mg");
console.log('source.id=' + source.id);
source.addEventListener("dragstart", (ev) => {
console.log("dragStart");
// Change the source element's background color
// to show that drag has started
ev.currentTarget.classList.add("dragging");
// Clear the drag data cache (for all formats/types)
ev.dataTransfer.clearData();
// Set the drag's format and data.
// Use the event target's id for the data
ev.dataTransfer.setData("text/plain", ev.target.id);
//ev.dataTransfer.setData("text/html", ev.target.outerHTML);
});
source.addEventListener("dragend", (ev) =>
ev.target.classList.remove("dragging")
);
const target = wod('body'); //window.opener.document.getElementsByTagName('body')[0];
target.id='usemap';
console.log('target.id=' + target.id);
target.addEventListener("dragover", (ev) => {
console.log("dragOver");
ev.preventDefault();
});
target.addEventListener("drop", (ev) => {
console.log("Drop");
ev.preventDefault();
// Get the data, which is the id of the source element
const data = ev.dataTransfer.getData("text");
const source = document.getElementById(data);
… where heap memory concerns related to the global variables memory used in our GeoJson World Coastlines webpage could cause mobile platform usage reloads of the web application, reminiscent of the external Javascript concerns we had back at GeoJson World Countries SVG Overlay Safari Error Tutorial.
There, as for here, mobile usage got better by swapping global variable usage for HTML content static PHP …
GeoJson World Coastline Function Noun Naming Tutorial
We’re working on an extension to yesterday’s GeoJson World Coastline Rivers Quiz Tutorial‘s Rivers Quiz functionality within our GeoJson World Coastlines web application, and have …
settled on an approach … but …
not yet finished on deployment issues
… but it is this approach we wanted to talk about today.
Our approach borrows from Object Oriented Programming (OOP) the idea that …
just as with OOP thinking class names are like nouns and the methods within that class are like verbs … we, with our approach …
help readability of our non-OOP functional code by including those nouns and verbs, as well as ideas like use of plurals to indicate array involvement, with our Javascript function naming
… we can best illustrate to you via showing you new functions and variables and modified code to show you this approach in code …
var rivers='', arivers=[], iguess=-1, isofar=' ', jscore=0, jgoes=0, elema=null, contexta=null, rectisleft=0, rectistop=0, isokto=true;
var populations='', apopulations=[], jguess=-1, jsofar=' ', both=false, jlastn='';
var idone=false;
function askapopulation() {
var another=false;
var origboth=both;
var midbit='';
var thing='population';
if (!both) { midbit='Append spaces to also answer a question regarding the Rivers Quiz, or R to just do Rivers Quiz.'; } else { thing='river'; }
var retthis=prompt('What is the name of this new red population area plotted on the world map? ' + midbit + ' Enter ? to get given more time looking at (longitude,latitude) = (' + apopulations[jguess].split(':')[1].split(',')[0] + ',' + apopulations[jguess].split(':')[1].split(',')[1] + ')', '');
if (retthis == null) {
both=false;
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (retthis.toLowerCase().trim() == 'r') {
both=false;
isokto=true;
getariver();
return '';
} else if (retthis.trim() == '?') {
if (retthis.trim() != retthis && !origboth) { both=true; }
setTimeout(askapopulation, 9000);
return '';
} else if (retthis.trim() == '') {
if (retthis != '' && !origboth) { thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
if (retthis != '' && !origboth) { isokto=true; both=true; getariver(); }
} else if (jlastn.toLowerCase().indexOf(retthis.toLowerCase()) != -1 && jlastn.toLowerCase() == retthis.toLowerCase() && retthis.trim().length >= 1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (jlastn.toLowerCase().indexOf(retthis.toLowerCase()) == -1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (jlastn.toLowerCase() == retthis.toLowerCase()) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Well done! Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (retthis.trim().length >= 1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
}
if (both) { contexta.clearRect(0,0,360,180); }
if (both && !origboth) { isitok=true; getariver(); return ''; }
if (another) { if (both) { getariver(); getapopulation(); } else { getapopulation(); } } else { contexta.clearRect(0,0,360,180); }
return '';
}
function plotapopulation(which) {
if (isokto) { contexta.clearRect(0,0,360,180); }
//if (both) { isokto=true; }
jlastn=apopulations[which].split(':')[0];
var rest=apopulations[which].split(':')[1];
var restlonglat=[]; //rest.split(',');
restlonglat=rest.split(',');
if (eval('' + restlonglat.length) >= 2) {
contexta.fillStyle = 'red';
contexta.fillRect(eval(180.0 + eval('' + restlonglat[0])), eval(90.0 - eval('' + restlonglat[1])),1,1);
contexta.fill();
}
}
It’s time to turn our attention away from GeoJson World Countries, as talked about with yesterday’s GeoJson World Countries Plotted Ports Tutorial, and back to GeoJson World Coastline ideas. Why? We want to add a …
Rivers Quiz
… via the (generously provided) HTTP://geojson.xyz rivers lake centerlines GeoJSON data we download and then uploaded to become rivers.geojson data file. Now we were wondering out of …
use the URL to this GeoJSON file as the “src” attribute of an HTML iframe …
<iframe id=ifrivers onload=getthejson(this); style=display:none; src=./rivers.geojson></iframe>
… element (and then access the content via the onload event …
var rivers='', arivers=[], iguess=-1, isofar=' ', jscore=0, jgoes=0, elema=null, contexta=null, rectisleft=0, rectistop=0;
function getthejson(iois) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
rivers='' + aconto.body.innerHTML;
setTimeout(populaterivers, 500);
}
}
}
… function) would suffice, or if we would end up using …
Ajax call
… to access this data, and were a bit surprised the former method was all fine. Of course there are snazzy inbuilt Javascript hierarchical calls you can make to process the data, but we find, with GeoJSON data, in the client realm (where we’re keen to stay with today’s work (though PHP serverside can, of course, be purloined to do all this work, should you have that available)), of Javascript, we just need very basic string functions …
The progress with GeoJson World Countries helped too. We knew to add another HTML canvas layer as per …
document.body (now with the new onmousemove=airportplot(event); event logic) lowest level …
overlayed by HTML canvas element plotted with world country linework … now including …
overlayed by HTML canvas element dedicated to nearest airport plotting …
<canvas id=myacanvas height='180' width='360' style='background-color:transparent;z-index:55;display:inline-block;position:absolute;top:0px;left:0px;'></canvas>
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… and to, at document.body onload logic …
// ... and extended document.body onload event logic has added, up near its top ...
elema = document.getElementById('myacanvas');
contexta = elema.getContext('2d');
… and supplement with another HTML sub “emoji button” ❓ ( ❓ ) type element …
function askariver() {
var another=false;
var retthis=prompt('What is the name of this new blue river plotted on the world map? Enter ? to get given more time looking at (longitude,latitude) = (' + arivers[iguess].split(':')[1].split(',')[0] + ',' + arivers[iguess].split(':')[1].split(',')[1] + ')', '');
if (retthis == null) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (retthis.trim() == '?') {
setTimeout(askariver, 8000);
return '';
} else if (retthis.trim() == '') {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (lastn.toLowerCase().indexOf(retthis.toLowerCase()) == -1) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (lastn.toLowerCase() == retthis.toLowerCase()) {
jgoes++;
jscore++;
another=confirm('Well done! Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (retthis.trim().length >= 1) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else {
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
}
if (another) { getariver(); } else { contexta.clearRect(0,0,360,180); }
return '';
}
… to work the Rivers Quiz. Finally, though, for all good practicalities we also need those zoom logics out of GeoJson World Countries logic, via “emoji button” 🔎 ( 🔎 ) …
where to modularise … we think “data collection” commonality is a good reason, and so we make these changes to intair.php
making an (“animated emoji”) button dual purpose on top of originally being a single purpose button …
<sub title='Show Nearby Airports' onclick='doair=how(true,this); twothousand*=2; this.title=this.title.substring(0,4) + String.fromCharCode(105) + String.fromCharCode(110) + String.fromCharCode(103) + this.title.replace(this.title.split(String.fromCharCode(32))[0] + String.fromCharCode(32), String.fromCharCode(32));' data-type=9992 style=cursor:pointer; id=portsub>✈</sub>
… working with the intairsuffix global variable that could add a new GET argument where both the “port” label in &port=[value] and that [value] can affect behaviour from the intair.php PHP helper tool above …
var intairsuffix='', zhra=null, zhrb=null, kklat=0, kklong=0, doair=false, vsll=[-999.0], answered=true;
function how(atr, isub) {
var curgd=isub.getAttribute('data-type');
if (('' + curgd) == '9992') { // airport
if (intairsuffix != '') {
intairsuffix='&port=air';
isub.title='Showing Nearby Airports and Ports';
document.getElementById('title').value='Nearby Timezone Places and Airports and Ports';
}
} else if (('' + curgd) == '128674') { // port
if (intairsuffix == '') {
if (doair) {
intairsuffix='&port=air';
isub.title='Showing Nearby Airports and Ports';
document.getElementById('title').value='Nearby Timezone Places and Airports and Ports';
} else {
intairsuffix='&port=y';
isub.title='Showing Nearby Ports';
document.getElementById('title').value='Nearby Timezone Places and Ports';
}
}
}
return true;
}
function feedhow() {
var isub=document.getElementById('portsub');
var curgd=isub.getAttribute('data-type');
if (('' + curgd) == '9992') { // airport
isub.innerHTML='🚢';
isub.setAttribute('data-type', '128674');
} else if (('' + curgd) == '128674') { // port
isub.innerHTML='✈';
isub.setAttribute('data-type', '9992');
}
}
Ajax asynchronous usage for second half of a synchronous previous usage …
var intairsuffix='', zhra=null, zhrb=null, kklat=0, kklong=0, doair=false, vsll=[-999.0], answered=true;
function stateChangedb() {
if (zhrb.readyState == 4) {
if (zhrb.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhrb.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
}
}
}
function stateChangeda() {
if (zhra.readyState == 4) {
if (zhra.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhra.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
if (intairsuffix.indexOf('&port=air') != -1) {
zhrb = new XMLHttpRequest();
zhrb.onreadystatechange=stateChangedb;
zhrb.open('get', '/HTMLCSS/intair.php?num=6&lat=' + kklat + '&long=' + kklong + '&port=y', true);
zhrb.send(null);
}
answered=true;
}
}
}
… keeps a fastish synchronous call (that we enforce via that answered global variable) but truely invokes an asynchronous arrangement extracting Nearby Ports data to plot, as applicable
Introducing the Map Chart recognition of nearby Airports with yesterday’s GeoJson World Countries Nearest Airports Tutorial‘s progress on our latest GeoJson World Countries PHP web application, it set us to seeing …
the combination of Google Directions‘s talents allowing you to reposition on the fly … and …
the onmousemove event, at least for our non-mobile users
… could mean that if we pre-plot airports on the world map, given that the user has clicked the ✈ ( ✈ ) “Show an Interest in Airports” emoji button, as a non-mobile user hovers over the world map, this pre-plotting might help trip planners with their travel options, should air travel be part of their interest, in the same way it is an option up at Google Directions in our changedcountries.phpweb application you can also try below. The overlay scenario now reads …
document.body (now with the new onmousemove=airportplot(event); event logic) lowest level …
overlayed by HTML canvas element plotted with world country linework … now including …
overlayed by HTML canvas element dedicated to nearest airport plotting …
<canvas id=myacanvas height='180' width='360' style='background-color:transparent;z-index:55;display:inline-block;position:absolute;top:0px;left:0px;'></canvas>
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… worked by new (sometimes Ajax) Javascript code …
function inarray(needle, haystack) { // thanks to https://stackoverflow.com/questions/784012/javascript-equivalent-of-phps-in-array
var length = haystack.length;
for (var i = 0; i < length; i++) {
if (haystack[i] == needle) return true;
}
return false;
}
function stateChangeda() {
if (zhra.readyState == 4) {
if (zhra.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhra.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
answered=true;
}
}
}
function naira(klat, klong) {
if (answered && doair) {
answered=false;
zhra = new XMLHttpRequest();
zhra.onreadystatechange=stateChangeda;
zhra.open('get', '/HTMLCSS/intair.php?num=6&lat=' + klat + '&long=' + klong, true);
zhra.send(null);
}
}
function airportplot(e) {
if (answered) {
var rectis=null; //document.body.getBoundingClientRect();
var blat=0, blong=0;
var topllong=-180.0;
var topllat=90.0;
onepixelequals=eval(0.0 + eval(1.0 * izoom));
e = e || window.event;
e.preventDefault();
if (e.touches) {
if (e.touches[0].pageX) {
naira(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY)); //if (drawac(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY))) e = e; }
} else {
rectis=document.body.getBoundingClientRect();
naira(eval(-rectis.left + e.touches[0].clientX), eval(-rectis.top + e.touches[0].clientY)); //if (drawac(eval(-rectis.left + e.touches[0].clientX), eval(-rectis.top + e.touches[0].clientY))) { e = e; }
}
} else if (e.pageX || e.pageY) {
blat=eval(eval(eval(topllat * onepixelequals - eval(-rectistop + e.pageY) * 1)) / onepixelequals);
blong=eval(eval(eval(topllong * onepixelequals + eval(-rectisleft + e.pageX) * 1)) / onepixelequals);
if ((blat >= -90.0 && blat <= 90.0) && (blong >= -180.0 && blong <= 180.0)) {
naira(blat, blong); //if (drawac(eval(-rectisleft + e.pageX), eval(-rectistop + e.pageY))) { e = e; }
}
} else {
rectis=document.body.getBoundingClientRect();
naira(eval(-rectis.left + e.clientX), eval(-rectis.top + e.clientY)); //if (drawac(eval(-rectis.left + e.clientX), eval(-rectis.top + e.clientY))) { e = e; }
}
}
}
// ... and extended document.body onload event logic has added, up near its top ...
elema = document.getElementById('myacanvas');
contexta = elema.getContext('2d');
add interfacing functionality to the excellent Google Directions part of Google Maps, perhaps to help with Trip planning, or even just to associate a Placename with a latitude and longitude as clicked by the user, via the very simple URL arrangement … https://www.google.com/maps/dir/[decimalLatitudeDegrees]/[decimalLongitudeDegrees]
… helped out by new Javascript functions …
var lastlats=[], lastlongs=[], lastlat=-99.0, lastlong=-99.0, thislat=0.0, thislong=0.0;
function preface(inblurb) {
var extras='';
var outblurb=inblurb;
if (Math.abs(eval('' + lastlat)) > 0.0 || Math.abs(eval('' + lastlong)) > 0.0) {
if (Math.abs(eval('' + lastlat)) <= 90.0 && Math.abs(eval('' + lastlong)) <= 180.0) {
extras=' Add G for Google Directions between (' + lastlat + ',' + lastlong + ') to (' + thislat + ',' + thislong + ') and spaces (also more trip legs) to hashtag navigate to Google Charts later. ';
}
}
return extras + outblurb;
}
function alats(inlat) {
if (inlat == 0 && lastlats.length == 0) { inlat=inlat; } else { lastlats.push(inlat); }
return inlat;
}
Onto yesterday’s GeoJson World Countries TimeZone Times Tutorial GeoJson World Countries web application’s capabilities we want to add zooming, that doesn’t rely on web browser functionality (which continues to work). With that in mind we create a new emoji ( 🔎 ) 🔎 link, with this onclick event code …
var jzoom=1.0, izoom=location.search.split('zoom=')[1] ? eval(decodeURIComponent(location.search.split('zoom=')[1].split('&')[0])) : 1.0;
… to multiply the webpage zoom factor in a programmatical way. To acheive this, we have a two way approach (as you might have surmised from above) …
for mobile, the logic is easier by introducing a new meta name=viewport …
<meta id="myviewport" name="viewport" content="width=device-width, initial-scale=1, minimum-scale=0.1, maximum-scale=8, user-scalable=yes" >
… tag … while …
for non-mobile we needed to realize that event.pageX and event.pageY co-ordinates grow in proportion to the zoom factor, and that better latitude and longitude determining lines of code would go …
function canvasclick(e) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
onepixelequals=eval(0.0 + eval(1.0 * izoom));
//document.title='canvasclick';
e = e || window.event;
e.preventDefault();
if (e.touches) {
if (e.touches[0].pageX) {
//lastl='Longitude,Latitude coordinates are ' + eval(topllong + eval(-rectis.left + e.touches[0].pageX) * onepixelequals) + ',' + eval(topllat - eval(-rectis.top + e.touches[0].pageY) * onepixelequals);
if (drawc(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY))) {
thislat=eval(topllat - eval(-rectistop + e.touches[0].pageY) * onepixelequals);
thislong=eval(topllong + eval(-rectisleft + e.touches[0].pageX) * onepixelequals);
//console.log('rectistop=' + rectistop + ' and rectisleft=' + rectisleft + ' and rectisy=' + rectisy + ' and thislat=' + thislat);
document.getElementById('nearestif').src='/PHP/tz_places.php?place=&latitude=' + encodeURIComponent('' + eval(topllat - eval(-rectistop + e.touches[0].pageY) * onepixelequals)) + '&longitude=' + encodeURIComponent('' + eval(topllong + eval(-rectisleft + e.touches[0].pageX) * onepixelequals)) + '&ntztontz=y';
}
} else {
Some readers might be aware of our “theory regarding adverbs” and “web applications” on the net …
the most catered for adverb relates to the “where of life” … and the second banana is …
the “when of life”
… and, further to yesterday’s GeoJson World Countries SVG Overlay Safari Error Tutorial‘s emphasis on the “where of life”, today we add in a bit of the “when of life”, something right down the line of the remit of TimeZone talents.
Seriously though, a lot of us dream of the rest of the world on a world map, and wonder what time it is in other parts of the world. Phone call to relatives? A reminder SMS call? Email a game collaboration? It could all be part of life’s rich tapestry!
The expresion of this, for us, today, improving the communications with our current GeoJsom World Countries web application, take the form of emoji clocks from the 12 hour clock example forms such as …
1 o’clock is 🕐 🕐
2 o’clock is 🕑 🕑
12 o’clock is 🕛 🕛
2:30 is 🕝 🕝
11:30 is 🕦 🕦
12:30 is 🕧 🕧
… to show in “prompt” and “confirm” popup windows, as well as Map Chart maps … via new Javascript functions …
Also, in these same places we add in Time Place country ISO-2 character code based emoji flags, adding to information and colour pizazz in the informational parts to the workings of our changedcountries.phpweb application you can also try below.
On discovering our first solution theory of turning yesterday’s mapsvg.js external Javascript work into an async piece of work made no difference to this situation, we surmised that the huge amount of content held in the Javascript (ie. client side) global variable appendtoinnerHTML was causing memory issues. We couldn’t shift much to do with the overall amount of “data” needing to be handled, in order to implement country SVG colour infilling, but we could shift the data from being …
client side (external) Javascript held … to, instead, (have that data) be (determined on the) …
server side PHP filling in the contents of our (relevant) HTML div id=svgd ahead of the document.body onload event timing …
<?php
$icnt=0;
function apptohtmstuff($coordsare, $origc) {
global $icnt;
$minl=-1;
$mint=-1;
$maxl=-1;
$maxt=-1;
$zysare=explode(',', $coordsare);
$svgcis='';
for ($ij=0; $ij<sizeof($zysare); $ij+=2) {
if ($minl < 0) {
$minl=$zysare[$ij];
$maxl=$zysare[$ij];
$mint=$zysare[1 + $ij];
$maxt=$zysare[1 + $ij];
} else {
if ($zysare[$ij] < $minl) { $minl=$zysare[$ij]; }
if ($zysare[$ij] > $maxl) { $maxl=$zysare[$ij]; }
if ($zysare[1 + $ij] < $mint) { $mint=$zysare[1 + $ij]; }
if ($zysare[1 + $ij] > $maxt) { $maxt=$zysare[1 + $ij]; }
}
}
…everywhere … and an idea we’d ditched yesterday of …
idea to pre-colour “land” parts of the world GeoJson map green (ahead of the document.body onload event) also came good (after causing problems yesterday)
… meaning now, “overlay” wise, we could say …
document.body lowest level …
overlayed by HTML canvas element plotted with world country linework …
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… and we (reckon we’ve) improved the colour coding user experience at the same time.
We noticed that tweaks in the changed …
var lastflagged='', appendtoinnerHTML='', waitplease=false; // used to make sure "area" element onclick code precedes any document.body onmousedown or ontouchdown code
… also lessened the burden on the client side by only asking any Javascript DOM command operations act on single HTML element at a time, not a whole swathe of hosted ones, in any operation.
What deducible data item needs to be determined for these Geo Charts to work? We need a way to deduce ISO-2 character country codes from the ISO-3 character codes existing in the GeoJson “countries.geojson” data from yesterday’s work. We happened upon the extremely generous mapping data webpage to help with these ISO-2 character deductions …
… in our image map area elements PHP creation code above. As you can see, extra “intelligence”, moving forward, is contained in area element global data attributes.
Geo Chart can involve emoji (🏠 &127968;) or image (SVG) circle based symbology for the “User Clicked Place” and nearby TimeZone places respectively …
all these symbols can be clicked to open popup windows containing TimeZone Place Wikipedia webpages of relevance …
an emoji national flag (eg. Zambia “ZA” could be used to derive 🇿🇦 🇿🇦 flag emoji) derived from those ISO-2 character codes can supplement the GeoJson (more ISO-3 character based) names presented in the underlying data, in the Geo Chart title …
contextualizing the accompanying Map Chart … and …
vice versa regarding hovering over symbology (which works on Map Chart, but not Geo Chart) …
within the Map Chart iframe a “Geo” link can glean a “zoomed out” world Geo Chart view of your TimeZone places
Know your GeoJson! Yes, pretty obviously, any two GeoJson datasets might display the same in that “map plotting” sense, but one might have different and/or more “intelligence” than the other. Often, an XML has more “intelligence” than equivalent HTML (barring the use of global data attributes, that is), as today’s Corollacorollary.
Luckily for programmers all over, the organization of TimeZones has had an International flavour in its development and maintenance. As such, given the “purely coastline” GeoJson data involved in our fledgling PHP web application of yesterday’s GeoJson World Coastline Primer Tutorial a useful arrangement for improvement involves …
document.body onclick event co-ordinates … able to be converted to …
longitude, latitude (easily, only because of our simplistic map projection, of course) … onfed to …
… can have us helping out your curious web “clicking” user with the 3 nearest TimeZone places, as a reference as to where they are “clicking” in the world.
in a discrete click methodology of interest, you could adopt a non-mobile “onmousedown” logic set that does not get interfered with by a mobile “ontouchdown” logic set (perhaps leaving “onclick” event, which both non-mobile and mobile both recognise, for another event logic role) … and …
neither will interrupt the mobile gestures associated with swiping and pinching, which refer to the events “ontouchstart” and “ontouchend” at either end of their lifespan
And so, we arrive at a long planned for tilt at Image Map functionality that we often turn to Mobilefish.Com and its excellent Image Map Creation to help us out … but not today?! Why not? We have a funny set of needs, they being …
our Image Map’s image will have a variable set of width x height dimensions …
our Image Map’s image will be transparent
our Image Map needs to have a hole left aside inside it where the functionality that originally existed (and pointed to WordPress Blog content like you are reading), is still working
We want to be able to control the way a Google Charts Geo Chart can be nested within an HTML div element, for instance. We started the day wanting to be able to make …
a Google Charts Geo Chart be a background image to a div element … alas, on this first draft we couldn’t get there (but will continue with the research here) … whereas we succeeded …
adding the Google Charts Geo Chart interfacer’s resultant SVG data as the innerHTML (ie. content) …
<?php echo ”
function newbackin() {
if (dmyxhr.readyState == 4) {
if (dmyxhr.status == 200) {
if (dmyxhr.responseText) {
var m_t='image/jpeg';
var h_t='179';
var w_t='320';
var dbits = dmyxhr.responseText.split('\"height\": ');
if (dbits.length > 1) {
h_t=dbits[1].split(',')[0].split(String.fromCharCode(10))[0].split('}')[0].trim();
}
dbits = dmyxhr.responseText.split('\"mime_type\": \"');
if (dbits.length > 1) {
m_t=dbits[1].split('\"')[0];
}
dbits = dmyxhr.responseText.split('\"width\": ');
if (dbits.length > 1) {
w_t=dbits[1].split(',')[0].split(String.fromCharCode(10))[0].split('}')[0].trim();
}
dbits = dmyxhr.responseText.split('\"data\":');
dbits = dmyxhr.responseText.split('\"data\":');
if (dbits.length > 1) {
// replace all '_' with '/' and all '-' with '+' thanks to https://stackoverflow.com/questions/757675/website-screenshots
dgsbi='<img alt=\"Blog Posting Image\" style=\"width:' + w_t + 'px;height:' + h_t + 'px;\" width=' + w_t + ' height=' + h_t + ' src=\"data:' + m_t + ';base64,' + dbits[1].split('\"')[1].split('\"')[0].replace(/\_/g,'/').replace(/\-/g,'+') + '\"></img>';
//alert('dgsbi=' + dgsbi);
}
}
}
}
}
function ajaxit(urlin) {
if (urlin.length > 0) {
aurl=urlin;
if (window.XMLHttpRequest) {
dmyxhr = new window.XMLHttpRequest;
}
else {
try {
dmyxhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (othermicrosoft) {
try {
dmyxhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (failed) {
dmyxhr = false;
}
}
}
var xurl = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=' + encodeURIComponent(urlin) + '&screenshot=true';
if (dmyxhr) {
dmyxhr.onreadystatechange = newbackin;
dmyxhr.open('GET', xurl, true);
dmyxhr.send(null);
}
}
}
function wbtoa(instris) {
var outstris=instris;
while (outstris.indexOf(String.fromCharCode(10)) != -1) {
outstris=outstris.replace(String.fromCharCode(10),'');
}
var xzs=prompt(outstris, outstris);
return outstris.replace(/\\\"/g, \"'\");
}
In that Nearest Places form part of the TimeZone places webpage, we noticed that even when shaping to enter a TimeZone Placename in the first textbox we made no attempt to fill in …
latitude
longitude
… when we have the information to do so, and even if we’re misunderstanding a placename designation, that should not stop us from trying, because those two numerical fields above can be corrected, and the form resubmitted, in these scenarios.
Apart from making a PHP derived Javascript variable be made available to the code, we “wrap” …
GeoJson World Countries Drag and Drop Makeover Nuance Tutorial
Nuance alert! We’re not sure if you noticed, but if you tried out the Drag and Drop functionality in the World Countries web application of yesterday’s GeoJson World Countries Drag and Drop Makeover Tutorial you may have noticed …
for a country with lots of TimeZone places, like Brazil, you could get a decent Google Chart Geo Chart map up … but if you were to click the “Map?” link down the bottom of that iframe …
it would fail to show a Google Chart Map Chart for that country’s TimeZone places
This fix, believe it or not, is interesting, perhaps only in an “internal use only” sense, we grant you. But our solution got us delving even more into hashtagging data, so that the solution we came up with was a hybrid whereby …
stayed with PHP $_GET[] (ie. address bar ? and & argumented) data (versus using PHP $_POST[] methodologies) … but …
where it came to the &data=[most of the data] part, other than its first character, we hashtagged the rest
… so that the logic flows as per usual, but we intervene at places and flesh it out via location.hash (client side only) means. We won’t bore you too much with all the places of intervention except the receiving map.php’s “easiest to get” intervention …
In addition to the Wikipedia information, at the very least, presented following a successful drag and drop operation, from today, we also start presenting a new HTML iframe element containing …
Nearest TimeZone places along with Google Charts for each unique country involved
we wanted the first popup window content be aligned to the top and left … and then …
we thought it would be good to also, in “Drag and Drop land”, relevant countries nearby to the user’s drop point TimeZone Places be showing below that (and it panned out the best way to show this, for us, was via an iframe pointing at another incarnation of the tz_places.php webpage, because it could have GET arguments iso, iso2, iso3 etcetera to point at ISO 2 letter country codes, which we made more readily available (via a new data-ccglobal data attribute applied to the select option subelements presented) for the changed external Javascript countries.js we decided should get into the mix via a new Javascript function …
function tzagain(inhtml) {
var outhtml=inhtml, dccs=[], getarg='?', theone=1;
if (inhtml.indexOf('left:0px;') != -1 && inhtml.indexOf(' data-cc=') != -1) {
dccs=inhtml.split(' data-cc=');
for (var ii=1; ii<dccs.length; ii++) {
if (getarg == '?') {
getarg+='iso=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2);
theone++;
} else if (getarg.indexOf('=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2)) == -1) {
getarg+='&iso' + theone + '=' + dccs[ii].substring(0,4).replace(/\'/g,'').replace(/\"/g,'').substring(0,2);
theone++;
}
}
if (getarg != '?') {
if (inhtml.indexOf('</bo' + 'ody>') != -1) {
outhtml=inhtml.split('</bo' + 'dy>')[0] + '<iframe src="./tz_places.php' + getarg + '" style="position:absolute;left:0px;top:120px;width:100%;height:900px;"></iframe></body></html>';
} else {
outhtml=inhtml + '<iframe src="./tz_places.php' + getarg + '" style="position:absolute;left:0px;top:120px;width:100%;height:900px;"></iframe>';
}
}
}
return outhtml;
}
… that superfluous looking ?rand=blah measure being pretty useful really regarding getting around the cache keeping old external Javascript in its mind after changes.
Curiously, the grandparent regions.php starting off all this needed no changing! We hope you like these tweaks!
add similar drag and drop logic into our World Coastlines GeoJson web application … and along the way, also for the World Countries web application …
hold off involving the (pretty kludgy looking) vertical scrollbar of our drag and drop pin’s underlying HTML iframe …
<iframe scrolling=no frameborder=0 name=iftr id=iftr style=display:none; srcdoc="<body style=background-color:transparent;><p id=mg title='Wikipedia country page below via drag and drop to world map' draggable='true'>📍</p><br><br><div id=myh1></div><script type='text/javascript' src='./countries.js?rand=321156747657' defer></script></body>" data-src=></iframe>
… until the first drag operation starting, calls on …
parent.document.getElementById('iftr').scrolling='yes';
… proving a Javascript DOM control of the “scrolling” attribute works (as we weren’t sure, having never done this before)
It’s worth beavering away at a guinea pig web application until (just about complete) satisfaction (for now) before having a parallel set of code changes happening simultaneously, we’ve always found.
So, what happened in “external Javascript land”? No need for a “regions.js” here, as parent.document.URL can be scrutinised in that “external Javascript land” to discover which web application is the parent, and act accordingly. So changed were our changed external Javascript countries.js in …
our GeoJson World Countries web application Drag and Drop logic worked on an iPhone … but …
our GeoJson World Countries web application Drag and Drop logic did not work on an iPad
They’re both iOS! And usually the smaller iPhone has the problem and the larger iPad is okay when there is an odd scenario happening. So, what gives? Well, the odd thing is, it was just rearrangements of code and iframe srcdoc usage …
<iframe frameborder=0 name=iftr id=iftr style=display:none; srcdoc="<body style=background-color:transparent;><p id=mg title='Wikipedia country page below via drag and drop to world map' draggable='true'>📍</p><br><br><div id=myh1></div><script type='text/javascript' src='./countries.js?rand=321156747657' defer></script></body>" data-src=></iframe>
… that ended up helping us fix the issues. Figure this, on iPad our emoji pin could not be made visible down the bottom left of iPad screen but could be made to work in the title elements section?! Of course, we might have been having a bad day, but in our defence, even debugging in Safari via …
iPad Safari web browser invocation …
Apple white lead from iPad to MacBook Air …
MacBook Air Safari web browser Develop menu dropdown got us to debugging functionality
“long hover” (ie. on non-mobile, wait for a long while after the onmouseover event initiation to see whether the user is still hovering) … and today, a bit like that, is the new, for us …
“long drag” (the user waits a long time between the drag initialization and the drop event)
… and because we found “dawdling” on a drag and drop fairly unnatural, we think this “long drag” idea “has legs”, in that it works well as a deliberate act made by a user, knowing at the end they benefit from their actions. For us, with our GeoJSON Map web application, yesterday, with GeoJson World Drag and Drop Pin Tutorial, the drag and drop led to …
Wikipedia country information webpage … and today, we allow a “long drag” get you to …
Google Maps drop position information webpage … if the “long drag” is for 10 or more seconds …
Google Earth drop position information webpage … if the “very long drag” is for 20 or more seconds
onclick event logic … and today, we start to also include …
drag and drop event logic (like, but nuanced as explained below, the experimental drag and drop ideas included in the recent Planet Moon Game Tutorial) … the nuanced differences involving …
the drag part of the events occurs in an iframe (populated via small amount of srcdoc HTML and Javascript) able to reference its originator via window.parent …
drop part of the events occurs in that originator parent and so several Javascript function called by the child reside in the parent … and …
the child “drag” event controller uses the new external Javascript countries.js …
// countries.js
// July, 2023
// RJM Programming
// Help out countries.html and countries.php
var pos3=0, pos4=0, tdid='', poligono, punto, coone='', prectis;
// var poligono = [[2,9],[8,6],[12,10],[15,2],[10,4],[5,1]];
// var punto = [6, 5];
function pointInPolygon(polygon, point) { // thanks to https://community.appinventor.mit.edu/t/geofence-check-if-a-point-is-inside-a-polygon-javascript-map/57091
var odd = false;
for (var i = 0, j = polygon.length - 1; i < polygon.length; i++) {
if (((polygon[i][1] > point[1]) !== (polygon[j][1] > point[1]))
&& (point[0] < ((polygon[j][0] - polygon[i][0]) * (point[1] - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0]))) {
odd = !odd;
}
j = i;
}
return odd;
}
function andlaterstill() {
if (9 == 6) { // temporary
if (tdid != '') {
document.getElementById(tdid).innerHTML=document.getElementById(tdid).innerHTML.substring(0,1);
} else if (document.getElementById('mytable').innerHTML.indexOf(clonedatatwo) != '') {
document.getElementById('myh1').innerHTML=document.getElementById('myh1').innerHTML.split('</table>')[0] + '</table>';
}
if (document.getElementsByTagName('div')[0].innerHTML.indexOf(clonedatatwo) != -1) {
document.getElementsByTagName('div')[0].innerHTML=document.getElementsByTagName('div')[0].innerHTML.replace(clonedatatwo,'');
} else if (document.getElementsByTagName('div')[0].innerHTML.indexOf(clonedatatwo.replace('dragging','')) != -1) {
document.getElementsByTagName('div')[0].innerHTML=document.getElementsByTagName('div')[0].innerHTML.replace(clonedatatwo.replace('dragging',''),'');
} else if (document.body.innerHTML.split('<table')[0].indexOf(clonedatatwo.replace('dragging','')) != -1) {
document.body.innerHTML=document.body.innerHTML.replace(document.body.innerHTML.split('<table')[0], document.body.innerHTML.split('<table')[0].replace(clonedatatwo.replace('dragging',''),''));
} else if (document.body.innerHTML.split('<table')[0].indexOf(clonedatatwo) != -1) {
document.body.innerHTML=document.body.innerHTML.replace(document.body.innerHTML.split('<table')[0], document.body.innerHTML.split('<table')[0].replace(clonedatatwo,''));
}
}
tdid='';
}
function getprectis() {
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
return window.opener.document.body.getBoundingClientRect();
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
return parent.document.body.getBoundingClientRect();
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
return parent.document.body.getBoundingClientRect();
}
}
return null;
}
function wod(ididea) {
if (window.opener) {
if (window.opener.document.getElementsByTagName(ididea)[0]) {
return window.opener.document.getElementsByTagName(ididea)[0];
} else if (window.parent) {
if (parent.document.getElementsByTagName(ididea)[0]) {
return parent.document.getElementsByTagName(ididea)[0];
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName(ididea)[0]) {
return parent.document.getElementsByTagName(ididea)[0];
}
}
return null;
}
function ccit() {
var divs, esot=[], bodyois=null;
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
bodyois=window.opener.document.getElementsByTagName('body')[0];
divs=window.opener.document.getElementsByTagName('div');
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
bodyois=parent.document.getElementsByTagName('body')[0];
divs=parent.document.getElementsByTagName('div');
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
bodyois=parent.document.getElementsByTagName('body')[0];
divs=parent.document.getElementsByTagName('div');
}
}
function andqlater() {
//alert('HeRe');
tdid='';
var ppig='[]', coo='', coos=[], ip=0;
var squares; //=window.opener.document.getElementsByTagName('area');
if (window.opener) {
if (window.opener.document.getElementsByTagName('body')[0]) {
squares=window.opener.document.getElementsByTagName('area');
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
squares=parent.document.getElementsByTagName('area');
}
}
} else if (window.parent) {
if (parent.document.getElementsByTagName('body')[0]) {
squares=parent.document.getElementsByTagName('area');
}
}
window.addEventListener("DOMContentLoaded", () => {
const source = document.querySelector("#mg");
console.log('source.id=' + source.id);
source.addEventListener("dragstart", (ev) => {
console.log("dragStart");
// Change the source element's background color
// to show that drag has started
ev.currentTarget.classList.add("dragging");
// Clear the drag data cache (for all formats/types)
ev.dataTransfer.clearData();
// Set the drag's format and data.
// Use the event target's id for the data
ev.dataTransfer.setData("text/plain", ev.target.id);
//ev.dataTransfer.setData("text/html", ev.target.outerHTML);
});
source.addEventListener("dragend", (ev) =>
ev.target.classList.remove("dragging")
);
const target = wod('body'); //window.opener.document.getElementsByTagName('body')[0];
target.id='usemap';
console.log('target.id=' + target.id);
target.addEventListener("dragover", (ev) => {
console.log("dragOver");
ev.preventDefault();
});
target.addEventListener("drop", (ev) => {
console.log("Drop");
ev.preventDefault();
// Get the data, which is the id of the source element
const data = ev.dataTransfer.getData("text");
const source = document.getElementById(data);
… where heap memory concerns related to the global variables memory used in our GeoJson World Coastlines webpage could cause mobile platform usage reloads of the web application, reminiscent of the external Javascript concerns we had back at GeoJson World Countries SVG Overlay Safari Error Tutorial.
There, as for here, mobile usage got better by swapping global variable usage for HTML content static PHP …
GeoJson World Coastline Function Noun Naming Tutorial
We’re working on an extension to yesterday’s GeoJson World Coastline Rivers Quiz Tutorial‘s Rivers Quiz functionality within our GeoJson World Coastlines web application, and have …
settled on an approach … but …
not yet finished on deployment issues
… but it is this approach we wanted to talk about today.
Our approach borrows from Object Oriented Programming (OOP) the idea that …
just as with OOP thinking class names are like nouns and the methods within that class are like verbs … we, with our approach …
help readability of our non-OOP functional code by including those nouns and verbs, as well as ideas like use of plurals to indicate array involvement, with our Javascript function naming
… we can best illustrate to you via showing you new functions and variables and modified code to show you this approach in code …
var rivers='', arivers=[], iguess=-1, isofar=' ', jscore=0, jgoes=0, elema=null, contexta=null, rectisleft=0, rectistop=0, isokto=true;
var populations='', apopulations=[], jguess=-1, jsofar=' ', both=false, jlastn='';
var idone=false;
function askapopulation() {
var another=false;
var origboth=both;
var midbit='';
var thing='population';
if (!both) { midbit='Append spaces to also answer a question regarding the Rivers Quiz, or R to just do Rivers Quiz.'; } else { thing='river'; }
var retthis=prompt('What is the name of this new red population area plotted on the world map? ' + midbit + ' Enter ? to get given more time looking at (longitude,latitude) = (' + apopulations[jguess].split(':')[1].split(',')[0] + ',' + apopulations[jguess].split(':')[1].split(',')[1] + ')', '');
if (retthis == null) {
both=false;
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (retthis.toLowerCase().trim() == 'r') {
both=false;
isokto=true;
getariver();
return '';
} else if (retthis.trim() == '?') {
if (retthis.trim() != retthis && !origboth) { both=true; }
setTimeout(askapopulation, 9000);
return '';
} else if (retthis.trim() == '') {
if (retthis != '' && !origboth) { thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
if (retthis != '' && !origboth) { isokto=true; both=true; getariver(); }
} else if (jlastn.toLowerCase().indexOf(retthis.toLowerCase()) != -1 && jlastn.toLowerCase() == retthis.toLowerCase() && retthis.trim().length >= 1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (jlastn.toLowerCase().indexOf(retthis.toLowerCase()) == -1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (jlastn.toLowerCase() == retthis.toLowerCase()) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Well done! Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else if (retthis.trim().length >= 1) {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
another=confirm('Bad luck. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
} else {
if (retthis.trim() != retthis && !origboth) { both=true; thing='river'; }
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + jlastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new ' + thing + '?');
}
if (both) { contexta.clearRect(0,0,360,180); }
if (both && !origboth) { isitok=true; getariver(); return ''; }
if (another) { if (both) { getariver(); getapopulation(); } else { getapopulation(); } } else { contexta.clearRect(0,0,360,180); }
return '';
}
function plotapopulation(which) {
if (isokto) { contexta.clearRect(0,0,360,180); }
//if (both) { isokto=true; }
jlastn=apopulations[which].split(':')[0];
var rest=apopulations[which].split(':')[1];
var restlonglat=[]; //rest.split(',');
restlonglat=rest.split(',');
if (eval('' + restlonglat.length) >= 2) {
contexta.fillStyle = 'red';
contexta.fillRect(eval(180.0 + eval('' + restlonglat[0])), eval(90.0 - eval('' + restlonglat[1])),1,1);
contexta.fill();
}
}
It’s time to turn our attention away from GeoJson World Countries, as talked about with yesterday’s GeoJson World Countries Plotted Ports Tutorial, and back to GeoJson World Coastline ideas. Why? We want to add a …
Rivers Quiz
… via the (generously provided) HTTP://geojson.xyz rivers lake centerlines GeoJSON data we download and then uploaded to become rivers.geojson data file. Now we were wondering out of …
use the URL to this GeoJSON file as the “src” attribute of an HTML iframe …
<iframe id=ifrivers onload=getthejson(this); style=display:none; src=./rivers.geojson></iframe>
… element (and then access the content via the onload event …
var rivers='', arivers=[], iguess=-1, isofar=' ', jscore=0, jgoes=0, elema=null, contexta=null, rectisleft=0, rectistop=0;
function getthejson(iois) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
rivers='' + aconto.body.innerHTML;
setTimeout(populaterivers, 500);
}
}
}
… function) would suffice, or if we would end up using …
Ajax call
… to access this data, and were a bit surprised the former method was all fine. Of course there are snazzy inbuilt Javascript hierarchical calls you can make to process the data, but we find, with GeoJSON data, in the client realm (where we’re keen to stay with today’s work (though PHP serverside can, of course, be purloined to do all this work, should you have that available)), of Javascript, we just need very basic string functions …
The progress with GeoJson World Countries helped too. We knew to add another HTML canvas layer as per …
document.body (now with the new onmousemove=airportplot(event); event logic) lowest level …
overlayed by HTML canvas element plotted with world country linework … now including …
overlayed by HTML canvas element dedicated to nearest airport plotting …
<canvas id=myacanvas height='180' width='360' style='background-color:transparent;z-index:55;display:inline-block;position:absolute;top:0px;left:0px;'></canvas>
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… and to, at document.body onload logic …
// ... and extended document.body onload event logic has added, up near its top ...
elema = document.getElementById('myacanvas');
contexta = elema.getContext('2d');
… and supplement with another HTML sub “emoji button” ❓ ( ❓ ) type element …
function askariver() {
var another=false;
var retthis=prompt('What is the name of this new blue river plotted on the world map? Enter ? to get given more time looking at (longitude,latitude) = (' + arivers[iguess].split(':')[1].split(',')[0] + ',' + arivers[iguess].split(':')[1].split(',')[1] + ')', '');
if (retthis == null) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (retthis.trim() == '?') {
setTimeout(askariver, 8000);
return '';
} else if (retthis.trim() == '') {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (lastn.toLowerCase().indexOf(retthis.toLowerCase()) == -1) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (lastn.toLowerCase() == retthis.toLowerCase()) {
jgoes++;
jscore++;
another=confirm('Well done! Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else if (retthis.trim().length >= 1) {
jgoes++;
another=confirm('Bad luck. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
} else {
jgoes++;
jscore++;
another=confirm('Will pay that. Answer was ' + lastn + '. Score ' + jscore + '/' + jgoes + '. Another go with a new river?');
}
if (another) { getariver(); } else { contexta.clearRect(0,0,360,180); }
return '';
}
… to work the Rivers Quiz. Finally, though, for all good practicalities we also need those zoom logics out of GeoJson World Countries logic, via “emoji button” 🔎 ( 🔎 ) …
where to modularise … we think “data collection” commonality is a good reason, and so we make these changes to intair.php
making an (“animated emoji”) button dual purpose on top of originally being a single purpose button …
<sub title='Show Nearby Airports' onclick='doair=how(true,this); twothousand*=2; this.title=this.title.substring(0,4) + String.fromCharCode(105) + String.fromCharCode(110) + String.fromCharCode(103) + this.title.replace(this.title.split(String.fromCharCode(32))[0] + String.fromCharCode(32), String.fromCharCode(32));' data-type=9992 style=cursor:pointer; id=portsub>✈</sub>
… working with the intairsuffix global variable that could add a new GET argument where both the “port” label in &port=[value] and that [value] can affect behaviour from the intair.php PHP helper tool above …
var intairsuffix='', zhra=null, zhrb=null, kklat=0, kklong=0, doair=false, vsll=[-999.0], answered=true;
function how(atr, isub) {
var curgd=isub.getAttribute('data-type');
if (('' + curgd) == '9992') { // airport
if (intairsuffix != '') {
intairsuffix='&port=air';
isub.title='Showing Nearby Airports and Ports';
document.getElementById('title').value='Nearby Timezone Places and Airports and Ports';
}
} else if (('' + curgd) == '128674') { // port
if (intairsuffix == '') {
if (doair) {
intairsuffix='&port=air';
isub.title='Showing Nearby Airports and Ports';
document.getElementById('title').value='Nearby Timezone Places and Airports and Ports';
} else {
intairsuffix='&port=y';
isub.title='Showing Nearby Ports';
document.getElementById('title').value='Nearby Timezone Places and Ports';
}
}
}
return true;
}
function feedhow() {
var isub=document.getElementById('portsub');
var curgd=isub.getAttribute('data-type');
if (('' + curgd) == '9992') { // airport
isub.innerHTML='🚢';
isub.setAttribute('data-type', '128674');
} else if (('' + curgd) == '128674') { // port
isub.innerHTML='✈';
isub.setAttribute('data-type', '9992');
}
}
Ajax asynchronous usage for second half of a synchronous previous usage …
var intairsuffix='', zhra=null, zhrb=null, kklat=0, kklong=0, doair=false, vsll=[-999.0], answered=true;
function stateChangedb() {
if (zhrb.readyState == 4) {
if (zhrb.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhrb.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
}
}
}
function stateChangeda() {
if (zhra.readyState == 4) {
if (zhra.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhra.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
if (intairsuffix.indexOf('&port=air') != -1) {
zhrb = new XMLHttpRequest();
zhrb.onreadystatechange=stateChangedb;
zhrb.open('get', '/HTMLCSS/intair.php?num=6&lat=' + kklat + '&long=' + kklong + '&port=y', true);
zhrb.send(null);
}
answered=true;
}
}
}
… keeps a fastish synchronous call (that we enforce via that answered global variable) but truely invokes an asynchronous arrangement extracting Nearby Ports data to plot, as applicable
Introducing the Map Chart recognition of nearby Airports with yesterday’s GeoJson World Countries Nearest Airports Tutorial‘s progress on our latest GeoJson World Countries PHP web application, it set us to seeing …
the combination of Google Directions‘s talents allowing you to reposition on the fly … and …
the onmousemove event, at least for our non-mobile users
… could mean that if we pre-plot airports on the world map, given that the user has clicked the ✈ ( ✈ ) “Show an Interest in Airports” emoji button, as a non-mobile user hovers over the world map, this pre-plotting might help trip planners with their travel options, should air travel be part of their interest, in the same way it is an option up at Google Directions in our changedcountries.phpweb application you can also try below. The overlay scenario now reads …
document.body (now with the new onmousemove=airportplot(event); event logic) lowest level …
overlayed by HTML canvas element plotted with world country linework … now including …
overlayed by HTML canvas element dedicated to nearest airport plotting …
<canvas id=myacanvas height='180' width='360' style='background-color:transparent;z-index:55;display:inline-block;position:absolute;top:0px;left:0px;'></canvas>
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… worked by new (sometimes Ajax) Javascript code …
function inarray(needle, haystack) { // thanks to https://stackoverflow.com/questions/784012/javascript-equivalent-of-phps-in-array
var length = haystack.length;
for (var i = 0; i < length; i++) {
if (haystack[i] == needle) return true;
}
return false;
}
function stateChangeda() {
if (zhra.readyState == 4) {
if (zhra.status == 200) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
var onepixelequals=izoom;
var bts=zhra.response.split('.src + ' + String.fromCharCode(39));
if (eval('' + bts.length) > 1) {
for (var ijh=1; ijh<bts.length; ijh++) {
var vs=eval(eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))) +
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top))));
if (!inarray(vs,vsll)) {
vsll.push(vs);
drawaac(
eval(eval(eval(-topllong + eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[1])) * onepixelequals) + eval(0 * eval(rectis.left))),
eval(eval(eval(topllat - eval(bts[ijh].split(String.fromCharCode(39))[0].split('[')[1].split(',')[0])) * onepixelequals) + eval(0 * eval(rectis.top)))
);
}
}
}
answered=true;
}
}
}
function naira(klat, klong) {
if (answered && doair) {
answered=false;
zhra = new XMLHttpRequest();
zhra.onreadystatechange=stateChangeda;
zhra.open('get', '/HTMLCSS/intair.php?num=6&lat=' + klat + '&long=' + klong, true);
zhra.send(null);
}
}
function airportplot(e) {
if (answered) {
var rectis=null; //document.body.getBoundingClientRect();
var blat=0, blong=0;
var topllong=-180.0;
var topllat=90.0;
onepixelequals=eval(0.0 + eval(1.0 * izoom));
e = e || window.event;
e.preventDefault();
if (e.touches) {
if (e.touches[0].pageX) {
naira(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY)); //if (drawac(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY))) e = e; }
} else {
rectis=document.body.getBoundingClientRect();
naira(eval(-rectis.left + e.touches[0].clientX), eval(-rectis.top + e.touches[0].clientY)); //if (drawac(eval(-rectis.left + e.touches[0].clientX), eval(-rectis.top + e.touches[0].clientY))) { e = e; }
}
} else if (e.pageX || e.pageY) {
blat=eval(eval(eval(topllat * onepixelequals - eval(-rectistop + e.pageY) * 1)) / onepixelequals);
blong=eval(eval(eval(topllong * onepixelequals + eval(-rectisleft + e.pageX) * 1)) / onepixelequals);
if ((blat >= -90.0 && blat <= 90.0) && (blong >= -180.0 && blong <= 180.0)) {
naira(blat, blong); //if (drawac(eval(-rectisleft + e.pageX), eval(-rectistop + e.pageY))) { e = e; }
}
} else {
rectis=document.body.getBoundingClientRect();
naira(eval(-rectis.left + e.clientX), eval(-rectis.top + e.clientY)); //if (drawac(eval(-rectis.left + e.clientX), eval(-rectis.top + e.clientY))) { e = e; }
}
}
}
// ... and extended document.body onload event logic has added, up near its top ...
elema = document.getElementById('myacanvas');
contexta = elema.getContext('2d');
add interfacing functionality to the excellent Google Directions part of Google Maps, perhaps to help with Trip planning, or even just to associate a Placename with a latitude and longitude as clicked by the user, via the very simple URL arrangement … https://www.google.com/maps/dir/[decimalLatitudeDegrees]/[decimalLongitudeDegrees]
… helped out by new Javascript functions …
var lastlats=[], lastlongs=[], lastlat=-99.0, lastlong=-99.0, thislat=0.0, thislong=0.0;
function preface(inblurb) {
var extras='';
var outblurb=inblurb;
if (Math.abs(eval('' + lastlat)) > 0.0 || Math.abs(eval('' + lastlong)) > 0.0) {
if (Math.abs(eval('' + lastlat)) <= 90.0 && Math.abs(eval('' + lastlong)) <= 180.0) {
extras=' Add G for Google Directions between (' + lastlat + ',' + lastlong + ') to (' + thislat + ',' + thislong + ') and spaces (also more trip legs) to hashtag navigate to Google Charts later. ';
}
}
return extras + outblurb;
}
function alats(inlat) {
if (inlat == 0 && lastlats.length == 0) { inlat=inlat; } else { lastlats.push(inlat); }
return inlat;
}
Onto yesterday’s GeoJson World Countries TimeZone Times Tutorial GeoJson World Countries web application’s capabilities we want to add zooming, that doesn’t rely on web browser functionality (which continues to work). With that in mind we create a new emoji ( 🔎 ) 🔎 link, with this onclick event code …
var jzoom=1.0, izoom=location.search.split('zoom=')[1] ? eval(decodeURIComponent(location.search.split('zoom=')[1].split('&')[0])) : 1.0;
… to multiply the webpage zoom factor in a programmatical way. To acheive this, we have a two way approach (as you might have surmised from above) …
for mobile, the logic is easier by introducing a new meta name=viewport …
<meta id="myviewport" name="viewport" content="width=device-width, initial-scale=1, minimum-scale=0.1, maximum-scale=8, user-scalable=yes" >
… tag … while …
for non-mobile we needed to realize that event.pageX and event.pageY co-ordinates grow in proportion to the zoom factor, and that better latitude and longitude determining lines of code would go …
function canvasclick(e) {
var rectis=document.body.getBoundingClientRect();
var topllong=-180.0;
var topllat=90.0;
onepixelequals=eval(0.0 + eval(1.0 * izoom));
//document.title='canvasclick';
e = e || window.event;
e.preventDefault();
if (e.touches) {
if (e.touches[0].pageX) {
//lastl='Longitude,Latitude coordinates are ' + eval(topllong + eval(-rectis.left + e.touches[0].pageX) * onepixelequals) + ',' + eval(topllat - eval(-rectis.top + e.touches[0].pageY) * onepixelequals);
if (drawc(eval(-rectisleft + e.touches[0].pageX), eval(-rectistop + e.touches[0].pageY))) {
thislat=eval(topllat - eval(-rectistop + e.touches[0].pageY) * onepixelequals);
thislong=eval(topllong + eval(-rectisleft + e.touches[0].pageX) * onepixelequals);
//console.log('rectistop=' + rectistop + ' and rectisleft=' + rectisleft + ' and rectisy=' + rectisy + ' and thislat=' + thislat);
document.getElementById('nearestif').src='/PHP/tz_places.php?place=&latitude=' + encodeURIComponent('' + eval(topllat - eval(-rectistop + e.touches[0].pageY) * onepixelequals)) + '&longitude=' + encodeURIComponent('' + eval(topllong + eval(-rectisleft + e.touches[0].pageX) * onepixelequals)) + '&ntztontz=y';
}
} else {
Some readers might be aware of our “theory regarding adverbs” and “web applications” on the net …
the most catered for adverb relates to the “where of life” … and the second banana is …
the “when of life”
… and, further to yesterday’s GeoJson World Countries SVG Overlay Safari Error Tutorial‘s emphasis on the “where of life”, today we add in a bit of the “when of life”, something right down the line of the remit of TimeZone talents.
Seriously though, a lot of us dream of the rest of the world on a world map, and wonder what time it is in other parts of the world. Phone call to relatives? A reminder SMS call? Email a game collaboration? It could all be part of life’s rich tapestry!
The expresion of this, for us, today, improving the communications with our current GeoJsom World Countries web application, take the form of emoji clocks from the 12 hour clock example forms such as …
1 o’clock is 🕐 🕐
2 o’clock is 🕑 🕑
12 o’clock is 🕛 🕛
2:30 is 🕝 🕝
11:30 is 🕦 🕦
12:30 is 🕧 🕧
… to show in “prompt” and “confirm” popup windows, as well as Map Chart maps … via new Javascript functions …
Also, in these same places we add in Time Place country ISO-2 character code based emoji flags, adding to information and colour pizazz in the informational parts to the workings of our changedcountries.phpweb application you can also try below.
On discovering our first solution theory of turning yesterday’s mapsvg.js external Javascript work into an async piece of work made no difference to this situation, we surmised that the huge amount of content held in the Javascript (ie. client side) global variable appendtoinnerHTML was causing memory issues. We couldn’t shift much to do with the overall amount of “data” needing to be handled, in order to implement country SVG colour infilling, but we could shift the data from being …
client side (external) Javascript held … to, instead, (have that data) be (determined on the) …
server side PHP filling in the contents of our (relevant) HTML div id=svgd ahead of the document.body onload event timing …
<?php
$icnt=0;
function apptohtmstuff($coordsare, $origc) {
global $icnt;
$minl=-1;
$mint=-1;
$maxl=-1;
$maxt=-1;
$zysare=explode(',', $coordsare);
$svgcis='';
for ($ij=0; $ij<sizeof($zysare); $ij+=2) {
if ($minl < 0) {
$minl=$zysare[$ij];
$maxl=$zysare[$ij];
$mint=$zysare[1 + $ij];
$maxt=$zysare[1 + $ij];
} else {
if ($zysare[$ij] < $minl) { $minl=$zysare[$ij]; }
if ($zysare[$ij] > $maxl) { $maxl=$zysare[$ij]; }
if ($zysare[1 + $ij] < $mint) { $mint=$zysare[1 + $ij]; }
if ($zysare[1 + $ij] > $maxt) { $maxt=$zysare[1 + $ij]; }
}
}
…everywhere … and an idea we’d ditched yesterday of …
idea to pre-colour “land” parts of the world GeoJson map green (ahead of the document.body onload event) also came good (after causing problems yesterday)
… meaning now, “overlay” wise, we could say …
document.body lowest level …
overlayed by HTML canvas element plotted with world country linework …
overlayed by HTML img (transparent image) element and its associated image map area elements … and today we add into the mix …
HTML div hosting SVG elements overlaying initialized with “land” parts green infilled SVG at a mid range z-index (only as well as when called upon) individual GeoJson entities overlay
… and we (reckon we’ve) improved the colour coding user experience at the same time.
We noticed that tweaks in the changed …
var lastflagged='', appendtoinnerHTML='', waitplease=false; // used to make sure "area" element onclick code precedes any document.body onmousedown or ontouchdown code
… also lessened the burden on the client side by only asking any Javascript DOM command operations act on single HTML element at a time, not a whole swathe of hosted ones, in any operation.
What deducible data item needs to be determined for these Geo Charts to work? We need a way to deduce ISO-2 character country codes from the ISO-3 character codes existing in the GeoJson “countries.geojson” data from yesterday’s work. We happened upon the extremely generous mapping data webpage to help with these ISO-2 character deductions …
… in our image map area elements PHP creation code above. As you can see, extra “intelligence”, moving forward, is contained in area element global data attributes.
Geo Chart can involve emoji (🏠 &127968;) or image (SVG) circle based symbology for the “User Clicked Place” and nearby TimeZone places respectively …
all these symbols can be clicked to open popup windows containing TimeZone Place Wikipedia webpages of relevance …
an emoji national flag (eg. Zambia “ZA” could be used to derive 🇿🇦 🇿🇦 flag emoji) derived from those ISO-2 character codes can supplement the GeoJson (more ISO-3 character based) names presented in the underlying data, in the Geo Chart title …
contextualizing the accompanying Map Chart … and …
vice versa regarding hovering over symbology (which works on Map Chart, but not Geo Chart) …
within the Map Chart iframe a “Geo” link can glean a “zoomed out” world Geo Chart view of your TimeZone places
Know your GeoJson! Yes, pretty obviously, any two GeoJson datasets might display the same in that “map plotting” sense, but one might have different and/or more “intelligence” than the other. Often, an XML has more “intelligence” than equivalent HTML (barring the use of global data attributes, that is), as today’s Corollacorollary.
Luckily for programmers all over, the organization of TimeZones has had an International flavour in its development and maintenance. As such, given the “purely coastline” GeoJson data involved in our fledgling PHP web application of yesterday’s GeoJson World Coastline Primer Tutorial a useful arrangement for improvement involves …
document.body onclick event co-ordinates … able to be converted to …
longitude, latitude (easily, only because of our simplistic map projection, of course) … onfed to …
… can have us helping out your curious web “clicking” user with the 3 nearest TimeZone places, as a reference as to where they are “clicking” in the world.
in a discrete click methodology of interest, you could adopt a non-mobile “onmousedown” logic set that does not get interfered with by a mobile “ontouchdown” logic set (perhaps leaving “onclick” event, which both non-mobile and mobile both recognise, for another event logic role) … and …
neither will interrupt the mobile gestures associated with swiping and pinching, which refer to the events “ontouchstart” and “ontouchend” at either end of their lifespan
And so, we arrive at a long planned for tilt at Image Map functionality that we often turn to Mobilefish.Com and its excellent Image Map Creation to help us out … but not today?! Why not? We have a funny set of needs, they being …
our Image Map’s image will have a variable set of width x height dimensions …
our Image Map’s image will be transparent
our Image Map needs to have a hole left aside inside it where the functionality that originally existed (and pointed to WordPress Blog content like you are reading), is still working
if we are talking URLs all on the same domain … check …
and you have a place on the webpage good to relocate … shaky check …
then it is better, in the scenario of using window.open (popup window creation) …
window.open(URL, name, specs, replace)
… syntax based navigation logic in Javascript, to …
… make use of that second parameter’s …
name Optional.
The target attribute or the name of the window.
The following values are supported:
Value Description
_blank URL is loaded into a new window, or tab. This is the default
_parent URL is loaded into the parent frame
_self URL replaces the current page
_top URL replaces any framesets that may be loaded
name The name of the window (does not specify the title of the window)
… relation to the name attribute of an inhouse HTML iframe element to “relocate”, and improve some user’s “user experience”.
So, please, respect window.open method, not so much some of the ways it is used. It is incredibly useful!
Here is our inhouse “wrapped” Javascript function approach to its usage incarnation …
function windowdotopen(a1, a2, a3) {
var pfx='';
if (document.getElementById('ifrmore')) {
document.getElementById('prermore').style.display='block';
document.getElementById('ifrmore').style.display='block';
//document.title='1';
return window.open(a1, 'ifrmore', a3);
} else if (document.getElementById('rmore')) {
pfx=document.getElementById('rmore').innerHTML;
setTimeout(function(){
document.getElementById('rmore').innerHTML+='<iframe title="Courtesy of Wikipedia ... thanks" name=ifrmore id=ifrmore src="' + a1 + '" style="width:800px;height:800px;"></iframe>';
topwo=window.open(document.getElementById('ifrmore').src, 'ifrmore');
}, 2000);
//document.title='3';
return null; //window.open(a1, 'ifrmore', a3);
} else if (document.getElementById('prermore')) {
document.getElementById('prermore').innerHTML='<iframe title="Courtesy of Wikipedia ... thanks" name=ifrmore id=ifrmore src="' + a1 + '" style="width:100%;height:800px;"></iframe>';
document.getElementById('prermore').style.display='block';
//document.title='2';
return window.open(a1, 'ifrmore', a3);
} else if (document.getElementById('tdright')) {
if (document.getElementById('rmore')) {
pfx=document.getElementById('rmore').outerHTML;
}
document.getElementById('tdright').innerHTML='<div style="display:block;" id="prermore"><iframe title="Courtesy of Wikipedia ... thanks" name=ifrmore id=ifrmore src="' + a1 + '" style="width:100%;height:800px;"></iframe></div>' + pfx;
//document.title='4';
return window.open(a1, 'ifrmore', a3);
}
return window.open(a1, a2, a3);
}
Region Picker GeoChart Region Wikipedia Representations Tutorial
We’re starting down the long and windy road, further to the recent Region Picker GeoJson Area of Interest Tutorial, of providing “workaround Google Chart Geo Chart solutions to semi-cover the loss (because nothing will be quite as good, as far as we are concerned, alas) of Google Chart Image Chart Map Chart” in our lives (please pass the tissues … fisst). In our case, the Region Picker intervention point (believe it or not) is our …
WordPress Blog 404.php (missing webpage page) logic we’ve tailored for all manner of image production purposes helping out …
… logic we get the great help from Wikipedia to make up for …
lack of boundary regional definition on a Google Chart Geo Chart marker map … with …
Wikipedia’s representative region positioning, thanks, we can present as the …
region name … toggleable backwards and forwards to …
region marker
… on the Google Chart Geo Chart marker map now displayed to the user instead of what used to be a Google Chart Image Chart Map Chart regional boundary map … (please pass the tissues … fisst).
There is no doubt we’ll be tweaking away at all this, trying to improve the integrations for both user experience (including speed) and aesthetic means. Please pack a sandwich (or 3) and a toothbrush … and toothpaste … and vegemite … and fisst, the tissues.
Meanwhile, back in “Region Picker Land” where, if we’re not mistaken, the grapes are peculiarly sweet this season, and we needed their “fortification” to tackle today’s progress, that being …
user has picked a country of interest and has gone “The Whole Shebang” resulting in those …
tutti-frutti region links below the Image Chart (rightmost) button …
one of which the user clicks/touches … resulting in …
presentation of inhouse menu prompt window … where …
option “J” (for GeoJson World Map option) is presented (because a relevant latitude and longitude were found) … and “lo and behold” …
user types in J …
user does not click Cancel at the next prompt window … ready for it …
as of today two new buttons appear …
Mobile
Non-mobile
… to the right of the subheading … and while we’re there see how the innards …
Mobile
Non-mobile
<button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:yellow; id=twoc onclick=’event.stopPropagation(); parent.dotwoc();’>Circle of Interest via Next 2 Double Clicks</button> <button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:magenta; id=twoc onclick=’event.stopPropagation(); parent.dotwor();’>Rectangle via 2 Double Clicks</button>
<button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:yellow; id=twoc onclick=’event.stopPropagation(); parent.dotwoc();’>Circle of Interest via Next 2 Right Clicks</button> <button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:magenta; id=twoc onclick=’event.stopPropagation(); parent.dotwor();’>Rectangle via 2 Right Clicks</button>
… are very OOP by nature (as is all DOM work in Javascript, when you think about it), allowing us to remain with the iframe initial content supervisor unchanged in code, and just referring back to the parent’s Javascript for anything new either via …
means of the iframe onload event
means of referring back to parent operations via references like …
parent.setdefzoom(1); // which is setting the variable "defzoom", back in the parent, to 1
… in this new Javascript …
var oneoftwo=0, xinxy=[], yinxy=[], opis='1.0', ovnum=1, defzoom=2, nextv='hidden';
var zaconto=null; // this is populated at the iframe element's onload event function
… type call) event function (non-mobile one semi-shown below) …
function nonmifcheck(ziois) { // non-mobile iframe onload event function
var waszoom=1;
var sparear=null, gsparear=null;
var xif=-999, yif=-999, xxif=-999, yyif=-999;
zaconto = (ziois.contentWindow || ziois.contentDocument);
if (zaconto.document) { zaconto = zaconto.document; }
// ...
// used later into the function, as well as in that new Javascript above, everywhere ...
//
zaconto.getElementsByTagName('table')[0].style.top='385px';
zaconto.getElementsByTagName('table')[0].style.left='0px';
if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
zaconto.getElementsByTagName('h3')[0].style.marginTop='6px';
zaconto.getElementsByTagName('h3')[0].innerHTML+=" <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:yellow; id=twoc onclick='event.stopPropagation(); parent.dotwoc();'>Circle of Interest via Next 2 Right Clicks</button> <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:magenta; id=twoc onclick='event.stopPropagation(); parent.dotwor();'>Rectangle via 2 Right Clicks</button><div id=imgmore></div><div id=dvstyle>";
zaconto.body.oncontextmenu=function(event){ if (parent.getoneoftwo() == 0) { event=event; } else if (Math.abs(parent.getoneoftwo()) == 1) { event.stopPropagation(); parent.getxynow(event); if (parent.getoneoftwo() < 0) { parent.setoneoftwo(eval(-1 + eval('' + parent.getoneoftwo()))); } else { parent.setoneoftwo(eval(1 + eval('' + parent.getoneoftwo()))); } } else if (Math.abs(parent.getoneoftwo()) == 2) { event.stopPropagation(); parent.getxynow(event); if (1 == 3) { parent.overlayit(0); } } };
} else {
zaconto.getElementsByTagName('h3')[0].innerHTML+=" <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:yellow; id=twoc onclick='event.stopPropagation(); parent.dotwoc();'>Circle of Interest via Next 2 Double Clicks</button> <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:magenta; id=twoc onclick='event.stopPropagation(); parent.dotwor();'>Rectangle via 2 Double Clicks</button><div id=imgmore></div><div id=dvstyle>";
zaconto.body.ondblclick=function(event){ if (parent.getoneoftwo() == 0) { event=event; } else if (Math.abs(parent.getoneoftwo()) == 1) { event.stopPropagation(); parent.getxynow(event); if (parent.getoneoftwo() < 0) { parent.setoneoftwo(eval(-1 + eval('' + parent.getoneoftwo()))); } else { parent.setoneoftwo(eval(1 + eval('' + parent.getoneoftwo()))); } } else if (Math.abs(parent.getoneoftwo()) == 2) { event.stopPropagation(); parent.getxynow(event); if (1 == 3) { parent.overlayit(0); } } };
}
// ...
}
… and yet, elements are added to the “iframe child” (rather than to the parent document.body element) here … believe me … this, and using the Mercator Projection means of moving between “pixel land” and “latitude and longitude land”, is better!
which have the on hover blurb …
One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom
… which is just to say that the more clicks in a row of the button, the more resultant zoom goes into an onmouseover “hover” over that intermittently shown “circle” or “polygon” rectangle clip-path affected image (ie. img) overlay element placed according to the 2x set of user right click sets (for non-mobile) or double click sets (for mobile) the user subsequently makes on the GeoJson world map above these new buttons
… that, if actioned by the user, ends up with an “augmented reality” (in what we like to think of as a Who Framed Roger Rabbitesque (or is that a “reverse Who Framed Roger Rabbitesque“) approach which happens, at least for us, when you overlay some more realistic media over a representation of that “realia” with the same scale) if you’ll pardon any “jargon clash” here?!
Recently we stumbled across the intriguing CSS property clip-path and set ourselves a one day thinking time to see whether we could make use of this CSS feature.
an intermittent (because the highlighting used can meddle with the original colour coding reasoning) highlighting …
<?php echo ”
<body onkeydown=\"return okd(event);\" style=\"width:600px;height:600px;\" onclick=\" if (oneoftwo == 0) { document.getElementById('lastcol').value=''; isclear=false; document.getElementById('imode').value='click'; filloutform(event,1); } else if (Math.abs(oneoftwo) == 1) { getxynow(event); if (oneoftwo < 0) { oneoftwo--; } else { oneoftwo++; } } else if (Math.abs(oneoftwo) == 2) { getxynow(event); overlayit(0); }\" onload=\" setTimeout(thisonl,2000); if (window.opener) { document.getElementById('premyp').innerHTML=lfdfn(window.opener.document.getElementById('myp').outerHTML); document.getElementById('patparent').value=window.opener.document.getElementById('myp').innerHTML; document.getElementById('mopatparent').value=window.opener.document.getElementById('myp').innerHTML; } else if (window.parent) { document.getElementById('premyp').innerHTML=lfdfn(parent.document.getElementById('myp').outerHTML); document.getElementById('patparent').value=parent.document.getElementById('myp').innerHTML; document.getElementById('mopatparent').value=parent.document.getElementById('myp').innerHTML; } \">
“; ?>
… and …
<?php echo ”
<button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); defzoom=1; ' style=background-color:yellow; id=twoc onclick='event.stopPropagation(); dotwoc();'>Circle of Interest via Next 2 Clicks</button><br><br> <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); defzoom=1; ' style=background-color:magenta; id=twoc onclick='event.stopPropagation(); dotwor();'>Rectangle via 2 Clicks</button>
“; ?>
… of Image Chart Map Chart image (ie. img) element “area of interest” (for which we’ve coded for “circle” and “polygon” rectangle, so far) …
coupled with “zoom on hover” …
<?php echo ”
var oneoftwo=0, xinxy=[], yinxy=[], opis='1.0', ovnum=1, defzoom=2;
We wanted to improve the internationalization credentials of our Region Picker web application, of recent times, adding to the progress of yesterday’s Region Picker Revealed Iframes Tutorial. As such, we turn to another great Google product called Google Translate to translate …
heading text and some button text … and …
country names
… this Region Picker being a suitable candidate for a “whole of webpage” Google Translation for a URL such as (this Dutch translation version below) …
… or use the language dropdown to the right below …
Yes, we wrote a regions_via_countries.htm version of our Region Picker especially for the occasion, because there are nuances among innerHTML and innerText of elements, that need to be considered, while the changedlatest draftRegion Picker gets given a new “languages” dropdown element that hangs around long enough to translate from English, via Google Translate, should the user wish to do so. Once there in another language, alas, some of the Geographics based inhouse menu options cannot be achieved.
… we reduce the dependency we have, in the Region Picker web application, on the use of popup windows. For this we funnelled a lot of the “window.open” calls within the purview of the rjmprogramming.com.au domain through the Javascript “wrapper style of function” …
var gltrans=''; // contains first lowercase letter entered by user at a Javascript prompt inhouse menu answer
Regular readers will know that we are keen on emojis …
regarding their way to attract attention
internationalization assistance
text (content) that is (like a) graphic (display)
… for we “graphically challenged”, shall we say? We think our Region Picker from yesterday’s Region Picker Geo Chart Image Chart GeoJson Tutorial could do with a little “emoji flag” help. Yes, every country with an ISO-3166 two character code associated with it, can have an associated emoji flag via a Javascript function like …
function orflag(thiscc) {
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 ccsuff='', ccchar=' ', cde='';
for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
ccsuff+=String.fromCodePoint(dri[eval('' + lri.indexOf(ccchar))]); //'' + dri[eval('' + lri.indexOf(ccchar))] + ';';
cde='.';
}
return ccsuff;
}
It might have been the recent work with our “rectangle of letter hashtag navigation breadcrumb emojis” in yesterday’s Region Picker Geo Chart Image Chart GeoJson Tutorial that spurred us on, because the keen observer can look at the code above, and if they are “number orientated” they’ll tee up those “1274xx” numbers with ones below. Can you believe that these Regional Indicators have a dual purpose for us now …
singly they are helping with the breadcrumbs
two together in the form of a country ISO-3166 two character code and they (we kind of think, miraculously) turn into the national flag (emoji) for that country
? And mixing these up into the content mix, we do not have to be quite so sheepish about all the English assumptions in the changedlatest draftRegion Picker.
Also, we think, it is clarifying the “dropdown” element in the Region Picker, contextualizing the right hand side as the “business end” of proceedings, which can have an “independent life” from “the work in progress” status of what goes on in that dropdown element (which, on non-mobile, is far more “jittery” because it responds to the “onmouseover” events going on).
Did you know?
Personally, we know of some products set up before there were emojis, and requiring flags for their functionality. Sadly, they resorted to individual image files required for each country’s flag … these days with the “emoji flags” this amounts to being an awkward arrangement to maintain, and we Linux web server managers go bananas regarding such a waste of “inode numbers” … because, the last time we looked, “inode numbers” do not grow on trees!
Region Picker calls Image Chart add GeoJson interfacing smarts … and …
Region Picker calls Geo Chart add GeoJson interfacing smarts
… given the lead in work from a couple of days back.
Another realization occurred to us regarding the wait a user had when using the Region Picker and trying to (on a non-mobile platform) right click a country name link (to release “The Whole Shebang”). We realized that that “letter block” we used to create dynamically always had the same content, so why not make it some static HTML, as per …
… and contrary to what we often admire, “static content” serves us better than a “dynamic scenario”, with “right clicking” working much faster after the document.body onload event.
Am sure there are users out there uncomfortable with overlapping or clashing HTML. As a programmer, we recommend “some chill” when re-orienting the device can be possible, but if there is a way to avoid the issues in the first place, count us in as programmers interested in solutions. So we spent a day in amongst the pixels, with some nitty gritty, further to yesterday’s Region Picker Mobile User Experience Tutorial mobile platform user experience start, and …
turned the “breadcrumb” style ascii letter links into emoji links (and so “I” got the same width as “W”) … and …
even added line feeds to some “a” country name links to help out so that background image overlapping happens less often to their left … and …
added country name to rightmost “Image Chart Map Chart” button wording … and …
played around with tablet and phone platform background-position (of the country image chart) images …
if (window.self == window.parent && eval('' + screen.width) >= 800 || document.URL.indexOf('?right=') != -1) {
document.getElementById('tdleft').style.backgroundPosition='right top';
} else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//document.getElementById('tdleft').style.backgroundPosition='' + eval(0.4 * eval('' + screen.width)) + 'px ' + eval(-450 + eval('' + screen.height)) + 'px'; // used to be center top
document.getElementById('tdleft').style.backgroundPosition='200px 200px'; // used to be center top
} else {
document.getElementById('tdleft').style.backgroundPosition='center top'; // used to be center top
}
Continuing on with mobile platform concerns regarding yesterday’s Region Picker Mobile GeoJson Trip Leg Tutorial‘s work on the Region Picker web application, today we improve the user experience for mobile platform users by …
making the country text bigger and more noticeable as they load the webpage …
<style>
a.ulmenulink {
font-size: 28px; /* used to be 14px */
font-weight: bold;
/* color: orange; */por
background-image: linear-gradient(to right, lightblue 0%, rgb(255,255,127) 100%);
text-shadow:-1px 1px 1px #ff2d95;
margin-left: 50px;
}
<style>
adding left hand side alternative way to get to non-mobile right click “the whole shebang” logic …
<span id=todd title='Navigate to region list for last country selected' style='border:1px solid green;position:fixed;text-shadow:-1px 1px 1px #2dff95;font-size:20px;left:8px;top:80px;text-decoration:underline;cursor:pointer;z-index:3245;' onclick="if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && lastop != null) { thewholeshebang(lastop); } else if (document.getElementById('bremember')) { window.scrollTo(eval(-80 + eval(document.getElementById('bremember').getBoundingClientRect().left)), 0); } ">↗</span>
… making some elements receive a new CSS margin-left property to help out …
<style>
a.ulmenulink {
font-size: 28px;
font-weight: bold;
/* color: orange; */
background-image: linear-gradient(to right, lightblue 0%, rgb(255,255,127) 100%);
text-shadow:-1px 1px 1px #ff2d95;
margin-left: 50px;
}
bunching up the single letter links into a rectangle of links which do not overlay to the left (and as such do not interfere with any country links) …
var nexttodo='A', nextih=' ', ournext='';
var orignextih=nextih;
var newih='';
//registers mouseenter to each element in xelms array
nextih+=orignextih;
nextih+=orignextih;
newih=nextih;
for(var xi=0; xi<xelms.length; xi++){
if (eval(('' + xelms[xi].id).length) == 3) {
if (('' + xelms[xi].innerHTML).substring(0).substring(0,1) >= nexttodo) {
ournext=('' + xelms[xi].innerHTML).substring(0).substring(0,1)
//alert('nexttodo=' + nexttodo + ' andpleasedonotbeequalveryoften ournext=' + ournext + ' and ' + xelms[xi].id);
while (nexttodo < ournext) {
nextih+=' <a style=color:blue;z-index:786; href="#' + xelms[xi].id + '">' + nexttodo + '</a>';
nexttodo=String.fromCharCode(1 + nexttodo.charCodeAt(0));
//alert('Nexttodo=' + nexttodo + ' and ournext=' + ournext + ' and ' + xelms[xi].id);
}
if (nexttodo <= 'Z') {
nextih+=' <a style=color:blue;z-index:786; href="#' + xelms[xi].id + '">' + nexttodo + '</a>';
nexttodo=String.fromCharCode(1 + nexttodo.charCodeAt(0));
}
} //else {
//alert('no for nexttodo=' + nexttodo + ' and ournext=' + ournext + ' and ' + xelms[xi].id);
//}
}
// more code follows
} // end for
if (nextih != '') {
nextih=nextih.replace('>F', '>F' + ' ' + newih);
nextih=nextih.replace('>J', '>J' + ' ' + newih);
nextih=nextih.replace('>O', '>O' + ' ' + newih);
nextih=nextih.replace('>T', '>T' + ' ' + newih);
improving the “highlight all dropdown options” code …
function selall() { // thanks to https://stackoverflow.com/questions/55486020/how-to-set-values-of-multiple-select-using-javascript
const selecte = document.getElementsByTagName('select')[0];
const selectValues = [''];
var soh=selecte.innerHTML;
var wassoh=soh;
var its='', jits=0;
/* Iterate options of select element */
for (const optionx of document.querySelectorAll('#' + selecte.id + ' option')) {
/* Parse value to integer */
const valuex = Number.parseInt(optionx.value);
/* If option value contained in values, set selected attribute */
if (selectValues.indexOf(valuex) !== -1 || 1 == 1) {
optionx.setAttribute('selected', 'selected');
if (soh.indexOf('">' + optionx.innerText + '<') != -1) {
soh=soh.replace('">' + optionx.innerText + '<', '" selected>' + optionx.innerText + '<');
} else {
its=optionx.innerText;
for (jits=eval(-1 + eval('' + optionx.innerText.length)); jits>=2; jits--) {
if (its != '' && soh.indexOf('">' + optionx.innerText.substring(0,jits)) != -1) {
soh=soh.replace('">' + optionx.innerText.substring(0,jits), '" selected>' + optionx.innerText.substring(0,jits));
its='';
}
}
}
}
/* Otherwise ensure no selected attribute on option */
else {
optionx.removeAttribute('selected');
}
}
add some background colour to any dropdown to help highlight its importance once country is decided upon …
<style>
select {
font-size: 7px;
font-weight: bold;
padding: 2 2 2 2;
min-height: 90%;
overflow-y: scroll;
overflow-y: hidden;
background-color: pink;
}
<style>
rule out the use of a meta name=”viewport” tag as being any help
The last couple of “right click leaning” days may have been annoying for mobile users of our Region Picker out there. And so, onto yesterday’s Region Picker GeoJson Trip Leg Right Click Tutorial we’re starting the …
mobile platform turnaround … recognising …
on mobile platforms zooming will be via a spread gesture rather than a zoom button click …
on mobile platforms the previous non-mobile right click logics will have to be replaced by other event logic (today being more “ondblclick” logic) as required …
on mobile platforms we do not want to re-navigate to the GeoJson iframe content, and so we use the iframe URL and add hashtag navigation helpers …
var locationhash='';
function lhit(inh) {
locationhash=inh;
ifcheck(document.getElementById('ifcountries'));
return inh;
}
function menuize(rans) {
var rdescis=lastplace;
var latdeg=-999, longdeg=-999;
if (gextras.indexOf(' (') != -1) {
if (gextras.split('t to (')[1].split(')')[0].indexOf(',') != -1) {
latdeg=eval('' + gextras.split('t to (')[1].split(')')[0].split(',')[0]);
longdeg=eval('' + gextras.split('t to (')[1].split(')')[0].split(',')[1]);
}
} else if (storedsuffs.indexOf('~' + lpw(lastplace) + '`') != -1 && storedsuffs.indexOf('~' + lpw(lastplace) + '`@') == -1) {
gextras=storedsuffs.split('~' + lpw(lastplace) + '`')[1].split('@')[0];
if (gextras.split(' (')[1].split(')')[0].indexOf(',') != -1) {
latdeg=eval('' + gextras.split(' (')[1].split(')')[0].split(',')[0]);
longdeg=eval('' + gextras.split(' (')[1].split(')')[0].split(',')[1]);
}
}
Region Picker GeoJson Trip Leg Right Click Tutorial
Regular readers know that we enjoy event-driven programming. And we really enjoy scenarios where a whole layer of new functionality is possible via an event design initiative, and today we have a …
right click
… or …
oncontextmenu
… event gala (minus any “h” appendix, thank you very much) for you.
It’s very rare that when you rely on a generic representation of a large entity with a single entity you will satisfy all users. And so, as far as yesterday’s …
Region Picker region representative geographical “marker” placement
… where the large entity is a whole country or region and the single entity is somewhere inside that, allowing for that is a start, but will only satisfy some users. But what if, along the way, with our …
GeoJson world map …
image map …
area subelement scouring … we could start adding to the relevant ones a whole …
within any programmatically shaded country area (and underlying div and SVG) elements representing the chosen country of interest from the Region Picker parent, and where the user chooses rather than where it is chosen for them
? And don't you find interesting with all this additional functionality, we've not touched the GeoJson World Map web application (being hosted in the Regional Picker iframe all this time), at all?! We also enjoy not needing to change every component, when trying to achieve new functionality.
And while we're into "and", it passes notice, especially with this work, how this is only a straightforward approach because of the good old Mercator projection used here, that many primary school kids get familiar with regarding wall maps. A pixel is worth a Mercator projection degree, when "unzoomed", and that the top left corner is 90 degrees latitude and -180 longitude. The implication is that areas near the poles are vastly bigger looking than they are (regarding surface area) in reality. Many other projections would involve quite complex mathematics. Phewwww!
Today, further to yesterday's Region Picker GeoJson Trip Leg Tutorial, we worried a lot about the "zoom" button 🔍. We encourage users who use the "J" inhouse menu option with "Yes Trip Planning" to click the "zoom" button as many times as they need to before any Trip Legs are defined via right click actions (within shaded countries). You can involve multiple countries, too, where "marker" inhouse options are presented.
We also allowed for Trip Leg visibility toggling (after the event) via double click, on a leg, functionality in the changedlatest draftRegion Picker
Nice legs! Regarding the trips, of course. Trip planning? GeoJson? Region Picker?
Yes, yesterday's Region Picker GeoJson Trip Planning Tutorial's progress had us starting to allow for a Trip Planner subset of functionality for our Google Image Chart Map Chart interfacing Region Picker. Our first job to do moving forward is to allow between ...
Region Picker region representative geographical "marker" placements on the ...
be able to be right clicked to flag sets of two such right clicks defining endpoints for a Trip "Leg" drawn as a straight line with huge thanks to ...
<style>
.crossedtotl { // thanks to https://stackoverflow.com/questions/18012420/draw-diagonal-lines-in-div-background-with-css
background:
linear-gradient(to top left,
rgba(0,0,0,0) 0%,
rgba(0,0,0,0) calc(50% - 0.8px),
rgba(0,0,0,1) 50%,
rgba(0,0,0,0) calc(50% + 0.8px),
rgba(0,0,0,0) 100%);
}
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
Region Picker GeoChart Region Wikipedia Representations Tutorial
We’re starting down the long and windy road, further to the recent Region Picker GeoJson Area of Interest Tutorial, of providing “workaround Google Chart Geo Chart solutions to semi-cover the loss (because nothing will be quite as good, as far as we are concerned, alas) of Google Chart Image Chart Map Chart” in our lives (please pass the tissues … fisst). In our case, the Region Picker intervention point (believe it or not) is our …
WordPress Blog 404.php (missing webpage page) logic we’ve tailored for all manner of image production purposes helping out …
… logic we get the great help from Wikipedia to make up for …
lack of boundary regional definition on a Google Chart Geo Chart marker map … with …
Wikipedia’s representative region positioning, thanks, we can present as the …
region name … toggleable backwards and forwards to …
region marker
… on the Google Chart Geo Chart marker map now displayed to the user instead of what used to be a Google Chart Image Chart Map Chart regional boundary map … (please pass the tissues … fisst).
There is no doubt we’ll be tweaking away at all this, trying to improve the integrations for both user experience (including speed) and aesthetic means. Please pack a sandwich (or 3) and a toothbrush … and toothpaste … and vegemite … and fisst, the tissues.
Meanwhile, back in “Region Picker Land” where, if we’re not mistaken, the grapes are peculiarly sweet this season, and we needed their “fortification” to tackle today’s progress, that being …
user has picked a country of interest and has gone “The Whole Shebang” resulting in those …
tutti-frutti region links below the Image Chart (rightmost) button …
one of which the user clicks/touches … resulting in …
presentation of inhouse menu prompt window … where …
option “J” (for GeoJson World Map option) is presented (because a relevant latitude and longitude were found) … and “lo and behold” …
user types in J …
user does not click Cancel at the next prompt window … ready for it …
as of today two new buttons appear …
Mobile
Non-mobile
… to the right of the subheading … and while we’re there see how the innards …
Mobile
Non-mobile
<button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:yellow; id=twoc onclick=’event.stopPropagation(); parent.dotwoc();’>Circle of Interest via Next 2 Double Clicks</button> <button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:magenta; id=twoc onclick=’event.stopPropagation(); parent.dotwor();’>Rectangle via 2 Double Clicks</button>
<button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:yellow; id=twoc onclick=’event.stopPropagation(); parent.dotwoc();’>Circle of Interest via Next 2 Right Clicks</button> <button title=’One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom’ oncontextmenu=’ event.stopPropagation(); parent.setdefzoom(1); ‘ style=background-color:magenta; id=twoc onclick=’event.stopPropagation(); parent.dotwor();’>Rectangle via 2 Right Clicks</button>
… are very OOP by nature (as is all DOM work in Javascript, when you think about it), allowing us to remain with the iframe initial content supervisor unchanged in code, and just referring back to the parent’s Javascript for anything new either via …
means of the iframe onload event
means of referring back to parent operations via references like …
parent.setdefzoom(1); // which is setting the variable "defzoom", back in the parent, to 1
… in this new Javascript …
var oneoftwo=0, xinxy=[], yinxy=[], opis='1.0', ovnum=1, defzoom=2, nextv='hidden';
var zaconto=null; // this is populated at the iframe element's onload event function
… type call) event function (non-mobile one semi-shown below) …
function nonmifcheck(ziois) { // non-mobile iframe onload event function
var waszoom=1;
var sparear=null, gsparear=null;
var xif=-999, yif=-999, xxif=-999, yyif=-999;
zaconto = (ziois.contentWindow || ziois.contentDocument);
if (zaconto.document) { zaconto = zaconto.document; }
// ...
// used later into the function, as well as in that new Javascript above, everywhere ...
//
zaconto.getElementsByTagName('table')[0].style.top='385px';
zaconto.getElementsByTagName('table')[0].style.left='0px';
if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
zaconto.getElementsByTagName('h3')[0].style.marginTop='6px';
zaconto.getElementsByTagName('h3')[0].innerHTML+=" <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:yellow; id=twoc onclick='event.stopPropagation(); parent.dotwoc();'>Circle of Interest via Next 2 Right Clicks</button> <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:magenta; id=twoc onclick='event.stopPropagation(); parent.dotwor();'>Rectangle via 2 Right Clicks</button><div id=imgmore></div><div id=dvstyle>";
zaconto.body.oncontextmenu=function(event){ if (parent.getoneoftwo() == 0) { event=event; } else if (Math.abs(parent.getoneoftwo()) == 1) { event.stopPropagation(); parent.getxynow(event); if (parent.getoneoftwo() < 0) { parent.setoneoftwo(eval(-1 + eval('' + parent.getoneoftwo()))); } else { parent.setoneoftwo(eval(1 + eval('' + parent.getoneoftwo()))); } } else if (Math.abs(parent.getoneoftwo()) == 2) { event.stopPropagation(); parent.getxynow(event); if (1 == 3) { parent.overlayit(0); } } };
} else {
zaconto.getElementsByTagName('h3')[0].innerHTML+=" <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:yellow; id=twoc onclick='event.stopPropagation(); parent.dotwoc();'>Circle of Interest via Next 2 Double Clicks</button> <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); parent.setdefzoom(1); ' style=background-color:magenta; id=twoc onclick='event.stopPropagation(); parent.dotwor();'>Rectangle via 2 Double Clicks</button><div id=imgmore></div><div id=dvstyle>";
zaconto.body.ondblclick=function(event){ if (parent.getoneoftwo() == 0) { event=event; } else if (Math.abs(parent.getoneoftwo()) == 1) { event.stopPropagation(); parent.getxynow(event); if (parent.getoneoftwo() < 0) { parent.setoneoftwo(eval(-1 + eval('' + parent.getoneoftwo()))); } else { parent.setoneoftwo(eval(1 + eval('' + parent.getoneoftwo()))); } } else if (Math.abs(parent.getoneoftwo()) == 2) { event.stopPropagation(); parent.getxynow(event); if (1 == 3) { parent.overlayit(0); } } };
}
// ...
}
… and yet, elements are added to the “iframe child” (rather than to the parent document.body element) here … believe me … this, and using the Mercator Projection means of moving between “pixel land” and “latitude and longitude land”, is better!
which have the on hover blurb …
One click uses hover 2x zoom afterwards … more for larger zoom … right click for no zoom
… which is just to say that the more clicks in a row of the button, the more resultant zoom goes into an onmouseover “hover” over that intermittently shown “circle” or “polygon” rectangle clip-path affected image (ie. img) overlay element placed according to the 2x set of user right click sets (for non-mobile) or double click sets (for mobile) the user subsequently makes on the GeoJson world map above these new buttons
… that, if actioned by the user, ends up with an “augmented reality” (in what we like to think of as a Who Framed Roger Rabbitesque (or is that a “reverse Who Framed Roger Rabbitesque“) approach which happens, at least for us, when you overlay some more realistic media over a representation of that “realia” with the same scale) if you’ll pardon any “jargon clash” here?!
Recently we stumbled across the intriguing CSS property clip-path and set ourselves a one day thinking time to see whether we could make use of this CSS feature.
an intermittent (because the highlighting used can meddle with the original colour coding reasoning) highlighting …
<?php echo ”
<body onkeydown=\"return okd(event);\" style=\"width:600px;height:600px;\" onclick=\" if (oneoftwo == 0) { document.getElementById('lastcol').value=''; isclear=false; document.getElementById('imode').value='click'; filloutform(event,1); } else if (Math.abs(oneoftwo) == 1) { getxynow(event); if (oneoftwo < 0) { oneoftwo--; } else { oneoftwo++; } } else if (Math.abs(oneoftwo) == 2) { getxynow(event); overlayit(0); }\" onload=\" setTimeout(thisonl,2000); if (window.opener) { document.getElementById('premyp').innerHTML=lfdfn(window.opener.document.getElementById('myp').outerHTML); document.getElementById('patparent').value=window.opener.document.getElementById('myp').innerHTML; document.getElementById('mopatparent').value=window.opener.document.getElementById('myp').innerHTML; } else if (window.parent) { document.getElementById('premyp').innerHTML=lfdfn(parent.document.getElementById('myp').outerHTML); document.getElementById('patparent').value=parent.document.getElementById('myp').innerHTML; document.getElementById('mopatparent').value=parent.document.getElementById('myp').innerHTML; } \">
“; ?>
… and …
<?php echo ”
<button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); defzoom=1; ' style=background-color:yellow; id=twoc onclick='event.stopPropagation(); dotwoc();'>Circle of Interest via Next 2 Clicks</button><br><br> <button title='One click uses hover 2x zoom afterwards ... more for larger zoom ... right click for no zoom' oncontextmenu=' event.stopPropagation(); defzoom=1; ' style=background-color:magenta; id=twoc onclick='event.stopPropagation(); dotwor();'>Rectangle via 2 Clicks</button>
“; ?>
… of Image Chart Map Chart image (ie. img) element “area of interest” (for which we’ve coded for “circle” and “polygon” rectangle, so far) …
coupled with “zoom on hover” …
<?php echo ”
var oneoftwo=0, xinxy=[], yinxy=[], opis='1.0', ovnum=1, defzoom=2;
We wanted to improve the internationalization credentials of our Region Picker web application, of recent times, adding to the progress of yesterday’s Region Picker Revealed Iframes Tutorial. As such, we turn to another great Google product called Google Translate to translate …
heading text and some button text … and …
country names
… this Region Picker being a suitable candidate for a “whole of webpage” Google Translation for a URL such as (this Dutch translation version below) …
… or use the language dropdown to the right below …
Yes, we wrote a regions_via_countries.htm version of our Region Picker especially for the occasion, because there are nuances among innerHTML and innerText of elements, that need to be considered, while the changedlatest draftRegion Picker gets given a new “languages” dropdown element that hangs around long enough to translate from English, via Google Translate, should the user wish to do so. Once there in another language, alas, some of the Geographics based inhouse menu options cannot be achieved.
… we reduce the dependency we have, in the Region Picker web application, on the use of popup windows. For this we funnelled a lot of the “window.open” calls within the purview of the rjmprogramming.com.au domain through the Javascript “wrapper style of function” …
var gltrans=''; // contains first lowercase letter entered by user at a Javascript prompt inhouse menu answer
Regular readers will know that we are keen on emojis …
regarding their way to attract attention
internationalization assistance
text (content) that is (like a) graphic (display)
… for we “graphically challenged”, shall we say? We think our Region Picker from yesterday’s Region Picker Geo Chart Image Chart GeoJson Tutorial could do with a little “emoji flag” help. Yes, every country with an ISO-3166 two character code associated with it, can have an associated emoji flag via a Javascript function like …
function orflag(thiscc) {
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 ccsuff='', ccchar=' ', cde='';
for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
ccsuff+=String.fromCodePoint(dri[eval('' + lri.indexOf(ccchar))]); //'' + dri[eval('' + lri.indexOf(ccchar))] + ';';
cde='.';
}
return ccsuff;
}
It might have been the recent work with our “rectangle of letter hashtag navigation breadcrumb emojis” in yesterday’s Region Picker Geo Chart Image Chart GeoJson Tutorial that spurred us on, because the keen observer can look at the code above, and if they are “number orientated” they’ll tee up those “1274xx” numbers with ones below. Can you believe that these Regional Indicators have a dual purpose for us now …
singly they are helping with the breadcrumbs
two together in the form of a country ISO-3166 two character code and they (we kind of think, miraculously) turn into the national flag (emoji) for that country
? And mixing these up into the content mix, we do not have to be quite so sheepish about all the English assumptions in the changedlatest draftRegion Picker.
Also, we think, it is clarifying the “dropdown” element in the Region Picker, contextualizing the right hand side as the “business end” of proceedings, which can have an “independent life” from “the work in progress” status of what goes on in that dropdown element (which, on non-mobile, is far more “jittery” because it responds to the “onmouseover” events going on).
Did you know?
Personally, we know of some products set up before there were emojis, and requiring flags for their functionality. Sadly, they resorted to individual image files required for each country’s flag … these days with the “emoji flags” this amounts to being an awkward arrangement to maintain, and we Linux web server managers go bananas regarding such a waste of “inode numbers” … because, the last time we looked, “inode numbers” do not grow on trees!
Region Picker calls Image Chart add GeoJson interfacing smarts … and …
Region Picker calls Geo Chart add GeoJson interfacing smarts
… given the lead in work from a couple of days back.
Another realization occurred to us regarding the wait a user had when using the Region Picker and trying to (on a non-mobile platform) right click a country name link (to release “The Whole Shebang”). We realized that that “letter block” we used to create dynamically always had the same content, so why not make it some static HTML, as per …
… and contrary to what we often admire, “static content” serves us better than a “dynamic scenario”, with “right clicking” working much faster after the document.body onload event.
Am sure there are users out there uncomfortable with overlapping or clashing HTML. As a programmer, we recommend “some chill” when re-orienting the device can be possible, but if there is a way to avoid the issues in the first place, count us in as programmers interested in solutions. So we spent a day in amongst the pixels, with some nitty gritty, further to yesterday’s Region Picker Mobile User Experience Tutorial mobile platform user experience start, and …
turned the “breadcrumb” style ascii letter links into emoji links (and so “I” got the same width as “W”) … and …
even added line feeds to some “a” country name links to help out so that background image overlapping happens less often to their left … and …
added country name to rightmost “Image Chart Map Chart” button wording … and …
played around with tablet and phone platform background-position (of the country image chart) images …
if (window.self == window.parent && eval('' + screen.width) >= 800 || document.URL.indexOf('?right=') != -1) {
document.getElementById('tdleft').style.backgroundPosition='right top';
} else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//document.getElementById('tdleft').style.backgroundPosition='' + eval(0.4 * eval('' + screen.width)) + 'px ' + eval(-450 + eval('' + screen.height)) + 'px'; // used to be center top
document.getElementById('tdleft').style.backgroundPosition='200px 200px'; // used to be center top
} else {
document.getElementById('tdleft').style.backgroundPosition='center top'; // used to be center top
}
Continuing on with mobile platform concerns regarding yesterday’s Region Picker Mobile GeoJson Trip Leg Tutorial‘s work on the Region Picker web application, today we improve the user experience for mobile platform users by …
making the country text bigger and more noticeable as they load the webpage …
<style>
a.ulmenulink {
font-size: 28px; /* used to be 14px */
font-weight: bold;
/* color: orange; */por
background-image: linear-gradient(to right, lightblue 0%, rgb(255,255,127) 100%);
text-shadow:-1px 1px 1px #ff2d95;
margin-left: 50px;
}
<style>
adding left hand side alternative way to get to non-mobile right click “the whole shebang” logic …
<span id=todd title='Navigate to region list for last country selected' style='border:1px solid green;position:fixed;text-shadow:-1px 1px 1px #2dff95;font-size:20px;left:8px;top:80px;text-decoration:underline;cursor:pointer;z-index:3245;' onclick="if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && lastop != null) { thewholeshebang(lastop); } else if (document.getElementById('bremember')) { window.scrollTo(eval(-80 + eval(document.getElementById('bremember').getBoundingClientRect().left)), 0); } ">↗</span>
… making some elements receive a new CSS margin-left property to help out …
<style>
a.ulmenulink {
font-size: 28px;
font-weight: bold;
/* color: orange; */
background-image: linear-gradient(to right, lightblue 0%, rgb(255,255,127) 100%);
text-shadow:-1px 1px 1px #ff2d95;
margin-left: 50px;
}
bunching up the single letter links into a rectangle of links which do not overlay to the left (and as such do not interfere with any country links) …
var nexttodo='A', nextih=' ', ournext='';
var orignextih=nextih;
var newih='';
//registers mouseenter to each element in xelms array
nextih+=orignextih;
nextih+=orignextih;
newih=nextih;
for(var xi=0; xi<xelms.length; xi++){
if (eval(('' + xelms[xi].id).length) == 3) {
if (('' + xelms[xi].innerHTML).substring(0).substring(0,1) >= nexttodo) {
ournext=('' + xelms[xi].innerHTML).substring(0).substring(0,1)
//alert('nexttodo=' + nexttodo + ' andpleasedonotbeequalveryoften ournext=' + ournext + ' and ' + xelms[xi].id);
while (nexttodo < ournext) {
nextih+=' <a style=color:blue;z-index:786; href="#' + xelms[xi].id + '">' + nexttodo + '</a>';
nexttodo=String.fromCharCode(1 + nexttodo.charCodeAt(0));
//alert('Nexttodo=' + nexttodo + ' and ournext=' + ournext + ' and ' + xelms[xi].id);
}
if (nexttodo <= 'Z') {
nextih+=' <a style=color:blue;z-index:786; href="#' + xelms[xi].id + '">' + nexttodo + '</a>';
nexttodo=String.fromCharCode(1 + nexttodo.charCodeAt(0));
}
} //else {
//alert('no for nexttodo=' + nexttodo + ' and ournext=' + ournext + ' and ' + xelms[xi].id);
//}
}
// more code follows
} // end for
if (nextih != '') {
nextih=nextih.replace('>F', '>F' + ' ' + newih);
nextih=nextih.replace('>J', '>J' + ' ' + newih);
nextih=nextih.replace('>O', '>O' + ' ' + newih);
nextih=nextih.replace('>T', '>T' + ' ' + newih);
improving the “highlight all dropdown options” code …
function selall() { // thanks to https://stackoverflow.com/questions/55486020/how-to-set-values-of-multiple-select-using-javascript
const selecte = document.getElementsByTagName('select')[0];
const selectValues = [''];
var soh=selecte.innerHTML;
var wassoh=soh;
var its='', jits=0;
/* Iterate options of select element */
for (const optionx of document.querySelectorAll('#' + selecte.id + ' option')) {
/* Parse value to integer */
const valuex = Number.parseInt(optionx.value);
/* If option value contained in values, set selected attribute */
if (selectValues.indexOf(valuex) !== -1 || 1 == 1) {
optionx.setAttribute('selected', 'selected');
if (soh.indexOf('">' + optionx.innerText + '<') != -1) {
soh=soh.replace('">' + optionx.innerText + '<', '" selected>' + optionx.innerText + '<');
} else {
its=optionx.innerText;
for (jits=eval(-1 + eval('' + optionx.innerText.length)); jits>=2; jits--) {
if (its != '' && soh.indexOf('">' + optionx.innerText.substring(0,jits)) != -1) {
soh=soh.replace('">' + optionx.innerText.substring(0,jits), '" selected>' + optionx.innerText.substring(0,jits));
its='';
}
}
}
}
/* Otherwise ensure no selected attribute on option */
else {
optionx.removeAttribute('selected');
}
}
add some background colour to any dropdown to help highlight its importance once country is decided upon …
<style>
select {
font-size: 7px;
font-weight: bold;
padding: 2 2 2 2;
min-height: 90%;
overflow-y: scroll;
overflow-y: hidden;
background-color: pink;
}
<style>
rule out the use of a meta name=”viewport” tag as being any help
The last couple of “right click leaning” days may have been annoying for mobile users of our Region Picker out there. And so, onto yesterday’s Region Picker GeoJson Trip Leg Right Click Tutorial we’re starting the …
mobile platform turnaround … recognising …
on mobile platforms zooming will be via a spread gesture rather than a zoom button click …
on mobile platforms the previous non-mobile right click logics will have to be replaced by other event logic (today being more “ondblclick” logic) as required …
on mobile platforms we do not want to re-navigate to the GeoJson iframe content, and so we use the iframe URL and add hashtag navigation helpers …
var locationhash='';
function lhit(inh) {
locationhash=inh;
ifcheck(document.getElementById('ifcountries'));
return inh;
}
function menuize(rans) {
var rdescis=lastplace;
var latdeg=-999, longdeg=-999;
if (gextras.indexOf(' (') != -1) {
if (gextras.split('t to (')[1].split(')')[0].indexOf(',') != -1) {
latdeg=eval('' + gextras.split('t to (')[1].split(')')[0].split(',')[0]);
longdeg=eval('' + gextras.split('t to (')[1].split(')')[0].split(',')[1]);
}
} else if (storedsuffs.indexOf('~' + lpw(lastplace) + '`') != -1 && storedsuffs.indexOf('~' + lpw(lastplace) + '`@') == -1) {
gextras=storedsuffs.split('~' + lpw(lastplace) + '`')[1].split('@')[0];
if (gextras.split(' (')[1].split(')')[0].indexOf(',') != -1) {
latdeg=eval('' + gextras.split(' (')[1].split(')')[0].split(',')[0]);
longdeg=eval('' + gextras.split(' (')[1].split(')')[0].split(',')[1]);
}
}
Region Picker GeoJson Trip Leg Right Click Tutorial
Regular readers know that we enjoy event-driven programming. And we really enjoy scenarios where a whole layer of new functionality is possible via an event design initiative, and today we have a …
right click
… or …
oncontextmenu
… event gala (minus any “h” appendix, thank you very much) for you.
It’s very rare that when you rely on a generic representation of a large entity with a single entity you will satisfy all users. And so, as far as yesterday’s …
Region Picker region representative geographical “marker” placement
… where the large entity is a whole country or region and the single entity is somewhere inside that, allowing for that is a start, but will only satisfy some users. But what if, along the way, with our …
GeoJson world map …
image map …
area subelement scouring … we could start adding to the relevant ones a whole …
within any programmatically shaded country area (and underlying div and SVG) elements representing the chosen country of interest from the Region Picker parent, and where the user chooses rather than where it is chosen for them
? And don't you find interesting with all this additional functionality, we've not touched the GeoJson World Map web application (being hosted in the Regional Picker iframe all this time), at all?! We also enjoy not needing to change every component, when trying to achieve new functionality.
And while we're into "and", it passes notice, especially with this work, how this is only a straightforward approach because of the good old Mercator projection used here, that many primary school kids get familiar with regarding wall maps. A pixel is worth a Mercator projection degree, when "unzoomed", and that the top left corner is 90 degrees latitude and -180 longitude. The implication is that areas near the poles are vastly bigger looking than they are (regarding surface area) in reality. Many other projections would involve quite complex mathematics. Phewwww!
Today, further to yesterday's Region Picker GeoJson Trip Leg Tutorial, we worried a lot about the "zoom" button 🔍. We encourage users who use the "J" inhouse menu option with "Yes Trip Planning" to click the "zoom" button as many times as they need to before any Trip Legs are defined via right click actions (within shaded countries). You can involve multiple countries, too, where "marker" inhouse options are presented.
We also allowed for Trip Leg visibility toggling (after the event) via double click, on a leg, functionality in the changedlatest draftRegion Picker
Nice legs! Regarding the trips, of course. Trip planning? GeoJson? Region Picker?
Yes, yesterday's Region Picker GeoJson Trip Planning Tutorial's progress had us starting to allow for a Trip Planner subset of functionality for our Google Image Chart Map Chart interfacing Region Picker. Our first job to do moving forward is to allow between ...
Region Picker region representative geographical "marker" placements on the ...
be able to be right clicked to flag sets of two such right clicks defining endpoints for a Trip "Leg" drawn as a straight line with huge thanks to ...
<style>
.crossedtotl { // thanks to https://stackoverflow.com/questions/18012420/draw-diagonal-lines-in-div-background-with-css
background:
linear-gradient(to top left,
rgba(0,0,0,0) 0%,
rgba(0,0,0,0) calc(50% - 0.8px),
rgba(0,0,0,1) 50%,
rgba(0,0,0,0) calc(50% + 0.8px),
rgba(0,0,0,0) 100%);
}
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
… with no backslashes needed to achieve the same result. This is a simple example, but please see a Javascript function reworked from that within the recent Form or Prompt Output Tagged Template Literal Tutorial blog posting thread.
Here’s the HTML and Javascript behind the iframe content below …
<html><head><script type=text/javascript>
var millis=7656757543;
var strings=[''], rest=';'
function myTag(strings, beingExp, ageExp, secondageExp, breedExp, streetExp, suburbExp, stateExp) {
let str0 = '';
let str1 = '';
let str2 = '';
let str3 = '';
let str4 = '';
let str5 = '';
let str6 = '';
let str7 = '';
let ageStr;
if (ageExp > 99){
ageStr = 'centenarian';
} else {
ageStr = 'youngster';
}
// We can even return a string built using a template literal
return `${str0}${beingExp}${str1}${ageExp}${str2}${secondageExp}${str3}${breedExp}${str4}${streetExp}${str5}${suburbExp}${str6}${stateExp}${str7}` + rest;
}
if (document.URL.indexOf('?') != -1) {
alert(myTag(["one'str",2,3,4], "two'str", "III", "iv", 'seven"str', "six'str", "VII", "viii"));
alert(`seconds elapsed = ${Math.floor(millis / 1000)}`);
} else {
console.log(myTag(["one'str",2,3,4], "two'str", "III", "iv", 'seven"str', "six'str", "VII", "viii"));
console.log(`seconds elapsed = ${Math.floor(millis / 1000)}`);
}
</script></head><body><a style=text-decoration:underline; onclick='location.href=document.URL + String.fromCharCode(63);''=>Click to show backtick calculations to two alert popups</a></body></html>
A more advanced form of template literals are tagged templates.
Tags allow you to parse template literals with a function. The first argument of a tag function contains an array of string values. The remaining arguments are related to the expressions.
The tag function can then perform whatever operations on these arguments you wish, and return the manipulated string. (Alternatively, it can return something completely different, as described in one of the following examples.)
… we’ve adapted into an HTML and Javascript tagged_template_literal.html codebase proof of concept web application closely using the start the webpages above started us with … thanks.
These “Tagged Template” logics helped us separate the chaff (small words magically handled via “Tagged Template” usage) from the wheat (form or prompt arguments formalized by our interactive input) in the English sentence … such as (today’s default) …
That Nala is a wonderful 9 year ( 81 in K9 years ) old Golden Retriever who lives at 33 Charles Street, Lawson, State of Wow.
… we produce as a result of all the efforts, here.
<html>
<head>
<title>Tagged Template Literals - RJM Programming - July, 2022 ... thanks to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals</title>
<style> input { width: 20%; } </style>
</head>
<body>
<h2 title='A Tagged Template Literal regimen is dealing with all the little word stuff between the arguments.'>Tagged Template Literals</h2>
<h3>RJM Programming - July, 2022</h3>
<h3>Thanks to <a target=_blank title='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals' href='//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals'>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals</a></h3>
<p id=blurb></p>
<script type='text/javascript'>
const prompt = location.search.split('prompt=')[1] ? (one,two) => { return window.prompt(one,two); } : (one,two) => { return two; };
const alert = location.search.split('prompt=')[1] ? (one) => { document.getElementById('blurb').innerHTML=one; return one; } : (one) => { return window.alert(one); };
let being = location.search.split('being=')[1] ? prompt('Being', decodeURIComponent(location.search.split('being=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('Being', 'Nala');
let age = location.search.split('age=')[1] ? prompt('Age',decodeURIComponent(location.search.split('age=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('Age','9');
let breed = location.search.split('breed=')[1] ? prompt('Breed',decodeURIComponent(location.search.split('breed=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('Breed','Golden Retriever');
let street = location.search.split('street=')[1] ? prompt('Street',decodeURIComponent(location.search.split('street=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('Street','33 Charles Street');
let suburb = location.search.split('suburb=')[1] ? prompt('Suburb',decodeURIComponent(location.search.split('suburb=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('Suburb','Lawson');
let state = location.search.split('state=')[1] ? prompt('State',decodeURIComponent(location.search.split('state=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('State','State of Wow');
let secondage = location.search.split('secondage=')[1] ? prompt('K9 Age', decodeURIComponent(location.search.split('secondage=')[1].split('&')[0]).replace(/\+/g,' ')) : prompt('K9 Age', '' + eval(eval('' + age) * 9));
let rest = location.search.split('rest=')[1] ? decodeURIComponent(location.search.split('rest=')[1].split('&')[0]) : '';
function checkis() {
var eis=document.getElementsByTagName('input');
for (var jis=0; jis<eis.length; jis++) {
if (eis[jis].value == '' && ('' + eis[jis].placeholder).indexOf('[') != -1) {
eis[jis].value=eis[jis].placeholder.split(String.fromCharCode(91))[1].split(String.fromCharCode(93))[0];
}
}
}
function myTag(strings, beingExp, ageExp, secondageExp, breedExp, streetExp, suburbExp, stateExp) {
let str0 = '';
let str1 = '';
let str2 = '';
let str3 = '';
let str4 = '';
let str5 = '';
let str6 = '';
let str7 = '';
let ageStr;
if (ageExp > 99){
ageStr = 'centenarian';
} else {
ageStr = 'youngster';
}
// We can even return a string built using a template literal
return `${str0}${beingExp}${str1}${ageExp}${str2}${secondageExp}${str3}${breedExp}${str4}${streetExp}${str5}${suburbExp}${str6}${stateExp}${str7}` + rest;
}
let output = myTag`That ${ being } is a wonderful ${ age } year ( ${ secondage } in K9 years ) old ${ breed } who lives at ${ street }, ${ suburb }, ${ state }.`;
if (document.URL.indexOf('being=') != -1) {
alert(output);
// That Mike is a youngster.
}
Template literals are literals delimited with backtick (`) characters, allowing for multi-line strings, for string interpolation with embedded expressions, and for special constructs called tagged templates.
Template literals are sometimes informally called template strings, because they are used most commonly for string interpolation (to create strings by doing substitution of placeholders). However, a tagged template literal may not result in a string; it can be used with a custom tag function to perform whatever operations you want on the different parts of the template literal.
… we’ve adapted for use today in our very simple “Scrolling Logging” console_override.htmlweb application that scrolls like for a command line interactive terminal session …
<html>
<head>
<title>Console Message Override - RJM Programming - July, 2022</title>
<script type='text/javascript'>
var logElem=null;
var firstisnot=false;
var ii=0;
function onl() {
logElem=document.getElementById('log');
console.log = msg => logElem.innerHTML += (firstisnot ? '<span id=span' + ii + '></span>' + document.getElementById('topbit').innerHTML : '') + `${msg}<br>Brought to you via console.log at ` + new Date() + `<br><br>`;
console.error = msg => logElem.innerHTML += `<span class="error">${msg}<br>Brought to you via console.error at ` + new Date() + `</span><br><br>`;
console.warn = msg => logElem.innerHTML += `<span class="warn">${msg}<br>Brought to you via console.warn at ` + new Date() + `<span><br><br>`;
console.info = msg => logElem.innerHTML += `<span class="info">${msg}<br>Brought to you via console.info at ` + new Date() + `</span><br><br>`;