Today’s involvement of Google Charts into the result information sources, today, was “inhouse” by nature, with our interfacing PHP web applications to the Map Chart and Geo Chart sitting inside HTML iframe elements (ie. “inhouse”, with the rjmprogramming.com.au URL “src” attributes). So you’d think “plain sailing”, wouldn’t you, onto yesterday’s World Scrolling and Clickarounds Primer Tutorial?
But we found you had to be careful with the timing of display of an overlayed “toast” like div element when popup windows combine with “inhouse” iframe usage, those iframe elements shown within the overlayed div element.
You’ll probably “feel the angst” within the the changed new_world.htm “moving on” scroll around and clickaround web application to test your world geography, and calling on more great Google products.
See in the code the way the “confirm” method can be overridden …
const confirm = (cblurb) => {
if (cblurb == cblurb) {
if (toastform != '') {
document.getElementById('custom-alert-1').style.width='40%';
document.getElementById('custom-alert-1').innerHTML=cblurb + "<br><br>" + toastform;
toastform='';
} else {
document.getElementById('custom-alert-1').innerHTML=document.getElementById('custom-alert-1').innerHTML.replace(document.getElementById('custom-alert-1').innerHTML.split('<br')[0], cblurb);
}
document.getElementById('custom-alert-1').style.visibility='visible';
document.getElementById('custom-alert-1').style.display='block';
if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('mysearch').focus();
}
return false;
}
return window.confirm(cblurb);
};
… to swap yesterday’s kludgy window.confirm interactive methodology with new overlay div form like arrangements.
Previous relevant World Scrolling and Clickarounds Primer Tutorial is shown below.
We found the previous World Clickarounds Stationery Positioned Annotations Tutorial idea pretty simple, but interesting, it being, to us …
- present a map …
- user clicks around the map and receives information
… and, today, the nuance goes …
- present a map a lot bigger than the screen …
- user can scroll around and clicks around the map and receives information
For this, we needed a really interesting Mercator projection (for ease of calculation) map image of the world, and found an excellent one at Natural Earth Data … thanks. We use this image as a simple position:absolute HTML img element, in conjunction with some client side Javascript code …
<script type=text/javascript>
var pos3=0.0, pos4=0.0;
var toplat=90.0, toplong=-180.0;
var bottomlat=-90.0, bottomlong=180.0;
var width=0.0, height=0.0;
var thislat=0.0, thislong=0.0;
var rect=null;
function onl() {
width=document.getElementById('world').width;
height=document.getElementById('world').height;
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//height=Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
//width=Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
//width=eval(('' + document.getElementById('world').style.width).replace('px',''));
//height=eval(('' + document.getElementById('world').style.height).replace('px',''));
rect=document.getElementById('world').getBoundingClientRect();
width=rect.width;
height=rect.height;
}
window.scrollTo(eval(width / 2.0), eval(height / 4.0));
}
function xycursorlook(e) {
e = e || window.event;
e.preventDefault();
rect=document.getElementById('world').getBoundingClientRect();
width=rect.width;
height=rect.height;
if (e.touches) {
if (e.touches[0].pageX) {
pos3 = e.touches[0].pageX;
pos4 = e.touches[0].pageY;
pos4-=eval('' + rect.top);
pos3-=eval('' + rect.left);
} else if (e.touches[0].screenX) {
pos3 = e.touches[0].screenX;
pos4 = e.touches[0].screenY;
} else {
pos3 = e.touches[0].clientX;
pos4 = e.touches[0].clientY;
pos4-=eval('' + rect.top);
pos3-=eval('' + rect.left);
}
//alert('height:' + height + ' ' + window.scrollY + ' top:' + rect.y + ' vs ' + rect.top + ' ' + pos4 + 'vs' + e.touches[0].clientY + 'vs' + e.touches[0].screenY + ' left:' + rect.x + ' vs ' + rect.left + ' ' + pos3 + ' You are at (longitude: ' + eval(eval((pos3 / width) * 360.0) + toplong) + ' degrees, latitude: ' + eval(toplat - eval(eval((pos4 / height) * 180.0))) + ' degrees)');
//console.log('pos3=' + pos3 + ',pos4=' + pos4);
} else if (e.clientX || e.clientY) {
pos3 = e.clientX;
pos4 = e.clientY;
pos4-=eval('' + rect.top);
pos3-=eval('' + rect.left);
//alert('HeighT:' + height + ' ' + window.scrollY + ' top:' + rect.y + ' vs ' + rect.top + ' ' + pos4 + 'vs' + e.screenY + ' left:' + rect.x + ' vs ' + rect.left + ' ' + pos3 + ' You are at (longitude: ' + eval(eval((pos3 / width) * 360.0) + toplong) + ' degrees, latitude: ' + eval(toplat - eval(eval((pos4 / height) * 180.0))) + ' degrees)');
} else if (e.screenX || e.screenY) {
pos3 = e.screenX;
pos4 = e.screenY;
//alert('Height:' + height + ' ' + window.scrollY + ' top:' + rect.y + ' vs ' + rect.top + ' ' + pos4 + 'vs' + e.screenY + ' left:' + rect.x + ' vs ' + rect.left + ' ' + pos3 + ' You are at (longitude: ' + eval(eval((pos3 / width) * 360.0) + toplong) + ' degrees, latitude: ' + eval(toplat - eval(eval((pos4 / height) * 180.0))) + ' degrees)');
} else {
pos3 = e.pageX;
pos4 = e.pageY;
pos4-=eval('' + rect.top);
pos3-=eval('' + rect.left);
}
//console.log(rect);
//pos4-=eval('' + rect.top);
//pos3-=eval('' + rect.left);
var huh=confirm('You are near (longitude: ' + eval(eval((pos3 / width) * 360.0) + toplong) + ' degrees, latitude: ' + eval(toplat - eval(eval((pos4 / height) * 180.0))) + ' degrees). Want more information?');
if (huh) {
//alert('https://www.google.com/maps/@' + ('+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + (',+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + ',15z');
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//window.open('https://www.google.com/maps/@' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + ',6z', '_blank', 'top=100,left=0,height=700,width=700');
window.open('https://maps.google.com/?q=' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + '&ll=' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + '&z=6', '_blank', 'top=100,left=0,height=700,width=700');
window.open('https://earth.google.com/web/@' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + ',328.51120179a,63169669.71505167d,1y,0h,0t,0r', '_blank', 'top=150,left=' + eval(-700 + screen.width) + ',height=700,width=700');
} else {
//window.open('https://www.google.com/maps/@' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + ',7z', '_blank', 'top=100,left=0,height=700,width=700');
window.open('https://maps.google.com/?q=' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + '&ll=' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + '&z=7', '_blank', 'top=100,left=0,height=700,width=700');
window.open('https://earth.google.com/web/@' + ('+' + eval(toplat - eval(eval((pos4 / height) * 180.0)))).replace('+-','-') + (',+' + eval(eval((pos3 / width) * 360.0) + toplong)).replace('+-','-') + ',328.51120179a,63169669.71505167d,1y,0h,0t,0r', '_blank', 'top=150,left=' + eval(-700 + screen.width) + ',height=700,width=700');
}
}
}
</script>
… in the “proof of concept” new_world.html scroll around and clickaround web application to test your world geography, and calling on the great Google products …
… as the information sources … thanks again!
Previous relevant World Clickarounds Stationery Positioned Annotations Tutorial is shown below.
Today, we want to …
- revisit the “World Clickarounds with Annotations” series of web applications featuring in World Clickarounds Scrollable Annotations Tutorial … along with the recent …
- Emoji Image use of Google PageSpeed‘s
screenwebpageshot capabilities talked about in Emoji Image Creator or Media Paster Multiple Copy Synchronize Tutorial … to … - collect the canvas maps and annotations at a
screenwebpageshot of time and “herd this” into a Google PageSpeed image that the user can “Copy Image” off … ready for use Pasting into an image editor or some such … where that … screenwebpageshot can be proportional to an A4 piece of stationery … and because our …- new annotation section button is combined with a mobilefish generated HTML map element to allow the user to specify the image positioning on that A4 “webpage” image rendering at Google PageSpeed
The good thing here for this lazy programmer is that these changes did not have to change any of the supervising [countryOfMap].htm parent code, just the …
- changed external Javascript world.js (you can see in action for the World Clickaround web applications available via today’s live run link) which looks after those Annotation menu buttons (including our new “A4” one which needs a [canvasElement].toDataURL(‘image/jpeg’,0.3) call in the onclick event logic …
var backpos='left top';
var pagename='a4';
function doa4() {
var elc=elem.toDataURL('image/jpeg',0.3);
clearval='' + elc.length;
if (backpos != 'left top') { // left top=0 center top=1 ... I=1 M=2 A=4 G=8
if (backpos == 'center top') {
elc=elc.replace(':imag', ':Imag');
} else if (backpos == 'center right') {
elc=elc.replace(':imag', ':iMag');
} else if (backpos == 'left center') {
elc=elc.replace(':imag', ':IMag');
} else if (backpos == 'center center') {
elc=elc.replace(':imag', ':imAg');
} else if (backpos == 'right center') {
elc=elc.replace(':imag', ':ImAg');
} else if (backpos == 'left bottom') {
elc=elc.replace(':imag', ':iMAg');
} else if (backpos == 'center bottom') {
elc=elc.replace(':imag', ':IMAg');
} else if (backpos == 'right bottom') {
elc=elc.replace(':imag', ':imaG');
}
}
if (1 == 1) {
console.log('Pre a4_content');
if (eval('' + elem.height) >= eval('' + elem.width)) {
document.getElementById('a4_content').value=elc;
} else {
document.getElementById('a4_content').value=('' + elc).replace('e/','E/');
}
console.log('Post a4_content');
//document.getElementById('ifa4').style.display='inline-block';
document.getElementById('fma4').action=document.getElementById('fma4').action.split('am_')[0] + 'am_' + pagename + '.php';
document.getElementById('ba4_content').click();
console.log('Post send');
setTimeout(ifclear, 8000);
} else {
var xzhr = new XMLHttpRequest();
var xzform=new FormData();
console.log('pre a4_content');
if (eval('' + elem.height) >= eval('' + elem.width)) {
xzform.append('a4_content', elc);
} else {
xzform.append('a4_content', ('' + elc).replace('e/','E/'));
}
console.log('post a4_content');
xzhr.open('post', '//www.rjmprogramming.com.au/PHP/am_' + pagename + '.php', true);
console.log('post post a4_content');
xzhr.send(xzform);
console.log('post send');
}
}
function ifclear() {
document.getElementById('ifa4').src='//www.rjmprogramming.com.au/PHP/am_' + pagename + '.php?clear=' + clearval;
}
) that appear as you use (ie. click on) the [countryOfMap] maps … as well as a new … - PHP middle
manperson am_a4.php web application to sit between the supervising [countryOfMap].htm parents and Google PageSpeed to arrange for that …- stationery sizing (not exact, but “Copy Image” will be proportional, and exactness to stationery can be handled by any self respecting image editor feeding off the Paste data you have established after a “Copy Image” operation at Google PageSpeed)
- organize the CSS background-position (the image map element combination helps out with) user requirements
We’ll see, over time, whether stationery other than A4 needs more Annotation buttons, or that is either not needed, or can be dynamically catered for in external Javascript code.
Previous relevant World Clickarounds Scrollable Annotations Tutorial is shown below.
Today we involve …
- the web applications of World Clickarounds Google Map Chart Onclick Logic Tutorial … and …
- the discovery made in Fixed Questions Flexible Answers Quiz Tutorial …
… pointing us to the fact that our limited left and top and width and height excitement over the wonders of [element].getBoundingClientRect() was enhanced about a week back by the discovery of right and bottom and the joy of the discovery of x and y today with this chance encounter (and lesson to read the documentation more thoroughly on first readings). Because the combination of use of y and height in code above saves the complication of trying to work the event timing of working out [element].scrollTop (and “murky such like”) complication, detecting when the correct left hand cell was sidled up somewhere within the right hand question “cell” as per the scoring rules of the quiz.
… and …
- working off the progress of Feedback Canvas Curve Annotations Tutorial
… to allow for non-mobile platform scrolling of “Map Clickaround” improvements to annotations, the menu for which shows after the user clicks a couple of places on the map (canvas/image).
The central changed external Javascript world.js affects …
- welcometonation.html changed this way with a live run link
- world.html changed this way with a live run link
- australia.html changed this way with a live run link
- brazil.html changed this way with a live run link
- china.html changed this way with a live run link
- germany.html changed this way with a live run link
- india.html changed this way with a live run link
- ireland.html changed this way with a live run link
- nigeria.html changed this way with a live run link
- united_states.html changed this way with a live run link
… and …
… also adding …
- the ability to define colour opacity (via a blank delimited 0.0 to 1.0 opacity suffix to input type=text “canvas element” colour textbox) we thought could be really useful as an “annotation overlay” tool over the top of the “Map Clickarounds” explaining or planning a topic regarding geography … via …
var bcols=['red','#ff0000',
'black','#000000',
'white','#ffffff',
'yellow','#ffff00',
'green','#00ff00',
'blue','#0000ff',
'cyan','#00ffff',
'magenta','#ff00ff',
'pink','#ffc0cb',
'lightblue','#add8e6',
'lightgreen','#90ee90',
'pink','#ffc0cb',
'lightpink','#ffb6c1'
,'hotpink','#ff69b4'
,'deeppink','#ff1493'
,'palevioletred','#db7093'
... etcetera etcetera etcetera ...
,'slategray','#708090'
,'darkslategray','#2f4f4f'];
function hexdec (hexString) { // thanks to https://locutus.io/php/math/hexdec/
// discuss at: https://locutus.io/php/hexdec/
// original by: Philippe Baumann
// example 1: hexdec('that')
// returns 1: 10
// example 2: hexdec('a0')
// returns 2: 160
hexString = (hexString + '').replace(/[^a-f0-9]/gi, '');
return parseInt(hexString, 16);
}
function hex2dec(couleur, inopac) {
var dolR = couleur.toLowerCase().replace('#','').substring(0,2);
var dolrouge = hexdec(dolR);
var dolV = couleur.toLowerCase().replace('#','').replace(dolR,'').substring(0,2);
var dolvert = hexdec(dolV);
var dolB = couleur.toLowerCase().replace('#','').replace(dolR,'').replace(dolV,'').substring(0,2);
var dolbleu = hexdec(dolB);
if (inopac != '') {
return 'rgba(' + dolrouge + ',' + dolvert + ',' + dolbleu + ',' + inopac + ')';
} else {
return couleur.toLowerCase();
}
}
function opacitymaybe(incvalo) {
var incval=incvalo.value;
var origincval=incval.toLowerCase();
var opac='';
var colwords=incval.split(' ');
if (colwords.length > 1) {
if ((colwords[eval(-1 + colwords.length)] + ' ').substring(0,1) == '.' || ((colwords[eval(-1 + colwords.length)] + ' ').substring(0,1) >= '0' && (colwords[eval(-1 + colwords.length)] + ' ').substring(0,1) <= '9')) {
opac=colwords[eval(-1 + colwords.length)];
incval=incval.replace(' ' + opac, '');
}
}
if ((incval.toLowerCase + ' ').substring(0,3) != 'rgb') {
if ((incval + ' ').substring(0,1) == '#') {
incval=hex2dec(incval, opac);
} else if (bcols.indexOf(incval.toLowerCase().replace(/\ /g,'')) != -1) {
incval=hex2dec(bcols[1 + bcols.indexOf(incval.toLowerCase().replace(/\ /g,''))], opac);
}
}
if (incval != origincval) { incvalo.value=incval; }
return incval;
}
- cater for those annotation functionalities that require more than two discrete clicks/touches, primarily curve functionalities
- allow the “end of scribble” button act as a “close of polyline” action as well
We hope you get to try these changes for yourself.
Previous relevant World Clickarounds Google Map Chart Onclick Logic Tutorial is shown below.
Revisiting our World Clickaround web applications today, last talked about with Canvas Annotation Email Attachment User Acceptance Tutorial, we were gobsmacked that we hadn’t defaulted their use of the Google Chart Map Charts integrated in, to allow for inhouse “onclick” (via a Google Chart select event) logic.
Without this integration you miss being able to click near a place and …
- use “Z” option to find nearest TimeZone (and then onto option “W” Weather) and option “T” for TimeZone information
- use “S” for Sun Angle … and others of that ilk … and …
- use “G” for (navigating to) various Google Map views
- use “Y” for YouTube video lookup (though one of the nearest Airports (that have a known name) may do better here
- use “A” for Nearest Airports (though you probably got this up already)
… anyway … didn’t want these possibilities to be hidden any longer.
The fix was very simple applied to many HTML web applications (as below), that being to add &onclick=y into the map.php based URLs in the code linking to our Google Chart Map Chart interfacing.
- welcometonation.html changed this way with a live run link
- world.html changed this way with a live run link
- australia.html changed this way with a live run link
- brazil.html changed this way with a live run link
- china.html changed this way with a live run link
- germany.html changed this way with a live run link
- india.html changed this way with a live run link
- ireland.html changed this way with a live run link
- nigeria.html changed this way with a live run link
- united_states.html changed this way with a live run link
Previous relevant Canvas Annotation Email Attachment User Acceptance Tutorial is shown below.
An important part of a web (or desktop or mobile) application is user acceptance. User acceptance is, as the words would imply, the giving of your (developing) web application to real users, to test out usability … or UX (user experience). We do this today for our “Canvas Annotation Email Attachment” web application, and use it to “Annotate” a make believe trip, some of the “talking points” of which are “overlayed” on our “Welcome to Nation” map introduced a couple of days ago when we presented Canvas Annotation Email Attachment Transparency Tutorial and this resulted in an email sent with the attachment as you see in today’s tutorial picture.
User acceptance often throws up surprising findings, some easy to handle, and others that are likely to be extremely hard to implement, or impossible, or unworkable at this time. We addressed some of the easier ones to improve the web application, as listed below …
- as far as “overlay” thoughts go overlaying a transparent image on top of a clean map goes, we found, before user acceptance, that we would have had to type in the URL to the web application, again, at the address bar, rather than having a way to do it in the web application, so we turned the “Your” in “Your Annotations++” to be a dropdown, that if you change its value, you start the web application again, and can immediately arrange to overlay what you may have emailed off (to yourself, possibly) and downloaded locally onto your hard disk
- (after the email today … alas) … as far as the red or yellow click/touch blobs appearing (a little annoyingly) during Annotation operations, we allow you, now, to click on any part of the green bit of the Annotation menu, to turn off these blobs … alas … and you may want to do your own research, perhaps starting at this very useful link we “bit the bullet” and made non-generic HTML changes, as well as generic external Javascript changes, to allow for this … adding a new global variable blobc containing the colour of the “blob” … no, not that “blob”, this ..
- allow an original URL image to be supplied on the address bar URL as with this URL for today’s “fantasy trip” from “Alice Springs to Broome”
… and so what functionality features featured in our user acceptance test …
- a good source of geographical information is Google … thanks
- the base overlay image used the “where is” functionality we introduced with Canvas Clickaround Where Is Primer Tutorial
… is teamed with the background transparency functionality of Canvas Annotation Email Attachment Transparency Tutorial
… to (self-)email the canvas contents as an Email Attachment we learnt in Canvas Image Email Attachment Primer Tutorial
… invoking the first of three of those changes that we saw needed to happen as a result of user acceptance testing, and so (asynchrononously … who said our sex can’t do two things at once) an email arrives with its attachment, which can be downloaded to our MacBook Pro’s hard disk
- (meanwhile … back at the second incarnation of the web application we use the functionality first talked about with Canvas Email Attachment New Image Tutorial to overlay our “overlay” work, of the first incarnation, via an email download off the local hard disk so that)
… scribble (of Canvas Email Attachment Scribble Tutorial) was used to draw the Tanami Track
- pretty much original Annotation functionality (of Canvas Image Email Attachment Primer Tutorial) put in some place names and other information
- yesterday’s Canvas Annotation Email Attachment Image Fit Tutorial image fitting was used to fit images into tight spots “overlayed” onto the map, the whole canvas result of which is emailed off as an attachment
- which brings us to the end resultant email attachment downloaded image of our “fantasy trip” from “Alice Springs to Broome”
Again, for today’s work, the external Javascript world.js needed to change (regarding the user acceptance testing) like this today, regarding this new “Canvas Annotation Email” image fitting ideas, and our (common) PHP you could call intair.php is unchanged for any/all of (changed slightly) …
- welcometonation.html changed this way with a live run link
- world.html changed this way with a live run link
- australia.html changed this way with a live run link
- brazil.html changed this way with a live run link
- china.html changed this way with a live run link
- germany.html changed this way with a live run link
- india.html changed this way with a live run link
- ireland.html changed this way with a live run link
- nigeria.html changed this way with a live run link
- united_states.html changed this way with a live run link
Hope you will try some or all of these web applications, and their “Canvas Annotation” and “Email Attachment” functionality, maybe even in a real world situation, emailing the results out to somebody, perhaps?
Previous relevant Canvas Annotation Email Attachment Image Fit Tutorial is shown below.
There is still more to do with regard to image manipulations functionality regarding our “Canvas Annotation Email Attachment” and “Clickaround” web applications. We want to be able to offer image scaling via user defined click or touch event outcomes on our HTML canvas.
What we do today in the form of a new HTML select element dropdown containing image placement options …
- place or overlay images not according to user click or touch events on the HTML canvas element, but use other “Annotation++” menu settings
- fit the image into the rectangle formed by the user’s last two click or touch canvas co-ordinates
- fit the image into the rectangle width, only, formed by the user’s last two click or touch canvas co-ordinates
- fit the image into the rectangle height, only, formed by the user’s last two click or touch canvas co-ordinates
The workings of this new functionality includes the HTML canvas methods …
So, for today’s work, only the external Javascript world.js needed to change like this today, regarding this new “Canvas Annotation Email” image fitting ideas, and our (common) PHP you could call intair.php is unchanged for any/all of …
- welcometonation.html with a live run link
- world.html with a live run link
- australia.htm with a live run link
- brazil.htm with a live run link
- china.htm with a live run link
- germany.htm with a live run link
- india.htm with a live run link
- ireland.htm with a live run link
- nigeria.htm with a live run link
- united_states.htm with a live run link
Hope you will try some or all of these web applications, and their “Canvas Annotation” and “Email Attachment” functionality.
Previous relevant Canvas Annotation Email Attachment Transparency Tutorial is shown below.
We’ve thought of some more useful functionality regarding our “Canvas Annotation Email Attachment” and “Clickaround” web applications. To explore possibilities here going forward, and with regard to ideas regarding genericization possibilities, which aren’t a straightforward “yes” decision for today’s ideas.
What we do today is …
- we add to the “Where Is?” functionality of “Clickaround” web applications that we first talked about with Canvas Clickaround Where Is Primer Tutorial by allowing not only a Place Name (of an Airport) to be the only option that results in active usefulness with the web application, but also allow that same HTML input type=text element to specify a latitude;longitude[;placeName] for the case of the majority of places on Earth that don’t have an airport
- we add an extra functionality type similar to the “Undo” button of Canvas Annotation Email Attachment Undo Tutorial as shown way below that simply undoes the HTML canvas original image (the map), replacing it with a transparent background HTML canvas element that is then loaded with all the rest of the new Annotations you, the user, had added, since … hope you can see how useful this idea could be for a whole new set of “overlay” thoughts, which we’ll endeavour to refine in your mind as time goes on
- we add a whole new “Clickaround” and “Canvas Annotation Email Attachment” web application we are calling “Welcome To Nation” because we use the wonderful map developed by TreatyRepublic.net, thanks, in the tutorial sequence culminating in Australian Indigenous Language HTML Map jQuery YQL Tutorial
Now that second new functionality we are trialling with that new third new HTML and Javascript source code welcometonation.html with its live run link.
Often with genericization possibilities, the detail of how things could work, or perhaps not, in a “generic way”, are best “played out” in terms of a new “player” into the scene. So that is how we proceed today. This trialling also affects that first piece of functionality, with “Welcome to Nation” usage, having the window.open() “compiler” of selected “Where Is?” dropdown selections opening back in the “welcometonation.html” rather than the default (for all other “Clickaround” web applications, as it stands right now) “world.html” … a job to do here, for later, is to check that the user’s “latitude;longitude[;placeName]” entry falls within that “subset” map of the world … no such checks here today.
Anyway, going through this motion … yes … we found there is thinking to do making “genericization” of that second functionality idea work, and this is for tomorrow, and on. As is explaining how “overlay” possibilities expand here with that second idea above.
But the real wonder is in the intricacy of the culture, “the oldest surviving culture in the world”, of the Koori people, the first people of Australia, and so with that third option’s new Welcome to Nation web application is a new first option of the “web application” “Clickaround” dropdown at the right that points at the HTML map element Indigenous Australian Language Map web application Indigenous Australian Language Regions, where you point at a region and can open search engine and other information relevant to that indigenous language and peoples of interest.
So, for today’s work, the external Javascript world.js needed to change like this today, regarding this new “Canvas Annotation Email” background transparency idea, and our (common) PHP you could call intair.php changed quite a bit, as it controls “Where Is?” functionality ideas to any/all of …
- welcometonation.html with a live run link
- world.html with a live run link
- australia.htm with a live run link
- brazil.htm with a live run link
- china.htm with a live run link
- germany.htm with a live run link
- india.htm with a live run link
- ireland.htm with a live run link
- nigeria.htm with a live run link
- united_states.htm with a live run link
Hope you try some or all of these out.
Previous relevant Canvas Annotation Email Attachment Scale and Clip Tutorial is shown below.
We’ve been busy continuing on with our Annotations functionality quest, specifically regarding Image content for Annotations, and the ability to be able to Scale and Clip (or crop) those images within the HTML canvas element that hosts them. This is also part of the functionality we need in our “toolbox” for our eventual destination with all this Annotation (with optional Email Attachment) functionality.
Some considerations with Scale, Clip and Rotation (the latter of which we first set our sights on with Canvas Annotation Email Attachment Rotation Tutorial as shown below) thoughts are …
- what should the origin point of rotation be? … we follow the lead of this excellent link … thanks … and choose the centre of the canvas element … but also as of today’s work we offer the last click/touch position to be an option for positioning
- should the canvas dimensions change? … this is debatable … and we continue, for now, to say “no” to this … but we are still open to changing this
- do you rotate all canvas content or just an added image’s content? … we allow for both modes of use … we’ve added the ability for Annotation computer font text to rotate, as of today, as well
- what should the origin point of clipping be? … we allow a percentage or pixel user defined method of defining
Today’s scaling and clipping calls on the full canvas.drawImage() specification. Up to now we’ve only ventured to the first of the three incarnations of ctx.drawImage calls below …
void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
… as you can read more about at that great link … but we make use of all three with today’s work, especially the third call with the clipping parameters “sx, sy, sWidth, sHeight” supplementing scaling parameters “dWidth, dHeight”.
So yet again, no HTML files needed to change today, and our (common) external Javascript you could call world.js changed quite a bit, adding Scaling and Clipping functionality to the recently added Rotation functionality affecting any/all of …
- world.html with a live run link
- australia.htm with a live run link
- brazil.htm with a live run link
- china.htm with a live run link
- germany.htm with a live run link
- india.htm with a live run link
- ireland.htm with a live run link
- nigeria.htm with a live run link
- united_states.htm with a live run link
We’ll be back to explain more soon.
Previous relevant Canvas Annotation Email Attachment Rotation Tutorial is shown below.
It’s time to return to Annotations, specifically Image content for Annotations, and the ability to be able to Rotate those images, or the whole HTML canvas element that hosts them. It’s part of the functionality we need in our “toolbox” for our eventual destination with all this Annotation functionality.
Some considerations with Rotation thoughts are …
- what should the origin point of rotation be? … we follow the lead of this excellent link … thanks … and choose the centre of the canvas element
- should the canvas dimensions change? … this is debatable … and we have, for now, said “no” to this … but we are open to changing this, along with “cropping” and “scaling” and “specified offsets for rotated images” for follow up tutorials
- do you rotate all canvas content or just an added image’s content? … we allow for both modes of use
Along the way, today, we thought we should add, at least for non-mobile platforms with an “onmouseover” event (available), the means to show “canvas” co-ordinates to assist these users with “Offset X and Y” decisions, perhaps.
Once again, no HTML files needed to change today, and our (common) external Javascript you could call world.js changed quite a bit, adding Rotation functionality affecting any/all of …
- world.html with a live run link
- australia.htm with a live run link
- brazil.htm with a live run link
- china.htm with a live run link
- germany.htm with a live run link
- india.htm with a live run link
- ireland.htm with a live run link
- nigeria.htm with a live run link
- united_states.htm with a live run link
Canvas Annotation Email Attachment Undo Tutorial is shown below.
A web application allowing user defined Annotations is better when there is an “Undo” and “Redo” functionality option. This is because with any user intervention, there can be erroneous work, which sometimes can be a real pain to recover from scratch.
With “Undo” and “Redo” functionality, however, you do not want the user to think it is as much a part of the “mainstream” of the web application’s functionality, so we supply a “-” (minus) button for “Undo” and a “+” (plus) button for “Redo”, and make them smaller than other Annotation functionality buttons.
So how do we achieve this functionality? We actually do it by actually …
- always clearing the contents of the HTML canvas element
- always place the original image via canvas.drawImage() method
- calling on a stored Javascript array containing HTML canvas drawing statements, flagging the ones that represent a single user defined action, that one “single user defined action” being what an “Undo” or “Redo” action works regarding
There is a great resource for information about the Javascript “Array” object called ECMAScript® Language Specification (we got to via this link, which is also excellent as an “Array” object member functionality synopsis (and which we urge you to consult), thanks).
You may wonder about how canvas.drawImage() parameter 1 (an image object) is handled. We assume you will only be interested in “Undo”s and “Redo”s of the last image (object) involved, which is stored in a global variable (and rereferenced by “Undo” and/or “Redo”) when the Annotations are created (and built up) by the user.
So yet again, our world.html (with its live run) did not need to change for this new “Undo”/”Redo” functionality but our external Javascript you could call world.js changed quite a bit, setting up these Javascript arrays storing HTML canvas commands, for later use in “Undo” and “Redo” scenarios instigated by users clicking the relevant respective (small) “-” and “+” buttons.
As for …
We “might” have genericized the world.html changes into other HTMLs of its ilk … well, we decided against that for now … but will later … and partly the reason is that there is more to do, and we just want to concentrate on world.html
… we can now apply changes to the other HTML web applications …
- australia.htm changed this way with a live run link
- brazil.htm changed this way with a live run link
- china.htm changed this way with a live run link
- germany.htm changed this way with a live run link
- india.htm changed this way with a live run link
- ireland.htm changed this way with a live run link
- nigeria.htm changed this way with a live run link
- united_states.htm changed this way with a live run link
Also changing is the email attachment PHP helper you could call world.php changed in this way.
Hope this HTML canvas web application set gives you some ideas for work of your own. To read some of the background to this, try Canvas Email Attachment Scribble Tutorial as shown below.
Previous relevant Canvas Email Attachment Scribble Tutorial is shown below.
Personally think that Annotations are better when there is a “Scribble” functionality option. Perhaps you want to “sign off” on your Annotations. Without a “Scribble” option, it’s a bit impersonal relying on computer fonts as the means by which you “sign” the work.
And down the track it’s helping with our “final aim”, which will be revealed as time goes on.
To “Scribble” the main mouse event that interests us is the “onmousemove” event which happens when the mouse … moves … in which case if you are in “Scribble” mode, draw a line between the last two data points. So from that you would glean, and we’ll fill in, as well, that …
- the user needs to tell the computer it wants to start into “Scribble” mode (like a green light on the traffic light) … after a 2 second delay to allow the user to position themselves with their mouse … so we introduce a button for that, that the user can click … but how does the user do what was considered in the early days of all graphical application work … “pen up” … ie. mouse up … so …
- if onmouseup (or touchend) gets triggered we want it not to draw lines but be ready to resume (like a yellow light on the traffic light) … and when in this mode …
- if onmousedown gets triggered while “the traffic light is yellow” (ie. in the mode above) we want it to start to draw lines again with any mouse moves … and to call the whole thing off …
- if the keyboard is used stop any “Scribble” operations (or click the crossed out button supplied) (like a red light on the traffic light)
Reinventing penmanpersonship is a bit of a stretch, but nevertheless, adds a degree of authenticity to your content, for this is what you are doing, should you go on and email your work as an email attachment … you become an uploader of content … yet again, no doubt. This is a lot more common on the net for all of us, as each day passes. Maybe also, as each night passes. Even as Collingwood streams down the left wing, and passes, no doubt.
Yet again, our world.html did not need to change for this new “Scribble” functionality but our external Javascript you could call world.js changed quite a bit, setting up these mouse (or touch) event logics, as its Javascript “setTimeout” delayed onload function …
function touchHandler(event) // thanks to http://stackoverflow.com/questions/1517924/javascript-mapping-touch-events-to-mouse-events
{
var touches = event.changedTouches,
first = touches[0],
type = "";
//if (event.targetTouches.length == 1) {
switch(event.type)
{
//case "touchstart": type="mousedown"; break;
case "touchmove": type="mousemove"; break;
case "touchend": type="mouseup"; break;
default: return;
}
//initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
event.stopPropagation();
switch(type)
{
//case "mousedown": if (isScribble == 1) { isScribble=2; } break;
case "mousemove": if (isScribble == 2) {
if (x == 0 && y == 0 && lastx == 0 && lasty == 0) {
if (event.pageX || event.pageY) {
x = event.pageX - elemLeft;
y = event.pageY - elemTop;
} else {
x = event.clientX - elemLeft;
y = event.clientY - elemTop;
}
lastx=x;
lasty=y;
} else {
lastx=x;
lasty=y;
if (event.pageX || event.pageY) {
x = event.pageX - elemLeft;
y = event.pageY - elemTop;
} else {
x = event.clientX - elemLeft;
y = event.clientY - elemTop;
}
}
if (x != lastx || y != lasty) {
document.getElementById('divannotation').style.display='block';
document.getElementById('myisubject').style.display = 'inline';
document.getElementById('myiemail').style.display = 'inline';
context.strokeStyle=document.getElementById('mycolour').value;
context.beginPath();
context.moveTo(x,y);
context.lineTo(lastx,lasty);
context.stroke();
}
}
break;
case "mouseup": if (isScribble == 2) { isScribble=1; } break;
default: return;
}
}
function tryit() {
var tds=document.getElementsByTagName('td'), hstuff='';
if (tds.length > 0) {
hstuff+="<div style='position: absolute; top:600px; left:860px; display:none; background-color: lightgreen; ' id='divan" + "notation'><h4>Your Annotations++</h4>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/line.png' onclick=' doline(); ' alt='Line' title='Line'></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/rectangle.png' onclick=' dorectangle(); ' alt='Rectangle' title='Rectangle'></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/rectangleborder.png' onclick=' dorectangleborder(); ' alt='Rectangle Border' title='Rectangle Border'></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/circle.png' onclick=' docircle(); ' alt='Circle' title='Circle'></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/clear.png' onclick=' clearall(); ' alt='Clear' title='Clear'></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/sline.png' onclick=\" alert('Ready to Scribble in two seconds. Any key stroke stops scribbling.'); setTimeout(intwo,2000); \" alt='Scribble' title=''></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/zline.png' onclick=' isScribble=0; ' alt='End of scribble' title='End of scribble'></img>";
hstuff+=" <img src='http://www.rjmprogramming.com.au/MarkItUp/image.png' onclick=\" document.getElementById('file').click(); document.getElementById('file').style.display='block'; document.getElementById('dpf').style.display='block'; \" alt='Image' title='Image'></img><input style='display:none;' id='file' type='file' name='file'><div id=dpf style='display:none;'> <span class='readBytesButtons'><button style='display:none;' data-endbyte='4' data-startbyte='0'>1-5</button><button style='display:none;' data-endbyte='14' data-startbyte='5'>6-15</button><button style='display:none;' data-endbyte='7' data-startbyte='6'>7-8</button><br>... vs Image URL: <input type='url' value='+' onblur='readUBlob(this.value,0,0);' style='width:60%;'></input><br>... Offset X: <input style='width:25%;' id='xoff' type='number' value='0'></input> Offset Y: <input style='width:25%;' id='yoff' type='number' value='0'></input><br><button onclick='readBlob(0,0);'>Place into Canvas</button><button onclick='readOBlob(0,0);'>Overlay into Canvas</button></div><div id='byte_range' style='display:none;'></div><div id='byte_content' style='display:none;'></div><input id='fil' value='' type='hidden'></input><img id='spareimg' src='' style='display:none;'></img>";
hstuff+="<br>Annotation (optional): <input onblur='placeannotation(this);' id='iannotation' type='text' value=''></input><br><span>Anno B&W (optional): <input onblur='placeannotation(this);' id='jannotation' type='text' value=''></input><br>Style: <input type='text' id='myfont' value='18px Verdana'></input> <input type='text' id='mycolour' value='black'></input></span><br>";
hstuff+="<form style='display:none;' id='myform' method='post' enctype='application/x-www-urlencoded' action='http://www.rjmprogramming.com.au/HTMLCSS/world.php' target='myiframetwo'><input type='hidden' name='mysubject' id='mysubject' value='My World Map'></input><input type='hidden' name='myfname' id='myfname' value=''></input><input type='submit' id='bsubmit' value='Submit' style='display:none;'></input><input type='hidden' name='ismobile' id='ismobile' value=''></input><input type='hidden' name='mode' id='mode' value='1'></input><input type='hidden' name='to' id='to' value=''></input><input type='hidden' name='mydurl' id='mydurl' value=''></input></form>";
hstuff+="<iframe style='display:none;' id='myiframetwo' src='http://www.rjmprogramming.com.au/HTMLCSS/world.php'></iframe>";
hstuff+="<input style='display:none;' onblur='fixmyemail(this.value + String.fromCharCode(32),1);' type='text' id='myisubject' value='My World Map '></input> <input style='background-color: yellow;' type='button' value='Email (optional)' onclick=' capture(document.getElementById(" + '"' + "mydurl" + '"' + "),document.getElementById(" + '"' + "bsubmit" + '"' + "),document.getElementById(" + '"' + "myemail" + '"' + ")); '></input> <a style='display:none;' target='_blank' id='myemail' href='mailto:fill.in.email@address?subject=My%20World%20Map&body='></a><input style='display:none;' onblur='fixmyemail(this.value,0);' type='text' id='myiemail' value='' title='Fill this in for emailed attachment'></input>";
hstuff+="</div>";
if (tds[eval(-1 + tds.length)].innerHTML.indexOf('diva' + 'nnotaxtion') == -1) tds[eval(-1 + tds.length)].innerHTML+=hstuff;
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
var hh = today.getHours();
var minm = today.getMinutes(); //January is 0!
var ss = today.getSeconds();
document.getElementById('myfname').value = "world_" + yyyy + "_" + mm + "_" + hh + "_" + minm + "_" + ss + ".png";
document.getElementById('myform').action = document.getElementById('myform').action.replace('?mode=1', '');
document.getElementById('mode').value = '';
document.getElementById('ismobile').value = 'y';
document.getElementById('myisubject').style.display = 'inline';
document.getElementById('myiemail').style.display = 'inline';
document.getElementById('myform').action = document.getElementById('myform').action.replace('?mode=1', '');
document.getElementById('myform').action = document.getElementById('myform').action.replace('mode=1', 'mode=');
//document.getElementById('myemail').href = '#' + document.getElementById('myemail').href;
}
document.body.addEventListener('keyup', function(event) {
if (isScribble == 2 || isScribble == 1) {
isScribble=0;
}
});
if (isTouch || isiPad) {
//elem.addEventListener("touchstart", touchHandler, true);
elem.addEventListener("touchmove", touchHandler, true);
elem.addEventListener("touchend", touchHandler, true);
elem.addEventListener("touchcancel", touchHandler, true);
//elem.addEventListener('touchstart', function(event) {
// if (isScribble == 1) {
// isScribble=2;
// }
//});
} else {
elem.addEventListener('mouseup', function(event) {
if (isScribble == 2) {
isScribble=1;
}
});
elem.addEventListener('touchend', function(event) {
if (isScribble == 2) {
isScribble=1;
}
});
elem.addEventListener('touchstart', function(event) {
if (isScribble == 1) {
isScribble=2;
}
});
elem.addEventListener('mousedown', function(event) {
if (isScribble == 1) {
isScribble=2;
}
});
elem.addEventListener('mousemove', function(event) {
if (isScribble == 2) {
if (x == 0 && y == 0 && lastx == 0 && lasty == 0) {
if (event.pageX || event.pageY) {
x = event.pageX - elemLeft;
y = event.pageY - elemTop;
} else {
x = event.clientX - elemLeft;
y = event.clientY - elemTop;
}
lastx=x;
lasty=y;
} else {
lastx=x;
lasty=y;
if (event.pageX || event.pageY) {
x = event.pageX - elemLeft;
y = event.pageY - elemTop;
} else {
x = event.clientX - elemLeft;
y = event.clientY - elemTop;
}
}
if (x != lastx || y != lasty) {
document.getElementById('divannotation').style.display='block';
document.getElementById('myisubject').style.display = 'inline';
document.getElementById('myiemail').style.display = 'inline';
context.strokeStyle=document.getElementById('mycolour').value;
context.beginPath();
context.moveTo(x,y);
context.lineTo(lastx,lasty);
context.stroke();
}
}
});
}
setTimeout(tryit, 2000);
… as you can see from this link. Regarding some mobile platform issues we’d like to thank this really useful link … so, thanks. And if actions speak louder than words no doubt you’ll be wanting the live run link.
As for …
We “might” have genericized the world.html changes into other HTMLs of its ilk … well, we decided against that for now … but will later … and partly the reason is that there is more to do, and we just want to concentrate on world.html
… from last time’s Canvas Email Attachment New Image Tutorial as shown below, that still remains the case … there is more to do. Hope to see you back again for that then.
Previous relevant Canvas Email Attachment New Image Tutorial is shown below.
When we last left off with Canvas Image Email Attachment External Javascript Tutorial project we posed two ongoing “trailers”/”spoiler alerts” …
- We “might” have genericized the world.html changes into other HTMLs of its ilk … well, we decided against that for now … but will later … and partly the reason is that there is more to do, and we just want to concentrate on world.html with …
- Did you guess what functionality we might want to do next? We want to allow the user to “overlay” or “clobber” the existing canvas’s map image with an image of their choosing in one of two entry methods …
- via a Browse button selection of an image on their computer … or …
- via the specification of a URL pointing at an image (on the web, probably)
We’ve grappled with the relatively newly arrived brilliance of HTML5 with ideas off Browse buttons and their manipulation of file data, the methods of which don’t even need PHP or ASP.Net (or any other server side language) to proceed … cute, huh?! We referenced this great link when we presented PHP/HTML/Javascript Media & Document File Browse Tutorial, and you may want to reference that regarding the useful Javascript HTML5 FileReader methods. Another really useful link for today’s work is … what we just linked … we presume … thanks. We find FileReader.readAsDataURL() method to be just what we want today to take the data of a file as a data URL and be able to use the canvas.drawImage() to place that image data onto the canvas by “overlaying” it or “clobbering” it.
Our world.html did not need to change for this new image friendly functionality but our external Javascript you could call world.js changed quite a bit as you can see from this link.
To envisage all this, you really should try a live run of our interactive World Map (with Annotation and Email Attachment functionality) web application. We hope some Browse button thoughts start springing forth from the bit below the hair (or if you’re standing on your head right now … the bit above the hair).
Previous relevant Canvas Image Email Attachment External Javascript Tutorial is shown below.
Rome wasn’t built in a day … just read “SPQR A History of Ancient Rome” by Mary Beard, to confirm that. And software takes time, and often revisits and rethinks, in between, running it past people, perhaps. So it is with the build up of our “cause”, which we’ll eventually reveal, that started with Canvas Image Email Attachment Primer Tutorial as shown below, and moves on today, in two directions …
- Organization wise … we move some of the “Annotation++” functionality specifics to external Javascript … via …
<script type='text/javascript' src='world.js' defer></script>
… to be more modular, and to apply it to other web applications like world.html that aren’t world.html (which we will also do event-U-al-ly … maybe even today?! … you’ll see at the end of this blog posting if we have) - Functionality wise … we allow for more than “Annotations” now … hence the “Annotation++” notation above … we’ve been delving into our HTML canvas codes for logic to draw lines and rectangles (including a “huge white rectangle” to “clear” the canvas) and circles today
When you redesign arrangements this way, you should retest all the functionality combinations to make sure you haven’t broken anything … because that would be kinda’ stUpid. The adage should be that you leave things better than when you start, to do a good job … doh!
So there’s still an important bit of “base” functionality missing, and we’ll get to that next time, though maybe you’ve guessed what it would be yourself?!
So take a look at our HTML and Javascript and CSS world.html which changed as per this link which now calls on new external Javascript you could call world.js if you like. Unchanged is the concept (and the content) regarding the HTML using PHP server side code you could call world.php within an HTML iframe element. Again, please don’t think you’ll be able to achieve this functionality just with client-side Javascript. It involves server data. So here is a live run link in order for you to try this new functionality, which kicks into action from the second canvas click/touch, and on.
Hint: Don’t be shy to try some “rgba([red0-255],[blue0-255],[green0-255],[opacity0.0-1.0])” colour field possibilities in combination with the filled in rectangle option to improve your “overlay” functionality possibilities, as with today’s main tutorial picture.
Previous relevant Canvas Image Email Attachment Primer Tutorial is shown below.
Maybe you remember the series of blog postings that we last visited with HTML5 Canvas Map Clickaround Onresize Tutorial some time ago? We’ve been, over the last couple of days, working out how to …
- take an HTML canvas element’s [canvasContext].drawImage() image
- be able to overlay some interactively entered textual annotations over the top of user entered rectangle corners
- take a snapshot of this canvas with its annotations via [canvasContext].toDataURL() (woh!)
- use an HTML form element with method=POST target=myiframetwo to post the data to our (new) PHP (featuring the use of php://input for the first time, for us anyway) … which …
- emails that snapshot to someone
We allow for …
- non-mobile platforms to use their email clients, perhaps, via a body link to an image file stored on the rjmprogramming.com.au domain web server … or, because such functionality is awkward for mobile platforms, we …
- allow for the canvas contents be turned into image data that can be used as the data for an email attachment, thus allowing the web server to not have to store the data (there) now
Here’s some of the PHP code to create that email with its attachment, for your perusal (where $idata has that data URL data of the canvas’s contents, that is image/png data (in base64)) …
//$headers = 'From: ' . 'rmetcalfe@rjmprogramming.com.au' . $eol;
$headers = 'Reply-To: ' . 'rmetcalfe@rjmprogramming.com.au' . $eol;
// 'X-Mailer: PHP/' . phpversion();
$contents = "";
if ($idata != "") $contents = $idata;
if (strpos('~' . $mybody, '~http') !== false || $contents != "") {
if ($contents == "") $contents = @file_get_contents($mybody);
if ($contents != '') {
//
date_default_timezone_set('Australia/Perth');
//
//$mysubject .= ' ... ' . $mybody;
$fs = explode("/", $mybody);
$filename = $fs[-1 + sizeof($fs)];
$content = chunk_split(base64_encode($contents));
//
// a random hash will be necessary to send mixed content
$separator = md5(time());
//
$headers .= "MIME-Version: 1.0" . $eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"" . $separator . "\"" . $eol . $eol;
$headers .= "Content-Transfer-Encoding: 7bit" . $eol;
$headers .= "This is a MIME encoded message." . $eol . $eol;
//
// message
$headers .= "--" . $separator . $eol;
$headers .= "Content-Type: text/plain; charset=\"iso-8859-1\"" . $eol;
$headers .= "Content-Transfer-Encoding: 8bit" . $eol . $eol;
//
$headers .= "Please see attached image below:" . $eol . $eol;
//
// attachment
$headers .= "--" . $separator . $eol;
$headers .= "Content-Type: application/octet-stream; name=\"" . $filename . "\"" . $eol;
$headers .= "Content-Transfer-Encoding: base64" . $eol;
$headers .= "Content-Disposition: attachment;filename=\"" . $filename . "\"" . $eol;
$headers .= $content . $eol . $eol;
$headers .= "--" . $separator . "--";
//
ourpremail($tem, $mysubject, "", $headers); // emails to $tem
}
}
And so, with our proof of concept ideas, the world becomes (hopefully, lots of) our (collective) oyster(s), given a little imagination, here. Really, take a look at our HTML and Javascript and CSS world.html which changed as per this link. It has new PHP server side code you could call world.php within an HTML iframe element. Please don’t think you’ll be able to achieve this functionality just with client-side Javascript. It involves server data. So here is a live run link in order for you to try this new functionality, which kicks into action from the second canvas click/touch, and on.
Previous relevant HTML5 Canvas Map Clickaround Onresize Tutorial is shown below.
Yesterday we came back after quite some time in the (PHP) server world to some client (Javascript and HTML) work, and today, after yesterday’s HTML5 Canvas Map Clickaround Overlay Tutorial as shown below, we tackle a client Javascript event, the “onresize” event (best intervened with in terms of looking at the Javascript DOM “window” object rather than the “document” object), that is often “left until last” in a programmer’s mind … and often not thought about at all. That’s often me … but not today.
Perhaps the reason it is (often) neglected is that the design (you’ve come up with) leaves lots of room, and the styling “position:absolute;” concept is not used at all with your web application. Yesterday, though, “position:absolute;” is pivotal to the working of the web application, as is the positioning of the HTML canvas element at (0,0) … why? … the slightly glib answer here is that to complicate life is to complicate your web application, and if you can cater for the simple case, why not work with that simple case, with its simplified coding logic?
Okay, so what’s the scenario with yesterday’s HTML5 Canvas Map Clickaround Overlay Tutorial where the Javascript “onresize” event gets triggered. On a laptop or desktop computer, it is when you “drag” (a window corner) and, we anticipate, shrink your window (by then “dropping” (a window corner)) to end up with a window smaller than the set established size, width or height, we cater for with the HTML canvas element’s width or height.
Now we currently rely on the right hand side being the user controlling side, but if a user shrinks the window, and we refuse to get into any “zooming” logic … my strong advice is not to go there … you have two choices to my mind …
- “copy” the right hand HTML (into an existant blank HTML div element’s innerHTML) and “overlay” at (0,0) (with less opacity than the rest)
- “copy” the right hand HTML and use Javascript (where myWidth is calculated width of the HTML canvas element … remember this functionality from yesterday?) … and use window.open(“”,”Title”,”top=0px,left=” + eval(20 + myWidth) + “px,width=350px,height=600px”) (along with a global variable wadd) … for a popup window, as per …
and then use wadd.document.write([someHTML]) … as per …
wadd = window.open("","Your Place and Airports Map Goes Here ...","top=0px,left=" + eval(20 + myWidth) + "px,width=350px,height=600px");
var newhtml="<!doctype html><html><head>" + document.head.innerHTML + "</head><body>" + document.getElementById('dhuh').innerHTML.replace(/opacity:0.0;/g, "opacity:1.0;").replace('"Cloudy"', '').replace('id="myqiframe', 'id="myiframe').replace('id="mypqiframe', 'id="mypiframe').replace('id="myqa', 'id="mya');
wadd.document.write(newhtml);
You’ve probably guessed by the added detail in the second of above, the first idea was awkward, but if you want to pursue it yourself, via leads, look for the (left in) if (additional != ”) { } logic parts in the HTML/Javascript coding of cloudy_world.html (or try the live run).
We later use a Javascript setTimeout() call to wait a while while the hidden right hand side’s HTML iframe element is filled out with the Airport Data Near Your World Map Clicked Position, and through that knowledge over to the “wadd” window (where it is viewable, presumably … unless you’ve repositioned again (which is okay to test if you want)).
So, today, everything should be as per yesterday with no “resizing” (and of course the programmer adage to “not make things backward in functionality” would tell you that to hold onto this “tooth and nail” should be thought of as extremely important … probably of higher priority than any new functionality … think probably users get pretty annoyed by things that used to work, not working later, because of your own newly introduced bug).
It behoves me, my liege, to leave you with the HTML/Javascript code differences, to make this happen, from yesterday, here, and we hope it helps you in some small way. We also want to thank the “powers that be” for the excellent advice at this link, for this topic … thanks, as always.
Previous relevant HTML5 Canvas Map Clickaround Overlay Tutorial is shown below.
After some time in the (PHP) server world, it’s time to dive back into some client (Javascript and HTML) work, in this client/server world of web applications.
Today we revisit the “overlay” theme of blog postings, as the web application world is full of possibilities for overlay ideas.
This time we overlay an HTML div element completely on top of an HTML canvas element, with some opacity (or some transparency), during the body “onload” event. We do not adjust the DOM “z-index” style property for either element. So what happens in this scenario when you click on this “multiple” HTML element combination? Well, it pans out you click on the HTML div element, so we have another task to do at the body “onload” event, to see things right, regarding the working of this web application, which starts where we left off with HTML5 Canvas Map Clickaround Follow Up Tutorial as shown below.
From this basis, this is how we got to today … there was HTML cloudy_world.html that changed like here.
You’ll see in the code above some great code presented at useful link (thanks) which is great for defining an HTML element’s size via …
function SetBox(what) {
var div = document.getElementById(what);
if (div.getBoundingClientRect) { // Internet Explorer, Firefox 3+, Google Chrome, Opera 9.5+, Safari 4+
// do stuff
}
}
… and we hope you can see that the implications for “overlay” ideas you have are huge … and that is fine … but you may wonder how the HTML div element is made to drape right over all the canvas element … well, it uses styling as per …
- position: absolute;
- top and left and width and height parameters are all defined
- borderTop defined as having a size the same as height above as per our HTML div id=’boxdiv’ element …
document.getElementById('boxdiv').style.position = 'absolute';
document.getElementById('boxdiv').style.top = y + "px";
document.getElementById('boxdiv').style.left = x + "px";
document.getElementById('boxdiv').style.width = w + "px";
document.getElementById('boxdiv').style.height = h + "px";
document.getElementById('boxdiv').style.borderTop = h + 'px solid rgba(255,255,255,0.5)';
… and you’ll also see with the code how the HTML div id=’boxdiv’ element’s “onclick” details are transferred to the (effectively underlying) HTML canvas element, where all the previous business logic of the web application resided, and continues to function (once you make variables “x” and “y” global and control how they are derived at the HTML div id=’boxdiv’ element’s “onclick” event logic).
So please try the live run to see all this in action.
Previous relevant HTML5 Canvas Map Clickaround Follow Up Tutorial is shown below.
HTML5 brought in the incredibly useful “canvas” element, for the first time. Its existence opens up a whole new world of possibilities for web applications that are graphical by nature, as we saw yesterday with HTML5 Canvas Map Clickaround Primer Tutorial as shown below. Today, we extend that functionality as of yesterday, by adding the use of a public data feed to enhance the information we present with the Google Map “iframe” we use, and for this we need to thank, profusely, The Global Airport Database project by Arash Partow … thanks very much. Now this database (really a file), as you can imagine, has data that changes over time, so is probably best used as a data feed. Nevertheless, the exercise of using it as a snapshot is useful, and we go ahead and show the nearest 4 airports on the database, in that Google Map “iframe” as of April, 2015.
This involved the use of PHP (intair.php) to read the file and parse it, which wasn’t hard as it contains well formed “:” delimited data, and there is just the check needed for security hidden data given a latitude and longitude of zero … unless I’m mistaken, and where the water goes down the sink the other way as you cross the equator due south of London has several hundred microscopic airports run by ants … what a movie script?!
With the canvas element’s drawImage() method, we use to position the image map of interest, you can draw more than your own geometrical constructs, you can have an image, and that image could be a map, as for today’s “World Clickaround” web application (with access to maps of Brazil and Ireland and United States of America too), where you click on the map (and thanks to mapsofworld.com for downloadable free maps here) to show a Google Map of interest via Google Chart Map Chart. Maybe you can use the map of the World to …
- plan a trip
- look up where relatives live
- count the fire hydrants in Monaco
This web application calls on tiny bits of mapping knowledge, namely the “orientation” of your “map”, as you are effectively digitizing to show where you want your Google Map to zoom in on.
Please have a go of our live run or download the HTML programming source code you could call world.htm (brazil.htm, ireland.htm, united_states.htm), or do both?!
From yesterday, this is how we got to today … there was new PHP you could call intair.php … and then there was changed HTML, the changes for which look like … world.htm, brazil.htm, ireland.htm, united_states.htm
Previous relevant HTML5 Canvas Map Clickaround Primer Tutorial is shown below.
HTML5 brought in the incredibly useful “canvas” element, for the first time. Its existence opens up a whole new world of possibilities for web applications that are graphical by nature.
With the canvas element’s drawImage() method you can draw more than your own geometrical constructs, you can have an image, and that image could be a map, as for today’s “Ireland Clickaround” web application (with access to maps of Brazil and United States of America and the World too), where you click on the map (and thanks to mapsofworld.com for downloadable free maps here) to show a Google Map of interest via Google Chart Map Chart. Maybe you can use the map of Ireland to …
- plan a trip
- look up where relatives live
- imagine you’re in O’Connell Street
This web application calls on tiny bits of mapping knowledge, namely the “orientation” of your “map”, as you are effectively digitizing to show where you want your Google Map to zoom in on.
This is one of those occasions that your (simple) software is a lot more effective using the Mercator map projection (that exaggerates the polar areas (like you might have had at school) because the simple latitude and longitude distances everywhere are the same (but relative areas definitely are not (ie. much bigger than reality near the poles))). Unfortunately, our United States of America projection is not Mercator, but you’ll still get a “ball park” Google Maps feel.
So we can have it that if the user doesn’t zoom, they need no orientation checks, but otherwise we need to determine a scale, by the user clicking on Dublin, on the map, and from that, we can work out the scaling that needs to be applied, as the top left co-ordinate is arranged to be (0,0) via the style=”position: absolute; top:0; left:0; “ part of …
<canvas id="canvaselement" width=600 height=600 style="position: absolute; top:0; left:0; " />
Please have a go of our live run or download the HTML programming source code you could call ireland.html (brazil.html, united_states.html, world.html), or do both?!
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.